pi-gauntlet 8.4.7 → 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.
@@ -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.
@@ -1,105 +1,134 @@
1
- # gatekeep-pr: menu templates
1
+ # gatekeep-pr: menus
2
2
 
3
- Read with `decision-menu.md` at step 6. Select the template from this state map; terminal state takes precedence over a pending contract exception, which takes precedence over course execution.
3
+ Read at step 6; execute picks through `post-selection-loop.md` `### Next action`. Apply SKILL.md's wording rules and [menu-layout](../../brainstorming/reference/menu-layout.md)'s numeric mapping. Derive availability from the digest's permissions; `unreadable` fails closed.
4
4
 
5
- | State | Template |
6
- |---|---|
7
- | this run's merge returned MERGED | own merge |
8
- | this run's merge returned another state | merge queued |
9
- | approved_head equals assessed head | approved |
10
- | PR state no longer OPEN | closed PR |
11
- | pending contract exception | contract exception |
12
- | readiness exit, including first report ready with course unset | final |
13
- | obstacle or cap exit, including course unset with undispositionable BLOCKED | obstacle |
14
- | assess completed | assess terminal |
15
- | first report not ready, course unset | initial |
16
- | multi-PR parent round | batch summary |
17
-
18
- Resolve BLOCKED through `post-selection-loop.md` `### Merge preconditions` before selecting an obstacle; treat only BLOCKED without eligible bypass as undispositionable.
19
-
20
- Render every menu in full from its template: the verdict line, every available row, and the hint line. Never narrate or summarize a menu; do not substitute "the initial template applied; the human picked 2" for its rendering. Quote a numeric pick only after the rendered menu.
21
-
22
- Append ` recommended=<n>` to each gate line using the actual rendered number of its tagged recommended row. Emit one first line per turn; when combining batch summary and child menus, emit only the parent `gatekeep-pr/batch-summary` line. Keep runtime guard text, including any quoted escalation instruction, inside the obstacle body, never as a second standalone marker.
23
-
24
- Render flat numbers through [menu-layout](../../brainstorming/reference/menu-layout.md); preserve its bare-numeric mapping. Put exactly one `[recommended]` on an available row and `stop` last. Put `show evidence` in every hint line, never in a row. Include every omission reason from `decision-menu.md`. A menu rendered under `deliver` before an exit condition, other than the contract-exception template, is a red flag; so is a menu not rendered from these templates, two recommendations, stop not last, or no evidence hint.
5
+ Render every menu in full: the standing sentence, every available row as `<n>. <verb> - <consequence>`, then the hint. Never narrate or summarize a menu. Quote a numeric pick only after the rendered menu. Move the recommended action to row 1 before numbering every menu, including child and batch menus; tag only it `[recommended]`. Keep non-recommended stop last; other rows follow table order. Append ` recommended=1` to each gate line. Emit one first line per turn: the parent batch-summary marker for combined nonterminal child menus, each terminal post menu's marker in its own message. Keep runtime guard text inside the obstacle body, not a second marker.
25
6
 
26
- Render terminal cleanup consequences through `cleanup.md`; use `skipped - needs a landed change` for merge-SHA-dependent overrides in the row text and result block.
7
+ Use `Pick one:` except for post combinations. Hint: `Type a number; show evidence prints the full record.` Append `check <name> flaky | real | ci-broken` for failing checks. Keep show evidence hint-only. Omit unavailable rows with a sentence from Missing rows; never suffix a disabled row. Under deliver, render no menu before an exit except contract exception.
27
8
 
28
- Use `viewer.is_author` (`viewer.login == pr.author.login`) and `author_is_bot` for defaults. Treat a bot-authored head as someone else's throughout. Keep `merge policy` (`squash | merge-commit | rebase`) solely as the `gh pr merge` flag selector, never approval or sync strategy. Treat `approve (round 1) / approve (round 2)` as spec approval history, not menu configuration.
9
+ ## States
29
10
 
30
- ## initial
11
+ Take the first matching row. Resolve BLOCKED through `post-selection-loop.md` `### Merge preconditions` before selecting an obstacle; only BLOCKED without eligible bypass is undispositionable. The table switches rows off in addition to their availability rules.
31
12
 
32
- Offer `assess`, eligible `deliver`, eligible `deliver with nits`, then `stop`. Recommend deliver for the human's own PR, assess for someone else's; when delivery is omitted on an own PR, recommend assess. Omit deliver with nits with zero nits, and both delivery rows with cap zero, missing helpers, or non-pushable/unreadable head; name each reason, including `Not offered: deliver (needs push to <head_url>:<head_ref>)`. For someone else's/bot PR change the sync consequence to "merge main into the branch". Map `deliver with nits` to stored `deliver-nits`.
33
-
34
- ```text
35
- gauntlet: gate=gatekeep-pr/initial recommended=2
36
- Verdict: not ready - 2 blockers, 1 nit
37
-
38
- Pick one:
39
- 1. assess - post the review to the PR; then approve or stop, no repairs.
40
- 2. deliver - repair blockers, rebase on main, watch CI, repeat until merge is offered. [recommended]
41
- 3. deliver with nits - deliver, and fold the 1 nit into the repairs.
42
- 4. stop - remove the worktree, leave the PR as is.
43
-
44
- Course holds until the final menu; `show evidence` prints the full record.
45
- ```
46
-
47
- ## final
13
+ | State | Entry | Archetype | Rows switched off | Marker |
14
+ |---|---|---|---|---|
15
+ | own-merge | This run's merge returned MERGED | post | wait | Start the message with `gauntlet: gate=gatekeep-pr/own-merge` |
16
+ | merge-queued | This run's merge returned another state | post | All except wait and stop | Start the message with `gauntlet: gate=gatekeep-pr/merge-queued` |
17
+ | approved | approved_head equals assessed head | post | Coverage, PR-named steps, wait | Start the message with `gauntlet: gate=gatekeep-pr/approved` |
18
+ | closed-pr | PR no longer OPEN | post | Own-merge coverage, wait; mark merge-dependent steps skipped on closed-unmerged | Start the message with `gauntlet: gate=gatekeep-pr/closed-pr` |
19
+ | contract-exception | Pending contract proposal | action | All except accept contract change, preserve contract and stop | Start the message with `gauntlet: gate=gatekeep-pr/contract-exception` |
20
+ | final | Readiness exit, including ready first report with course unset | final | deliver | Start the message with `gauntlet: gate=gatekeep-pr/final` |
21
+ | obstacle | Obstacle or cap exit, including course unset with undispositionable BLOCKED | action | Contract rows, deliver with nits | Start the message with `gauntlet: gate=gatekeep-pr/obstacle` |
22
+ | assess-terminal | Assess completed | final | merge, fix nits | Start the message with `gauntlet: gate=gatekeep-pr/assess-terminal` |
23
+ | initial | First report not ready, course unset: repairable blockers or pending-only CI | action | Contract rows, approve workflow run | Start the message with `gauntlet: gate=gatekeep-pr/initial`; render: `gauntlet: gate=gatekeep-pr/initial recommended=1` |
48
24
 
49
- Start the message with `gauntlet: gate=gatekeep-pr/final`.
25
+ ## Recommendation
50
26
 
51
- For eligible BLOCKED readiness, render `merge - <policy>-merge on ruleset bypass authority; CI evidence stands` with the resolved policy, and carry `merge_state_status BLOCKED (bypass eligible; reviewDecision <value>)` in the `Evidence:` line below. Keep the ordinary `merge` row and the same recommendation defaults; render no separate bypass row.
27
+ Choose from the findings, including obstacle and cap exits. Apply these pins in order: contract-exception recommends `preserve contract`; when no available non-stop row can change the outcome, recommend `stop`; else use rule 3's own-PR action default. Treat bot-authored heads as someone else's. An unchanged failed prerequisite still blocks after a cap extension; a cap with a changed prerequisite does not force stop.
52
28
 
53
- Offer available `merge`, `approve`, `fix nits` when nits remain and the course excluded them, `reply` when drafted replies exist, then `stop`. Recommend merge for own PR; recommend approve for someone else's when available, else merge; with neither available recommend stop. Omit merge on a draft with `Not offered: merge (draft)` or below WRITE with `Not offered: merge (needs WRITE on <owner>/<repo>)`. Omit approve on drafts and own PRs. Authorize exactly one delivery iteration for fix nits, leaving course unchanged (`post-selection-loop.md` `### Next action`). Hint: `Type a number; show evidence prints the full record.` Print one compact `Evidence:` line above the `Delivers:` line naming the source (`CI (source: ci)` or the local run), the head SHA, each run and its checks with their conclusions, the binding-pending count, and `merge_state_status`; put the same record in the `show evidence` hint's parenthetical.
29
+ Without a pin, use the first match:
54
30
 
55
- ## assess terminal
31
+ 1. After assess, recommend stop unless a concrete change since that pick (new head, cleared blocker, author answer) warrants another row; name that change.
32
+ 2. With a pending binding check or a failing check classified flaky as the only obstacle, recommend `deliver` when offered.
33
+ 3. Recommend deliver for the human's own PR, assess for someone else's when an open blocker needs the author's decision. Use offered action rows. Require an author decision for behavior, contract or scope not settled by the ticket, spec or PR text: a missing requirement, an acceptance-criteria change, or a scope choice. Exclude repairs matching their promises.
34
+ 4. When every open blocker has a drafted repair, none needs the author's decision, and the head is pushable and `deliver` is offered, recommend `deliver` regardless of authorship.
35
+ 5. In the final state, recommend `merge` whenever available through the ordinary path or an eligible admin override, regardless of authorship; otherwise recommend `approve` when available, else `stop`.
56
36
 
57
- Start the message with `gauntlet: gate=gatekeep-pr/assess-terminal`.
37
+ Otherwise choose the available row that settles this PR with the fewest human stops. Put one sentence immediately above `Pick one:` naming the recommendation and its reason from the finding or state. A recommendation confers no authority; wait for the pick.
58
38
 
59
- Offer available `deliver` (switch course), `approve` only on someone else's non-draft PR with zero blockers, `reply` for drafted thread replies, then `stop` `[recommended]`. Hint: `Type a number; show evidence prints the full record.`
39
+ ## action
60
40
 
61
- ## obstacle
41
+ | Row | Availability | Pick |
42
+ |---|---|---|
43
+ | `deliver` | Helpers, positive maxFixRounds, head_pushable true | Run the persistent delivery course to readiness, obstacle or cap; use `fix-wave.md` accounting. |
44
+ | `deliver with nits` | Delivery available and nits remain | Store deliver-nits; include all current and subsequently minted nits. |
45
+ | `assess` | Initial or obstacle | Post open blockers with locators as one head-pinned review through `post-selection-loop.md` `### Fix wave`; with zero blockers post nothing. Render assess-terminal, without repair or sync; keep C# replies behind reply. |
46
+ | `approve workflow run` | Held run on assessed head; viewer_permission WRITE, MAINTAIN or ADMIN | Run `gh api --method POST repos/<base-owner>/<base-repo>/actions/runs/<id>/approve`, refresh and watch under the course. |
47
+ | `accept contract change` | Pending recorded proposal | Invoke its owning amendment through `### Contract decision`; replace the baseline only after completion. |
48
+ | `preserve contract` | Pending recorded proposal | Reject the proposal, keep the named requirement and independent blockers, resume scope-preserving authorized work without the rejected payload this re-run. |
49
+ | `stop` | Always | Run `### Teardown`; non-final stop delegates to `cleanup.md` `## Non-final stop`. |
62
50
 
63
- Start the message with `gauntlet: gate=gatekeep-pr/obstacle`.
51
+ Show the proposal. Offer `accept contract change`, `preserve contract` `[recommended]`, then `stop` before numbering. Describe delivery sync as rebase for the viewer's own PR, merge main into the branch for someone else's or a bot's.
64
52
 
65
- For undispositionable BLOCKED with no local repair, use this template even with course unset: keep stop last and `[recommended]`, with no wait row, no sync promise, and no approve row. Describe eligible deliver only as retrying after the failed prerequisite changes; promise no automatic sync. Reserve the course-unset initial assess/deliver/stop template for a pending-only report when its sole withhold is a not-yet-resolved binding CI check; source blockers still use initial under the state map.
53
+ Own-PR: `1. deliver - repair blockers, rebase on main, watch CI, repeat until merge is offered. [recommended]`
66
54
 
67
- Print the concrete obstacle and retained failed prerequisites. Keep the `Delivers:` line in the obstacle report. Offer eligible `deliver`, `approve workflow run` only for the held-run permission case, `assess` (switch course), then `stop` `[recommended]`. Feed the `Evidence:` line from the verifier record's resolved source, never from the raw check or run rollup - render a `source: pending` record as `Evidence: pending (<binding check> binding; head <sha>)`, and when `course` is unset render the deliver row as `deliver - set course to deliver; <one clause naming what retries>, no round charged` instead of `resume the retained course`. Render ordinary obstacle continuation as `deliver - resume the retained course; <one clause naming what retries>, no round charged`. For every non-timeout deliver selection, add exactly `2 x maxFixRounds` to both caps and persist before work, preserving usage. Append `add <n> to each cap` (`+2 x maxFixRounds`, with cumulative usage/caps) to the row even below both caps. On timeout describe exactly one additional watch window instead, with neither cap extended. An unchanged prerequisite re-exits even after extension. Print exactly one `Evidence:` line before the verdict, naming the resolved evidence source and assessed head per `report.md` (for example `Evidence: CI (run 7001, test_unit and build_image green on 9c1e4f2)`). Include `check <name> flaky | real | ci-broken` in the hint for failing checks; flaky followed by a numeric deliver selection can resume. Hint: `Type a number; show evidence prints the full record (<source summary>)`. Replace `<source summary>` with the same source summary used in `Evidence:`, including the CI run, check outcomes, and assessed head when CI is the source.
55
+ ### obstacle
68
56
 
69
- ## contract exception
57
+ Choose the recommendation through `## Recommendation`. Show the actual failed prerequisite. For undispositionable BLOCKED with no local repair, offer no wait row, no sync promise, and no approve row; describe deliver only as retrying after that prerequisite changes. With course unset describe starting work; otherwise describe continuing it.
70
58
 
71
- Start the message with `gauntlet: gate=gatekeep-pr/contract-exception`.
59
+ For every non-timeout deliver selection, add exactly `2 x maxFixRounds` to both caps and persist before work, preserving usage; explain the added repair and sync attempts in the row, leaving counters under show evidence. On timeout offer exactly one additional watch window instead, with neither cap extended. An unchanged prerequisite re-exits even after extension.
72
60
 
73
- Print the concrete proposed contract change before the rows. Offer `accept contract change`, `preserve contract` `[recommended]`, then `stop`. Render preserve's consequence as "reject the proposal, keep <named requirement>, and resume authorized implementation repair within it". Route through `post-selection-loop.md` `### Contract decision`; show evidence settles nothing. Hint: `Type a number; show evidence prints the full record.`
74
-
75
- ## own merge
76
-
77
- Start the message with `gauntlet: gate=gatekeep-pr/own-merge`.
78
-
79
- After this run's merge returns `MERGED`, offer `cleanup` `[recommended]` until attempted, `post coverage to ticket` when issue and scope rows exist, `post coverage to PR`, then `stop`. Suppress each successful post for the rest of the run; a failed post keeps its row and prints the error. A post re-renders this template, never tears down or ends the run, and runs no compare-and-swap. After cleanup removes its row recommend the first available post, else stop. Hint: `Type a number; show evidence prints the full record.`
80
-
81
- ## merge queued
82
-
83
- Start the message with `gauntlet: gate=gatekeep-pr/merge-queued`.
84
-
85
- After this run's merge returns a state other than `MERGED`, offer `wait` - re-run `gh pr view <N> --json state,mergeCommit` `[recommended]`, then `stop`. Render `The merge is queued, so coverage posts wait. (<state>)`. A MERGED read records pr.state and pr.merge_commit and renders own merge; OPEN or another state keeps this template. Run no CI watch. Hint: `Type a number; show evidence prints the full record.`
61
+ ## final
86
62
 
87
- ## approved
63
+ Choose the recommendation through `## Recommendation`; print its `[recommended]` tag on row 1.
88
64
 
89
- Start the message with `gauntlet: gate=gatekeep-pr/approved`.
65
+ | Row | Availability | Pick |
66
+ |---|---|---|
67
+ | `merge` | Non-draft; viewer_permission WRITE, MAINTAIN or ADMIN; all `### Merge preconditions` hold | Run `gh pr merge --match-head-commit <assessed-sha>` with the resolved policy flag; append `--admin` only on the bypass path in `post-selection-loop.md` `### Merge course`. |
68
+ | `approve` | viewer.is_author false, zero blockers, non-draft | Approve; persist approved_head only after success. |
69
+ | `fix nits` | Nits outside the course; helpers and head_pushable true; accounting permits one iteration | Run exactly one delivery iteration, course unchanged; initialize missing accounting through `fix-wave.md` `## Wave`. |
70
+ | `reply` | Unposted drafted reply, source review complete | Post drafted replyable C# replies; exact `reply <n>` selects one. |
71
+ | `deliver` | Assess-terminal; action's delivery availability | Switch to the delivery course defined in action. |
72
+ | `stop` | Always | Run Teardown; keep final stop distinct from non-final assess-terminal stop. |
90
73
 
91
- When `approved_head` equals the assessed head, offer `cleanup` `[recommended]` until attempted, then `stop`; recommend stop after cleanup. Hint: `Type a number; show evidence prints the full record.`
74
+ For eligible BLOCKED readiness, explain that GitHub requires an admin override and required checks passed. Render `merge - <policy>-merge using your admin override.` Keep one merge row, no bypass row. Use merge policy solely as the command flag selector, never approval or sync strategy; spec approval history configures no menu. Keep the resolved source, head, check results and merge state under show evidence, not a report line or hint parenthetical.
92
75
 
93
- ## closed PR
76
+ ## post
94
77
 
95
- Start the message with `gauntlet: gate=gatekeep-pr/closed-pr`.
78
+ Render once on entry to own-merge, approved or closed-pr. Retain the numbered mapping in `post_steps` through inspection and execution. Build steps in this order:
96
79
 
97
- When state is not OPEN at step 1 or mid-course, offer `cleanup` `[recommended]` until attempted, then `stop`; recommend stop after cleanup. Keep this distinct from this run's own merge. Hint: `Type a number; show evidence prints the full record.`
80
+ | Step | Availability and pick |
81
+ |---|---|
82
+ | post the drafted replies | Unposted, source-reviewed drafts: post saved bodies to their PR threads. |
83
+ | post coverage to ticket | Own-merge, issue and scope rows, not previously successful: post the saved AC coverage block to the resolved ticket. |
84
+ | post coverage to PR | Own-merge, not previously successful: post the same block as a PR comment. |
85
+ | cleanup | At least one worktree, local branch or base-pull sub-step can run: execute `cleanup.md` steps 1-3. |
86
+ | each PR-named step | Merged PR, runnable through `findings.md` `## PR-named steps`: show its source sentence beside its command. |
87
+ | each cleanup override | One runnable merge-base `## cleanup` item per row, in list order: execute through `cleanup.md` step 4. |
88
+ | wait | Merge-queued only: re-run `gh pr view <N> --json state,mergeCommit`. MERGED records pr.state and pr.merge_commit and renders own-merge once; any other state re-renders merge-queued. Run no CI watch. |
89
+ | stop | Run Teardown without a step; retain its merge-queued ending for that variant. |
90
+
91
+ Only number a step with work to execute, showing its exact command or what it posts and where. List fully skipped steps below the rows with reasons, not numbers. Keep cleanup one row, naming skipped sub-steps and reasons beside runnable ones. Show substitutions, primary cwd, and the base-pull prerequisite for steps needing the merged change when cleanup is not picked.
92
+
93
+ With multiple runnable steps, make row 1 a combination naming members' labels and row numbers; give each step its own row below. Include all except the PR copy of coverage when the ticket copy is included, and apply `batch.md`'s shared-item scheduling. Omit another step only for a concrete assessment reason, stated above the prompt; always include runnable PR-named steps. With one runnable step it is row 1; with none offer only stop. Stop runs no step and delegates to Teardown.
94
+
95
+ Use `Pick one, or several separated by commas:`. Parse through `post-selection-loop.md` `### Next action`, execute through its `### Post steps`, and settle without another menu. That owner retains freshness, failed/unpicked payloads, nested skill gates and closing messages.
96
+
97
+ > I recommend every step except the PR copy of the checklist, because the ticket comment carries it.
98
+ >
99
+ > Pick one, or several separated by commas:
100
+ > 1. post the reply, post coverage to ticket, cleanup, publish the handbook, close the ticket - rows 2, 3, 5, 6 and 7. [recommended]
101
+ > 2. post the reply - answer robin's retry question in its PR thread.
102
+ > 3. post coverage to ticket - comment the acceptance checklist on acme/widgets#45.
103
+ > 4. post coverage to PR - comment the same checklist on the PR.
104
+ > 5. cleanup - remove .worktrees/csv-export (including untracked files), delete branch csv-export and pull main in the primary checkout.
105
+ > 6. publish the handbook - run `scripts/publish-handbook.sh` from the primary. The PR says: "After merge, publish the handbook."
106
+ > 7. close the ticket - run `gh issue close 45 --comment "Delivered in <pr url>, merged 9f1c2d3."`.
107
+ > 8. stop - run nothing; list unpicked steps with their commands.
108
+ >
109
+ > Type a number; show evidence prints the full record.
110
+
111
+ For merge-queued, take one number, never a combination; offer only wait and stop, recommend wait, and explain that coverage waits for the merge.
112
+
113
+ ## Missing rows
114
+
115
+ Resolve every unmet prerequisite through `post-selection-loop.md` `### Exit check`; permission never turns a repairable gap into readiness. Explain each omission in one plain sentence; invent no named GitHub rule.
116
+
117
+ | Observation | Explanation |
118
+ |---|---|
119
+ | BLOCKED with no eligible bypass and no local repair | GitHub blocks this actor from merging and no local repair applies. |
120
+ | UNKNOWN/unreadable after one re-poll | GitHub's merge status could not be read, so merging cannot proceed. |
121
+ | binding pending check | Name the required check still running; watch only at delivery step 4. |
122
+ | draft | Mark the draft ready for review before merging or approval. |
123
+ | below WRITE | Merging needs write access to the repository. |
124
+ | own PR | You cannot approve your own PR. |
125
+ | missing helpers, zero cap, head not pushable | Name each reason delivery is unavailable. |
126
+ | other failed prerequisite | Name its actual missing input or unsafe state from Exit check. |
98
127
 
99
128
  ## batch summary
100
129
 
101
130
  Start the message with `gauntlet: gate=gatekeep-pr/batch-summary`.
102
131
 
103
- For a recovered `CONFLICTING` child, offer only safe `retry` and `stop`, with `show evidence` hint-only. Render `retry - re-dispatch this PR's assessment with the same record` `[recommended]` only after `batch.md`'s clean-recovery and no-rebase checks pass; otherwise omit retry with its recorded reason and recommend stop. Keep stop last; offer no update branch or merge base rows. Hint: `Type a number; show evidence prints the full record.`
132
+ For a recovered `CONFLICTING` child, offer only safe `retry` and `stop`. Offer retry only after `batch.md`'s clean-recovery and no-rebase checks pass: re-dispatch assessment with the same record; otherwise explain its omission. Recommend retry when available, else stop. Offer no update branch or merge base rows.
104
133
 
105
- Let the `batch.md` parent render its current summary rows and each child's template from this file. Keep terminal posts and queued-merge wait parent-owned, including after worktree removal; suppress successful posts and retain failed posts. Preserve the parent's row consequences and admission/queue semantics. Put stop last and exactly one recommendation. Hint: `Type a number; show evidence prints the full record.`
134
+ Let `batch.md` render summary rows and child archetypes, preserving its admission, queue and row consequences. Keep terminal posts and queued-merge wait parent-owned after worktree removal, retaining every outcome for the parent's closing message.
@@ -4,7 +4,7 @@ Read from SKILL.md step 7. Execute only the course or terminal pick through `###
4
4
 
5
5
  ### Continuation record
6
6
 
7
- Before tracker initialization, mint one `mktemp "${TMPDIR:-/tmp}/gatekeep-state.XXXXXX"` record using `../verification-brief.md`. Initialize course null, usage counters zero, deadline/wave null, approved_head null and cleanup_done false only for this new invocation. Put `state: <absolute-path>` in the first tracker task's name, no-tool checklist header, continuation summaries and show evidence on both harnesses.
7
+ Before tracker initialization, mint one `mktemp "${TMPDIR:-/tmp}/gatekeep-state.XXXXXX"` record using `../verification-brief.md`. Initialize course null, usage counters zero, deadline/wave null, approved_head null and post_steps empty only for this new invocation. Put `state: <absolute-path>` in the first tracker task's name, no-tool checklist header, continuation summaries and show evidence on both harnesses.
8
8
 
9
9
  Persist assessed head/body, the selected scope block including original_intent, IDs and independent contributions, payload snapshots, evidence/helper paths, comment identity/body baseline and ledger. Retain consent.target solely as immutable PR/base identity, not authority. Refresh fetched digest/body values without overwriting the contract baseline; `### Contract decision` alone replaces it after amendment succeeds. Keep raw diff/logs outside the record. Once Finding artifacts creates the pair, persist its absolute locators `repair.wave.spec` and `repair.wave.ledger`; retain them and the files' row history through wave settlement, cleanup and show evidence until terminal teardown.
10
10
 
@@ -26,11 +26,13 @@ Normalize the numeric selection to its rendered row; treat other strings through
26
26
 
27
27
  ### Next action
28
28
 
29
- Recognize only exact `show evidence`, `reply <n>`, and `check <name> flaky | real | ci-broken` before numeric lookup. Show evidence through `report.md` `## What stays out` and re-render the same template without settlement. Record check dispositions through findings.md; helpers never disposition a check. Apply bare-numeric mapping from menu-layout unchanged; every other non-numeric string is a change request, including typed `deliver` even when a delivery row exists.
29
+ Recognize exact `show evidence`, `reply <n>`, and `check <name> flaky | real | ci-broken` before numeric lookup, on the states offering them. Show evidence through `report.md` `## What stays out` and re-render the same menu without settlement. Record check dispositions through findings.md; helpers never disposition a check.
30
+
31
+ On own-merge, approved and closed-pr post menus, parse a comma-separated set of row numbers against the retained rendered mapping. Expand the combination to its member steps and collapse duplicates. Exact `reply <n>` on a post menu listing drafted replies selects drafted reply n, not menu row n. A number outside 1-N, stop combined with another number, or several numbers on any other menu asks one clarifying question naming the valid range and runs nothing. On a second invalid reply, leave the same menu waiting; emit no new question or `gauntlet: question` marker and run nothing. A sole stop runs Teardown. Persist valid picked steps and enter `### Post steps` before the live-course path below. Apply bare-numeric mapping from menu-layout unchanged on other menus; every other non-numeric string is a change request, including typed `deliver` even when a delivery row exists.
30
32
 
31
33
  At this boundary and before each external write fetch actual body and live baseRefName with head/state. Compare live `baseRefName` against `consent.target.baseRefName`; an unreadable or changed base exits without overwriting `consent.target`. A same-head body edit invalidates old readiness and selected merge; narrowly recheck changed claims, preserving original intent. Refresh proposals against actual body.
32
34
 
33
- First report ready -> final with course unset. Before choosing initial for a not-ready first report, resolve obstacle states through `### Exit check`; render obstacle for undispositionable BLOCKED even with course unset. Use initial for repairable blockers or a pending-only CI withhold through `menus.md`. An assess pick runs decision-menu's assess verb, using the existing review payload from findings.md Namespaces, then assess terminal; perform no repair or sync. Under deliver or deliver-nits and no exit, continue the body below. Under deliver or deliver-nits or an outstanding terminal nit selection, run only this D3 body, with no menu except contract exception:
35
+ First report ready -> final with course unset. Before choosing initial for a not-ready first report, resolve obstacle states through `### Exit check`; render obstacle for undispositionable BLOCKED even with course unset. Use initial for repairable blockers or a pending-only CI withhold through `menus.md`. An assess pick runs `menus.md`'s assess row with the review payload from `findings.md` Namespaces. Under deliver or deliver-nits and no exit, continue the body below. Under deliver or deliver-nits or an outstanding terminal nit selection, run only this D3 body, with no menu except contract exception:
34
36
 
35
37
  1. Run `### Exit check`, then repair every source-backed and CI-minted `P#` blocker through `### Fix wave` and `fix-wave.md` `## Wave`. Under deliver-nits include all current and later nits. Preserve independent P#/L# contributor IDs; close only reviewer resolved lines.
36
38
  2. Run `### Loop sync` only for CONFLICTING, BEHIND, or local merge-tree conflict.
@@ -40,17 +42,27 @@ First report ready -> final with course unset. Before choosing initial for a not
40
42
 
41
43
  A final fix nits pick authorizes exactly one complete D3 iteration (required sync, review, push, watch and re-review included) and returns final or obstacle/cap without changing course. Before invoking the entry Exit check, persist `repair.wave.action: fix-nits` with selected_ids and payload snapshots in selected_payloads. Initialize missing accounting from fix-wave.md defaults for a course-unset final nit pick; never create a standing nit course. With course unset or deliver, dispatch the recorded nit work before readiness can return final. Keep the selection through repair/sync/review/push/watch/re-review; release the one-shot hold only after selected work and reconciliation complete, then evaluate fresh readiness. Obstacles and caps retain the checkpoint without fabricating completion. After that single iteration render final or the concrete obstacle/cap; later independent nits stay outside this selection.
42
44
 
45
+ ### Post steps
46
+
47
+ Before rendering `menus.md` `## post`, persist one `post_steps` entry per known step: label, source, exact command or payload file, picked false and result null or its guard skip reason. Preserve the mapping and completed results across inspection or a nested skill pause; never replay completed steps. Save drafted reply and coverage bodies in files before showing their rows.
48
+
49
+ Run the picked steps in `menus.md`'s step order, not reply order. Execute posts in the orchestrator after Output done-check; posts on merged or closed PRs need no compare-and-swap. For a reply on an approved, still-open PR, retain the pre-write freshness read from Compare-and-swap: head movement yields `skipped - head moved`, keeps the body file and continues the set without re-entering assessment. Execute cleanup, resolved PR-named commands and individual overrides through `cleanup.md`; its failure and base-sync guards remain binding. Persist each result immediately, print `<label>: <result>`, and continue after a failed step without retry.
50
+
51
+ Invoke a picked `/skill:` step with its gates intact at its place in the order. While it waits, report `invoked /skill:<name> - paused at <where>` and emit only that skill's marker. Retain the picked set and remaining steps; after its return record what it returned and continue, never mark a paused step done.
52
+
53
+ After all picked steps finish, end through Teardown without another gatekeep-pr menu. Keep set-mode retirement parent-owned through `batch.md`.
54
+
43
55
  ### Exit check
44
56
 
45
57
  Evaluate before every iteration and after every head, digest, or record change. Immediately after record validation, evaluate the last helper result and retained no-progress checkpoint before any binding-pending CI watch. For an unchanged `open - needs <X>` prerequisite, exit `stuck - needs <X>` immediately; name the prerequisite alone, without a CI timeout qualification. Apply the same ordering at own-push Re-render entry. Take the first matching exit:
46
58
 
47
59
  | Exit | Condition and render |
48
60
  |---|---|
49
- | readiness | Every `### Merge preconditions` holds and no outstanding terminal fix-nits selection remains; deliver-nits also requires resolved closure lines for every opted-in and subsequently minted nit. Render final, with draft/WRITE omissions from decision-menu.md. Permission never converts a repairable source gap into readiness. |
61
+ | readiness | Every `### Merge preconditions` holds and no outstanding terminal fix-nits selection remains; deliver-nits also requires resolved closure lines for every opted-in and subsequently minted nit. Render final, with omissions from `menus.md`. Permission never converts a repairable source gap into readiness. |
50
62
  | obstacle | Resolve the table below; render obstacle with its concrete reason, except contract exception and closed PR use their own templates. |
51
63
  | cap | rounds_used reaches rounds_cap -> `round cap reached: <used> of <cap>`; syncs_used reaches syncs_cap -> `sync cap reached: <used> of <cap>`; render obstacle, keep local commits. |
52
64
 
53
- Resolve every unmet merge prerequisite; retain failed prerequisites and append checkpoint history. An unlisted withhold is a protocol defect: stop with the concrete missing input rather than iterate.
65
+ Resolve every unmet merge prerequisite; retain failed prerequisites and append checkpoint history. Translate the internal exit reasons below into the report's plain standing sentence; keep protocol markers and actual errors intact. An unlisted withhold is a protocol defect: stop with the concrete missing input rather than iterate.
54
66
 
55
67
  | Observed state | Action/verdict |
56
68
  |---|---|
@@ -61,7 +73,7 @@ Resolve every unmet merge prerequisite; retain failed prerequisites and append c
61
73
  | Helper open - contract exception, or pi failed decision's second slot starts contract exception: | Render contract exception through `### Contract decision`, not obstacle. |
62
74
  | HEAD equals pre_wave_head with all payloads open, or scoped test unchanged-red after restore | render per ### No-progress obstacle |
63
75
  | Undispositionable BLOCKED without eligible bypass under Merge preconditions | `GitHub reports BLOCKED, no local repair applies`; invent no rule attribution. |
64
- | UNKNOWN/unreadable after step 2's single re-poll, regardless of CI color or a pending binding check | Render `stuck - merge state unknown` through `menus.md`'s obstacle template; let merge state own the withhold reason and the PR comments line. Authorize no sync, offer no ordinary wait row, keep stop last and `[recommended]`, report both usage counters unchanged, and print `Not offered: merge (merge state unknown)`. |
76
+ | UNKNOWN/unreadable after step 2's single re-poll, regardless of CI color or a pending binding check | Render `stuck - merge state unknown` through `menus.md`'s obstacle template; let merge state own the withhold reason; render the wait through `report.md`. Authorize no sync, offer no ordinary wait row, recommend stop through `menus.md`, report both usage counters unchanged, and explain that merging cannot proceed until GitHub's merge status is readable. |
65
77
  | Nonzero gh or incomplete pagination during refresh/refetch | One retry, then `stuck - refresh failed: <actual reason>`. |
66
78
  | Incomplete comment source review | One fresh reviewer retry, then `stuck - comment source review incomplete`. |
67
79
  | Deadline elapsed with binding checks | `stuck - CI pending past <n> minutes`; obstacle deliver opens exactly one additional window and extends neither cap. |
@@ -140,19 +152,18 @@ gh api --method POST repos/<base-owner>/<base-repo>/pulls/<N>/reviews -f commit_
140
152
 
141
153
  Set `event` to `COMMENT` for `viewer.is_author` true, `REQUEST_CHANGES` otherwise; quote each field value as one shell word. Read the response's `commit_id`: equality confirms the posted review as the assessed-head baseline; a different value prints `review posted at <sha7>, not the assessed <sha7>` without claiming that baseline. On a failed POST or missing response commit, report the error or missing provenance without claiming a baseline or blindly reposting. Keep C# thread replies behind their own pick. With zero blockers post nothing and leave the GitHub baseline unchanged; a new session reviews that older baseline's delta again, with no local carry-over of cleared spans.
142
154
 
143
- After successful `gh pr review --approve`, persist approved_head as the assessed head before rendering approved; on failure print the gh error without claiming approval.
155
+ After successful `gh pr review --approve`, persist approved_head as the assessed head before rendering the approved post menu once; on failure print the gh error without claiming approval.
144
156
 
145
157
  ### Merge course
146
158
 
147
159
  `merge` executes as `gh pr merge --match-head-commit <assessed-sha>` with the flag of the resolved merge policy: `squash` -> `--squash`, `merge-commit` -> `--merge`, `rebase` -> `--rebase`. Push and merge are never one pick. Append `--admin` only on the bypass path: `merge_state_status == BLOCKED` and `permissions.bypass_eligible == true`, with every merge precondition satisfied. Omit `--admin` on every other path. This flag skips the merge queue; the bypass path merges directly, not through the merge queued template. In batch mode the parent reads `permissions.bypass_eligible` from the retained child record and applies this same predicate and refusal branch, without a new handoff field or batch compare-and-swap.
148
160
 
149
- On a nonzero exit, print gh's error verbatim, consume the selection without retry (no second attempt with or without `--admin`), and re-run `### Pre-menu refresh`. Render from the refreshed prerequisites: final while all merge preconditions hold; obstacle with `Not offered: merge (blocked by GitHub)` when `BLOCKED` remains and `bypass_eligible` is no longer `true`; otherwise use the refreshed withhold resolver. Do not treat refusal as a queued merge or `stuck` by itself.
161
+ On a nonzero exit, print gh's error verbatim, consume the selection without retry (no second attempt with or without `--admin`), and re-run `### Pre-menu refresh`. Render from the refreshed prerequisites: final while all merge preconditions hold; obstacle explaining that GitHub still blocks this actor from merging when `BLOCKED` remains and `bypass_eligible` is no longer `true`; otherwise use the refreshed withhold resolver. Do not treat refusal as a queued merge or `stuck` by itself.
150
162
 
151
- On a zero exit, read `gh pr view <N> --json state,mergeCommit`. `state: MERGED` -> write the returned `state` into `pr.state` and `mergeCommit.oid` into `pr.merge_commit` (the same two writes when a queued merge's `wait` re-read returns `MERGED`), render the `AC coverage` block once and re-render the menu under the `own merge` overlay (`menus.md`); any other state (a merge queue) -> one `PR comments` line `The merge is queued, so coverage posts wait. (<state>)` and the merge queued template (wait re-runs the read; show evidence stays hint-only). The block, `<sha>` = `mergeCommit.oid`, one row per `scope.rows` entry in row order with its outcome (`covered`, `deferred per spec to <ref>`, `deviates per spec: <why>`, `elsewhere per spec: <repo>`, `venue: <env> - <observation>, checked before prod deploy`); with no rows (`source: pr`, or an empty `scope.rows`) the block has no row lines and `post coverage to ticket` is not offered. With `source: pr` the header line drops `, spec <path>`. An `in-scope` row whose observation half is `not judged here` renders `covered; observable half checked after merge`.
163
+ On a zero exit, read `gh pr view <N> --json state,mergeCommit`. `state: MERGED` -> write the returned `state` into `pr.state` and `mergeCommit.oid` into `pr.merge_commit` (the same two writes when a queued merge's `wait` re-read returns `MERGED`), save the `AC coverage` block as a payload file and render the own-merge post menu once (`menus.md` `## post`); any other state (a merge queue) -> render the queued-merge wait through `report.md` and the merge queued template (wait re-runs the read; show evidence stays hint-only). The block, `<sha>` = `mergeCommit.oid`, one row per `scope.rows` entry in row order with its outcome (`covered`, `deferred per spec to <ref>`, `deviates per spec: <why>`, `elsewhere per spec: <repo>`, `venue: <env> - <observation>, checked before prod deploy`); with no rows (`source: pr`, or an empty `scope.rows`) the block has no row lines and `post coverage to ticket` is not offered. With `source: pr` the header line drops `, spec <path>`. An `in-scope` row whose observation half is `not judged here` renders `covered; observable half checked after merge`.
152
164
 
153
165
  Read and apply [menu-layout](../../brainstorming/reference/menu-layout.md) before presenting these options and before acting on a numeric reply.
154
166
 
155
- ```markdown
156
167
  ## AC coverage
157
168
  Informational - the ticket's rows are unchanged. PR <url>, merged <sha>, spec <path>
158
169
  - [ ] <row 1 text verbatim> - covered
@@ -160,7 +171,6 @@ Informational - the ticket's rows are unchanged. PR <url>, merged <sha>, spec <p
160
171
  - [ ] <row 2 text verbatim> - deviates per spec: <why>
161
172
  - [ ] <row 4 text verbatim> - venue: <env> - <observation>, checked before prod deploy
162
173
  - [ ] <row 5 text verbatim> - elsewhere per spec: <repo>
163
- ```
164
174
 
165
175
  A post is one write of that block, verbatim; a post that succeeded cannot be picked again in this run. `/skill:check-delivery` reads a posted block as any other comment, and the block's first line states that it amends nothing.
166
176
 
@@ -199,18 +209,22 @@ On completion or timeout, refresh then run steps 2-5 of Re-render plus step 1's
199
209
 
200
210
  ### Output done-check
201
211
 
202
- Before posting or committing any external payload - review bodies, replies, commit subjects, tracker comments - re-read it against SKILL.md `## Wording rules` and any `## comms style` rules: ASCII only; no headings or template scaffolding under ~150 words; findings `file:line`-specific where one exists; ends on the fix or asked action, not a recap; never invents content to fill a section. The `AC coverage` block is the one exception: it posts verbatim, heading and checkbox rows included.
212
+ Before posting or committing any external payload, apply SKILL.md `### Output done-check` and `## Wording rules`, including its coverage exception, plus any `## comms style` rules. End review bodies and replies on the fix or asked action, not a recap; never invent content to fill a section.
203
213
 
204
214
  ### Settlement rows
205
215
 
206
- Emit the terminal message only after every selected follow-on step finishes and the cleanup pick is answered (run or declined by stop); a report or menu is not settlement. Below its marker print one plain `#<N>@<head sha>: <outcome>[ (<ticket ref>)]` row per PR in roster order, singleton included. Use the full assessed `headRefOid`, not the merge commit or a shortened display SHA. Use the last gathered head when assessment could not start. Append the parenthetical only when the PR title or body's first line names a ticket under the overrides `## Issue tracker` `refs:` convention; otherwise omit it. Use exactly `approved`, `merged`, `closed-pr`, `final`, `merge-queued`, or `stuck - <reason>`, retaining the actual stop/error reason. Keep rows without bullets, code fences or emphasis; put checkout paths and cleanup results after them.
216
+ Emit the terminal message only after the selected post set finishes or stop declines it; a report or menu is not settlement. Below its marker print one plain `#<N>@<head sha>: <outcome>[ (<ticket ref>)]` row per PR in roster order, singleton included. Use the full assessed `headRefOid`, not the merge commit or a shortened display SHA. Use the last gathered head when assessment could not start. Append the parenthetical only when the PR title or body's first line names a ticket under the overrides `## Issue tracker` `refs:` convention; otherwise omit it. Use exactly `approved`, `merged`, `closed-pr`, `final`, `merge-queued`, or `stuck - <reason>`, retaining the actual stop/error reason. Keep rows without bullets, code fences or emphasis; put checkout paths and cleanup results after them.
207
217
 
208
- For set mode, retain each row before deleting its PR record and follow `batch.md`'s retirement and final-settlement rules. Keep private child result lines unchanged.
218
+ For set mode, retain each row before deleting its PR record; print it only in the parent's closing message through `batch.md`'s retirement and final-settlement rules. Keep private child result lines unchanged.
209
219
 
210
220
  ### Teardown
211
221
 
212
- Start the message with `gauntlet: done approved` for stop on approved. Start the message with `gauntlet: done merged` for stop on own-merge. Start the message with `gauntlet: done closed-pr` for stop on closed-pr. Start the message with `gauntlet: done final` for stop on final. Start the message with `gauntlet: done merge-queued` for stop on merge-queued. Print the row from `### Settlement rows`, then the checkout path and local branch. A report Verdict above a menu is not a terminal. Start the message with `gauntlet: stuck` followed by the actual error on any hard assertion failure, including a delegated fix-wave restore/assert failure; print the PR row with `stuck - <actual error>` below it and end with the actual error, without a continuation menu. In set mode use `batch.md`'s per-PR retirement marker until every PR retires.
222
+ Save every unrun or failed drafted reply and coverage body without a file under `${TMPDIR:-/tmp}`; reuse existing body files. Do this on `final`, `merge-queued` and `post` stops too, before printing their paths or deleting drafts.
223
+
224
+ Start the message with `gauntlet: done approved` for post completion or stop on approved. Start the message with `gauntlet: done merged` for post completion or stop on own-merge. Start the message with `gauntlet: done closed-pr` for post completion or stop on closed-pr. Start the message with `gauntlet: done final` for stop on final. Start the message with `gauntlet: done merge-queued` for stop on merge-queued. Print the row from `### Settlement rows`, then the checkout path and local branch. Render reports through `report.md`; a report above a menu is not a terminal. Start the message with `gauntlet: stuck` followed by the actual error on any hard assertion failure, including a delegated fix-wave restore/assert failure; print the PR row with `stuck - <actual error>` below it and end with the actual error, without a continuation menu. In set mode use `batch.md`'s per-PR retirement marker until every PR retires.
225
+
226
+ Delegate non-final stop (initial, assess terminal, obstacle, contract exception) to `cleanup.md` `## Non-final stop`. Keep terminal cleanup behind a selected post step; terminal stop leaves the checkout as found and reports its path and local branch. Render cleanup only on terminal templates; never run cleanup steps 2-4 for a non-final stop.
213
227
 
214
- Delegate non-final stop (initial, assess terminal, obstacle, contract exception) to `cleanup.md` `## Non-final stop`. Keep terminal cleanup behind its own pick; terminal stop leaves the checkout as found and reports its path and local branch. Render cleanup only on terminal templates; never run cleanup steps 2-4 for a non-final stop.
228
+ After the terminal marker and settlement row, print the post-step results, then one sentence per unpicked, skipped or failed step naming its label, reason and command or payload path. Include skipped cleanup sub-steps. Keep these not-run sentences distinct from `<label>: <result>` lines. On stop, include every known drafted reply, coverage post, cleanup, PR-named action and override, stating whether it could run now or awaits the merge; keep the existing final and merge-queued outcomes. Retain the body files of unrun or failed posts and name them in these sentences. In set mode retain these sentences with the PR's row for the parent's closing message.
215
229
 
216
- Delete both finding artifacts at `repair.wave.spec` and `repair.wave.ledger` with the run record, temporary description body files, every helper output and its log_path on every handled terminal exit. Drop unapplied drafts. Never discover authority in a new session.
230
+ Delete both finding artifacts at `repair.wave.spec` and `repair.wave.ledger` with the run record, temporary description body files, every helper output and its log_path on every handled terminal exit, except retained post payload files. Drop other unapplied drafts. Never discover authority in a new session.