Code-change risk analysis, with provenance
Evidence for every risk in your diff.
ChangeGuard reads a change the way a careful reviewer does. It rebuilds both revisions, follows every caller, reruns static analysis on what is new, and measures the lines your tests never touch. A language model may explain the result, but only where the evidence holds.
Python, JavaScript and TypeScript in depth; secrets, migrations, and dependencies for any file. Runs locally, needs no API key, and never executes the code it reads.
- ◆2 call site(s) incompatible with new signature of format_pricesrc/billing/pricing.py:16High
- ◆Undefined name REGIONAL_RATESsrc/billing/pricing.py:27High
- ◆No test executes src/billing/api.py (3 changed executable line(s))src/billing/api.py:4Medium
- ◆Async functions should not call time.sleepsrc/billing/api.py:11Medium
A finding is only as good as the way it was found.
Most review tools merge everything into one confident list. ChangeGuard keeps three kinds of knowledge apart, labels each finding with its kind, and never lets a weaker kind overrule a stronger one.
Deterministic
established by analysisA parse, a resolved call, a measured line. If the rule says a caller passes a keyword the new signature rejects, it found that call and checked it the way Python binds arguments.
2 call site(s) incompatible with new signature of
format_price× passes unexpected keyword argument
currencysrc/billing/pricing.py:16E2E3E4
Heuristic
inferred by a ruleA pattern worth a reviewer’s attention whose impact depends on context: a flipped comparison, a function no test references. Stated as an inference, with its confidence, never as a fact.
Condition logic changed:
>→>=Inputs exactly at the boundary (or on the side the condition now excludes/includes) take the other branch than before — the classic off-by-one / inverted-condition regression.
src/billing/pricing.py:11E10
AI-generated
proposed by a model, then verifiedExplanations and extra risks from a language model, kept only if every evidence ID, file, line, and symbol they mention checks out. Shown beside the rule’s analysis, never in place of it.
“The new signature of
format_pricechanges the required parameter fromcurrencytolocale, making it incompatible with existing call sites.”llama3.2:3b · local, via Ollama · citesE4
Eleven stages, all of them visible.
No single score hides the work. Every report records what each stage did, how long it took, and what it skipped and why. On the billing sample the full deterministic pipeline took 30 ms.
Read the system card01Parse inputs
0.68 msValidates and parses the patch, snapshot archive, and coverage report.
Never extracts archives to disk or follows symlinks.
02Reconstruct revisions
0.08 msApplies the patch to the snapshot in memory to rebuild the base and head revisions.
Never runs git hooks or repository scripts.
03Structural diff
1.6 msParses both revisions with tree-sitter and diffs functions, classes, and signatures.
04Cross-file references
1.0 msResolves imports and finds every caller of a changed symbol, then checks each call against the new signature.
05Static analysis
24 msRuns Ruff on both revisions and keeps only diagnostics the change introduced.
Never executes the analysed code.
06Risk rules
1.5 msSecrets, injection sinks, migrations, dependencies, condition flips, and test-integrity rules on added lines.
07Test mapping
0.38 msFinds tests that import and exercise each changed symbol.
08Coverage
0.42 msMeasures which changed lines the uploaded coverage report says never ran.
09AI synthesis
offOptional: a model explains findings and proposes risks, citing evidence IDs only.
Never sees secrets or prompt-injection text.
10Grounding verification
offRejects any model claim whose evidence, paths, lines, or numbers do not check out.
11Assemble report
0.45 msDe-duplicates findings, verifies every evidence reference, and computes the review priority.
Models may explain. They may not invent.
The model sees only fenced evidence, with secrets masked and prompt-injection text withheld. It must cite evidence IDs for every claim. Its output then passes through a verifier that rejects the claim outright, never repairing it, when any check fails.
Architecture does the rest: model output can add an explanation or a capped, separately labelled risk. It cannot delete, downgrade, or rewrite what the rules found.
- Evidence existsEvery cited ID must be one ChangeGuard produced for this change.
- Paths are realFile paths mentioned must belong to the change or its evidence.
- Lines are in rangeLine numbers must fall within the evidence the claim cites.
- Symbols are attributedA function named in a claim must appear in the evidence it cites.
- No invented numbersPercentages must appear in the evidence; coverage is never estimated.
- No test resultsChangeGuard runs no tests, so claims that tests passed or failed are rejected.
Measured on labelled changes, including the ones it misses.
67 code changes with 65 hand-written labels and 9 negative controls, compared against two naive baselines. Two holdout sets were written only after the rules were frozen, and each was run once before anything changed.
Clean holdout results: first run of each set
| Set | Precision | Recall | False alarms on safe changes |
|---|---|---|---|
| Holdout · 21 cases | 83.3% | 75.0% | 67% |
| Holdout v2 · 13 cases | 100.0% | 81.8% | 0% |
Small and synthetic: these numbers show consistency with the labelling guide, not real-world effectiveness.
Precision
95% CI- ChangeGuard100.0%
- ChangeGuard, diff only100.0%
- Keyword search baseline59.3%
- Flag-every-change baseline31.4%
Recall
95% CI- ChangeGuard93.8%
- ChangeGuard, diff only72.3%
- Keyword search baseline49.2%
- Flag-every-change baseline16.9%
Six things ChangeGuard will never do.
- Run your code.Uploads are parsed, never executed. Git is invoked with hooks and external diff drivers disabled.
- Send a secret to a model.Detected credentials are masked before any report, export, or prompt is built.
- Let a model overrule a rule.AI output is additive and capped at medium confidence. It cannot remove a finding.
- Dress a heuristic as a fact.Every finding carries its provenance, and severity is kept separate from confidence.
- Invent a probability.No blended risk score. The review priority is a transparent rule over labelled findings.
- Keep your repository.Archives are read in memory and discarded; reports store only the excerpts they cite.
Run it on your next pull request.
Start the engine and the web app with one command, or use the CLI as a CI gate that emits SARIF for code scanning. Local models via Ollama are optional; nothing requires a paid API.
docker compose up# web: http://localhost:3000 engine: http://localhost:8000/api/docschangeguard analyze --git-repo . --base origin/main \ --format sarif --output changeguard.sarif --fail-on high