pi-gauntlet 4.5.1 → 4.6.1

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,27 @@
1
1
  # Changelog
2
2
 
3
+ ## v4.6.1 - 2026-08-04
4
+
5
+ Lazy-load the conformance disposition protocol (#5). The carried-open disposition
6
+ grammar (dense render, response grammar, execute order) moves out of
7
+ `finishing-a-development-branch/SKILL.md` Step 3.5 into a new GAPS-only
8
+ `reference/disposition-protocol.md`, so the common CONFORMS fast path no longer
9
+ pays that grammar's token cost. The human decision menu and the CONFORMS/summary
10
+ render stay inline. Byte-for-byte relocation, behavior unchanged. Also
11
+ single-sources the `maxFixRounds: 0` / precondition-unavailable carry-OPEN rule
12
+ in `conformance-check.md` (one authoritative statement plus four
13
+ back-references), retaining every distinct contract.
14
+
15
+ ## v4.6.0 - 2026-07-30
16
+
17
+ Default supersession marking (#4). When a new spec replaces a known predecessor,
18
+ brainstorming's spec-writing step edits the old spec to add a
19
+ `> **Superseded by:** [<path>](<href>) - <scope>` banner under its title —
20
+ append-only, mark-never-delete, no transitive rewrite, no corpus sweep. The scout
21
+ task template in gatherer.md follows such banners during context gathering. Syntax
22
+ is overridable via `.pi/gauntlet-overrides.md`; placement and retention semantics
23
+ are fixed. No new settings key.
24
+
3
25
  ## v4.5.1 - 2026-07-30
4
26
 
5
27
  Fix the v4.5.0 package startup regression that exposed the new top-level
package/README.md CHANGED
@@ -35,7 +35,7 @@ pi-gauntlet's only hard dependency is pi-cohort - every gate that dispatches a r
35
35
 
36
36
  Concretely, one change through the gauntlet:
37
37
 
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.
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. If the spec replaces a known prior spec, brainstorming marks the predecessor with a `> **Superseded by:**` banner under its title (default format, syntax overridable via `.pi/gauntlet-overrides.md`; event-driven only — gauntlet never sweeps historical specs). **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
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. Inside a brainstorming-entered flow 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "4.5.1",
3
+ "version": "4.6.1",
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",
@@ -22,6 +22,7 @@ You **may**:
22
22
  - Read code and docs
23
23
  - Run the existing system to observe its **current** behaviour — this is research and feeds the spec (boot a local service, replay a sample request, capture a baseline classification, etc.)
24
24
  - Write to the project's `doc/specs/` directory
25
+ - `edit` a predecessor spec in the project's spec directory to add a supersession banner (see [Marking superseded specs](#marking-superseded-specs)) — the `edit` prohibition at spec-writing binds the spec being written, not a predecessor file
25
26
 
26
27
  You may **not**:
27
28
 
@@ -57,10 +58,10 @@ Work through the items below **in order**. This is your own checklist to follow,
57
58
  claims against real code, ask questions one at a time, append citable findings
58
59
  5. **Propose 2-3 approaches** — with trade-offs and a recommendation
59
60
  6. **Present the design** — in sections, get approval after each
60
- 7. **Write the spec** — to `doc/specs/` (see [Filename Convention](#filename-convention))
61
+ 7. **Write the spec** — to `doc/specs/` (see [Filename Convention](#filename-convention)); then mark any known superseded predecessor(s) per [Marking superseded specs](#marking-superseded-specs), at the exact-order position defined in [Spec Self-Review](#spec-self-review-before-user-review-gate)
61
62
  8. **Spec self-review (lint)** — placeholder scan + internal consistency + documentation named, run inline
62
63
  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
+ 10. **Re-run placeholder scan** — after the critique pass returns, re-scan the **applied** spec for placeholders its edits may have introduced; if a predecessor banner exists, confirm its `<scope>` still matches the applied spec (critique edits can change what is superseded); surface any ambiguity the critique could not safely resolve at the user gate
64
65
  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
66
  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
67
  13. **Transition** — only after approval, invoke `/skill:writing-plans`
@@ -130,7 +131,9 @@ path.
130
131
  section starts that answer; confirm it before designing from scratch.
131
132
  - Ask questions **one at a time** to refine the idea. Prefer multiple-choice; one
132
133
  question per message. Focus on: purpose, constraints, success criteria, who/what
133
- it touches.
134
+ it touches. Ask once whether the design replaces a prior spec, fully or in part,
135
+ so the supersession event is captured before spec-writing (see
136
+ [Marking superseded specs](#marking-superseded-specs)).
134
137
  - **Append bar:** append to the draft's `## Appended during questionary` only
135
138
  findings the spec will cite — schema shapes, hard constraints, ticket-vs-code
136
139
  contradictions, user answers that changed scope. Not a log of every grep.
@@ -220,6 +223,25 @@ overwrite reuses the path. If the questionary invalidated the slug, rename at
220
223
  spec-writing: write the spec at the new path **and delete the old draft file**
221
224
  (nothing was committed, so this is free).
222
225
 
226
+ ## Marking superseded specs
227
+
228
+ When the new spec replaces a prior spec — fully or in part — and you **already know which one** (from the questionary, the draft, or the request), mark the predecessor. Never search, sweep, or audit the spec corpus for candidates: marking is event-driven authorial knowledge only.
229
+
230
+ - `edit` the predecessor spec (in the project's spec directory, per [Project Routing](#project-routing)) to insert, after its title line and a blank line, one banner line per successor:
231
+
232
+ ```markdown
233
+ > **Superseded by:** [<repo-relative path to successor>](<href relative to THIS file>) - <scope>
234
+ ```
235
+
236
+ - The visible label is the successor's repo-relative path; the href is computed relative to the predecessor's own directory (Markdown resolves links from the containing file). Same directory: `[doc/specs/B.md](./B.md)`.
237
+ - `<scope>` is the value after the ` - ` separator: `fully`, or the named superseded section(s), e.g. `"Settings resolution" section only`. The scope value itself carries no leading dash — the template above already supplies the separator.
238
+ - Banners are **append-only**: add below any existing supersession lines, formatted or free-form prose. One old spec may accumulate banners from multiple successors. No migration, no dedup.
239
+ - **No transitive rewrite**: if A points at B and B is later superseded by C, A keeps pointing at B; the reader hops.
240
+ - **Mark, never delete.** Delete/archive policy is consumer territory via overrides.
241
+ - **Coverage limits**: unmarked does NOT mean current (code drift, abandoned designs, and partial ships produce no successor spec); marked does NOT mean dead (partial supersession leaves live sections).
242
+ - Predecessor in a **different service's spec directory**: out of scope — record it in the new spec's Open Questions instead of editing outside the write grant.
243
+ - **Override contract**: `.pi/gauntlet-overrides.md` may replace the banner *syntax*; placement, append-only, no-transitive-rewrite, and mark-never-delete stay fixed. A syntax override entry must itself state the scout-citation guidance for its format (the shipped `gatherer.md` guidance names only the default banner).
244
+
223
245
  ## Spec Self-Review (Before User Review Gate)
224
246
 
225
247
  Spec-writing replaces the context draft, in this exact order:
@@ -233,11 +255,15 @@ Spec-writing replaces the context draft, in this exact order:
233
255
  `# CONTEXT DRAFT - NOT A SPEC - fully replaced at spec-writing` — before
234
256
  dispatching lint, critique, council, or summarizer. The phase-tracker commit
235
257
  guard is a backstop, not the primary check.
258
+ 4. **After the line-1 check and before the inline lint**, `edit` any known
259
+ predecessor spec to insert its supersession banner (see
260
+ [Marking superseded specs](#marking-superseded-specs)). This position is fixed:
261
+ the banner is written after any slug rename, so it always cites the final path.
236
262
 
237
263
  After writing the spec to `<project>/doc/specs/<filename>.md` (per [Filename Convention](#filename-convention)) and before showing it to the user, run a self-review pass. **Read all five bullets first, then act:** only the **first three** run here at the main loop (the inline lint); the **last two** (scope + ambiguity) do **not** run inline — they are the dispatched critique pass (checklist item 9). Do not apply scope/ambiguity edits yourself.
238
264
 
239
265
  - **Placeholder scan.** Any `TODO`, `TBD`, `<fill in>`, `[example]`, `xxx`? Either resolve them or convert to explicit "Open Questions" with names.
240
- - **Internal consistency.** Does Section 4 contradict Section 2? Are component names and field names consistent throughout?
266
+ - **Internal consistency.** Does Section 4 contradict Section 2? Are component names and field names consistent throughout? If the spec replaces a prior design, confirm the predecessor carries the supersession banner and its href resolves to this spec's final filename.
241
267
  - **Documentation named.** Does the spec name all three classes (feature/user-facing introduced; materially amended; derived/memory invalidated), or an explicit "none" for each? Enforce the materiality bar in `reference/documentation-impact.md` without restating it: each listed doc names the category it clears, none is a code-mirror, amend-over-create was applied, and skill/agent bodies are implementation surface, not doc-impact entries here.
242
268
  - **Scope check.** Does every paragraph serve the goal? Cut filler. If something is out of scope, say it's out of scope.
243
269
  - **Ambiguity check.** Is every "we should…" backed by a concrete decision? Replace "we could probably" with "we will" or "we won't".
@@ -262,7 +288,7 @@ The first three checks — **placeholder scan**, **internal consistency**, and *
262
288
 
263
289
  `worker`'s model resolves from `subagents.agentOverrides.worker.model` in `settings.json` (unset → inherits the main loop); the dispatch passes no `model:`.
264
290
 
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.
291
+ 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, and — if a predecessor banner was written — confirm its `<scope>` still matches the applied spec, reconciling the banner if critique edits changed what is superseded. 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.
266
292
 
267
293
  ## Spec Council (Optional)
268
294
 
@@ -286,7 +312,7 @@ subagent({ agent: "spec-summarizer", context: "fresh", cwd: "<abs worktree path,
286
312
 
287
313
  `<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.
288
314
 
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):
315
+ Then commit the spec — staging any predecessor spec edited per [Marking superseded specs](#marking-superseded-specs) alongside it; a change request at the gate that renames, materially revises, or drops the spec also reconciles the predecessor's banner before recommitting. 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):
290
316
 
291
317
  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.
292
318
  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.
@@ -351,6 +377,7 @@ phase_tracker({ action: "complete", phase: "brainstorm" })
351
377
  - About to run the scope or ambiguity checks inline yourself instead of dispatching them (those two are the critique pass, not the inline lint)
352
378
  - About to skip the self-review pass
353
379
  - About to proceed to `/skill:writing-plans` before the user has approved the spec (proceeding *after* approval is correct; skipping the gate is the violation)
380
+ - About to finish spec-writing for a replacement design without marking the known predecessor (see [Marking superseded specs](#marking-superseded-specs))
354
381
  - Spec contains `TODO`, `TBD`, or unnamed components
355
382
  - Spec spans multiple independent subsystems with no decomposition flag
356
383
  - User said "this is just a small change" and you accepted it without applying the [Anti-Pattern](#anti-pattern-too-simple-to-need-a-design) check
@@ -41,7 +41,11 @@ Scout (always dispatched):
41
41
  > Map the territory this change touches: relevant files with line ranges, existing
42
42
  > patterns and conventions the change must match, test conventions, integration
43
43
  > points, and whether the codebase or ecosystem already solves any of this. Cite
44
- > exact paths and line ranges. End with an "Open questions that matter for the spec"
44
+ > exact paths and line ranges. If a spec you cite carries a supersession marker
45
+ > (default: a `> **Superseded by:**` banner; the project's overrides may define
46
+ > another format), follow the successor for the superseded scope and cite it
47
+ > instead; cite the old spec only for its unsuperseded sections. End with an
48
+ > "Open questions that matter for the spec"
45
49
  > section. Compact handoff, not a dump.
46
50
 
47
51
  Context-builder (conditional):
@@ -88,17 +88,7 @@ Closure / conformance: CONFORMS
88
88
 
89
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
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").
91
+ **Carried-open (`status: GAPS (N open)`).** Read `reference/disposition-protocol.md` and follow it for the carried-open render (dense) grammar, the response grammar, and the 9-step execute order. Render the human decision menu in the shape below, drive the dispositions per that reference, then print the summary render and continue to Step 4. If that reference file cannot be read, stop and surface a blocking error — do **not** improvise the grammar from memory.
102
92
 
103
93
  Representative carried-open render (multi-concern gap split to `e2e`; single-concern gap `cache`; `UNAUTHORIZED` gap `auth`):
104
94
 
@@ -119,36 +109,7 @@ Other options per item: fix-now / accept / rescope / follow-up / custom.
119
109
 
120
110
  A single-concern render is identical minus the split: one bullet whose handle is the gap ID or word, no sibling.
121
111
 
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:
112
+ Execute the chosen dispositions per `reference/disposition-protocol.md` (Execute order), then print the closure summary and continue to Step 4:
152
113
 
153
114
  ```
154
115
  Closure / conformance: CONFORMS
@@ -0,0 +1,46 @@
1
+ # Carried-open disposition protocol
2
+
3
+ Consumed by `finishing-a-development-branch` Step 3.5 on the **GAPS branch only** — the CONFORMS fast path never reads this file. Antecedent map for the relocated grammar below: "the reference" = `../../verification-before-completion/reference/conformance-check.md` (canonical for the availability table, the `UNAUTHORIZED` question, the `recommended: none` preflight, the freshness rule, and the concern-scoped fix projection); "Revert semantics", "the zero-gap path", and every `Step N` (`Step 1`, `Step 3.5`, `Step 4`) reference = `../SKILL.md`.
4
+
5
+ **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.
6
+
7
+ Each bullet:
8
+
9
+ `* <handle> - <plain title>: <what's unresolved, one clause>. <short question> Recommended: <choice> (<one-clause why>).`
10
+
11
+ - `<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`.
12
+ - 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.
13
+ - Group items under one recommended line only when they share a disposition and rationale; each grouped handle repeats its title.
14
+ - 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.
15
+ - `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").
16
+
17
+ #### Response grammar
18
+
19
+ ```
20
+ 1 -> apply every recommendation
21
+ 2: cache=follow-up
22
+ 2: e2e=custom(open ticket after image lands), cache=follow-up
23
+ ```
24
+
25
+ - `1` (or `apply recommended`) applies all recommendations.
26
+ - `2:` takes a comma-separated override list, each `<handle>=<choice>`; omitted items keep their recommendation. A handle may appear at most once (repeat = invalid).
27
+ - `custom(<concrete effect>)` supplies an inline effect. Manual fix-in-place is expressed only as `custom(...)` where isolated `fix-now` is unavailable.
28
+ - `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.
29
+ - `revert conformance fix Gn` is a valid standalone reply, mutually exclusive with `1` and `2:`; it never appears inside a `2:` override list.
30
+ - 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.
31
+
32
+ #### Execute order
33
+
34
+ Take **no** disposition action before the reply. Then, once, in order:
35
+
36
+ 1. **Normalize** every `custom(...)` into explicit operations; classify state-changing (edits code or spec) vs not. Clarify only an ambiguous or unexecutable effect.
37
+ 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).
38
+ 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.
39
+ 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.
40
+ 5. **Re-audit after all state-changing work;** obtain fresh decisions **only if** the refreshed inventory differs from the approved one, else proceed.
41
+ 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.
42
+ 7. **Non-state-changing custom:** execute and record the result.
43
+ 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.
44
+ 9. Re-enter Step 3.5 with the re-audited block if any concern remains open.
45
+
46
+ 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:
@@ -103,8 +103,11 @@ No prompt, no menu: this partition is deterministic and exhaustive.
103
103
  3. **Every remaining `PARTIAL`/`MISSING`/`DRIFTED` gap**:
104
104
  - `recommended: fix` → auto-run the fix loop below — **unless a declared
105
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).
106
+ named-branch worktree), in which case carry the gap **OPEN** and defer it
107
+ to the finish gate. This is the authoritative statement of the
108
+ precondition-unavailable carry-OPEN rule; the fix-loop precondition, the
109
+ `maxFixRounds: 0` note, the availability table, and the closure section
110
+ below all reference it.
108
111
  - `recommended: accept` or `recommended: rescope` → carry the gap **OPEN**,
109
112
  deferred to the finish gate. Do not apply a spec edit here — the finish
110
113
  gate owns disposition of deferred gaps.
@@ -131,7 +134,8 @@ Only the fan-out/integrate/review shape and `plan_tracker` are reused.
131
134
  **Precondition — worktree required.** The loop needs a worktree HEAD to branch
132
135
  fixes from. On the ad-hoc `finishing-a-development-branch` paths that run in a
133
136
  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
137
+ skip this loop and carry every `fix` gap OPEN per the precondition-unavailable
138
+ carry-OPEN rule in the partition step above, resolving it at finish via the
135
139
  canonical Disposition catalog and availability table below. `fix-now` is
136
140
  unavailable there; any other disposition is offered only when its table
137
141
  prerequisites hold.
@@ -184,11 +188,13 @@ Commit each per-gap fix with the message **`conformance fix Gn`** (durable,
184
188
  `git log`-readable pre-squash) so the finish gate and any revert can identify
185
189
  auto-applied fixes.
186
190
 
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.
191
+ **`maxFixRounds: 0`**: skip this loop entirely; every `recommended: fix` gap is
192
+ carried OPEN to the finish gate per the precondition-unavailable
193
+ carry-OPEN rule in the partition step above. The load-bearing distinction here
194
+ is opted-out vs. exhausted: `maxFixRounds: 0` means the user opted out of
195
+ auto-fix, so treat `fix` gaps like any other deferred gap — unlike a cap > 0
196
+ that is *exhausted*, which escalates mid-verify because the loop tried and
197
+ could not converge.
192
198
 
193
199
  ### `spec-reviewer` gap-block reference contract
194
200
 
@@ -284,7 +290,9 @@ prerequisite. `touched-files: unknown` makes `fix-now` unavailable until
284
290
  ownership is established. A normal checkout (`GIT_DIR == GIT_COMMON`) or detached
285
291
  HEAD cannot dispatch the isolated fix loop at all - it has no named-branch
286
292
  worktree to branch fixes from - so `fix-now` stays unavailable there regardless
287
- of ownership; resolve those concerns manually at finish. `maxFixRounds: 0`
293
+ of ownership; those `fix` gaps are carried OPEN per the precondition-unavailable
294
+ carry-OPEN rule in the partition step above and resolved manually at finish.
295
+ `maxFixRounds: 0`
288
296
  (audit-only) likewise leaves `fix-now` visible but unavailable — the user
289
297
  configured no auto-fix loop, and finish-time selection never bypasses or resets
290
298
  that cap; a concrete `custom`/manual-fix disposition remains possible. `UNAUTHORIZED` cards
@@ -340,9 +348,8 @@ Emit this block in the verify completion summary. It is the durable handoff
340
348
  `finishing-a-development-branch` Step 3.5 consumes — parseable even if session
341
349
  context was pruned. Verify completes when every gap is either fixed
342
350
  (`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
351
+ or a `recommended: fix` gap carried OPEN per the precondition-unavailable
352
+ carry-OPEN rule in the partition step above (the loop never started). Escalation - a started
346
353
  positive-cap loop that exhausted its rounds or blocked/failed with an open `fix`
347
354
  gap - is the one non-completing terminal state; the precondition-unavailable
348
355
  carried-open `fix` state is valid closure inventory, not escalation.