pi-gauntlet 8.4.7 → 8.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +12 -6
- package/extensions/telemetry-settlement-contract.test.ts +29 -1
- package/package.json +2 -2
- package/skills/brainstorming/SKILL.md +5 -24
- package/skills/brainstorming/reference/opening-message.md +96 -0
- package/skills/gatekeep-pr/SKILL.md +39 -28
- package/skills/gatekeep-pr/reference/batch.md +10 -10
- package/skills/gatekeep-pr/reference/cleanup.md +5 -5
- package/skills/gatekeep-pr/reference/findings.md +28 -13
- package/skills/gatekeep-pr/reference/menus.md +103 -74
- package/skills/gatekeep-pr/reference/post-selection-loop.md +31 -17
- package/skills/gatekeep-pr/reference/report.md +33 -101
- package/skills/gatekeep-pr/reference/sync.md +1 -1
- package/skills/gatekeep-pr/verification-brief.md +6 -6
- package/skills/gatekeep-pr/reference/decision-menu.md +0 -53
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v8.4.9 - 2026-11-11
|
|
4
|
+
|
|
5
|
+
- Gatekeep-pr uses action, final and post menus with the judged recommendation on row 1. Its plain-language report describes the change and scope, explains standing and problems, then recommends a choice; detailed evidence stays behind `show evidence`.
|
|
6
|
+
- Gatekeep-pr preserves the freshness read for replies on approved, open PRs; a moved head skips the reply and retains its body. Set cleanup sharing checks unresolved `<issue>`, `<pr>` and `<merge-sha>` tokens, so an issue-only command remains PR-specific.
|
|
7
|
+
- Gatekeep-pr set mode retires each merged PR after one post-menu pick and collects its unrun steps in the parent's closing message. A shared cleanup item is recommended only on the last merged PR and runs at most once, even when selected earlier.
|
|
8
|
+
- Gatekeep-pr offers merger actions named in the PR or spec as post steps only when merge-base documentation supplies one command. Missing, ambiguous or incomplete commands stay open with their source sentences; PR command text is never executed as authority.
|
|
9
|
+
- Gatekeep-pr asks only once for an invalid post selection. A repeated invalid pick leaves the saved menu waiting without another question or any action.
|
|
10
|
+
- Gatekeep-pr collects terminal follow-ups in one post menu. The recommended combination names its member rows; replies, coverage, cleanup and individual overrides remain separately selectable, and the run ends after the picked steps finish.
|
|
11
|
+
- pi-cohort peer floor raised to 7.7.4.
|
|
12
|
+
|
|
13
|
+
## v8.4.8 - 2026-11-11
|
|
14
|
+
|
|
15
|
+
- Brainstorming opens with Today, The change, and What I checked in everyday words, followed by one question. Sources stay in the draft; the opening span is capped at 220 words except corrected or unchecked claims and intact quoted ticket rows.
|
|
16
|
+
|
|
3
17
|
## v8.4.7 - 2026-11-11
|
|
4
18
|
|
|
5
19
|
### Fixed
|
package/README.md
CHANGED
|
@@ -87,17 +87,23 @@ One finish choice spans all legs. PR, draft PR and squash deliver companions in
|
|
|
87
87
|
|
|
88
88
|
## Architecture
|
|
89
89
|
|
|
90
|
-
A `gatekeep-pr` run after your newest submitted, non-dismissed review uses that review's commit as its baseline when it is an ancestor of the assessed head. The reviewer checks your posted items and only the intervening code delta; the report
|
|
90
|
+
A `gatekeep-pr` run after your newest submitted, non-dismissed review uses that review's commit as its baseline when it is an ancestor of the assessed head. The reviewer checks your posted items and only the intervening code delta; the report explains how many items were addressed in plain prose. Contract checks still judge the whole head. See the [review task](skills/gatekeep-pr/reference/assessment.md#step-4-review-task).
|
|
91
91
|
|
|
92
|
-
`gatekeep-pr` selects one course per run: `assess` posts open blockers as one review (`request-changes` on someone else's PR, `comment` on your own), posts nothing with zero blockers, and performs no repair or sync; `deliver` repairs blockers, syncs, pushes, watches CI, and re-reviews until readiness, an obstacle, or a cap exit. `deliver with nits` stores `deliver-nits` and includes current and later nits. A ready first report skips the course pick and renders the final menu directly. Delivery rebases your own non-bot branch with `--force-with-lease` unless its history contains merge commits; someone else's, bot-authored, and merge-containing heads merge base instead. Final `merge` and `approve` remain separate picks; approval is offered only on someone else's non-draft PR with zero blockers. See the [course loop](skills/gatekeep-pr/reference/post-selection-loop.md) and [
|
|
92
|
+
`gatekeep-pr` selects one course per run: `assess` posts open blockers as one review (`request-changes` on someone else's PR, `comment` on your own), posts nothing with zero blockers, and performs no repair or sync; `deliver` repairs blockers, syncs, pushes, watches CI, and re-reviews until readiness, an obstacle, or a cap exit. `deliver with nits` stores `deliver-nits` and includes current and later nits. A ready first report skips the course pick and renders the final menu directly. Delivery rebases your own non-bot branch with `--force-with-lease` unless its history contains merge commits; someone else's, bot-authored, and merge-containing heads merge base instead. Final `merge` and `approve` remain separate picks; approval is offered only on someone else's non-draft PR with zero blockers. See the [course loop](skills/gatekeep-pr/reference/post-selection-loop.md) and [three menus](skills/gatekeep-pr/reference/menus.md). In pi, `/skill:gatekeep-pr 12 15 18 [--rebase [base]]` gates a set of PR numbers or same-repository URLs, with one fresh `pr-gatekeeper` child and one worktree per PR. The parent shows a summary and unchanged per-PR menus in input order and queues every pick until the last menu. It runs terminal consequences in roster order from the primary checkout and dispatches nonterminal child work in parallel. The set must fit pi-cohort's `parallel.maxTasks` (default `8`); it is never chunked. With `--rebase`, the parent asks once per set for eligible other-author or unreadable-author heads, excluding no-op heads and heads with merge commits. Multi-PR mode rejects positional issue references and is pi-only. An explicit no-argument invocation on either harness discovers your open PRs in origin, authored by you or directly awaiting your review (not team requests), excludes drafts and the `APPROVED` and `CHANGES_REQUESTED` states, and sorts by additions plus deletions, then PR number, ascending. One match gates directly on the single-PR path; multiple matches enter pi's batch path, while Claude Code stops with the sorted `discovered, smallest first:` list. Every report explains the refreshed viewer's role and the other requested reviewers in plain prose, not in the batch summary row. See the [parent-child contract](skills/gatekeep-pr/reference/batch.md).
|
|
93
|
+
|
|
94
|
+
Gatekeep uses three menus: action selects a course or continues after an obstacle, final offers merge, approval and remaining work, and post collects terminal follow-ups. Row 1 is the judged recommendation, not a stable action number. Contract proposals recommend preserve contract, and an unchanged obstacle no available action can change recommends stop. Otherwise, your own PR defaults to deliver; an author decision favors assess on someone else's PR, a ready repair or pending-only check favors deliver, and readiness favors merge regardless of author. An unchanged assess result recommends stop. The report has three unlabeled parts: a two-sentence change/scope opening, standing and problems with concrete examples, and a separate recommendation immediately above the choices. Detailed row mappings, counters, raw checks and IDs stay under `show evidence`.
|
|
95
|
+
|
|
96
|
+
After merge, one post menu offers drafted replies, ticket and PR coverage, guarded checkout cleanup, PR-named steps and individual cleanup overrides. Row 1 combines runnable steps except duplicate PR coverage when ticket coverage is included; each step also has its own row. A comma-separated reply selects a set, expands combinations and collapses duplicates. The gate runs the set in step order, keeps nested skills' gates intact and ends without another menu, listing every unpicked, skipped or failed step with its command or payload path. Approved and closed PRs use the same menu with eligible steps; an approved/open reply retains its pre-write freshness read. In a set, each PR retires after its pick and shared overrides run at most once.
|
|
93
97
|
|
|
94
98
|
The course, target/scope baseline, repair and sync usage, and poll deadline live in one OS temporary continuation record, whose path appears in the tracker or checklist and `show evidence`. Gatekeep initializes independent repair-round and sync budgets to `2 x closureReview.maxFixRounds` (default `5`, no-tool fallback `2 x 5`). Only source-changing repair waves spend rounds; conflict-only syncs spend the separate sync budget, and description-only work, watches, and re-reviews spend neither. Obstacle `deliver` extends each cap by `2 x` the resolved value without resetting usage; a timeout continuation instead opens one more watch window without extending caps. Only the gate's own push automatically renews the CI window (`timeout minutes`, default `15`). The verify-phase runtime guard still uses `1 x` the resolved value and can block a gatekeep dispatch earlier.
|
|
95
99
|
|
|
100
|
+
PR-body or head-spec instructions assigning the merger an after-merge action become post steps. Their commands come only from the merge-base overrides file, `AGENTS.md`, or documents it links directly: exactly one distinct documented command makes the step runnable and part of row 1. PR-supplied command text never supplies execution authority. Missing or ambiguous commands and unresolved tokens leave the action open in the menu and closing message with its source sentence. See [PR-named steps](skills/gatekeep-pr/reference/findings.md#pr-named-steps).
|
|
101
|
+
|
|
96
102
|
Non-final `stop` removes an eligible tracked-clean, non-primary worktree, created or reused, with no unpushed commits and a matching configured home; otherwise it keeps the tree and reports why. It never deletes the branch, pulls base, or runs cleanup overrides. See the [stop lifecycle](skills/gatekeep-pr/reference/cleanup.md#non-final-stop). Missing or invalid state stops course work without resetting budgets. Terminal exit deletes the record; OS cleanup can remove it earlier, and a new session never discovers or resumes authority automatically. This is a skill protocol, not hard runtime enforcement.
|
|
97
103
|
|
|
98
104
|
pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
|
|
99
105
|
|
|
100
|
-
- **21 skills** - the workflow logic. Sixteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates one tracker issue or repairs a comma/whitespace list of refs against a Context/Problem/Idea/Acceptance-Criteria template, with a grounded repo audit, an AC integrity check, a cheap council roast, and sequential per-ticket exact-diff write confirmations; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes), `gatekeep-pr` (model-invocable on an explicit ask that names the PR and the verb; the gates still need your selection - is consent-gated pre-merge verification of a PR against the scope contract at its head - the approved spec's acceptance-criteria dispositions and Design when the PR carries one, else the PR's stated intent; the ticket is cross-checked, never judged here (`check-delivery` owns it) - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; a pending commit status that GitHub does not report as blocking the gating actor (`mergeStateStatus` not `BLOCKED`) is not waited for - external-CI commit statuses included - while a running Actions check and an unknown merge state still withhold; a viewer GitHub reports as a ruleset bypass actor merges a `BLOCKED` PR on the ordinary `merge` row with CI evidence still binding and all other merge preconditions unchanged; false or unreadable bypass eligibility keeps `BLOCKED` withheld, and live non-admin bypass behavior remains unverified; the project's verification command runs only as fallback), a rubric-based review, a
|
|
106
|
+
- **21 skills** - the workflow logic. Sixteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates one tracker issue or repairs a comma/whitespace list of refs against a Context/Problem/Idea/Acceptance-Criteria template, with a grounded repo audit, an AC integrity check, a cheap council roast, and sequential per-ticket exact-diff write confirmations; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes), `gatekeep-pr` (model-invocable on an explicit ask that names the PR and the verb; the gates still need your selection - is consent-gated pre-merge verification of a PR against the scope contract at its head - the approved spec's acceptance-criteria dispositions and Design when the PR carries one, else the PR's stated intent; the ticket is cross-checked, never judged here (`check-delivery` owns it) - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; a pending commit status that GitHub does not report as blocking the gating actor (`mergeStateStatus` not `BLOCKED`) is not waited for - external-CI commit statuses included - while a running Actions check and an unknown merge state still withhold; a viewer GitHub reports as a ruleset bypass actor merges a `BLOCKED` PR on the ordinary `merge` row with CI evidence still binding and all other merge preconditions unchanged; false or unreadable bypass eligibility keeps `BLOCKED` withheld, and live non-admin bypass behavior remains unverified; the project's verification command runs only as fallback), a rubric-based review, a three-part plain-language report (change and scope, standing and problems, then recommendation) and action, final and post menus whose rows derive from the actor's permissions on the PR; nothing mutates (repairs, pushes, reviews, merges, tracker comments) until you pick a course or terminal row, except the opt-in `--rebase [base]` sync that rebases, reviews, and lease-pushes the head before verification, or holds the rebased head locally when a conflict stop's scoped tests fail, so a selected delivery course resolves it before the lease push; after your own merge one post menu offers drafted replies, ticket and PR copies of `AC coverage`, guarded checkout cleanup and separate `## cleanup` items; row 1 combines the runnable steps except duplicate PR coverage when ticket coverage is included, each step keeps its own row, and the run ends after the selected set finishes; approved and closed-PR states use the same post menu with their eligible steps - run it with `/skill:gatekeep-pr [<pr>] [--rebase [base]]` (no argument: your open PRs)), `check-delivery` (model-invocable on an explicit ask that names the ticket and the verb; the gates still need your selection - is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>` or, in pi, `/skill:check-delivery #12 #15` for fresh parallel verification and one gate and write per ticket in turn), `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `loop-implementation` (the plan-free implement driver that iterates a fresh `loop-implementer` over the spec's acceptance-criteria ledger when approval picks the loop engine), `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `forge-skill`, `linear` (reads/searches/comments on/manages Linear tickets via the `linearis` CLI; owns all linearis mechanics and the `## Issue tracker` overrides schema; tracker-facing skills route to it). Five more require explicit entry (`disable-model-invocation: true`): `brainstorming` starts the gated workflow on explicit consent - use `/skill:brainstorming` for reliable discovery, or opt in through reachable explicit prose or a human-selected handoff; after spec approval, downstream planning and implementation still chain automatically. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/hotfix/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage; the hotfix row hands off to `skills/chase-bug/hotfix.md` after the menu - run it with `/skill:chase-bug`. `gauntlet-performance` reads the committed run telemetry (current repo by default, `--dir <path>` adds others) through the parse-only `gauntlet-performance` CLI and answers with one example-led recommendation, 3-5 cornerstone numbers, a council assessment when available, and a menu of at most three actions (render a report file, open the recommendation as a ticket via `shape-ticket`, drill into one run); it writes nothing unless you pick render - run it with `/skill:gauntlet-performance [--dir <path>]... [--since <version>]`. `gauntlet-handoff` ends a session whose flow a fresh session will continue: it invokes pi-cohort's `handoff` skill (`--out <path>` or `--key <name>`, default key = the run worktree's branch with `/` flattened to `-`, default file `<tmpdir>/pi-handoff/<key>.md`), then appends the gauntlet process-state section (phase/plan tracker status) per the shared contract `skills/gauntlet-resume/reference/brief-contract.md` - run it with `/skill:gauntlet-handoff [--out <path> | --key <name>]`. `gauntlet-resume` is the only way back into an interrupted flow from a fresh session: it takes a `gauntlet-handoff` brief (a file path, pasted text, or - with no arguments - a pick from the briefs under `<tmpdir>/pi-handoff/`), a bare worktree that already holds a spec, or a spec tracked on main under a configured spec dir (a spec seed: it creates or reuses the worktree through `using-git-worktrees` and pins the spec), restores phase/plan tracker state through the legal arming sequence (`start brainstorm`, `skip` with `resume:` reasons, `plan_check` before implement-or-later), and never infers approval from artifacts - run it with `/skill:gauntlet-resume [<brief-file> | <spec>.md | <worktree-name-or-path>]`.
|
|
101
107
|
- **11 subagent personas** - the specialized child agents the skills dispatch via pi-cohort: `implementer`, `loop-implementer`, `wave-reviewer`, `conformance-reviewer`, `spec-summarizer`, `plan-writer`, `spec-council-member`, `spec-council-synthesizer`, `spec-council-applier`, `pr-gatekeeper`, `delivery-checker`. See [doc/personas.md](./doc/personas.md) for what each one does and why its permissions are scoped the way they are.
|
|
102
108
|
- **4 runtime extensions** - the enforcement layer. `plan-tracker` and `phase-tracker` are tools skills call to track progress (with a TUI widget); `verify-before-ship` is a hook that warns if you push or open a PR without a passing test run since your last edit (expected when a loop gate set does not match its patterns; the scoped `Verification:` line answers it, not a full local run); a phase-tracker flow guard reminds on implement-phase commits missing spec/code review. Both engines use the tracker: waves manages plan tasks, while loop calls `plan_tracker refresh` to project ledger rows and preserve conformance tasks. Loop implement completes when every row is closed, then verify step 1 runs the ledger's gate set in the owning checkouts. In a brainstorming-entered flow, phase-tracker rejects `implement` or `verify` completion while tracker tasks remain pending or in progress; see [its configuration reference](./doc/configuration.md#phase-tracker). phase-tracker also registers `plan_check`, which verifies a plan against its spec and against the grammar in [skills/writing-plans/reference/plan-contract.md](./skills/writing-plans/reference/plan-contract.md), including that each task's `Tests:` commands are selective and never the full suite, and that every test command carries a passing base-commit result; a pass stamps the plan and spec content hashes for implementation and returns a bounded task manifest; see the [manifest contract and size limit](./doc/configuration.md#phase-tracker). `telemetry` publishes YAML records on the `refs/telemetry/records` ref, outside the product diff: one sealed brainstorming run plus one session leg per settled `shape-ticket`, `gatekeep-pr` or `check-delivery` invocation. In-progress runs live in Git common-dir metadata; `gauntlet-telemetry-seal` publishes before landing without changing checkout HEAD or index. Publication failure warns without blocking ship; plain jj keeps local metadata and reports no Git remote. A fetched shipped record blocks a brainstorm `write` into that spec. See [the record layout, settings and migration guide](./doc/configuration.md#telemetry). See [doc/configuration.md](./doc/configuration.md) for the settings each one reads. `phase_tracker`, `plan_check`, and `plan_tracker` are model-only (not callable from codemode scripts) because their state is rebuilt from transcript tool results, which nested calls do not persist.
|
|
103
109
|
|
|
@@ -142,7 +148,7 @@ Run by a human against pi-cohort >= 7.1.0, before a pi-gauntlet release claims t
|
|
|
142
148
|
## Requirements
|
|
143
149
|
|
|
144
150
|
- [pi-coding-agent](https://github.com/earendil-works/pi) >= 1.5.0 - supports model-only tracker exposure and sequential tracker execution, so updates persist as transcript tool results rather than nested calls.
|
|
145
|
-
- [pi-cohort](https://github.com/jjuraszek/pi-cohort) >= 7.7.
|
|
151
|
+
- [pi-cohort](https://github.com/jjuraszek/pi-cohort) >= 7.7.4 - required peer package, including binary-safe worktree patches; it also lets a persona with `subagent` in `tools:` start with inherited extensions ([pi-cohort #26](https://github.com/jjuraszek/pi-cohort/issues/26)), which multi-PR `gatekeep-pr` needs. Skills that dispatch agents (`requesting-code-review`, `subagent-driven-development`, `dispatching-parallel-agents`, `writing-plans`, `forge-skill`, `shape-ticket`, `roasting-the-spec`) call `subagent({})`, which pi-cohort provides. pi-gauntlet does not vendor the dispatch tool; without pi-cohort those skills have nothing to call. Gauntlet execution dispatches explicitly use `async: false`; do not enable pi-cohort's incompatible `forceTopLevelAsync` setting. See pi-cohort's [dispatch configuration](https://github.com/jjuraszek/pi-cohort/blob/main/doc/configuration.md) for that setting's owner and semantics. A wave of N >= 1 tasks dispatches its implementers and first spec reviews as one chain call. `subagent-driven-development` stops before dispatch on unsupported installs; there is no older-runtime fallback.
|
|
146
152
|
|
|
147
153
|
Both packages must be listed in your `.pi/settings.json#packages` array (pi adds them automatically when you `pi install`). pi-gauntlet and pi-cohort are versioned independently but release together whenever dispatch semantics change - pin compatible versions of both. At each pi-gauntlet release, set the pi-cohort peer minimum and README floor together to the newest released pi-cohort version; `/skill:release` checks the registry before proceeding.
|
|
148
154
|
|
|
@@ -345,7 +351,7 @@ The gauntlet overrides file is the one place a repo tunes gauntlet's Markdown su
|
|
|
345
351
|
| `## using-git-worktrees` `- home: <path pattern>` | using-git-worktrees, finishing-a-development-branch, gatekeep-pr | `<primary>/.worktrees/<name>` | overrides | where worktrees live; `<name>` is the branch (`/` -> `-`) or `pr-<N>`; the ownership test at cleanup |
|
|
346
352
|
| `## using-git-worktrees` `- create: <command>` | using-git-worktrees, gatekeep-pr | `git worktree add` at `home:` | overrides | creation command run from the primary; `<name>`, `<branch>` substituted, other `<token>`s resolved from context or asked once |
|
|
347
353
|
| `## using-git-worktrees` `- destroy: <command>` | finishing-a-development-branch, gatekeep-pr | `git worktree remove` + `prune` when the path matches `home:` | overrides | removal command run from the primary; a failure keeps the branch |
|
|
348
|
-
| `## cleanup` items `- <label>: <command or /skill:...>` | gatekeep-pr | git teardown and base sync only | extends |
|
|
354
|
+
| `## cleanup` items `- <label>: <command or /skill:...>` | gatekeep-pr | git teardown and base sync only | extends | separate post-menu steps with `<issue>`, `<pr>`, `<merge-sha>` selected individually or in the recommended combination; inherits `## PR gate` `timeout minutes:`; missing placeholders or unlanded-change steps are skipped with a reason; `/skill:` items keep their own gates |
|
|
349
355
|
| `## PR gate` keys (`verification command`, `timeout minutes`, `requires credentials`, `local verification`, `ci checks`, `issue fetch`, `merge policy`) | gatekeep-pr | per-key defaults in the block below | overrides | the gate's verification, evidence, and merge configuration |
|
|
350
356
|
| `## comms style` | gatekeep-pr | shipped wording rules | extends | tone and format of reports, menus, and external payloads |
|
|
351
357
|
| `## verification-before-completion` | verification-before-completion; gatekeep-pr (verification command only); chase-bug (hotfix verification) | repo test entrypoint discovery | overrides | the canonical verification target |
|
|
@@ -585,7 +591,7 @@ customization lives in three places, never in the wrapper itself:
|
|
|
585
591
|
- merge policy: squash | merge-commit | rebase # optional; default squash; chooses gh pr merge flag for final merge only, never sync strategy or approval
|
|
586
592
|
```
|
|
587
593
|
|
|
588
|
-
- **The gauntlet overrides file, `## cleanup` section** - the ordered
|
|
594
|
+
- **The gauntlet overrides file, `## cleanup` section** - the ordered follow-up steps selected through the post menu (contract under Project-specific overrides above).
|
|
589
595
|
|
|
590
596
|
An existing `## verification-before-completion` overrides section is an accepted
|
|
591
597
|
equivalent source for the verification command only; all other PR-gate keys
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { readFileSync, readdirSync } from "node:fs";
|
|
3
3
|
import test from "node:test";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { lintGateContract } from "../scripts/gate-contract-lint.mjs";
|
|
4
6
|
import { settlementItems } from "./lib/telemetry-leg.ts";
|
|
5
7
|
import { MODELS } from "../eval/lib/models.mjs";
|
|
6
8
|
|
|
@@ -41,7 +43,7 @@ test("skill owners keep terminal rows after writes and cleanup", () => {
|
|
|
41
43
|
const gate = read("skills/gatekeep-pr/reference/post-selection-loop.md");
|
|
42
44
|
assert.ok(gate.includes("#<N>@<head sha>: <outcome>"));
|
|
43
45
|
assert.match(gate, /full assessed `headRefOid`/);
|
|
44
|
-
assert.match(gate, /
|
|
46
|
+
assert.match(gate, /Emit the terminal message only after the selected post set finishes or stop declines it; a report or menu is not settlement/);
|
|
45
47
|
assert.match(read("skills/gatekeep-pr/reference/batch.md"), /gauntlet: retired #<N> - <reason>/);
|
|
46
48
|
assert.match(read("skills/gatekeep-pr/reference/cleanup.md"), /### Settlement rows/);
|
|
47
49
|
const ci = read("scripts/ci.mjs");
|
|
@@ -52,6 +54,32 @@ test("skill owners keep terminal rows after writes and cleanup", () => {
|
|
|
52
54
|
}
|
|
53
55
|
});
|
|
54
56
|
|
|
57
|
+
test("gatekeep published gate markers and terminal settlements stay compatible", () => {
|
|
58
|
+
const contract = read("doc/gate-contract.md");
|
|
59
|
+
for (const id of ["initial", "obstacle", "contract-exception", "final", "assess-terminal", "own-merge", "approved", "closed-pr", "merge-queued"]) {
|
|
60
|
+
assert.ok(contract.includes(`| gatekeep-pr/${id} | gate | skills/gatekeep-pr/reference/menus.md |`), id);
|
|
61
|
+
}
|
|
62
|
+
assert.deepEqual(lintGateContract(fileURLToPath(new URL("../", import.meta.url))), []);
|
|
63
|
+
const terminals = contract.split("\n")
|
|
64
|
+
.filter((line) => line.startsWith("| gatekeep-pr |"))
|
|
65
|
+
.map((line) => line.split("|")[4].trim());
|
|
66
|
+
assert.deepEqual([...new Set(terminals)].sort(), [
|
|
67
|
+
"gauntlet: done approved", "gauntlet: done merged", "gauntlet: done closed-pr",
|
|
68
|
+
"gauntlet: done final", "gauntlet: done merge-queued", "gauntlet: stuck",
|
|
69
|
+
"gauntlet: done retired", "gauntlet: stuck retired",
|
|
70
|
+
].sort());
|
|
71
|
+
for (const outcome of ["approved", "merged", "closed-pr", "final", "merge-queued", "stuck - CI failed"]) {
|
|
72
|
+
const marker = outcome.startsWith("stuck -") ? "gauntlet: stuck CI failed" : `gauntlet: done ${outcome}`;
|
|
73
|
+
for (const ticket of [undefined, "#12"]) {
|
|
74
|
+
const row = `#31@${head}: ${outcome}${ticket ? ` (${ticket})` : ""}`;
|
|
75
|
+
assert.deepEqual(settlementItems("gatekeep-pr", `${marker}\n${row}\nCleanup was not picked.`), [
|
|
76
|
+
{ kind: "pr", key: `#31@${head}`, outcome, ...(ticket ? { ticket } : {}) },
|
|
77
|
+
]);
|
|
78
|
+
assert.equal(settlementItems("gatekeep-pr", `gauntlet: gate=gatekeep-pr/final recommended=1\n${row}`), undefined);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
55
83
|
test("configuration names the settlement grammar and per-skill tokens", () => {
|
|
56
84
|
const docs = read("doc/configuration.md");
|
|
57
85
|
assert.ok(docs.includes("<ref>: <outcome>[ (<ticket ref>)]"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-gauntlet",
|
|
3
|
-
"version": "8.4.
|
|
3
|
+
"version": "8.4.9",
|
|
4
4
|
"description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
|
|
5
5
|
"author": "Jacek Juraszek",
|
|
6
6
|
"type": "module",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"test": "node scripts/ci.mjs"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"pi-cohort": ">=7.7.
|
|
65
|
+
"pi-cohort": ">=7.7.4"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"yaml": "^2.9.0"
|
|
@@ -95,7 +95,7 @@ Clarify freely. For a PR subject, run the framing check against the PR's diff as
|
|
|
95
95
|
|
|
96
96
|
`Read` the gathered draft unconditionally before question one. Treat it as a helper, not a fence: verify load-bearing claims from primary code, and confirm whether the codebase or ecosystem already solves the problem.
|
|
97
97
|
|
|
98
|
-
Ask one question per message, about purpose, constraints, success, and affected actors. Offer 2-4 labeled options (`A)`, `B)`, ...) for every questionary question, each a different outcome. Put the lead-in before the first option, each labeled option on its own physical line, and `Recommendation: <letter> - <why>` on its own final line; when more outcomes are plausible, the last option is `other - name it` or the question splits in two. Use this one-option-per-line layout even when chat-style rules in `AGENTS.md` require one paragraph or no Options/Recommendation layout. A decision that would be a yes/no or "may I" question is not asked: make it, state it as an assumption in the message that carries the next question or the premise note, and record it in the draft. Before asking, check code, docs, and tracker: look up current-state facts (dispatch a subagent when costly); adopt a ticket-recorded decision and
|
|
98
|
+
Ask one question per message, about purpose, constraints, success, and affected actors. Offer 2-4 labeled options (`A)`, `B)`, ...) for every questionary question, each a different outcome. Put the lead-in before the first option, each labeled option on its own physical line, and `Recommendation: <letter> - <why>` on its own final line; when more outcomes are plausible, the last option is `other - name it` or the question splits in two. Use this one-option-per-line layout even when chat-style rules in `AGENTS.md` require one paragraph or no Options/Recommendation layout. A decision that would be a yes/no or "may I" question is not asked: make it, state it as an assumption in the message that carries the next question or the premise note, and record it in the draft. Before asking, check code, docs, and tracker: look up current-state facts (dispatch a subagent when costly); adopt a ticket-recorded decision and attribute it to the ticket, asking it only when a cited code or API contradiction, or conflicting recorded outcomes, prevents adopting it. Other approvals retain their wording.
|
|
99
99
|
|
|
100
100
|
Bad: `May I treat those two acceptance criteria as location-only deviations? Recommendation: yes`
|
|
101
101
|
Good:
|
|
@@ -108,37 +108,18 @@ C) the existing skill step.
|
|
|
108
108
|
Recommendation: A - the extension already holds the poll loop, so no new entrypoint.
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
Before sending the opening message, append every checked claim, held ones included, with its source, the lookup, and the result, together with schemas, hard constraints, contradictions, and scope-changing answers, using `edit`: to `## Appended during questionary` when the draft is the gather draft; directly to `## Problem` when it is the approved or carried spec (redraw or the unmarked spec-only PR route), where gather is skipped and that section does not exist.
|
|
112
112
|
|
|
113
|
-
Before approaches, state in chat the supported, disproved, corrected, and unverified premises
|
|
113
|
+
Before approaches, state in chat the supported, disproved, corrected, and unverified premises in the opening message's `## What I checked` section: supported renders as `Held:`, disproved and corrected as `Corrected:`, and unverified as `Not checked:`; that section is the premise note, and after the opening message a premise note is a `Corrected:` line. Treat an implicit dependency found missing as a corrected premise and one not checkable as unverified; state each in the premise note in everyday words that name what was looked at and what was found; record the lookup the repo or spec names and its result in the draft, and carry it into `## Problem`. An unverified claim is not a stop: put it in Open Questions or a stated assumption. If a load-bearing claim is contradicted, the premise note is your next message - even as question one - and states the corrected fact; the design continues on it and the user overrides in reply. Record the corrected fact, and any override, in the draft for `## Problem` or the relevant design decision; spec-writing carries every recorded claim, held ones included, into `## Problem`.
|
|
114
114
|
|
|
115
|
-
Before question one, verify the draft's `Framing:` line against primary code and add your own recon. This check adds to the premise verification above and never replaces it: trace every consumer, caller, and data path the ask's constraints name, including retained loaders and every repro and verification step's implicit dependencies, before writing the holds-statement or the question; check those dependencies with the lookup the repo or spec names, and
|
|
115
|
+
Before question one, verify the draft's `Framing:` line against primary code and add your own recon. This check adds to the premise verification above and never replaces it: trace every consumer, caller, and data path the ask's constraints name, including retained loaders and every repro and verification step's implicit dependencies, before writing the holds-statement or the question; check those dependencies with the lookup the repo or spec names, and record the traces and dependencies in the draft through the evidence write above. A framing concern exists when you can state a cited case that the ask is misdiagnosed, wrong-sized, already solved, a band-aid where the root cause is reachable, or cuts across a sound pattern - including a repo convention that is itself the debt - and can name the alternative it implies; an objection without an alternative is a lead to investigate, not a concern. With a concern, question one is the framing question; without a concern, the message carries the holds-statement and the first ordinary question.
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
gauntlet: question
|
|
119
|
-
A) as framed
|
|
120
|
-
B) pivot: <named alternative> - <cited reason>
|
|
121
|
-
C) smaller or none: <what ships, or what happens if nothing ships>
|
|
122
|
-
Recommendation: <letter> - <why>
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
For a band-aid concern, put the root-cause alternative in B. Without a concern, follow the marker with one sentence naming what was checked - `The framing holds: checked <x>, <y>` - and continue to the first ordinary question; a scout objection that yielded no alternative is named among the things checked.
|
|
117
|
+
Read [Opening message](reference/opening-message.md) now and write question one's message against it; unreadable -> stop with a blocking error, never write it from memory.
|
|
126
118
|
|
|
127
119
|
After any premise correction in the same message, ask the framing question or give the holds-statement. Ask the framing question at most once per brainstorm, including after pushback; the user's reply is final, and later doubts on the same point go to Open Questions or a `Pattern:` line. Recommend; never pivot without the reply. A ticket-recorded decision on the exact point follows the ticket rule above; an adopted decision records `Framing: kept (ticket <id>)`. A pivot never rewrites AC rows: rows it no longer satisfies take `deviates:` dispositions, and a pivot that changes the topic re-mints the slug.
|
|
128
120
|
|
|
129
121
|
Record the outcome in the draft under `## Appended during questionary` as `Framing: kept` or `Framing: pivoted to <x> - <why>`; spec-writing carries that line into `## Problem`. On redraw entry (checklist step 4) the count restarts: run this evaluation once against the new draft. On redraw the draft is the approved spec: its `## Problem` `Framing:` line is context, not scout evidence, and the new outcome is recorded directly in `## Problem`. When the scout failed there is no `Framing:` line; supply the implicit-dependency check and the holds-statement or question from your own recon.
|
|
130
122
|
|
|
131
|
-
Bad: `The ask adds another settings path - should we? Recommendation: no`
|
|
132
|
-
Good:
|
|
133
|
-
```text
|
|
134
|
-
gauntlet: question
|
|
135
|
-
The ask adds a second settings path beside the resolver that already owns every setting (settings/resolver.ts:11).
|
|
136
|
-
A) as framed
|
|
137
|
-
B) pivot: a key under the existing resolver - one read path, no new boundary
|
|
138
|
-
C) smaller or none: document the default and ship no setting.
|
|
139
|
-
Recommendation: B - the owning schema already exists.
|
|
140
|
-
```
|
|
141
|
-
|
|
142
123
|
### 4. Explore approaches
|
|
143
124
|
|
|
144
125
|
In a separate message after the premise note, restate each implicit dependency recorded as missing or not checkable, with its lookup and result, before presenting any approaches.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Opening message
|
|
2
|
+
|
|
3
|
+
Use this wording for question one's message at checklist step 4, including fresh, redraw, restored, and unmarked spec-only PR entry. Apply [Menu layout](menu-layout.md) for the first-line rule. The relatedness question before provisioning belongs to `pr-subject.md`.
|
|
4
|
+
|
|
5
|
+
## Shape
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
gauntlet: question
|
|
9
|
+
|
|
10
|
+
## Today
|
|
11
|
+
<how the affected part works now>
|
|
12
|
+
|
|
13
|
+
## The change
|
|
14
|
+
<what the request does to it, as something the user observes>
|
|
15
|
+
|
|
16
|
+
## What I checked
|
|
17
|
+
- Held: <one short sentence naming the held claims by role>
|
|
18
|
+
- Corrected: <the claim as stated>; <the fact>, so <the consequence for the design>.
|
|
19
|
+
- Not checked: <the claim> - <why it could not be checked>, so <what the design assumes or waits on>.
|
|
20
|
+
|
|
21
|
+
The framing holds: checked <things, named by what they do>.
|
|
22
|
+
<lead-in question>
|
|
23
|
+
A) <outcome>
|
|
24
|
+
B) <outcome>
|
|
25
|
+
Recommendation: <letter> - <why>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Keep the three titles in that order, with a blank line between sections. Give each body one short paragraph or one list. Use `##`: pi renders it as a bold title, while `###` keeps its hashes.
|
|
29
|
+
|
|
30
|
+
| Section | Write |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `## Today` | Summarize how the affected part behaves now in one to three present-tense sentences total, combining related behaviors within a sentence. For a PR subject describe the PR's current state; on a redraw, the approved spec. |
|
|
33
|
+
| `## The change` | Write one to three sentences total about the changes the user observes once it ships; fit related outcomes and any stated assumption into those sentences. Put the held claims' consequence for the design here, not on the `Held:` line. For a ticket request, say what the ticket asks, without listing acceptance rows. Put an assumption made in place of a yes/no question last. |
|
|
34
|
+
| `## What I checked` | Group the held claims by role in one short `Held:` sentence; keep per-claim evidence in the draft. Give each corrected premise one `Corrected:` line stating the fact and its consequence for the design. Give each unverified premise, and a ticket gather could not fetch, one `Not checked:` line with the reason and what the design assumes or waits on. Use SKILL.md's premise paragraph to classify them. Omit labels with no entry. With no claims, write only `The design rests on no claims.` |
|
|
35
|
+
|
|
36
|
+
For a request that is only an unread ticket reference, make `## Today` and `## The change` one sentence each saying their content is not known until the ticket's content is supplied. Infer neither current behavior nor the requested change from the reference or repo recon. Keep the `Not checked:` line, the framing line, and the usual question slot; name the failed ticket fetch among the things checked in `The framing holds: checked ...`.
|
|
37
|
+
|
|
38
|
+
## Words and length
|
|
39
|
+
|
|
40
|
+
Name each part by what it does. Use a literal name when the user used it in the request or when it is the finding itself: a missing file, a failing input, a quoted ticket row. Name a lookup by what was looked at, such as `the supplied templates/ directory listing`. Keep file-and-line references, commit ids, tracker ids, and trace counts in the draft. Use a tracker id only inside a command option such as `/skill:shape-ticket <ref>`, even when the user typed it; elsewhere, including an unfetched-ticket line, say `the ticket`, and render a lettered option with an unsupplied destination as a request to name that destination.
|
|
41
|
+
|
|
42
|
+
Keep at most 220 words from the `## Today` line through the line before the first lettered option, both included. Exclude the marker and options. Count whitespace-delimited tokens containing a letter or digit: titles and labels count; `##` and `-` do not. Over the cap, cut `## Today` and `## The change` to one sentence each; keep `Held:` to its one short sentence. Only `Corrected:` lines, `Not checked:` lines, and an intact quoted ticket row in the question may then carry the message past 220: none of them is dropped, and the row stays intact.
|
|
43
|
+
|
|
44
|
+
## Framing and question
|
|
45
|
+
|
|
46
|
+
Write `The framing holds: checked <x>, <y>` with the checked things named by role, including a scout objection that yielded no alternative. For a concern, replace that line with the concern in one sentence, then offer `A) as framed`, `B) pivot: <named alternative> - <reason in everyday words>`, and `C) smaller or none: <what ships, or what happens if nothing ships>`, ending with `Recommendation: <letter> - <why>`. Put the root-cause alternative in B for a band-aid concern.
|
|
47
|
+
|
|
48
|
+
Use the question slot for one question: the framing question with a concern, otherwise the first ordinary question. Apply [Ticket acceptance - Cut question](ticket-acceptance.md#cut-question) and its trigger table for which question comes first, when a cut question takes the slot, and how its row is quoted.
|
|
49
|
+
|
|
50
|
+
Render the sections from the recon at hand; give anything it could not check a `Not checked:` line. Leave scout-failure flow to SKILL.md's `Framing:` record paragraph.
|
|
51
|
+
|
|
52
|
+
Open the next message after a later correction with one `Corrected:` line under the same register, with no section titles: the first line, or directly after the marker when the message has one.
|
|
53
|
+
|
|
54
|
+
## Worked examples
|
|
55
|
+
|
|
56
|
+
Holds:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
gauntlet: question
|
|
60
|
+
|
|
61
|
+
## Today
|
|
62
|
+
The export uses the saved column order for every download.
|
|
63
|
+
|
|
64
|
+
## The change
|
|
65
|
+
Users can choose a different order for one download. The saved order remains the default, so existing downloads stay the same.
|
|
66
|
+
|
|
67
|
+
## What I checked
|
|
68
|
+
- Held: The export reads the saved order, and the download form can pass a different order.
|
|
69
|
+
|
|
70
|
+
The framing holds: checked the saved order and the download form.
|
|
71
|
+
Where should users choose the order?
|
|
72
|
+
A) in the download form
|
|
73
|
+
B) in a separate preview
|
|
74
|
+
Recommendation: A - users can choose without leaving the download.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Concern:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
gauntlet: question
|
|
81
|
+
|
|
82
|
+
## Today
|
|
83
|
+
Every caller reads settings through the same resolver.
|
|
84
|
+
|
|
85
|
+
## The change
|
|
86
|
+
The request adds another settings file to supply a timeout override.
|
|
87
|
+
|
|
88
|
+
## What I checked
|
|
89
|
+
- Corrected: The draft says the resolver cannot accept overrides; it already accepts a timeout override, so the caller can pass it without another settings file.
|
|
90
|
+
|
|
91
|
+
Another settings file duplicates the existing read path. Which outcome should we pursue?
|
|
92
|
+
A) as framed
|
|
93
|
+
B) pivot: pass the override through the existing resolver - it already supports it
|
|
94
|
+
C) smaller or none: document the default and ship no setting
|
|
95
|
+
Recommendation: B - the existing resolver can handle the override.
|
|
96
|
+
```
|
|
@@ -6,7 +6,7 @@ argument-hint: "[no argument: my open PRs] | <pr> [issue-ref] [--rebase [base]]
|
|
|
6
6
|
|
|
7
7
|
# gatekeep-pr
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Judge whether code, tests and docs at the assessed head make each promised behavior possible; leave observations requiring the merged change to `/skill:check-delivery`. Persist one course through `reference/post-selection-loop.md`'s run record; keep final merge/approval and posts separately selected. Before the initial pick, permit only provisioning and the explicit `--rebase` sync; steps 1-5 read, verify and draft. Execute later writes under a set course, terminal pick or the sync's `--rebase` authority. Running the verification command executes PR code with your ambient credentials and no sandbox - gate only PRs you are willing to execute.
|
|
10
10
|
|
|
11
11
|
## Arguments
|
|
12
12
|
|
|
@@ -28,8 +28,8 @@ Verify (step 3) and Review (step 4) each run as a fresh helper with `cwd` the PR
|
|
|
28
28
|
| 3 Verify | `verification-brief.md` Section B | evidence record (CI-first) and one disposition per material claim | `verify` |
|
|
29
29
|
| 4 Review | `verification-brief.md` Section C | reviewer findings and the internal comment ledger | `review` |
|
|
30
30
|
| 5 Integrate + report | `reference/post-selection-loop.md` `### Pre-menu refresh`, then `reference/findings.md`, then `reference/report.md` | AC outcomes, blockers, nits, drafted payloads, the rendered report | `report` |
|
|
31
|
-
| 6 Menu | `reference/
|
|
32
|
-
| 7 Loop | `reference/post-selection-loop.md` (delivery continues in `reference/fix-wave.md`) | the fixed delivery body until readiness, obstacle or cap; terminal picks and contract decisions through `reference/menus.md`; re-entry until stop | (re-opens the re-entered stage) |
|
|
31
|
+
| 6 Menu | `reference/menus.md` | state-selected action, final or post archetype; row 1 is the sole recommendation | `menu` |
|
|
32
|
+
| 7 Loop | `reference/post-selection-loop.md` (delivery continues in `reference/fix-wave.md`) | the fixed delivery body until readiness, obstacle or cap; terminal picks and contract decisions through `reference/menus.md`; re-entry until stop or completion of the terminal post set | (re-opens the re-entered stage) |
|
|
33
33
|
|
|
34
34
|
Re-entry: a fix wave's own push re-enters step 4 through the own-push sequence (`reference/fix-wave.md` `## Evidence after push`, then `reference/post-selection-loop.md` `### Re-render`); any other head move re-enters step 3; an unchanged head re-enters step 5 through `reference/post-selection-loop.md` `### Pre-menu refresh`. A loop re-entry never re-runs step 2b; the sync runs once per invocation.
|
|
35
35
|
|
|
@@ -47,38 +47,49 @@ For pi file-finding row dispatch, use `subagent({ agent: "loop-implementer", con
|
|
|
47
47
|
|
|
48
48
|
These bind every rendered report, menu, and external payload (review bodies, replies, commit subjects, tracker comments). A `## comms style` section in the overrides file extends them.
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
50
|
+
- Write for a reader with neither the code nor this run's notes open. Ground each claim in gathered facts; name the behavior and give one concrete example per problem. Explain a needed term in everyday words before using it.
|
|
51
|
+
- Write one or two whole sentences per finding: what is wrong, then why it matters. In a posted review body, trail each finding with its file and line in parentheses. Name files, lines and checks only where the reader must open or type them; keep exact supplied failing-test locators with their blocker.
|
|
52
|
+
- Omit empty sections. Use ASCII, American English, no hedges on checked facts and no intensifiers.
|
|
53
|
+
- Keep explanatory prose free of field names, run ids, commit ids and repair or sync counters outside `show evidence`; translate internal vocabulary and leave records unchanged. Write thread replies as plain sentences.
|
|
54
|
+
- Keep output unfenced. Preserve these exceptions verbatim: first-line markers, settlement rows, per-step result lines, typed commands, `[recommended]`, set queue/retirement lines, consent previews, the `AC coverage` heading and checkbox rows, and exact commands with substituted values in rows or closing messages. Keep repository-owned cleanup item text unchanged.
|
|
55
|
+
|
|
56
|
+
| Internal term | Say instead |
|
|
57
|
+
|---|---|
|
|
58
|
+
| binding pending check | a required check is still running |
|
|
59
|
+
| merge_state_status BLOCKED | GitHub won't let this merge yet |
|
|
60
|
+
| assessed head | the commit being reviewed |
|
|
61
|
+
| durable run record | saved progress |
|
|
62
|
+
| PR-named action | the step the PR asks for |
|
|
63
|
+
| coverage post | a comment saying which requirements the PR covers |
|
|
64
|
+
| withhold | the reason this cannot merge yet |
|
|
65
|
+
| terminal pick | your choice |
|
|
66
|
+
| post set | the steps you picked |
|
|
67
|
+
| disposition | how you classified the check |
|
|
68
|
+
| merge blocked, no bypass | GitHub reports the merge as blocked for you |
|
|
69
|
+
| bypass eligible | you can use GitHub's admin override |
|
|
70
|
+
| conflicting / behind | the branch conflicts with, or is behind, the base branch |
|
|
71
|
+
| evidence source ci / local | the checks ran in CI / on this machine |
|
|
72
|
+
| cap reached | the repair attempts allowed for this run are used up |
|
|
73
|
+
| nit | a smaller point that does not block merging |
|
|
74
|
+
| contradicted claim | the description says one thing and the code does another |
|
|
75
|
+
| observable half | the part that can only be seen after merge |
|
|
76
|
+
| deferred / deviates / elsewhere | the spec defers it, deliberately differs, or assigns it to another repo |
|
|
77
|
+
| pending reviewer placeholder | an automated review is still running |
|
|
78
|
+
|
|
79
|
+
### Output done-check
|
|
80
|
+
|
|
81
|
+
Before sending any report, menu or external payload, reread it for internal jargon, raw field/value pairs, labeled-field scaffolding and instructions for the human to run a command the skill can run. Rewrite those lines in plain language, preserve the facts and concrete step commands needed for a choice, and execute selected commands yourself. Treat commands for steps not run as information, never a request to paste them.
|
|
60
82
|
|
|
61
83
|
## Red flags - STOP
|
|
62
84
|
|
|
63
|
-
- A mutation without a set course, a terminal pick, or the sync's `--rebase` authority - owner: `reference/post-selection-loop.md` `### Continuation record`.
|
|
64
|
-
- A code or doc edit sitting in the worktree when a menu renders - except helper residue that `reference/fix-wave.md` `## Wave` names in the re-rendered menu - owner: `reference/findings.md` `## Drafted payloads`.
|
|
65
|
-
- Blocking on an AC's observation half, or on a PR-body claim the gate cannot check - owner: `reference/findings.md` `## AC outcomes`.
|
|
66
|
-
- Judging a ticket row the spec does not carry, or treating a spec `deferred: <ref>` row as a gap - owner: `reference/findings.md` `## AC outcomes`.
|
|
67
|
-
- Reading the rubric, the verification command, or any ladder source from the PR's head instead of the base branch's merge-base - owner: `reference/assessment.md` `## Configuration`.
|
|
68
|
-
- Raw command output, drafted payloads except the exact description consent preview, or internal IDs in the rendered report - owner: `reference/report.md`.
|
|
69
|
-
- A menu rendered under deliver before an exit condition, other than the contract-exception template; a menu not rendered from `reference/menus.md`, two recommendations, stop not last or no show evidence hint - owner: `reference/menus.md`.
|
|
70
|
-
- `cleanup` rendered on a non-terminal template, or cleanup steps 2-4 run on non-final stop - owner: `reference/cleanup.md` `## Non-final stop`.
|
|
71
|
-
- A CI watch outside D3 step 4 or before the first report, or a second push inside one iteration - owner: `reference/post-selection-loop.md` `### Next action`.
|
|
72
|
-
- The orchestrator resolving a merge conflict itself, or editing or committing a tracked file during a fix wave - owner: `reference/fix-wave.md` `## Sync` and `## Wave`.
|
|
73
|
-
- A helper's duty run in the orchestrator's own context - owner: `## Harness notes`.
|
|
74
|
-
- Approving your own PR - owner: `reference/decision-menu.md` `## Availability`.
|
|
75
85
|
- Merging around an undispositioned failing check or a binding pending check, or a merge-state withhold under `reference/post-selection-loop.md` `### Merge preconditions` - owner: `reference/findings.md` `## Dispositions`.
|
|
86
|
+
- A menu rendered under deliver before an exit condition, other than the contract-exception template; a menu not rendered from `reference/menus.md`, two recommendations, a recommendation not on row 1 or no show evidence hint - owner: `reference/menus.md`.
|
|
87
|
+
- `cleanup` rendered on a non-terminal template, or cleanup steps 2-4 run on non-final stop - owner: `reference/cleanup.md` `## Non-final stop`.
|
|
88
|
+
- Approving your own PR - owner: `reference/menus.md` `## final`.
|
|
76
89
|
- A menu rendered without the pre-menu refresh - owner: `reference/post-selection-loop.md` `### Pre-menu refresh`.
|
|
77
|
-
- Reading `mergeStateStatus` from anything but a `gh pr view` invocation, attributing a `BLOCKED` to a named rule, or treating a non-`BLOCKED` value as a merge verdict - owner: `verification-brief.md` Section A.
|
|
78
|
-
- A claim verdict recorded behind a pending tracker stage - owner: `## Progress tracking`.
|
|
79
90
|
|
|
80
91
|
## Project overrides
|
|
81
92
|
|
|
82
|
-
If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it once per session - a skill that already has the file's content in context from an earlier skill's read skips the read; a restored session has nothing in context and reads it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## PR gate` keys are read in step 2 (`reference/assessment.md`); `## comms style` extends the wording rules. `## cleanup` steps
|
|
93
|
+
If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it once per session - a skill that already has the file's content in context from an earlier skill's read skips the read; a restored session has nothing in context and reads it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## PR gate` keys are read in step 2 (`reference/assessment.md`); `## comms style` extends the wording rules. `## cleanup` items are separate steps selected through the post menu (`reference/menus.md` `## post`); execute them through `reference/cleanup.md`.
|
|
83
94
|
|
|
84
95
|
The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
|
|
@@ -28,7 +28,7 @@ With rebase requested, read the viewer via `gh api user --jq .login`. After fetc
|
|
|
28
28
|
|
|
29
29
|
Create the OS-temp roster with `mktemp "${TMPDIR:-/tmp}/gatekeep-roster.XXXXXX"`, never in a worktree. Store per PR number, worktree, record path, report path, status (`pending`, `report`, `conflicting`, `failed`, `stopped`, `retired`), reason, and queued pick. Pre-mint record/report paths outside worktrees.
|
|
30
30
|
|
|
31
|
-
Initialize each existing-format continuation record once: `consent.target` (lowercase base owner/repo, PR number, gathered baseRefName), PR identity, worktree, `course` null, `repair.rounds_used` and `repair.syncs_used` zero, `approved_head` null
|
|
31
|
+
Initialize each existing-format continuation record once: `consent.target` (lowercase base owner/repo, PR number, gathered baseRefName), PR identity, worktree, `course` null, `repair.rounds_used` and `repair.syncs_used` zero, `approved_head` null. Use the continuation-record schema; initialize `repair.rounds_cap` and `repair.syncs_cap` to `2 x` the resolved `closureReview.maxFixRounds` under D4 (`fix-wave.md` `## Wave`). Only the first course pick may resolve its initial D4 allowance; re-dispatch never reinitializes usage or caps. The parent owns only initialization and direct queued picks; the child owns all assessment and execution fields, findings, digest, evidence, repair state, approved head, payloads, and comment ledger. Carry confirmations and answers in task text only; never overwrite course, counters, caps, deadline, ledger, or helper paths on refresh or re-dispatch. Carry `repair.wave.spec` and `repair.wave.ledger` once created, with their row history and counters, through every private handoff; wave settlement retains the pair until terminal teardown. Validate supplied records using the continuation-record identity and finding-artifact rules: a missing locator or missing, unreadable or malformed artifact exits `stuck - run record unreadable`, never resets them.
|
|
32
32
|
|
|
33
33
|
## Foreground dispatch
|
|
34
34
|
|
|
@@ -76,24 +76,24 @@ Re-assess from steps 1-5 with the same record; substitute the answer at that ask
|
|
|
76
76
|
|
|
77
77
|
## Summary and menu round
|
|
78
78
|
|
|
79
|
-
The parent alone renders menus, gathers answers, and runs
|
|
79
|
+
The parent alone renders menus, gathers answers, and runs post/stop consequences. Render the summary once, after the children's closing lines and before the first menu, without a standalone report block before it. Preserve each supplied child report unchanged, including under show evidence. For each PR in roster order, print `#<N>` and copy the child's standing sentence unchanged on one line; add no verdict, evidence or blocker fields. For a child without a report, state its recorded conflict, failure or ask as a sentence. Describe a pending required check in that PR's deliver row; leave the supplied standing sentence unchanged. Follow with `Shared files:` and every changed path shared by two or more PRs, `<path> - #<N>, #<M>`. Include `#<N> - files unknown` for missing gathered files; print `none` when no path overlaps. Never schedule merges or choose landing order.
|
|
80
80
|
|
|
81
|
-
`#<N
|
|
81
|
+
Print each supplied child report file verbatim in roster order, each under its own `#<N>` heading and directly above that PR's queued menu from `menus.md`; add no synthetic `Verdict:` restatement at the menu turn. Render only the first PR's report and menu in the summary turn; collect each PR's pick before rendering the next PR's report and menu in a new turn. Never put two PRs' menus in one message or ask for all picks in one combined reply. Render each child's template from `menus.md`: reports with their template rows, conflicts through `menus.md` `## batch summary`'s recovered CONFLICTING template, failures with retry/evidence/stop, STOPPED with the recorded ask and stop. Apply `menus.md`'s row ordering to every child menu. For retry use exactly `retry - re-dispatch this PR's assessment with the same record`, recommended only after clean recovery and no rebase. Resolve the actual gitdir with git (a worktree .git can be a file); require empty `git -C <worktree> status --porcelain` and neither rebase-merge nor rebase-apply there. Otherwise omit retry and explain that the worktree is dirty or mid-rebase, naming the observed porcelain line or rebase directory.
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
Render one post menu per merged PR, each in its own message, using `menus.md` `## post`. Keep the batch summary in a separate message before these menus. Each post-menu message starts with `gauntlet: gate=gatekeep-pr/own-merge recommended=1`, never the batch-summary marker. Before substitution, assign a `## cleanup` item whose unresolved text holds none of `<issue>`, `<pr>`, `<merge-sha>` to the shared set: include it in the last merged PR's row 1 only, in roster order for this round. Offer its individual row on earlier merged PRs while it has not run. Keep PR-specific items with their PR. Record shared-item execution in the parent roster across rounds: a shared item runs at most once in the set. Omit it from later menus and skip it in queued picks only after its command runs with a recorded result, never because an earlier pick is queued.
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
Queue every parent-owned terminal pick (a post row or set of rows, merge, wait, stop) until every roster entry's pick for the round is collected. Print `Queued until all picks are collected (<roster summary>)` before the execution block for each queued pick, including a single-entry roster. Summarize each roster entry's collected pick or pending status inside `<roster summary>`.
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
Show evidence in-place from retained record/helper paths and leave the same menu waiting. Queue all other picks and answers until the round's final pick. Record direct picks as the child's `course` or terminal selection; do not turn answers into grants. Execute queued terminal picks in roster order from the primary checkout through `post-selection-loop.md` `### Post steps`, preserving its step order, deduplication, guards, failed-step continuation and nested-skill pauses. Keep remaining steps and other PRs' queued picks waiting until a picked skill returns. The parent owns every post step, even after cleanup removes a PR worktree; exclude terminal picks from child dispatch and never use a removed worktree as cwd. Run no helper for terminal posts. Skip compare-and-swap only on merged or closed PRs; delegate approved/open reply freshness to `### Post steps`.
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
For `merge queued`, the parent handles `wait` after all picks: re-read `gh pr view <N> --json state,mergeCommit` per `post-selection-loop.md` `### Merge course`. On `MERGED`, persist `pr.state` and `pr.merge_commit` and render its one post menu under `own merge`; otherwise re-render `merge queued` with wait/stop and the evidence hint, without helper, child or CI watch. Next batch mixes retry/answered-ask `report` with ordinary nonterminal `execute` tasks, always the same record.
|
|
90
90
|
|
|
91
91
|
## Between batches and retirement
|
|
92
92
|
|
|
93
|
-
Run parent
|
|
93
|
+
Run parent post/stop consequences only after all children finish, never on a live child's tree. After all selected post steps finish for a PR, retire it with no re-render, including when a step failed. On stop retire it without running unpicked post steps. For non-final stop run `cleanup.md` `## Non-final stop`; under terminal overlays leave the checkout as found and print its leftover path/branch.
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
Before teardown, retain each PR's settlement row and per-PR not-run sentences from `post-selection-loop.md` `### Teardown` in the parent roster for the final message. Keep payload files for unrun or failed posts; delete only that PR's other helper/log files and record under those teardown rules. Start every PR retirement message, including the last, with `gauntlet: retired #<N> - <reason>`, without a terminal marker or settlement row; keep private child result lines unchanged. Await all next-batch results and render only nonretired PRs until all retire.
|
|
96
96
|
|
|
97
|
-
After the last PR retires and every selected
|
|
97
|
+
After the last PR retires and every selected step finishes, render one parent closing message. Start the message with `gauntlet: stuck retired` when any retained outcome is `stuck - <reason>`, otherwise `gauntlet: done retired`. Print every retained PR settlement row and its not-run sentences in roster order, including PRs retired in earlier rounds.
|
|
98
98
|
|
|
99
99
|
Initialize parent tracker tasks `pr-<N> state: <record path>`; mark in_progress on dispatch, complete on retirement, failed on unretried failure. Child trackers are session-local stages, not parent roster tasks. Use a plain checklist if plan_tracker is unavailable.
|