pi-gauntlet 7.31.1 → 7.32.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,12 @@
1
1
  # Changelog
2
2
 
3
+ ## v7.32.0 - 2026-10-25
4
+
5
+ ### Added
6
+
7
+ - **Ticketless specs get drafted, gate-ratified acceptance criteria, so the loop engine is available to them.** When the ticket path yields no rows (a free-text brainstorm, a fetched ticket without acceptance criteria, or an unbound PR subject), brainstorming drafts `- [ ]` rows from the approved Design under a `Drafted from the design, ...` header, the approval gate renders them in a `Drafted acceptance criteria (approval ratifies):` block between `Scope cuts:` and `Council:`, and options 4/5 (loop engine) appear beside 1-3. A missing yardstick asks for clarification instead of inventing a value or falling back to `none`; the council and its applier never delete a drafted row except through the scope-decision procedure, and the post-council re-scan re-drafts from the applied Design when the section was erased. After ratification drafted text is frozen: dispositions move through the existing cut-question/amendment path, and any row change is a redraw with the full gate. A ticket with rows and `none - ticket not fetched (<reason>)` keep today's behavior; `checkLedger`, `loop-implementation`, and `loop-implementer` are untouched (`skills/brainstorming/reference/ticket-acceptance.md`, `spec-finalization.md`; `doc/configuration.md` names the availability rule). (#84)
8
+ - Eval samples `drafted-ac-rows` (five cells) and `drafted-ac-recovery` under `eval/brainstorming/`, and `drafted-rows-block` under `eval/spec-gate/`; `loop-gate` and the `pr-subject-*` samples are rewritten for the drafted-row contract. (#84)
9
+
3
10
  ## v7.31.1 - 2026-10-25
4
11
 
5
12
  ### Changed
@@ -40,4 +40,6 @@ Anything else (not found, inconclusive, timed out, contradicted) -> create `## O
40
40
 
41
41
  Inline an `external-ref:` cluster only from the human-input block or fetched external context carrying the reference. Otherwise defer it with `-> user supplies at gate`.
42
42
 
43
- Execute an applied `over-spec:` cluster by deleting or shrinking the quoted clause and every acceptance-criteria or testing-approach line that exists only for it. Keep the human-input block off-limits for over-spec. End its audit line with `-> cut (was adds: M files / N tests / K ACs)` or `-> shrunk to <replacement> (was adds: ...)`.
43
+ Drafted rows are spec requirements, not Human input; permit pre-approval rewrites only for integrity (wishful, tautological, unspecified-but-binding, external-input, or post-deployment proof). Preserve the committed outcome and use only Design-sourced proof; leave missing values for clarification. Delete a drafted row only after its Design commitment is cut through the user's scope-decision procedure; quoting the row alone never permits deletion, and never replace the section with `none`. Never draft new rows.
44
+
45
+ Subject to the drafted-row protection above, execute an applied `over-spec:` cluster by deleting or shrinking the quoted clause and every acceptance-criteria or testing-approach line that exists only for it. Keep the human-input block off-limits for over-spec. End its audit line with `-> cut (was adds: M files / N tests / K ACs)` or `-> shrunk to <replacement> (was adds: ...)`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "7.31.1",
3
+ "version": "7.32.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",
@@ -186,7 +186,7 @@ Execute in place from any later phase; never invoke `/skill:brainstorming` for i
186
186
 
187
187
  Every skill resource in this flow (a `SKILL.md` or a `reference/*.md`) is loaded with the `read` tool at its absolute path under `skills/`, never with a shell command - pruning protection keys on `read`'s `path`.
188
188
 
189
- Classify first. Redraw test: the change alters the problem statement, adds or removes a component, or moves a component boundary -> redraw. A change inside one component (a persistence mechanism, a worker's HTTP client, dropping a fallback and its task) -> amend. State the call; the user overrides either way.
189
+ Classify a change to an approved drafted acceptance-criteria row - its text, a row added, a row removed - as a redraw at batch preparation, before any standing grant, never a disposition amendment: re-draft from the new design and ratify at the full gate; keep a disposition-only change to such a row in the amendment grammar so it keeps the cut question. Apply an item the human has answered by letter or custom text as recorded. Redraw test: the change alters the problem statement, adds or removes a component, or moves a component boundary -> redraw. A change inside one component (a persistence mechanism, a worker's HTTP client, dropping a fallback and its task) -> amend. State the call; the user overrides either way.
190
190
 
191
191
  Amend -> `read` `reference/amendment-surface.md` and follow it (unreadable -> stop with a blocking error; never improvise the grammar). Apply its [Standing grants](reference/amendment-surface.md#standing-grants) boundaries.
192
192
 
@@ -1,6 +1,6 @@
1
1
  # Amendment surface
2
2
 
3
- `read` this file (the `read` tool at its absolute path, never a shell command) from `skills/brainstorming/SKILL.md` § Amending an approved spec, from any phase, for amend-class changes; at approval, load only [Standing grants](#standing-grants), not the batch procedure. Keep redraws outside this procedure. Only the main loop holding `edit`/`write` authors amendments and human-facing amendment text. Use the human last: a fresh reviewer clears evidence-backed factual corrections; present the rest to the human once per batch plainly.
3
+ `read` this file (the `read` tool at its absolute path, never a shell command) from `skills/brainstorming/SKILL.md` § Amending an approved spec, from any phase, for amend-class changes; at approval, load only [Standing grants](#standing-grants), not the batch procedure. Keep redraws outside this procedure. Classify a change to an approved drafted acceptance-criteria row - its text, a row added, a row removed - as a redraw at batch preparation, before any standing grant, never a disposition amendment: re-draft from the new design and ratify at the full gate; keep a disposition-only change to such a row in this grammar so it keeps the cut question. Apply an item the human has answered by letter or custom text as recorded. Only the main loop holding `edit`/`write` authors amendments and human-facing amendment text. Use the human last: a fresh reviewer clears evidence-backed factual corrections; present the rest to the human once per batch plainly.
4
4
 
5
5
  ## Standing grants
6
6
 
@@ -142,7 +142,7 @@ Before the aftermath, `read` this section again; never run it from memory.
142
142
 
143
143
  Apply accepted items only: reviewer clears, `accept`, `alt-n`, and state-changing `custom`. Print one line per applied item: `amended the spec: <title> - <what>`.
144
144
 
145
- Aftermath, once per batch, only when at least one item applied (nothing applied -> skip to the commit below). Ledger exists (line 1 `# Ledger - loop engine` in the resolved plan dir) -> skip `plan-writer`, `plan_check`, and `plan_tracker`. Reconcile the ledger against the approved spec dispositions: `deviates:`, `deferred:`, or `elsewhere:` -> `cut`, evidence = the disposition; factual or requirement-preserving amendment -> preserve rows; re-bounded `done` row -> `open`, evidence = `reopened by amendment`. Preserve every row's attempts and the ledger's iterations. Never auto-edit ticket AC row texts. Commit spec + ledger together with subject `loop: cut row <n>` for a single cut, otherwise `loop: amend`, carrying the amendment audit body below (including each `granted` record and granting sentence); continue without task-plan aftermath. No plan yet -> commit the spec; continue. Plan exists -> read `git -C "<abs worktree path>" status --porcelain` (plain jj: `jj -R "<abs worktree path>" diff --summary`); collect the parent's in-flight workflow edits as worktree-relative paths, including the amended spec and staged in-place wave-repair deliverables. Dispatch `plan-writer` per `writing-plans` `## Author the plan` step 3 with an `Amend:` block naming the amended spec sections, an `In-flight:` list of those paths (the parent supplies the set; the child never infers it), and the rule "preserve every task title and wave position the amendment does not touch; edit only affected anchors and tasks", then run that section's steps 5-6 (the parent `plan_check` and its branches), then read the amended plan once (step 7's read, without its phase completion or `plan_tracker` init) - the main loop never edits the plan text; then update the tracker: `plan_tracker` `add` for new tasks; anchor-changed completed tasks are reopened as `in_progress` and re-run the task loop (`update` never sets `pending`). A removed task is deleted from the plan; then re-`init` the tracker with `{ name, status }` elements: preserved tasks keep their order and statuses, reopened tasks are `in_progress` in place, every still-`pending` task (including newly added ones, whatever wave label they carry) trails the non-pending ones, removed tasks are the only deletions (the only permitted `init` after handoff; never `clear`). Commit spec + plan together; continue. A task reopened while `verify` or `ship` is in progress stays in that phase - no `phase_tracker` call. Repair it through the current phase's fix loop and `plan_tracker({ action: "update", index: N, status: "complete" })` it once that repair's review or re-audit accepts; open tasks block `complete verify`, and in `ship` nothing checks them, so close them explicitly.
145
+ Aftermath, once per batch, only when at least one item applied (nothing applied -> skip to the commit below). Ledger exists (line 1 `# Ledger - loop engine` in the resolved plan dir) -> skip `plan-writer`, `plan_check`, and `plan_tracker`. Reconcile the ledger against the approved spec dispositions: `deviates:`, `deferred:`, or `elsewhere:` -> `cut`, evidence = the disposition; factual or requirement-preserving amendment -> preserve rows; re-bounded `done` row -> `open`, evidence = `reopened by amendment`. Preserve every row's attempts and the ledger's iterations. Never auto-edit ticket or approved drafted AC row texts; reconcile dispositions only, never text/add/remove changes. Commit spec + ledger together with subject `loop: cut row <n>` for a single cut, otherwise `loop: amend`, carrying the amendment audit body below (including each `granted` record and granting sentence); continue without task-plan aftermath. No plan yet -> commit the spec; continue. Plan exists -> read `git -C "<abs worktree path>" status --porcelain` (plain jj: `jj -R "<abs worktree path>" diff --summary`); collect the parent's in-flight workflow edits as worktree-relative paths, including the amended spec and staged in-place wave-repair deliverables. Dispatch `plan-writer` per `writing-plans` `## Author the plan` step 3 with an `Amend:` block naming the amended spec sections, an `In-flight:` list of those paths (the parent supplies the set; the child never infers it), and the rule "preserve every task title and wave position the amendment does not touch; edit only affected anchors and tasks", then run that section's steps 5-6 (the parent `plan_check` and its branches), then read the amended plan once (step 7's read, without its phase completion or `plan_tracker` init) - the main loop never edits the plan text; then update the tracker: `plan_tracker` `add` for new tasks; anchor-changed completed tasks are reopened as `in_progress` and re-run the task loop (`update` never sets `pending`). A removed task is deleted from the plan; then re-`init` the tracker with `{ name, status }` elements: preserved tasks keep their order and statuses, reopened tasks are `in_progress` in place, every still-`pending` task (including newly added ones, whatever wave label they carry) trails the non-pending ones, removed tasks are the only deletions (the only permitted `init` after handoff; never `clear`). Commit spec + plan together; continue. A task reopened while `verify` or `ship` is in progress stays in that phase - no `phase_tracker` call. Repair it through the current phase's fix loop and `plan_tracker({ action: "update", index: N, status: "complete" })` it once that repair's review or re-audit accepts; open tasks block `complete verify`, and in `ship` nothing checks them, so close them explicitly.
146
146
 
147
147
  One commit per batch:
148
148
 
@@ -14,7 +14,7 @@ Parse the PR base repository from `url` and this checkout's repository from `git
14
14
 
15
15
  Bind the first tracker reference in the title, then the body's first line. Never bind from branch names, commit subjects, or `closingIssuesReferences`. Fetch a bound ticket, extract its AC rows using `reference/ticket-acceptance.md`, and dispatch context-builder for it. Preserve `none - ticket not fetched (<reason>)` on fetch failure. When title and first body line name different tickets, use the title's ticket and name the other in `## Problem` as context.
16
16
 
17
- For an unbound PR, write `none - no ticket` under `## Acceptance criteria`; carry raw title/body as stated intent, not invented AC rows. Name its spec `YYYY-MM-DD-pr-<N>-<topic>.md`; emit the concrete filename with the actual date, PR number, and topic slug derived from the PR title. For a bound ticket keep `YYYY-MM-DD-<ticket-id>-<topic>.md`.
17
+ For an unbound PR, retain the gather-time result `none - no ticket`; at spec-writing use `ticket-acceptance.md`'s drafted branch from the agreed rework design. Carry raw title/body as stated intent, not invented AC rows; derive the drafted outcomes from the agreed design, not the title/body carry-over. Name its spec `YYYY-MM-DD-pr-<N>-<topic>.md`; emit the concrete filename with the actual date, PR number, and topic slug derived from the PR title. For a bound ticket keep `YYYY-MM-DD-<ticket-id>-<topic>.md`.
18
18
 
19
19
  Pass exactly `{ number, url, title, headRefName, headRefOid, baseRefName, isCrossRepository, headRepository.nameWithOwner }` by value to provisioning in `using-git-worktrees/reference/pr-head.md`; write nothing during resolution.
20
20
 
@@ -8,6 +8,11 @@ Spec-writing replaces the context draft, in this exact order:
8
8
  pruned questionary plus a full-replacement `write` destroys the only copy of the
9
9
  gathered context at the moment it feeds the spec.
10
10
  2. Write the spec with the `write` tool (**full replacement**) at the spec path.
11
+ After the mandatory draft read and before the full replacement, apply
12
+ `ticket-acceptance.md`'s row-production branch to the approved two-round design plus the original prompt.
13
+ Keep `## Acceptance criteria` after Problem; draft one observable outcome per row,
14
+ default `in-scope`, retaining environment-bound pre-production proof as `venue:`.
15
+ Apply the inline integrity recovery and cut question there before writing.
11
16
  Using `edit` at this step is a red flag. The header block (between the H1 and the
12
17
  first `##`) carries `**Amend-grant:** none` directly below `**Goal:**`; a redraw's
13
18
  rewrite carries `none` too - a redraw is a new approval, with no carry-over.
@@ -46,14 +51,16 @@ After writing the spec to `<project>/doc/specs/<filename>.md` (per [Filename Con
46
51
  - **Placeholder scan.** Any `TODO`, `TBD`, `<fill in>`, `[example]`, `xxx`? Either resolve them or convert to explicit "Open Questions" with names.
47
52
  - **Internal consistency.** Does Section 4 contradict Section 2? Does the header block carry `**Amend-grant:**` exactly once with the value `none` (the [predicate](amendment-surface.md#standing-grants))? 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.
48
53
  - **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 `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.
49
- - **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. For a PR subject, require the complete `## Rework record` per `pr-subject.md`; absence fails inline lint, including after a full replacement or redraw.
54
+ - **Ticket contract present.** Require `## Acceptance criteria` in exactly three forms: ticket provenance (`Ticket <ref>, <heading or "checkbox list">, rows verbatim:`) with verbatim rows and dispositions; drafted provenance (`Drafted from the design, no ticket rows:` or `Drafted from the design, ticket <ref> has no acceptance criteria:`) with at least one `- [ ]` row and a disposition on every row; or the single line `none - ticket not fetched (<reason>)`. Reject `none - no ticket` and `none - ticket has no acceptance criteria` as final bodies. For a PR subject, require the complete `## Rework record` per `pr-subject.md`; absence fails inline lint, including after a full replacement or redraw.
50
55
  - **Scope check.** Does every paragraph serve the goal? Cut filler. If something is out of scope, say it's out of scope.
51
56
  - **Ambiguity check.** Is every "we should..." backed by a concrete decision? Replace "we could probably" with "we will" or "we won't".
52
57
 
53
- 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). After it returns, re-run the placeholder scan over the applied spec and re-apply the predicate to the header block - if the critique pass removed or altered the `**Amend-grant:**` line, repair it to `none`, exactly once; 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).
58
+ 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). After it returns, re-run the placeholder scan over the applied spec and reapply the same whole-section predicate from **Ticket contract present**: a correct provenance header with zero rows still fails. Have the main loop repair an invalid drafted section (including erased provenance, a triggering `none` line, or a header with no rows) from the applied Design by re-drafting at least one valid row using `ticket-acceptance.md`'s integrity recovery; never delegate drafting to the applier. With no valid outcome, obtain clarification or an explicit scope decision before the gate. On successful repair, append `Drafted AC repair: restored acceptance rows from the applied Design.` after the existing commit-body audit, preserving council cluster lines and counts; on the worker path append it to the otherwise empty body. Then re-apply the predicate to the header block - if the critique pass removed or altered the `**Amend-grant:**` line, repair it to `none`, exactly once; 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).
54
59
 
55
60
  ## Spec Council
56
61
 
62
+ Exclude drafted rows from `Human input (verbatim; off-limits for over-spec)`; they are spec requirements, not a ticket snapshot. Keep the original prompt, ticket snapshot, PR input, and human scope answers in today's transport.
63
+
57
64
  Before dispatching the worker below, resolve `documentation-impact.md` relative to this loaded reference as one absolute `<DOCUMENTATION_IMPACT_GUIDELINE>` path value. Pass that value in the worker task; do not add it to the spec.
58
65
 
59
66
  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`; for a PR subject include the PR title and body verbatim beside the bound ticket rows in `Human input`; 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, for every question that offered a disposition (the cut question and the unmatched-group question in `ticket-acceptance.md`), the full question and the user's answer) - roasting-the-spec forwards it to members, chair, and applier as the `Human input (verbatim; off-limits for over-spec)` block; its dispatched applier applies the spec edits and supplies the returned 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`.
@@ -66,6 +73,8 @@ subagent({ agent: "worker", context: "fresh", async: false, cwd: "<abs worktree
66
73
  "Read the spec at <abs path to doc/specs/...>. Edit ONLY that file.\n" +
67
74
  "The portable citation `reference/documentation-impact.md` in the spec is the pi-gauntlet guideline at <DOCUMENTATION_IMPACT_GUIDELINE>, not a consumer doc; do not flag it as an external reference, and preserve it - never remove it as redundant or replace it with the resolved absolute path.\n" +
68
75
  "The `**Amend-grant:**` header line is flow machinery owned by the brainstorming gate; never cut, shrink, flag, or edit it.\n" +
76
+ "Drafted rows are spec requirements, not Human input; permit pre-approval rewrites only for integrity. Preserve every committed outcome and rewrite only its proof using Design-sourced values; never invent a baseline, target, measurement, or missing value. Flag missing inputs for main-loop clarification before the gate rather than dropping the outcome.\n" +
77
+ "Delete a drafted row only after its Design commitment is cut through the user's scope-decision procedure; quoting the row alone never permits deletion, and never replace the section with `none`. Preserve the cut's `deviates:`/`deferred:` disposition and `## Out of scope` entry for gate disclosure. Never draft new rows; leave drafting and integrity recovery requiring clarification to the main loop under `ticket-acceptance.md`.\n" +
69
78
  "Apply two checks and fix what you find in place: (1) Scope - does every paragraph serve the goal? Cut filler;\n" +
70
79
  "state out-of-scope explicitly. (2) Ambiguity - is every 'we should' a concrete decision?\n" +
71
80
  "Replace 'we could probably' with 'we will'/'we won't'. Also inline any load-bearing\n" +
@@ -105,7 +114,7 @@ git -C <abs worktree path> add -- <spec path> [<predecessor path>] && git -C <ab
105
114
  EOF
106
115
  ```
107
116
 
108
- If the council path ran, the body is its audit (`Coverage:` when present, then `Applied:` / `Deferred:` / `Rejected:`, verbatim from `/skill:roasting-the-spec`'s return) - the durable, non-contractual record a finish-time revert and row 3 below read back; the audit is never a committed spec section. On the worker path the body is empty. `-m`, `-F <file>`, `printf | ... -F -`, and `$'...'` strings are not used for this commit. The `add` on the same line is required because the spec is untracked at its first commit and `commit -- <path>` rejects an untracked path.
117
+ If the council path ran, the body is its audit (`Coverage:` when present, then `Applied:` / `Deferred:` / `Rejected:`, verbatim from `/skill:roasting-the-spec`'s return) - the durable, non-contractual record a finish-time revert and row 3 below read back; the audit is never a committed spec section. On the worker path the body is empty except for a main-loop drafted-AC repair audit line when a repair occurred. Append that repair line after the council audit on the council path; never alter its labels, cluster lines, or counts. `-m`, `-F <file>`, `printf | ... -F -`, and `$'...'` strings are not used for this commit. The `add` on the same line is required because the spec is untracked at its first commit and `commit -- <path>` rejects an untracked path.
109
118
 
110
119
  Evaluate the summary in two stages (the **Degrade path** referenced in each is defined just below):
111
120
 
@@ -124,6 +133,11 @@ Paste the summary verbatim, unedited in the template below; use adjacent lines f
124
133
  Spec written and committed to <project>/doc/specs/<filename>.md (worktree: <path>).
125
134
  Scope cuts: <row text, first 60 chars> - <disposition>; ... | none
126
135
 
136
+ Drafted acceptance criteria (approval ratifies):
137
+ - [ ] <row text verbatim>
138
+ <disposition verbatim>
139
+ <every drafted row and disposition, verbatim; drafted provenance only>
140
+
127
141
  Council: <A> applied, <D> deferred, <R> rejected
128
142
  (council path only: A, D, R count the non-`none` lines under each label of the returned audit; append `; coverage <N> of <M>` only when the return carried a `Coverage:` line, e.g. `Council: 11 applied, 0 deferred, 0 rejected; coverage 2 of 3`; omit the whole line and row 3 on the worker path or when the council aborted before an audit existed)
129
143
 
@@ -140,7 +154,9 @@ Add "; fund N fix rounds" (or "N more fix rounds") to 1, 2, 4, or 5 to fund N ex
140
154
  Or tell me what to change in the spec, or say "revert applied council edit <X>" to undo a specific applied edit.
141
155
  ```
142
156
 
143
- For `none - <reason>` in `## Acceptance criteria`, render only options 1-3 and explain: "Loop engine unavailable: this spec has no acceptance-criteria rows." Keep the worker-path omission of option 3; do not invent a council audit.
157
+ For zero `- [ ]` rows under `## Acceptance criteria`, render only options 1-3 and explain: "Loop engine unavailable: this spec has no acceptance-criteria rows." The only legal zero-row body is `none - ticket not fetched (<reason>)`; retain its paste-rows affordance. Whenever rows exist, render options 4/5. Keep the worker-path omission of option 3; do not invent a council audit.
158
+
159
+ Render the drafted-only block in the template from the applied spec section, never from the summarizer: copy every row and disposition verbatim. Include it for a fetched ticket without ACs; omit it for ticket-row provenance. Approval ratifies these rows at this gate, with no pre-gate acceptance stop. On reply `3`, keep the block reused verbatim with the briefing; on a row-touching change request, render from the recommitted section; on redraw, render from the re-drafted section.
144
160
 
145
161
  If you believe the summary needs correcting, do **not** silently rewrite it - re-dispatch the summarizer or note the discrepancy as an adjacent line beneath the verbatim block.
146
162
 
@@ -17,6 +17,44 @@ Ticket <ref>, <heading or "checkbox list">, rows verbatim:
17
17
  <disposition>
18
18
  ```
19
19
 
20
- The heading `## Acceptance criteria` names the ticket contract only; the spec's own requirements stay in Design, and the section stays flat - a row's repo lives in its disposition token, never in a heading. Disposition is exactly one of `in-scope`, `deviates: <why>`, `deferred: <where>`, `venue: <env> - <observation>`, `elsewhere: <repo>`; default `in-scope`. Never edit the row text: an ambiguous row stays `in-scope` with the chosen reading written as a Design clause, and a moved path or a workflow artifact (spec, plan, changelog, telemetry file) is a Design clause too, never a disposition and never asked. A row under a repo group that is not this repo is `elsewhere: <repo>`, stated, never asked; a group matching no repo asks `A) this repo B) elsewhere: <name> C) repair the ticket - /skill:shape-ticket <ref>`. Replace `<name>` with the supplied unmatched group heading verbatim in option B, not a request to name a repo. Name a `venue:` row's enabling change in Design; `venue:` states where the observation can happen and is never `prd`, `prod`, or `production` - a row observable only in production is a wrong row. 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. A `deferred:` destination is a tracker ref (`#N`, `owner/repo#N`, `ABC-123`), a spec path, or a URL; a prose destination with none of these is a gap at the PR gate.
20
+ Under `Ticket <ref>, <heading or "checkbox list">, rows verbatim:`, the section names the ticket contract only; the spec's own requirements stay in Design. Keep every provenance form flat - a row's repo lives in its disposition token, never in a heading. Disposition is exactly one of `in-scope`, `deviates: <why>`, `deferred: <where>`, `venue: <env> - <observation>`, `elsewhere: <repo>`; default `in-scope`. For ticket rows, never edit the row text: an ambiguous row stays `in-scope` with the chosen reading written as a Design clause, and a moved path or a workflow artifact (spec, plan, changelog, telemetry file) is a Design clause too, never a disposition and never asked. A row under a repo group that is not this repo is `elsewhere: <repo>`, stated, never asked; a group matching no repo asks `A) this repo B) elsewhere: <name> C) repair the ticket - /skill:shape-ticket <ref>`. Replace `<name>` with the supplied unmatched group heading verbatim in option B, not a request to name a repo. Name a `venue:` row's enabling change in Design; `venue:` states where the observation can happen and is never `prd`, `prod`, or `production` - a row observable only in production is a wrong row. 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. A `deferred:` destination is a tracker ref (`#N`, `owner/repo#N`, `ABC-123`), a spec path, or a URL; a prose destination with none of these is a gap at the PR gate.
21
21
 
22
- **Cut question.** `deviates:` and `deferred:` come only from the user's answer to this question; never propose one. Ask it, in the questionary format, when the user's prompt or an answer raises dropping or changing a row, or when code, a cited contract, or the user shows a row is wrong or impossible: `A) in-scope - <reading> B) deviates: <why> C) deferred: <where> D) repair the ticket - /skill:shape-ticket <ref> <row and evidence>`, `Recommendation:` A or D with the reason the row ships in this gauntlet; B and C are never recommended. On D, run `/skill:shape-ticket <ref> <row and evidence>` (repair mode per `shape-ticket/SKILL.md:43`, its own confirm gate), then re-fetch the ticket, replace the gather draft's `## Ticket acceptance criteria (verbatim)` block, and re-extract; a cancel at that gate returns to this question with the row unchanged. Carry the full question and the user's answer of every question that offered a disposition into the council's `Human input` block. The gate lists every `deferred:`, `deviates:`, and `venue:` row on its `Scope cuts:` line (`spec-finalization.md`). 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](../SKILL.md#amending-an-approved-spec) (`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.
22
+ **Cut question.** `deviates:` and `deferred:` come only from the user's answer to this question; never propose one. Ask it, in the questionary format, when the user's prompt or an answer raises dropping or changing a row, or when code, a cited contract, or the user shows a row is wrong or impossible: `A) in-scope - <reading> B) deviates: <why> C) deferred: <where> D) repair the ticket - /skill:shape-ticket <ref> <row and evidence>`, `Recommendation:` A or D with the reason the row ships in this gauntlet; B and C are never recommended. On D, run `/skill:shape-ticket <ref> <row and evidence>` (repair mode per `shape-ticket/SKILL.md:43`, its own confirm gate), then re-fetch the ticket, replace the gather draft's `## Ticket acceptance criteria (verbatim)` block, and re-extract; a cancel at that gate returns to this question with the row unchanged. Carry the full question and the user's answer of every question that offered a disposition into the council's `Human input` block. The gate lists every `deferred:`, `deviates:`, and `venue:` row on its `Scope cuts:` line (`spec-finalization.md`). 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](../SKILL.md#amending-an-approved-spec) (`amendment-surface.md`); the row text still never changes. For ticket rows, preserve the ticket contract: Never author acceptance criteria on the ticket's behalf; that is `/skill:shape-ticket`'s job.
23
+
24
+ ## Row production at spec-writing
25
+
26
+ Branch on the gathered result after reading the draft, before writing the spec:
27
+
28
+ | Gathered result | Section body |
29
+ |---|---|
30
+ | Ticket rows extracted | Keep the `Ticket <ref>, <heading or "checkbox list">, rows verbatim:` header, rows copied character-for-character from the verbatim block, including terminal punctuation, and dispositions |
31
+ | `none - ticket not fetched (<reason>)` | Keep that single line unchanged and the gate's paste-rows affordance |
32
+ | `none - no ticket` | Draft under `Drafted from the design, no ticket rows:` |
33
+ | `none - ticket has no acceptance criteria` | Draft under `Drafted from the design, ticket <ref> has no acceptance criteria:` |
34
+
35
+ Pasted rows are ticket rows and never trigger drafting. Never append `## Spec contract` or Design-derived rows to a ticket-row section.
36
+
37
+ Draft from the approved two-round design plus the original prompt (for an unbound PR, the agreed rework design, not its raw title/body). Write one `- [ ]` row per observable outcome the design commits to, with a two-space-indented disposition, default `in-scope`. State what a user, reviewer, or test observes, not a mechanism. Spec, plan, changelog, and telemetry artifacts are never outcome rows. Keep environment-bound pre-production proof as `venue: <env> - <observation>`; a venue requirement alone never drops an outcome.
38
+
39
+ Apply these integrity classes inline without invoking ticket shaping. Preserve each committed outcome and rewrite its proof:
40
+
41
+ | Class | Recovery before writing |
42
+ |---|---|
43
+ | Wishful | Rewrite to the design's observable with design-sourced baseline, target, and measurement |
44
+ | Tautological | Rewrite to a design-sourced, already-enumerated set or observable |
45
+ | Unspecified-but-binding | Resolve the value from Design and record the resolution there; ask the user for a missing value |
46
+ | External-input | Ask the user for the external yardstick before writing |
47
+ | Post-deployment | Rewrite to a pre-production observation when available, retaining `venue:`; move production-only observations to a tracked, non-blocking `Post-deployment housekeeping` Design clause, never an AC row |
48
+
49
+ Preserve behavioral binary outcomes with setup, action, and expected result; require no invented numeric baseline. Use only design-sourced values; never invent a baseline, target, measurement, or enumerated set. Ask for missing inputs before writing; never silently remove an outcome. Let an outcome leave in-scope only through an explicit scope decision by the user (the cut question or a clarification answer); record `deviates:`/`deferred:` and an `## Out of scope` entry so `Scope cuts:` discloses it. With no valid row remaining, stop for clarification or an explicit scope decision before writing; never emit a `none` fallback.
50
+
51
+ **Drafted cut question.** Use the existing questionary layout with one option per physical line:
52
+
53
+ ```text
54
+ A) in-scope - <reading>
55
+ B) deviates: <why>
56
+ C) deferred: <where>
57
+ Recommendation: A - <why the outcome ships>
58
+ ```
59
+
60
+ Recommend A, never B/C; omit D because no ticket contract or snapshot exists to repair - ticket rows keep the four-option cut question above, including D. Preserve the full question and answer in council `Human input`. Keep drafted rows themselves out of that block. Before approval, rewrite drafted rows only for integrity; delete one only after its Design commitment is cut through the user's scope-decision procedure. After approval, freeze drafted row text; route text/add/remove changes to redraw and disposition-only changes through the existing cut question and amendment grammar.
@@ -69,14 +69,14 @@ subagent({
69
69
  cwd: "<abs worktree path>",
70
70
  task: "Problem statement: <the problem the spec addresses, from its Context section and the user's stated intent>.\n" +
71
71
  "Human input (verbatim; off-limits for over-spec):\n```\n<original prompt>\n<ticket AC snapshot, if any>\n<questionary answers that changed scope>\n```\n" +
72
- "Read the spec at <abs path to doc/specs/...>. The portable citation `reference/documentation-impact.md` in the spec is the pi-gauntlet guideline at <DOCUMENTATION_IMPACT_GUIDELINE>, not a consumer doc; do not flag it as an external reference. The `**Amend-grant:**` header line is flow machinery owned by the brainstorming gate; never cut, shrink, flag, or edit it. Verify the spec's load-bearing claims against the codebase, bounded per your verification-hygiene rules (rg, explicit paths, timeout 30). Critique it on your five axes and emit your template.",
72
+ "Read the spec at <abs path to doc/specs/...>. The portable citation `reference/documentation-impact.md` in the spec is the pi-gauntlet guideline at <DOCUMENTATION_IMPACT_GUIDELINE>, not a consumer doc; do not flag it as an external reference. The `**Amend-grant:**` header line is flow machinery owned by the brainstorming gate; never cut, shrink, flag, or edit it. Drafted rows are spec requirements, not Human input; permit pre-approval rewrites only for integrity. Delete a drafted row only after its Design commitment is cut through the user's scope-decision procedure; quoting the row alone never permits deletion, and never replace the section with `none`. Never draft new rows. Verify the spec's load-bearing claims against the codebase, bounded per your verification-hygiene rules (rg, explicit paths, timeout 30). Critique it on your five axes and emit your template.",
73
73
  output: "<tmpdir>/member-" + i + "-" + slug(model) + ".md",
74
74
  outputMode: "file-only"
75
75
  }))
76
76
  })
77
77
  ```
78
78
 
79
- The `Human input (verbatim; off-limits for over-spec)` block is supplied by the caller (brainstorming passes the original prompt, any ticket AC snapshot, and the questionary answers that changed scope; shape-ticket passes the raw ask). It is the only source members and the chair may quote for the over-spec predicate's leg 2; without it members correctly emit `lean: nothing to cut`.
79
+ The `Human input (verbatim; off-limits for over-spec)` block is supplied by the caller (brainstorming passes the original prompt, any ticket AC snapshot, and the questionary answers that changed scope; shape-ticket passes the raw ask). Keep drafted rows out of this block; preserve original prompt, ticket snapshot, existing PR input, and human scope answers. It is the only source members and the chair may quote for the over-spec predicate's leg 2; without it members correctly emit `lean: nothing to cut`.
80
80
 
81
81
  `control` is a **run-level** field: it must sit beside `tasks`, not inside the `members.map(...)` task objects (the per-task schema has no `control` field and would silently drop it). The three fields together set an effective silence-kill of max(600s, 300+300) = 600s - a genuinely wedged member (e.g. stuck in one unbounded scan) is killed at 10 minutes instead of pi-cohort's 30-minute default. Record all three fields verbatim: the kill is computed as max(inFlightSilenceKillMs, inFlightSilenceCeilingMs + needsAttentionAfterMs), so leaving a field to its default lets a future pi-cohort default change silently stretch it. The 5-minute needsAttentionAfterMs reintroduces idle notices on long healthy xhigh turns - those are notices, not kills, and are acceptable.
82
82
 
@@ -109,7 +109,7 @@ subagent({
109
109
  usableMemberPaths.join("\n") + "\n" +
110
110
  "Coverage: <N> of <M> members reported<; <slug>: <one-line reason> per missing member>.\n" +
111
111
  "The portable citation `reference/documentation-impact.md` in the spec is the pi-gauntlet guideline at <DOCUMENTATION_IMPACT_GUIDELINE>, not a consumer doc; do not flag it as an external reference. The `**Amend-grant:**` header line is flow machinery owned by the brainstorming gate; never cut, shrink, flag, or edit it.\n" +
112
- "Consolidate and adjudicate the member critiques. Codebase access is permitted for contested-claim checks only, bounded per your hygiene rules (rg, explicit paths, timeout 30)."
112
+ "Drafted rows are spec requirements, not Human input; permit pre-approval rewrites only for integrity. Delete a drafted row only after its Design commitment is cut through the user's scope-decision procedure; quoting the row alone never permits deletion, and never replace the section with `none`. Never draft new rows. Consolidate and adjudicate the member critiques. Codebase access is permitted for contested-claim checks only, bounded per your hygiene rules (rg, explicit paths, timeout 30)."
113
113
  })
114
114
  ```
115
115
 
@@ -142,7 +142,7 @@ subagent({
142
142
  "External context fetched during brainstorming: <ticket reference + body/comments, or 'none'>.\n" +
143
143
  "<Coverage: same partial-coverage line; omit at full coverage>\n" +
144
144
  "The portable citation `reference/documentation-impact.md` in the spec is the pi-gauntlet guideline at <DOCUMENTATION_IMPACT_GUIDELINE>, not a consumer doc; do not flag it as an external reference. The `**Amend-grant:**` header line is flow machinery owned by the brainstorming gate; never cut, shrink, flag, or edit it.\n" +
145
- "Decide and apply the chair's clusters to the spec, then return the audit."
145
+ "Drafted rows are spec requirements, not Human input; permit pre-approval rewrites only for integrity. Delete a drafted row only after its Design commitment is cut through the user's scope-decision procedure; quoting the row alone never permits deletion, and never replace the section with `none`. Never draft new rows. Decide and apply the chair's clusters to the spec, then return the audit."
146
146
  })
147
147
  ```
148
148