pi-gauntlet 5.13.0 → 5.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.15.0 - 2026-09-20
4
+
5
+ - New human-only `/skill:gauntlet-handoff`: invokes pi-cohort's `handoff` skill (`--out <path>` or `--key <name>`; default key = the run worktree's branch, `/` flattened to `-`, file `<tmpdir>/pi-handoff/<key>.md`) and appends the gauntlet `## Process state` section in the layout fixed by `skills/gauntlet-resume/reference/brief-contract.md` (`## Producers`); stops instead of writing when the skill is absent or the installed cohort still writes that section itself. `/skill:gauntlet-resume` with no arguments lists the briefs under `<tmpdir>/pi-handoff/` for a human pick, and a token that looks like a path is always a brief file (missing -> stop, never a scan). `scripts/ci.mjs` gains a drift lint (`scripts/brief-contract-lint.mjs`): the three process-state grammar lines may appear only in the contract file, both skills must cite it, and gauntlet-handoff may not carry cohort's core headings. Requires pi-cohort >= the release shipping [pi-cohort #18](https://github.com/jjuraszek/pi-cohort/issues/18) (exact version filled at release). (#40)
6
+
7
+ ## v5.14.0 - 2026-09-20
8
+
9
+ - Specs carry the ticket's acceptance criteria verbatim in a required `## Acceptance criteria` section, one disposition per row (`in-scope`, `deviates: <why>`, `deferred: <where>`, `venue: <env> - <observation>`; `none - <reason>` when there is no ticket or no ACs). `brainstorming` extracts heading-scoped rows and lints the section's presence, `gatherer` quotes the raw rows, `spec-council-member` flags dropped/reworded rows and invalid deferrals, `conformance-reviewer` and `conformance-check` read the section as origin (`in-scope`/`venue:` rows are requirements, `venue:` observations never block), `writing-plans` tables only `in-scope`/`venue:` rows, and `finishing-a-development-branch` lists `venue:`/`deferred:` rows in the PR body. `scripts/ci.mjs` pins the new tokens. (#41)
10
+
3
11
  ## v5.13.0 - 2026-09-19
4
12
 
5
13
  - Post-approval spec amendments go through a reviewer-first funnel (`skills/brainstorming/reference/amendment-surface.md`): a fresh `spec-council-member` in `Mode: amendment-review` clears evidence-backed factual corrections that touch no human-owned section, a deterministic prefilter sends descopes and acceptance-criteria edits to the human, and escalations render as one readable batch (what / why / example / recommended, real alternatives only) with a one-reply grammar and the standing-grant offer; each batch lands as one `amend:` commit with per-item records. The spec gate offers the grant. `finishing-a-development-branch` runs eligible conformance `accept` gaps through the same funnel before the disposition menu and lists auto-applied amendments above the ship options. `brainstorming/SKILL.md` shrinks; `scripts/ci.mjs` pins the new tokens.
package/README.md CHANGED
@@ -36,7 +36,7 @@ pi-gauntlet's only hard dependency is pi-cohort - every gate that dispatches a r
36
36
  Concretely, one change through the gauntlet:
37
37
 
38
38
  0. *(Optional)* Before there's even a spec, `/skill:shape-ticket` can create or repair a single tracker issue - shaping a raw ask into a Context/Problem/Idea/Acceptance Criteria ticket, gated by an AC integrity check, a cheap council roast, and one human-confirmed write that may include one optional gated Reporter-note comment. A failed roast is retried once, then surfaced inline at the gate if it fails again. It's a tool, not a phase: no worktree, no plan/phase tracker, runs from any repo state. It never activates on its own (`disable-model-invocation: true`) - invoke it explicitly. Similarly, `/skill:chase-bug` triages a raw bug report into an evidenced verdict - and can hand off to shape-ticket, brainstorming, or a bounded hotfix - before any spec exists.
39
- 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`; candidates come from brainstorming's scout recon, never a mechanical sweep). **You read and approve the spec - human gate 1.** No implementation code exists yet.
39
+ 1. You describe the change. **`brainstorming`** sets up an isolated worktree, explores the codebase, and turns your description into a written spec; when the run starts from a ticket, the spec carries the ticket's acceptance criteria verbatim, each with a disposition (`in-scope`, `deviates:`, `deferred:`, `venue:`), the conformance gate checks the in-scope ones, and `/skill:check-delivery` verifies `venue:` rows after deploy. 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`; candidates come from brainstorming's scout recon, never a mechanical sweep). **You read and approve the spec - human gate 1.** No implementation code exists yet.
40
40
  2. **`writing-plans`** decomposes the approved spec into atomic, independently-verifiable tasks, grouped into parallel waves where they don't touch the same files.
41
41
  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. Independent implementation, review, and council batches remain parallel, but their dispatches are foreground: the orchestrator waits for terminal results before accepting work or advancing a phase.
42
42
  4. **verify**: the parent first runs the plan's full verification command set; only a passing result permits whole-diff code review, then the **conformance gate**. A review fix invalidates that result, so the parent reruns full verification before the next review or conformance gate. The conformance 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. Unauthorized rows - shipped surface no human input asked for, whether it crept in or was laundered through the spec - follow their recommendation like every other row: a contained removal auto-runs, anything another requirement leans on is deferred with a plain-language "I'd cut it / I'd keep it" recommendation. 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.
@@ -69,7 +69,7 @@ Everything between gate 1 and gate 2 - task breakdown, implementation, both revi
69
69
 
70
70
  pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
71
71
 
72
- - **19 skills** - the workflow logic. Thirteen activate automatically when pi sees the matching kind of task, and each one gates the next: `brainstorming`, `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `writing-skills`, `linear` (reads/searches/comments on/manages Linear tickets via the `linearis` CLI; owns all linearis mechanics and the `## Issue tracker` overrides schema; tracker-facing skills route to it). Six more are explicit-invocation-only (`disable-model-invocation: true`): `shape-ticket` creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write - run it with `/skill:shape-ticket`. `gatekeep-pr` is consent-gated pre-merge verification of a PR against its issue - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; the project's verification command runs only as fallback), a rubric-based review, then a deterministic authorship-aware menu with stable finding IDs (P#/L#/C#/F#) and numbered pre-composed courses (fixes execute as a single parallel-safe wave: one gate run, one re-review, one push); nothing mutates (fixes, pushes, reviews, merges) until you pick a row - run it with `/skill:gatekeep-pr <pr>`. `check-delivery` is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/hotfix/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage; the hotfix row hands off to `skills/chase-bug/hotfix.md` after the menu - run it with `/skill:chase-bug`. `gauntlet-performance` reads the committed run telemetry (current repo by default, `--dir <path>` adds others) through the parse-only `gauntlet-performance` CLI and answers with one example-led recommendation, 3-5 cornerstone numbers, and a menu of at most three actions (render a report file, open the recommendation as a ticket via `shape-ticket`, drill into one run); it writes nothing unless you pick render - run it with `/skill:gauntlet-performance [--dir <path>]... [--since <version>]`. `gauntlet-resume` is the only way back into an interrupted flow from a fresh session: it takes a pi-cohort `/handoff` brief (file or pasted) or a bare worktree that already holds a spec, restores phase/plan tracker state through the legal arming sequence (`start brainstorm`, `skip` with `resume:` reasons, `plan_check` before implement-or-later), never creates a worktree, and never infers approval from artifacts - run it with `/skill:gauntlet-resume [<brief>] [<worktree>]`.
72
+ - **20 skills** - the workflow logic. Thirteen activate automatically when pi sees the matching kind of task, and each one gates the next: `brainstorming`, `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `writing-skills`, `linear` (reads/searches/comments on/manages Linear tickets via the `linearis` CLI; owns all linearis mechanics and the `## Issue tracker` overrides schema; tracker-facing skills route to it). Seven more are explicit-invocation-only (`disable-model-invocation: true`): `shape-ticket` creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write - run it with `/skill:shape-ticket`. `gatekeep-pr` is consent-gated pre-merge verification of a PR against its issue - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; the project's verification command runs only as fallback), a rubric-based review, then a deterministic authorship-aware menu with stable finding IDs (P#/L#/C#/F#) and numbered pre-composed courses (fixes execute as a single parallel-safe wave: one gate run, one re-review, one push); nothing mutates (fixes, pushes, reviews, merges) until you pick a row - run it with `/skill:gatekeep-pr <pr>`. `check-delivery` is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/hotfix/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage; the hotfix row hands off to `skills/chase-bug/hotfix.md` after the menu - run it with `/skill:chase-bug`. `gauntlet-performance` reads the committed run telemetry (current repo by default, `--dir <path>` adds others) through the parse-only `gauntlet-performance` CLI and answers with one example-led recommendation, 3-5 cornerstone numbers, and a menu of at most three actions (render a report file, open the recommendation as a ticket via `shape-ticket`, drill into one run); it writes nothing unless you pick render - run it with `/skill:gauntlet-performance [--dir <path>]... [--since <version>]`. `gauntlet-handoff` ends a session whose flow a fresh session will continue: it invokes pi-cohort's `handoff` skill (`--out <path>` or `--key <name>`, default key = the run worktree's branch with `/` flattened to `-`, default file `<tmpdir>/pi-handoff/<key>.md`), then appends the gauntlet process-state section (phase/plan tracker status) per the shared contract `skills/gauntlet-resume/reference/brief-contract.md` - run it with `/skill:gauntlet-handoff [--out <path> | --key <name>]`. `gauntlet-resume` is the only way back into an interrupted flow from a fresh session: it takes a `gauntlet-handoff` brief (a file path, pasted text, or - with no arguments - a pick from the briefs under `<tmpdir>/pi-handoff/`) or a bare worktree that already holds a spec, restores phase/plan tracker state through the legal arming sequence (`start brainstorm`, `skip` with `resume:` reasons, `plan_check` before implement-or-later), never creates a worktree, and never infers approval from artifacts - run it with `/skill:gauntlet-resume [<brief>] [<worktree>]`.
73
73
  - **7 subagent personas** - the specialized child agents the skills dispatch via pi-cohort: `implementer`, `code-reviewer`, `spec-reviewer`, `conformance-reviewer`, `spec-summarizer`, `spec-council-member`, `spec-council-synthesizer`. See [doc/personas.md](./doc/personas.md) for what each one does and why its permissions are scoped the way they are.
74
74
  - **4 runtime extensions** - the enforcement layer. `plan-tracker` and `phase-tracker` are tools skills call to track progress (with a TUI widget); `verify-before-ship` is a hook that warns if you push or open a PR without a passing test run since your last edit; a phase-tracker flow guard reminds on implement-phase commits missing spec/code review. In a brainstorming-entered flow, phase-tracker rejects `implement` or `verify` completion while tracker tasks remain pending or in progress; see [its configuration reference](./doc/configuration.md#phase-tracker). phase-tracker also registers `plan_check`, which verifies a plan against its spec and against the grammar in [skills/writing-plans/reference/plan-contract.md](./skills/writing-plans/reference/plan-contract.md), including that each task's `Tests:` commands are selective and never the full suite; a pass stamps the plan for implementation. `telemetry` records one committed YAML record per gauntlet run (phase timing, models, personas, gate/fix rounds, diff at ship) that ships in the squash beside the spec - finishing and the PR gate restore a stripped record, and stamp a record left `in_progress` with no ship phase as `shipped`, with `gauntlet-telemetry-salvage` - and blocks a brainstorm `write` into an already-shipped spec; see [its configuration reference](./doc/configuration.md#telemetry). See [doc/configuration.md](./doc/configuration.md) for the settings each one reads.
75
75
 
@@ -77,6 +77,20 @@ pi-gauntlet is **opinionated**: every non-trivial change is *meant* to ride this
77
77
 
78
78
  **Worktree contract.** pi runs in the primary checkout; the work happens in `.worktrees/<branch>`. Skills never `cd` there - the worktree path is a value from the `using-git-worktrees` report (or the handoff brief on `gauntlet-resume`), carried as dispatch `cwd: "<path>"`, as `git -C <path>`, or as `(cd "<path>" && <cmd>)` for other cwd-bound commands; the runtime extensions derive the checkout from the artifact path they act on. Requires git >= 2.31; a plain (non-colocated) jj workspace has no `.git`, so the resolver falls back to `jj root` there, reading primary-vs-workspace from `.jj/repo` (a directory in the primary checkout, a pointer file in added workspaces).
79
79
 
80
+ ## Handoff and resume
81
+
82
+ `/skill:gauntlet-handoff` and `/skill:gauntlet-resume` are a pair: cohort's `handoff` skill writes the six flow-agnostic headings, gauntlet-handoff appends `## Process state`, and gauntlet-resume reads the whole brief back. Both gauntlet skills read one grammar file, `skills/gauntlet-resume/reference/brief-contract.md`; the repo validator (`scripts/ci.mjs`) fails if a grammar line appears anywhere else under `skills/`. Requires the pi-cohort release that ships [pi-cohort #18](https://github.com/jjuraszek/pi-cohort/issues/18) (the `handoff` skill); on an older pi-cohort, gauntlet-handoff stops before writing.
83
+
84
+ ### Smoke walkthrough (release-gated)
85
+
86
+ Run by a human against the pi-cohort release that ships #18, before a pi-gauntlet release claims the pair works; record the outcome in the release commit body.
87
+
88
+ 1. Implement phase with tasks `complete`/`in_progress`/`pending` in a `.worktrees/<branch>` flow, session in the primary checkout: `/skill:gauntlet-handoff` writes `<tmpdir>/pi-handoff/<branch>.md` with the six core headings then `## Process state` last; a fresh session running `/skill:gauntlet-resume <path>` restores implement with the three statuses and ends `Gate history not restored; re-validating <task> before any stage advance`.
89
+ 2. Plan phase, `No plan active.`: the brief keeps that line and `Active task: none`; resume restores phase-only with no `plan_tracker init`.
90
+ 3. Hotfix context with non-pending trackers: the brief ends at `## Skills loaded`; resume takes the `chase-bug` route.
91
+ 4. Fresh session, zero arguments: the listing shows the briefs from 1-3 and a pick restores; `/skill:gauntlet-resume /nonexistent.md` stops naming that path without listing anything.
92
+ 5. Branch `hotfix/x`: the default file is `pi-handoff/hotfix-x.md` and appears in the zero-argument listing.
93
+
80
94
  ## Key concepts
81
95
 
82
96
  | Term | Meaning |
@@ -39,6 +39,8 @@ Work flows `origin (prompt + spec) → plan → code/doc`. Every hop is lossy: a
39
39
  3. The feature ships correctly without it. If another requirement needs it, keep it.
40
40
 
41
41
  Report such a clause once, as `UNAUTHORIZED` (not `DELIVERED`, not origin drift). Unsure on 2 -> keep it as an `Rn`. This is the only exception to "spec is canonical"; "could be cleaner" is still not a reason.
42
+
43
+ **Spec `## Acceptance criteria`.** When the spec has a heading starting `## Acceptance criteria` (a legacy `## Acceptance criteria (from #N)` heading matches), read that section as an origin beside the spec body. Each `in-scope` row yields one `Rn` with `origin: spec "Acceptance criteria" - "<AC verbatim>"`; a row with no disposition line is `in-scope`. Each `venue:` row yields one `Rn` that is `DELIVERED` when the Design clauses naming its enabling change are `DELIVERED`, with the venue and observation text on the verdict line; the observation itself is never a finding; a `venue:` row no Design clause names is `MISSING`, `recommended: rescope`. `deviates:` and `deferred:` rows yield no `Rn`; list them under `Origin drift` as `recorded in spec? yes`. A disposition word outside the four is `DRIFTED`, `recommended: fix` (correct the word). A section whose body is a single `none - <reason>` line has no rows: it yields no `Rn` and no drift. A spec without the section is read as before - spec body and prompt only; every existing rule and the source order above are unchanged. When a spec exists you do not fetch the ticket.
42
44
  2. **Check origin drift.** If the spec and the prompt/ticket disagree, do **not** absorb it silently. A deviation recorded in the spec → spec wins (it was review-gated). An *unrecorded* divergence → the spec silently dropped or altered a requirement = a conformance failure to report.
43
45
  3. **Map each requirement to the deliverable.** Read the diff (code **and** docs) yourself — do not trust any summary. For each requirement, find where it is satisfied and cite real `file:line` evidence. Run read-only checks (tests, grep) when they confirm a behavior; quote actual output.
44
46
  4. **Flag the unrequested.** Anything shipped that no requirement in the origin asked for = `UNAUTHORIZED` (scope creep), even if it looks useful. Do not negotiate scope with yourself. This includes the step-1 exception clauses. `origin` is always `none (scope creep)`. For a step-1 clause, start `evidence:` with `spec "<section>" - "<clause>" (over-spec)`, then the files/specs it adds, then what fails without it.
@@ -143,6 +145,7 @@ serial waves — identical to planned-execution wave grouping. Runtime-resource
143
145
  - **Evidence or it didn't happen.** Cite a real `file:line` for every DELIVERED/PARTIAL. If you cannot, downgrade the row to MISSING.
144
146
  - **Origin quote or it isn't a gap.** Every non-UNAUTHORIZED gap's `origin` carries a locator AND a verbatim quote: `origin: <file/section, 'prompt', or 'ticket'> - "<quoted clause>"` (truncate long clauses with `[...]` as long as the fragment uniquely identifies the clause). No quotable origin clause = no gap. Do not derive implicit requirements. Do not flag wording preferences. A deviation recorded in the spec wins over an older origin value (Process step 2); report it only if unrecorded.
145
147
  - **Spec is canonical; the prompt catches what the spec dropped; the ticket is fallback only** when no spec exists.
148
+ - **The spec's `## Acceptance criteria` section is origin, not ticket.** Its `in-scope`/`venue:` rows are `Rn`; its `deviates:`/`deferred:` rows are recorded drift (`recorded in spec? yes`).
146
149
  - **Do not absorb origin drift silently** — flag every spec↔prompt/ticket disagreement.
147
150
  - **Quote real command output** if you ran checks. Do not paraphrase from memory.
148
151
  - **Coverage is binary per requirement** — "mostly done" is PARTIAL, not DELIVERED.
@@ -31,7 +31,7 @@ When the first line of your task is `Mode: amendment-review`, this section repla
31
31
  Assess the spec on five axes:
32
32
 
33
33
  1. **Addresses the problem.** Does the spec actually solve the problem in the problem statement? Answer yes / partial / no and say why. A well-written spec for the wrong problem is unsound.
34
- 2. **Logical gaps.** Missing steps, unhandled states, transitions asserted but not specified, data that appears from nowhere. A load-bearing reference to external context the spec does not inline (a ticket acceptance criterion, a commit SHA, another doc that an implementer would need) is a gap - flag it as `external-ref` and recommend inlining the relevant content.
34
+ 2. **Logical gaps.** Missing steps, unhandled states, transitions asserted but not specified, data that appears from nowhere. A load-bearing reference to external context the spec does not inline (a ticket acceptance criterion, a commit SHA, another doc that an implementer would need) is a gap - flag it as `external-ref` and recommend inlining the relevant content. Compare the `Human input` ticket AC rows against the spec's `## Acceptance criteria`: a row absent or reworded is `external-ref`; a `deferred:` row whose reason fails the operates-without-it test (the change needs it to operate) is `scope`. Judge a `deviates:` row as any other design decision.
35
35
  3. **Oversimplifications.** Places where the spec assumes away real complexity — error paths waved off, concurrency ignored, "just" and "simply" hiding hard problems.
36
36
  4. **Ambiguities.** Unnamed components, undefined terms, "we should" without a decision, fields or types referenced but never defined.
37
37
  5. **Actionable and testable.** Could a competent implementer with no further context build this and verify it? If not, what is missing?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "5.13.0",
3
+ "version": "5.15.0",
4
4
  "description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
5
5
  "author": "Jacek Juraszek",
6
6
  "type": "module",
@@ -119,7 +119,22 @@ Use doc names, `none`, or `deferred: <trigger>`. Apply `reference/documentation-
119
119
 
120
120
  ## Ticket Handling
121
121
 
122
- A ticket is guidance, not sole truth. Fetch it; propose scope, approach, or acceptance changes when code disagrees, and record deviations in the spec.
122
+ A ticket is guidance, not sole truth. Fetch it; propose scope, approach, or acceptance changes when code disagrees, and record deviations in the spec. Implied requirements in the ticket body (Context, Problem, Idea) land in the spec body as any other requirement; the ticket's explicit acceptance criteria land verbatim in the section below.
123
+
124
+ **Extract the ticket's ACs.** When the ticket body has a heading matching `/acceptance criteria/i`, every list item under it until the next heading is an AC (numbered, bullet, or checkbox) and no other list in the body is. When there is no such heading, every top-level checkbox row in the body is an AC, except rows under a `Post-deployment housekeeping`, `Out of scope`, or `Follow-up` heading. Otherwise the ticket has no ACs. A nested list under an AC row rides with its parent as one row; an AC heading holding prose and no list makes each paragraph one row. Carry checked and unchecked rows alike, all written `- [ ]`. Take the rows from the gather draft's `## Ticket acceptance criteria (verbatim)` heading; when the ticket was not fetched, the gate summary shows the `none` line so the user can paste the rows, which then become rows.
125
+
126
+ **Write the section in every spec**, after `## Problem`:
127
+
128
+ ```markdown
129
+ ## Acceptance criteria
130
+
131
+ Ticket <ref>, <heading or "checkbox list">, rows verbatim:
132
+
133
+ - [ ] <row text copied verbatim>
134
+ <disposition>
135
+ ```
136
+
137
+ The heading `## Acceptance criteria` names the ticket contract only; the spec's own requirements stay in Design. Disposition is exactly one of `in-scope`, `deviates: <why>`, `deferred: <where>`, `venue: <env> - <observation>`; default `in-scope`. Never edit the row text: a wrongly stated row is `deviates: <why>`, an ambiguous row stays `in-scope` with the chosen reading written as a Design clause. Name a `venue:` row's enabling change in Design. An `in-scope` row is a requirement as written; disposition reasons are never normative for the plan or the reviewer, so a `deviates:` reason that adopts part of a row restates that part as a Design clause. Defer a row only when the shipped change operates without it - cost is never a reason; a hard but direct AC stays `in-scope` and ships. Ask every `deviates:`/`deferred:` decision in the questionary and name it in the gate summary; `venue:` states where the observation can happen and is not a scope decision. A disposition changes in any later phase - a reviewer finding `recommended: rescope` at the finish gate, a wrong row noticed mid-implementation, or a ticket edited after approval when the user asks - through [Amending an approved spec](#amending-an-approved-spec) (`reference/amendment-surface.md`); the row text still never changes. With no ticket, or a ticket without ACs, the section body is the single line `none - no ticket`, `none - ticket has no acceptance criteria`, or `none - ticket not fetched (<reason>)`. Never author acceptance criteria on the ticket's behalf; that is `/skill:shape-ticket`'s job.
123
138
 
124
139
  ## First-Feature Oversight (Early Project Stages)
125
140
 
@@ -158,14 +173,15 @@ After writing the spec to `<project>/doc/specs/<filename>.md` (per [Filename Con
158
173
  - **Placeholder scan.** Any `TODO`, `TBD`, `<fill in>`, `[example]`, `xxx`? Either resolve them or convert to explicit "Open Questions" with names.
159
174
  - **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.
160
175
  - **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.
176
+ - **Ticket contract present.** Does `## Acceptance criteria` exist with either verbatim ticket rows plus dispositions or one `none - <reason>` line? Presence is enforced here, at authoring, and nowhere later.
161
177
  - **Scope check.** Does every paragraph serve the goal? Cut filler. If something is out of scope, say it's out of scope.
162
178
  - **Ambiguity check.** Is every "we should…" backed by a concrete decision? Replace "we could probably" with "we will" or "we won't".
163
179
 
164
- The first three are the inline **lint**: run them here and fix what they surface. The last two are the **critique pass**, dispatched per [Spec Council](#spec-council-optional). After it returns, re-run the placeholder scan over the applied spec; if a predecessor banner exists, confirm its `<scope>` still matches and reconcile it; carry any ambiguity the critique could not resolve to the [User Review Gate](#user-review-gate).
180
+ The first four are the inline **lint**: run them here and fix what they surface. The last two are the **critique pass**, dispatched per [Spec Council](#spec-council-optional). After it returns, re-run the placeholder scan over the applied spec; if a predecessor banner exists, confirm its `<scope>` still matches and reconcile it; carry any ambiguity the critique could not resolve to the [User Review Gate](#user-review-gate).
165
181
 
166
182
  ## Spec Council (Optional)
167
183
 
168
- 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`; also pass the verbatim human input (the original prompt, any ticket AC snapshot, and the questionary answers that changed scope) - roasting-the-spec forwards it to members and chair as the `Human input (verbatim; off-limits for over-spec)` block; it applies its apply-set and returns the audit (Applied/Deferred/Rejected). When `verdict` is `"worker"`, dispatch the worker below. 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`.
184
+ 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`; also pass the verbatim human input (the original prompt, any ticket AC snapshot - the raw rows under the gather draft's `## Ticket acceptance criteria (verbatim)` heading, never the spec's section, which holds the author's dispositions - and the questionary answers that changed scope) - roasting-the-spec forwards it to members and chair as the `Human input (verbatim; off-limits for over-spec)` block; it applies its apply-set and returns the audit (Applied/Deferred/Rejected). When `verdict` is `"worker"`, dispatch the worker below. 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`.
169
185
 
170
186
  When `verdict` is `"worker"`, dispatch one fresh `worker` that applies the scope + ambiguity checks and fixes them in place:
171
187
 
@@ -74,8 +74,12 @@ Context-builder (conditional):
74
74
  > `<initial prompt verbatim>`. Fetch and distill these references:
75
75
  > `<detected refs, one per line>`. For each: acceptance criteria, hard constraints,
76
76
  > linked discussion that changes scope, and contradictions with the request as
77
- > stated. Write ONLY the context handoff to your output path; do NOT produce a
78
- > meta-prompt file. End with an "Open questions that matter for the spec" section.
77
+ > stated. Quote the ticket's acceptance-criteria rows verbatim under their own
78
+ > `## Ticket acceptance criteria (verbatim)` heading before distilling the rest;
79
+ > brainstorming copies these rows unchanged into the spec and the council's
80
+ > `Human input` block. Write ONLY the context handoff to your output path; do NOT
81
+ > produce a meta-prompt file. End with an "Open questions that matter for the spec"
82
+ > section.
79
83
  > If a ref is unreadable, say so explicitly and continue.
80
84
 
81
85
  (The meta-prompt exclusion matters: in chain mode context-builder emits two files —
@@ -231,6 +231,14 @@ EOF
231
231
  )")
232
232
  ```
233
233
 
234
+ When the spec's `## Acceptance criteria` has at least one `venue:` or `deferred:` row, append this block after `## Test Plan`, listing those rows verbatim with their disposition, so the reader knows what `/skill:check-delivery` verifies after deploy and what a follow-up owns. With no such rows the body ends at `## Test Plan`, byte-identical to today. Option 1's squash commit message is unchanged.
235
+
236
+ ```markdown
237
+ ## Acceptance criteria
238
+ - [ ] <row text verbatim> - venue: <env> - <observation>
239
+ - [ ] <row text verbatim> - deferred: <where>
240
+ ```
241
+
234
242
  **Do NOT clean up worktree** — user needs it alive to iterate on PR feedback.
235
243
 
236
244
  #### Option 3: Keep As-Is
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: gauntlet-handoff
3
+ description: Human-only producer of a gauntlet handoff brief - invokes pi-cohort's `handoff` skill, then appends the gauntlet process-state section (phase/plan tracker status) to the brief it wrote, per the shared brief contract. Run at the end of a session whose flow a fresh session will continue with /skill:gauntlet-resume.
4
+ disable-model-invocation: true
5
+ argument-hint: "[--out <path> | --key <name>]"
6
+ ---
7
+
8
+ > **Related skills:** Pairs with `/skill:gauntlet-resume`, the sole consumer of the brief this skill finishes. The grammar both read is `../gauntlet-resume/reference/brief-contract.md` - this file cites it and restates none of it.
9
+
10
+ # Gauntlet Handoff
11
+
12
+ ## Overview
13
+
14
+ pi-cohort's `handoff` skill writes the flow-agnostic core of a brief (six headings,
15
+ ending at `## Skills loaded`). Only this package knows what `phase_tracker` and
16
+ `plan_tracker` state mean, so this skill appends that state as one more section, in
17
+ the layout fixed by `reference/brief-contract.md` (`## Producers`). Runs in the main
18
+ loop: tracker state is extension state no subagent can read.
19
+
20
+ **Announce at start:** "I'm using the gauntlet-handoff skill to write a resumable handoff brief."
21
+
22
+ ## Boundaries
23
+
24
+ - Reads: `../gauntlet-resume/reference/brief-contract.md` in full (resolve against this
25
+ skill's directory) before any other action; the transcript; git metadata by path.
26
+ - Writes: only an append to the brief cohort wrote, wherever the resolved path puts it
27
+ (a repository-local `--out` included). Never a second file, never the trackers, never
28
+ any other repository file.
29
+ - Every STOP below prints the offending path or fact and writes nothing further.
30
+
31
+ ## Sequence
32
+
33
+ 1. **Resolve the target.**
34
+ - `--out` and `--key` both given -> STOP: they are exclusive in cohort's grammar.
35
+ - `--out <path>` -> resolve to an absolute path against the session cwd
36
+ (`node -p "require('path').resolve(process.argv[1])" -- "<path>"`); that is the
37
+ expected path and the form passed to cohort.
38
+ - Otherwise the key is `--key <name>` when given, else derived from the **run
39
+ worktree**: the path a flow skill reported as `Worktree ready at <path>` in this
40
+ transcript (the same evidence cohort's snapshot uses):
41
+
42
+ ```bash
43
+ git -C "<run worktree>" branch --show-current
44
+ ```
45
+
46
+ No run worktree in the transcript -> the session cwd branch:
47
+
48
+ ```bash
49
+ BRANCH=$(git branch --show-current)
50
+ DEFAULT=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's#^origin/##')
51
+ ```
52
+
53
+ `BRANCH` empty (detached HEAD) or equal to `DEFAULT` -> STOP asking for `--key` or
54
+ `--out` (a default-branch key would collide across flows).
55
+ - A derived key has every `/` replaced by `-` (`hotfix/x` -> `hotfix-x`) so the file
56
+ lands flat in the default directory. A human-given `--key` is passed verbatim.
57
+ - Expected path = `<tmpdir>/pi-handoff/<key>.md`, `<tmpdir>` from
58
+ `node -p "require('os').tmpdir()"`. This is the one place this package restates
59
+ cohort's default-path rule; step 3 verifies it.
60
+ 2. **Invoke cohort.** `/skill:handoff --out <absolute path>` or `/skill:handoff --key <key>`,
61
+ exactly as resolved in step 1. The skill must be present in the session skill list
62
+ under `name: handoff`. Absent -> STOP: "cohort `handoff` skill not in the session
63
+ skill list - install or upgrade pi-cohort to the release that ships pi-cohort #18".
64
+ No version lookup, no fallback to the `/handoff` prompt.
65
+ 3. **Verify the file.** Expected path missing, or line 1 not starting `# Handoff:` ->
66
+ STOP with the expected path.
67
+ 4. **Refuse a double section.** The file already has a line matching
68
+ `^## Process state\s*$` -> STOP: "the installed pi-cohort still writes process state
69
+ itself - upgrade to the release that ships #18".
70
+ 5. **Hotfix exclusion.** `skills/chase-bug/hotfix.md` is in this session's context ->
71
+ append nothing; report a plain hotfix handoff and go to step 7. Checked before the
72
+ trackers: chase-bug never touches tracker state, and a stale armed flow appended here
73
+ would steer resume away from its hotfix route.
74
+ 6. **Append.** `phase_tracker({ action: "status" })`, then `plan_tracker({ action: "status" })`.
75
+ - No phase `in_progress` -> append nothing; say the brief is a plain handoff.
76
+ - A phase `in_progress` (verify or ship included - resume stops at verify on its own)
77
+ -> append the process-state section exactly as `## Producers` in
78
+ `reference/brief-contract.md` lays it out: both status outputs verbatim
79
+ (`No plan active.` verbatim when there is no plan), the active-task line naming
80
+ the first `→` task else `none`, the gate-history line. Append with a single
81
+ `cat >> "<expected path>" <<'EOF' ... EOF` whose body is that block.
82
+ - Re-read the file tail and confirm it ends with the gate-history line from the
83
+ contract and nothing after.
84
+ 7. **Report.** Print the path and `/skill:gauntlet-resume <path>`. When a section was
85
+ appended and the brief's `worktree:` field is `no`, resume's entry check 2 needs an
86
+ override: print `/skill:gauntlet-resume <path> <override>` where `<override>` is the
87
+ run worktree from step 1 when one was found, else the session checkout root,
88
+ `dirname "$(git rev-parse --path-format=absolute --git-common-dir)"`. If that command
89
+ fails (session cwd is not inside a git repository), print the one-argument form and
90
+ the line `No resumable worktree found - pass the worktree path as the second argument.`
91
+
92
+ ## Red flags - STOP
93
+
94
+ - Writing the brief yourself instead of invoking `/skill:handoff` (the core headings are
95
+ cohort's; this skill appends one section).
96
+ - Restating the section layout here instead of reading `reference/brief-contract.md`.
97
+ - Appending when step 4 or step 5 fired.
98
+ - Deriving the key from the primary checkout's branch while a run worktree exists.
99
+
100
+ ## Project overrides
101
+
102
+ If a gauntlet overrides file exists - checked in order:
103
+ `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`,
104
+ `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Any
105
+ sections relevant to this skill - by name match, by topic (routing,
106
+ verification, worktrees, etc.), or by workflow convention - override or
107
+ extend the instructions above. Project-local `AGENTS.md` is already in
108
+ context - check it for project-specific routing tables, service paths, and
109
+ verification commands.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gauntlet-resume
3
- description: Use when a human wants to continue an interrupted gauntlet flow in a fresh session - from a pi-cohort handoff brief (file or pasted) or from a bare worktree that already holds a spec. Human-only; the sole resume entry point. Restores phase/plan tracker state through the legal arming sequence, never creates a worktree, never infers approval.
3
+ description: Use when a human wants to continue an interrupted gauntlet flow in a fresh session - from a gauntlet-handoff brief (file, pasted, or picked from the default handoff directory) or from a bare worktree that already holds a spec. Human-only; the sole resume entry point. Restores phase/plan tracker state through the legal arming sequence, never creates a worktree, never infers approval.
4
4
  disable-model-invocation: true
5
5
  argument-hint: "[<brief-file>] [<worktree-name-or-path>]"
6
6
  ---
@@ -12,7 +12,7 @@ argument-hint: "[<brief-file>] [<worktree-name-or-path>]"
12
12
  ## Overview
13
13
 
14
14
  Re-enter an interrupted gauntlet flow in a fresh session. Two inputs: a handoff brief
15
- produced by pi-cohort's `/handoff` (grammar in `reference/brief-contract.md`), or a bare
15
+ produced by `/skill:gauntlet-handoff` (grammar in `reference/brief-contract.md`), or a bare
16
16
  worktree whose spec/plan artifacts are reconstructed into tracker state
17
17
  (`reference/reconstruction.md`). Every check runs before any tracker mutation; every
18
18
  stop names the offending path, field, or line.
@@ -35,14 +35,21 @@ optional pasted text after the command line.
35
35
 
36
36
  | Form | Meaning |
37
37
  |---|---|
38
- | `<brief-file>` | readable file whose line 1 starts `# Handoff:` |
38
+ | (no tokens, no pasted text) | discovery: `<tmpdir>` via `node -p "require('os').tmpdir()"`; candidates are the regular files directly under `<tmpdir>/pi-handoff/` ending `.md` (non-recursive) whose line 1 starts `# Handoff:`; sorted by mtime, newest first; displayed one per line as `<n>. <title line> - <worktree: field value> - <mtime ISO-8601>` with `worktree: unavailable` when the field is absent; the human picks `<n>` (a single candidate is still confirmed); none -> STOP "no handoff briefs found under <tmpdir>/pi-handoff" |
39
+ | `<brief-file>` | a single token that is an absolute path, contains a path separator, or ends in `.md`; used as given, never widened to a scan; missing, unreadable, or line 1 not `# Handoff:` -> STOP with that path |
39
40
  | pasted text whose first line starts `# Handoff:` | inline brief (equivalent to a file) |
40
- | `<worktree>` alone | bare name resolved as `<primary>/.worktrees/<name>`, or an absolute path; must already be a git worktree |
41
+ | `<worktree>` alone | any other single token (no path separator, not ending `.md`): bare name resolved as `<primary>/.worktrees/<name>`; must already be a git worktree. An absolute worktree path is given only in the two-token `<brief> <worktree>` form |
41
42
  | `<brief> <worktree>` | brief plus an explicit worktree override (required when the brief's worktree field is `no`/`unavailable`/not a git repo; must equal the brief's worktree after `realpath` otherwise) |
42
43
  | anything else | not a resume input - stop with "this is a new idea - run /skill:brainstorming" |
43
44
 
44
45
  `<primary>` is the checkout owning `.worktrees/`: `dirname "$(git rev-parse --path-format=absolute --git-common-dir)"` run in the session cwd - absolute from any primary subdirectory and from inside a linked worktree (`--show-toplevel` would return the linked worktree there). A bare `<name>` resolves as `<primary>/.worktrees/<name>`. A pasted brief that needs an override uses the file form. This skill never runs `git worktree add`.
45
46
 
47
+ Classification runs before anything else: a token that is an absolute path, contains a
48
+ path separator, or ends in `.md` is a `<brief-file>` - never a worktree name, never
49
+ widened to a scan. Any other single token is tried as `<worktree>`. A picked or given
50
+ brief then runs entry checks 1-5 unchanged, so a stale or foreign-repo brief stops there.
51
+ Free-form text still lands on the "anything else" row.
52
+
46
53
  ## Entry checks
47
54
 
48
55
  In order. All before any tracker mutation; entry check 1 is read-only.
@@ -1,9 +1,12 @@
1
- # Handoff brief contract (gauntlet-resume supplementary)
1
+ # Handoff brief contract (gauntlet-resume + gauntlet-handoff supplementary)
2
2
 
3
- Consumed only by `SKILL.md` in this directory. This file is the single concentration
4
- point for text coupled to pi-cohort's `/handoff` template (`doc/handoff-template.md`
5
- in pi-cohort; baseline inlined from its `prune-prompts` branch, commit `812de45`).
6
- Cohort drift is reconciled here and nowhere else.
3
+ Consumed by `gauntlet-resume/SKILL.md` (consumer) and `gauntlet-handoff/SKILL.md`
4
+ (producer). Grammar lives only here; both skills cite this file and inline none of it
5
+ (`scripts/ci.mjs` drift lint). Coupled to pi-cohort's `handoff` skill (pi-cohort #18)
6
+ for exactly six headings - `# Handoff:`, `## Intent`, `## Repo state`, `## Decisions`,
7
+ `## Open questions`, `## Skills loaded` - and the `## Repo state` fields. `## Process
8
+ state` grammar and its consumer rules are owned here. Cohort drift is reconciled here
9
+ and nowhere else.
7
10
 
8
11
  ## Brief grammar
9
12
 
@@ -24,9 +27,9 @@ Headings, fixed order. A consumer keys on headings, never prose.
24
27
  | `## Repo state` | one field per line: `toplevel`, `worktree: yes <path>` or `worktree: no`, `branch` (`detached` when none), `HEAD`, `base` (`unknown` when no remote resolves), `dirty: <porcelain>` or `dirty: clean`, `diff-stat` (`unavailable` when base unknown), `test cmd`; any field `unavailable` when its command failed; heading `## Repo state: not a git repo` outside git | always |
25
28
  | `## Decisions` | bullets; rejected alternatives marked `rejected:` | always |
26
29
  | `## Skills loaded` | frontmatter `name`s; `## Skills loaded: none` when none | always |
27
- | `## Process state` | `phase_tracker status` then `plan_tracker status` verbatim; `Active task: <name|none>`; the line `Gate history not restored - re-validate before advancing.` | only when both tracker tools exist and a phase is `in_progress` |
30
+ | `## Process state` | `phase_tracker status` then `plan_tracker status` verbatim; `Active task: <name|none>`; the line `Gate history not restored - re-validate before advancing.` | only when a phase is `in_progress` and no hotfix flow is in context |
28
31
 
29
- Consumer rules (cohort): process state absent -> plain handoff (the consumer starts its
32
+ Consumer rules: process state absent -> plain handoff (the consumer starts its
30
33
  own process from `## Intent`); present with `No plan active.` -> phase-only, restore no
31
34
  plan; loading named skills is the consumer's job.
32
35
 
@@ -34,6 +37,38 @@ A brief is any text whose first line starts `# Handoff:` - a file on disk or pas
34
37
  inline. `## Repo state` is matched by prefix: `## Repo state` or
35
38
  `## Repo state: not a git repo`.
36
39
 
40
+ ## Producers
41
+
42
+ `gauntlet-handoff` is the only writer of `## Process state`; it appends to the file
43
+ cohort's `handoff` skill wrote, which ends at `## Skills loaded`. Layout, byte-exact:
44
+ one blank line, the heading on its own line, a blank line, the `phase_tracker status`
45
+ output verbatim, a blank line, the `plan_tracker status` output verbatim, a blank line,
46
+ `Active task: <name|none>`, then the gate-history line - unfenced, nothing after.
47
+ `Active task` is the first `→` task name, else `none` (also for `No plan active.`).
48
+
49
+ Example appended block (the fence is documentation; the brief carries no fence):
50
+
51
+ ```text
52
+
53
+ ## Process state
54
+
55
+ Phases:
56
+ ⊘ brainstorm (resume: pasted brief)
57
+ ⊘ plan (resume: pasted brief)
58
+ → implement(W2)
59
+ ○ verify
60
+ ○ ship
61
+
62
+ Plan: 1/3 done (1 in progress, 1 pending)
63
+
64
+ ✓ [0] W1: contract
65
+ → [1] W2: producer
66
+ ○ [2] W2: consumer
67
+
68
+ Active task: W2: producer
69
+ Gate history not restored - re-validate before advancing.
70
+ ```
71
+
37
72
  ## Tracker output grammar
38
73
 
39
74
  Must match `formatStatus` in the phase-tracker and plan-tracker extensions.
@@ -57,6 +57,7 @@ Self-checking in the main session is the fallback when delegation isn't possible
57
57
  | Order | Source | Why |
58
58
  |---|---|---|
59
59
  | 1 | The written spec (`doc/specs/…`) | Canonical. Brainstorm already fetched the ticket, reconciled its ACs, recorded deviations here. |
60
+ | 1 | The spec's `## Acceptance criteria` section | Same priority as the spec body. The ticket's AC rows verbatim with dispositions; `in-scope`/`venue:` rows are requirements, `deviates:`/`deferred:` rows are recorded drift - read per the `conformance-reviewer` persona. |
60
61
  | 2 | Original prompt | Catches inline requirements never folded into the spec. |
61
62
  | 3 | Re-fetch the ticket | **Fallback only**, when no spec exists. Skip when a spec exists — the live ticket may have drifted. |
62
63
 
@@ -229,7 +229,7 @@ Task commit steps use bare `git`: the implementer subagent runs with the checkou
229
229
 
230
230
  ## Spec Coverage Table
231
231
 
232
- Every plan ends with a `## Spec coverage` section (grammar and example: [reference/plan-contract.md § Spec coverage table](reference/plan-contract.md)). Build it extraction-first: walk the spec top to bottom and write one row per normative requirement **before** assigning owners — every Design imperative (Add/Remove/Keep/Replace-style directives, not any fixed lexical form), every Edge-cases rule, every Acceptance criterion, every Out-of-scope entry, and every non-none Documentation-impact entry. Then assign owners, then re-walk the spec once: every normative clause has a row. Two row kinds:
232
+ Every plan ends with a `## Spec coverage` section (grammar and example: [reference/plan-contract.md § Spec coverage table](reference/plan-contract.md)). Build it extraction-first: walk the spec top to bottom and write one row per normative requirement **before** assigning owners — every Design imperative (Add/Remove/Keep/Replace-style directives, not any fixed lexical form), every Edge-cases rule, every Acceptance criterion, every Out-of-scope entry, and every non-none Documentation-impact entry. Then assign owners, then re-walk the spec once: every normative clause has a row. From the spec's `## Acceptance criteria`, table only `in-scope` and `venue:` rows (a `venue:` row's owner is the task delivering its named enabling change); `deviates:`, `deferred:`, and `none` rows get no table row - their disposition is the record, and any obligation a `deviates:` reason adopts is already a Design clause with its own row. Two row kinds:
233
233
 
234
234
  - **Requirement rows:** a cross-cutting requirement (decided in more than one task) lists **every** deciding task as owner, not the first. `waived: <reason>` is only for requirements the spec marks out of scope **and** that exclude work from the change. A requirement whose text carries an inline code span (`` `literal` ``) names concrete behaviour and is never waivable - it maps to a task or `Verification`. A waiver on an in-scope normative requirement is a Self-Review failure — there is no human plan-review gate to catch it downstream.
235
235
  - **`Verification` owner:** only for a requirement the header command proves; grammar in the reference.