pi-gauntlet 8.4.8 → 8.4.9

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,15 @@
1
1
  # Changelog
2
2
 
3
+ ## v8.4.9 - 2026-11-11
4
+
5
+ - Gatekeep-pr uses action, final and post menus with the judged recommendation on row 1. Its plain-language report describes the change and scope, explains standing and problems, then recommends a choice; detailed evidence stays behind `show evidence`.
6
+ - Gatekeep-pr preserves the freshness read for replies on approved, open PRs; a moved head skips the reply and retains its body. Set cleanup sharing checks unresolved `<issue>`, `<pr>` and `<merge-sha>` tokens, so an issue-only command remains PR-specific.
7
+ - Gatekeep-pr set mode retires each merged PR after one post-menu pick and collects its unrun steps in the parent's closing message. A shared cleanup item is recommended only on the last merged PR and runs at most once, even when selected earlier.
8
+ - Gatekeep-pr offers merger actions named in the PR or spec as post steps only when merge-base documentation supplies one command. Missing, ambiguous or incomplete commands stay open with their source sentences; PR command text is never executed as authority.
9
+ - Gatekeep-pr asks only once for an invalid post selection. A repeated invalid pick leaves the saved menu waiting without another question or any action.
10
+ - Gatekeep-pr collects terminal follow-ups in one post menu. The recommended combination names its member rows; replies, coverage, cleanup and individual overrides remain separately selectable, and the run ends after the picked steps finish.
11
+ - pi-cohort peer floor raised to 7.7.4.
12
+
3
13
  ## v8.4.8 - 2026-11-11
4
14
 
5
15
  - Brainstorming opens with Today, The change, and What I checked in everyday words, followed by one question. Sources stay in the draft; the opening span is capped at 220 words except corrected or unchecked claims and intact quoted ticket rows.
package/README.md CHANGED
@@ -87,17 +87,23 @@ One finish choice spans all legs. PR, draft PR and squash deliver companions in
87
87
 
88
88
  ## Architecture
89
89
 
90
- A `gatekeep-pr` run after your newest submitted, non-dismissed review uses that review's commit as its baseline when it is an ancestor of the assessed head. The reviewer checks your posted items and only the intervening code delta; the report shows `Prior review: <k> of <n> items addressed`. Contract checks still judge the whole head. See the [review task](skills/gatekeep-pr/reference/assessment.md#step-4-review-task).
90
+ A `gatekeep-pr` run after your newest submitted, non-dismissed review uses that review's commit as its baseline when it is an ancestor of the assessed head. The reviewer checks your posted items and only the intervening code delta; the report explains how many items were addressed in plain prose. Contract checks still judge the whole head. See the [review task](skills/gatekeep-pr/reference/assessment.md#step-4-review-task).
91
91
 
92
- `gatekeep-pr` selects one course per run: `assess` posts open blockers as one review (`request-changes` on someone else's PR, `comment` on your own), posts nothing with zero blockers, and performs no repair or sync; `deliver` repairs blockers, syncs, pushes, watches CI, and re-reviews until readiness, an obstacle, or a cap exit. `deliver with nits` stores `deliver-nits` and includes current and later nits. A ready first report skips the course pick and renders the final menu directly. Delivery rebases your own non-bot branch with `--force-with-lease` unless its history contains merge commits; someone else's, bot-authored, and merge-containing heads merge base instead. Final `merge` and `approve` remain separate picks; approval is offered only on someone else's non-draft PR with zero blockers. See the [course loop](skills/gatekeep-pr/reference/post-selection-loop.md) and [menu templates](skills/gatekeep-pr/reference/menus.md). In pi, `/skill:gatekeep-pr 12 15 18 [--rebase [base]]` gates a set of PR numbers or same-repository URLs, with one fresh `pr-gatekeeper` child and one worktree per PR. The parent shows a summary and unchanged per-PR menus in input order, queues every pick until the last menu, then executes the queued work in parallel. The set must fit pi-cohort's `parallel.maxTasks` (default `8`); it is never chunked. With `--rebase`, the parent asks once per set for eligible other-author or unreadable-author heads, excluding no-op heads and heads with merge commits. Multi-PR mode rejects positional issue references and is pi-only. An explicit no-argument invocation on either harness discovers your open PRs in origin, authored by you or directly awaiting your review (not team requests), excludes drafts and the `APPROVED` and `CHANGES_REQUESTED` states, and sorts by additions plus deletions, then PR number, ascending. One match gates directly on the single-PR path; multiple matches enter pi's batch path, while Claude Code stops with the sorted `discovered, smallest first:` list. Every report shows the refreshed viewer `Role:` under `Delivers`, not in the batch summary row. See the [parent-child contract](skills/gatekeep-pr/reference/batch.md).
92
+ `gatekeep-pr` selects one course per run: `assess` posts open blockers as one review (`request-changes` on someone else's PR, `comment` on your own), posts nothing with zero blockers, and performs no repair or sync; `deliver` repairs blockers, syncs, pushes, watches CI, and re-reviews until readiness, an obstacle, or a cap exit. `deliver with nits` stores `deliver-nits` and includes current and later nits. A ready first report skips the course pick and renders the final menu directly. Delivery rebases your own non-bot branch with `--force-with-lease` unless its history contains merge commits; someone else's, bot-authored, and merge-containing heads merge base instead. Final `merge` and `approve` remain separate picks; approval is offered only on someone else's non-draft PR with zero blockers. See the [course loop](skills/gatekeep-pr/reference/post-selection-loop.md) and [three menus](skills/gatekeep-pr/reference/menus.md). In pi, `/skill:gatekeep-pr 12 15 18 [--rebase [base]]` gates a set of PR numbers or same-repository URLs, with one fresh `pr-gatekeeper` child and one worktree per PR. The parent shows a summary and unchanged per-PR menus in input order and queues every pick until the last menu. It runs terminal consequences in roster order from the primary checkout and dispatches nonterminal child work in parallel. The set must fit pi-cohort's `parallel.maxTasks` (default `8`); it is never chunked. With `--rebase`, the parent asks once per set for eligible other-author or unreadable-author heads, excluding no-op heads and heads with merge commits. Multi-PR mode rejects positional issue references and is pi-only. An explicit no-argument invocation on either harness discovers your open PRs in origin, authored by you or directly awaiting your review (not team requests), excludes drafts and the `APPROVED` and `CHANGES_REQUESTED` states, and sorts by additions plus deletions, then PR number, ascending. One match gates directly on the single-PR path; multiple matches enter pi's batch path, while Claude Code stops with the sorted `discovered, smallest first:` list. Every report explains the refreshed viewer's role and the other requested reviewers in plain prose, not in the batch summary row. See the [parent-child contract](skills/gatekeep-pr/reference/batch.md).
93
+
94
+ Gatekeep uses three menus: action selects a course or continues after an obstacle, final offers merge, approval and remaining work, and post collects terminal follow-ups. Row 1 is the judged recommendation, not a stable action number. Contract proposals recommend preserve contract, and an unchanged obstacle no available action can change recommends stop. Otherwise, your own PR defaults to deliver; an author decision favors assess on someone else's PR, a ready repair or pending-only check favors deliver, and readiness favors merge regardless of author. An unchanged assess result recommends stop. The report has three unlabeled parts: a two-sentence change/scope opening, standing and problems with concrete examples, and a separate recommendation immediately above the choices. Detailed row mappings, counters, raw checks and IDs stay under `show evidence`.
95
+
96
+ After merge, one post menu offers drafted replies, ticket and PR coverage, guarded checkout cleanup, PR-named steps and individual cleanup overrides. Row 1 combines runnable steps except duplicate PR coverage when ticket coverage is included; each step also has its own row. A comma-separated reply selects a set, expands combinations and collapses duplicates. The gate runs the set in step order, keeps nested skills' gates intact and ends without another menu, listing every unpicked, skipped or failed step with its command or payload path. Approved and closed PRs use the same menu with eligible steps; an approved/open reply retains its pre-write freshness read. In a set, each PR retires after its pick and shared overrides run at most once.
93
97
 
94
98
  The course, target/scope baseline, repair and sync usage, and poll deadline live in one OS temporary continuation record, whose path appears in the tracker or checklist and `show evidence`. Gatekeep initializes independent repair-round and sync budgets to `2 x closureReview.maxFixRounds` (default `5`, no-tool fallback `2 x 5`). Only source-changing repair waves spend rounds; conflict-only syncs spend the separate sync budget, and description-only work, watches, and re-reviews spend neither. Obstacle `deliver` extends each cap by `2 x` the resolved value without resetting usage; a timeout continuation instead opens one more watch window without extending caps. Only the gate's own push automatically renews the CI window (`timeout minutes`, default `15`). The verify-phase runtime guard still uses `1 x` the resolved value and can block a gatekeep dispatch earlier.
95
99
 
100
+ PR-body or head-spec instructions assigning the merger an after-merge action become post steps. Their commands come only from the merge-base overrides file, `AGENTS.md`, or documents it links directly: exactly one distinct documented command makes the step runnable and part of row 1. PR-supplied command text never supplies execution authority. Missing or ambiguous commands and unresolved tokens leave the action open in the menu and closing message with its source sentence. See [PR-named steps](skills/gatekeep-pr/reference/findings.md#pr-named-steps).
101
+
96
102
  Non-final `stop` removes an eligible tracked-clean, non-primary worktree, created or reused, with no unpushed commits and a matching configured home; otherwise it keeps the tree and reports why. It never deletes the branch, pulls base, or runs cleanup overrides. See the [stop lifecycle](skills/gatekeep-pr/reference/cleanup.md#non-final-stop). Missing or invalid state stops course work without resetting budgets. Terminal exit deletes the record; OS cleanup can remove it earlier, and a new session never discovers or resumes authority automatically. This is a skill protocol, not hard runtime enforcement.
97
103
 
98
104
  pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
99
105
 
100
- - **21 skills** - the workflow logic. Sixteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates one tracker issue or repairs a comma/whitespace list of refs against a Context/Problem/Idea/Acceptance-Criteria template, with a grounded repo audit, an AC integrity check, a cheap council roast, and sequential per-ticket exact-diff write confirmations; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes), `gatekeep-pr` (model-invocable on an explicit ask that names the PR and the verb; the gates still need your selection - is consent-gated pre-merge verification of a PR against the scope contract at its head - the approved spec's acceptance-criteria dispositions and Design when the PR carries one, else the PR's stated intent; the ticket is cross-checked, never judged here (`check-delivery` owns it) - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; a pending commit status that GitHub does not report as blocking the gating actor (`mergeStateStatus` not `BLOCKED`) is not waited for - external-CI commit statuses included - while a running Actions check and an unknown merge state still withhold; a viewer GitHub reports as a ruleset bypass actor merges a `BLOCKED` PR on the ordinary `merge` row with CI evidence still binding and all other merge preconditions unchanged; false or unreadable bypass eligibility keeps `BLOCKED` withheld, and live non-admin bypass behavior remains unverified; the project's verification command runs only as fallback), a rubric-based review, a compact bottom-up report (what the PR delivers, including rows deferred or deviating per spec, PR comments, nits, blockers, then a `mergeable` / `fixable` verdict) and course and terminal menus whose rows derive from the actor's permissions on the PR; nothing mutates (repairs, pushes, reviews, merges, tracker comments) until you pick a course or terminal row, except the opt-in `--rebase [base]` sync that rebases, reviews, and lease-pushes the head before verification, or holds the rebased head locally when a conflict stop's scoped tests fail, so a selected delivery course resolves it before the lease push; after your own merge two opt-in rows post the `AC coverage` block to the ticket or the PR; own-merge, approved, and closed-PR menus offer a recommended `cleanup` row that tears down the gate's worktree and branch and runs the overrides file's `## cleanup` steps - run it with `/skill:gatekeep-pr [<pr>] [--rebase [base]]` (no argument: your open PRs)), `check-delivery` (model-invocable on an explicit ask that names the ticket and the verb; the gates still need your selection - 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>` or, in pi, `/skill:check-delivery #12 #15` for fresh parallel verification and one gate and write per ticket in turn), `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `loop-implementation` (the plan-free implement driver that iterates a fresh `loop-implementer` over the spec's acceptance-criteria ledger when approval picks the loop engine), `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `forge-skill`, `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). Five more require explicit entry (`disable-model-invocation: true`): `brainstorming` starts the gated workflow on explicit consent - use `/skill:brainstorming` for reliable discovery, or opt in through reachable explicit prose or a human-selected handoff; after spec approval, downstream planning and implementation still chain automatically. `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, a council assessment when available, 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/`), a bare worktree that already holds a spec, or a spec tracked on main under a configured spec dir (a spec seed: it creates or reuses the worktree through `using-git-worktrees` and pins the spec), restores phase/plan tracker state through the legal arming sequence (`start brainstorm`, `skip` with `resume:` reasons, `plan_check` before implement-or-later), and never infers approval from artifacts - run it with `/skill:gauntlet-resume [<brief-file> | <spec>.md | <worktree-name-or-path>]`.
106
+ - **21 skills** - the workflow logic. Sixteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates one tracker issue or repairs a comma/whitespace list of refs against a Context/Problem/Idea/Acceptance-Criteria template, with a grounded repo audit, an AC integrity check, a cheap council roast, and sequential per-ticket exact-diff write confirmations; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes), `gatekeep-pr` (model-invocable on an explicit ask that names the PR and the verb; the gates still need your selection - is consent-gated pre-merge verification of a PR against the scope contract at its head - the approved spec's acceptance-criteria dispositions and Design when the PR carries one, else the PR's stated intent; the ticket is cross-checked, never judged here (`check-delivery` owns it) - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; a pending commit status that GitHub does not report as blocking the gating actor (`mergeStateStatus` not `BLOCKED`) is not waited for - external-CI commit statuses included - while a running Actions check and an unknown merge state still withhold; a viewer GitHub reports as a ruleset bypass actor merges a `BLOCKED` PR on the ordinary `merge` row with CI evidence still binding and all other merge preconditions unchanged; false or unreadable bypass eligibility keeps `BLOCKED` withheld, and live non-admin bypass behavior remains unverified; the project's verification command runs only as fallback), a rubric-based review, a three-part plain-language report (change and scope, standing and problems, then recommendation) and action, final and post menus whose rows derive from the actor's permissions on the PR; nothing mutates (repairs, pushes, reviews, merges, tracker comments) until you pick a course or terminal row, except the opt-in `--rebase [base]` sync that rebases, reviews, and lease-pushes the head before verification, or holds the rebased head locally when a conflict stop's scoped tests fail, so a selected delivery course resolves it before the lease push; after your own merge one post menu offers drafted replies, ticket and PR copies of `AC coverage`, guarded checkout cleanup and separate `## cleanup` items; row 1 combines the runnable steps except duplicate PR coverage when ticket coverage is included, each step keeps its own row, and the run ends after the selected set finishes; approved and closed-PR states use the same post menu with their eligible steps - run it with `/skill:gatekeep-pr [<pr>] [--rebase [base]]` (no argument: your open PRs)), `check-delivery` (model-invocable on an explicit ask that names the ticket and the verb; the gates still need your selection - 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>` or, in pi, `/skill:check-delivery #12 #15` for fresh parallel verification and one gate and write per ticket in turn), `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `loop-implementation` (the plan-free implement driver that iterates a fresh `loop-implementer` over the spec's acceptance-criteria ledger when approval picks the loop engine), `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `forge-skill`, `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). Five more require explicit entry (`disable-model-invocation: true`): `brainstorming` starts the gated workflow on explicit consent - use `/skill:brainstorming` for reliable discovery, or opt in through reachable explicit prose or a human-selected handoff; after spec approval, downstream planning and implementation still chain automatically. `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, a council assessment when available, 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/`), a bare worktree that already holds a spec, or a spec tracked on main under a configured spec dir (a spec seed: it creates or reuses the worktree through `using-git-worktrees` and pins the spec), restores phase/plan tracker state through the legal arming sequence (`start brainstorm`, `skip` with `resume:` reasons, `plan_check` before implement-or-later), and never infers approval from artifacts - run it with `/skill:gauntlet-resume [<brief-file> | <spec>.md | <worktree-name-or-path>]`.
101
107
  - **11 subagent personas** - the specialized child agents the skills dispatch via pi-cohort: `implementer`, `loop-implementer`, `wave-reviewer`, `conformance-reviewer`, `spec-summarizer`, `plan-writer`, `spec-council-member`, `spec-council-synthesizer`, `spec-council-applier`, `pr-gatekeeper`, `delivery-checker`. See [doc/personas.md](./doc/personas.md) for what each one does and why its permissions are scoped the way they are.
102
108
  - **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 (expected when a loop gate set does not match its patterns; the scoped `Verification:` line answers it, not a full local run); a phase-tracker flow guard reminds on implement-phase commits missing spec/code review. Both engines use the tracker: waves manages plan tasks, while loop calls `plan_tracker refresh` to project ledger rows and preserve conformance tasks. Loop implement completes when every row is closed, then verify step 1 runs the ledger's gate set in the owning checkouts. 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, and that every test command carries a passing base-commit result; a pass stamps the plan and spec content hashes for implementation and returns a bounded task manifest; see the [manifest contract and size limit](./doc/configuration.md#phase-tracker). `telemetry` publishes YAML records on the `refs/telemetry/records` ref, outside the product diff: one sealed brainstorming run plus one session leg per settled `shape-ticket`, `gatekeep-pr` or `check-delivery` invocation. In-progress runs live in Git common-dir metadata; `gauntlet-telemetry-seal` publishes before landing without changing checkout HEAD or index. Publication failure warns without blocking ship; plain jj keeps local metadata and reports no Git remote. A fetched shipped record blocks a brainstorm `write` into that spec. See [the record layout, settings and migration guide](./doc/configuration.md#telemetry). See [doc/configuration.md](./doc/configuration.md) for the settings each one reads. `phase_tracker`, `plan_check`, and `plan_tracker` are model-only (not callable from codemode scripts) because their state is rebuilt from transcript tool results, which nested calls do not persist.
103
109
 
@@ -142,7 +148,7 @@ Run by a human against pi-cohort >= 7.1.0, before a pi-gauntlet release claims t
142
148
  ## Requirements
143
149
 
144
150
  - [pi-coding-agent](https://github.com/earendil-works/pi) >= 1.5.0 - supports model-only tracker exposure and sequential tracker execution, so updates persist as transcript tool results rather than nested calls.
145
- - [pi-cohort](https://github.com/jjuraszek/pi-cohort) >= 7.7.3 - required peer package, including binary-safe worktree patches; it also lets a persona with `subagent` in `tools:` start with inherited extensions ([pi-cohort #26](https://github.com/jjuraszek/pi-cohort/issues/26)), which multi-PR `gatekeep-pr` needs. Skills that dispatch agents (`requesting-code-review`, `subagent-driven-development`, `dispatching-parallel-agents`, `writing-plans`, `forge-skill`, `shape-ticket`, `roasting-the-spec`) call `subagent({})`, which pi-cohort provides. pi-gauntlet does not vendor the dispatch tool; without pi-cohort those skills have nothing to call. Gauntlet execution dispatches explicitly use `async: false`; do not enable pi-cohort's incompatible `forceTopLevelAsync` setting. See pi-cohort's [dispatch configuration](https://github.com/jjuraszek/pi-cohort/blob/main/doc/configuration.md) for that setting's owner and semantics. A wave of N >= 1 tasks dispatches its implementers and first spec reviews as one chain call. `subagent-driven-development` stops before dispatch on unsupported installs; there is no older-runtime fallback.
151
+ - [pi-cohort](https://github.com/jjuraszek/pi-cohort) >= 7.7.4 - required peer package, including binary-safe worktree patches; it also lets a persona with `subagent` in `tools:` start with inherited extensions ([pi-cohort #26](https://github.com/jjuraszek/pi-cohort/issues/26)), which multi-PR `gatekeep-pr` needs. Skills that dispatch agents (`requesting-code-review`, `subagent-driven-development`, `dispatching-parallel-agents`, `writing-plans`, `forge-skill`, `shape-ticket`, `roasting-the-spec`) call `subagent({})`, which pi-cohort provides. pi-gauntlet does not vendor the dispatch tool; without pi-cohort those skills have nothing to call. Gauntlet execution dispatches explicitly use `async: false`; do not enable pi-cohort's incompatible `forceTopLevelAsync` setting. See pi-cohort's [dispatch configuration](https://github.com/jjuraszek/pi-cohort/blob/main/doc/configuration.md) for that setting's owner and semantics. A wave of N >= 1 tasks dispatches its implementers and first spec reviews as one chain call. `subagent-driven-development` stops before dispatch on unsupported installs; there is no older-runtime fallback.
146
152
 
147
153
  Both packages must be listed in your `.pi/settings.json#packages` array (pi adds them automatically when you `pi install`). pi-gauntlet and pi-cohort are versioned independently but release together whenever dispatch semantics change - pin compatible versions of both. At each pi-gauntlet release, set the pi-cohort peer minimum and README floor together to the newest released pi-cohort version; `/skill:release` checks the registry before proceeding.
148
154
 
@@ -345,7 +351,7 @@ The gauntlet overrides file is the one place a repo tunes gauntlet's Markdown su
345
351
  | `## using-git-worktrees` `- home: <path pattern>` | using-git-worktrees, finishing-a-development-branch, gatekeep-pr | `<primary>/.worktrees/<name>` | overrides | where worktrees live; `<name>` is the branch (`/` -> `-`) or `pr-<N>`; the ownership test at cleanup |
346
352
  | `## using-git-worktrees` `- create: <command>` | using-git-worktrees, gatekeep-pr | `git worktree add` at `home:` | overrides | creation command run from the primary; `<name>`, `<branch>` substituted, other `<token>`s resolved from context or asked once |
347
353
  | `## using-git-worktrees` `- destroy: <command>` | finishing-a-development-branch, gatekeep-pr | `git worktree remove` + `prune` when the path matches `home:` | overrides | removal command run from the primary; a failure keeps the branch |
348
- | `## cleanup` items `- <label>: <command or /skill:...>` | gatekeep-pr | git teardown and base sync only | extends | ordered post-gate steps with `<issue>`, `<pr>`, `<merge-sha>`; inherits `## PR gate` `timeout minutes:`; missing placeholders or unlanded-change steps are skipped with a reason; `/skill:` items keep their own gates |
354
+ | `## cleanup` items `- <label>: <command or /skill:...>` | gatekeep-pr | git teardown and base sync only | extends | separate post-menu steps with `<issue>`, `<pr>`, `<merge-sha>` selected individually or in the recommended combination; inherits `## PR gate` `timeout minutes:`; missing placeholders or unlanded-change steps are skipped with a reason; `/skill:` items keep their own gates |
349
355
  | `## PR gate` keys (`verification command`, `timeout minutes`, `requires credentials`, `local verification`, `ci checks`, `issue fetch`, `merge policy`) | gatekeep-pr | per-key defaults in the block below | overrides | the gate's verification, evidence, and merge configuration |
350
356
  | `## comms style` | gatekeep-pr | shipped wording rules | extends | tone and format of reports, menus, and external payloads |
351
357
  | `## verification-before-completion` | verification-before-completion; gatekeep-pr (verification command only); chase-bug (hotfix verification) | repo test entrypoint discovery | overrides | the canonical verification target |
@@ -585,7 +591,7 @@ customization lives in three places, never in the wrapper itself:
585
591
  - merge policy: squash | merge-commit | rebase # optional; default squash; chooses gh pr merge flag for final merge only, never sync strategy or approval
586
592
  ```
587
593
 
588
- - **The gauntlet overrides file, `## cleanup` section** - the ordered post-gate steps the `cleanup` menu row runs (contract under Project-specific overrides above).
594
+ - **The gauntlet overrides file, `## cleanup` section** - the ordered follow-up steps selected through the post menu (contract under Project-specific overrides above).
589
595
 
590
596
  An existing `## verification-before-completion` overrides section is an accepted
591
597
  equivalent source for the verification command only; all other PR-gate keys
@@ -1,6 +1,8 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { readFileSync, readdirSync } from "node:fs";
3
3
  import test from "node:test";
4
+ import { fileURLToPath } from "node:url";
5
+ import { lintGateContract } from "../scripts/gate-contract-lint.mjs";
4
6
  import { settlementItems } from "./lib/telemetry-leg.ts";
5
7
  import { MODELS } from "../eval/lib/models.mjs";
6
8
 
@@ -41,7 +43,7 @@ test("skill owners keep terminal rows after writes and cleanup", () => {
41
43
  const gate = read("skills/gatekeep-pr/reference/post-selection-loop.md");
42
44
  assert.ok(gate.includes("#<N>@<head sha>: <outcome>"));
43
45
  assert.match(gate, /full assessed `headRefOid`/);
44
- assert.match(gate, /cleanup pick is answered/);
46
+ assert.match(gate, /Emit the terminal message only after the selected post set finishes or stop declines it; a report or menu is not settlement/);
45
47
  assert.match(read("skills/gatekeep-pr/reference/batch.md"), /gauntlet: retired #<N> - <reason>/);
46
48
  assert.match(read("skills/gatekeep-pr/reference/cleanup.md"), /### Settlement rows/);
47
49
  const ci = read("scripts/ci.mjs");
@@ -52,6 +54,32 @@ test("skill owners keep terminal rows after writes and cleanup", () => {
52
54
  }
53
55
  });
54
56
 
57
+ test("gatekeep published gate markers and terminal settlements stay compatible", () => {
58
+ const contract = read("doc/gate-contract.md");
59
+ for (const id of ["initial", "obstacle", "contract-exception", "final", "assess-terminal", "own-merge", "approved", "closed-pr", "merge-queued"]) {
60
+ assert.ok(contract.includes(`| gatekeep-pr/${id} | gate | skills/gatekeep-pr/reference/menus.md |`), id);
61
+ }
62
+ assert.deepEqual(lintGateContract(fileURLToPath(new URL("../", import.meta.url))), []);
63
+ const terminals = contract.split("\n")
64
+ .filter((line) => line.startsWith("| gatekeep-pr |"))
65
+ .map((line) => line.split("|")[4].trim());
66
+ assert.deepEqual([...new Set(terminals)].sort(), [
67
+ "gauntlet: done approved", "gauntlet: done merged", "gauntlet: done closed-pr",
68
+ "gauntlet: done final", "gauntlet: done merge-queued", "gauntlet: stuck",
69
+ "gauntlet: done retired", "gauntlet: stuck retired",
70
+ ].sort());
71
+ for (const outcome of ["approved", "merged", "closed-pr", "final", "merge-queued", "stuck - CI failed"]) {
72
+ const marker = outcome.startsWith("stuck -") ? "gauntlet: stuck CI failed" : `gauntlet: done ${outcome}`;
73
+ for (const ticket of [undefined, "#12"]) {
74
+ const row = `#31@${head}: ${outcome}${ticket ? ` (${ticket})` : ""}`;
75
+ assert.deepEqual(settlementItems("gatekeep-pr", `${marker}\n${row}\nCleanup was not picked.`), [
76
+ { kind: "pr", key: `#31@${head}`, outcome, ...(ticket ? { ticket } : {}) },
77
+ ]);
78
+ assert.equal(settlementItems("gatekeep-pr", `gauntlet: gate=gatekeep-pr/final recommended=1\n${row}`), undefined);
79
+ }
80
+ }
81
+ });
82
+
55
83
  test("configuration names the settlement grammar and per-skill tokens", () => {
56
84
  const docs = read("doc/configuration.md");
57
85
  assert.ok(docs.includes("<ref>: <outcome>[ (<ticket ref>)]"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "8.4.8",
3
+ "version": "8.4.9",
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",
@@ -62,7 +62,7 @@
62
62
  "test": "node scripts/ci.mjs"
63
63
  },
64
64
  "peerDependencies": {
65
- "pi-cohort": ">=7.7.3"
65
+ "pi-cohort": ">=7.7.4"
66
66
  },
67
67
  "dependencies": {
68
68
  "yaml": "^2.9.0"
@@ -6,7 +6,7 @@ argument-hint: "[no argument: my open PRs] | <pr> [issue-ref] [--rebase [base]]
6
6
 
7
7
  # gatekeep-pr
8
8
 
9
- Verify, don't trust: a PR description is a claim, and over-claimed coverage, hallucinated references, and "tests pass" that never ran are the normal case on generated code. Judge the mechanism only - whether code, tests, and docs at the assessed head make each promised behavior possible - and leave what can be seen only after merge (a staging run, production data, an external system) to `/skill:check-delivery`. Persist one course through `reference/post-selection-loop.md`'s run record; keep final merge/approval and posts separately selected. Before the initial pick, permit only provisioning and the explicit `--rebase` sync; steps 1-5 read, verify and draft. Execute later writes under a set course, terminal pick or the sync's `--rebase` authority. A menu pick authorizes every command that pick needs: run them yourself, never print a command for the human to paste. Running the verification command executes PR code with your ambient credentials and no sandbox - gate only PRs you are willing to execute.
9
+ Judge whether code, tests and docs at the assessed head make each promised behavior possible; leave observations requiring the merged change to `/skill:check-delivery`. Persist one course through `reference/post-selection-loop.md`'s run record; keep final merge/approval and posts separately selected. Before the initial pick, permit only provisioning and the explicit `--rebase` sync; steps 1-5 read, verify and draft. Execute later writes under a set course, terminal pick or the sync's `--rebase` authority. Running the verification command executes PR code with your ambient credentials and no sandbox - gate only PRs you are willing to execute.
10
10
 
11
11
  ## Arguments
12
12
 
@@ -28,8 +28,8 @@ Verify (step 3) and Review (step 4) each run as a fresh helper with `cwd` the PR
28
28
  | 3 Verify | `verification-brief.md` Section B | evidence record (CI-first) and one disposition per material claim | `verify` |
29
29
  | 4 Review | `verification-brief.md` Section C | reviewer findings and the internal comment ledger | `review` |
30
30
  | 5 Integrate + report | `reference/post-selection-loop.md` `### Pre-menu refresh`, then `reference/findings.md`, then `reference/report.md` | AC outcomes, blockers, nits, drafted payloads, the rendered report | `report` |
31
- | 6 Menu | `reference/decision-menu.md`, then `reference/menus.md` | initial for a repairable or pending-only not-ready first report, obstacle for undispositionable BLOCKED even with course unset, final for first-report readiness or a readiness exit, assess terminal after assess, obstacle at obstacle/cap, or the matching terminal/contract-exception template; exactly one `[recommended]` | `menu` |
32
- | 7 Loop | `reference/post-selection-loop.md` (delivery continues in `reference/fix-wave.md`) | the fixed delivery body until readiness, obstacle or cap; terminal picks and contract decisions through `reference/menus.md`; re-entry until stop | (re-opens the re-entered stage) |
31
+ | 6 Menu | `reference/menus.md` | state-selected action, final or post archetype; row 1 is the sole recommendation | `menu` |
32
+ | 7 Loop | `reference/post-selection-loop.md` (delivery continues in `reference/fix-wave.md`) | the fixed delivery body until readiness, obstacle or cap; terminal picks and contract decisions through `reference/menus.md`; re-entry until stop or completion of the terminal post set | (re-opens the re-entered stage) |
33
33
 
34
34
  Re-entry: a fix wave's own push re-enters step 4 through the own-push sequence (`reference/fix-wave.md` `## Evidence after push`, then `reference/post-selection-loop.md` `### Re-render`); any other head move re-enters step 3; an unchanged head re-enters step 5 through `reference/post-selection-loop.md` `### Pre-menu refresh`. A loop re-entry never re-runs step 2b; the sync runs once per invocation.
35
35
 
@@ -47,38 +47,49 @@ For pi file-finding row dispatch, use `subagent({ agent: "loop-implementer", con
47
47
 
48
48
  These bind every rendered report, menu, and external payload (review bodies, replies, commit subjects, tracker comments). A `## comms style` section in the overrides file extends them.
49
49
 
50
- 1. One item is one or two whole sentences: what is wrong, then why it matters. No fragments, no field separators.
51
- 2. Name the behavior, not the artifact: "retries forever" beats "attempts counter not incremented".
52
- 3. Locators trail in parentheses (`file:line`, check name, doc path), never inside the sentence.
53
- 4. No category tags, severity words, or IDs in prose - the section heading is the severity, the list number is the ID.
54
- 5. Report only non-conformance; passing checks, per-row AC outcomes, and matched claims print only under `show evidence`; `Delivers` names the covered and settled rows.
55
- 6. Omit empty sections.
56
- 7. `Delivers` is always present and names which spec rows this PR covers, which are `deferred per spec`, `deviates per spec`, or `elsewhere per spec`, and which observable half is checked after merge.
57
- 8. The verdict is one line in the fixed form.
58
- 9. Menu rows start with a verb selected numerically, carry one clause of consequence, and exactly one row is `[recommended]`; typed evidence/reply/check commands live in the hint line only.
59
- 10. ASCII only, American English, no hedges on checked facts, no intensifiers.
50
+ - Write for a reader with neither the code nor this run's notes open. Ground each claim in gathered facts; name the behavior and give one concrete example per problem. Explain a needed term in everyday words before using it.
51
+ - Write one or two whole sentences per finding: what is wrong, then why it matters. In a posted review body, trail each finding with its file and line in parentheses. Name files, lines and checks only where the reader must open or type them; keep exact supplied failing-test locators with their blocker.
52
+ - Omit empty sections. Use ASCII, American English, no hedges on checked facts and no intensifiers.
53
+ - Keep explanatory prose free of field names, run ids, commit ids and repair or sync counters outside `show evidence`; translate internal vocabulary and leave records unchanged. Write thread replies as plain sentences.
54
+ - Keep output unfenced. Preserve these exceptions verbatim: first-line markers, settlement rows, per-step result lines, typed commands, `[recommended]`, set queue/retirement lines, consent previews, the `AC coverage` heading and checkbox rows, and exact commands with substituted values in rows or closing messages. Keep repository-owned cleanup item text unchanged.
55
+
56
+ | Internal term | Say instead |
57
+ |---|---|
58
+ | binding pending check | a required check is still running |
59
+ | merge_state_status BLOCKED | GitHub won't let this merge yet |
60
+ | assessed head | the commit being reviewed |
61
+ | durable run record | saved progress |
62
+ | PR-named action | the step the PR asks for |
63
+ | coverage post | a comment saying which requirements the PR covers |
64
+ | withhold | the reason this cannot merge yet |
65
+ | terminal pick | your choice |
66
+ | post set | the steps you picked |
67
+ | disposition | how you classified the check |
68
+ | merge blocked, no bypass | GitHub reports the merge as blocked for you |
69
+ | bypass eligible | you can use GitHub's admin override |
70
+ | conflicting / behind | the branch conflicts with, or is behind, the base branch |
71
+ | evidence source ci / local | the checks ran in CI / on this machine |
72
+ | cap reached | the repair attempts allowed for this run are used up |
73
+ | nit | a smaller point that does not block merging |
74
+ | contradicted claim | the description says one thing and the code does another |
75
+ | observable half | the part that can only be seen after merge |
76
+ | deferred / deviates / elsewhere | the spec defers it, deliberately differs, or assigns it to another repo |
77
+ | pending reviewer placeholder | an automated review is still running |
78
+
79
+ ### Output done-check
80
+
81
+ Before sending any report, menu or external payload, reread it for internal jargon, raw field/value pairs, labeled-field scaffolding and instructions for the human to run a command the skill can run. Rewrite those lines in plain language, preserve the facts and concrete step commands needed for a choice, and execute selected commands yourself. Treat commands for steps not run as information, never a request to paste them.
60
82
 
61
83
  ## Red flags - STOP
62
84
 
63
- - A mutation without a set course, a terminal pick, or the sync's `--rebase` authority - owner: `reference/post-selection-loop.md` `### Continuation record`.
64
- - A code or doc edit sitting in the worktree when a menu renders - except helper residue that `reference/fix-wave.md` `## Wave` names in the re-rendered menu - owner: `reference/findings.md` `## Drafted payloads`.
65
- - Blocking on an AC's observation half, or on a PR-body claim the gate cannot check - owner: `reference/findings.md` `## AC outcomes`.
66
- - Judging a ticket row the spec does not carry, or treating a spec `deferred: <ref>` row as a gap - owner: `reference/findings.md` `## AC outcomes`.
67
- - Reading the rubric, the verification command, or any ladder source from the PR's head instead of the base branch's merge-base - owner: `reference/assessment.md` `## Configuration`.
68
- - Raw command output, drafted payloads except the exact description consent preview, or internal IDs in the rendered report - owner: `reference/report.md`.
69
- - A menu rendered under deliver before an exit condition, other than the contract-exception template; a menu not rendered from `reference/menus.md`, two recommendations, stop not last or no show evidence hint - owner: `reference/menus.md`.
70
- - `cleanup` rendered on a non-terminal template, or cleanup steps 2-4 run on non-final stop - owner: `reference/cleanup.md` `## Non-final stop`.
71
- - A CI watch outside D3 step 4 or before the first report, or a second push inside one iteration - owner: `reference/post-selection-loop.md` `### Next action`.
72
- - The orchestrator resolving a merge conflict itself, or editing or committing a tracked file during a fix wave - owner: `reference/fix-wave.md` `## Sync` and `## Wave`.
73
- - A helper's duty run in the orchestrator's own context - owner: `## Harness notes`.
74
- - Approving your own PR - owner: `reference/decision-menu.md` `## Availability`.
75
85
  - Merging around an undispositioned failing check or a binding pending check, or a merge-state withhold under `reference/post-selection-loop.md` `### Merge preconditions` - owner: `reference/findings.md` `## Dispositions`.
86
+ - A menu rendered under deliver before an exit condition, other than the contract-exception template; a menu not rendered from `reference/menus.md`, two recommendations, a recommendation not on row 1 or no show evidence hint - owner: `reference/menus.md`.
87
+ - `cleanup` rendered on a non-terminal template, or cleanup steps 2-4 run on non-final stop - owner: `reference/cleanup.md` `## Non-final stop`.
88
+ - Approving your own PR - owner: `reference/menus.md` `## final`.
76
89
  - A menu rendered without the pre-menu refresh - owner: `reference/post-selection-loop.md` `### Pre-menu refresh`.
77
- - Reading `mergeStateStatus` from anything but a `gh pr view` invocation, attributing a `BLOCKED` to a named rule, or treating a non-`BLOCKED` value as a merge verdict - owner: `verification-brief.md` Section A.
78
- - A claim verdict recorded behind a pending tracker stage - owner: `## Progress tracking`.
79
90
 
80
91
  ## Project overrides
81
92
 
82
- If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it once per session - a skill that already has the file's content in context from an earlier skill's read skips the read; a restored session has nothing in context and reads it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## PR gate` keys are read in step 2 (`reference/assessment.md`); `## comms style` extends the wording rules. `## cleanup` steps run on the `cleanup` pick (`reference/cleanup.md`).
93
+ If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it once per session - a skill that already has the file's content in context from an earlier skill's read skips the read; a restored session has nothing in context and reads it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## PR gate` keys are read in step 2 (`reference/assessment.md`); `## comms style` extends the wording rules. `## cleanup` items are separate steps selected through the post menu (`reference/menus.md` `## post`); execute them through `reference/cleanup.md`.
83
94
 
84
95
  The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -28,7 +28,7 @@ With rebase requested, read the viewer via `gh api user --jq .login`. After fetc
28
28
 
29
29
  Create the OS-temp roster with `mktemp "${TMPDIR:-/tmp}/gatekeep-roster.XXXXXX"`, never in a worktree. Store per PR number, worktree, record path, report path, status (`pending`, `report`, `conflicting`, `failed`, `stopped`, `retired`), reason, and queued pick. Pre-mint record/report paths outside worktrees.
30
30
 
31
- Initialize each existing-format continuation record once: `consent.target` (lowercase base owner/repo, PR number, gathered baseRefName), PR identity, worktree, `course` null, `repair.rounds_used` and `repair.syncs_used` zero, `approved_head` null, `cleanup_done` false. Use the continuation-record schema; initialize `repair.rounds_cap` and `repair.syncs_cap` to `2 x` the resolved `closureReview.maxFixRounds` under D4 (`fix-wave.md` `## Wave`). Only the first course pick may resolve its initial D4 allowance; re-dispatch never reinitializes usage or caps. The parent owns only initialization and direct queued picks; the child owns all assessment and execution fields, findings, digest, evidence, repair state, approved head, payloads, and comment ledger. Carry confirmations and answers in task text only; never overwrite course, counters, caps, deadline, ledger, or helper paths on refresh or re-dispatch. Carry `repair.wave.spec` and `repair.wave.ledger` once created, with their row history and counters, through every private handoff; wave settlement retains the pair until terminal teardown. Validate supplied records using the continuation-record identity and finding-artifact rules: a missing locator or missing, unreadable or malformed artifact exits `stuck - run record unreadable`, never resets them.
31
+ Initialize each existing-format continuation record once: `consent.target` (lowercase base owner/repo, PR number, gathered baseRefName), PR identity, worktree, `course` null, `repair.rounds_used` and `repair.syncs_used` zero, `approved_head` null. Use the continuation-record schema; initialize `repair.rounds_cap` and `repair.syncs_cap` to `2 x` the resolved `closureReview.maxFixRounds` under D4 (`fix-wave.md` `## Wave`). Only the first course pick may resolve its initial D4 allowance; re-dispatch never reinitializes usage or caps. The parent owns only initialization and direct queued picks; the child owns all assessment and execution fields, findings, digest, evidence, repair state, approved head, payloads, and comment ledger. Carry confirmations and answers in task text only; never overwrite course, counters, caps, deadline, ledger, or helper paths on refresh or re-dispatch. Carry `repair.wave.spec` and `repair.wave.ledger` once created, with their row history and counters, through every private handoff; wave settlement retains the pair until terminal teardown. Validate supplied records using the continuation-record identity and finding-artifact rules: a missing locator or missing, unreadable or malformed artifact exits `stuck - run record unreadable`, never resets them.
32
32
 
33
33
  ## Foreground dispatch
34
34
 
@@ -76,24 +76,24 @@ Re-assess from steps 1-5 with the same record; substitute the answer at that ask
76
76
 
77
77
  ## Summary and menu round
78
78
 
79
- The parent alone renders menus, gathers answers, and runs cleanup/stop consequences. Render the summary once, after the children's closing lines and before the first menu, without a standalone report block before it. Never rewrite, correct, or reconcile a child's report: preserve spelling, counts, verdict wording, missing lines, and off-contract lines, including under show evidence; add no corrections block or inserted report lines. Render summary rows in roster order:
79
+ The parent alone renders menus, gathers answers, and runs post/stop consequences. Render the summary once, after the children's closing lines and before the first menu, without a standalone report block before it. Preserve each supplied child report unchanged, including under show evidence. For each PR in roster order, print `#<N>` and copy the child's standing sentence unchanged on one line; add no verdict, evidence or blocker fields. For a child without a report, state its recorded conflict, failure or ask as a sentence. Describe a pending required check in that PR's deliver row; leave the supplied standing sentence unchanged. Follow with `Shared files:` and every changed path shared by two or more PRs, `<path> - #<N>, #<M>`. Include `#<N> - files unknown` for missing gathered files; print `none` when no path overlaps. Never schedule merges or choose landing order.
80
80
 
81
- `#<N> <verdict line> | evidence: <ci | local | pending | unknown> | blockers: <count | unknown>`
81
+ Print each supplied child report file verbatim in roster order, each under its own `#<N>` heading and directly above that PR's queued menu from `menus.md`; add no synthetic `Verdict:` restatement at the menu turn. Render only the first PR's report and menu in the summary turn; collect each PR's pick before rendering the next PR's report and menu in a new turn. Never put two PRs' menus in one message or ask for all picks in one combined reply. Render each child's template from `menus.md`: reports with their template rows, conflicts through `menus.md` `## batch summary`'s recovered CONFLICTING template, failures with retry/evidence/stop, STOPPED with the recorded ask and stop. Apply `menus.md`'s row ordering to every child menu. For retry use exactly `retry - re-dispatch this PR's assessment with the same record`, recommended only after clean recovery and no rebase. Resolve the actual gitdir with git (a worktree .git can be a file); require empty `git -C <worktree> status --porcelain` and neither rebase-merge nor rebase-apply there. Otherwise omit retry and explain that the worktree is dirty or mid-rebase, naming the observed porcelain line or rebase directory.
82
82
 
83
- Use the child's supplied Verdict text unchanged, `conflicting - <sync record>`, `failed - <reason>`, or `stopped - <ask>`. Express a pending binding check only in that PR's queued menu: describe watching the check in its deliver row and print `Not offered: merge (<check> pending)`; leave the supplied verdict unchanged. Evidence is the record's resolved source; use unknown before Verify. Count open P# findings; use unknown without review. Follow with `Shared files:` and every changed path shared by two or more PRs, `<path> - #<N>, #<M>`. Include `#<N> - files unknown` for missing gathered files; print `none` when no path overlaps. Never schedule merges or choose landing order.
83
+ Render one post menu per merged PR, each in its own message, using `menus.md` `## post`. Keep the batch summary in a separate message before these menus. Each post-menu message starts with `gauntlet: gate=gatekeep-pr/own-merge recommended=1`, never the batch-summary marker. Before substitution, assign a `## cleanup` item whose unresolved text holds none of `<issue>`, `<pr>`, `<merge-sha>` to the shared set: include it in the last merged PR's row 1 only, in roster order for this round. Offer its individual row on earlier merged PRs while it has not run. Keep PR-specific items with their PR. Record shared-item execution in the parent roster across rounds: a shared item runs at most once in the set. Omit it from later menus and skip it in queued picks only after its command runs with a recorded result, never because an earlier pick is queued.
84
84
 
85
- Print each supplied child report file verbatim in roster order, each under its own `#<N>` heading and directly above that PR's queued menu from `menus.md`; add no synthetic `Verdict:` restatement at the menu turn. Render only the first PR's report and menu in the summary turn; collect each PR's pick before rendering the next PR's report and menu in a new turn. Never put two PRs' menus in one message or ask for all picks in one combined reply. Render each child's template from `menus.md`: reports with their template rows, conflicts through `menus.md` `## batch summary`'s recovered CONFLICTING template, failures with retry/evidence/stop, STOPPED with the recorded ask and stop last. For retry use exactly `retry - re-dispatch this PR's assessment with the same record`, recommended only after clean recovery and no rebase. Resolve the actual gitdir with git (a worktree .git can be a file); require empty `git -C <worktree> status --porcelain` and neither rebase-merge nor rebase-apply there. Otherwise omit the row and print `Not offered: retry (worktree dirty or mid-rebase: <state>)`. Substitute `<observed state>` with the concrete observation - the porcelain line(s) or the rebase directory name - one line per snapshot, never the placeholder text.
85
+ Queue every parent-owned terminal pick (a post row or set of rows, merge, wait, stop) until every roster entry's pick for the round is collected. Print `Queued until all picks are collected (<roster summary>)` before the execution block for each queued pick, including a single-entry roster. Summarize each roster entry's collected pick or pending status inside `<roster summary>`.
86
86
 
87
- Queue every parent-owned terminal pick (post coverage to PR or ticket, merge, cleanup, wait, stop) until every roster entry's pick for the round is collected. Print `Queued until all picks are collected (<roster summary>)` before the execution block for each queued pick, including a single-entry roster. Summarize each roster entry's collected pick or pending status inside `<roster summary>`.
87
+ Show evidence in-place from retained record/helper paths and leave the same menu waiting. Queue all other picks and answers until the round's final pick. Record direct picks as the child's `course` or terminal selection; do not turn answers into grants. Execute queued terminal picks in roster order from the primary checkout through `post-selection-loop.md` `### Post steps`, preserving its step order, deduplication, guards, failed-step continuation and nested-skill pauses. Keep remaining steps and other PRs' queued picks waiting until a picked skill returns. The parent owns every post step, even after cleanup removes a PR worktree; exclude terminal picks from child dispatch and never use a removed worktree as cwd. Run no helper for terminal posts. Skip compare-and-swap only on merged or closed PRs; delegate approved/open reply freshness to `### Post steps`.
88
88
 
89
- Show evidence only in-place from record/helper paths, then re-ask. Queue all other picks and answers until the final menu. Record direct picks as the child's `course` or terminal verb; do not turn answers into grants. For terminal overlays, the parent handles `post coverage to ticket`, `post coverage to PR`, and `show evidence` from the primary checkout, even after cleanup removes the PR worktree; assign the parent the `merge queued` overlay's `wait` pick after all picks are collected: re-run `post-selection-loop.md` `### Merge course`'s post-merge read (`gh pr view <N> --json state,mergeCommit`), on `MERGED` persist `pr.state` and `pr.merge_commit` and render coverage/menu under `own merge`, otherwise re-render `merge queued` (`wait`/`show evidence`/`stop`), with no helper, child, or CI watch. Follow `decision-menu.md`'s terminal rows and `post-selection-loop.md` `### Merge course` and `### Output done-check`: execute the direct selected post only, with no compare-and-swap or helper dispatch; preserve successful-post suppression, failed-post rows, and terminal re-rendering. Queue terminal posts with all other external writes until every PR's pick is collected; keep evidence in-place from the retained record/helper paths. Exclude terminal picks from child dispatch; never use a removed worktree as cwd. Next batch mixes retry/answered-ask `report` with ordinary nonterminal `execute` tasks, always same record.
89
+ For `merge queued`, the parent handles `wait` after all picks: re-read `gh pr view <N> --json state,mergeCommit` per `post-selection-loop.md` `### Merge course`. On `MERGED`, persist `pr.state` and `pr.merge_commit` and render its one post menu under `own merge`; otherwise re-render `merge queued` with wait/stop and the evidence hint, without helper, child or CI watch. Next batch mixes retry/answered-ask `report` with ordinary nonterminal `execute` tasks, always the same record.
90
90
 
91
91
  ## Between batches and retirement
92
92
 
93
- Run parent cleanup/stop only after all children finish, never on a live child's tree. For cleanup apply cleanup guards and ordered overrides. Keep the PR and post rows in the roster, set cleanup_done, and re-render with cleanup gone. Cleanup does not retire.
93
+ Run parent post/stop consequences only after all children finish, never on a live child's tree. After all selected post steps finish for a PR, retire it with no re-render, including when a step failed. On stop retire it without running unpicked post steps. For non-final stop run `cleanup.md` `## Non-final stop`; under terminal overlays leave the checkout as found and print its leftover path/branch.
94
94
 
95
- For non-final stop run `cleanup.md` `## Non-final stop` after all children finish. Under terminal overlays leave checkout as found and print leftover path/branch. Retain the PR's row from `post-selection-loop.md` `### Settlement rows` in the parent roster before deleting only that PR's record, helper outputs, and log_path files under existing teardown rules, then retire it. While any PR remains, start a retirement message with `gauntlet: retired #<N> - <reason>`, never `gauntlet: done` or `gauntlet: stuck`; keep private child result lines unchanged. Await all next-batch results and re-render every nonretired PR; repeat until all retire.
95
+ Before teardown, retain each PR's settlement row and per-PR not-run sentences from `post-selection-loop.md` `### Teardown` in the parent roster for the final message. Keep payload files for unrun or failed posts; delete only that PR's other helper/log files and record under those teardown rules. Start every PR retirement message, including the last, with `gauntlet: retired #<N> - <reason>`, without a terminal marker or settlement row; keep private child result lines unchanged. Await all next-batch results and render only nonretired PRs until all retire.
96
96
 
97
- After the last PR retires and every selected cleanup or follow-on step finishes, render one final message. Start the message with `gauntlet: stuck retired` when any retained outcome is `stuck - <reason>`, otherwise `gauntlet: done retired`. Print every retained PR row below it in roster order, including PRs retired in earlier rounds. Emit no per-PR terminal message before this set settlement.
97
+ After the last PR retires and every selected step finishes, render one parent closing message. Start the message with `gauntlet: stuck retired` when any retained outcome is `stuck - <reason>`, otherwise `gauntlet: done retired`. Print every retained PR settlement row and its not-run sentences in roster order, including PRs retired in earlier rounds.
98
98
 
99
99
  Initialize parent tracker tasks `pr-<N> state: <record path>`; mark in_progress on dispatch, complete on retirement, failed on unretried failure. Child trackers are session-local stages, not parent roster tasks. Use a plain checklist if plan_tracker is unavailable.
@@ -1,22 +1,22 @@
1
1
  # gatekeep-pr: cleanup
2
2
 
3
- Read from `decision-menu.md` when `cleanup` is picked on a terminal overlay. Input: the digest (`pr.url`, `pr.merge_commit` - `mergeCommit.oid` from Section A or `### Merge course`, `pr.state`, `pr.headRefOid`, `pr.baseRefName`, `issue.ref` or `issue: null`, the `worktree` block) and the continuation record, plus the `## cleanup` section of the merge-base overrides file (`assessment.md` `## Configuration`). Output: one rendered line per step - `<label>: done`, `<label>: skipped - <reason>`, `<label>: failed - <first error line>`, or `<label>: invoked /skill:<name> - <where it paused or what it returned>` for a `/skill:` item - then set `cleanup_done` and re-render the same terminal menu without the `cleanup` row.
3
+ Read from `menus.md` `## post` to resolve step guards and commands before numbering, and from `post-selection-loop.md` `### Post steps` to execute a picked cleanup, PR-named action or override. Input: the digest (`pr.url`, `pr.merge_commit`, `pr.state`, `pr.headRefOid`, `pr.baseRefName`, `issue.ref` or `issue: null`, `worktree`), the continuation record and merge-base overrides (`assessment.md` `## Configuration`). Return each result to the picked set's executor, not a menu.
4
4
 
5
5
  **Landed** means `pr.state` is `MERGED`. **Primary** is the parent directory of `git -C <worktree.path> rev-parse --git-common-dir`; it is the checkout the session runs in. Never remove it and never change its branch. Run every git command as `git -C <primary>`; touch nothing under the removed worktree path after step 1.
6
6
 
7
- Run the steps in order; a failing step prints its first error line and the loop continues; retry nothing.
7
+ Run only the picked step: cleanup executes steps 1-3 as one group, each override executes its own step-4 item, and a resolved PR-named action uses step 4's dispatcher. Keep guards in execution as well as row preparation. A failed sub-step prints its first error line and the loop continues; retry nothing. Before a picked PR-named action or `/skill:release` item, require step 3's synced result; run step 3 first when cleanup is not picked. A failed or skipped base pull yields `skipped - base not synced` for the dependent action.
8
8
 
9
9
  1. **Worktree.** Eligible when `worktree.path` is not the primary, `git -C <worktree.path> status --porcelain --untracked-files=no` is empty (tracked-clean; untracked files never block removal), and - when landed - `git -C <worktree.path> log origin/<baseRefName>..HEAD` shows no commit outside the assessed head's history (`git -C <worktree.path> merge-base --is-ancestor HEAD <headRefOid>` succeeds). When the merge-base `## using-git-worktrees` section has at least one of `- home:`, `- create:`, `- destroy:` (the keyed contract), eligibility also requires the ownership match of `../../finishing-a-development-branch/SKILL.md` Step 6 (the recorded `worktree.destroy` already carries the recovered identifier): `home:` resolved against `$PRIMARY` (absent -> `.worktrees/<name>`), the `<name>` segment matched as `<prefix>*<suffix>` within one segment (`../acme-mono-<name>` against `/work/acme-mono-fix-x` recovers `fix-x`), `$WORKTREE` (the digest `worktree.path`) and the pattern both through `realpath`; an ambiguous match stops; no match -> `worktree: skipped - outside configured home, left at <path>` and the branch step reports it still checked out. Eligible and (`worktree.created` or landed) -> run `worktree.destroy` when recorded (from the primary; a non-zero exit prints `worktree: failed - <its output>`, keeps the branch (the branch step reports it still checked out), and never falls back to a forced removal), else `git worktree remove --force <worktree.path>` (the single `--force` removes a tree whose only dirt is untracked files; those files are deleted); then `git worktree prune`; print `worktree: done`. Reused and not landed -> `worktree: skipped - reused, left at <path>`. Dirty -> `worktree: skipped - uncommitted changes at <path>`. Commits beyond the assessed head -> `worktree: skipped - unmerged commits <shas> at <path>`. Under `approved` on a `rebased locally` head this step reports `unmerged commits` and leaves the tree, and `stop` leaves the rewritten local head in place and names it.
10
10
  2. **Branch.** A non-zero `worktree.destroy` exit in step 1 -> `branch: skipped - worktree destroy failed`, whatever `git worktree list` shows. Landed, the branch exists locally, and no worktree holds it (`git worktree list --porcelain` lists no `branch refs/heads/<worktree.branch>`) -> `git branch -D <worktree.branch>`; print `branch: done`. Not landed -> `branch: skipped - PR not merged`. Still checked out -> `branch: skipped - checked out at <path>`. Never delete a remote branch.
11
11
  3. **Base.** Landed, the primary is on `<baseRefName>`, and its tree is tracked-clean -> `git fetch origin` then `git pull --ff-only`; print `base: synced <sha>` when `git merge-base --is-ancestor <pr.merge_commit> HEAD` succeeds, else `base: failed - merge commit not on local <baseRefName>`. Primary on another branch -> `base: skipped - primary on <branch>`; dirty -> `base: skipped - uncommitted changes`; not landed -> `base: skipped - PR not merged`. Never switch the primary's branch.
12
- 4. **Override steps**, one per `## cleanup` item in list order. An item is `<label>: <text>`; any other shape -> `skipped - malformed item: <text>`.
12
+ 4. **Override dispatcher**, invoked separately for each picked `## cleanup` item in list order. An item is `<label>: <text>`; any other shape -> `skipped - malformed item: <text>`.
13
13
  - Landed-change guard first: not landed and the text contains `<merge-sha>` or `/skill:release` -> `skipped - needs a landed change`. The guard decides before any placeholder is read, so an item it skips never prints a `no <name> resolved` line, whatever its placeholders hold. A `/skill:release` item when step 3 did not print `synced` -> `skipped - base not synced`.
14
14
  - Substitute: `<issue>` is `issue.ref` with a leading `#` stripped for the bare `#N` form (other forms verbatim); `<pr>` is `pr.url`; `<merge-sha>` is `pr.merge_commit`. A null `<merge-sha>` -> `skipped - needs a landed change` in both the cleanup row text and the result block. Other null values -> `skipped - no <name> resolved`: `skipped - no issue resolved`, `skipped - no pr resolved`. Any other `<...>` token -> `skipped - malformed item: <text>`. Insert each value as literal argument text: inside an existing quoted span verbatim; outside, single-quoted as one shell word.
15
15
  - Text starting with `/skill:` -> invoke that skill with the rest of the text as its arguments, gates intact: the step's line is `<label>: invoked /skill:<name> - <where it paused or what it returned>` (for example `release: invoked /skill:release - paused at its level pick`) - never a `skipped` or `failed` line about skill availability, because the gate itself runs as a skill and every `/skill:` item is invokable; `/skill:release` with no level runs the skill's propose-then-pick gate; a level written in the item (`patch`, `minor`, `major`) authorizes the release without a pause. Any other text -> run it as a non-interactive shell command with cwd the primary, bounded by the resolved `timeout minutes` (default 15) through the Safety contract ladder of `../verification-brief.md` Section B; a timeout prints `failed - timed out after <n> minutes` and later steps still run.
16
16
 
17
- With no overrides file or no `## cleanup` section, run steps 1-3 only. On a closed-unmerged PR steps 2 and 3 print `PR not merged` and the landed-change guard skips release and `<merge-sha>` items before substitution. Do not delete the consent record, helper output files, or temporary body files here - `show evidence` and the post rows stay available after `cleanup`; `post-selection-loop.md` `### Teardown` deletes them on terminal exit.
17
+ With no `## cleanup` section, offer no overrides. Build each row through `menus.md` `## post` with its resolved command and worktree removal's deletion of untracked files; keep overrides separate.
18
18
 
19
- Consequence clause for the menu row (`decision-menu.md`): `remove <worktree.path> (untracked files there are deleted) and branch <worktree.branch>, pull <baseRefName>, then <label> (<resolved command>), ...` with every placeholder already substituted, so the tracker comment text and the release invocation are confirmed by the one pick and `/skill:release` keeps its own level gate; steps the guards would skip render as `<label> (skipped - <reason>)`; with no `## cleanup` section the clause is `tear down the gate's checkout and local branch (untracked files there are deleted)`.
19
+ For [Teardown's closing message](post-selection-loop.md#teardown), include each unpicked, skipped or failed cleanup sub-step's command: recorded `worktree.destroy` or `git -C <primary> worktree remove --force <worktree.path>`, `git -C <primary> branch -D <worktree.branch>`, `git -C <primary> fetch origin` then `git -C <primary> pull --ff-only`, and each `## cleanup` item's resolved command; repeat the executable command literally in each closing sentence, never an alias, reference to earlier text or retained worktree path. List a skipped sub-step even when its group was picked and all other steps ran.
20
20
 
21
21
  ## Non-final stop
22
22
 
@@ -4,7 +4,7 @@ Read from SKILL.md step 5, before `report.md`. Inputs: the digest, the step-2 `s
4
4
 
5
5
  ## Provenance
6
6
 
7
- Local evidence: `worktree_root` matches the provisioned path, every `run_cwd` sits inside it, `head_sha` matches the digest's `headRefOid`. On mismatch, re-fetch the PR head once and re-sync + re-run steps 3-4 when it advanced; a second mismatch, or any path mismatch, is missing evidence. The evidence clause names its source exactly: local -> `verification command passed locally`; CI -> `CI green on the assessed head (<check name>)`, never worded as a local run.
7
+ Local evidence: `worktree_root` matches the provisioned path, every `run_cwd` sits inside it, `head_sha` matches the digest's `headRefOid`. On mismatch, re-fetch the PR head once and re-sync + re-run steps 3-4 when it advanced; a second mismatch, or any path mismatch, is missing evidence. Preserve the resolved evidence source in the record. In report prose, distinguish a local verification result from CI; never describe CI success as a local run (`report.md` `## Standing`).
8
8
 
9
9
  ## AC outcomes
10
10
 
@@ -12,25 +12,40 @@ Inputs: the digest's `scope` block (step 2: the spec's rows with dispositions an
12
12
 
13
13
  Split each AC row once into a **mechanism half** (code + test + doc that make the behavior possible) and, when the row names an observation that needs an environment, dataset, deployed target, or external system that repository tests cannot reach, an **observation half**. Behavior a unit test can assert ("retries three times then fails", "rejects a nil name") is mechanism, never an observation half. A `venue:` row's mechanism half is judged like an `in-scope` row. Judge the mechanism half only; the observation half is checked after merge, not here, and blocks nothing.
14
14
 
15
- | Outcome | Condition | Renders as | Blocks |
15
+ | Outcome | Condition | Report through `report.md` | Blocks |
16
16
  |---|---|---|---|
17
- | `covered` | evidence matches what the AC promises: executable behavior needs the code path plus a real test that exercises it; a documentation-only AC is judged against the promised doc text and demands no test; in both cases docs that describe the behavior agree with it | counted in `Delivers` | no |
18
- | `gap` | any part of the mechanism absent in this PR for an `in-scope` or `venue:` row, a `deferred:` row with empty `ref`, or a Design clause | one `Blockers` item | yes - a mechanism `gap` is a blocker |
19
- | `not judged here` | the observation half; the mechanism half of the same row is still judged `covered`/`gap` | one `Delivers` clause ("<row>'s observable half is checked after merge, not here"); nothing is written, listed, or handed to check-delivery | no |
20
- | `deferred per spec` | a `deferred: <ref>` row with non-empty `ref` | one `Delivers` clause (`<n> deferred per spec to <ref>`) | no |
21
- | `deviates per spec` | a `deviates: <why>` row; the Design clauses the `<why>` names or quotes are judged for mechanism like an `in-scope` row | one `Delivers` clause (`<n> deviates per spec: <why>`); a missing adopted clause is one `Blockers` item | only an adopted clause's `gap` |
22
- | `elsewhere per spec` | an `elsewhere: <repo>` row | one `Delivers` clause (`<n> elsewhere per spec: <repo>`) | no |
17
+ | `covered` | evidence matches what the AC promises: executable behavior needs the code path plus a real test that exercises it; a documentation-only AC is judged against the promised doc text and demands no test; in both cases docs that describe the behavior agree with it | covered behavior | no |
18
+ | `gap` | any part of the mechanism absent in this PR for an `in-scope` or `venue:` row, a `deferred:` row with empty `ref`, or a Design clause | missing behavior as a blocker | yes - a mechanism `gap` is a blocker |
19
+ | `not judged here` | the observation half; the mechanism half of the same row is still judged `covered`/`gap` | observation half is checked after merge, not here; write, list or hand nothing to check-delivery | no |
20
+ | `deferred per spec` | a `deferred: <ref>` row with non-empty `ref` | deferred behavior and its `ref` | no |
21
+ | `deviates per spec` | a `deviates: <why>` row; the Design clauses the `<why>` names or quotes are judged for mechanism like an `in-scope` row | deviation and its `why`; keep a missing adopted clause as one blocker | only an adopted clause's `gap` |
22
+ | `elsewhere per spec` | an `elsewhere: <repo>` row | external behavior and its `repo` | no |
23
23
 
24
24
  The `design` section is always part of the judged contract: a Design requirement with no mechanism in the diff is a `gap` blocker whether or not an AC row points at it. A `deferred:` row whose `ref` is empty is a `gap` ("row <n> is deferred to no ticket, spec, or URL"); the gate checks the reference's shape only, never that its destination shipped - delivery is `/skill:check-delivery`'s job. A row the repository cannot satisfy is corrected in the spec (`deviates: <why>` through brainstorming's amendment path) and, for `/skill:check-delivery`, on the ticket through `/skill:shape-ticket`; this gate posts no tracker comment, and no ticket edit lifts a withhold.
25
25
 
26
- **No spec rows** (`source: pr`, or `source: spec` with empty `rows`): no AC rows; `Delivers` states the PR's intent as read from its title and body, `design` is judged when present; `not judged here` and scope creep against rows do not apply.
26
+ **No spec rows** (`source: pr`, or `source: spec` with empty `rows`): judge the PR's intent from its title and body and `design` when present; apply neither `not judged here` nor scope creep against rows. Render through `report.md`.
27
27
 
28
- **Coverage.** With `source: spec`, `Delivers` lists the covered rows, then the `deferred per spec`, `deviates per spec`, and `elsewhere per spec` rows, then the observation halves (`report.md`); any other uncovered row is `gap`. The spec's disposition is the record: a tracker comment, a PR named in the body, or a later PR never widens or narrows it, and a bare `deferred:` is never confirmed by the ticket.
28
+ **Coverage.** With `source: spec`, retain covered, `deferred per spec`, `deviates per spec`, `elsewhere per spec` and observation-half outcomes; classify any other uncovered row as `gap`. Render through `report.md`. The spec's disposition is the record: a tracker comment, a PR named in the body, or a later PR never widens or narrows it, and a bare `deferred:` is never confirmed by the ticket.
29
29
 
30
30
  **Claims.** Treat `contradicted` as a blocker and draft a scope-neutral exact description correction; when a correction would narrow either spec-owned or PR-owned scope, pause the correction and route to the explicit contract-decision course in `post-selection-loop.md` `### Continuation record`, retaining the independent mechanism blocker. Render `unverifiable-pre-merge` as optional non-blocking Description uncertainty naming what the gate cannot verify, not as a nit or proof. Assess supplied evidence; leave `matched`, explicitly pending observations, and qualitative prose alone. Never invent unperformed work or a future commitment. Draft requested factual clarification only after an explicit human request; preserve the assertion with the two-part replacement `Author's statement: <assertion> (not verified by this gate). Gate evidence: <evidence>`, rather than deleting it. Use pending-work wording only with an explicit record in the assessed body, approved spec, linked ticket, or request; conflicting records remain uncertain.
31
31
 
32
32
  Treat a human body rewording dropping a mechanism sentence as a description defect; repair the description without amending untouched spec requirements. Keep spec-owned scope and independent mechanism blockers in force. Record a real proposed contract change and its paused continuation through `post-selection-loop.md` `### Contract decision`; limit it to the requested obligation, not omitted description mechanisms.
33
33
 
34
+ ## PR-named steps
35
+
36
+ At step 5, record every sentence in the PR body or spec at the assessed head assigning the merger an action after merge. Keep each action's label and source sentences in `post_steps`; state each action in one report sentence. Leave observation-only acceptance or verification clauses and automatic deploy or release notes to `/skill:check-delivery`, not post steps.
37
+
38
+ Resolve commands only from merge-base files: the overrides file, `AGENTS.md`, and documents it links directly (one hop). Count a command only when the document names it for that action in the same sentence, list item or table row. Count distinct command strings; repeated citations of the same string count once. PR text triggers an action and never supplies its command.
39
+
40
+ | Resolution | Step |
41
+ |---|---|
42
+ | Exactly one command with all tokens resolved | Mark runnable; substitute `<issue>`, `<pr>` and `<merge-sha>` through `cleanup.md` step 4. |
43
+ | No command, two or more distinct commands, or any unfilled token | Keep open; execute nothing for it. |
44
+
45
+ Before numbering, combine sentences naming the same action into one step retaining every source sentence. Match a resolved command against resolved `## cleanup` item text: keep one row at that item's place in list order, retaining the action's sources and mandatory inclusion in row 1. List each open action in the post menu and closing message with its reason and every source sentence, without a runnable row or a command borrowed from the PR.
46
+
47
+ Offer resolved steps through `menus.md` `## post`; execute picked steps through `cleanup.md`'s dispatcher after its base-sync prerequisite succeeds. Keep the resolved command and sources in `post_steps` through settlement.
48
+
34
49
  ## Namespaces
35
50
 
36
51
  Every finding is one of two:
@@ -76,7 +91,7 @@ For an ancestor step-4 review, match each live inline `C#` comment id to `prior_
76
91
 
77
92
  ## Dispositions
78
93
 
79
- Any blocking conclusion in the resolved check set (required or not - `../verification-brief.md` Section B, Evidence resolution table) withholds `merge` until the user dispositions it, and mints a `P#` - except the reviewer check, whose exception the brief's Section B defines (one `show evidence` line `reviewer check <name> failed - inert`). A **binding** pending check (`../verification-brief.md` Section B, binding classification) mints nothing and is not dispositionable: merge waits until it turns green, or `merge_state_status` leaves `BLOCKED`, or it converts to a failing check with its own `P#`. A not-binding pending check withholds nothing, never renders under `PR comments`, and prints under `show evidence` only, as `<name> pending - not binding this viewer (merge_state_status <value>)`; the `required` field stays gathered and no longer withholds on its own.
94
+ Any blocking conclusion in the resolved check set (required or not - `../verification-brief.md` Section B, Evidence resolution table) withholds `merge` until the user dispositions it, and mints a `P#` - except the reviewer check, whose exception the brief's Section B defines (one `show evidence` line `reviewer check <name> failed - inert`). A **binding** pending check (`../verification-brief.md` Section B, binding classification) mints nothing and is not dispositionable: merge waits until it turns green, or `merge_state_status` leaves `BLOCKED`, or it converts to a failing check with its own `P#`. A not-binding pending check withholds nothing; render it through `report.md` under `show evidence` only, as `<name> pending - not binding this viewer (merge_state_status <value>)`; the `required` field stays gathered and no longer withholds on its own.
80
95
 
81
96
  | Disposition | Annotation on the `P#` |
82
97
  |---|---|
@@ -87,7 +102,7 @@ Any blocking conclusion in the resolved check set (required or not - `../verific
87
102
 
88
103
  Only `flaky` lifts the blocker; an undispositioned check, `real`, and `ci-infrastructure-broken` keep it until the check - or, for `ci-infrastructure-broken`, the fallback local run (brief Section B, Failed CI row) - is green.
89
104
 
90
- Record dispositions only from direct human check commands. A flaky disposition followed by numeric deliver can resume; no helper can disposition a check. With BLOCKED, no eligible bypass under `post-selection-loop.md` `### Merge preconditions`, and no dispositionable local repair, render the obstacle template from `menus.md`, even with course unset, and use verdict `GitHub reports BLOCKED, no local repair applies`. Render its PR-comments line as `GitHub reports this actor's merge as blocked, so merge waits. (merge_state_status BLOCKED; reviewDecision <value>)`; keep the locator and never attribute a named rule.
105
+ Record dispositions only from direct human check commands. A flaky disposition followed by numeric deliver can resume; no helper can disposition a check. With BLOCKED, no eligible bypass under `post-selection-loop.md` `### Merge preconditions`, and no dispositionable local repair, render the obstacle template from `menus.md`, even with course unset, and explain that GitHub blocks this actor from merging and no local repair applies. Keep raw merge-state and review values under `show evidence`; never attribute a named rule.
91
106
 
92
107
  ## Drafted payloads
93
108
 
@@ -97,4 +112,4 @@ Extend each finding-keyed evidence pack with `target: file | description`. For f
97
112
 
98
113
  A payload is the smallest in-repo edit that turns the finding green and keeps the behavior the PR promises; it never adds infrastructure, a dependency, or a new module. A failure caused outside the repo (image pull, toolchain, credentials, external service) gets the smallest in-repo workaround with its reason in one sentence; a skip never removes a test an AC row relies on. Keep a finding whose smallest fix needs another repo, infrastructure, or a credential open with the `loop-implementer` failed decision's `needs <what>` second slot on pi, or the native helper's `open - needs <what>` sentence on Claude Code. A delivery course applies a description payload alongside the file payloads through `post-selection-loop.md` `### Description repair`; show compact exact old-to-new text under the blocker and the full replacement body under `show evidence`. Apply a requested factual clarification only within selected course work; mint no fake blocker. Never draft an unsolicited style rewrite.
99
114
 
100
- Compose a posted review body at post time from the blockers being addressed - one summary sentence, then the numbered items, ending on the fix or asked action. For a carried open blocker backed by a pi row, include `open - <last decision line>` on its item so the next run's prior review retains the failed-attempt knowledge.
115
+ Compose a posted review body at post time from the blockers being addressed through SKILL.md `## Wording rules`. For a carried open blocker backed by a pi row, include `open - <last decision line>` on its item so the next run's prior review retains the failed-attempt knowledge.