Engineering notes · GovernDiff v0.6

Building Policy CI without uploading the policy

A policy edit can look small in a line diff and still change who must act, how soon they must act, or who may grant an exception. We built GovernDiff to catch those changes in a pull request while keeping the source documents on the runner or the reviewer’s machine.

23 August 2026 8 minute read Open source · MIT

The problem is not finding changed words

Ordinary diff tools are good at showing that text changed. The harder question is what the edit means for a reviewer. Moving from “may report within 72 hours” to “must report within 24 hours” changes both normative force and deadline pressure. A red-and-green character diff leaves that interpretation to every reader, every time.

A generic language model can summarize the change, but a summary is a poor CI contract. The output may vary, evidence can be compressed away, and private documents may cross a service boundary. GovernDiff takes a narrower approach: deterministic checks, explicit confidence reasons, source locations, and stable finding fingerprints.

The unit of output is not a verdict. It is a review cue with enough evidence for a person to verify.

Four contracts keep the system honest

1. Parse structure before comparing prose

GovernDiff accepts digital PDF, DOCX, HTML, Markdown, and plain text. Each parser produces a shared block model with physical page, paragraph, line, section, table, and cell locations where the source format permits it. That model lets table cells participate in comparison and keeps evidence attached to its original location.

The preflight step is deliberately strict. Empty, encrypted, corrupt, oversized, low-text-coverage, and image-only inputs receive actionable diagnostics. OCR is outside the current release rather than being silently invoked.

2. Align clauses through document churn

Policies are often reorganized while they are edited. A useful comparison must distinguish an addition from a move and cope with one clause splitting into two or several clauses merging. GovernDiff aligns blocks first, classifies the relationship, and then produces token-level spans for the evidence view.

Article references get separate treatment. When numbering changes, the report retains ranked mapping candidates and ambiguity instead of forcing a confident-looking answer.

3. Run small, explainable checks

The v0.6 contract contains 15 bilingual checks covering modality, permission, prohibition, scope, authority, deadlines, thresholds, exceptions, effective dates, definitions, and reference retargeting. Every finding records the before and after values, the aligned source evidence, severity, confidence layer, and confidence reasons.

A content-derived GVD-* fingerprint identifies the substantive finding across line movement and report formats. That identity connects CI output, human decisions, exports, and dated waivers without relying on a database.

4. Separate machine output from human decisions

The local Reviewer can confirm, reject, modify, or waive a finding. Machine-extracted values remain alongside the effective human-reviewed values, so a correction does not erase what the detector originally produced. Decisions export as portable JSON and can be reapplied by the CLI.

The Reviewer binds to loopback, uses a session cookie, and does not create a hosted document service. The core AI-off verification records zero network attempts across all five supported formats.

What the pull-request gate actually does

The composite Action compares configured paths against the pull request’s base commit. It writes JSON, Markdown, HTML, and CSV reports before enforcing the gate, so a failed check still leaves a complete artifact. Workflow annotations are privacy-safe by default; repository paths, source lines, and finding summaries require an explicit opt-in.

- uses: haiqi825-arch/governdiff@v1
  with:
    paths: "policies/**/*.md"
    min-confidence: high
    fail-on-severity: high

The public synthetic example PR shortens an incident deadline from 24 hours to 12 hours. It is intentionally left as a Draft. The page shows the same workflow a real repository receives: automatic PR-base comparison, a finding in the Job Summary, a complete report artifact, CodeQL, dependency checks, and cross-platform installation gates.

A release test caught a packaging mistake

The first public tag contained a working wheel, but the Marketplace Action installs from its source checkout. Our initial public tree excluded the Reviewer build output, so a clean-source Action install failed even though the wheel and the main quality workflow passed. The workflow had built the frontend before installing Python, which masked the mismatch.

We fixed the boundary in PR #5. The 26-file, 4.4 MB deterministic runtime bundle is now the single approved generated tree. Hosting state remains excluded. A regression test asserts that a public snapshot contains the required runtime files and no .openai directory.

The fixes were merged only after Windows, macOS, and Linux clean installs, both Action canaries, CodeQL, dependency audit, Grype artifact scanning, and reproducible-build checks passed. The stable v1 Action channel now points to that verified commit; v1.0.2 is the immutable tag.

Try the evidence, not the pitch

Start with the bundled synthetic case. It contains no third-party policy text and produces a self-contained HTML report you can inspect offline.

git clone https://github.com/haiqi825-arch/governdiff.git
cd governdiff
python -m pip install .
governdiff diff \
  examples/public-cases/01-incident-deadline/old.md \
  examples/public-cases/01-incident-deadline/new.md \
  --format html --output report.html

Useful links

Open the static evidence report · Read the quick start · Report a boundary case