pi-gauntlet 7.11.1 → 7.11.3
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 +12 -0
- package/README.md +20 -2
- package/package.json +1 -1
- package/skills/gatekeep-pr/SKILL.md +3 -2
- package/skills/gatekeep-pr/reference/assessment.md +3 -3
- package/skills/gatekeep-pr/reference/cleanup.md +19 -0
- package/skills/gatekeep-pr/reference/decision-menu.md +14 -10
- package/skills/gatekeep-pr/reference/post-selection-loop.md +5 -10
- package/skills/gatekeep-pr/verification-brief.md +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v7.11.3 - 2026-10-16
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **gatekeep-pr `cleanup` row.** Every terminal menu (own merge, approved, already merged or closed) offers `cleanup` as row 1 `[recommended]`: it removes the gate's worktree and local branch, fast-forwards the base, then runs the overrides file's ordered `## cleanup` items with `<issue>`, `<pr>`, and `<merge-sha>` substituted; steps that need a landed change are skipped with a reason when nothing merged. `stop` under those menus now leaves the checkout as found and names it instead of tearing it down silently. New reference `skills/gatekeep-pr/reference/cleanup.md`; the digest carries `pr.url`, `pr.merge_commit`, and a `worktree` record; this repo's overrides close the ticket, then release.
|
|
8
|
+
|
|
9
|
+
## v7.11.2 - 2026-10-15
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **Claude Code plugin is versioned.** `.claude-plugin/marketplace.json` carries a plugin `version` equal to the npm version; `release.sh` writes it in the Release commit and `npm test` fails when the two diverge. Claude Code now sees each release as a new plugin version, so `claude plugin update gauntlet@pi-gauntlet` (or the `/plugin` auto-update toggle) picks it up; before, the plugin entry had no version and an installed copy never knew a newer release existed. Same mechanism as pi-quiver.
|
|
14
|
+
|
|
3
15
|
## v7.11.1 - 2026-10-14
|
|
4
16
|
|
|
5
17
|
### Changed
|
package/README.md
CHANGED
|
@@ -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. 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>]`.
|
|
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; every terminal menu offers a recommended `cleanup` row that tears down the gate's worktree and branch and runs the overrides file's `## cleanup` steps - run it with `/skill:gatekeep-pr <pr> [--rebase [base]]`), `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
|
|
|
@@ -223,6 +223,12 @@ then install.
|
|
|
223
223
|
|
|
224
224
|
Invocation: `/gauntlet:shape-ticket` (or bare `/shape-ticket` when unambiguous).
|
|
225
225
|
|
|
226
|
+
Updates: the plugin's marketplace `version` equals the npm version; the release
|
|
227
|
+
script writes it on every release, so Claude Code sees each release as a new
|
|
228
|
+
plugin version. Third-party marketplaces do not auto-update by default - run
|
|
229
|
+
`claude plugin update gauntlet@pi-gauntlet` or turn on auto-update for the
|
|
230
|
+
marketplace in `/plugin`. `claude update` updates Claude Code itself, not plugins.
|
|
231
|
+
|
|
226
232
|
Project instructions: Claude Code reads `CLAUDE.md`, pi reads `AGENTS.md` - a
|
|
227
233
|
symlink keeps one source of truth: `ln -s AGENTS.md CLAUDE.md`. The gauntlet
|
|
228
234
|
overrides ladder (`.pi/gauntlet-overrides.md` -> `gauntlet-overrides.md` ->
|
|
@@ -305,6 +311,16 @@ Use the project's wrapper: `script/worktree create <name>`. It provisions an iso
|
|
|
305
311
|
database and copies `.env.local`. Never call `git worktree add` directly.
|
|
306
312
|
```
|
|
307
313
|
|
|
314
|
+
A `## cleanup` section lists what gatekeep-pr runs after a PR is merged, approved, or found already merged or closed, in order, after the implied git teardown (worktree, local branch, base fast-forward):
|
|
315
|
+
|
|
316
|
+
```markdown
|
|
317
|
+
## cleanup
|
|
318
|
+
- close ticket: gh issue close <issue> --comment "Delivered in <pr>, merged <merge-sha>."
|
|
319
|
+
- release: /skill:release
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Each item is `<label>: <command or /skill:... invocation>`. Placeholders `<issue>`, `<pr>`, and `<merge-sha>` are filled from the gate's digest; an item whose placeholder has no value is skipped with a reason, and items that need a landed change (`<merge-sha>`, `/skill:release`) are skipped when the PR was only approved or closed. A `/skill:` item keeps its own gates; anything else runs as a shell command in the primary checkout under the PR gate's `timeout minutes`.
|
|
323
|
+
|
|
308
324
|
Beyond `## conventions` and skill-named sections, headings a skill reads by name are documented in their owning skills; other headings retain topic/workflow-convention matching. The override file is read by skill instructions and, for its `## Spec index` section only, by `gauntlet-spec-index`; the Pi runtime itself never reads it. Missing or empty `## conventions` adds no rules; a lower-priority file cannot supplement the selected file.
|
|
309
325
|
|
|
310
326
|
**Discovery ladder:** skills check three locations, in order, and use the first one found - never merged: `.pi/gauntlet-overrides.md`, then `<repo root>/gauntlet-overrides.md`, then `<repo root>/doc/gauntlet-overrides.md` (`<repo root>` = `git rev-parse --show-toplevel`, or the current directory outside a repo). Pick one location per repo.
|
|
@@ -451,7 +467,7 @@ Everything else follows the shipped baseline rubric.
|
|
|
451
467
|
A consumer repo that wants its own trigger phrases for the pre-merge gate (e.g. "gate
|
|
452
468
|
this PR", "ready to merge?") adds a wrapper skill that carries **zero data** - only a
|
|
453
469
|
name, its trigger phrases, and an instruction to follow `/skill:gatekeep-pr`. All
|
|
454
|
-
customization lives in
|
|
470
|
+
customization lives in three places, never in the wrapper itself:
|
|
455
471
|
|
|
456
472
|
- **`REVIEW.md`** - the review rubric (see above).
|
|
457
473
|
- **The gauntlet overrides file, `## PR gate` section** - everything operational:
|
|
@@ -468,6 +484,8 @@ customization lives in two places, never in the wrapper itself:
|
|
|
468
484
|
- merge policy: squash | merge-commit # optional
|
|
469
485
|
```
|
|
470
486
|
|
|
487
|
+
- **The gauntlet overrides file, `## cleanup` section** - the ordered post-gate steps the `cleanup` menu row runs (contract under Project-specific overrides above).
|
|
488
|
+
|
|
471
489
|
An existing `## verification-before-completion` overrides section is an accepted
|
|
472
490
|
equivalent source for the verification command only; all other PR-gate keys
|
|
473
491
|
still live under `## PR gate`. A `## comms style` section in the same overrides
|
package/package.json
CHANGED
|
@@ -62,7 +62,8 @@ These bind every rendered report, menu, and external payload (review bodies, rep
|
|
|
62
62
|
- Judging a ticket row the spec does not carry, or treating a spec `deferred: <ref>` row as a gap - owner: `reference/findings.md` `## AC outcomes`.
|
|
63
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`.
|
|
64
64
|
- Raw command output, drafted payloads except the exact description consent preview, or internal IDs in the rendered report - owner: `reference/report.md`.
|
|
65
|
-
- An open-PR menu, other than the conflict menu,
|
|
65
|
+
- An open-PR menu, other than the conflict menu, a terminal overlay (`reference/decision-menu.md`), 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 `cleanup`, `show evidence`, and `stop` only); any menu without `show evidence`, with two `[recommended]`, or with `stop` not last - owner: `reference/decision-menu.md`.
|
|
66
|
+
- `cleanup` rendered on an ordinary open-PR menu, or its steps run without a pick - owner: `reference/cleanup.md`.
|
|
66
67
|
- 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`.
|
|
67
68
|
- 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`.
|
|
68
69
|
- A helper's duty run in the orchestrator's own context - owner: `## Harness notes`.
|
|
@@ -74,4 +75,4 @@ These bind every rendered report, menu, and external payload (review bodies, rep
|
|
|
74
75
|
|
|
75
76
|
## Project overrides
|
|
76
77
|
|
|
77
|
-
If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## PR gate` keys are read in step 2 (`reference/assessment.md`); `## comms style` extends the wording rules.
|
|
78
|
+
If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## PR gate` keys are read in step 2 (`reference/assessment.md`); `## comms style` extends the wording rules. `## cleanup` steps run on the `cleanup` pick (`reference/cleanup.md`).
|
|
@@ -10,7 +10,7 @@ Read from SKILL.md step 2. Input: the step-1 digest. Output: a provisioned workt
|
|
|
10
10
|
| The default path `.worktrees/pr-<N>` exists but holds a different branch | STOP and surface; never repurpose | STOP and surface; never repurpose | - |
|
|
11
11
|
| Nothing exists (an overrides worktree wrapper can relocate it, following `using-git-worktrees` conventions, gitignore-first) | Create at `.worktrees/pr-<N>`; `git fetch origin` + `git worktree add .worktrees/pr-<N> <headRefName>`; verify post-checkout that HEAD == the digest's `headRefOid` | Create at `.worktrees/pr-<N>`; `git fetch origin pull/<N>/head:pr-<N>` first, then add on that local branch; verify post-checkout that HEAD == the digest's `headRefOid` | - |
|
|
12
12
|
|
|
13
|
-
Record
|
|
13
|
+
Record the digest's `worktree` block (`../verification-brief.md`): `path`, `branch` (the actual local branch - `headRefName`, `pr-<N>`, or whatever a wrapper created), `created` (true when this run created it), and `destroy` (the exact destroy invocation when a `worktree wrapper` created it, else null). `cleanup.md` reads it; `post-selection-loop.md` `### Teardown` points there.
|
|
14
14
|
|
|
15
15
|
Then set the digest's `permissions.head_pushable` (`../verification-brief.md` Section A): `git -C <worktree> push --dry-run --no-verify --no-follow-tags <head_url> HEAD:refs/heads/<head_ref>` exit 0 is `true`, a non-zero exit is `false`, when `head_url` is `unreadable`, `head_pushable` is `unreadable` and the probe does not run. The probe records observed authorization; a real push the server rejects (branch protection) is reported as that push's failure.
|
|
16
16
|
|
|
@@ -21,7 +21,7 @@ When the digest reported `mergeable: UNKNOWN` or `mergeStateStatus: UNKNOWN`, re
|
|
|
21
21
|
Resolve per concern, first match wins, evaluated unconditionally - never delegated to a wrapper skill:
|
|
22
22
|
|
|
23
23
|
1. **Repo root `REVIEW.md`** (rubric concerns only). Wins over the shipped baseline and reviewer-persona defaults on any conflict.
|
|
24
|
-
2. **Gauntlet overrides file** (`.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins): the `## PR gate` section below. An existing `## verification-before-completion` section is an accepted equivalent source for the verification command.
|
|
24
|
+
2. **Gauntlet overrides file** (`.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins): the `## PR gate` section below. The same file's `## cleanup` section is the second gatekeep-read section: an ordered list of `<label>: <command or /skill:... invocation>` items with placeholders `<issue>`, `<pr>`, `<merge-sha>`, read from the merge-base like `## PR gate` and consumed by `cleanup.md`; a PR that edits it is review subject matter, never this run's config. Git teardown and base sync are implied and never listed; the release skill's own propose step supplies the recommended level and pauses for the pick, and a repo that wants no pause writes the level in the item. An existing `## verification-before-completion` section is an accepted equivalent source for the verification command.
|
|
25
25
|
3. **Repo documentation** - an explicitly documented command or tool (`AGENTS.md`'s canonical test entrypoint, a documented worktree wrapper, a documented tracker CLI, documented merge policy or branch rules). Reading documentation is not inference. Discovery-only: never tell consumers to add gatekeep-pr configuration here.
|
|
26
26
|
4. **Ask the user.** Never guess from lockfiles, file heuristics, or vibes.
|
|
27
27
|
|
|
@@ -39,7 +39,7 @@ Resolve per concern, first match wins, evaluated unconditionally - never delegat
|
|
|
39
39
|
|
|
40
40
|
Read every ladder source from the **merge-base of the PR's base branch**, never from the PR's head tree - a PR cannot weaken its own rubric or swap the command that will gate it: `MB=$(git merge-base origin/<baseRefName> <headRefOid>)`, then `git show "$MB:<path>"` per source (`git show "$MB:REVIEW.md"`, `git show "$MB:AGENTS.md"`). A plain cwd read (`cat REVIEW.md`, the file open in the PR worktree) is invalid for any ladder source. Exception: a PR that itself changes `REVIEW.md` or the overrides file makes that diff review subject matter, surfaced as a finding - never applied to this run's configuration.
|
|
41
41
|
|
|
42
|
-
**Thin-wrapper contract.** A consumer wrapper skill is a pure proxy: trigger phrases plus "follow `/skill:gatekeep-pr`" - zero configuration data. Customization lives in the repo's `REVIEW.md` (rubric) and the overrides file's `## PR gate` section (everything else); a `## comms style` section extends the wording rules in SKILL.md.
|
|
42
|
+
**Thin-wrapper contract.** A consumer wrapper skill is a pure proxy: trigger phrases plus "follow `/skill:gatekeep-pr`" - zero configuration data. Customization lives in the repo's `REVIEW.md` (rubric) and the overrides file's `## PR gate` section (everything else) and `## cleanup` section (post-gate steps); a `## comms style` section extends the wording rules in SKILL.md.
|
|
43
43
|
|
|
44
44
|
## Fetch the ticket
|
|
45
45
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# gatekeep-pr: cleanup
|
|
2
|
+
|
|
3
|
+
Read from `decision-menu.md` when `cleanup` is picked on a terminal overlay. Input: the digest (`pr.url`, `pr.merge_commit` - `mergeCommit.oid` from Section A or `### Merge course`, `pr.state`, `pr.headRefOid`, `pr.baseRefName`, `issue.ref` or `issue: null`, the `worktree` block) and the continuation record, plus the `## cleanup` section of the merge-base overrides file (`assessment.md` `## Configuration`). Output: one rendered line per step - `<label>: done`, `<label>: skipped - <reason>`, `<label>: failed - <first error line>`, or `<label>: invoked /skill:<name> - <where it paused or what it returned>` for a `/skill:` item - then set `cleanup_done` and re-render the same terminal menu without the `cleanup` row.
|
|
4
|
+
|
|
5
|
+
**Landed** means `pr.state` is `MERGED`. **Primary** is the parent directory of `git -C <worktree.path> rev-parse --git-common-dir`; it is the checkout the session runs in. Never remove it and never change its branch. Run every git command as `git -C <primary>`; touch nothing under the removed worktree path after step 1.
|
|
6
|
+
|
|
7
|
+
Run the steps in order; a failing step prints its first error line and the loop continues; retry nothing.
|
|
8
|
+
|
|
9
|
+
1. **Worktree.** Eligible when `worktree.path` is not the primary, `git -C <worktree.path> status --porcelain --untracked-files=no` is empty (tracked-clean; untracked files never block removal), and - when landed - `git -C <worktree.path> log origin/<baseRefName>..HEAD` shows no commit outside the assessed head's history (`git -C <worktree.path> merge-base --is-ancestor HEAD <headRefOid>` succeeds). Eligible and (`worktree.created` or landed) -> run `worktree.destroy` when recorded, else `git worktree remove --force <worktree.path>` (the single `--force` removes a tree whose only dirt is untracked files; those files are deleted); then `git worktree prune`; print `worktree: done`. Reused and not landed -> `worktree: skipped - reused, left at <path>`. Dirty -> `worktree: skipped - uncommitted changes at <path>`. Commits beyond the assessed head -> `worktree: skipped - unmerged commits <shas> at <path>`. Under `approved` on a `rebased locally` head this step reports `unmerged commits` and leaves the tree, and `stop` leaves the rewritten local head in place and names it.
|
|
10
|
+
2. **Branch.** Landed, the branch exists locally, and no worktree holds it (`git worktree list --porcelain` lists no `branch refs/heads/<worktree.branch>`) -> `git branch -D <worktree.branch>`; print `branch: done`. Not landed -> `branch: skipped - PR not merged`. Still checked out -> `branch: skipped - checked out at <path>`. Never delete a remote branch.
|
|
11
|
+
3. **Base.** Landed, the primary is on `<baseRefName>`, and its tree is tracked-clean -> `git fetch origin` then `git pull --ff-only`; print `base: synced <sha>` when `git merge-base --is-ancestor <pr.merge_commit> HEAD` succeeds, else `base: failed - merge commit not on local <baseRefName>`. Primary on another branch -> `base: skipped - primary on <branch>`; dirty -> `base: skipped - uncommitted changes`; not landed -> `base: skipped - PR not merged`. Never switch the primary's branch.
|
|
12
|
+
4. **Override steps**, one per `## cleanup` item in list order. An item is `<label>: <text>`; any other shape -> `skipped - malformed item: <text>`.
|
|
13
|
+
- Landed-change guard first: not landed and the text contains `<merge-sha>` or `/skill:release` -> `skipped - needs a landed change`. The guard decides before any placeholder is read, so an item it skips never prints a `no <name> resolved` line, whatever its placeholders hold. A `/skill:release` item when step 3 did not print `synced` -> `skipped - base not synced`.
|
|
14
|
+
- Substitute: `<issue>` is `issue.ref` with a leading `#` stripped for the bare `#N` form (other forms verbatim); `<pr>` is `pr.url`; `<merge-sha>` is `pr.merge_commit`. A null value -> `skipped - no <name> resolved`: `skipped - no issue resolved`, `skipped - no pr resolved`, `skipped - no merge-sha resolved`. Any other `<...>` token -> `skipped - malformed item: <text>`. Insert each value as literal argument text: inside an existing quoted span verbatim; outside, single-quoted as one shell word.
|
|
15
|
+
- Text starting with `/skill:` -> invoke that skill with the rest of the text as its arguments, gates intact: the step's line is `<label>: invoked /skill:<name> - <where it paused or what it returned>` (for example `release: invoked /skill:release - paused at its level pick`) - never a `skipped` or `failed` line about skill availability, because the gate itself runs as a skill and every `/skill:` item is invokable; `/skill:release` with no level runs the skill's propose-then-pick gate; a level written in the item (`patch`, `minor`, `major`) authorizes the release without a pause. Any other text -> run it as a non-interactive shell command with cwd the primary, bounded by the resolved `timeout minutes` (default 15) through the Safety contract ladder of `../verification-brief.md` Section B; a timeout prints `failed - timed out after <n> minutes` and later steps still run.
|
|
16
|
+
|
|
17
|
+
With no overrides file or no `## cleanup` section, run steps 1-3 only. On a closed-unmerged PR steps 2 and 3 print `PR not merged` and the landed-change guard skips release and `<merge-sha>` items before substitution. Do not delete the consent record, helper output files, or temporary body files here - `show evidence` and the post rows stay available after `cleanup`; `post-selection-loop.md` `### Teardown` deletes them on terminal exit.
|
|
18
|
+
|
|
19
|
+
Consequence clause for the menu row (`decision-menu.md`): `remove <worktree.path> (untracked files there are deleted) and branch <worktree.branch>, pull <baseRefName>, then <label> (<resolved command>), ...` with every placeholder already substituted, so the tracker comment text and the release invocation are confirmed by the one pick and `/skill:release` keeps its own level gate; steps the guards would skip render as `<label> (skipped - <reason>)`; with no `## cleanup` section the clause is `tear down the gate's checkout and local branch (untracked files there are deleted)`.
|
|
@@ -4,11 +4,11 @@ Read from SKILL.md step 6. Input: the report's verdict and the PR state. Output:
|
|
|
4
4
|
|
|
5
5
|
## Verbs
|
|
6
6
|
|
|
7
|
-
`accept contract change`, `preserve contract`, `fix`, `fix nits`, `push`, `review`, `approve`, `approve workflow run`, `update branch`, `merge base`, `merge`, `merge anyway`, `reply`, `post coverage to ticket`, `post coverage to PR`, `show evidence`, `wait`, `stop`.
|
|
7
|
+
`accept contract change`, `preserve contract`, `fix`, `fix nits`, `push`, `review`, `approve`, `approve workflow run`, `update branch`, `merge base`, `merge`, `merge anyway`, `reply`, `post coverage to ticket`, `post coverage to PR`, `cleanup`, `show evidence`, `wait`, `stop`.
|
|
8
8
|
|
|
9
9
|
Render fix consequences with the applicable lifetime from `post-selection-loop.md` `### Continuation record`. For named fixes, state that authority retains only the selected stable IDs for later independent reassessments, with the same lifetime as broad fixes; link active pre-push retries to `fix-wave.md` `## Review before push`. For clarification-only fixes, state one-shot authority for the exactly selected payload; keep nit consequences one-shot.
|
|
10
10
|
|
|
11
|
-
Rows are `<n>. <verb> - <consequence>`; every row, `stop` included, carries its consequence clause. `stop` is always last, before the compose hint. `show evidence` is always offered and never `[recommended]`. A row the actor cannot execute - by `## Availability` below, or because the forge would refuse it (branch protection, a withhold) - is omitted and named in the compose line's `Not offered:` sentence; it is never `[recommended]`. Exactly one row is `[recommended]`.
|
|
11
|
+
Rows are `<n>. <verb> - <consequence>`; every row, `stop` included, carries its consequence clause. `stop` is always last, before the compose hint. `show evidence` is always offered and never `[recommended]`. A row the actor cannot execute - by `## Availability` below, or because the forge would refuse it (branch protection, a withhold) - is omitted and named in the compose line's `Not offered:` sentence; it is never `[recommended]`. Exactly one row is `[recommended]`. A **terminal overlay** is `own merge`, `merge queued` (once its read returns `MERGED` it re-renders as `own merge`), `approved`, or `merged or closed PR`; every other menu is an ordinary open-PR menu. **Landed** means the PR's `state` is `MERGED`; under `approved` and under a closed-unmerged PR nothing has landed.
|
|
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
|
|
@@ -25,9 +25,10 @@ Rows are `<n>. <verb> - <consequence>`; every row, `stop` included, carries its
|
|
|
25
25
|
- `reply` - post the drafted replies under `PR comments` (`reply <n>` for one)
|
|
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
|
+
- `cleanup` - tear down the gate's checkout and local branch per `cleanup.md`, then run the repo's `## cleanup` steps in order; the consequence clause names each override step as `<label> (<resolved command>)` with placeholders already substituted, so the exact tracker comment or release invocation is visible before the pick; with no `## cleanup` section the clause reads `tear down the gate's checkout and local branch (untracked files there are deleted)`
|
|
28
29
|
- `show evidence` - print the evidence record, claim and AC outcomes, dispositions, drafted payloads and replies (`report.md` `## What stays out`)
|
|
29
30
|
- `wait` - run one bounded `gh pr checks --watch` on every **binding** pending check in the resolved set (required or not), then re-render
|
|
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
|
+
- `stop` - leave the PR as-is; under a terminal overlay leave the checkout as found and print one line naming the leftover worktree path and local branch; on an ordinary open-PR menu with 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
32
|
|
|
32
33
|
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`).
|
|
33
34
|
|
|
@@ -49,6 +50,7 @@ Rows derive from the digest's `permissions` block (`../verification-brief.md` Se
|
|
|
49
50
|
| `approve workflow run` | `viewer_permission` is `WRITE`, `MAINTAIN`, or `ADMIN`, and a held run exists on the assessed head |
|
|
50
51
|
| `update branch` | `can_update_branch` is true and no unpushed wave commit exists |
|
|
51
52
|
| `update branch`, `review`, `merge`, `merge anyway`, `push`, `wait` | omitted while the sync record is `rebased locally`, named in `Not offered:` as `(head not pushed)`; the fix wave's lease push is the only write to the PR head |
|
|
53
|
+
| `cleanup` | only under a terminal overlay, never on an ordinary open-PR menu; it leaves the menu after it runs, success or not (`cleanup.md`) |
|
|
52
54
|
| `approve`, `review`, `reply`, `post coverage to ticket`, `post coverage to PR`, `show evidence`, `wait`, `stop` | per the consent table and overlays below |
|
|
53
55
|
|
|
54
56
|
## Consent table
|
|
@@ -80,13 +82,14 @@ The single source for the merge-withhold reason, the `PR comments` line, and the
|
|
|
80
82
|
|
|
81
83
|
For a pending contract exception, print the concrete proposed contract change before the rows, using the recorded proposal; numeric and typed picks select these actual rows and route to `post-selection-loop.md` `### Contract decision`. Render the `preserve contract` consequence as "reject the proposal, keep <named requirement>, and resume authorized implementation repair within it". Existing terminal/sync stops take precedence; otherwise the contract-exception overlay replaces ordinary rows, and lower overlays cannot discard its decision rows.
|
|
82
84
|
|
|
83
|
-
Apply overlays to the consent row; take additional rows only from
|
|
85
|
+
Apply overlays to the consent row; take additional rows only from a terminal overlay (`cleanup` and the post-coverage rows) or the pending `contract exception` (contract-decision rows). When two apply, the one higher in this table wins the `merge` reason and `[recommended]`.
|
|
84
86
|
|
|
85
87
|
| Overlay | Trigger | Effect |
|
|
86
88
|
|---|---|---|
|
|
87
|
-
| own merge | this run's `merge` pick ran and the post-merge read (`post-selection-loop.md` `### Merge course`) returned `state: MERGED` | the menu is `post coverage to ticket` (when `issue` is non-null and `scope.rows` is non-empty), `post coverage to PR`, `show evidence`, `stop
|
|
89
|
+
| own merge | this run's `merge` pick ran and the post-merge read (`post-selection-loop.md` `### Merge course`) returned `state: MERGED` | the menu is `cleanup` `[recommended]`, `post coverage to ticket` (when `issue` is non-null and `scope.rows` is non-empty), `post coverage to PR`, `show evidence`, `stop`; each post row renders once and leaves the menu after its post succeeds, and a successful post re-renders this menu - posting never tears down and never ends the run; a failed post keeps its row and prints the `gh` error; no compare-and-swap runs before a post |
|
|
88
90
|
| merge queued | this run's `merge` pick ran and the post-merge read returned a state other than `MERGED` | the menu is `wait` (re-run the post-merge read, then re-render), `show evidence`, `stop`, with `wait` `[recommended]`; one `PR comments` line `The merge is queued, so coverage posts wait. (<state>)` |
|
|
89
|
-
|
|
|
91
|
+
| approved | the continuation record's `approved_head` equals the assessed head (`post-selection-loop.md` sets it only when `gh pr review --approve` exits 0, before the re-render; a non-zero exit prints the `gh` error and the ordinary menu re-renders) | the menu is `cleanup` `[recommended]`, `show evidence`, `stop` |
|
|
92
|
+
| merged or closed PR | `state` was not `OPEN` at step 1 | the report renders; the menu is `cleanup` `[recommended]`, `show evidence`, `stop` |
|
|
90
93
|
| contract exception | a recorded contract exception is pending, with no terminal/sync stop | replace the ordinary menu with `accept contract change`, `preserve contract`, `show evidence`, `stop`; recommend `preserve contract`; use `post-selection-loop.md` `### Contract decision` for every selection |
|
|
91
94
|
| draft PR | `isDraft` | `merge` and `approve` are omitted (`Not offered: merge (draft)`, plus `approve (draft)` when the consent row holds `approve`) and never carry `[recommended]`; `review` is recommended on someone else's fixable draft, `fix nits` on their mergeable draft when a nit exists, else `stop`; on your own, `fix` when a blocker exists, else `stop` |
|
|
92
95
|
| held run | an `action_required` conclusion on an Actions run of the assessed head (`../verification-brief.md` Evidence resolution, Held run) with no `local run: held run not approvable` evidence yet for that head | `approve workflow run` renders as row 1 when available (`## Availability`) and is `[recommended]` when `Blockers` is empty, else `[recommended]` stays on the consent row's first row; `merge` is omitted (`Not offered: merge (workflow run awaiting approval)`); once the held-run-not-approvable local run exists, this overlay no longer applies and `merge` follows the preconditions |
|
|
@@ -161,9 +164,10 @@ Informational - the ticket's rows are unchanged. PR https://github.com/acme/widg
|
|
|
161
164
|
- [ ] The reports page offers an Export CSV button. - covered
|
|
162
165
|
- [ ] Exports are emailed to the requesting user. - deferred per spec to acme/widgets#46
|
|
163
166
|
|
|
164
|
-
1.
|
|
165
|
-
2. post coverage to
|
|
166
|
-
3.
|
|
167
|
-
4.
|
|
167
|
+
1. cleanup - remove .worktrees/pr-210 and branch csv-export, pull main, then close ticket (gh issue close 45 --comment "Delivered in https://github.com/acme/widgets/pull/210, merged 9f1c2d3e4b5a6978.") [recommended]
|
|
168
|
+
2. post coverage to ticket - comment the block above on acme/widgets#45
|
|
169
|
+
3. post coverage to PR - comment the block above on the PR
|
|
170
|
+
4. show evidence - gate output, CI run
|
|
171
|
+
5. stop - leave the PR as-is; .worktrees/pr-210 and branch csv-export stay
|
|
168
172
|
Type a number.
|
|
169
173
|
```
|
|
@@ -4,7 +4,7 @@ Read from SKILL.md step 7. Execute only the selected pick or validated retained
|
|
|
4
4
|
|
|
5
5
|
### Continuation record
|
|
6
6
|
|
|
7
|
-
Before tracker initialization, mint `mktemp "${TMPDIR:-/tmp}/gatekeep-state.XXXXXX"` and write the continuation subset as JSON using the field schema in `../verification-brief.md`. Initialize grants to null and rounds to zero only for this new invocation. Put `state: <absolute-path>` in the first tracker task's name, the no-tool checklist header, continuation summaries, and `show evidence` on both harnesses. Use native file operations on Claude Code; no pi tool is required.
|
|
7
|
+
Before tracker initialization, mint `mktemp "${TMPDIR:-/tmp}/gatekeep-state.XXXXXX"` and write the continuation subset as JSON using the field schema in `../verification-brief.md`. Initialize grants to null and rounds to zero only for this new invocation. Put `state: <absolute-path>` in the first tracker task's name, the no-tool checklist header, continuation summaries, and `show evidence` on both harnesses. Use native file operations on Claude Code; no pi tool is required. Initialize `approved_head` to null and `cleanup_done` to false.
|
|
8
8
|
|
|
9
9
|
Persist the assessed head/body, scope, finding IDs and independent contributions, exact selected payload/body snapshots, evidence and helper-output paths, prior comment identity/body baseline and ledger. Keep raw diff, logs, and bulk metadata outside this record. Update changed JSON fields, not a recreated memory summary; fetched fields never overwrite grants, usage, or scope-at-grant.
|
|
10
10
|
|
|
@@ -84,13 +84,13 @@ A retained grant never re-dispatches a finding the implementer returned `open -
|
|
|
84
84
|
|
|
85
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
|
-
`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.
|
|
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. When `gh pr review --approve` exits 0, write the assessed head into the record's `approved_head` before the re-render, so the `approved` overlay renders (`decision-menu.md`: `cleanup` `[recommended]`, `show evidence`, `stop`; it sits below `own merge` and `merge queued` and above `contract exception`); a non-zero exit prints the `gh` error and the ordinary menu re-renders.
|
|
88
88
|
|
|
89
89
|
### Merge course
|
|
90
90
|
|
|
91
91
|
`merge` executes as `gh pr merge --match-head-commit <assessed-sha>` with the resolved merge policy. Push and merge are never one pick.
|
|
92
92
|
|
|
93
|
-
After `gh pr merge` returns, read `gh pr view <N> --json state,mergeCommit`. `state: MERGED` -> render the `AC coverage` block once and re-render the menu under the `own merge` overlay (`decision-menu.md`); any other state (a merge queue) -> one `PR comments` line `The merge is queued, so coverage posts wait. (<state>)` and the menu `wait` (re-run the read) / `show evidence` / `stop`. The block, `<sha>` = `mergeCommit.oid`, one row per `scope.rows` entry in row order with its outcome (`covered`, `deferred per spec to <ref>`, `deviates per spec: <why>`, `elsewhere per spec: <repo>`, `venue: <env> - <observation>, checked before prod deploy`); with no rows (`source: pr`, or an empty `scope.rows`) the block has no row lines and `post coverage to ticket` is not offered. With `source: pr` the header line drops `, spec <path>`. An `in-scope` row whose observation half is `not judged here` renders `covered; observable half checked after merge`.
|
|
93
|
+
After `gh pr merge` returns, read `gh pr view <N> --json state,mergeCommit`. `state: MERGED` -> write the returned `state` into `pr.state` and `mergeCommit.oid` into `pr.merge_commit` (the same two writes when a queued merge's `wait` re-read returns `MERGED`), render the `AC coverage` block once and re-render the menu under the `own merge` overlay (`decision-menu.md`); any other state (a merge queue) -> one `PR comments` line `The merge is queued, so coverage posts wait. (<state>)` and the menu `wait` (re-run the read) / `show evidence` / `stop`. The block, `<sha>` = `mergeCommit.oid`, one row per `scope.rows` entry in row order with its outcome (`covered`, `deferred per spec to <ref>`, `deviates per spec: <why>`, `elsewhere per spec: <repo>`, `venue: <env> - <observation>, checked before prod deploy`); with no rows (`source: pr`, or an empty `scope.rows`) the block has no row lines and `post coverage to ticket` is not offered. With `source: pr` the header line drops `, spec <path>`. An `in-scope` row whose observation half is `not judged here` renders `covered; observable half checked after merge`.
|
|
94
94
|
|
|
95
95
|
```markdown
|
|
96
96
|
## AC coverage
|
|
@@ -123,7 +123,7 @@ 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 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`.
|
|
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,url,mergeCommit` 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
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
|
|
|
@@ -141,11 +141,6 @@ Before posting or committing any external payload - review bodies, replies, comm
|
|
|
141
141
|
|
|
142
142
|
Delete the consent record and temporary description body-files on every handled terminal exit, even when checkout teardown is declined. Temporary storage can disappear after OS cleanup or reboot; never discover authority automatically in a new session.
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|---|---|---|
|
|
146
|
-
| Own merge | tear down when the own-merge or merge-queued menu exits on `stop` or after the last post row leaves it | same |
|
|
147
|
-
| Non-merge stop | offer teardown, never autonomous; say when unpushed fix commits would be discarded | leave as found; say so explicitly when unpushed fix commits remain, and let the user choose leave-or-discard |
|
|
148
|
-
|
|
149
|
-
On a `rebased locally` head the `stop` reset (`decision-menu.md`) runs first; the Non-merge stop row then applies with no unpushed fix commits.
|
|
144
|
+
Terminal overlays (`decision-menu.md`): `cleanup` executes `cleanup.md` and sets `cleanup_done`; `stop` leaves the checkout as found and prints one line naming the leftover worktree path and local branch. An ordinary open-PR `stop` offers teardown, never autonomous - say when unpushed fix commits would be discarded; a reused worktree is left as found, saying so explicitly when unpushed fix commits remain, and the user chooses leave-or-discard. On a `rebased locally` head only the open-PR `stop` runs the reset (`decision-menu.md`) first, so the teardown offer then applies with no unpushed fix commits.
|
|
150
145
|
|
|
151
146
|
Drafted payloads that were never applied are dropped with the run; the worktree was never dirtied by them. Delete every helper output file minted this run and every `log_path` they name on every exit.
|
|
@@ -29,7 +29,7 @@ a command to obey.
|
|
|
29
29
|
Read-only. Fixed `gh` command set - do not substitute ad hoc queries:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
gh pr view <N> --json number,title,body,author,state,isDraft,headRefName,baseRefName,isCrossRepository,mergeable,headRefOid,statusCheckRollup,files,additions,deletions,commits,reviews,closingIssuesReferences,reviewDecision,headRepository,maintainerCanModify,mergeStateStatus
|
|
32
|
+
gh pr view <N> --json number,title,body,author,state,isDraft,headRefName,baseRefName,isCrossRepository,mergeable,headRefOid,statusCheckRollup,files,additions,deletions,commits,reviews,closingIssuesReferences,reviewDecision,headRepository,maintainerCanModify,mergeStateStatus,url,mergeCommit
|
|
33
33
|
gh run list -R <owner>/<repo> -c <headRefOid> --json databaseId,status,conclusion,workflowName,url # Actions runs on the assessed head: held-run detection (action_required with or without a rollup entry)
|
|
34
34
|
gh api user --jq .login # viewer_is_author = (login == pr.author.login)
|
|
35
35
|
gh api graphql -f query='query($o:String!,$r:String!,$n:Int!){ repository(owner:$o,name:$r){ viewerPermission pullRequest(number:$n){ viewerCanUpdateBranch } } }' -f o=<owner> -f r=<repo> -F n=<N> # viewer_permission, can_update_branch; a null field is recorded as `unreadable`
|
|
@@ -62,7 +62,7 @@ provisioning, so it never re-reads; step 2 re-reads once after provisioning (`re
|
|
|
62
62
|
|
|
63
63
|
```text
|
|
64
64
|
- pr: { number, title, body, author, author_is_bot, state, isDraft, headRefName, baseRefName,
|
|
65
|
-
isCrossRepository, mergeable, mergeStateStatus, headRefOid, headRepository, maintainerCanModify, files, additions, deletions, reviewDecision }
|
|
65
|
+
isCrossRepository, mergeable, mergeStateStatus, headRefOid, headRepository, maintainerCanModify, files, additions, deletions, reviewDecision, url, merge_commit } # pr.url from url; pr.merge_commit = mergeCommit.oid, null while unmerged
|
|
66
66
|
- base_repository: <lowercase nameWithOwner from gh repo view in the resolved base context | unreadable>
|
|
67
67
|
- consent.target: { base_repository, number, baseRefName }
|
|
68
68
|
- consent.scope_at_grant: <selected scope; source: pr includes original_intent: { title, body }>
|
|
@@ -71,6 +71,8 @@ provisioning, so it never re-reads; step 2 re-reads once after provisioning (`re
|
|
|
71
71
|
- repair.rounds_used: <nonnegative integer, initially 0>
|
|
72
72
|
- repair.poll_deadline: null | <absolute timestamp for the watch window; reference/post-selection-loop.md ### Wait course>
|
|
73
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
|
+
- approved_head: null | <sha> # set by reference/post-selection-loop.md when gh pr review --approve exits 0; triggers the approved overlay
|
|
75
|
+
- cleanup_done: false | true # set by reference/cleanup.md after the cleanup pick runs
|
|
74
76
|
- viewer: { login, is_author }
|
|
75
77
|
- 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
78
|
- 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)
|
|
@@ -79,6 +81,7 @@ provisioning, so it never re-reads; step 2 re-reads once after provisioning (`re
|
|
|
79
81
|
- issue_ref: <ref> | null
|
|
80
82
|
- issue: null # shape and fill: step 2, reference/assessment.md ## Fetch the ticket
|
|
81
83
|
- worktree_discovery: { expected_path, exists, branch, dirty, ahead, behind }
|
|
84
|
+
- worktree: { path, branch, created, destroy } # filled in step 2, reference/assessment.md: worktree.path; worktree.branch is the actual local branch (headRefName, pr-<N>, or whatever a worktree wrapper created); worktree.created is true when this run created it; worktree.destroy is the wrapper's exact destroy invocation, else null
|
|
82
85
|
- sync: <record> # only with --rebase; grammar: reference/sync.md ## Sync record
|
|
83
86
|
- truncation_notes: []
|
|
84
87
|
```
|