The closed loop
The auto-fix verify loop has four stages, each of which has a clear owner and a clear artifact:
- Propose. For a recognized rule class, ChipVerify selects the matching deterministic fix template and instantiates it against the failing finding (rule ID, file, line, surrounding code, project conventions), emitting a unified diff against a candidate branch. No changes are pushed yet.
- Apply. The backend applies the patch to an in-memory copy of the project’s active RTL files. Nothing is written to disk and no branch or clone is created. If no deterministic template is available for the rule the loop stops and leaves the finding for manual review.
- Verify. The same static analyzer that produced the original findings runs again over the in-memory patched files and emits the same rule IDs, so the two findings sets can be diffed directly.
- Report. A diff of the two findings sets is presented to the engineer: which findings the fix resolved, which ones it left alone, which ones it newly introduced, and a numeric score delta. The engineer reviews the patch and the report side by side and decides whether to merge.
Why this is hard
A patch can look right and still be wrong. Common failure modes the static re-analysis catches — and one important class it does not:
- Did not actually fix. The patch claims to resolve the inferred latch but the analyzer still reports it on the patched source. The target finding stays in the after-set, and resolved comes back false.
- Breaks an unrelated rule. The fix clears the inferred-latch but introduces a new width-mismatch the analyzer flags. It shows up as a new entry in the after-set, so the issue count does not drop the way you expected.
- What it cannot see. Because the verify step only re-runs the static analyzer, it cannot catch a behavioral regression — a cosmetic fix that silences a warning but changes a held value, a signedness flip, or a dropped clock-gating cell. Those need simulation, synth-lint, or formal, which you run as separate engines on the project.
The verify run is not a luxury — a fast static re-analysis on the patched source is what lets an engineer reject an obviously-wrong patch in seconds. It is not, however, a full re-verification.
Worked example
Suppose the analysis tab shows an inferred latch on uart_rx.data_out:
// rtl/uart_rx.sv - fix candidate: missing default in case
module uart_rx (
input logic clk,
input logic rst_n,
input logic [1:0] state_in,
output logic [7:0] data_out
);
always_comb begin
case (state_in)
2'b00: data_out = 8'h00;
2'b01: data_out = 8'h41;
2'b10: data_out = 8'h42;
// 2'b11 missing -> latch on data_out
endcase
end
endmoduleThe engineer clicks Auto-Fix. The matching template emits this candidate:
// rtl/uart_rx.sv - template fix candidate
module uart_rx (
input logic clk,
input logic rst_n,
input logic [1:0] state_in,
output logic [7:0] data_out
);
always_comb begin
data_out = 8'h00; // unconditional default
case (state_in)
2'b00: data_out = 8'h00;
2'b01: data_out = 8'h41;
2'b10: data_out = 8'h42;
default: data_out = 8'h00;
endcase
end
endmoduleThe engineer clicks Verify. The backend applies the patch to an in-memory copy of the files and re-runs the static analyzer. A few seconds later the report panel comes back with structured output:
{
"project_id": "proj_19f201",
"analysis_id": "run_2026_05_07_T1006_19f201",
"issue_index": 0,
"filename": "uart_rx.sv",
"rule": "inferred_latch",
"method": "template",
"summary": "Add default branch to case on state_in",
"confidence": "high",
"patch": "--- a/uart_rx.sv\n+++ b/uart_rx.sv\n...",
"before_issue_count": 2,
"after_issue_count": 1,
"before_score": 78,
"after_score": 91,
"resolved": true
}The issue count drops from 2 to 1, the target finding resolved, and the score moves from 78 to 91. The engineer can review the patch and apply it with confidence because the analyzer was actually re-run on the patched source, not just shown a diff.
Trust boundaries
The loop is opinionated about where automation stops. ChipVerify never writes the patch back to your project on its own. Specifically:
- The patch is applied only to an in-memory copy of the files for the duration of the verify run. The project’s stored RTL is never mutated, and there is no branch, clone, remote push, or PR.
- The diff and the verify report are presented together. The engineer is expected to read both before deciding whether to apply the change to their own source.
- The before/after issue counts and score are advisory. The engineer decides whether the delta justifies taking the patch — ChipVerify does not gate anything on the engineer’s behalf.
The loop is a force multiplier on engineer time, not a replacement for engineer judgment. The point is to remove the cost of trying a fix, not to remove the cost of deciding whether to take it.
What the verify run actually runs
The same static analyzer that produced the original report — and only that analyzer:
- The structural analyze pass walks the AST of the in-memory patched files and re-emits findings with the same rule IDs the original report used. Same IDs are what makes the before/after diff possible.
- The verify step does not run simulation, synth-lint, Yosys, or Verible. Those engines run as part of the normal project pipeline, but the in-memory fix-verify loop is scoped to a fast static re-analysis so it can return a delta in seconds.
What the template has access to
The proposal step is fully deterministic. There is no language model and nothing is sent off-box. Each fix is produced by a template bound to a specific rule class, and that template reads only a constrained, structured set of inputs:
- The finding itself. Rule ID, file, line, signal name, the specific message the engine emitted, and the severity. This tells the template which fix pattern applies.
- A focused source window. The function or always block surrounding the offending line, plus relevant module headers and parameter declarations — parsed from the project AST so the patch lands on the right construct.
- Project conventions. If the project has a coding-style hint (always_comb vs always @*, naming pattern for registers, preferred default values), the template uses it so the patch matches the existing style.
- The fix pattern. For canonical rule classes (inferred latch, missing default, width mismatch), the template encodes the known-correct transformation, so the same finding always produces the same, reviewable patch.
Equally important: what the template does not touch. It does not read the simulation testbench, the regression history, or the repository’s commit log. The proposal is constrained to the finding and its locality. The verify run is what proves the proposal interacts well with the rest of the design.
The issue delta
The most useful field in the report is the issue delta: what changed between the base run and the candidate run. The three buckets:
- Fixed. Findings that existed on the base run and are absent on the candidate. This is the headline metric — usually you want exactly the target finding here.
- Introduced. Findings on the candidate that were not on the base. The number to watch: an introduced non-empty list is a strong signal to reject the patch.
- Unchanged. Findings present on both. Healthy for findings unrelated to the fix; a warning sign if the target finding shows up here, because it means the fix did not actually fix.
Why this matters more than a one-shot patch
A bare diff and a self-reported confidence number tell you nothing about whether the patch actually works on your design. The verify loop replaces assertion with measurement. It runs the patched source through the static analyzer, observes the result, and reports the change in the same units the rest of the team thinks in: analyzer findings and score deltas.
The cost of being wrong is higher in RTL than in software. A bad fix can add a week of debug to a tapeout schedule or, worse, ship to silicon. The verify loop is the cheapest reliable way to make a proposed fix safe to land in a hardware codebase.
Related reading
- Verification waivers — what to do when the fix is not worth taking and you accept the residual risk instead.
- Inferred latches — the canonical class of finding the auto-fix loop handles well.
- RTL verification — how the verify loop fits next to lint, sim, synth, and formal in the broader flow.
- Schematic issue highlighting — how findings (before and after) are mapped onto the netlist for visual review.
Try it on your project
Paste a GitHub URL at chipverify.ai/tinytapeout (free) for a one-shot scan, or sign in at chipverify.ai/dashboard to use the auto-fix loop with patch preview and in-memory re-analysis of the candidate change.
Preview a fix before you land it
Sign in and ChipVerify AI applies a deterministic template patch to an in-memory copy of your RTL, re-runs the analyzer, and reports the finding delta before you commit — pre-signoff evidence, not a foundry signoff.