pi-gauntlet 6.0.1 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## v6.1.0 - 2026-09-30
4
+
5
+ ### Changed
6
+
7
+ - Minor code-review findings ride along in a `FIX_FIRST` fix round and never trigger one; a `SHIP` report ends the loop whatever Minors it lists. The whole-diff review's Minors land in the closure block as `whole-diff minors:` and the finish gate offers a one-shot `fix minors` reply. Re-reviews are scoped to a `## Fix delta` block (the whole-diff review and its re-reviews stay unscoped): a new finding outside it blocks only when Critical; `TRAJECTORY:` counts Critical and Moderate only. Telemetry counts `[Critical]`/`[Moderate]` into `blocker`/`major`. (#56)
8
+
3
9
  ## v6.0.1 - 2026-09-30
4
10
 
5
11
  ### Changed
@@ -59,6 +59,7 @@ Rules:
59
59
  - Verify before praising: no "looks good" on code you did not read.
60
60
  - Report only on code you read.
61
61
  - Name the concrete change in every Fix; "improve error handling" is not a Fix.
62
+ - On a re-review (the task carries `## Previous review report (re-review trigger)`): confirm each prior finding is resolved, then review the `## Fix delta` block, reading surrounding code as needed. A new finding outside that delta is Critical, or it is `[Minor]` with the note `(outside fix delta)`. No `## Fix delta` block -> the task's whole diff is the delta. The whole-diff review and its re-reviews are never scoped.
62
63
 
63
64
  Label every finding with a globally unique `F1..Fn` ID (no restart per severity),
64
65
  and a `touched-files:`/`touched-resources:` pair (files a fix would edit, not only
@@ -147,7 +147,7 @@ Footer order: `Parallel-safe:` is the final line of the report.
147
147
  - **Read-only. Never edit.** You audit; you do not fix.
148
148
  - **Propose, do not dispose.** For each gap you may suggest a one-line remediation *direction*, but you do **not** decide the disposition - the orchestrator auto-applies `fix` gaps and defers `accept`/`rescope` gaps to the user at the finish gate (an `UNAUTHORIZED` row follows its `recommended` value like every other verdict). Never present a fix as a decision you made.
149
149
  - **Evidence or it didn't happen.** Cite a real `file:line` for every DELIVERED/PARTIAL. If you cannot, downgrade the row to MISSING.
150
- - **Origin quote or it isn't a gap.** Every non-UNAUTHORIZED gap's `origin` carries a locator AND a verbatim quote: `origin: <file/section, 'prompt', or 'ticket'> - "<quoted clause>"` (truncate long clauses with `[...]` as long as the fragment uniquely identifies the clause). No quotable origin clause = no gap. Do not derive implicit requirements. Do not flag wording preferences. A deviation recorded in the spec wins over an older origin value (Process step 2); report it only if unrecorded.
150
+ - **Origin quote or it isn't a gap.** Every non-UNAUTHORIZED gap's `origin` carries a locator AND a verbatim quote: `origin: <file/section, 'prompt', or 'ticket'> - "<quoted clause>"` (truncate long clauses with `[...]` as long as the fragment uniquely identifies the clause). No quotable origin clause = no gap. Do not derive implicit requirements. Do not flag wording preferences. A code-review finding - style, naming, comment, micro-efficiency - with no origin clause is never a gap, whatever its severity. A deviation recorded in the spec wins over an older origin value (Process step 2); report it only if unrecorded.
151
151
  - **Spec is canonical; the prompt catches what the spec dropped; the ticket is fallback only** when no spec exists.
152
152
  - **The spec's `## Acceptance criteria` section is origin, not ticket.** Its `in-scope`/`venue:` rows are `Rn`; its `deviates:`/`deferred:` rows are recorded drift (`recorded in spec? yes`).
153
153
  - **Do not absorb origin drift silently** — flag every spec↔prompt/ticket disagreement.
@@ -54,8 +54,8 @@ derived:
54
54
  worker: { dispatches: 3, models: [m/beta] }
55
55
  spec-council-member: { dispatches: 4, models: [m/alpha] }
56
56
  reviews:
57
- spec-reviewer: { dispatches: 1, nonzero_exit: 0, findings: { blocker: 1, major: 2, minor: 3 } }
58
- code-reviewer: { dispatches: 1, nonzero_exit: 0 }
57
+ spec-reviewer: { dispatches: 1, nonzero_exit: 0 }
58
+ code-reviewer: { dispatches: 1, nonzero_exit: 0, findings: { blocker: 1, major: 2, minor: 3 } }
59
59
  conformance_loops: 2
60
60
  conformance_open_gaps: 0
61
61
  gates: { spec_rounds: 1, plan_rounds: 1, fix_round_grants: 1, task_reopens: 0, ship_option: squash }
@@ -211,8 +211,8 @@ test("malformed reviewer entries and findings objects contribute null counters",
211
211
  'findings: "bad"',
212
212
  );
213
213
  const malformedReviewer = COMPLETE.replace(
214
- "spec-reviewer: { dispatches: 1, nonzero_exit: 0, findings: { blocker: 1, major: 2, minor: 3 } }",
215
- 'spec-reviewer: "bad"',
214
+ "code-reviewer: { dispatches: 1, nonzero_exit: 0, findings: { blocker: 1, major: 2, minor: 3 } }",
215
+ 'code-reviewer: "bad"',
216
216
  );
217
217
  write(root, `${TDIR}/malformed-findings-object.yaml`, malformedFindings);
218
218
  write(root, `${TDIR}/malformed-reviewer.yaml`, malformedReviewer.replace(
@@ -16,6 +16,12 @@ test("countFindings tallies [blocker]/[major]/[minor] tags; none -> undefined",
16
16
  assert.equal(countFindings("all good"), undefined);
17
17
  });
18
18
 
19
+ test("countFindings aliases persona tags [Critical]/[Moderate]/[Minor] onto blocker/major/minor", () => {
20
+ const report = "[Critical] F1: a\n[Moderate] F2: b\n[Moderate] F3: c\n[Minor] F4: d\n[Minor] F5: e\n[Minor] F6: f";
21
+ assert.deepEqual(countFindings(report), { blocker: 1, major: 2, minor: 3 });
22
+ assert.deepEqual(countFindings("[Critical] x\n[blocker] y\n[MODERATE] z"), { blocker: 2, major: 1, minor: 0 });
23
+ });
24
+
19
25
  test("countOpenGaps returns the latest conformance result's open gap count", () => {
20
26
  assert.equal(countOpenGaps("Conformance verdict: CONFORMS"), 0);
21
27
  assert.equal(countOpenGaps("Conformance verdict: GAPS\nG1:\n verdict: MISSING\nG2:\n verdict: PARTIAL\nG1:\n evidence: repeated"), 2);
@@ -11,12 +11,14 @@ export function usageToTokens(u: unknown): Tokens | undefined {
11
11
  return t.input || t.output || t.cache_read || t.cache_write || t.cost ? t : undefined;
12
12
  }
13
13
 
14
- const FINDING_TAG_RE = /\[(blocker|major|minor)\]/gi;
14
+ const FINDING_TAG_RE = /\[(critical|blocker|moderate|major|minor)\]/gi;
15
+ // Persona tags alias onto the persisted keys; the schema and gauntlet-performance stay on blocker/major/minor.
16
+ const FINDING_KEY: Record<string, "blocker" | "major" | "minor"> = { critical: "blocker", blocker: "blocker", moderate: "major", major: "major", minor: "minor" };
15
17
  export function countFindings(text: string): { blocker: number; major: number; minor: number } | undefined {
16
18
  const out = { blocker: 0, major: 0, minor: 0 };
17
19
  let any = false;
18
20
  for (const m of text.matchAll(FINDING_TAG_RE)) {
19
- out[m[1].toLowerCase() as keyof typeof out] += 1;
21
+ out[FINDING_KEY[m[1].toLowerCase()]] += 1;
20
22
  any = true;
21
23
  }
22
24
  return any ? out : undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "6.0.1",
3
+ "version": "6.1.0",
4
4
  "description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
5
5
  "author": "Jacek Juraszek",
6
6
  "type": "module",
@@ -111,7 +111,7 @@ When agents return:
111
111
 
112
112
  Fix rounds in review loops reuse the fan-out mechanics above, keyed off the reviewer's partition certificate — the orchestrator never partitions findings itself.
113
113
 
114
- Reviewers certify fix concurrency with a `Parallel-safe:` line (see the reviewer's report contract). The fan-out trigger is a `disjoint` group naming **≥ 2 finding IDs**: that group IS the parallel wave — dispatch **one `implementer` per finding ID in the group** (`context: "fresh"`, `worktree: true`, `cwd` = the current worktree; task = that finding's block **verbatim**, including its `touched-files` line as the ownership boundary). A finding named in any `conflicts` pair runs sequentially after every finding it names has integrated (chained `conflicts` define a partial order; remaining serial findings run in the line's order). Findings outside any ≥ 2-ID `disjoint` group run sequentially. Fan out per review line only — never merge or co-schedule groups from different `Parallel-safe:` lines; run those fan-outs serially.
114
+ Reviewers certify fix concurrency with a `Parallel-safe:` line (see the reviewer's report contract). The fan-out trigger is a `disjoint` group naming **≥ 2 actionable finding IDs**: that group IS the parallel wave — dispatch **one `implementer` per actionable finding ID in the group (the probe's actionable set; the consuming loop places non-actionable findings)** (`context: "fresh"`, `worktree: true`, `cwd` = the current worktree; task = that finding's block **verbatim**, including its `touched-files` line as the ownership boundary). An actionable finding named in any `conflicts` pair runs sequentially after every finding it names has integrated (chained `conflicts` define a partial order; remaining serial findings run in the line's order). Actionable findings outside any ≥ 2-ID `disjoint` group run sequentially. Fan out per review line only — never merge or co-schedule groups from different `Parallel-safe:` lines; run those fan-outs serially.
115
115
 
116
116
  **Precondition:** a clean committed HEAD containing the code under review. When the reviewed change is an unintegrated patch (a wave-mode per-patch spec review), each fix task branches from the wave's base HEAD and carries the prior patch verbatim in its task text — the consuming loop's existing re-dispatch protocol. When the tree is dirty (e.g. post-integration, before the wave commit), the fan-out is unavailable: fix sequentially in place.
117
117
 
@@ -82,7 +82,9 @@ This is an **enforced disposition gate**, not a surface-only notice. The user is
82
82
 
83
83
  **Freshness precondition - before any verdict branch, including `CONFORMS`.** The durable block opens with a sentinel: `status: CONFORMS (0 open)` or `status: GAPS (N open)`, then `audited-base: <full HEAD SHA at audit time>`, then an optional `happy-path: <outcome>` line (present exactly when a happy-path run happened; informational, never a freshness input). Read the sentinel, then apply the reference's freshness rule (its `## Closure / conformance` block is the single source): compare `audited-base` to the current working tree; any change, doubt, missing/mismatched sentinel, legacy terse row, or malformed structured reviewer block triggers a fresh audit and replacement of the closure block. Never infer `CONFORMS` from the absence of bullets. Only a clean, valid `status: CONFORMS (0 open)` handoff enters the zero-gap fast path.
84
84
 
85
- **Zero-gap fast path:** print exactly
85
+ **Whole-diff minors (both paths).** Read the block's `whole-diff minors:` section (`conformance-check.md` "Closure / conformance") and render it as one informational, non-blocking line in the `happy-path:` position - directly under the `happy-path:` line when present, otherwise directly under `Closure / conformance: CONFORMS` or the `Conformance: N decisions needed before shipping.` header: `whole-diff minors (3, not blocking): F3, F7, F9`, `whole-diff minors: none`, or `whole-diff minors: not recorded` (section absent). Never a re-audit trigger. The reply point is the Step 4 menu.
86
+
87
+ **Zero-gap fast path:** print (plus the informational lines below)
86
88
 
87
89
  ```
88
90
  Closure / conformance: CONFORMS
@@ -177,7 +179,9 @@ Which option?
177
179
 
178
180
  Rows 1-2 run the Option 1/2 blocks; row 3 runs the Keep block and row 4 the Discard block.
179
181
 
180
- **Don't add explanation** - keep options concise.
182
+ **Don't add explanation** - keep options concise. When the minors line lists findings and the block has no `whole-diff minors fix:` line, add only this line under the menu: `Or reply "fix minors" (or "fix minors F3, F9") for one Minor fix round.` This line is the only addition to the exact numbered options.
183
+
184
+ **Standalone extra reply - `fix minors`.** When the rendered `whole-diff minors` line lists findings, `fix minors` (all) or `fix minors F3, F9` (a subset by `Fn`) is a valid reply beside the numbered options. It dispatches one `implementer` round (`cwd` = the worktree; task = the selected finding lines verbatim; `SCOPED_TEST_COMMANDS` = the plan-header verification set), commits `whole-diff minors fix`, and returns to Step 3.5, where the freshness rule re-audits conformance as for any working-tree change and the regenerated block records the spent round (`whole-diff minors fix: <full SHA>`); Step 4 then re-renders. No code review follows this round: the whole-diff review is an unscoped first review, so its Minors are graded Minors. A block that already carries `whole-diff minors fix:` refuses the reply with "minors round already spent". Any numbered choice ships without them.
181
185
 
182
186
  ### Step 5: Execute Choice
183
187
 
@@ -51,9 +51,11 @@ subagent({ agent: "code-reviewer", async: false, task: "... filled template ..."
51
51
  - `{DESCRIPTION}` - Brief summary
52
52
  - `{SCOPED_TEST_COMMANDS}` - the scoped verification commands the reviewer may run, or `none`
53
53
 
54
- **Fix rounds.** Critical and Moderate findings trigger a fix round; when dispatched from an orchestrating skill, fixes go to `implementer` subagents (per the orchestrator's no-self-coding rule), fanned out per `dispatching-parallel-agents` "Fix fan-out" when the review's `Parallel-safe:` line certifies a `disjoint` group of ≥ 2 findings. Before fanning out, validate the review's `Parallel-safe:` line with the structural probe in `dispatching-parallel-agents` § Fix fan-out (exactly-one-line grammar check, one re-ask, then explicit sequential fallback). After integration and the project's test command, re-dispatch the reviewer once on the integrated delta in the foreground with top-level `async: false`; await its terminal result. If Critical or Moderate findings remain, run one more fix round and one more foreground re-review; still failing → escalate to the user. Minor findings never trigger the fan-out.
54
+ **Fix rounds.** A `FIX_FIRST` report triggers a fix round. A `SHIP` report dispatches nothing and ends the loop, whatever Minors it lists. `REJECT` is neither: stop and report (in SDD, per its `stop-note.md`); no fix round. When dispatched from an orchestrating skill, fixes go to `implementer` subagents (per the orchestrator's no-self-coding rule), fanned out per `dispatching-parallel-agents` "Fix fan-out" when the review's `Parallel-safe:` line certifies a `disjoint` group of ≥ 2 Critical/Moderate findings. Before fanning out, validate the review's `Parallel-safe:` line with the structural probe in `dispatching-parallel-agents` § Fix fan-out (exactly-one-line grammar check, one re-ask, then explicit sequential fallback). Sequential round (one task): the task carries the whole report; every Minor rides. Fan-out: the certificate partitions the Critical and Moderate findings; each Minor attaches once to the first task, in `Fn` order, whose ownership boundary - the union of its findings' `touched-files:` - already contains the Minor's `touched-files:`; a Minor no boundary contains is not dispatched this round, and a boundary never grows for a Minor. The implementer fixes its Minors or declines one with a stated reason. After integration and the project's test command, re-dispatch the reviewer once on the integrated delta in the foreground with top-level `async: false`; await its terminal result. A `FIX_FIRST` re-review buys one more fix round and one more foreground re-review; still `FIX_FIRST` -> escalate to the user. A `SHIP` report's Minors are not carried, with one exception: the whole-diff review's Minor finding lines go verbatim into the closure block's `whole-diff minors:` section (`verification-before-completion/reference/conformance-check.md` "Closure / conformance").
55
55
 
56
- Take the recipient stance from `receiving-code-review`: verify each finding, answer a wrong finding with evidence, defer Minor items explicitly.
56
+ Worked example: a `FIX_FIRST` report with 1 Moderate and 3 Minors -> one implementer task holding all four findings (one actionable ID, no fan-out). A `SHIP` report with 4 Minors -> no dispatch; the loop ends.
57
+
58
+ Take the recipient stance from `receiving-code-review`: verify each finding, answer a wrong finding with evidence.
57
59
 
58
60
  ## Integration with Workflows
59
61
 
@@ -62,7 +62,7 @@ For each task in `plan_tracker`:
62
62
  3. **Dispatch spec reviewer.** Pass the task text, the patch diff, the absolute spec path, and the task's `**Spec:**` anchors, plus the task's `**Tests:**` block and `- Test:` paths as contract (never as commands - SR never executes) — SR reads the anchored ranges from the spec file itself; never inline spec excerpts. The spec wins every dispute; the authority hierarchy and finding labels live in `./spec-reviewer-prompt.md`. Anchor-less tasks (no `**Spec:**` line): task text alone is the contract. Verify the change satisfies the anchored spec — nothing missing, nothing extra.
63
63
  4. If spec reviewer finds gaps → re-dispatch implementer to fix → re-review. Loop until ✅, within [Fix-Loop Rounds](#fix-loop-rounds).
64
64
  5. **Dispatch code-quality reviewer.** Only after spec is ✅. Skip for doc-only tasks (every file in the task's `Files:` block documentation-only) — SR-only, same exemption as doc-only waves. Pass the task's `SCOPED_TEST_COMMANDS`.
65
- 6. If quality reviewer finds issues → re-dispatch implementer → re-review. Loop until ✅, within [Fix-Loop Rounds](#fix-loop-rounds).
65
+ 6. If the quality review is issue-bearing → re-dispatch the implementer per `/skill:requesting-code-review` Fix rounds → re-review. Loop until ✅, within [Fix-Loop Rounds](#fix-loop-rounds).
66
66
  7. After its existing reviews accept the work (and its required commit point), mark that same task index `complete` in `plan_tracker`. A subagent exit or green tests alone are not acceptance.
67
67
 
68
68
  The orchestrator is the spec's only writer during execution. Amendment trigger: implementer `BLOCKED` citing a spec defect, or a review finding showing the spec (not the code) is wrong -> pause the fix loop, execute brainstorming's [amendment path](../brainstorming/SKILL.md#amending-an-approved-spec) in place (it reviews first, stops only on escalation or redraw), resume. Code-vs-spec mismatch stays in the SR loop. An SR unable to read the spec at a cited anchor (missing file, unresolvable heading/range) returns a blocking finding — the contract is spec+task or stop, never a silent fallback to task-only review.
@@ -73,15 +73,15 @@ After all tasks: proceed to [After All Tasks](#after-all-tasks-complete) - it ow
73
73
 
74
74
  One rule governs both review loops - spec-compliance and code-quality - in sequential and parallel-wave modes alike.
75
75
 
76
- **Re-review dispatch rule:** every re-review task includes the complete prior review report verbatim under the marker `## Previous review report (re-review trigger)`, plus the trajectory block from the reviewer's prompt template. The marker's presence is what obligates the reviewer to emit the `TRAJECTORY:` line. You never select, summarize, or diff findings yourself - pattern-match the sentinel line only.
76
+ **Re-review dispatch rule:** every re-review task includes the complete prior review report verbatim under the marker `## Previous review report (re-review trigger)`, plus the trajectory block from the reviewer's prompt template. The marker's presence is what obligates the reviewer to emit the `TRAJECTORY:` line. You never select, summarize, or diff findings yourself - pattern-match the sentinel line only. Code re-reviews also carry a `## Fix delta` block holding the fix round just integrated: sequential mode, the output of `git diff <HEAD the prior review was dispatched against> HEAD`; wave mode (HEAD unmoved until step 7), the applied fix patch(es) verbatim, never a SHA range. Whole-diff re-reviews never carry the block. Omit it otherwise only when the input is unavailable (a fresh-session resume); the reviewer then treats the task's whole diff as the delta.
77
77
 
78
- **Fix fan-out.** When the triggering review's `Parallel-safe:` line certifies a `disjoint` group of ≥ 2 findings, dispatch that fix round per `dispatching-parallel-agents` "Fix fan-out"; the fan-out counts as **one** fix against this budget, its scoped test gate is the consuming task/wave's `SCOPED_TEST_COMMANDS`, and one re-review of the integrated delta follows.
78
+ **Fix fan-out.** When a fix round is fanned out per `/skill:requesting-code-review` Fix rounds, dispatch per `dispatching-parallel-agents` "Fix fan-out"; the fan-out counts as **one** fix against this budget, its scoped test gate is the consuming task/wave's `SCOPED_TEST_COMMANDS`, and one re-review of the integrated delta follows.
79
79
 
80
80
  **Behaviour-change reroute.** When the triggering CR report carries `Behaviour-change: yes`, the fix round's re-review is SR first, then CR. The SR dispatch reviews the fix diff against the task's spec anchors as a first review (no `## Previous review report` marker, so no `TRAJECTORY:` line; SR carries no test commands but does carry the task's `**Tests:**` block and `- Test:` paths), but its ordinal continues the task's SR-loop count - a task whose SR loop ended at review 2 gets review 3 here, and an issue-bearing rerouted SR after review 4 escalates. Issues follow the normal sequence: fix, then SR re-review pasting this SR's report. CR round numbering is unchanged. `Behaviour-change: no` re-reviews with CR only. A missing or malformed `Behaviour-change:` line is re-asked once like `Parallel-safe:` (see `dispatching-parallel-agents` "Structural probe"); still missing -> route through SR, never default to `no`. In wave mode the SR re-review targets the task(s) whose files the fix touched.
81
81
 
82
82
  Every fix re-dispatch (implementer) and code-review re-review carries the consuming task/wave's `SCOPED_TEST_COMMANDS`; spec-reviewer re-reviews carry the `**Tests:**` block and `- Test:` paths, no commands - SR never executes.
83
83
 
84
- **The sequence.** Each review that finds issues is a decision point: read the `TRAJECTORY:` line before dispatching anything (review 1 has no line - on issues, dispatch fix 1). Any clean review ends the loop.
84
+ **The sequence.** Each review that finds issues is a decision point: read the `TRAJECTORY:` line before dispatching anything (review 1 has no line - on issues, dispatch fix 1). Any clean review ends the loop. For code review, *issue-bearing* means verdict `FIX_FIRST` and *clean* means verdict `SHIP`, whatever Minors the report lists; spec review keeps its gaps/acceptance meaning. `REJECT` is neither: stop and report per `stop-note.md`; the loop never enters.
85
85
 
86
86
  1. **Review 1** (first review - no sentinel). Issues -> dispatch fix 1.
87
87
  2. **Review 2** (re-review). Issues -> if `STAGNANT`, escalate now - no fix 2. Otherwise dispatch fix 2.
@@ -170,7 +170,7 @@ Auto-selected at handoff by `writing-plans` (any wave with ≥2 tasks) when the
170
170
  3. **Status + spec review per task.** Parse each `DONE`/`BLOCKED`/etc. (see [Implementer Status](#implementer-status)) **first**. Then **dispatch a `spec-reviewer` per accepted patch** (`DONE`, or a `DONE_WITH_CONCERNS` you proceeded with) in one parallel fan-out — `context: "fresh"`, `cwd: <this worktree>`, **no `worktree` flag** (read-only) — each passed its task text, the returned **patch diff**, the absolute spec path, and the task's `**Spec:**` anchors, plus its `**Tests:**` block and `- Test:` paths as contract — SR reads the anchored ranges itself (never inline excerpts; authority hierarchy in `./spec-reviewer-prompt.md`; anchor-less tasks are task-text-only). Review starts from the diff (its hunks carry `file:line`) and reads each touched file in full, and test execution is never the reviewer's job - in either mode (persona rule; the wave test gate in step 5 runs the wave's `SCOPED_TEST_COMMANDS`). Inline verdicts are fine at normal wave sizes; large waves use `output:` + `outputMode: "file-only"` to keep verdicts out of your context. **Re-dispatch by cause:** `BLOCKED`/`NEEDS_CONTEXT` per the [Implementer Status](#implementer-status) matrix; a **spec gap** re-dispatches the implementer (fresh, `worktree: true`) carrying the prior patch + the reviewer's findings, the new patch superseding the old at step 4. Loop until accepted + spec ✅, within [Fix-Loop Rounds](#fix-loop-rounds), same as sequential.
171
171
  4. **Integrate.** `git -C <worktree> apply` each task's patch sequentially onto HEAD. Apply fails = textual conflict → drop that task, finish the rest, re-run the dropped task sequentially on the updated HEAD.
172
172
  5. **Test gate.** Run the wave's `SCOPED_TEST_COMMANDS` (union of its tasks' `Tests:` commands) on the integrated tree as `(cd "<worktree>" && <command>)` for each command — the full verification set is the verify phase's job, run once. Failure = semantic conflict or bug → re-run the offending task sequentially, else fix per [When a Subagent Fails](#when-a-subagent-fails).
173
- 6. **Quality review.** CR binds to the wave: exactly one **initial** code-review dispatch per code-touching wave, over the integrated wave diff - never per task within a wave, never batched across waves. Subsequent dispatches within the wave are re-reviews triggered only by findings, per Fix-Loop Rounds. Pass the wave's `SCOPED_TEST_COMMANDS`. Code-quality review on the integrated wave diff; loop fixes to ✅ within [Fix-Loop Rounds](#fix-loop-rounds), same as sequential. Skip for doc-only waves (SR-only per the commit precondition below).
173
+ 6. **Quality review.** CR binds to the wave: exactly one **initial** code-review dispatch per code-touching wave, over the integrated wave diff - never per task within a wave, never batched across waves. Subsequent dispatches within the wave are re-reviews triggered only by findings, per Fix-Loop Rounds. Pass the wave's `SCOPED_TEST_COMMANDS`. Code-quality review on the integrated wave diff; when issue-bearing, re-dispatch the implementer per `/skill:requesting-code-review` Fix rounds and re-review, to ✅ within [Fix-Loop Rounds](#fix-loop-rounds), same as sequential. Skip for doc-only waves (SR-only per the commit precondition below).
174
174
  7. **Commit and complete the wave.** After the gate passes, commit with `git -C <worktree> add ... && git -C <worktree> commit ...`, then mark all of its existing indices `complete`. Leaves a clean tree; the next wave's children branch from this commit and so see the integrated work.
175
175
 
176
176
  **Two-stage review is preserved:** spec review per task (pre-integration, dispatched `spec-reviewer` — not inline), quality review per wave (post-integration). A wave commit requires one spec-review verdict per accepted task, plus one code-review verdict on the integrated diff for waves that touch code. A doc-only wave (every task's `Files:` block documentation-only, per `writing-plans`' Wave Grouping) is SR-only — the CR gate does not apply.
@@ -221,7 +221,7 @@ For the fan-out + worktree + patch-integration + conflict mechanics, see `dispat
221
221
 
222
222
  0. Call `phase_tracker({ action: "start", phase: "verify" })`. (The `implement` phase was started at execution start and auto-completes from `plan_tracker` once all tasks are done; this flow runs its own verify gate instead of `/skill:verification-before-completion`, so it must mark verify itself.)
223
223
  1. **Parent full verification.** Run the complete plan-header `**Verification:**` command set foreground in the worktree via `(cd "<worktree>" && <command>)`: tests plus every declared lint, type, format, and build check. A failure must be repaired and the full set rerun successfully before the next step. Before dispatching a verification repair, reopen (`in_progress`) every existing plan-task index whose `Files:` ownership includes its touched files; leave unowned cross-cutting repair work in the verification report. Those indices stay `in_progress` through the successful full rerun **and** step 2's whole-diff review accepting the repair — that acceptance is their completion point, not the passing rerun. Commit any verification-produced tracked changes; use the resulting `HEAD_SHA` in the review task and include the commands/results in its existing `DESCRIPTION`.
224
- 2. **Whole-diff code review.** Only after passing full verification, dispatch one foreground whole-diff `code-reviewer` per `/skill:requesting-code-review` against that committed HEAD, with `SCOPED_TEST_COMMANDS: none`; the reviewer does not repeat the full suite. Address Critical and Moderate findings. Before dispatching a review repair, reopen (`in_progress`) every existing plan-task index whose `Files:` ownership includes its touched files; leave unowned cross-cutting repair work in the review report. Mark each reopened index `complete` only once the repair is re-verified and the re-review accepts it — this is the same completion point step 1's reopened indices wait for, not an extra gate, and the gate order stays full verification -> whole-diff CR -> conformance. Any repair invalidates prior full verification, so rerun the full set successfully before the next gate.
224
+ 2. **Whole-diff code review.** Only after passing full verification, dispatch one foreground whole-diff `code-reviewer` per `/skill:requesting-code-review` against that committed HEAD, with `SCOPED_TEST_COMMANDS: none`; the reviewer does not repeat the full suite. Act on the verdict per `/skill:requesting-code-review` Fix rounds; carry the final `SHIP` report's Minor finding lines verbatim into the closure block's `whole-diff minors:` section (`verification-before-completion/reference/conformance-check.md` "Closure / conformance"), or `whole-diff minors: none`. Before dispatching a review repair, reopen (`in_progress`) every existing plan-task index whose `Files:` ownership includes its touched files; leave unowned cross-cutting repair work in the review report. Mark each reopened index `complete` only once the repair is re-verified and the re-review accepts it — this is the same completion point step 1's reopened indices wait for, not an extra gate, and the gate order stays full verification -> whole-diff CR -> conformance. Any repair invalidates prior full verification, so rerun the full set successfully before the next gate.
225
225
  3. **Close the loop — conformance check.** The review in step 2 is plan-vs-code (single-step); it inherits any requirement the plan already dropped.
226
226
 
227
227
  **Happy-path run - first action of this step, only when the plan header carries a `**Happy path:**` line or the diff selects a row.** The overrides file's `## Happy path` table (schema in the README overrides contract) names path-prefixed rows; the plan header's line is the plan-time default.
@@ -41,16 +41,18 @@ TRAJECTORY: STAGNANT (repeat of: <finding>)
41
41
 
42
42
  Pick the first label that applies, in this order:
43
43
 
44
- 1. STAGNANT: a previous finding survives materially unchanged - name it.
44
+ 1. STAGNANT: a previous Critical or Moderate finding survives materially unchanged - name it.
45
45
  (e.g. the same unchecked error path flagged last round is still unchecked)
46
- 2. DIVERGING: <n_now> >= <n_prev>, or the fix introduced any new finding.
46
+ 2. DIVERGING: <n_now> >= <n_prev>, or the fix introduced a new Critical or Moderate finding.
47
47
  (e.g. 3 findings fixed but the fix broke an import: DIVERGING, not CONVERGING)
48
- 3. CONVERGING: otherwise - the count fell, nothing new appeared, and every
49
- surviving finding was materially improved.
50
-
51
- <n_prev>/<n_now> are finding counts; <X> is the highest remaining severity.
52
- For this line the severity set is exactly Critical/Moderate/Minor, regardless
53
- of the vocabulary used elsewhere in your report.
48
+ 3. CONVERGING: otherwise - the Critical/Moderate count fell, no new Critical or
49
+ Moderate appeared, and every surviving Critical or Moderate was materially improved.
50
+
51
+ <n_prev>/<n_now> count Critical and Moderate findings only; Minors - ride-along
52
+ Minors declined or unchanged, and `(outside fix delta)` downgrades alike - never
53
+ move the `TRAJECTORY:` line. <X> is the highest remaining severity. For this line the severity set is
54
+ exactly Critical/Moderate/Minor, regardless of the vocabulary used elsewhere in
55
+ your report.
54
56
 
55
57
  The orchestrator dispatches one extra fix only when this line says CONVERGING
56
58
  without "max severity Critical" - be accurate, not generous.
@@ -443,6 +443,8 @@ finish gate's revert option needs them all:
443
443
  auto-applied fix commits: <Gn: SHA>, <Gm: SHA>, ... (revertable)
444
444
  ```
445
445
 
446
+ Then the trailing `whole-diff minors:` section - read `whole-diff-minors.md` now (same directory); it is present in every block, a `CONFORMS` handoff too.
447
+
446
448
  ## Concern-scoped fix projection
447
449
 
448
450
  When the finish gate selects `fix-now` on some concerns of a gap, the fix loop
@@ -0,0 +1,31 @@
1
+ # Whole-diff minors section
2
+
3
+ The trailing section of every `## Closure / conformance` block
4
+ (conformance-check.md "Closure / conformance"); the spec contract is D3 of the
5
+ change that introduced it.
6
+
7
+ Then, in every block (a `CONFORMS` handoff too), the whole-diff review's Minor
8
+ findings - the source is the final `SHIP` whole-diff report (SDD "After All
9
+ Tasks Complete" step 2; a `FIX_FIRST` whole-diff review's re-review `SHIP`
10
+ report when one ran):
11
+
12
+ ```text
13
+ whole-diff minors: none
14
+ ```
15
+
16
+ ```text
17
+ whole-diff minors:
18
+ [Minor] F3: [shrink] path.ts:30 - ...
19
+ [Minor] F7: [yagni] other.ts:12 - ...
20
+ ```
21
+
22
+ Use one persona finding line per Minor, verbatim (`Fn` is the selector), or
23
+ `whole-diff minors: not recorded` when no whole-diff review ran in this flow.
24
+ This section is not a concern card: the sentinel `N`, the card count, and the
25
+ freshness rule ignore it. After a `fix minors` round
26
+ (`finishing-a-development-branch` Step 4) the regenerated block carries the
27
+ prior list minus the selected `Fn` lines plus one line
28
+ `whole-diff minors fix: <full SHA>`, so the spent round survives pruning and
29
+ resume. On any other re-audit that regenerates the block without the source
30
+ report, copy the prior block's `whole-diff minors:` section minus lines selected
31
+ by `fix minors`.