pi-gauntlet 4.4.0 → 4.4.2

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,58 @@
1
1
  # Changelog
2
2
 
3
+ ## v4.4.2 - 2026-07-15
4
+
5
+ Condense the finish-time conformance disposition gate to a dense, human-readable
6
+ decision list - the corrective second pass over v4.4.1's disposition work, which
7
+ delivered the right behavior but bloated the render and the freshness protocol.
8
+
9
+ - **Finish gate (`finishing-a-development-branch`):** carried-open conformance
10
+ findings now render as a dense one-line-per-decision list - each line carries a
11
+ plain-language title, the unresolved point, its question, and an inline recommended
12
+ choice - with a two-option reply (`1` = every recommendation; `2:` =
13
+ recommended-except comma-separated `<handle>=<choice>` overrides). Replaces the
14
+ terse `Gn` tokens and the flat D1-D5 per-gap menu. Single-concern gaps show no
15
+ `/Cn` symbol; `UNAUTHORIZED` items note availability deviations inline; the
16
+ zero-gap path still goes straight to branch options with no sign-off.
17
+ - **Freshness (`verification-before-completion/reference/conformance-check.md`,
18
+ `finishing-a-development-branch`, `subagent-driven-development`):** the four-field
19
+ audit-identity/hash protocol (duplicated across three files) collapses to a
20
+ `status`/`audited-base` sentinel plus a two-command working-tree drift check;
21
+ any change or doubt re-audits. The durable `## Closure / conformance` handoff
22
+ header drops `audited-spec-path`/`audited-diff-hash`/`audited-spec-hash`.
23
+ - **De-duplication:** the disposition-availability table, the `UNAUTHORIZED`
24
+ question, the `recommended: none` preflight, and the fix loop now live only in
25
+ `conformance-check.md`; the finish gate and SDD consume them by link.
26
+
27
+ ## v4.4.1 - 2026-07-13
28
+
29
+ Gates ratify, not ceremony: two gauntlet gates now auto-apply mechanical/drafting
30
+ changes and stop the human only for a load-bearing decision, not ritual confirmation.
31
+
32
+ - **Conformance gate (`verification-before-completion/reference/conformance-check.md`,
33
+ `subagent-driven-development`, `verification-before-completion`):** GAPS handling is
34
+ a deterministic verdict-then-`recommended` partition, no menu. `fix` gaps auto-close
35
+ through an isolated SDD-mirror fix loop (per-gap `implementer` + `spec-reviewer` on a
36
+ gap-block contract, `plan_tracker` fix-wave progress, per-round `code-reviewer`, delta
37
+ re-audit with regression guard, `maxFixRounds` cap -> escalate). `accept`/`rescope`/
38
+ `UNAUTHORIZED` gaps carry OPEN to the finishing gate. New `## Closure / conformance`
39
+ handoff schema + `conformance fix Gn` commit convention.
40
+ - **Spec council (`roasting-the-spec`, `brainstorming`):** the main-loop model applies
41
+ the chair's apply-set before the single brainstorming review gate; a gate-only
42
+ Applied/Deferred/Rejected audit is recorded in the spec commit body. The verbatim
43
+ summary now reflects the final post-apply spec on both worker and council paths;
44
+ checklist item 10 reduced to a re-scan; revert valve at the gate.
45
+ - **`finishing-a-development-branch` Step 3.5:** enforced per-gap disposition gate
46
+ (accept-into-spec / rescope-into-spec / fix-now / custom disposition / revert) with
47
+ three-tier revert semantics.
48
+ - **`agents/conformance-reviewer.md`:** deterministic `UNAUTHORIZED` recommendation
49
+ (harmless -> accept, else fix).
50
+ - **Extensions (`phase-tracker.ts`, `plan-tracker.ts`):** `SHIP_ADVISORY` and the
51
+ `plan_tracker` tool description reworded to allow carried-open deferred gaps and
52
+ verify-phase fix waves (description strings only, no logic change).
53
+ - **`README.md`:** conformance gate auto-fixes requirement-restoring gaps, defers
54
+ spec-rewriting decisions to the finishing gate.
55
+
3
56
  ## v4.4.0 - 2026-07-12
4
57
 
5
58
  Add an unconditional parallel context-gather step to `/skill:brainstorming`. Step 3's
package/README.md CHANGED
@@ -38,7 +38,7 @@ Concretely, one change through the gauntlet:
38
38
  1. You describe the change. **`brainstorming`** sets up an isolated worktree, explores the codebase, and turns your description into a written spec. A multi-model critique runs on it automatically. **You read and approve the spec - human gate 1.** No implementation code exists yet.
39
39
  2. **`writing-plans`** decomposes the approved spec into atomic, independently-verifiable tasks, grouped into parallel waves where they don't touch the same files.
40
40
  3. **`subagent-driven-development`** executes the plan one task at a time, each in a fresh subagent, behind spec-compliance review then code-quality review. TDD-locked: red, green, refactor.
41
- 4. **verify**: a whole-diff code review, then the **conformance gate** - a subagent reads the finished code and docs against your *original words* from step 1, not the plan, and reports per-requirement: delivered, partial, missing, drifted, or unauthorized. This gate is machine-blocked from being skipped.
41
+ 4. **verify**: a whole-diff code review, then the **conformance gate** - a subagent reads the finished code and docs against your *original words* from step 1, not the plan, and reports per-requirement: delivered, partial, missing, drifted, or unauthorized. This gate is machine-blocked from being skipped. Compatible executable recommendations auto-run through an isolated fix-and-re-audit loop with no prompt; anything still open surfaces as a dense list - one line per decision, plain-language, with its recommended choice inline. Reply `1` to take every recommendation, or `2:` with per-item overrides; a current `CONFORMS` / no-concerns result goes straight to the branch options with no extra conformance sign-off.
42
42
  5. **`finishing-a-development-branch`**: squash, PR, keep, or discard. **Human gate 2** - the only other decision you make.
43
43
 
44
44
  ```mermaid
@@ -74,7 +74,7 @@ pi-gauntlet is **opinionated**: every non-trivial change rides this one pipeline
74
74
  | --- | --- |
75
75
  | Gate | A machine-enforced checkpoint between phases (e.g. `complete verify` is blocked until conformance review has run). Not a suggestion. |
76
76
  | Spec council | Multi-model critique of the spec before you see it (`roasting-the-spec`); falls back to a single-model critique if no council is configured. |
77
- | Conformance gate | The closing check: does the delivered code + docs match your *original prompt*, not the derived plan? Per-requirement verdict, no auto-fix. |
77
+ | Conformance gate | The closing check: does the delivered code + docs match your *original prompt*, not the derived plan? Compatible executable recommendations auto-fix first; anything still open renders as a dense one-line-per-decision list with each recommended choice inline. Reply `1` to accept all recommendations or `2:` with per-item overrides; a current `CONFORMS` / no-concerns handoff goes straight to branch options with no extra sign-off. |
78
78
  | Wave | A batch of plan tasks that don't touch the same files, dispatched to implementers in parallel. |
79
79
  | Overrides file | `.pi/gauntlet-overrides.md` - where you put project-specific detail the generic skills don't know (CI command, worktree wrapper, routing rules). |
80
80
 
@@ -64,7 +64,7 @@ DELIVERED rows keep an `Rn` id; every non-DELIVERED row gets a durable `Gn` id r
64
64
  ## Structured gap blocks
65
65
 
66
66
  After the coverage table, emit one fenced block per non-DELIVERED row so the
67
- orchestrator can drive the disposition menu mechanically. In a re-audit round
67
+ orchestrator can partition and dispose of them mechanically. In a re-audit round
68
68
  (see conformance-check.md "When the check finds gaps"), also emit a `DELIVERED`
69
69
  block for any gap that closed, reusing its original `Gn` id.
70
70
 
@@ -122,15 +122,15 @@ disjointness rule does. When you cannot confidently certify a pair disjoint, mar
122
122
  `recommended` is a proposal; you never decide, edit, dispatch, or re-audit.
123
123
 
124
124
  - Default `fix` for every `PARTIAL` / `MISSING` / `DRIFTED` row.
125
- - `accept` only for an `UNAUTHORIZED` row whose behavior is harmless, with a one-line
126
- rationale in `remediation`.
125
+ - For every `UNAUTHORIZED` row: harmless `accept` with a one-line rationale in
126
+ `remediation`; otherwise `fix` (= remove the unrequested code).
127
127
  - `rescope` only when the `origin` requirement is impractical to satisfy in this branch
128
128
  (`rescope` is inapplicable to `UNAUTHORIZED` — there is no requirement to defer).
129
129
 
130
130
  ## Rules
131
131
 
132
132
  - **Read-only. Never edit.** You audit; you do not fix.
133
- - **Propose, do not dispose.** For each gap you may suggest a one-line remediation *direction*, but you do **not** decide whether to apply it, defer it, or accept it that is the user's call, surfaced by the orchestrator. Never present a fix as a decision made.
133
+ - **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`/`UNAUTHORIZED` to the user at the finish gate. Never present a fix as a decision you made.
134
134
  - **Evidence or it didn't happen.** Cite a real `file:line` for every DELIVERED/PARTIAL. If you cannot, downgrade the row to MISSING.
135
135
  - **Spec is canonical; the prompt catches what the spec dropped; the ticket is fallback only** when no spec exists.
136
136
  - **Do not absorb origin drift silently** — flag every spec↔prompt/ticket disagreement.
@@ -71,12 +71,12 @@ const CLOSURE_GATE_ERROR =
71
71
  ' phase_tracker({ action: "skip", phase: "verify", reason: "<user waiver>" })';
72
72
 
73
73
  const SHIP_ADVISORY =
74
- "Verify is complete and ship is pending. If the conformance verdict is resolved\n" +
75
- "(CONFORMS, or every gap dispositioned and approved), invoke\n" +
76
- "/skill:finishing-a-development-branch now - do not add a 'ready to finish?' prompt;\n" +
77
- "its squash/PR/keep/discard menu is the human gate. If a requirement decision is\n" +
78
- "still open, you should not have completed verify - reopen it and surface the open\n" +
79
- "decision instead.";
74
+ "Verify is complete and ship is pending. Verify may complete when the conformance\n" +
75
+ "verdict is CONFORMS, or every gap is either fixed or carried open as a deferred\n" +
76
+ "accept/rescope/unauthorized decision. Invoke /skill:finishing-a-development-branch\n" +
77
+ "now - do not add a 'ready to finish?' prompt; its disposition + squash/PR/keep/discard\n" +
78
+ "menu is the human gate that resolves any carried-open decision. Only reopen verify if\n" +
79
+ "a `fix` gap was left unresolved (neither fixed nor deferred).";
80
80
 
81
81
  // --- Flow guards (spec 2026-06-17-gauntlet-flow-guards) ---
82
82
 
@@ -129,7 +129,7 @@ export default function (pi: ExtensionAPI) {
129
129
  name: "plan_tracker",
130
130
  label: "Plan Tracker",
131
131
  description:
132
- "Track progress while EXECUTING an implementation plan the implement phase only. Actions: init (set task list), update (change task status), status (show current state), clear (remove plan). Do NOT use for brainstorming, research, or planning checklists: those phases are open-ended and a bounded task list misrepresents them as a fixed N-step process.",
132
+ "Track progress while EXECUTING an implementation plan (the implement phase) or a verify-phase conformance fix wave. Actions: init (set task list), update (change task status), status (show current state), clear (remove plan). Do NOT use for brainstorming, research, or planning checklists: those phases are open-ended and a bounded task list misrepresents them as a fixed N-step process.",
133
133
  parameters: PlanTrackerParams,
134
134
 
135
135
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "4.4.0",
3
+ "version": "4.4.2",
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",
@@ -59,10 +59,10 @@ Work through the items below **in order**. This is your own checklist to follow,
59
59
  6. **Present the design** — in sections, get approval after each
60
60
  7. **Write the spec** — to `doc/specs/` (see [Filename Convention](#filename-convention))
61
61
  8. **Spec self-review (lint)** — placeholder scan + internal consistency + documentation named, run inline
62
- 9. **Critique pass (auto-dispatched)** — scope + ambiguity; the spec council via `/skill:roasting-the-spec` when `gauntlet_setting` returns verdict `council`, else a fresh `worker` (see [Spec Council](#spec-council-optional))
63
- 10. **Re-run placeholder scan** — after the critique pass returns, first inline any `external-ref:` flags it raised (see [Spec Self-Review](#spec-self-review-before-user-review-gate)), then re-scan for placeholders its edits may have introduced; surface any ambiguity the worker could not safely resolve at the user gate
64
- 11. **Generate spec summary** — dispatch a fresh, spec-only `spec-summarizer` writing to an absolute temp-dir path via `outputMode: "file-only"`, then `Read` that file back as the **last content-producing** tool call before composing the gate and render its contents **verbatim** at the top of the gate message — do not paraphrase, condense, re-section, or rewrite it (see [User Review Gate](#user-review-gate)); this is part of the existing gate, not a new one
65
- 12. **User review gate** — user reviews the committed spec
62
+ 9. **Critique pass (auto-dispatched)** — scope + ambiguity; the spec council via `/skill:roasting-the-spec` when `gauntlet_setting` returns verdict `council` (it applies its apply-set, including any external-ref inlining, to the spec before returning — see [Spec Council](#spec-council-optional)), else a fresh `worker` that applies its own fixes in place
63
+ 10. **Re-run placeholder scan** — after the critique pass returns, re-scan the **applied** spec for placeholders its edits may have introduced; surface any ambiguity the critique could not safely resolve at the user gate
64
+ 11. **Generate spec summary** — dispatch a fresh, spec-only `spec-summarizer` over the **final (post-apply)** spec, writing to an absolute temp-dir path via `outputMode: "file-only"`, then `Read` that file back as the **last content-producing** tool call before composing the gate and render its contents **verbatim** at the top of the gate message — do not paraphrase, condense, re-section, or rewrite it (see [User Review Gate](#user-review-gate)); this is part of the existing gate, not a new one
65
+ 12. **User review gate** — user reviews the applied spec's verbatim summary plus the council audit (Applied/Deferred/Rejected), with a revert valve for any applied council edit
66
66
  13. **Transition** — only after approval, invoke `/skill:writing-plans`
67
67
 
68
68
  ## Project Routing
@@ -244,7 +244,7 @@ After writing the spec to `<project>/doc/specs/<filename>.md` (per [Filename Con
244
244
 
245
245
  The first three checks — **placeholder scan**, **internal consistency**, and **documentation named** — are the inline **lint**: run them here at the main loop and fix what they surface. The last two — **scope** and **ambiguity** — are **not** run inline; they are the **critique pass**, auto-dispatched (per [Spec Council](#spec-council-optional)):
246
246
 
247
- - **Council** (`gauntlet_setting({ key: "specCouncil" })` returns verdict `council`) → invoke `/skill:roasting-the-spec`; it runs the critique and proposes dispositions.
247
+ - **Council** (`gauntlet_setting({ key: "specCouncil" })` returns verdict `council`) → invoke `/skill:roasting-the-spec`; it runs the critique, derives dispositions, and **applies the apply-set to the spec** (including inlining any `external-ref:` cluster it has context for) **before returning** — see that skill for apply mechanics. It returns a structured audit: `Applied:` / `Deferred:` / `Rejected:`.
248
248
  - **Otherwise** → dispatch one fresh `worker` that applies the scope + ambiguity checks and fixes them in place:
249
249
 
250
250
  ```
@@ -253,23 +253,24 @@ The first three checks — **placeholder scan**, **internal consistency**, and *
253
253
  "Read the spec at <abs path to doc/specs/...>. Edit ONLY that file. Apply two checks and\n" +
254
254
  "fix what you find in place: (1) Scope — does every paragraph serve the goal? Cut filler;\n" +
255
255
  "state out-of-scope explicitly. (2) Ambiguity — is every 'we should' a concrete decision?\n" +
256
- "Replace 'we could probably' with 'we will'/'we won't'. Also flag (do NOT fetch) any\n" +
257
- "load-bearing external reference (ticket AC, commit SHA, doc) the spec relies on but does\n" +
258
- "not inline, and recommend inlining it. Return a summary of what you changed, and flag any\n" +
259
- "ambiguity you could NOT safely resolve." })
256
+ "Replace 'we could probably' with 'we will'/'we won't'. Also inline any load-bearing\n" +
257
+ "external reference (ticket AC, commit SHA, doc) already given to you in the problem\n" +
258
+ "statement above; if the spec relies on one not provided here, flag it (do NOT fetch) in\n" +
259
+ "your summary. Return a summary of what you changed, and flag any ambiguity you could NOT\n" +
260
+ "safely resolve." })
260
261
  ```
261
262
 
262
263
  `worker`'s model resolves from `subagents.agentOverrides.worker.model` in `settings.json` (unset → inherits the main loop); the dispatch passes no `model:`.
263
264
 
264
- After the critique pass returns, scan it for load-bearing external references before re-running the placeholder scan: in the council path, look for chair clusters whose theme is prefixed `external-ref:`; in the worker path, look for the worker's external-ref flag. For each, inline the referenced content you have context for (e.g. the ticket fetched during brainstorming) via the normal disposition/edit path - you hold the ticket, the critics do not. Then re-run the placeholder scan to catch anything the edits introduced. If the worker flagged ambiguities it could not safely resolve, surface them in the [User Review Gate](#user-review-gate) message so the user decides - the worker auto-applies fixes but never silently swallows an open question.
265
+ Both paths apply their fixes **before returning** the council auto-applies inside `/skill:roasting-the-spec`, the worker edits the spec file directly. After the critique pass returns, re-run the placeholder scan over the **applied** spec to catch anything the edits introduced. If the worker flagged ambiguities it could not safely resolve, surface them in the [User Review Gate](#user-review-gate) message so the user decides - the worker auto-applies fixes but never silently swallows an open question.
265
266
 
266
267
  ## Spec Council (Optional)
267
268
 
268
- After the inline lint and before the user review gate, **brainstorming owns the critique-pass gate**. Resolve the council with `gauntlet_setting({ key: "specCouncil" })` - the tool returns the merged (repo-over-preset) value as `{ verdict, members, chair, malformed, warning, errors }`. **Do not** hand-roll a settings read. When `verdict` is `"council"`, the council *is* the critique pass - invoke `/skill:roasting-the-spec` automatically (no offer, no prompt), passing `members`/`chair`. When `verdict` is `"worker"`, run the fresh-`worker` critique instead (see [Spec Self-Review](#spec-self-review-before-user-review-gate)). If `malformed` is true or `errors` is non-empty, emit the `warning`/error as one line, then branch strictly on `verdict` - `malformed` can accompany *either* verdict (e.g. a bad `chair` with valid `members` still returns `council`), so never infer the worker path from `malformed` alone. If `gauntlet_setting` is unavailable, stop and report - never fall back to a manual bash/JSON settings merge. Approved council edits (or the worker's in-place fixes) ride in the same worktree commit. The conceptual precedence rule lives in `verification-before-completion/reference/settings-precedence.md`.
269
+ After the inline lint and before the user review gate, **brainstorming owns the critique-pass gate**; council **apply mechanics** live in `/skill:roasting-the-spec` (single source of truth - link, don't restate). Resolve the council with `gauntlet_setting({ key: "specCouncil" })` - the tool returns the merged (repo-over-preset) value as `{ verdict, members, chair, malformed, warning, errors }`. **Do not** hand-roll a settings read. When `verdict` is `"council"`, the council *is* the critique pass - invoke `/skill:roasting-the-spec` automatically (no offer, no prompt), passing `members`/`chair`; it applies its apply-set and returns the audit (Applied/Deferred/Rejected). When `verdict` is `"worker"`, run the fresh-`worker` critique instead (see [Spec Self-Review](#spec-self-review-before-user-review-gate)). If `malformed` is true or `errors` is non-empty, emit the `warning`/error as one line, then branch strictly on `verdict` - `malformed` can accompany *either* verdict (e.g. a bad `chair` with valid `members` still returns `council`), so never infer the worker path from `malformed` alone. If `gauntlet_setting` is unavailable, stop and report - never fall back to a manual bash/JSON settings merge. The already-applied council edits (or the worker's in-place fixes) ride in the same worktree commit. The conceptual precedence rule lives in `verification-before-completion/reference/settings-precedence.md`.
269
270
 
270
271
  ## User Review Gate
271
272
 
272
- After self-review (and council review, if configured) and after inlining any external-ref flags, dispatch the spec-only summarizer, then commit the spec on the worktree branch and stop. This is the **same** single human gate - the summary is folded into it, not a new gate.
273
+ After self-review and the critique pass (council or worker, both already applied to the spec - see [Spec Council](#spec-council-optional)), dispatch the spec-only summarizer over the **applied** spec, then commit the spec on the worktree branch and stop. This is the **same** single human gate - the summary is folded into it, not a new gate.
273
274
 
274
275
  Mint an absolute temp path outside the worktree (so it is never committed), then dispatch the summarizer on a fresh context, reading only the spec, writing to that path via file-only output (no `model:` - it inherits the main loop unless a preset sets `subagents.agentOverrides.spec-summarizer.model`):
275
276
 
@@ -285,7 +286,7 @@ subagent({ agent: "spec-summarizer", context: "fresh", cwd: "<abs worktree path,
285
286
 
286
287
  `<SUMMARY_PATH>` above is a placeholder in the dispatch object; it means substitute the value of the shell variable `$SUMMARY_PATH` set above. The steps below use `$SUMMARY_PATH` (the shell form) once the value is in hand.
287
288
 
288
- Then commit the spec — this commit is **unconditional**: the summary is only a gate aid, so a degraded or missing summary never blocks it. Evaluate the summary in two stages (the **Degrade path** referenced in each is defined just below):
289
+ Then commit the spec — this commit is **unconditional**: the summary is only a gate aid, so a degraded or missing summary never blocks it. If the council path ran, include its audit (`Applied:` / `Deferred:` / `Rejected:`, verbatim from `/skill:roasting-the-spec`'s return) in the **commit message body** - this is the durable, non-contractual record a finish-time revert reads back; the audit is never a committed spec section. Evaluate the summary in two stages (the **Degrade path** referenced in each is defined just below):
289
290
 
290
291
  1. **From the dispatch tool result, before the `Read`.** If the result is **not** an `"Output saved to: <path> (<N> KB, <M> lines)"` reference (e.g. an exit-0 save error returns the full inline output plus an "Output file error" line — the prunable shape, no file to read), or the reference reports under ~500 bytes, or a size grossly disproportionate to the spec (under ~2% of its byte size), or over ~45 KB (the `Read` truncates at 50KB / 2000 lines, so a larger file cannot render whole) — skip the `Read` and take the degrade path. Use the reference's reported figures; do not re-derive them.
291
292
  2. **The `Read` itself, as the last content-producing tool call before composing the gate.** `Read` `$SUMMARY_PATH` and paste its contents verbatim at the top of the gate. If the `Read` fails, returns 0 bytes, or reports truncation — take the degrade path. The `Read` must be last: pi-condense does not protect a `/tmp` read, so any turn boundary between the `Read` and the render lets the ~9KB read result be pruned, reproducing the bug.
@@ -294,21 +295,28 @@ Then commit the spec — this commit is **unconditional**: the summary is only a
294
295
 
295
296
  Either way — summary rendered or degraded — then `rm "$SUMMARY_PATH"` (unconditional cleanup; harmless if the file was never created, since it lives outside the worktree under the OS temp dir).
296
297
 
297
- Render the temp file's contents **verbatim** first — paste it as-is, do **not** paraphrase, condense, re-section, drop sections, or merge it with council output. "Fold into the gate" means *place it inside the gate message*, not *rewrite it*. After the verbatim block, append the commit confirmation, then — as their **own** adjacent lines, not edits to the summary — any council outcome, critique-pass-unresolved ambiguities, and every entry from the summarizer's gap/external-context footer (surface **all** of them, not just the top risk):
298
+ Render the temp file's contents **verbatim** first — paste it as-is, do **not** paraphrase, condense, re-section, drop sections, or merge it with the council audit. "Fold into the gate" means *place it inside the gate message*, not *rewrite it*. This summary is of the **final (post-apply)** spec, since both critique paths already applied before this dispatch. After the verbatim block, append the commit confirmation, then — as their **own** adjacent lines, not edits to the summary — the council audit (if the council path ran: `Applied:` / `Deferred:` / `Rejected:`, one line each), critique-pass-unresolved ambiguities, and every entry from the summarizer's gap/external-context footer (surface **all** of them, not just the top risk):
298
299
 
299
300
  ```
300
301
  <spec-only summary read back from the temp file — pasted verbatim, unedited>
301
302
 
302
303
  Spec written and committed to <project>/doc/specs/<filename>.md (worktree: <path>).
303
304
 
304
- <council outcome, if any; unresolved ambiguities; every gap-footer entry from the summary>
305
+ Applied: <cluster -> edit>, ...
306
+ Deferred: <cluster -> where it belongs>, ...
307
+ Rejected: <cluster -> one-line reason>, ...
308
+ (omit the three lines above when the worker path ran, not the council)
305
309
 
306
- Please review. Approve to proceed, or tell me what to change in the spec.
310
+ <unresolved ambiguities; every gap-footer entry from the summary>
311
+
312
+ Please review. Approve to proceed, tell me what to change in the spec, or say "revert applied council edit <X>" to undo a specific applied edit.
307
313
  ```
308
314
 
309
315
  If you believe the summary needs correcting, do **not** silently rewrite it — re-dispatch the summarizer or note the discrepancy as an adjacent line beneath the verbatim block.
310
316
 
311
- Wait for the user. On a change request, revise the spec and re-present mint a **fresh** temp path for the re-dispatched summarizer (never reuse a prior round's path, so stale content can never be mistaken for the new summary). On approval, proceed immediately to `/skill:writing-plans` with no further prompt — the plan and execution mode are mechanical derivatives, so the only human gate here is spec approval itself. Don't land the spec on `main`; it stays in the worktree and ships in the same squash commit as the implementation.
317
+ **Revert valve.** "Revert applied council edit X" is a normal change request: revise the spec to undo edit X, re-dispatch the summarizer with a **fresh** temp path (per the re-dispatch rule below), and re-present the gate. This is cheap here - the spec is not yet plan- or code-bearing.
318
+
319
+ Wait for the user. On a change request (including a revert), revise the spec and re-present — mint a **fresh** temp path for the re-dispatched summarizer (never reuse a prior round's path, so stale content can never be mistaken for the new summary). On approval, proceed immediately to `/skill:writing-plans` with no further prompt — the plan and execution mode are mechanical derivatives, so the only human gate here is spec approval itself. Don't land the spec on `main`; it stays in the worktree and ships in the same squash commit as the implementation.
312
320
 
313
321
  After approval, mark the brainstorm phase complete:
314
322
 
@@ -70,23 +70,105 @@ git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
70
70
 
71
71
  Or ask: "This branch split from main - is that correct?"
72
72
 
73
- ### Step 3.5: Surface Closure / Conformance Status
73
+ ### Step 3.5: Closure / Conformance Disposition Gate
74
74
 
75
- Before presenting finish options, surface the closing-loop conformance result as **its own section** — the user is about to choose how to ship, and they need to see whether the deliverable matches what was *asked*, not just whether tests pass. Tests prove the code runs; conformance proves it does what was requested. Different gates.
75
+ This is an **enforced disposition gate**, not a surface-only notice. The user is about to choose how to ship; every carried-open decision must get an explicit disposition here, before Step 4's menu. Tests prove the code runs; conformance proves it does what was requested - different gates.
76
76
 
77
- - **If the execution flow already closed the loop** (the `conformance-reviewer` ran in the `subagent-driven-development` verify gate), restate its verdict here: `CONFORMS`, or the `GAPS` and how each was dispositioned (fixed / accepted-and-recorded-in-spec / rescoped). If any gap is still open, drive it through the remediation loop in `verification-before-completion/reference/conformance-check.md` "When the check finds gaps"; on a normal-repo (`GIT_DIR == GIT_COMMON`) or detached-HEAD finish there is no worktree to dispatch fix waves into, so that menu offers accept / rescope / manual fix-in-place only.
78
- - **If no conformance check has run in this flow** (e.g., ad-hoc work that landed without an execution skill), say so plainly and offer to run it now — dispatch a fresh-context `conformance-reviewer` against the origin (spec + verbatim prompt + full diff vs base) per `verification-before-completion/reference/conformance-check.md`. Closing the loop is cheap relative to shipping unverified intent.
79
- - **Unreconciled gaps are a blocker, not a footnote.** Do not bury them inside the options menu. If any gap is still open, resolve it (or get explicit user acceptance recorded in the spec) before offering Option 1 (squash-merge) or Option 2 (PR).
77
+ `verification-before-completion/reference/conformance-check.md` is **canonical** for the durable handoff schema, concern-decomposition rules, the single disposition-availability table, the `UNAUTHORIZED` question text, the `recommended: none` preflight, the freshness rule, and the concern-scoped fix projection. This step owns only **render, response, and execute-order** and consumes the rest by link - it does not restate the availability table, the `UNAUTHORIZED` question, or the preflight prose.
80
78
 
81
- Present it as a distinct line the user reads before choosing:
79
+ **If no conformance check has run in this flow** (e.g. ad-hoc work that landed without an execution skill): say so, then dispatch a fresh-context `conformance-reviewer` against the origin (spec + verbatim prompt + full diff vs base) per that reference - it owns the audit-time input rule (stage/commit untracked deliverables before auditing). Closing the loop is cheap relative to shipping unverified intent. Route the raw reviewer verdict through the reference's canonical pipeline (gap/concern partition, auto-fix where eligible, concern decomposition, emission of a durable `## Closure / conformance` block), then consume that block through the branching below exactly as a carried handoff.
80
+
81
+ **Freshness precondition - before any verdict branch, including `CONFORMS`.** The durable block opens with a two-line sentinel: `status: CONFORMS (0 open)` or `status: GAPS (N open)`, then `audited-base: <full HEAD SHA at audit time>`. 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.
82
+
83
+ **Zero-gap fast path:** print exactly
84
+
85
+ ```
86
+ Closure / conformance: CONFORMS
87
+ ```
88
+
89
+ then continue directly to Step 4. No approval prompt, no menu, no shared options line, no sign-off. If the run auto-applied fixes, surface the flat `auto-applied fix commits: <Gn: SHA>, ...` index from the durable block as **one informational, non-blocking line** with a one-line revert offer (see "Revert semantics") - a gap that auto-converged mid-verify has no bullet, so this index is the only place its fix commit stays revertable. Do not wait for acknowledgment.
90
+
91
+ **Carried-open render (dense).** Read the `## Closure / conformance` block. Render a header with the decision count, one bullet per decision unit (a gap by default; a `Gn/Cn` concern only where the reference split it), then the shared options line, then the recommended-set reply. Never show durable-card internals (ownership, evidence tokens, identity, hashes) in the render.
92
+
93
+ Each bullet:
94
+
95
+ `* <handle> - <plain title>: <what's unresolved, one clause>. <short question> Recommended: <choice> (<one-clause why>).`
96
+
97
+ - `<handle>` leads the bullet and is a short unique human word derived from the title (`Cache coverage` -> `cache`); on collision append a digit. It is the token option 2 targets. When a gap split and no clean word fits, use the bare `Gn/Cn`; a single-concern gap uses its gap ID `Gn`.
98
+ - The shared options line sits below the bullets: `Other options per item: fix-now / accept / rescope / follow-up / custom`, listing the options **generally available across items**. When a specific item's availability deviates - an option unavailable for it, or an `UNAUTHORIZED` item whose `rescope` is unavailable and whose `fix-now` means removal - note that deviation as a short parenthetical on **that item's bullet** (one clause, not a block), e.g. `(rescope N/A: scope creep)`. The shared line appears **only in the carried-open render**, never in the zero-gap path. Full per-option effects only on request, or when option 2 targets an unclear choice.
99
+ - Group items under one recommended line only when they share a disposition and rationale; each grouped handle repeats its title.
100
+ - Availability per concern comes from the reference's single availability table - apply it against current context (worktree state, `maxFixRounds`, ownership, resource accessibility), do not restate it. `UNAUTHORIZED` bullets ask the reference's question verbatim (`Should this unrequested behavior become part of the current workflow?`); `rescope-into-spec` is shown **unavailable** (not dropped) and `fix-now` means **removal** of the unrequested code.
101
+ - `revert conformance fix Gn`, when the gap has an auto-applied fix, renders on the shared options line as a **separate one-off action** - never inside a bullet's recommendation and never in the option-2 list. Name the parent gap and warn that revert undoes the entire gap-level commit (see "Revert semantics").
102
+
103
+ Representative carried-open render (multi-concern gap split to `e2e`; single-concern gap `cache`; `UNAUTHORIZED` gap `auth`):
104
+
105
+ ```
106
+ Conformance: 3 decisions needed before shipping.
107
+
108
+ * e2e - Source-image E2E validation: not run; blocked (HYDRA1.png, HTTP 401).
109
+ Still in scope for this branch? Recommended: rescope (defer until image available) (fix-now N/A: needs HYDRA1.png).
110
+ * cache - Cache coverage: implemented but the spec is silent on it.
111
+ In scope? Recommended: accept into spec (behavior is intentional).
112
+ * auth - Unrequested admin bypass: adds an unlisted route. Should this unrequested behavior become part of the current workflow? Recommended: fix-now = remove it (rescope N/A: scope creep).
113
+
114
+ Other options per item: fix-now / accept / rescope / follow-up / custom.
115
+
116
+ 1. Go with recommended
117
+ 2. Recommended except <handle>=<choice> e.g. "2: cache=follow-up"
118
+ ```
119
+
120
+ A single-concern render is identical minus the split: one bullet whose handle is the gap ID or word, no sibling.
121
+
122
+ #### Response grammar
123
+
124
+ ```
125
+ 1 -> apply every recommendation
126
+ 2: cache=follow-up
127
+ 2: e2e=custom(open ticket after image lands), cache=follow-up
128
+ ```
129
+
130
+ - `1` (or `apply recommended`) applies all recommendations.
131
+ - `2:` takes a comma-separated override list, each `<handle>=<choice>`; omitted items keep their recommendation. A handle may appear at most once (repeat = invalid).
132
+ - `custom(<concrete effect>)` supplies an inline effect. Manual fix-in-place is expressed only as `custom(...)` where isolated `fix-now` is unavailable.
133
+ - `recommended: none` items follow the reference's preflight (linked, not restated): the item needs a `<handle>=custom(...)` decision, and option 1 is withheld until every open item has an executable recommendation; after the custom decision the menu re-renders for the remainder.
134
+ - `revert conformance fix Gn` is a valid standalone reply, mutually exclusive with `1` and `2:`; it never appears inside a `2:` override list.
135
+ - Invalid handle or choice -> focused reprompt naming only that item, retaining every valid pick and never reopening the gate. Unknown token: list the valid titled handles. Known item, bad choice: repeat its title + its available choices.
136
+
137
+ #### Execute order
138
+
139
+ Take **no** disposition action before the reply. Then, once, in order:
140
+
141
+ 1. **Normalize** every `custom(...)` into explicit operations; classify state-changing (edits code or spec) vs not. Clarify only an ambiguous or unexecutable effect.
142
+ 2. **Commit spec edits** (`accept-into-spec`, `rescope-into-spec`, state-changing spec `custom`) - the main session edits the spec directly, before any fix dispatch (a dirty tree rejects `worktree: true`, and the re-audit must read the amended spec).
143
+ 3. **Re-audit if step 2 changed the spec**; regenerate the inventory and re-render if it changed. Project `fix-now` only from the refreshed inventory.
144
+ 4. **fix-now + code-changing custom:** project the selected concerns per gap into the reference's concern-scoped fix contract (excluding accepted/rescoped/followed-up siblings); run the reference "Fix loop" (unchanged - do not re-describe it). A code-changing `custom` runs the project's tests + `code-reviewer` on its delta before proceeding. Re-run Step 1's canonical tests.
145
+ 5. **Re-audit after all state-changing work;** obtain fresh decisions **only if** the refreshed inventory differs from the approved one, else proceed.
146
+ 6. **follow-up** from the current inventory: create the item via the project's issue-tracker convention (`.pi/gauntlet-overrides.md`), record the ticket ID/URL; on failure keep the concern open.
147
+ 7. **Non-state-changing custom:** execute and record the result.
148
+ 8. **revert** (`revert conformance fix Gn`): light-revert the indexed commit, re-run Step 1's canonical tests; on failure stop; on pass re-audit and regenerate.
149
+ 9. Re-enter Step 3.5 with the re-audited block if any concern remains open.
150
+
151
+ Record every final disposition with its **stable ID** as `Gn/Cn - <title>: <disposition>` (or `Gn - <title>: <disposition>` for a single-concern gap) - ticket ID/URL for `follow-up`, result for `custom`; never relabel a `custom` result as a recommendation. This durable record is the machine/audit surface; the interactive render stays handle-based. Then continue to Step 4:
82
152
 
83
153
  ```
84
154
  Closure / conformance: CONFORMS
85
- (or: GAPS <n> open)
86
- - <gap> → proposed remediation: <one line> [if any open]
155
+ (or: GAPS resolved - G1/C1 - Source-image E2E validation: rescope-into-spec;
156
+ G2 - Cache coverage: follow-up (PROJ-123); ...)
87
157
  ```
88
158
 
89
- Then continue to Step 4.
159
+ No auto-proceed: every carried-open decision needs an explicit disposition before Step 4 renders.
160
+
161
+ ### Revert semantics
162
+
163
+ Three tiers, increasing cost — name the tier when a revert is requested:
164
+
165
+ | Tier | What's reverted | Cost | Mechanics |
166
+ |---|---|---|---|
167
+ | Cheap | Council edit, reverted at the `brainstorming` gate | Spec isn't yet plan- or code-bearing | Revise spec, re-present |
168
+ | Light | Conformance fix, reverted at finish | Gap re-opens for a fresh disposition | Revert the `conformance fix Gn` commit(s), re-audit |
169
+ | Heavy | Council edit, reverted at finish | Rewrites the already-ratified contract that drove the plan and code | Amend spec → re-approve → regenerate affected plan/code → re-run verify before ship |
170
+
171
+ A **heavy** revert is not a menu toggle — say so explicitly to the user before proceeding, and do not present it as equivalent-effort to the light tier. The council audit that lets the human identify revert candidates lives in the `brainstorming` spec commit message body (not a committed spec section).
90
172
 
91
173
  ### Step 4: Present Options
92
174
 
@@ -300,7 +382,7 @@ phase_tracker({ action: "complete", phase: "ship" })
300
382
  - Remove a worktree before confirming merge success
301
383
  - Clean up worktrees you didn't create (provenance check)
302
384
  - Run `git worktree remove` from inside the worktree
303
- - Present finish options while a conformance gap is open and undispositioned
385
+ - Auto-proceed past an undispositioned carried-open gap
304
386
  - Skip the guarded plan-doc removal before push on Option 2 when a plan doc was committed
305
387
 
306
388
  **Always:**
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: roasting-the-spec
3
- description: Use after writing a spec, when a spec council is configured (the resolved piGauntlet.specCouncil council, via the gauntlet_setting tool, repo settings over the preset). Auto-dispatched by /skill:brainstorming as the critique pass when members is non-empty (no longer offered). N members on different models critique in parallel, a neutral chair consolidates and adjudicates, the parent proposes dispositions, the user approves.
3
+ description: Use after writing a spec, when a spec council is configured (the resolved piGauntlet.specCouncil council, via the gauntlet_setting tool, repo settings over the preset). Auto-dispatched by /skill:brainstorming as the critique pass when members is non-empty (no longer offered). N members on different models critique in parallel, a neutral chair consolidates and adjudicates, the parent applies its own dispositions and returns an audit for the user to ratify at brainstorming's gate.
4
4
  ---
5
5
 
6
6
  # Roasting the Spec (Spec Council)
7
7
 
8
8
  ## Overview
9
9
 
10
- A multi-model critique pass for a freshly written spec. Each council **member** runs on a different model and critiques the spec independently — different models surface different angles. A neutral **chair** consolidates the critiques and adjudicates disagreements. The parent proposes what to apply; the **user** approves. The council never decides on its own what changes land.
10
+ A multi-model critique pass for a freshly written spec. Each council **member** runs on a different model and critiques the spec independently — different models surface different angles. A neutral **chair** consolidates the critiques and adjudicates disagreements. The parent decides what to apply and applies it before returning; the **user** ratifies (or reverts) the result at brainstorming's single gate. The council never decides on its own what changes land.
11
11
 
12
12
  Auto-dispatched from `/skill:brainstorming` as the critique pass, after the inline lint and before the user review gate, **only when a council is configured** (`members` non-empty). brainstorming owns that gate; when no council is configured it runs a single fresh-`worker` critique instead and does not invoke this skill.
13
13
 
@@ -19,8 +19,8 @@ This skill may read anything and edit **only** the spec under `doc/specs/`. It d
19
19
 
20
20
  - **Members** — independent witnesses. One per configured model, fresh context, read-only.
21
21
  - **Chair** — judge of the testimony. Fresh context (never saw the spec authored); consolidates and resolves member-vs-member conflicts. Final say on conflicts; no say on what gets applied.
22
- - **Parent (you)** — advocate. Proposes apply / defer / reject per finding on scope grounds. Cannot suppress findings.
23
- - **User** — jury. Approves what actually lands, at the existing review gate.
22
+ - **Parent (you)** — advocate, and now also executor. You decide apply / defer / reject per finding on scope grounds, then apply the apply-set yourself (you hold the `edit`/`write` tools; this was always the main-loop model's job, just moved earlier). Cannot suppress findings — every finding lands in the audit as applied, deferred, or rejected.
23
+ - **User** — sole jury. Ratifies (or reverts) the finished spec at brainstorming's one gate — after the apply, not before.
24
24
 
25
25
  ## Configuration and gating
26
26
 
@@ -100,32 +100,41 @@ List the exact member paths in the task text. The `reads:` array injects their c
100
100
 
101
101
  If the configured `chair` model is unreachable, retry once with the inherited model.
102
102
 
103
- ### 3 — Propose dispositions
103
+ ### 3 — Decide and apply
104
104
 
105
- For each cluster in the chair's report, decide and state one of:
105
+ For each cluster in the chair's report, decide one of:
106
106
 
107
- - **apply** — with the concrete edit you will make.
108
- - **defer** — out of scope for this spec; name where it belongs.
109
- - **reject** — with a one-line reason.
107
+ - **apply** — make the concrete edit to the spec under `doc/specs/` now.
108
+ - **defer** — out of scope for this spec; name where it belongs. Do not edit the spec.
109
+ - **reject** — one-line reason. Do not edit the spec.
110
110
 
111
- You are the advocate here, not the judgepropose, do not unilaterally apply.
111
+ Also inline any `external-ref:` cluster you have context for (e.g. a ticket fetched during brainstorming) as part of the apply-setthis is your call, same as any other cluster.
112
112
 
113
- ### 4User gate
113
+ You are the advocate decide on scope grounds — and, unlike a dispatched subagent, also the executor: you hold `edit`/`write` tools directly, so apply the edit yourself instead of proposing it for someone else to make. Do this **before** returning to brainstorming.
114
114
 
115
- Fold the chair's clusters, its `resolved` audit notes, and your proposed dispositions into brainstorming's user review gate. Let the user approve or adjust.
115
+ ### 4 Emit the audit
116
116
 
117
- ### 5Apply and clean up
117
+ Return a structured audit, gate-only (not a committed spec section) three labelled lists:
118
118
 
119
- Apply the approved edits to the spec under `doc/specs/`. Re-run brainstorming's placeholder scan. Remove the temp dir (`rm -rf` the `mktemp -d` path). Then continue with brainstorming's normal commit. Nothing council-related (member files) is ever staged.
119
+ - `Applied:` cluster -> the concrete edit made.
120
+ - `Deferred:` — cluster -> where it belongs.
121
+ - `Rejected:` — cluster -> one-line reason.
120
122
 
121
- Single pass no automatic re-roast loop. The user can invoke this skill again after edits for another round.
123
+ Hand this audit to brainstorming along with the now-final spec. brainstorming writes it into the **spec commit message body** (git-native, readable pre-squash) so it survives for finish-time revert visibility, then shows it to the user alongside the final spec at its one review gate. The user can revert any applied edit there — that gate, not this skill, is where ratification happens.
124
+
125
+ ### 5 — Clean up
126
+
127
+ Re-run brainstorming's placeholder scan over the applied result. Remove the temp dir (`rm -rf` the `mktemp -d` path). Nothing council-related (member files) is ever staged.
128
+
129
+ Single pass — no automatic re-roast loop. The user can invoke this skill again after the gate for another round.
122
130
 
123
131
  ## Red flags — STOP
124
132
 
125
133
  - Running the council when `piGauntlet.specCouncil.members` is absent or empty (brainstorming owns the gate and should have used the worker fallback).
126
134
  - Reading member critique files yourself instead of routing them through the chair.
127
135
  - Writing member files to a relative path (they land in the worktree).
128
- - Auto-applying findings without the user gate.
136
+ - Applying edits without surfacing the audit at brainstorming's gate — apply-before-the-gate is correct; apply-without-the-gate is not.
137
+ - Suppressing a finding instead of routing it to applied, deferred, or rejected in the audit.
129
138
  - Surfacing member-vs-member disagreements to the user instead of letting the chair adjudicate.
130
139
  - Editing anything other than the spec under `doc/specs/`.
131
140
 
@@ -190,9 +190,9 @@ For the fan-out + worktree + patch-integration + conflict mechanics, see `dispat
190
190
 
191
191
  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.)
192
192
  1. **Run the whole-diff code review.** Dispatch `/skill:requesting-code-review` against the worktree's full diff vs `main` (already covered in [The Process](#the-process) step "After all tasks"). Address Critical and Moderate findings before handoff. (Consumers wanting an in-flow project-specific audit re-add it as an explicit step in `.pi/gauntlet-overrides.md`, or run `/self-audit` manually.)
193
- 2. **Close the loop — conformance check.** The review in step 1 is plan-vs-code (single-step); it inherits any requirement the plan already dropped. Before marking verify complete, dispatch a fresh-context **`conformance-reviewer`** — its **own** dispatch, never fused into the step-1 review — to confront the deliverable (code **and** docs) against the *origin* — the spec **and** the original prompt — per `verification-before-completion/reference/conformance-check.md`. Pass the spec path, the verbatim original prompt, and the full diff. On `GAPS`, do not auto-fix or auto-proceed: run the remediation loop in `verification-before-completion/reference/conformance-check.md` "When the check finds gaps" (disposition menu isolated fix wavesbounded delta re-audit, capped by `gauntlet_setting({ key: "closureReview" }).maxFixRounds`). Only when the verdict is `CONFORMS` (or every gap is dispositioned) call `phase_tracker({ action: "complete", phase: "verify" })`.
194
- 3. Summarize what was implemented (tasks completed, files changed, test counts, code-review verdict). Give the closing loop its **own section** `Closure / conformance: CONFORMS` (or `GAPS` with each gap and its disposition) so the user sees intent-fidelity as a first-class line before any finishing decision, not buried in the review verdict.
195
- 4. **Proceed to finishing — no confirmation prompt.** When the verdict is `CONFORMS` (or every gap is dispositioned), invoke `/skill:finishing-a-development-branch` immediately. Its Step 4 menu (squash / PR / keep / discard) is the human gate; a separate "ready to finish?" prompt only stacks a second stop in front of it. Open gaps are already owned by step 2, so nothing is left to decide here. Manual testing is a follow-up after the finishing choice (on `<base-branch>` after a squash-merge, or on the PR branch), never a reason to hold this gate.
193
+ 2. **Close the loop — conformance check.** The review in step 1 is plan-vs-code (single-step); it inherits any requirement the plan already dropped. Before marking verify complete, dispatch a fresh-context **`conformance-reviewer`** — its **own** dispatch, never fused into the step-1 review — to confront the deliverable (code **and** docs) against the *origin* — the spec **and** the original prompt — per `verification-before-completion/reference/conformance-check.md`. Pass the spec path, the verbatim original prompt, and the full diff. Follow that reference for the partition rule, concern decomposition, and fix-loop mechanics; do not reimplement them here. The fix loop may drive `plan_tracker` to surface fix-wave progress (task name = `Gn: <short desc>`, lifecycle `pending in_progress complete` per gap); it never calls `phase_tracker`. Call `phase_tracker({ action: "complete", phase: "verify" })` only when the reference says the handoff is durably complete: either a current `CONFORMS` result, or a current `## Closure / conformance` inventory whose carried-open concerns all come from valid deferred gaps, including `recommended: fix` gaps carried open because a declared precondition made the fix loop unavailable (`maxFixRounds: 0`, or no eligible named-branch worktree). A started positive-cap fix loop that blocks, fails, or exhausts its rounds with an open `fix` gap is escalation, not completion; on escalation, do not complete verify, stop and report.
194
+ 3. Summarize what was implemented (tasks completed, files changed, test counts, code-review verdict). Emit the `## Closure / conformance` block exactly as defined in `verification-before-completion/reference/conformance-check.md`: it must open with the two-line sentinel (`status: CONFORMS (0 open)` or `status: GAPS (N open)`, then `audited-base: <full HEAD SHA>`), then carry the exact durable concern schema by reference with no renamed or reformatted fields. `finishing-a-development-branch` Step 3.5 consumes that block verbatim.
195
+ 4. **Proceed to finishing — no confirmation prompt.** Once verify is complete per step 2's criterion, invoke `/skill:finishing-a-development-branch` immediately. Its Step 4 menu (squash / PR / keep / discard) is the human gate; a separate "ready to finish?" prompt only stacks a second stop in front of it. Carried-open concerns are resolved there per concern via the `## Closure / conformance` block from step 3. Manual testing is a follow-up after the finishing choice (on `<base-branch>` after a squash-merge, or on the PR branch), never a reason to hold this gate.
196
196
 
197
197
  ## Red Flags — STOP
198
198
 
@@ -215,7 +215,7 @@ For the fan-out + worktree + patch-integration + conflict mechanics, see `dispat
215
215
  - `/skill:using-git-worktrees` — set up isolation first (small changes can branch in place with user approval)
216
216
  - `/skill:writing-plans` — creates the plan this skill executes
217
217
  - `/skill:requesting-code-review` — review template for reviewer subagents
218
- - `/skill:finishing-a-development-branch` — invoked automatically once the conformance verdict is `CONFORMS` (or all gaps dispositioned)
218
+ - `/skill:finishing-a-development-branch` — invoked automatically once every gap is fixed (`CONFORMS`) or carried open
219
219
 
220
220
  **Subagents follow by default:**
221
221
 
@@ -57,7 +57,7 @@ Skip any step = lying, not verifying
57
57
  | Regression test works | Red-green cycle verified | Test passes once |
58
58
  | Agent completed | VCS diff shows changes | Agent reports "success" |
59
59
  | Requirements met | Line-by-line checklist | Tests passing |
60
- | Intent delivered (loop closed) | Fresh reviewer audits code+doc vs origin spec + prompt (`reference/conformance-check.md`) | Plan-vs-code review, tests passing |
60
+ | Intent delivered (loop closed) | Fresh reviewer audits code+doc vs origin spec + prompt; verify completes only on a current `CONFORMS` result or a current durable carried-open closure inventory permitted by `reference/conformance-check.md` (including declared-precondition-unavailable `recommended: fix` gaps). A started positive-cap fix loop that blocks, fails, or exhausts rounds with an open `fix` gap is escalation, not completion. | Plan-vs-code review, tests passing |
61
61
 
62
62
  ## Rationalization Prevention
63
63
 
@@ -89,131 +89,378 @@ The reviewer **proposes, it does not dispose.** It emits structured gap blocks
89
89
  the verify gate) drives disposition, fixes, and re-audit. The reviewer never edits,
90
90
  dispatches, or re-audits itself.
91
91
 
92
- ### CONFORMS
93
-
94
- Record the verdict in the completion summary's closure section and proceed.
92
+ ### Disposition — verdict-then-`recommended` partition, no menu
93
+
94
+ Render the enumerated gap list each as `Gn [VERDICT] origin — remediation
95
+ (recommended: fix|accept|rescope)` — then partition and act, in this exact order.
96
+ No prompt, no menu: this partition is deterministic and exhaustive.
97
+
98
+ 1. **Verdict `CONFORMS`** (no gaps) → record the verdict in the completion
99
+ summary's closure section and proceed. No loop.
100
+ 2. **Any gap is `UNAUTHORIZED`** → that gap **always** defers to the finish gate,
101
+ regardless of its `recommended` value. Never auto-remove or auto-accept
102
+ unrequested code here.
103
+ 3. **Every remaining `PARTIAL`/`MISSING`/`DRIFTED` gap**:
104
+ - `recommended: fix` → auto-run the fix loop below — **unless a declared
105
+ fix-loop precondition is unavailable** (`maxFixRounds: 0`, or no eligible
106
+ named-branch worktree), in which case carry the gap **OPEN** (see the fix
107
+ loop's precondition and `maxFixRounds: 0` notes).
108
+ - `recommended: accept` or `recommended: rescope` → carry the gap **OPEN**,
109
+ deferred to the finish gate. Do not apply a spec edit here — the finish
110
+ gate owns disposition of deferred gaps.
111
+
112
+ So the fast path (all gaps `recommended: fix`, none `UNAUTHORIZED`, cap > 0,
113
+ eligible named-branch worktree) therefore auto-runs the fix loop with no menu,
114
+ stop, or confirmation; any other mix carries the
115
+ `accept`/`rescope`/`UNAUTHORIZED` gaps OPEN while the `fix` gaps run. Record every gap's outcome (`CONFORMS`-closed or carried OPEN) in the
116
+ `## Closure / conformance` block (schema below).
117
+
118
+ **Re-partition after every re-audit.** A re-audit can introduce `Gn+1` or flip a
119
+ carried gap's `recommended`. Re-run steps 1-3 above over the **full current
120
+ open-gap set** each time the reviewer returns a report — never reuse a stale
121
+ partition from an earlier round.
122
+
123
+ ### Fix loop — SDD Parallel-Wave mirror, per round
124
+
125
+ Mirrors `subagent-driven-development` Parallel-Wave Mode and reuses its
126
+ `plan_tracker` progress surface. Runs entirely inside the gate — it invokes
127
+ **no** `phase_tracker` calls (`phase_tracker({ phase: "implement" })` errors
128
+ while verify is `in_progress`) and does **not** enter SDD's phase machinery.
129
+ Only the fan-out/integrate/review shape and `plan_tracker` are reused.
130
+
131
+ **Precondition — worktree required.** The loop needs a worktree HEAD to branch
132
+ fixes from. On the ad-hoc `finishing-a-development-branch` paths that run in a
133
+ normal repo (`GIT_DIR == GIT_COMMON`) or detached HEAD, there is no such HEAD:
134
+ skip this loop, carry every `fix` gap OPEN, and resolve it at finish via the
135
+ canonical Disposition catalog and availability table below. `fix-now` is
136
+ unavailable there; any other disposition is offered only when its table
137
+ prerequisites hold.
138
+
139
+ Per round:
140
+
141
+ 1. **`plan_tracker` init** with the round's gaps as tasks. Wave-prefix tasks
142
+ when the reviewer's `Parallel-safe:` line marks a `conflicts` pair (file OR
143
+ `touched-resources` overlap) — that pair runs in separate serial waves;
144
+ `disjoint` gaps share one wave. Lifecycle per gap: `pending` →
145
+ `in_progress` → `complete`. This re-init **replaces** the implement phase's
146
+ completed task list in the singleton widget — state-safe, since
147
+ `phase-tracker.ts` `applyPlanActivity` only auto-completes `implement`
148
+ while it is `in_progress`; the widget now shows fix-wave progress during
149
+ verify.
150
+ 2. **Per gap** (task → `in_progress`): dispatch `implementer` (fresh context,
151
+ `worktree: true`, `cwd` = the conformance worktree, `touched-files` from the
152
+ gap block as an explicit ownership boundary) → dispatch `spec-reviewer` on
153
+ the gap-block reference contract below → task → `complete`.
154
+ 3. **Integrate** serially via `git apply` onto the worktree HEAD, one gap's
155
+ patch at a time. Failure handling is inherited verbatim from
156
+ `dispatching-parallel-agents` "Review and Integrate": textual conflict →
157
+ re-run one agent sequentially with the other's integrated changes as
158
+ context; semantic conflict (applies clean, suite fails) → re-run the
159
+ offending task sequentially on integrated HEAD; a failed agent → integrate
160
+ the successes, then retry the failure with fresh context including the
161
+ integrated changes. A `BLOCKED`/`NEEDS_CONTEXT` return surfaces to the user.
162
+ 4. **Test gate** on the integrated tree, using the project's canonical test
163
+ command. A failure re-enters the failure-handling rules above.
164
+ 5. **`code-reviewer` once** on the round's cumulative fix delta (not per gap).
165
+ 6. **Re-audit**: re-dispatch `conformance-reviewer` over the fixes **plus** the
166
+ regression guard (any prior-`DELIVERED` requirement whose `evidence` file
167
+ the fix diff touched). Pass the full prior conformance report (every row,
168
+ including DELIVERED rows and their `evidence` `file:line`) and the round's
169
+ fix diff. Inject `model:` call-site per `gauntlet_setting({ key:
170
+ "closureReview" }).model` — same mechanism as the initial audit; omit
171
+ `model:` when it is `undefined` to inherit the parent's model. The
172
+ phase-tracker closure guard blocks a dispatch that omits `model:` when
173
+ `closureReview.model` is set, and warns (non-blocking) on one whose model
174
+ differs.
175
+ 7. **Converge or continue**: verdict `CONFORMS` → record it, done. Open gaps
176
+ within the cap → re-partition (per the rule above) and start the next
177
+ round. Cap (`gauntlet_setting({ key: "closureReview" }).maxFixRounds`,
178
+ default `2`, floors negatives at `0`, coerces non-integers to `2`) reached
179
+ with an open `fix` gap → **escalate to the human** with the per-gap
180
+ round-by-round verdict trail. Escalation is the sole non-completing
181
+ terminal state — no silent re-loop, no auto-ship.
182
+
183
+ Commit each per-gap fix with the message **`conformance fix Gn`** (durable,
184
+ `git log`-readable pre-squash) so the finish gate and any revert can identify
185
+ auto-applied fixes.
186
+
187
+ **`maxFixRounds: 0`**: skip this loop entirely. Every `recommended: fix` gap
188
+ becomes carried OPEN to the finish gate instead of auto-running — the user
189
+ opted out of auto-fix, so treat `fix` gaps like any other deferred gap. This
190
+ differs from a cap > 0 that is *exhausted*: that case escalates mid-verify
191
+ because the loop tried and could not converge.
192
+
193
+ ### `spec-reviewer` gap-block reference contract
194
+
195
+ Per-gap `spec-reviewer` in step 2 above is a **pre-integration mechanical
196
+ check**, distinct from the round-level re-audit in step 6 (which still
197
+ references the *origin* — spec + original prompt — unchanged). Frame the
198
+ per-gap dispatch against the **gap block**, not a plan task:
199
+
200
+ - **Requirement** = the gap's `origin` + `remediation` (what must be true
201
+ after the fix).
202
+ - **Closure proof** = the patch satisfies that requirement within the gap's
203
+ `touched-files` — nothing missing, nothing extra.
204
+ - **Output** = `spec-reviewer`'s normal MATCH/DRIFT verdict, referenced to the
205
+ gap block instead of a plan task.
206
+
207
+ This is a task-framing contract in the dispatch, not a new persona.
208
+
209
+ ## Concern decomposition
210
+
211
+ The main verification orchestrator — **not** `conformance-reviewer` — decomposes
212
+ each carried-open gap into concerns when it writes the completion summary. A
213
+ **gap** is the reviewer's overall finding; a **concern** (`Gn/Cn`) is one
214
+ consequence within it that could reasonably receive a *different* disposition.
215
+ Observations that necessarily move together stay one concern.
216
+
217
+ The orchestrator reasons from:
218
+
219
+ - The final reviewer coverage row and structured gap block.
220
+ - The origin spec and original prompt already supplied to verification.
221
+ - Session-observed blockers, prerequisite checks, and fix-loop outcomes.
222
+ - The round history and current touched-file/resource ownership.
223
+
224
+ Per gap, apply these rules **in order**:
225
+
226
+ 1. Extract atomic unmet clauses and remediation actions from `origin`,
227
+ `evidence`, and `remediation`. Add a session-observed blocker **only** when a
228
+ tool result or fix-loop outcome established it.
229
+ 2. **Split** two points when either could be fixed, accepted, rescoped, or
230
+ followed up without imposing the same disposition on the other.
231
+ 3. **Keep together** when one action is meaningful only with the other, or no
232
+ different disposition could be executed independently.
233
+ 4. Map **every** unmet clause, remediation action, and established blocker to at
234
+ least one concern. Do **not** add a requirement absent from the origin or
235
+ prompt — invent nothing.
236
+ 5. Order concerns by first appearance in the origin/remediation and assign
237
+ `C1`, `C2`, and so on (source order).
238
+
239
+ A valid decomposition has no omitted source point, no invented requirement or
240
+ evidence, and a concern-scoped remediation plus ownership estimate for every
241
+ `fix-now` candidate. Shared evidence may appear in multiple concerns. When the
242
+ source cannot support a safe split, the fallback is **one indivisible `Gn/C1`**
243
+ concern carrying the complete gap and the known blocker; decomposition never
244
+ blocks on obtaining richer prose from the unchanged reviewer.
245
+
246
+ Field derivation is explicit: `title` and `unresolved` summarize the unmet
247
+ clause; `origin` narrows the gap `origin` to this concern's specific clause
248
+ without inventing a new requirement; `remediation` states the concern-scoped
249
+ remediation action drawn from the gap `remediation`; `impact` states the
250
+ consequence already implied by the origin requirement; `evidence` copies
251
+ reviewer evidence plus verified session observations;
252
+ `touched-files`/`touched-resources` narrow the gap ownership where supported,
253
+ otherwise `unknown`/`none`. For an `UNAUTHORIZED` concern there is no origin
254
+ requirement to narrow: keep `origin: none (scope creep)` verbatim — never invent
255
+ an origin clause; derive `unresolved` from the reviewer's `evidence`/`remediation`
256
+ as a plain description of the unrequested behavior; and derive `impact` from the
257
+ consequence of retaining, removing, or ratifying that behavior, not from an origin
258
+ requirement. These per-concern fields persist the exact contract
259
+ the concern-scoped fix projection consumes after pruning. **`evidence: absent`
260
+ is an unmet-delivery fact, not
261
+ an external blocker** — never relabel missing implementation evidence as a
262
+ blocker. A malformed structured reviewer gap block — missing its stable `Gn`
263
+ label or any required field (`verdict`, `origin`, `evidence`, `remediation`,
264
+ `touched-files`, `touched-resources`, `recommended`) — triggers a **fresh
265
+ audit**; a complete structured reviewer gap block does not — the orchestrator
266
+ decomposes it or emits the indivisible fallback.
267
+
268
+ ## Disposition catalog and availability
269
+
270
+ Each concern lists **every** supported disposition, its concrete effect, and
271
+ current availability. This table is the single availability contract, referenced
272
+ by both this verify gate and `finishing-a-development-branch`:
273
+
274
+ |Disposition|Ordinary gap effect|`UNAUTHORIZED` effect|Available when|
275
+ |---|---|---|---|
276
+ |`fix-now`|Complete missing implementation or validation.|Remove the unrequested code or behavior.|Named-branch worktree; `maxFixRounds > 0`; concern ownership is known; every required local/external resource is accessible.|
277
+ |`accept-into-spec`|Ratify intentional implemented behavior when the written contract is stale.|Ratify the unrequested behavior as approved scope.|A writable spec exists and there is concrete behavior to ratify.|
278
+ |`rescope-into-spec`|Explicitly remove or defer the origin requirement from this workflow.|Unavailable: scope creep has no origin requirement to defer.|The verdict is not `UNAUTHORIZED` and a writable spec exists.|
279
+ |`follow-up`|Keep the concern valid but transfer it to separately owned work.|Transfer a separately valid decision or removal task.|The concern can stand alone and the project defines an executable issue-tracker convention. Without one, mark unavailable and direct the user to `custom` to name another durable owner.|
280
+ |`custom`|Execute another user-defined disposition after its effect is clarified.|Same.|Always visible; executable only after the user supplies a concrete effect. It is never an automatic recommendation.|
281
+
282
+ A failed condition leaves the disposition visible and names the exact missing
283
+ prerequisite. `touched-files: unknown` makes `fix-now` unavailable until
284
+ ownership is established. A normal checkout (`GIT_DIR == GIT_COMMON`) or detached
285
+ HEAD cannot dispatch the isolated fix loop at all - it has no named-branch
286
+ worktree to branch fixes from - so `fix-now` stays unavailable there regardless
287
+ of ownership; resolve those concerns manually at finish. `maxFixRounds: 0`
288
+ (audit-only) likewise leaves `fix-now` visible but unavailable — the user
289
+ configured no auto-fix loop, and finish-time selection never bypasses or resets
290
+ that cap; a concrete `custom`/manual-fix disposition remains possible. `UNAUTHORIZED` cards
291
+ replace the primary question with
292
+ `Should this unrequested behavior become part of the current workflow?`, so
293
+ removal and ratification are not presented as missing-feature choices.
294
+
295
+ Reviewer tokens map to executable concern recommendations:
296
+
297
+ - `fix` maps to `fix-now`; for `UNAUTHORIZED`, that means removal.
298
+ - `accept` maps to `accept-into-spec`; for `UNAUTHORIZED`, that means ratification.
299
+ - `rescope` maps to `rescope-into-spec` and is invalid for `UNAUTHORIZED`.
300
+ - `follow-up` may replace an unavailable `fix-now`/`rescope-into-spec` **only**
301
+ when the concern remains valid, has separate ownership, and the issue-tracker
302
+ action is executable.
303
+
304
+ The orchestrator may choose another named disposition only when current evidence
305
+ supports its stated effect. If no named executable disposition is available, the
306
+ concern serializes `recommended: none` - the durable state for "no named
307
+ executable choice exists" - and its `rationale` must name the exact missing
308
+ prerequisites plus the concrete custom effect still required. `custom` is never
309
+ auto-recommended, so `none` never silently resolves to `custom`.
310
+
311
+ A concern with `recommended: none` is excluded from the recommended set. Before
312
+ any exhaustive `Apply recommended set`, the finish gate asks for a targeted
313
+ custom approval that supplies a concrete effect for that one concern (finishing
314
+ owns the exact reply syntax - a per-item `custom(...)` decision - not an `apply
315
+ recommended` variant). That reply approves only that concrete custom effect for
316
+ that concern. Validate and normalize it immediately: if the effect is ambiguous or
317
+ unexecutable, clarify and keep the concern open; if executable, record it as a
318
+ **pending approved custom decision** and remove that concern from the still-open
319
+ inventory used to build the recommended set. If other open concerns remain,
320
+ render the exhaustive recommended set for them and visibly carry the pending
321
+ approved custom decision through the existing action-order and freshness
322
+ barriers; `apply recommended` approves only the remaining recommendations. If no
323
+ other concerns remain, execute the approved custom directly through the existing
324
+ mechanics. The final disposition record keeps this concern as a `custom` result;
325
+ never relabel it as a model recommendation.
326
+
327
+ **Never recommend an unavailable disposition or an unexecutable `custom`
328
+ placeholder.**
329
+
330
+ `revert` is a separate action, not a generic concern disposition. The commit
331
+ index stays gap-granular (`conformance fix Gn`). A listed gap-level commit makes
332
+ revert visible on every concern card under that gap, with an explicit warning
333
+ that the **entire gap commit** is reverted. Existing light-revert semantics
334
+ remain: revert the indexed commit, re-audit, and return to the decision gate
335
+ only if a concern remains open.
336
+
337
+ ## Closure / conformance
338
+
339
+ Emit this block in the verify completion summary. It is the durable handoff
340
+ `finishing-a-development-branch` Step 3.5 consumes — parseable even if session
341
+ context was pruned. Verify completes when every gap is either fixed
342
+ (`CONFORMS`) or carried OPEN as a deferred gap - `accept`/`rescope`/`UNAUTHORIZED`,
343
+ or a `recommended: fix` gap carried open because a declared fix-loop precondition
344
+ was unavailable so the loop never started (`maxFixRounds: 0`, or no eligible
345
+ named-branch worktree - normal checkout / detached HEAD). Escalation - a started
346
+ positive-cap loop that exhausted its rounds or blocked/failed with an open `fix`
347
+ gap - is the one non-completing terminal state; the precondition-unavailable
348
+ carried-open `fix` state is valid closure inventory, not escalation.
349
+
350
+ ### Handoff sentinel and freshness anchor - every handoff
351
+
352
+ Every `## Closure / conformance` block - a `CONFORMS` no-card handoff and a
353
+ carried-open GAPS handoff alike - **opens with a two-line sentinel** that lets
354
+ the finish gate re-verify freshness after context pruning, with no session
355
+ history:
356
+
357
+ ```text
358
+ status: CONFORMS (0 open) # or: status: GAPS (N open)
359
+ audited-base: <full HEAD SHA at audit time>
360
+ ```
95
361
 
96
- ### GAPS disposition menu
362
+ `N` = count of open concerns (decision units), matching the number of emitted
363
+ concern cards. Record `audited-base` as the full 40-char HEAD SHA at audit time;
364
+ never abbreviate. This block is the **single source** for the freshness rule;
365
+ `finishing-a-development-branch` links here rather than restating it.
97
366
 
98
- Do **not** auto-proceed and do **not** auto-fix. Render the enumerated gap list —
99
- each as `Gn [VERDICT] origin remediation (recommended: fix|accept|rescope)` — then
100
- a numbered prompt (a chat turn cannot express a bare keystroke):
367
+ **Freshness rule.** The audit-input rule requires deliverables committed before
368
+ auditing, so `audited-base` captures the audited state; freshness compares that
369
+ commit to the **current working tree**, not to HEAD (a commit-to-commit diff
370
+ misses staged/unstaged edits when HEAD has not moved). Run two cheap commands:
101
371
 
372
+ ```bash
373
+ ROOT=$(git rev-parse --show-toplevel)
374
+ git -C "$ROOT" diff --stat <audited-base> -- . # tracked changes since the audited commit (staged + unstaged)
375
+ git -C "$ROOT" status --porcelain --untracked-files=all # new/untracked deliverables
102
376
  ```
103
- [1] apply all recommended dispositions
104
- [2] review per-gap (override fix/accept/rescope before applying)
105
- ```
106
-
107
- `[1]` applies each gap's `recommended` disposition, **except** any gap whose
108
- `recommended` is `accept` or `rescope`: list those and require an explicit confirming
109
- reply before their spec edits land (accept/rescope rewrite the origin — never on the
110
- unconfirmed fast path). `[2]` prompts a per-gap override, then applies.
111
377
 
112
- Disposition semantics:
378
+ Any output from either command, any doubt, a missing/mismatched sentinel, or any
379
+ closure block not opening with the two-line sentinel above (e.g. a legacy
380
+ `Gn: PARTIAL - recommended: ...` row) triggers a fresh audit - never infer
381
+ `CONFORMS` from the absence of cards. This is a lightweight freshness check (two
382
+ git commands, no hashing or identity fields).
383
+
384
+ **Sentinel validation.** `status: CONFORMS` requires `N = 0` and **no** emitted
385
+ concern cards; `status: GAPS` requires `N > 0` exactly matching the emitted card
386
+ count (`Gn/Cn` blocks), not merely gap headers. A mismatch is stale -> re-audit.
387
+
388
+ **Audit-time input rule.** Stage or commit untracked deliverables before
389
+ auditing, since `git diff <base> -- .` omits untracked files from the reviewer
390
+ payload.
391
+
392
+ For each carried-open gap, emit a durable gap header plus one card per concern
393
+ (decomposition and derivation rules above). In rendered cards, recommendation
394
+ lists, clarification lists, and final disposition records, every user-facing
395
+ identifier carries both its ID **and** title; bare `Gn`/`Cn` or grouped
396
+ identifier lists without titles are prohibited. The only exceptions are the
397
+ machine/interaction tokens the grammar requires: bare `Gn/Cn` inside typed
398
+ response tokens, the literal `conformance fix Gn` commit/action identifiers, and
399
+ the flat `auto-applied fix commits` index below. The surrounding prompt or list
400
+ must map each token to its titled concern or gap before asking for input.
401
+
402
+ ```text
403
+ G1 - Source-image validation is incomplete
404
+ verdict: PARTIAL
405
+ origin: <requirement source and clause>
406
+ evidence: <current file:line or observed state>
407
+ blocker: <specific blocker, or none>
408
+ touched-files: <paths or unknown>
409
+ touched-resources: <resources or none>
410
+ round history: R1 <verdict/action>, R2 <verdict/action>, ...
411
+
412
+ G1/C1 - End-to-end OCR output has not been validated
413
+ unresolved: <plain statement of the concern>
414
+ impact: <why it matters to the current workflow>
415
+ origin: <requirement source and clause, narrowed from the gap origin; or none (scope creep) for UNAUTHORIZED>
416
+ remediation: <concern-scoped remediation action>
417
+ evidence: <concern-specific evidence or blocker>
418
+ touched-files: <concern-scoped paths, narrowed from the gap; or unknown>
419
+ touched-resources: <concern-scoped resources, narrowed from the gap; or none>
420
+ available dispositions:
421
+ fix-now: <effect and availability>
422
+ accept-into-spec: <effect and availability>
423
+ rescope-into-spec: <effect and availability>
424
+ follow-up: <effect and availability>
425
+ custom: <effect and availability>
426
+ recommended: <available named disposition, or none>
427
+ rationale: <why this is the best current choice; for none, the missing prerequisites and the concrete custom effect required>
428
+ ```
113
429
 
114
- - `fix` dispatch a remediation unit (below), then re-audit. For an `UNAUTHORIZED`
115
- gap, "fix" = **remove** the unrequested code.
116
- - `accept` — the **main session** (not a subagent) folds the deviation into the spec as
117
- a dated decision (template below). For `UNAUTHORIZED`, accept = keep the behavior,
118
- document it as intended.
119
- - `rescope` — the main session records the requirement in the spec as an explicit
120
- out-of-scope / deferred item, dated.
430
+ All concerns in a gap must be represented.
121
431
 
122
- Dated-decision template (append to the spec's decisions/deviations section):
432
+ Then a single flat revert index of **every** `conformance fix Gn` commit the fix
433
+ loop produced this run — including gaps that later converged to `CONFORMS`
434
+ (a closed gap has no card above, so its commit lives only here) — since the
435
+ finish gate's revert option needs them all:
123
436
 
124
437
  ```
125
- - YYYY-MM-DD accept|rescope Gn: <requirement/behavior> <one-line rationale> (conformance gate)
126
- ```
127
-
128
- **Commit accept/rescope spec edits BEFORE any fix wave dispatches:** pi-cohort
129
- rejects a dirty tree on a `worktree: true` dispatch, and the re-audit must read the
130
- amended spec. If a round has only accept/rescope and no `fix`, the edits land, the
131
- verdict is recorded, and no re-audit runs.
132
-
133
- ### Fix dispatch — reuse dispatching-parallel-agents mechanics
134
-
135
- Fixes reuse the `dispatching-parallel-agents` fan-out primitive. Invoke **no**
136
- `phase_tracker` / `plan_tracker` calls and do **not** enter `subagent-driven-development`
137
- Parallel-Wave Mode (that mode opens with `phase_tracker({ phase: "implement" })`, which
138
- errors while the verify phase is `in_progress`, and needs a plan the fix loop lacks).
139
-
140
- **Precondition — worktree required.** Fix-via-dispatch needs a worktree HEAD to branch
141
- from. On the ad-hoc `finishing-a-development-branch` paths that run in a normal repo
142
- (`GIT_DIR == GIT_COMMON`) or detached HEAD, there is no such HEAD: the menu offers
143
- `accept` / `rescope` and **manual fix-in-place** only; unresolved gaps route to escalation.
144
- The loop below applies only when the gate already runs inside a worktree.
145
-
146
- **Wave grouping** comes from the reviewer's `Parallel-safe:` line: `disjoint` gaps form
147
- one parallel wave; any `conflicts` pair splits into separate serial waves. A pair conflicts
148
- on **file OR runtime-resource** overlap - two gaps whose fixes touch disjoint files but whose
149
- verification shares a `touched-resources` entry (DB/schema, port, fixture, external service,
150
- shared temp path) are **not** parallel-safe and run in separate serial waves, identical to
151
- planned-execution wave grouping. This is why the reviewer certifies both axes.
152
-
153
- **Dispatch shape** (mirrors `dispatching-parallel-agents`):
154
-
155
- ```ts
156
- subagent({
157
- context: "fresh",
158
- worktree: true,
159
- cwd: "<abs worktree path, from git rev-parse --show-toplevel>",
160
- tasks: [
161
- { agent: "implementer",
162
- task: "Close conformance gap G1. Origin requirement: <origin>. What's missing: " +
163
- "<remediation>. Satisfy the requirement; do not expand scope. " +
164
- "Ownership boundary — modify only: <touched-files>." },
165
- // one task per disjoint gap in this wave
166
- ],
167
- })
438
+ auto-applied fix commits: <Gn: SHA>, <Gm: SHA>, ... (revertable)
168
439
  ```
169
440
 
170
- - Unit = `implementer`, fresh context, `worktree: true`, `cwd` = the conformance
171
- worktree. Pass `touched-files` as an explicit ownership boundary.
172
- - **Integrate** serially via `git apply` back onto the worktree HEAD the fix ships in
173
- the same worktree and rides `finishing-a-development-branch`'s squash. No new merge machinery.
174
- - **Failure handling is inherited verbatim** from `dispatching-parallel-agents`
175
- "Review and Integrate": textual conflict → re-run one agent sequentially with the
176
- other's integrated changes as context; semantic conflict (applies clean, suite fails)
177
- → re-run the offending task sequentially on integrated HEAD; a failed agent → integrate
178
- the successes, then retry the failure with fresh context including the integrated changes.
179
- A `BLOCKED` / `NEEDS_CONTEXT` return surfaces to the user.
180
- - **`code-reviewer` over the integrated fix delta, once per round** (not per gap) — gap
181
- fixes land after the branch's final code review, so review the round's cumulative diff.
182
- - **`spec-reviewer` is excluded** — plan-vs-code is the wrong reference point; the re-audit
183
- checks fixes against the origin.
184
- - **Test gate** on the integrated tree after the round's waves apply, using the project's
185
- canonical test command. A failure re-enters the failure-handling rules above.
186
-
187
- One round = dispatch waves serial integrate `code-reviewer` on round delta → test
188
- gate re-audit.
189
-
190
- ### Delta re-audit + cap
191
-
192
- Re-dispatch `conformance-reviewer` for a delta-scoped re-audit. Pass:
193
-
194
- - the **full prior conformance report** — every row including DELIVERED rows and their
195
- `evidence` `file:line` (needed for the regression guard), not just gap IDs;
196
- - the **fix diff** for the round.
197
-
198
- The reviewer (not the orchestrator) computes the regression intersection: it re-verifies
199
- the gaps marked `fix` this round **plus** any previously-DELIVERED requirement whose
200
- `evidence` file appears in the fix diff. It reuses `G1..Gn`, marking each `DELIVERED`,
201
- still-open with its prior verdict, or introducing `Gn+1`.
202
-
203
- - The re-audit dispatch carries the **same call-site `model:` injection** as the initial
204
- audit (when `piGauntlet.closureReview.model` is set, the phase-tracker closure guard
205
- blocks a `conformance-reviewer` dispatch that omits `model:`, and warns — non-blocking —
206
- on one whose model differs from the configured value).
207
- - New or still-open gaps within the cap re-enter the menu above.
208
- - **Cap: `gauntlet_setting({ key: "closureReview" }).maxFixRounds`** (the tool applies the
209
- default `2`, floors negatives at `0`, and coerces non-integers to `2`). `0` = audit-only:
210
- `GAPS` renders an accept/rescope-only menu and any unresolved gap escalates instead of
211
- dispatching a fix.
212
- - **On non-convergence** (cap reached with open gaps): **escalate to human** with the
213
- per-gap round-by-round verdict trail. No silent re-loop, no auto-ship.
214
-
215
- No completion claim stands over a gap that is neither fixed, accepted, nor rescoped.
216
- "Surface, don't auto-fix": the orchestrator presents options, the user decides.
441
+ ## Concern-scoped fix projection
442
+
443
+ When the finish gate selects `fix-now` on some concerns of a gap, the fix loop
444
+ above runs against a **projected** contract, not the original whole-gap block.
445
+ For each parent gap with selected `fix-now` concerns, project only those
446
+ concerns into one gap-scoped fix contract:
447
+
448
+ - The parent gap ID.
449
+ - The selected concern IDs and titles.
450
+ - Their origin clauses, concern remediations, and evidence.
451
+ - The **union** of the selected concerns' touched files/resources (ownership
452
+ boundary).
453
+
454
+ Rescoped, accepted, and followed-up sibling concerns are **excluded** from the
455
+ projection. The `implementer` and the pre-integration `spec-reviewer` receive
456
+ this projected contract in place of the original whole-gap block.
457
+
458
+ The projected task runs the existing full loop above: it retains the gap-level
459
+ `conformance fix Gn` commit name, reruns the project's tests, runs
460
+ `code-reviewer`, re-audits against the amended spec, and reenters the gate only
461
+ if concerns remain. Gap-level revert stays available through the flat commit
462
+ index. The gate records the final result by concern ID and title before showing
463
+ branch integration options.
217
464
 
218
465
  ## Checklist
219
466