Fix-Verify Loop
Leave fixes staged and return their paths plus one outcome per finding.
The caller owns regression detection, new-issue discovery, and whole-diff review.
Verification scope
- Focused checks: Fixers and verifiers run the narrowest check that proves the assigned finding, plus directly affected tests.
- Broad suites: Run a subsystem or full-project suite inside this loop only for shared test infrastructure, order dependence, or a finding reproducible only in that suite; the caller owns every other broad gate.
- Harness exits: After test bodies pass, retry a harness that fails to exit only when a new hypothesis distinguishes the rerun.
Protocol
Input
- Findings: Confirmed P0/P1 findings conforming to the Output Schema.
- Artifact paths: Files the resolver may edit.
- Criteria: Original requirements each fix must satisfy.
Intake filter: Process only findings with verdict = "confirmed" and severity in ["P0", "P1"]. The caller owns confirmation quality; finding source does not affect intake. Leave P2/P3 findings with the caller.
Pre-gate: Route each finding by validated_by before mutation; treat a missing field as null.
validated_by |
Action |
null or reviewer |
Independently verify. |
verifier |
Skip the pre-gate. |
machine |
Skip only when evidence names the exact check and observed failure, and the finding states only what that result proves; otherwise verify. |
Confidence measures certainty; it never changes this routing.
Complete the pre-gate for findings that require independent verification before any mutation; skipped findings proceed directly to Round 1:
- Batch. Group those findings by shared files, symbols, call chains, or reported root cause. Put at most four findings in each batch.
- Dispatch. Run up to four
verifier agents concurrently and queue the rest. Repository rules that forbid overlapping checks override this limit. Give each verifier:
- Artifact: the files or surrounding context for its batch.
- Findings: every finding in its batch.
- Criteria: "Is each finding real?"
- Output contract: a
ReviewOutput envelope with one verdict per finding.
- Collect. Wait for every batch before Round 1. A missing or unparseable verdict makes only that finding inconclusive.
- Route. Route each finding independently:
rejected → add to dropped and skip the fix loop.
confirmed → proceed to Round 1.
demoted to P0/P1 → proceed to Round 1.
demoted to P2/P3 → add to demoted and skip the fix loop.
- inconclusive → proceed to Round 1 without consuming a fix attempt.
Conflict-group loop
Group surviving findings by shared files, symbols, call chains, tests, mutable artifacts, behavior, or root cause. Keep groups to four findings unless one root cause cannot split safely.
- Fix in parallel. Run one fixer per group. Dispatch every proven-disjoint group concurrently up to agent capacity; queue known or uncertain overlap. Repository concurrency rules override dispatch.
- Verify in parallel. Verify a completed group while unrelated fixers continue. Give each verifier up to four related findings, and run verifier batches concurrently unless their checks share mutable resources or repository rules forbid overlap. Wait when an active fixer could affect the files, behavior, or checks under verification.
- Account separately. Keep each finding's verdict, attempt count, bucket, and escalation state independent even when one fixer or verifier handles the group.
- Stage serially. The parent stages one group at a time. Fixers never stage files.
Give each finding at most two attempts. Proven-disjoint groups may occupy different rounds concurrently.
Include these rules in every fix-subagent brief:
- Git writes. Keep Git mutations within assigned files; never run
git stash, git checkout -- ., git reset, or another whole-tree command.
- Git index. Do not run
git add or otherwise change the Git index; the parent stages each group for verification.
- Git reads. Keep Git reads within assigned paths.
- Committed baseline. Read a committed baseline without changing shared state with
git show HEAD:<path>.
- Edit scope. Do not edit outside the group's approved paths.
- Expansion request. When a fix needs more files, return
{ needs_scope_expansion: true, additional_files: [paths], justification: string } before editing them.
- Expansion decision. Use
AskUserQuestion with "Approve expanded scope", "Reject — fix within original scope only", and "Defer this finding"; recommend approval with the justification and file list.
- Approved expansion. After approval, add the files to verification, regroup any overlapping findings, and re-dispatch the fixer.
- Test failures. For a test failure, inspect the code and test, decide which is wrong, and fix that side.
Staging safety
Apply this check to each group in each round:
- Snapshot. Before dispatching the fixer, record
git diff --staged --binary -- <group's approved artifact paths>.
- Detect index changes. After the fixer returns, compare the staged diff with the snapshot. On mismatch, report the change and ask how to proceed; do not stage over it.
- Validate paths. Confirm every path in
files_changed belongs to the group's approved artifact paths. On mismatch, report the out-of-scope paths and ask how to proceed; do not stage them.
- Check existing hunks. When the snapshot contains hunks in
files_changed, proceed only if every hunk belongs to an earlier resolved finding in this invocation or exactly matches this group's recorded earlier attempt. Otherwise, inspect the hunks and ask the user:
- Small unrelated hunks without line overlap → recommend "Commit pre-existing first".
- Large, sprawling, or overlapping hunks → recommend "Stash pre-existing".
- Hunks that continue the fix → recommend "Proceed (treat as part of this fix)".
- Use
AskUserQuestion with those three options, put the recommendation first with (Recommended), and summarize the hunks in one line.
- Stage. After the checks pass, run
git add <files_changed> for one group at a time. Record the exact path-scoped staged binary diff for the group's next round.
Round 1 — Fix + Verify
Fix. Apply staging-safety Step 1, then spawn one fix subagent per conflict group with every finding, approved path, and violated criterion in that group. It edits the working tree and returns { files_changed: [paths], summary: string, finding_summaries: [{ id: Finding.id, summary: string }], concerns: [string] | null }.
Stage. Apply staging-safety Steps 2–5 without committing.
Verify. Dispatch the group's findings in related batches of at most four. Each verifier receives:
- Artifact: the exact staged diff captured for the group's files after staging
- Findings: every finding in its verification batch
- Criteria: "Is each finding resolved?" and no broader review
- Output contract: a
ReviewOutput envelope with one verdict per finding
Decide. Map each finding's verdict independently:
| Verdict |
Action |
confirmed |
Still P0/P1 → proceed to Round 2. |
rejected |
Add to resolved → done. |
demoted to P0/P1 |
Proceed to Round 2. |
demoted to P2/P3 |
Add to demoted → done. |
| Inconclusive — crash, malformed output, or no verdict for this finding |
Count the attempt → proceed to Round 2. |
Round 2 — Fix + Verify
Regroup the P0/P1 findings that survive Round 1 using the same conflict test. Proven-disjoint groups may enter Round 2 while other groups finish Round 1.
Fix. Apply staging-safety Step 1, then spawn one fixer per surviving group with each finding's Round 1 attempt, failure reason, and verifier evidence. Use the Round 1 return shape.
Stage. Apply staging-safety Steps 2–5 without committing.
Verify. Use the Round 1 verification dispatch for the surviving findings.
Decide. Map each finding's verdict independently:
| Verdict |
Action |
confirmed |
Add to escalated → escalate. |
rejected |
Add to resolved → done. |
demoted to P0/P1 |
Add to escalated → escalate. |
demoted to P2/P3 |
Add to demoted → done. |
| Inconclusive |
Count the attempt, add to escalated, and escalate. |
Escalation
For each finding still unresolved after Round 2:
After all findings are processed, return a FixVerifyLoopOutput envelope. Set files_changed to the deduplicated validated paths whose fix-loop changes remain staged.
Output Schema
FixVerifyLoopOutput
The skill returns this envelope after all findings are processed:
{
files_changed: [string, ...], // validated paths with fix-loop changes still staged
resolved: [Finding.id, ...], // fixed in R1 or R2
escalated: [{ // could not be fixed in 2 attempts
id: Finding.id,
attempts: [string, string], // R1 + R2 summaries
evidence: string | null, // verifier's evidence (null if R2 was inconclusive)
staged_summary: string // e.g., "R2's changes to auth.js, +12/-4 lines"
}, ...],
dropped: [{ // pre-gate verifier rejected as not-real
id: Finding.id,
reason: string // verifier's rejection evidence
}, ...],
demoted: [{ // demoted to P2/P3 (out of scope)
id: Finding.id,
new_severity: "P2" | "P3",
evidence: string // verifier's demotion reasoning
}, ...]
}
Finding
Finding {
id: sequential number starting from 1,
severity: "P0" | "P1" | "P2" | "P3",
title: short title,
body: detailed explanation with evidence,
file: file path or null for global issues,
line_start: number or null,
line_end: number or null,
confidence: 0.0-1.0,
criterion: what was violated,
verdict: "confirmed" | "demoted" | "rejected" | null,
validated_by: "reviewer" | "verifier" | "machine" | null,
evidence: reasoning for verdict | null
}
ReviewOutput
Findings are wrapped in a ReviewOutput envelope:
ReviewOutput {
schema_version: "v1",
findings: Finding[],
checks_run: string[]
}
Severity calibration
- P0 — Must fix: breaks functionality, security breach, data loss, or violates criteria
- P1 — Fix before shipping: correct but incomplete, fragile, or reliability risk
- P2 — Should fix: quality issue, code smell, not blocking
- P3 — Nice to have: observation, style, minor improvement
Field notes
confidence — 1.0 means certain, below 0.5 means you're guessing. Be honest.
criterion — required for P0/P1 findings. Name the specific criterion violated.
verdict — initial reviewers set null; verifiers populate it after adjudication. A caller may set confirmed when routing an observed failure with honest validated_by and evidence values.
validated_by — reviewer means initial review only; verifier means independent verification; machine requires the exact check and observed failure. Missing or null means unverified.
- A machine result proves only the observed failure, not an inferred cause.
evidence — reasoning or an exact observed result supporting the verdict; use null before adjudication.
checks_run — list every criterion evaluated, file path checked, or acceptance criterion verified. For ACs, use AC-NNN-XX: PASS — [evidence] or AC-NNN-XX: FAIL — [reason].
1---2name: fix-verify-loop3description: Resolve confirmed P0/P1 findings in at most two fix-and-verify attempts, then escalate. TRIGGER when: review findings or test failures need resolution; user says 'fix these findings' or 'resolve the P0s'. Per-finding resolution only; the caller owns regressions.4---56# Fix-Verify Loop78Leave fixes staged and return their paths plus one outcome per finding.910The caller owns regression detection, new-issue discovery, and whole-diff review.1112## Verification scope1314- **Focused checks:** Fixers and verifiers run the narrowest check that proves the assigned finding, plus directly affected tests.15- **Broad suites:** Run a subsystem or full-project suite inside this loop only for shared test infrastructure, order dependence, or a finding reproducible only in that suite; the caller owns every other broad gate.16- **Harness exits:** After test bodies pass, retry a harness that fails to exit only when a new hypothesis distinguishes the rerun.1718## Protocol1920### Input2122- **Findings:** Confirmed P0/P1 findings conforming to the [Output Schema](#output-schema).23- **Artifact paths:** Files the resolver may edit.24- **Criteria:** Original requirements each fix must satisfy.2526**Intake filter:** Process only findings with `verdict = "confirmed"` and `severity in ["P0", "P1"]`. The caller owns confirmation quality; finding source does not affect intake. Leave P2/P3 findings with the caller.2728**Pre-gate:** Route each finding by `validated_by` before mutation; treat a missing field as `null`.2930| `validated_by` | Action |31|---|---|32| `null` or `reviewer` | Independently verify. |33| `verifier` | Skip the pre-gate. |34| `machine` | Skip only when `evidence` names the exact check and observed failure, and the finding states only what that result proves; otherwise verify. |3536Confidence measures certainty; it never changes this routing.3738Complete the pre-gate for findings that require independent verification before any mutation; skipped findings proceed directly to Round 1:39401. **Batch.** Group those findings by shared files, symbols, call chains, or reported root cause. Put at most four findings in each batch.412. **Dispatch.** Run up to four `verifier` agents concurrently and queue the rest. Repository rules that forbid overlapping checks override this limit. Give each verifier:42 - **Artifact**: the files or surrounding context for its batch.43 - **Findings**: every finding in its batch.44 - **Criteria**: "Is each finding real?"45 - **Output contract**: a `ReviewOutput` envelope with one verdict per finding.463. **Collect.** Wait for every batch before Round 1. A missing or unparseable verdict makes only that finding inconclusive.474. **Route.** Route each finding independently:48 - `rejected` → add to `dropped` and skip the fix loop.49 - `confirmed` → proceed to Round 1.50 - `demoted` to P0/P1 → proceed to Round 1.51 - `demoted` to P2/P3 → add to `demoted` and skip the fix loop.52 - inconclusive → proceed to Round 1 without consuming a fix attempt.5354### Conflict-group loop5556Group surviving findings by shared files, symbols, call chains, tests, mutable artifacts, behavior, or root cause. Keep groups to four findings unless one root cause cannot split safely.5758- **Fix in parallel.** Run one fixer per group. Dispatch every proven-disjoint group concurrently up to agent capacity; queue known or uncertain overlap. Repository concurrency rules override dispatch.59- **Verify in parallel.** Verify a completed group while unrelated fixers continue. Give each verifier up to four related findings, and run verifier batches concurrently unless their checks share mutable resources or repository rules forbid overlap. Wait when an active fixer could affect the files, behavior, or checks under verification.60- **Account separately.** Keep each finding's verdict, attempt count, bucket, and escalation state independent even when one fixer or verifier handles the group.61- **Stage serially.** The parent stages one group at a time. Fixers never stage files.6263Give each finding at most two attempts. Proven-disjoint groups may occupy different rounds concurrently.6465Include these rules in every fix-subagent brief:6667- **Git writes.** Keep Git mutations within assigned files; never run `git stash`, `git checkout -- .`, `git reset`, or another whole-tree command.68- **Git index.** Do not run `git add` or otherwise change the Git index; the parent stages each group for verification.69- **Git reads.** Keep Git reads within assigned paths.70- **Committed baseline.** Read a committed baseline without changing shared state with `git show HEAD:<path>`.71- **Edit scope.** Do not edit outside the group's approved paths.72- **Expansion request.** When a fix needs more files, return `{ needs_scope_expansion: true, additional_files: [paths], justification: string }` before editing them.73- **Expansion decision.** Use `AskUserQuestion` with "Approve expanded scope", "Reject — fix within original scope only", and "Defer this finding"; recommend approval with the justification and file list.74- **Approved expansion.** After approval, add the files to verification, regroup any overlapping findings, and re-dispatch the fixer.75- **Test failures.** For a test failure, inspect the code and test, decide which is wrong, and fix that side.7677### Staging safety7879Apply this check to each group in each round:80811. **Snapshot.** Before dispatching the fixer, record `git diff --staged --binary -- <group's approved artifact paths>`.822. **Detect index changes.** After the fixer returns, compare the staged diff with the snapshot. On mismatch, report the change and ask how to proceed; do not stage over it.833. **Validate paths.** Confirm every path in `files_changed` belongs to the group's approved artifact paths. On mismatch, report the out-of-scope paths and ask how to proceed; do not stage them.844. **Check existing hunks.** When the snapshot contains hunks in `files_changed`, proceed only if every hunk belongs to an earlier resolved finding in this invocation or exactly matches this group's recorded earlier attempt. Otherwise, inspect the hunks and ask the user:85 - Small unrelated hunks without line overlap → recommend "Commit pre-existing first".86 - Large, sprawling, or overlapping hunks → recommend "Stash pre-existing".87 - Hunks that continue the fix → recommend "Proceed (treat as part of this fix)".88 - Use `AskUserQuestion` with those three options, put the recommendation first with `(Recommended)`, and summarize the hunks in one line.895. **Stage.** After the checks pass, run `git add <files_changed>` for one group at a time. Record the exact path-scoped staged binary diff for the group's next round.9091### Round 1 — Fix + Verify92931. **Fix.** Apply staging-safety Step 1, then spawn one fix subagent per conflict group with every finding, approved path, and violated criterion in that group. It edits the working tree and returns `{ files_changed: [paths], summary: string, finding_summaries: [{ id: Finding.id, summary: string }], concerns: [string] | null }`.942. **Stage.** Apply staging-safety Steps 2–5 without committing.953. **Verify.** Dispatch the group's findings in related batches of at most four. Each verifier receives:96 - **Artifact**: the exact staged diff captured for the group's files after staging97 - **Findings**: every finding in its verification batch98 - **Criteria**: "Is each finding resolved?" and no broader review99 - **Output contract**: a `ReviewOutput` envelope with one verdict per finding1004. **Decide.** Map each finding's verdict independently:101102 | Verdict | Action |103 |---|---|104 | `confirmed` | Still P0/P1 → **proceed to Round 2**. |105 | `rejected` | Add to `resolved` → **done**. |106 | `demoted` to P0/P1 | **Proceed to Round 2**. |107 | `demoted` to P2/P3 | Add to `demoted` → **done**. |108 | Inconclusive — crash, malformed output, or no verdict for this finding | Count the attempt → **proceed to Round 2**. |109110### Round 2 — Fix + Verify111112Regroup the P0/P1 findings that survive Round 1 using the same conflict test. Proven-disjoint groups may enter Round 2 while other groups finish Round 1.1131141. **Fix.** Apply staging-safety Step 1, then spawn one fixer per surviving group with each finding's Round 1 attempt, failure reason, and verifier evidence. Use the Round 1 return shape.1152. **Stage.** Apply staging-safety Steps 2–5 without committing.1163. **Verify.** Use the Round 1 verification dispatch for the surviving findings.1174. **Decide.** Map each finding's verdict independently:118119 | Verdict | Action |120 |---|---|121 | `confirmed` | Add to `escalated` → **escalate**. |122 | `rejected` | Add to `resolved` → **done**. |123 | `demoted` to P0/P1 | Add to `escalated` → **escalate**. |124 | `demoted` to P2/P3 | Add to `demoted` → **done**. |125 | Inconclusive | Count the attempt, add to `escalated`, and **escalate**. |126127### Escalation128129For each finding still unresolved after Round 2:130- **Stop.** Do not attempt Round 3 for this finding.131- Present its `finding_summaries` entries in this shape; derive the staged line with `git diff --staged --stat -- <files_changed>`:132 ```133 **Escalated — finding not resolved after 2 attempts:**134 - Finding: [ID — title]135 - Attempted: [Round 1 summary] → [Round 2 summary]136 - Still unresolved: [verifier's evidence | verifier inconclusive]137 - Currently staged: [e.g. "R2's changes to auth.js, +12/-4 lines" | nothing staged]138 ```139 Then use `AskUserQuestion` with "Manual fix", "Try a different approach", "Defer this finding", and "Discard R2 changes and revert"; recommend "Defer this finding".140141After all findings are processed, return a [`FixVerifyLoopOutput`](#fixverifyloopoutput) envelope. Set `files_changed` to the deduplicated validated paths whose fix-loop changes remain staged.142143---144145## Output Schema146147### FixVerifyLoopOutput148149The skill returns this envelope after all findings are processed:150151```152{153 files_changed: [string, ...], // validated paths with fix-loop changes still staged154 resolved: [Finding.id, ...], // fixed in R1 or R2155 escalated: [{ // could not be fixed in 2 attempts156 id: Finding.id,157 attempts: [string, string], // R1 + R2 summaries158 evidence: string | null, // verifier's evidence (null if R2 was inconclusive)159 staged_summary: string // e.g., "R2's changes to auth.js, +12/-4 lines"160 }, ...],161 dropped: [{ // pre-gate verifier rejected as not-real162 id: Finding.id,163 reason: string // verifier's rejection evidence164 }, ...],165 demoted: [{ // demoted to P2/P3 (out of scope)166 id: Finding.id,167 new_severity: "P2" | "P3",168 evidence: string // verifier's demotion reasoning169 }, ...]170}171```172173<!-- source: references/finding-schema.md#output-schema -->174175### Finding176177```178Finding {179 id: sequential number starting from 1,180 severity: "P0" | "P1" | "P2" | "P3",181 title: short title,182 body: detailed explanation with evidence,183 file: file path or null for global issues,184 line_start: number or null,185 line_end: number or null,186 confidence: 0.0-1.0,187 criterion: what was violated,188 verdict: "confirmed" | "demoted" | "rejected" | null,189 validated_by: "reviewer" | "verifier" | "machine" | null,190 evidence: reasoning for verdict | null191}192```193194### ReviewOutput195196Findings are wrapped in a `ReviewOutput` envelope:197198```199ReviewOutput {200 schema_version: "v1",201 findings: Finding[],202 checks_run: string[]203}204```205206### Severity calibration207208- **P0** — Must fix: breaks functionality, security breach, data loss, or violates criteria209- **P1** — Fix before shipping: correct but incomplete, fragile, or reliability risk210- **P2** — Should fix: quality issue, code smell, not blocking211- **P3** — Nice to have: observation, style, minor improvement212213### Field notes214215- `confidence` — 1.0 means certain, below 0.5 means you're guessing. Be honest.216- `criterion` — required for P0/P1 findings. Name the specific criterion violated.217- `verdict` — initial reviewers set `null`; verifiers populate it after adjudication. A caller may set `confirmed` when routing an observed failure with honest `validated_by` and `evidence` values.218- `validated_by` — `reviewer` means initial review only; `verifier` means independent verification; `machine` requires the exact check and observed failure. Missing or `null` means unverified.219- A machine result proves only the observed failure, not an inferred cause.220- `evidence` — reasoning or an exact observed result supporting the verdict; use `null` before adjudication.221- `checks_run` — list every criterion evaluated, file path checked, or acceptance criterion verified. For ACs, use `AC-NNN-XX: PASS — [evidence]` or `AC-NNN-XX: FAIL — [reason]`.222223<!-- /source: references/finding-schema.md#output-schema -->