pi-gauntlet 7.10.1 → 7.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## v7.11.1 - 2026-10-14
4
+
5
+ ### Changed
6
+
7
+ - **gatekeep-pr and check-delivery: model invocation allowed on an explicit ask; every in-skill gate still needs your selection.** `disable-model-invocation: true` is gone from `skills/gatekeep-pr/SKILL.md` and `skills/check-delivery/SKILL.md`, so a task that names the PR or ticket and the verb ("gatekeep PR 123", "check delivery of ABC-123", a loop over tickets) loads the skill instead of being refused by Claude Code's Skill tool. Both descriptions are now trigger-only ("Use only when explicitly asked to ..."); neither names a situation (a ready-looking PR, a fresh merge) as a trigger. The decision menu, run grants, zero-writes-on-failure, and the no-auto-chain rule from `finishing-a-development-branch` are unchanged. Follows the v7.7.1 `shape-ticket` precedent.
8
+
9
+ ## v7.11.0 - 2026-10-13
10
+
11
+ ### Changed
12
+
13
+ - `gatekeep-pr` waits on CI once: one `gh pr checks --watch` call bounded by `timeout minutes`, run only when Blockers are empty after the first report; the 30 s poll loop and the post-push poll are gone, and a wave push re-enters the menu on scoped-test evidence. A failing check is a `fix` target. Description corrections apply on `fix` or a retained fix grant like any payload, with readback and a re-propose when the body changed. Every payload is the smallest in-repo edit that turns the finding green - never infrastructure, a dependency, or a new module.
14
+
3
15
  ## v7.10.1 - 2026-10-13
4
16
 
5
17
  ### Changed
package/README.md CHANGED
@@ -41,7 +41,7 @@ Concretely, one change through the gauntlet:
41
41
  3. **`subagent-driven-development`** executes the plan one task at a time, each in a fresh subagent, behind spec-compliance review then code-quality review. TDD-locked: red, green, refactor. Independent implementation, review, and council batches remain parallel, but their dispatches are foreground: the orchestrator waits for terminal results before accepting work or advancing a phase.
42
42
  4. **verify**: the parent first runs the plan's full verification command set; only a passing result permits whole-diff code review, then the **conformance gate**. A review fix invalidates that result, so the parent reruns full verification before the next review or conformance gate. When the overrides file declares a happy path for the touched paths (see [Project-specific overrides](#project-specific-overrides)), the parent runs it once here, between code review and the conformance gate, and the reviewer reads its transcript as runtime evidence - a hang or a failed request shows up in the audit with the transcript quoted - as a gap when an origin clause ties to it, otherwise as a `happy-path: failed - unattributable` line - never as a silent green. The conformance subagent reads the finished code and docs against your *original words* from step 1, not the plan, and reports per-requirement: delivered, partial, missing, drifted, or unauthorized. Unauthorized rows - shipped surface no human input asked for, whether it crept in or was laundered through the spec - follow their recommendation like every other row: a contained removal auto-runs, anything another requirement leans on is deferred with a plain-language "I'd cut it / I'd keep it" recommendation. Inside a brainstorming-entered flow this gate is machine-blocked from being skipped. Compatible executable recommendations auto-run through an isolated fix-and-re-audit loop with no prompt; anything still open surfaces as a dense list - one line per decision, plain-language, with its recommended choice inline. Reply `1` to take every recommendation, or `2:` with per-item overrides; a current `CONFORMS` / no-concerns result goes straight to the branch options with no extra conformance sign-off.
43
43
  5. **`finishing-a-development-branch`**: PR, draft PR, squash, keep, or discard. Once a PR exists, run `/skill:gatekeep-pr <pr>` to verify it before merging - it judges the diff against the spec at the PR's head (the acceptance-criteria dispositions and Design you approved; the PR description when no spec applies) - rows the spec defers or deviates are settled, every other row needs its mechanism (code, tests, docs) - and against the rubric; whatever can be seen only after merge is left to step 6. **Human gate 2** - the only other decision you make.
44
- 6. *(Optional)* Once the merge lands, `/skill:check-delivery <ref>` can prove delivery - default-branch landing, delivery target, per-AC evidence - before the tracker status advances. Explicit invocation only, no auto-chain: deploys commonly lag merges by minutes to hours, so an auto-run would routinely check too early.
44
+ 6. *(Optional)* Once the merge lands, `/skill:check-delivery <ref>` can prove delivery - default-branch landing, delivery target, per-AC evidence - before the tracker status advances. Explicit ask only, no auto-chain: deploys commonly lag merges by minutes to hours, so an auto-run would routinely check too early.
45
45
 
46
46
  Only the machine-owned `plan -> implement` and `verify -> ship` handoffs receive a branch-local one-shot nudge after an unexpected settled stop; it is fire-and-forget, does not bypass either human gate, and older Pi hosts without `agent_settled` retain existing behavior.
47
47
 
@@ -77,7 +77,7 @@ The run's grants, target/scope baseline, repair usage, and poll deadline live in
77
77
 
78
78
  pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
79
79
 
80
- - **20 skills** - the workflow logic. Thirteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes), `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `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). Seven 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. `gatekeep-pr` 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, an unknown merge state, and every other merge precondition still withhold; 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 a verb menu whose rows derive from the actor's permissions on the PR; nothing mutates (fixes, pushes, reviews, merges, tracker comments) until you pick a 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 the normal `fix` row 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 - run it with `/skill:gatekeep-pr <pr> [--rebase [base]]`. `check-delivery` is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/hotfix/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage; the hotfix row hands off to `skills/chase-bug/hotfix.md` after the menu - run it with `/skill:chase-bug`. `gauntlet-performance` reads the committed run telemetry (current repo by default, `--dir <path>` adds others) through the parse-only `gauntlet-performance` CLI and answers with one example-led recommendation, 3-5 cornerstone numbers, 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>]`.
80
+ - **20 skills** - the workflow logic. Fifteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write; 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, an unknown merge state, and every other merge precondition still withhold; 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 a verb menu whose rows derive from the actor's permissions on the PR; nothing mutates (fixes, pushes, reviews, merges, tracker comments) until you pick a 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 the normal `fix` row 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 - run it with `/skill:gatekeep-pr <pr> [--rebase [base]]`), `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>`), `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `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>]`.
81
81
  - **7 subagent personas** - the specialized child agents the skills dispatch via pi-cohort: `implementer`, `code-reviewer`, `spec-reviewer`, `conformance-reviewer`, `spec-summarizer`, `spec-council-member`, `spec-council-synthesizer`. See [doc/personas.md](./doc/personas.md) for what each one does and why its permissions are scoped the way they are.
82
82
  - **4 runtime extensions** - the enforcement layer. `plan-tracker` and `phase-tracker` are tools skills call to track progress (with a TUI widget); `verify-before-ship` is a hook that warns if you push or open a PR without a passing test run since your last edit; a phase-tracker flow guard reminds on implement-phase commits missing spec/code review. In a brainstorming-entered flow, phase-tracker rejects `implement` or `verify` completion while tracker tasks remain pending or in progress; see [its configuration reference](./doc/configuration.md#phase-tracker). phase-tracker also registers `plan_check`, which verifies a plan against its spec and against the grammar in [skills/writing-plans/reference/plan-contract.md](./skills/writing-plans/reference/plan-contract.md), including that each task's `Tests:` commands are selective and never the full suite; a pass stamps the plan for implementation. `telemetry` records one YAML record per gauntlet run (phase timing, models, personas, gate/fix rounds, diff at ship) that ships in the squash beside the spec - it is written only inside a brainstorming-entered flow, kept out of history until `finishing-a-development-branch` seals it once with `gauntlet-telemetry-seal` (a `telemetry:` commit under git; the working-copy snapshot in a plain jj workspace) - and blocks a brainstorm `write` into an already-shipped spec; see [its configuration reference](./doc/configuration.md#telemetry). See [doc/configuration.md](./doc/configuration.md) for the settings each one reads.
83
83
 
@@ -459,7 +459,7 @@ customization lives in two places, never in the wrapper itself:
459
459
  ```markdown
460
460
  ## PR gate
461
461
  - verification command: <command> # required unless documented elsewhere
462
- - timeout minutes: 15 # optional; default 15
462
+ - timeout minutes: 15 # optional; default 15; bounds each gh pr checks --watch window
463
463
  - requires credentials: false # optional; true => skill reports "not run" as missing evidence
464
464
  - local verification: always # optional; default (absent) = CI-first; "always" forces the local run even when exact-head CI is green
465
465
  - ci checks: <comma-separated check names> # optional; narrows which checks count as evidence; absent = all checks on the assessed head
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "7.10.1",
3
+ "version": "7.11.1",
4
4
  "description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
5
5
  "author": "Jacek Juraszek",
6
6
  "type": "module",
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: check-delivery
3
- description: Use when a merged issue needs delivery proof before its tracker status advances - explicit-only post-merge detective control (/skill:check-delivery <ticket-ref>) that verifies default-branch landing, delivery target, and per-AC evidence, stopping loudly with zero writes on any failure.
4
- disable-model-invocation: true
3
+ description: Use only when explicitly asked to prove delivery of a named merged ticket ("check delivery of ABC-123", a loop task naming the ticket and the verb) before its tracker status advances; pre-merge gating belongs to /skill:gatekeep-pr.
5
4
  ---
6
5
 
7
6
  # Check Delivery
@@ -53,7 +52,7 @@ no metadata to check. Where the tracker exposes cheap classification
53
52
  detectably-terminal write** - the evidence comment still posts, the
54
53
  misconfiguration is reported.
55
54
 
56
- Explicit invocation only (`/skill:check-delivery <ticket-ref>`), read-only
55
+ Explicit ask only (`/skill:check-delivery <ticket-ref>`, or a task that names the ticket and the verb), read-only
57
56
  against the repository (no builds, no branch/tag/worktree mutation) plus at
58
57
  most one batched tracker write, runs from wherever invoked, no worktree.
59
58
 
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: gatekeep-pr
3
- description: Use when gating a pull request before it merges - whether you authored it or are reviewing someone else's work. Judges whether the diff delivers the mechanism each acceptance criterion needs (code, tests, docs) and conforms to the review rubric; what can be seen only after merge belongs to /skill:check-delivery. Consent-gated - repairs use explicit action-scoped run grants; final merge, approval, and external posts require their own selection, except the sync `--rebase` asks for.
4
- disable-model-invocation: true
3
+ description: Use only when explicitly asked to gatekeep, verify, or gate a named pull request before it merges ("gatekeep PR 123", a loop task naming the PR and the verb); post-merge delivery proof belongs to /skill:check-delivery.
5
4
  argument-hint: "<pr> [issue-ref] [--rebase [base]] (e.g. 123, 123 gh-45, 123 --rebase, 123 gh-45 --rebase release/2)"
6
5
  ---
7
6
 
@@ -34,7 +33,7 @@ Re-entry: a fix wave's own push re-enters step 4 through the own-push sequence (
34
33
 
35
34
  ## Progress tracking
36
35
 
37
- Mint and initialize the continuation record before progress initialization (`reference/post-selection-loop.md` `### Continuation record`). Use `plan_tracker`, never `phase_tracker`. `init` with the first three stages of the table, four when `--rebase` is present (`gather, provision, sync, verify, ...`); `reference/sync.md` closes `sync` before step 3 starts - `complete` after a push, a `no-op`, or a rebased, unpushed head (`rebased locally`), `skipped` when step 3 runs unsynced, `failed` on a terminal stop. In step 3 `add` one task per material claim and record each verdict: `complete` matched, `failed` contradicted, `skipped` unverifiable-pre-merge. Once every claim is terminal and `verify` is closed, `add` the remaining three stages - the tracker rejects a verdict recorded behind a still-pending stage. A failed stage or claim stays `failed` while the skill stops at the menu. Without a `plan_tracker` tool, keep a plain checklist; behavior is unchanged.
36
+ Mint and initialize the continuation record before progress initialization (`reference/post-selection-loop.md` `### Continuation record`). Use `plan_tracker`, never `phase_tracker`. `init` with the first three stages of the table, four when `--rebase` is present (`gather, provision, sync, verify, ...`); `reference/sync.md` closes `sync` before step 3 starts - `complete` after a push, a `no-op`, or a rebased, unpushed head (`rebased locally`), `skipped` when step 3 runs unsynced, `failed` on a terminal stop. In step 3 `add` one task per claim whose evidence is the head's source and record its verdict: `complete` matched, `failed` contradicted, `skipped` unverifiable-pre-merge. Leave claims `pending` on CI outside the tracker for now; close `verify`. From then on, `add` each later stage (`review`, `report`, `menu`, ...) only when it starts, never ahead of time. When the claim-check-only helper runs after a green watch, `add` one task per pending claim then and record its verdict in the same step. A failed stage or claim stays `failed` while the skill stops at the menu. Without a `plan_tracker` tool, keep a plain checklist; behavior is unchanged.
38
37
 
39
38
  ## Harness notes
40
39
 
@@ -64,7 +63,7 @@ These bind every rendered report, menu, and external payload (review bodies, rep
64
63
  - 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`.
65
64
  - Raw command output, drafted payloads except the exact description consent preview, or internal IDs in the rendered report - owner: `reference/report.md`.
66
65
  - An open-PR menu, other than the conflict menu, an own-merge or merge-queued menu, a pending contract-exception menu, or a `--rebase` terminal stop (`stop` and `show evidence` only, `reference/sync.md`), without `fix` while an open blocker exists, or without `fix nits` while a nit exists, when a helper facility exists and the fix-round cap is neither `0` nor reached (a PR already merged or closed at step 1 offers `show evidence` and `stop` only); any menu without `show evidence`, with two `[recommended]`, or with `stop` not last - owner: `reference/decision-menu.md`.
67
- - A local verification run while a binding check is pending, or a second push inside one round - owner: `reference/fix-wave.md` `## Evidence after push`.
66
+ - A CI wait while a blocker is open or before the first report, or a second push inside one round - owner: `reference/post-selection-loop.md` `### Pre-menu refresh`.
68
67
  - The orchestrator resolving a merge conflict itself, or editing or committing a tracked file during a fix wave - owner: `reference/fix-wave.md` `## Conflicts` and `## Wave`.
69
68
  - A helper's duty run in the orchestrator's own context - owner: `## Harness notes`.
70
69
  - Approving your own PR - owner: `reference/decision-menu.md` `## Consent table`.
@@ -12,12 +12,12 @@ Rows are `<n>. <verb> - <consequence>`; every row, `stop` included, carries its
12
12
 
13
13
  - `accept contract change` - invoke the concrete proposal's owning amendment process through `post-selection-loop.md` `### Contract decision`; settle the baseline only after completion
14
14
  - `preserve contract` - reject the concrete proposal and resume only permitted scope-preserving repair through `post-selection-loop.md` `### Contract decision`; keep independent blockers open
15
- - `fix` - retain covered blocker repair during this run until readiness or a new decision boundary (`post-selection-loop.md`); show exact old-to-new description text and require its selection per `findings.md`; apply description targets through the loop's Description repair and file payloads for the named blockers (open blockers by default) through fresh implementer helpers in the provisioned worktree, review the wave before any push, push when `push` is available (`fix-wave.md`); on a `rebased locally` head, lease-push once every carried blocker is resolved (`fix-wave.md` `## Evidence after push`); `fix + nits` composes this verb with `fix nits`
15
+ - `fix` - retain covered blocker repair during this run until readiness or a new decision boundary (`post-selection-loop.md`); apply description targets through the loop's Description repair and file payloads for the named blockers (open blockers by default) through fresh implementer helpers in the provisioned worktree, review the wave before any push, push when `push` is available (`fix-wave.md`); on a `rebased locally` head, lease-push once every carried blocker is resolved (`fix-wave.md` `## Evidence after push`); `fix + nits` composes this verb with `fix nits`
16
16
  - `fix nits` - apply one-shot nit payloads drafted at this pick (`findings.md` `## Drafted payloads`) through fresh implementer helpers in the provisioned worktree, review the wave before any push, push when `push` is available (`fix-wave.md`); `fix + nits` typed with zero open blockers runs as this verb
17
17
  - `push` - push local fix commits (renders only when unpushed commits exist)
18
18
  - `review` - post the blockers as a GitHub review: request-changes on someone else's PR, a comment on your own
19
19
  - `approve` - approve the PR (never your own)
20
- - `approve workflow run` - `gh api --method POST repos/<base-owner>/<base-repo>/actions/runs/<id>/approve` for a held run on the assessed head, then re-poll (`fix-wave.md` `## Evidence after push`)
20
+ - `approve workflow run` - `gh api --method POST repos/<base-owner>/<base-repo>/actions/runs/<id>/approve` for a held run on the assessed head, then re-enter the refresh (`post-selection-loop.md` `### Pre-menu refresh`)
21
21
  - `update branch` - `gh pr update-branch <N>`, then fast-forward the worktree to the new head (`fix-wave.md` `## Conflicts`); renders on a conflict with no wave commit, or when `merge_state_status` is `BEHIND` at the merge preconditions
22
22
  - `merge base` - retain merging the recorded base and resolving conflicts through reviewed helper work and push during this run until readiness or a new decision boundary (`fix-wave.md`)
23
23
  - `merge` - `gh pr merge --match-head-commit <assessed-sha>` with the resolved `merge policy` (default squash); preconditions per `post-selection-loop.md` `### Merge preconditions`
@@ -26,7 +26,7 @@ Rows are `<n>. <verb> - <consequence>`; every row, `stop` included, carries its
26
26
  - `post coverage to ticket` - post the rendered `AC coverage` block as a comment on the source ticket via the resolved tracker verb (`gh issue comment`, the overrides' tracker mapping, or `/skill:linear`); renders only under the `own merge` overlay
27
27
  - `post coverage to PR` - post the same block with `gh pr comment <N> --body-file`; renders only under the `own merge` overlay
28
28
  - `show evidence` - print the evidence record, claim and AC outcomes, dispositions, drafted payloads and replies (`report.md` `## What stays out`)
29
- - `wait` - poll the reviewer run, every **binding** pending check in the resolved set (required or not), `mergeStateStatus` while it is `BLOCKED`, `UNKNOWN`, or `unreadable`, and the comment set, then re-render
29
+ - `wait` - run one bounded `gh pr checks --watch` on every **binding** pending check in the resolved set (required or not), then re-render
30
30
  - `stop` - leave the PR as-is; on a `rebased locally` head run `git reset --hard <pre_head>` before `### Teardown`, discarding the rewrite and any unpushed fix commits, and assert `HEAD == <pre_head>` with a clean tree; a mismatch is the existing hard stop with the error, and the remote stays untouched
31
31
 
32
32
  Compose hint: `Type a number, or compose: "fix 2", "fix nits", "fix + nits", "fix 1 + reply". Not offered: push (needs push to <head_url>:<head_ref>), merge (needs WRITE on <owner>/<repo>).` The first sentence lists only compositions whose every verb is a rendered row: `fix nits` and `fix + nits` appear only when both the `fix` and `fix nits` rows render; no `reply` row, no `fix 1 + reply`; no composable row, `Type a number.` alone. The second sentence names every omitted row as `<verb> (<why it is omitted>)` and is dropped when nothing is omitted. `merge anyway` renders as its own row when `## Availability` allows it, so the rendered-row rule does not apply to it. Offer `revoke fix` and `revoke merge base` compose forms for held grants, persisting only the named revocation through the loop. A composed line never bundles a push-producing verb (`fix`, `fix nits`, `push`, `merge base`) with `merge`. When a failing check withholds `merge`, the hint line also offers `check <name> flaky | real | ci-broken`, which records the disposition on that check (`findings.md` `## Dispositions`): `flaky` lifts the blocker, `real` keeps it until green, `ci-broken` triggers the fallback local run (`ci-broken` records `ci-infrastructure-broken`).
@@ -40,7 +40,7 @@ Rows derive from the digest's `permissions` block (`../verification-brief.md` Se
40
40
  | Row | Available when |
41
41
  |---|---|
42
42
  | `accept contract change`, `preserve contract` | a recorded contract exception is pending and no terminal/sync stop applies; route numeric and typed selections through `post-selection-loop.md` `### Contract decision` |
43
- | `fix` | an open blocker or explicitly requested exact clarification payload exists (a failing-check `P#` included; the wave reports a blocker with no file or description payload as not fixable, `post-selection-loop.md` `### Fix wave`), a helper facility exists (`../SKILL.md` `## Harness notes`), and the fix-round cap is neither `0` nor reached (`fix-wave.md` `## Wave`) |
43
+ | `fix` | an open blocker or explicitly requested exact clarification payload exists (a failing-check `P#` included), a helper facility exists (`../SKILL.md` `## Harness notes`), and the fix-round cap is neither `0` nor reached (`fix-wave.md` `## Wave`) |
44
44
  | `fix nits` | a nit exists, a helper facility exists (`../SKILL.md` `## Harness notes`), and the fix-round cap is neither `0` nor reached (`fix-wave.md` `## Wave`); a `fix` with neither blocker nor requested clarification, or a `fix nits` with no nit, is dropped from the row set and never named in `Not offered:` |
45
45
  | `merge base` | open PR with `mergeable: CONFLICTING` or `mergeStateStatus: BEHIND`, even with zero code blockers; head_pushable true, helpers, remaining budget, and no terminal/sync stop; preserve rebased-locally lease-only restrictions |
46
46
  | `push` | `head_pushable` is true and unpushed wave commits exist and the last pre-push review's carried set (`fix-wave.md` `## Review before push`) held no Critical or Moderate |
@@ -117,7 +117,7 @@ Nits:
117
117
 
118
118
  Verdict: fixable - reviewer run in progress
119
119
 
120
- 1. wait - poll the reviewer run, then re-render [recommended]
120
+ 1. wait - run one bounded CI watch, then re-render [recommended]
121
121
  2. fix nits - apply the one-shot nit payload in the worktree, review the wave, push
122
122
  3. reply - post the drafted reply to maria
123
123
  4. show evidence - gate output, CI run
@@ -52,7 +52,7 @@ Behavior the spec keeps in scope is a blocker until its mechanism ships; a row t
52
52
 
53
53
  ## Dispositions
54
54
 
55
- 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`). An undispositioned failing check is never a target of `fix`; close it by disposition. 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.
55
+ 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.
56
56
 
57
57
  | Disposition | Annotation on the `P#` |
58
58
  |---|---|
@@ -67,10 +67,10 @@ How each disposition changes the menu: `decision-menu.md` `## Overlays`, CI chec
67
67
 
68
68
  ## Drafted payloads
69
69
 
70
- Step 5 drafts, never applies. For every blocker with a file-level fix - code and doc drift alike - draft the concrete edit as a payload keyed to the finding's internal ID. Draft nit payloads on a `fix nits` or `fix + nits` pick, which is the consent: print them in the `show evidence` payload shape and dispatch the wave in the same pick with no second confirmation; before that pick `show evidence` prints only the payloads that exist. For every replyable `C#`, draft the reply. The worktree stays tracked-clean (`git status --porcelain --untracked-files=no` empty) at every menu render; a payload is applied only on a `fix`, `fix nits`, or `fix + nits` pick or a validated retained grant (the same path for code and docs) and dropped at teardown otherwise. A `P#` carried by a `rebased locally` sync record is drafted like any blocker, from the helper's test output and `git show <stopped commit>`; a `P#` with no draftable edit stays open and `fix` reports it as not fixable. The human sees the draft at the `fix` consent and decides whether code or test expectations change; the implementer never decides it.
70
+ Step 5 drafts, never applies. For every blocker with a file-level fix - code and doc drift alike - draft the concrete edit as a payload keyed to the finding's internal ID. Draft nit payloads on a `fix nits` or `fix + nits` pick, which is the consent: print them in the `show evidence` payload shape and dispatch the wave in the same pick with no second confirmation; before that pick `show evidence` prints only the payloads that exist. For every replyable `C#`, draft the reply. The worktree stays tracked-clean (`git status --porcelain --untracked-files=no` empty) at every menu render; a payload is applied only on a `fix`, `fix nits`, or `fix + nits` pick or a validated retained grant (the same path for code and docs) and dropped at teardown otherwise. A `P#` carried by a `rebased locally` sync record is drafted like any blocker, from the helper's test output and `git show <stopped commit>`; a `P#` whose smallest fix needs another repo, infrastructure, or a credential stays open. The human sees the draft at the `fix` consent and decides whether code or test expectations change; the implementer never decides it.
71
71
 
72
72
  Extend each finding-keyed evidence pack with `target: file | description`. For file targets retain the concrete edit and scoped test files. For description targets store `{ finding_id, contributor_ids, assessed_head, original_body, old_text, new_text, replacement_body, source_evidence }` with exact old-to-new text and unrelated body text preserved. Keep independent contributions under all their IDs when one finding combines a claim and test/scope/check gap; close only source-backed resolved claim contributions, never the whole combined finding from a body edit. Judge source: pr gaps against original_intent, not the shortened body.
73
73
 
74
- Every new description proposal requires exact-text selection, even under a broad fix grant. Any changed head/body snapshot requires renewed selection, not just a material change. Show compact exact old-to-new text at consent and full replacement body under `show evidence`; decline writes nothing. A requested factual clarification enables a clarification-only `fix` without minting a blocker or ongoing grant. Never draft an unsolicited style rewrite. Apply description targets through `post-selection-loop.md` `### Description repair`, not a file helper.
74
+ 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. A finding whose smallest fix needs another repo, infrastructure, or a credential stays open with the implementer's `open - needs <what>` sentence. A `fix` pick or a validated retained fix grant applies a description payload in the same round as 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`. A requested factual clarification enables a clarification-only `fix` without minting a blocker or ongoing grant. Never draft an unsolicited style rewrite.
75
75
 
76
76
  A posted review body is composed at post time from the blockers being addressed - one summary sentence, then the numbered items, ending on the fix or asked action.
@@ -28,11 +28,11 @@ A worktree holding unpushed wave commits never shows `update branch`. The orches
28
28
 
29
29
  `pre_wave_head` was recorded before the first `## Conflicts` check. A round is one pass over the open payloads plus one `## Review before push`. The round cap is `closureReview.maxFixRounds`, read with `gauntlet_setting({ key: "closureReview" })` when that tool exists, else 3; a cap of `0` omits `fix` and `fix nits` from the menu, named as `fix, fix nits (maxFixRounds is 0)` in the `Not offered:` sentence. The round count is per run; at the cap `fix` and `fix nits` are omitted, named `fix, fix nits (round cap reached)` in `Not offered:`.
30
30
 
31
- Increment `repair.rounds_used` before the first body write or helper dispatch and persist `repair.wave` with its current stage. Count file, description-only, and conflict-only attempts under the same cap; cap 0 disables every repair target. Initial combined base/file/body work shares one increment and one push. Post-review resolution or completed unsuccessful retry spends another pass; paused-action resumption, context restoration, refresh, and polling do not increment or reset usage. Stop automatic work at exhaustion; a grant never raises the cap. Update apply/review/push/poll checkpoints and clear the wave only after reconciliation and settlement of any `post-selection-loop.md` `### No-progress obstacle`.
31
+ Increment `repair.rounds_used` before the first body write or helper dispatch and persist `repair.wave` with its current stage. Count file, description-only, and conflict-only attempts under the same cap; cap 0 disables every repair target. Initial combined base/file/body work shares one increment and one push. Post-review resolution or completed unsuccessful retry spends another pass; paused-action resumption, context restoration, refresh, and a watch or the `P#` it mints do not increment or reset usage. Stop automatic work at exhaustion; a grant never raises the cap. Update apply/review/push checkpoints and clear the wave only after reconciliation and settlement of any `post-selection-loop.md` `### No-progress obstacle`.
32
32
 
33
33
  For each file payload in review order, dispatch one fresh implementer helper with `cwd` the PR worktree. Its task holds:
34
34
 
35
- - the finding's evidence pack (`findings.md` `## Drafted payloads` shape) and the instruction to apply the consented payload - or, for a reviewer finding that has no drafted payload, the reviewer's finding text - never to re-solve the finding;
35
+ - the finding's evidence pack (`findings.md` `## Drafted payloads` shape) and the instruction to apply the consented payload - or, for a reviewer finding that has no drafted payload, the reviewer's finding text - never to re-solve the finding. 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.
36
36
  - `SCOPED_TEST_COMMANDS`, resolved once per wave from the merge-base copies of the overrides file, then `AGENTS.md` (`git show "$MB:<path>"`, the trust rule of `assessment.md` `## Configuration`): a scoped runner is a documented test command carrying a `<paths>` or `<files>` placeholder, or a command the doc labels scoped, in any section of either file (`## PR gate`, `## Project`, `## routing`, `## test-driven-development`, `## verification-before-completion` alike); keep its cwd and flags verbatim; with several runners take the one whose directory prefix matches the payload's test file; substitute the test files the payload touches or writes, and for a `P#` carried by a `rebased locally` sync record the failing test file named in that record; no runner or no test file -> `none`. Never the resolved `verification command`, whatever a consumer sentence says about fix waves - that command runs only where `../verification-brief.md` Section B selects a local-run row; `none` -> the helper reports `no scoped test` and the pre-push reviewer is its only gate;
37
37
  - the commit rule: commit on the PR branch only when the scoped test passes, or when `SCOPED_TEST_COMMANDS` is `none`, one commit per payload, subject naming the fix; otherwise discard its edits (`git checkout -- <its files>`, remove files it created) and return `open - <why>`;
38
38
  - the report shape: the scoped test's failing run before the edit and passing run after it; a doc-only payload with no test reports `no scoped test` and its diff, and the reviewer below is its only gate.
@@ -51,8 +51,6 @@ Mark a finding resolved only from a `resolved` closure line; the orchestrator ne
51
51
 
52
52
  Run `## Conflicts` once more, then push to the recorded destination: `git -C <worktree> push --no-follow-tags <head_url> HEAD:refs/heads/<head_ref>`. On a `rebased locally` head push only when every carried `P#` has a `resolved` closure line, with `--force-with-lease=<head_ref>:<pre_head>`; otherwise the commits stay unpushed and the menu re-renders with the open `P#`. A refusal naming the lease (`stale info`): `git reset --hard <pre_head>`, assert `HEAD == <pre_head>` and a clean tree; a mismatch is a hard stop with the error, record `sync: failed - push rejected: <first server line>`, and render `stop` and `show evidence` only - the fix commits are discarded with the rewrite, and the reason says so. After a successful lease push rewrite the sync record to the plain `rebased ...` form. Report any other rejected push verbatim and re-render the menu with the commits unpushed.
53
53
 
54
- On a newly successful push, follow the poll deadline owned by `post-selection-loop.md` `### Wait course`: persist the new window together with `repair.wave.pushed_head` before checking expiry or polling; re-entry for an already recorded push reuses that deadline. Apply the owner's expiry checks and timeout obstacle route; poll the pushed head only, every 30 seconds within that window: `gh pr view <N> --json headRefOid,statusCheckRollup,mergeStateStatus` and `gh run list -R <base-owner>/<base-repo> -c <head> --json databaseId,status,conclusion`. A moved `headRefOid` stops the poll and takes the head-move rule (re-enter step 3, `post-selection-loop.md` intro). Normalize first: a `CheckRun` is terminal at `status: COMPLETED` with its `conclusion`; a `StatusContext` maps `state` `SUCCESS` to success, `FAILURE` and `ERROR` to blocking, `PENDING` and `EXPECTED` to pending; apply the `ci checks` filter and the reviewer-check exception (`../verification-brief.md` Section B) before the table, then the binding classification of every pending check on the pushed head's `mergeStateStatus`.
55
-
56
- Resolve the normalized set through `../verification-brief.md` `## Section B - Verifier` (Evidence resolution) - the same table the first pass uses. When the re-resolve moves the evidence from `source: pending` to CI-sufficient (an approved held run went green, or a `wait` ended), dispatch a fresh Section B helper in claim-check-only mode (`../verification-brief.md` Section B) before rendering the menu. `approve workflow run` executes `gh api --method POST repos/<base-owner>/<base-repo>/actions/runs/<id>/approve`, then re-polls. The evidence block records the outcome and, when a local-run row fires, dispatch a fresh Section B helper; the evidence block records which trigger fired: `local run: no conclusive check`, `local run: held run not approvable`, or `local run: local verification: always`.
54
+ On a newly successful push, persist `repair.wave.pushed_head`, run no poll (the one `gh pr view` and `gh run list` read belongs to the refresh), and re-enter step 5 through `post-selection-loop.md` `### Re-render` step 1 (the pre-menu refresh runs once; its watch guard decides, by the brief's binding classification, whether a watch follows). No claim re-check and no whole-wave review runs after an own push; the description recheck of `### Description repair` is the one exception. When the refresh moves the evidence from `source: pending` to CI-sufficient, dispatch a fresh Section B helper in claim-check-only mode (`../verification-brief.md` Section B) before rendering the menu. `approve workflow run` executes `gh api --method POST repos/<base-owner>/<base-repo>/actions/runs/<id>/approve`, then re-enters the refresh; an `action_required` run renders `approve workflow run` before any watch, and `### Re-render` reconciliation is unchanged. When a local-run row fires, dispatch a fresh Section B helper; the evidence block records which trigger fired: `local run: no conclusive check`, `local run: held run not approvable`, or `local run: local verification: always`.
57
55
 
58
56
  Then run the own-push sequence of `post-selection-loop.md` `### Re-render`: the comment refetch and reconciliation, a fresh reviewer helper for any eligible comment delta, and the menu rendered from the closure lines for the exact pushed SHA. No claim re-check and no whole-wave review runs after an own push except the affected-claims-only description recheck in `post-selection-loop.md` `### Description repair`; preserve unrelated dispositions. The sequence runs the pre-menu refresh as `post-selection-loop.md` `### Re-render` step 1 (`### Pre-menu refresh`) - an approval dismissed by the push flips a bound viewer to `BLOCKED`, and the menu says so.
@@ -35,12 +35,12 @@ After fresh evidence/permission assessment and eligible comment source review, v
35
35
  | Completed no-progress result with unchanged failed prerequisite | Render the obstacle through `### No-progress obstacle` before any retained repair routing. |
36
36
  | Reconciled active pre-push wave has carried items and no unresolved obstacle, authorized by an explicit current or recorded still-valid pick or a matching held grant that has not been revoked, under the existing continuation validation | Retry the carried set through `fix-wave.md` `## Review before push`, including under a named grant; preserve its cap, scoped tests, fresh helpers, and single push. `revoke fix` invalidates the old fix pick as authority; require a restored one-shot nit wave's recorded still-valid pick, not an invented broad grant. Route missing or invalid authority to the existing decision obstacle. |
37
37
  | Covered conflict or behind-base repair with merge-base grant | Run the helper-owned base course in `fix-wave.md`, preserving the selected strategy. |
38
- | Covered source-backed file blockers with fix grant | Run the existing wave; description targets still need exact selection per `findings.md`. |
39
- | Held repair grant and only readiness evidence for the authorized repair course is pending, including after its payloads were pushed, within current deadline | Continue bounded `### Wait course`; without a grant require explicit wait. |
38
+ | Covered source-backed blockers (file or description payload) with fix grant | Run the existing wave; a description-only round goes through `### Description repair`; a finding the implementer returned `open - needs <what>` is not covered; it stays open through `### No-progress obstacle` until a new explicit pick names it. |
39
+ | Held repair grant and only readiness evidence for the authorized repair course is pending, including after its payloads were pushed, within current deadline | Nothing extra: the watch guard in `### Pre-menu refresh` decides whether a watch runs. |
40
40
  | Every merge prerequisite holds | Render fresh final menu; never automatically merge or approve. |
41
41
  | Missing decision, budget, permission, input, failed refresh or expired deadline | Render the concrete obstacle; preserve valid grants without silently renewing the deadline. |
42
42
 
43
- At this boundary and before every external write, fetch actual body and live `baseRefName` with head/state. Compare live `baseRefName` against `consent.target.baseRefName` before consuming authority; pause on an unreadable or changed base without overwriting `consent.target`, choosing a new base, or continuing against the old base. A same-head body edit invalidates old readiness and selected merge; narrowly recheck changed material claims while preserving original intent. Refresh changed proposals and request renewed exact selection. Keep the record through ready-menu rendering; readiness lost later can resume covered work but final merge consent is fresh.
43
+ At this boundary and before every external write, fetch actual body and live `baseRefName` with head/state. Compare live `baseRefName` against `consent.target.baseRefName` before consuming authority; pause on an unreadable or changed base without overwriting `consent.target`, choosing a new base, or continuing against the old base. A same-head body edit invalidates old readiness and selected merge; narrowly recheck changed material claims while preserving original intent. Refresh changed proposals; the next `fix` round applies them. Keep the record through ready-menu rendering; readiness lost later can resume covered work but final merge consent is fresh.
44
44
 
45
45
  ### No-progress obstacle
46
46
 
@@ -50,11 +50,11 @@ Check this checkpoint before retained repair routing. Keep grants and `repair.ro
50
50
 
51
51
  ### Description repair
52
52
 
53
- For an exactly selected payload, perform external-write checks, fetch actual head/body, and compare both with the proposal. Any snapshot change, including an own push, requires renewed selection before writing. Count the pass per `fix-wave.md` before this first mutation. Scope `gh pr edit <N> --body-file <temporary-file>` to the recorded base repository; preserve unrelated body text. Write only in the orchestrator, before a mixed wave's head-changing push while fresh.
53
+ For a description payload applied on a `fix` pick or a validated retained fix grant, perform external-write checks, fetch actual head/body, and compare both with the proposal. A body or head that changed since the proposal: the old proposal is invalid; re-propose from the current body at the current head and write nothing this round; the next `fix` round applies it. Count the pass per `fix-wave.md` before this first mutation. Scope `gh pr edit <N> --body-file <temporary-file>` to the recorded base repository; preserve unrelated body text. Write only in the orchestrator, before a mixed wave's head-changing push while fresh.
54
54
 
55
55
  Read back actual head/body and require expected text, unchanged head, and a fresh Section B `description recheck` helper before resolving only the claim contribution. Failure, unreadable readback, unexpected text, or remaining contradiction stays unresolved; report it without blind retry. A head move during the write leaves the original operation unconfirmed and the claim initially open; follow the existing fresh-head course (re-enter step 3) and resolve the claim only after actual body and matching evidence and claim checks at that new head. Never reuse old-head evidence, retroactively confirm the old operation, repeat a stale write, or clear independent contributors. API success alone is not closure. No file implementer, empty commit, or full suite runs for body-only work. Keep successful file commits independent of body failures.
56
56
 
57
- Record mixed-pass potentially affected claim IDs in `repair.wave.affected_claims`; before readiness narrowly recheck them against actual pushed head/body and that head's evidence. Preserve unrelated dispositions and independent test/scope/check contributions. A new contradiction gets a new exact proposal and selection. This is the sole relevant exception to own-push claim carry, not whole-wave review. Preserve evidence as specified by the brief's recheck mode. A resolved unchanged claim gets no repeated correction.
57
+ Record mixed-pass potentially affected claim IDs in `repair.wave.affected_claims`; before readiness narrowly recheck them against actual pushed head/body and that head's evidence. Preserve unrelated dispositions and independent test/scope/check contributions. A new contradiction gets a new proposal, applied on the next `fix` round. This is the sole relevant exception to own-push claim carry, not whole-wave review. Preserve evidence as specified by the brief's recheck mode. A resolved unchanged claim gets no repeated correction.
58
58
 
59
59
  Treat pre-write comparison and readback as stale-write checks, not atomic compare-and-swap: a concurrent edit inside the read/write interval remains a race; never overwrite an already observed change.
60
60
 
@@ -80,9 +80,9 @@ Before every external write, re-fetch `headRefOid`, `state`, `mergeable`, and `m
80
80
 
81
81
  ### Fix wave
82
82
 
83
- For a `fix` pick, take the drafted payloads (`findings.md` `## Drafted payloads`) for the named blockers - all open blockers by default; `fix nits` takes nit payloads only, drafted at this pick; `fix + nits` both. A finding closed by disposition is skipped. Route selected description targets through `### Description repair`. A failing check or finding with no drafted file or description edit is reported as not fixable by this verb and stays open.
83
+ A retained grant never re-dispatches a finding the implementer returned `open - needs <what>`, and never starts a round whose only open blockers are such findings: render the report and menu instead. For a `fix` pick, take the drafted payloads (`findings.md` `## Drafted payloads`) for the named blockers - all open blockers by default; `fix nits` takes nit payloads only, drafted at this pick; `fix + nits` both. A finding closed by disposition is skipped. Route description targets through `### Description repair`.
84
84
 
85
- Apply per `fix-wave.md`: the local conflict check, one fresh implementer helper per payload with scoped tests only, the pre-push reviewer with its closure lines, the push, and the evidence poll. The orchestrator never edits a tracked file and never commits. When `head_pushable` is false, the wave's commits stay in the local `pr-<N>` worktree: report the branch name and re-enter step 5.
85
+ Apply per `fix-wave.md`: the local conflict check, one fresh implementer helper per payload with scoped tests only, the pre-push reviewer with its closure lines, and the push. The orchestrator never edits a tracked file and never commits. When `head_pushable` is false, the wave's commits stay in the local `pr-<N>` worktree: report the branch name and re-enter step 5.
86
86
 
87
87
  `approve workflow run` and `update branch` execute per `fix-wave.md` (`## Evidence after push`, `## Conflicts`). Execute `review`, `reply`, `approve`, `post coverage to ticket`, and `post coverage to PR` via `gh pr review`, `gh api`, `gh issue comment`, `gh pr comment`, or the resolved tracker tool, non-interactively, with the drafted payload - after the output done-check below.
88
88
 
@@ -108,7 +108,7 @@ A post is one write of that block, verbatim; a post that succeeded cannot be pic
108
108
 
109
109
  After every push or any mutation that can change readiness (fix wave pushed, PR head moved), re-sync the worktree. On an own push, after `fix-wave.md` `## Evidence after push`, run steps 1-5 below and render the menu from the pre-push reviewer's closure lines for the exact pushed SHA, where a blocker whose closure line reads `resolved` leaves the rendered list while its internal ID stays in the ledger and new findings continue each sequence; no claim re-check and no whole-wave review runs after an own push except the narrow affected-claim recheck in `### Description repair`. On every other head move, re-enter step 3, then run steps 1-5 below - the last read before the menu renders:
110
110
 
111
- 1. Run the pre-menu refresh (`### Pre-menu refresh`), then re-run the Section A comment fetches (`../verification-brief.md`: both `--paginate` calls, plus the GraphQL `reviewThreads` query when the initial gather used it), one `gh run view` per placeholder row, and the reviewer-run `gh run list` when a reviewer workflow is known. Read-only.
111
+ 1. Run the pre-menu refresh (`### Pre-menu refresh`) once. Then re-run the Section A comment fetches (`../verification-brief.md`: both `--paginate` calls, plus the GraphQL `reviewThreads` query when the initial gather used it), one `gh run view` per placeholder row, and the reviewer-run `gh run list` when a reviewer workflow is known (after an own push, use the refresh's `actions_runs[]` instead of a second run-list call). Read-only.
112
112
  2. Diff the fresh set against the `C#` ledger (`findings.md` `## Namespaces`) by `id` and `updated_at`:
113
113
  - same `id`, same `updated_at` -> unchanged: keep the existing `C#`.
114
114
  - same `id`, different `updated_at` -> edited: mint a new `C#`; the old one is `superseded by C<new>`. An `updated_at` change with an identical body (reaction, revert) still counts as edited.
@@ -123,15 +123,15 @@ After every push or any mutation that can change readiness (fix wave pushed, PR
123
123
 
124
124
  ### Pre-menu refresh
125
125
 
126
- The first read of step 5, before the report and the menu render from one state - the first pass included (a long local run or review can stale the gather), every `### Re-render` entry, the post-`wait` re-fetch, `update branch`, a `merge base` round, and a fix-wave push (`fix-wave.md` `## Evidence after push`). Run `gh pr view <N> --json headRefOid,state,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup` and `gh run list -R <owner>/<repo> -c <headRefOid> --json databaseId,status,conclusion,workflowName,url`. While the sync record is `rebased locally`, compare the fetched `headRefOid` against the record's `<pre_head>` and render from that alone: a move takes the lease-refusal path of `fix-wave.md` `## Evidence after push` (`git reset --hard <pre_head>`, assert `HEAD == <pre_head>` and a clean tree, record `sync: failed - remote head moved`, render `stop` and `show evidence` only); an unmoved head keeps `status_checks[]` and `actions_runs[]` as they are, skips the evidence re-resolve, and ignores `mergeable` and `mergeStateStatus` changes - `source: pending` holds until the lease push rewrites the record; a `state` change to closed or merged renders `stop` and `show evidence` only. On a pushed head: head moved -> the head-move rule (re-enter step 3). `state` or `mergeable` changed (head unchanged) -> route through `### Compare-and-swap` re-assessment. Head unchanged with `state` and `mergeable` unchanged -> replace `permissions.merge_state_status`, `pr.reviewDecision`, `status_checks[]`, and `actions_runs[]` in the digest together, re-normalize and re-classify every pending check (`../verification-brief.md` Section B, binding classification), and re-resolve the Evidence resolution table on the fresh set, so a check whose run completed since the last menu is never paired with its cached run status; when that re-resolve moves `source: pending` to CI-sufficient, dispatch the Section B helper in claim-check-only mode (`../verification-brief.md` Section B) before rendering. A `gh` failure keeps the prior values, classifies every pending check as binding (`../verification-brief.md` Section B, binding classification), and renders the `merge state` overlay (`decision-menu.md` `## Overlays`) through `## Withhold reason resolver` reason 2 (locator `merge state not refreshed (<reason>)`). Also run `gh pr view <N> --json headRefOid,body,baseRefName` at this next-action boundary and apply `### Next action` target and body freshness before readiness. The refresh is read-only and never mints `C#` rows - comment reconciliation stays in `### Re-render`.
126
+ The first read of step 5, before the report and the menu render from one state - the first pass included (a long local run or review can stale the gather), every `### Re-render` entry, the post-`wait` re-fetch, `update branch`, a `merge base` round, and a fix-wave push (`fix-wave.md` `## Evidence after push`). Run exactly one `gh pr view <N> --json headRefOid,state,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,body,baseRefName,number,title,author,isDraft,headRefName,isCrossRepository,files,additions,deletions,commits,reviews,closingIssuesReferences,headRepository,maintainerCanModify` and one `gh run list -R <owner>/<repo> -c <headRefOid> --json databaseId,status,conclusion,workflowName,url` (Section A's fixed fields, folding the `gh pr view <N> --json headRefOid,body,baseRefName` fields into the single call). While the sync record is `rebased locally`, compare the fetched `headRefOid` against the record's `<pre_head>` and render from that alone: a move takes the lease-refusal path of `fix-wave.md` `## Evidence after push` (`git reset --hard <pre_head>`, assert `HEAD == <pre_head>` and a clean tree, record `sync: failed - remote head moved`, render `stop` and `show evidence` only); an unmoved head keeps `status_checks[]` and `actions_runs[]` as they are, skips the evidence re-resolve, and ignores `mergeable` and `mergeStateStatus` changes - `source: pending` holds until the lease push rewrites the record; a `state` change to closed or merged renders `stop` and `show evidence` only. On a pushed head: head moved -> the head-move rule (re-enter step 3). `state` or `mergeable` changed (head unchanged) -> route through `### Compare-and-swap` re-assessment. Head unchanged with `state` and `mergeable` unchanged -> replace `permissions.merge_state_status`, `pr.reviewDecision`, `status_checks[]`, and `actions_runs[]` in the digest together, re-normalize and re-classify every pending check (`../verification-brief.md` Section B, binding classification), and re-resolve the Evidence resolution table on the fresh set, so a check whose run completed since the last menu is never paired with its cached run status; when that re-resolve moves `source: pending` to CI-sufficient, dispatch the Section B helper in claim-check-only mode (`../verification-brief.md` Section B) before rendering. A `gh` failure keeps the prior values, classifies every pending check as binding (`../verification-brief.md` Section B, binding classification), and renders the `merge state` overlay (`decision-menu.md` `## Overlays`) through `## Withhold reason resolver` reason 2 (locator `merge state not refreshed (<reason>)`). Apply `### Next action` target and body freshness from that same read before readiness. The refresh is read-only and never mints `C#` rows - comment reconciliation stays in `### Re-render`.
127
127
 
128
- ### Wait course
128
+ Watch guard: when this is not the first report, Blockers are empty, and a binding check is pending (open nits do not count), run `### Wait course` once before rendering; a `wait` pick runs it too. After the watch returns, for any reason, re-run the two reads above once and re-resolve the Evidence resolution table (`../verification-brief.md` Section B). CI-sufficient -> the claim-check-only helper for `pending` claims (named in `fix-wave.md` `## Evidence after push`), then the menu. A failing check in the resolved set -> one `P#` per check with its failing line from `gh run view <id> -R <repo> --log-failed`, a drafted payload (`findings.md` `## Drafted payloads`), and the menu; the `P#` closes on the reviewer's `resolved` line like any blocker and the next watch re-mints it when the check still fails; the watch mints no round (`closureReview.maxFixRounds` is untouched). Still pending -> the menu with `wait` as row 1. A `gh` read that fails is a failed refresh under the existing `### Re-render` rule; a head that moved during the watch re-enters step 3. An `action_required` run renders `approve workflow run` instead of a watch.
129
129
 
130
- Own the existing poll window here for the first-pass evidence poll, after-push poll, and selected or retained Wait entry. Start a new window only on the first poll with a null deadline, an actual newly successful authorized push, or a new explicit `wait` selection. Persist `repair.poll_deadline` as an absolute timestamp equal to current time plus the resolved `timeout minutes` (default 15) before checking expiry or polling; preserve it through re-entry and context restoration. Record the new deadline with the successful push checkpoint or direct wait selection, not on replay. On re-entry to the same active window, including the after-push course for an already recorded push, reuse the saved deadline. A retained grant, repeated menu/Wait entry, or expiry alone never renews it. A held grant alone never starts unrelated polling; retained entry requires the authorized-course pending-evidence row in `### Next action`.
130
+ ### Wait course
131
131
 
132
- Before any poll, check the saved deadline; when expired, take the completion/timeout reconciliation below and render the concrete obstacle through `### Next action`, without another poll. Run a sequence of short bounded calls - never one long bash call. Each iteration: `gh run view -R <repo> <run-id> --json status,conclusion` for every tracked run (placeholder-linked and head-listed), and `gh pr view <N> -R <repo> --json statusCheckRollup,mergeStateStatus` while any pending check in the resolved set is binding when classified against the polled rollup and the polled `mergeStateStatus`, or the polled `mergeStateStatus` is `BLOCKED`, `UNKNOWN`, or `unreadable`; when any row has no parsable URL, or its run is completed while the prefix persists, one comment refetch as well; then sleep 30 s. Use each polling refetch to classify binding checks and compare the loop's stop condition against the polled values; leave the digest and `C#` ledger untouched until the completion/timeout reconciliation below - this preserves persisted digest state, not the loop's comparison values. Check the persisted absolute deadline between iterations (the same timeout knob as the local verification run). Stop when every tracked run is completed and no pending check is binding against the polled values and the polled `mergeStateStatus` is none of `BLOCKED`, `UNKNOWN`, `unreadable` and no row is in the "completed `success`, prefix persists" state, or the deadline passes.
132
+ Persist `repair.poll_deadline` only on the first watch with a null deadline or a new explicit `wait` selection as current time plus the resolved `timeout minutes` (default 15); preserve it through re-entry and context restoration. Before the call, if the deadline has already passed, run no call and render the timeout obstacle with `wait` as row 1. A retained grant, repeated menu/Wait entry, or expiry alone never renews it. A `wait` pick on an expired window first applies the expiry step below: a completed-`success`/prefix-persists placeholder becomes `reviewer failed (stale placeholder)` and opens no new window; only a check still running gets one. A held grant alone never starts a watch; the watch guard in `### Pre-menu refresh` or an explicit `wait` pick does.
133
133
 
134
- Then run `### Pre-menu refresh` (it re-fetches `statusCheckRollup`, `headRefOid`, `state`, `mergeable`, `mergeStateStatus`). If the head advanced or state/mergeability changed, route through compare-and-swap re-assessment before reusing evidence or reviewing comments; otherwise re-resolve the brief's Evidence table on the fresh rollup; dispatch a fresh Section B helper for a local run only when the re-resolved table selects a local-run row (Fallback, Held run not approvable, or Opt-out - `../verification-brief.md` Evidence resolution) and no evidence exists yet for this head - otherwise the existing evidence stands. On completion or timeout, run steps 2-5 of `### Re-render` plus step 1's comment and reviewer-run reads - the pre-menu refresh already ran - and re-render; do not re-run claim-check or whole-diff review solely because the head did not move. On timeout: rows in the completed-`success`/prefix-persists state become `reviewer failed (stale placeholder)` (brief Section C placeholder table); every other `pending` row stays `pending`, merge stays withheld, `wait` renders as row 1 again for a new explicit selection; render the expired-window obstacle through `### Next action`, never automatically re-enter Wait.
134
+ The watch is one call bounded by the remaining window through the Safety contract ladder of `../verification-brief.md` Section B (harness bash timeout, else `timeout`/`gtimeout`, else background-and-kill), never unbounded: `gh pr checks <N> -R <base-owner>/<base-repo> --watch`. Its exit code is not read; the `### Pre-menu refresh` watch guard reads the refreshed digest. On expiry every `pending` row stays `pending`, merge stays withheld, and `wait` renders as row 1 for a new explicit selection; rows in the completed-`success`/prefix-persists state become `reviewer failed (stale placeholder)` (brief Section C placeholder table). On completion or timeout, run steps 2-5 of `### Re-render` plus step 1's comment and reviewer-run reads after the watch guard's refresh, then re-render.
135
135
 
136
136
  ### Output done-check
137
137
 
@@ -48,7 +48,7 @@ Two states: `mergeable` or `fixable`. `mergeable` carries the evidence clause fr
48
48
 
49
49
  Verbatim command output stays in its `log_path` file and never prints; `show evidence` prints its `show evidence: <log_path>` line instead. CI run URLs and conclusions (the pending-reviewer locator in `PR comments` is the one URL that prints in the report), drafted file edits and full description bodies, drafted replies, matched claims, per-row AC outcomes, internal IDs, and disposition annotations print only under the `show evidence` pick. A clean run with a spec renders `Delivers`, the verdict line, and the menu - about four lines.
50
50
 
51
- Print the compact exact old-to-new description preview before selection at the rendered consent menu, including a new payload under a held fix grant; keep the full replacement body under `show evidence`. Uncertainty alone preserves the mergeable verdict.
51
+ Print the compact exact old-to-new description preview under its blocker; keep the full replacement body under `show evidence`. Uncertainty alone preserves the mergeable verdict.
52
52
 
53
53
  `show evidence` prints `state: <absolute-path>` for the authoritative continuation record, then, in this order: the evidence record (CI: each satisfying check's name, conclusion, SHA, run URL; local: each run's command, `result`, `exit_code`, and one `show evidence: <log_path>` line pointing at its captured output - never the output itself); claim dispositions; AC outcomes per row and the `cross-check:` line (`assessment.md` `## Select the scope contract`); check dispositions; drafted payloads keyed by the blocker or nit number they fix; drafted replies keyed by the `PR comments` item they answer.
54
54
 
@@ -52,9 +52,9 @@ A refusal whose message names the lease (`stale info`, the remote head moved sin
52
52
 
53
53
  ## Re-gather
54
54
 
55
- Re-run every step-1 forge read for the PR (`../verification-brief.md` Section A fixed command set): `headRefOid`, `mergeable`, `mergeStateStatus`, `reviewDecision`, status checks and `actions_runs`, commits, changed files and diff, comments and reviews; the step-1 ticket reads are not repeated; re-run `assessment.md` `## Select the scope contract` on the pushed head. Unreadable fields fail closed as in step 1. Re-resolve the configuration ladder (`assessment.md` `## Configuration`) at `git merge-base origin/<baseRefName> HEAD` - `baseRefName` stays the trust source even when `<base>` names another branch. Run no CI poll here: step 3's first pass is the single poll window (every 30 s for up to `timeout minutes`; a binding check still pending at the limit renders the `verification evidence pending` overlay (`../verification-brief.md` Section B, binding classification), never green, and a head with no check, or only not-binding pending checks, takes the `Fallback` row) and step 3 resolves the pushed head as any assessed head - the sync push is not an own push for `### Re-render` and the `Fix wave` row of Section B does not apply; a head that moves during that poll takes the existing head-move rule (`post-selection-loop.md` `### Re-render`), with step 2's divergence stop as the backstop. Red CI on the pushed head triggers no automatic fix: step 3 records the failing checks and the menu offers `fix` - `fix [recommended]` only when `decision-menu.md` and `../verification-brief.md` Section B make it `[recommended]`. Set the digest's `sync` field (`../verification-brief.md` Section A), close the `sync` stage `complete`, and enter step 3 with the refreshed digest.
55
+ Re-run every step-1 forge read for the PR (`../verification-brief.md` Section A fixed command set): `headRefOid`, `mergeable`, `mergeStateStatus`, `reviewDecision`, status checks and `actions_runs`, commits, changed files and diff, comments and reviews; the step-1 ticket reads are not repeated; re-run `assessment.md` `## Select the scope contract` on the pushed head. Unreadable fields fail closed as in step 1. Re-resolve the configuration ladder (`assessment.md` `## Configuration`) at `git merge-base origin/<baseRefName> HEAD` - `baseRefName` stays the trust source even when `<base>` names another branch. Run no CI watch here: a binding check still pending renders the `verification evidence pending` overlay (`../verification-brief.md` Section B, binding classification), never green, and a head with no check, or only not-binding pending checks, takes the `Fallback` row and step 3 resolves the pushed head as any assessed head - the sync push is not an own push for `### Re-render` and the `Fix wave` row of Section B does not apply; a head that moves before step 3 takes the existing head-move rule (`post-selection-loop.md` `### Re-render`), with step 2's divergence stop as the backstop. Red CI on the pushed head triggers no automatic fix: step 3 records the failing checks and the menu offers `fix` - `fix [recommended]` only when `decision-menu.md` and `../verification-brief.md` Section B make it `[recommended]`. Set the digest's `sync` field (`../verification-brief.md` Section A), close the `sync` stage `complete`, and enter step 3 with the refreshed digest.
56
56
 
57
- On a `rebased locally` head the forge re-read returns `<pre_head>` as `headRefOid`; keep it in the record and leave the digest's `headRefOid` at the local HEAD, which the scope-contract read and step 3 use, and take the digest's changed files and diff from `git diff origin/<base>...HEAD`. Mint one blocker `P#` per `scoped tests red in` clause before step 3 - evidence the helper's scoped-test output, the blocker contract of `findings.md` (IDs append-only, surviving re-renders); skip the step-3 check poll and the local verification run - step 3 records `source: pending` for the local head (no claims) - the carried blockers are the verification evidence and the verdict is `fixable`; `plan_tracker` closes the `sync` stage `complete`.
57
+ On a `rebased locally` head the forge re-read returns `<pre_head>` as `headRefOid`; keep it in the record and leave the digest's `headRefOid` at the local HEAD, which the scope-contract read and step 3 use, and take the digest's changed files and diff from `git diff origin/<base>...HEAD`. Mint one blocker `P#` per `scoped tests red in` clause before step 3 - evidence the helper's scoped-test output, the blocker contract of `findings.md` (IDs append-only, surviving re-renders); skip the local verification run - step 3 records `source: pending` for the local head (no claims) - the carried blockers are the verification evidence and the verdict is `fixable`; `plan_tracker` closes the `sync` stage `complete`.
58
58
 
59
59
  ## Failure path
60
60
 
@@ -55,7 +55,7 @@ never a partial digest.
55
55
  Missing PR number: `gh pr view --json number,url` on the current branch; no PR found -> STOP and report. Issue reference: the explicit argument, else `closingIssuesReferences`, then the branch name, PR title, PR body, and commit subjects; none found -> `issue_ref: null`. The Gatherer only resolves the reference - fetching the ticket is step 2 (`reference/assessment.md` `## Fetch the ticket`), after the issue-fetch command resolves from the merge-base.
56
56
 
57
57
  `mergeable` is reported as-is, including `UNKNOWN` - the Gatherer runs before
58
- provisioning, so it never re-polls; step 2 re-polls once after provisioning (`reference/assessment.md`). Bot author noted
58
+ provisioning, so it never re-reads; step 2 re-reads once after provisioning (`reference/assessment.md`). Bot author noted
59
59
  (`author_is_bot`). Capture each status check's `isRequired` where exposed (digest field: `required`).
60
60
 
61
61
  **Gather digest output schema (normative):**
@@ -69,10 +69,10 @@ provisioning, so it never re-polls; step 2 re-polls once after provisioning (`re
69
69
  - consent.fix: null | { scope: "all" or an array of stable finding IDs, granted_by: string }
70
70
  - consent.merge_base: null | { granted_by: string } # base is consent.target.baseRefName
71
71
  - repair.rounds_used: <nonnegative integer, initially 0>
72
- - repair.poll_deadline: null | <absolute timestamp for the existing poll window; reference/post-selection-loop.md ### Wait course>
73
- - repair.wave: null | { pre_wave_head, pushed_head, selected_ids, affected_claims, stage: apply | review | push | poll, no_progress: { failed_prerequisite, observed_value, result_path }? }
72
+ - repair.poll_deadline: null | <absolute timestamp for the watch window; reference/post-selection-loop.md ### Wait course>
73
+ - repair.wave: null | { pre_wave_head, pushed_head, selected_ids, affected_claims, stage: apply | review | push, no_progress: { failed_prerequisite, observed_value, result_path }? }
74
74
  - viewer: { login, is_author }
75
- - permissions: { viewer_permission, is_cross_repository, maintainer_can_modify, merge_state_status, can_update_branch, head_url, head_ref, head_pushable } # head_pushable is set in step 2 after provisioning (reference/assessment.md); merge_state_status is `BLOCKED`, `BEHIND`, `UNKNOWN`, `unreadable` (null), or any other GitHub value (`CLEAN`, `UNSTABLE`, `HAS_HOOKS`, `DIRTY`) and is written only from a `gh pr view` invocation that names `mergeStateStatus` (this call, the step-2 re-poll, the step-2b re-gather (`reference/sync.md`), the pre-menu refresh, compare-and-swap, the wait and fix-wave polls), never from an ad hoc GraphQL query or `gh pr list`, and never from a reply carrying `errors`; any field that cannot be read is the literal `unreadable`; menu availability derives from this block (reference/decision-menu.md ## Availability)
75
+ - permissions: { viewer_permission, is_cross_repository, maintainer_can_modify, merge_state_status, can_update_branch, head_url, head_ref, head_pushable } # head_pushable is set in step 2 after provisioning (reference/assessment.md); merge_state_status is `BLOCKED`, `BEHIND`, `UNKNOWN`, `unreadable` (null), or any other GitHub value (`CLEAN`, `UNSTABLE`, `HAS_HOOKS`, `DIRTY`) and is written only from a `gh pr view` invocation that names `mergeStateStatus` (this call, the step-2 re-read, the step-2b re-gather (`reference/sync.md`), the pre-menu refresh before and after the single watch, compare-and-swap), never from an ad hoc GraphQL query or `gh pr list`, and never from a reply carrying `errors`; any field that cannot be read is the literal `unreadable`; menu availability derives from this block (reference/decision-menu.md ## Availability)
76
76
  - status_checks: [ { name, kind, status, conclusion, required, url, workflowName } ] # kind: check_run | status_context | unreadable, from the rollup entry's __typename; evidence semantics: Section B Evidence resolution; workflowName from the CheckRun rollup entry (absent on StatusContext)
77
77
  - actions_runs: [ { databaseId, status, conclusion, workflowName, url } ] # from the fixed gh run list call on the assessed head
78
78
  - comments: { inline[ { id, updated_at, user_type, body, ... } ], top_level[ { id, updated_at, user_type, body, ... } ], review_threads[]? } # retain REST body for source-review deltas; C# identity diffs on id/updated_at, Section C gates placeholder detection on user_type
@@ -120,7 +120,7 @@ edit, fix, or commit anything; you are running a gate and claim-checking,
120
120
  not implementing.
121
121
 
122
122
  **Evidence resolution (normative).** The single rule for whether the local
123
- command runs. Inputs come from Section A's fixed `gh pr view` and `gh run list` calls - no ad hoc fetch; after a push by this gate, `reference/fix-wave.md` re-runs those two calls as its poll.
123
+ command runs. Inputs come from Section A's fixed `gh pr view` and `gh run list` calls - no ad hoc fetch; after a push by this gate, the pre-menu refresh re-runs those two calls.
124
124
 
125
125
  - **Resolved check set** = checks named by `ci checks:` if configured, else all
126
126
  checks on the assessed `headRefOid`.
@@ -147,17 +147,15 @@ command runs. Inputs come from Section A's fixed `gh pr view` and `gh run list`
147
147
 
148
148
  Row precedence is top-down: the first matching row wins. The Fix wave row is an entry point, not a state row: it names when the table is re-resolved (after a push by this gate), and the state rows above it then decide.
149
149
 
150
- On the first pass the orchestrator uses the persisted poll deadline owned by `reference/post-selection-loop.md` `### Wait course` and re-runs Section A's fixed `gh pr view` and `gh run list` calls every 30 seconds while no row other than Pending or Fallback matches (cadence as in `reference/fix-wave.md` `## Evidence after push`), then resolves the table.
151
-
152
150
  | Path | Trigger | Action | Evidence recorded |
153
151
  |---|---|---|---|
154
152
  | Opt-out | `local verification: always` in `## PR gate` | Run local command unconditionally; a Failed-CI block below still applies independently | Local; `local run: local verification: always` |
155
153
  | Failed CI | Any blocking conclusion in the resolved set | Blocks: mints a `P#` (any resolved-set failure, required or not) and names the check in the evidence block; the menu re-renders with `fix` recommended only when a drafted payload exists for that failure, else per the overlays. A green local run never overrides it. Only the human `ci-infrastructure-broken` disposition - a pick, never a trigger - runs the fallback local run; merge stays withheld until that run is green | The disposition; plus the fallback run's result when the disposition triggered one |
156
154
  | Held run | an `action_required` rollup CheckRun whose run matches an `actions_runs` entry, or an `actions_runs` entry with `action_required` and no rollup entry (a rollup CheckRun matches the `actions_runs` entry whose `databaseId` equals the run id parsed from the CheckRun's `detailsUrl`) | Pending: render `approve workflow run` when available - `viewer_permission` in `WRITE`/`MAINTAIN`/`ADMIN`, the rule `reference/decision-menu.md` `## Availability` owns; when the row is not available, or it was picked and the API returned 403 or 404, run the local command at once; the fresh Section B helper receives the resolved row `held run not approvable` in its task; an approved run that completes is re-resolved per `reference/fix-wave.md` `## Evidence after push`, which dispatches the claim-check-only helper | `local run: held run not approvable` when it fired, else n/a (waiting) |
157
- | Pending | >=1 **binding** pending check, no blocking conclusion, and the poll window (first pass or after a push) elapsed | the `verification evidence pending` overlay renders (`reference/decision-menu.md` `## Overlays`); a new explicit `wait` renews the expired window per `reference/post-selection-loop.md` `### Wait course`; never a local run, never an evidence-less merge; when a later re-resolve moves this head to CI-sufficient, the orchestrator dispatches a fresh Section B helper in claim-check-only mode (no local run) so every material claim gets a disposition | n/a (waiting) |
155
+ | Pending | >=1 **binding** pending check, no blocking conclusion | the `verification evidence pending` overlay renders (`reference/decision-menu.md` `## Overlays`); a `wait` pick runs one bounded watch per `reference/post-selection-loop.md` `### Wait course`; never a local run, never an evidence-less merge; when a later re-resolve moves this head to CI-sufficient, the orchestrator dispatches a fresh Section B helper in claim-check-only mode (no local run) so every material claim gets a disposition | n/a (waiting) |
158
156
  | CI-sufficient | >=1 `success`, zero blocking, zero binding pending | Skip local run | CI claim: check name(s), conclusion, assessed SHA, run URL |
159
- | Fallback | No conclusive check: no checks on the assessed head, or only inert / fail-safe conclusions or only not-binding pending checks, after `timeout minutes` | Run local command (protocol below) | Local command + `log_path`; `local run: no conclusive check` |
160
- | Fix wave | A fix-wave push by this gate (not the step-2b sync push) | Poll the pushed head per `reference/fix-wave.md` `## Evidence after push`, then resolve this table on the normalized set | The resolved row's evidence for the pushed SHA |
157
+ | Fallback | No conclusive check: no checks on the assessed head, or only inert / fail-safe conclusions or only not-binding pending checks | Run local command (protocol below) | Local command + `log_path`; `local run: no conclusive check` |
158
+ | Fix wave | A fix-wave push by this gate (not the step-2b sync push) | Re-enter the pre-menu refresh per `reference/fix-wave.md` `## Evidence after push`; its watch guard and this table decide | The resolved row's evidence for the pushed SHA; the evidence block lists every failing and every pending binding check on the pushed head |
161
159
  | Stale head | Head advances since evidence was resolved (another actor's push); fires across runs - a single gather is same-head by construction | All prior evidence (CI or local) is stale; re-resolve this table for the new head before merge is offered | Fresh evidence for the new head |
162
160
 
163
161
  CI-sufficient predicate, stated once (the rows implement exactly this): **>=1
@@ -202,14 +200,14 @@ run fires on exactly three triggers, each recorded in the evidence block:
202
200
  head_sha: <git rev-parse HEAD at run time>
203
201
  runs: [ { run_cwd, command (verbatim), exit_code, result: pass|fail|not run,
204
202
  log_path: <file under ${TMPDIR:-/tmp} holding the full captured output> } ]
205
- - claims: [ { claim, disposition: matched|contradicted|unverifiable-pre-merge, evidence } ] # ci and local sources; a pending result carries no claims
203
+ - claims: [ { claim, disposition: matched|contradicted|unverifiable-pre-merge|pending, evidence } ] # source: pending -> disposition source-checkable claims now; keep check-dependent claims pending for the claim-check-only helper after a green watch
206
204
  ```
207
205
 
208
206
  Claim-check-only mode: the orchestrator's task says `claim check only`; emit the resolved row's `source: ci` block (`head_sha`, `checks`), no run, and the per-claim dispositions.
209
207
 
210
208
  `description recheck` mode: take the actual body, assessed head, affected claims/finding IDs, and existing evidence block. Emit only affected `{ claim, disposition, evidence }` entries and supplied claim findings' `<finding id>: resolved` or `<finding id>: open - <why>` closure lines. No replacement evidence block is emitted. Run no tests or evidence resolver; preserve `source: ci`, `source: local` (including `log_path`), or `source: pending` unchanged. Preserve unrelated dispositions; pending evidence remains insufficient. Judge supplied proof against source, not author assertion alone. This mode is separate from `claim check only`.
211
209
 
212
- `source: pending` records a Pending or Held run outcome - no local run, no CI sufficiency, no claims; the orchestrator waits.
210
+ `source: pending` records a Pending or Held run outcome - no local run, no CI sufficiency; disposition every claim whose evidence is the head's source (code, tests, docs) now and list claims that need a check result as `pending`; the claim-check-only helper dispositions those after a green watch.
213
211
 
214
212
  Local provenance rules bind only to `source: local`. `log_path` holds captured
215
213
  output, not authored prose; anything written in your own words is labeled