pi-gauntlet 6.2.0 → 7.0.0
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 +17 -0
- package/README.md +10 -10
- package/package.json +1 -1
- package/skills/brainstorming/SKILL.md +28 -170
- package/skills/brainstorming/gatherer.md +3 -2
- package/skills/brainstorming/reference/amendment-surface.md +9 -3
- package/skills/brainstorming/reference/documentation-impact.md +4 -2
- package/skills/brainstorming/reference/spec-finalization.md +128 -0
- package/skills/brainstorming/reference/ticket-acceptance.md +18 -0
- package/skills/chase-bug/SKILL.md +2 -2
- package/skills/check-delivery/SKILL.md +6 -0
- package/skills/gatekeep-pr/SKILL.md +43 -181
- package/skills/gatekeep-pr/reference/assessment.md +53 -106
- package/skills/gatekeep-pr/reference/decision-menu.md +97 -205
- package/skills/gatekeep-pr/reference/findings.md +67 -117
- package/skills/gatekeep-pr/reference/post-selection-loop.md +38 -27
- package/skills/gatekeep-pr/reference/report.md +96 -0
- package/skills/gatekeep-pr/review-baseline.md +6 -5
- package/skills/gatekeep-pr/verification-brief.md +20 -55
- package/skills/gauntlet-resume/SKILL.md +2 -2
- package/skills/gauntlet-resume/reference/reconstruction.md +6 -3
- package/skills/writing-plans/SKILL.md +1 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Spec finalization
|
|
2
|
+
|
|
3
|
+
## Spec Self-Review (Before User Review Gate)
|
|
4
|
+
|
|
5
|
+
Spec-writing replaces the context draft, in this exact order:
|
|
6
|
+
|
|
7
|
+
1. `Read` the draft in full - **immediately before** the overwrite. Without this, a
|
|
8
|
+
pruned questionary plus a full-replacement `write` destroys the only copy of the
|
|
9
|
+
gathered context at the moment it feeds the spec.
|
|
10
|
+
2. Write the spec with the `write` tool (**full replacement**) at the spec path.
|
|
11
|
+
Using `edit` at this step is a red flag.
|
|
12
|
+
3. **Immediately after the write**, confirm line 1 of the file is no longer
|
|
13
|
+
`# CONTEXT DRAFT - NOT A SPEC - fully replaced at spec-writing` - before
|
|
14
|
+
dispatching lint, critique, council, or summarizer. The phase-tracker commit
|
|
15
|
+
guard is a backstop, not the primary check.
|
|
16
|
+
4. **After the line-1 check**, run the second predecessor pass. Compose a query from
|
|
17
|
+
the spec's H1 terms, then the terms of every H2 that is not a template heading
|
|
18
|
+
(Problem, Acceptance criteria, Design, Errors and edge cases, Tests, Documentation
|
|
19
|
+
impact, Out of scope, Open questions), then the `**Goal:**` line's terms - same
|
|
20
|
+
token rules as the scout, deduplicated, cut at 15. Run
|
|
21
|
+
`(cd <abs worktree path> && node <SPEC_INDEX> --query '<terms>' --limit 5 --exclude <spec path relative to the worktree>)`
|
|
22
|
+
with `<SPEC_INDEX>` resolved as in `../gatherer.md`. Take the `live` rows and drop every
|
|
23
|
+
path the draft's `Predecessor:` line(s) named (retained from the step-1 read). Carry
|
|
24
|
+
the remainder to the gate as one adjacent line:
|
|
25
|
+
`New predecessor candidates at spec-writing: <path> (<title>), ... - index rows are a hint; code is the source and an absent row proves nothing.`
|
|
26
|
+
or `New predecessor candidates at spec-writing: none.` A non-zero exit degrades to
|
|
27
|
+
`Second predecessor pass unavailable: <first stderr line>`; it never blocks the gate
|
|
28
|
+
or the commit. "yes, <path> is a predecessor" at the gate is a change request that
|
|
29
|
+
adds the `supersedes <path>, <scope>` clause and the banner, then re-presents the gate.
|
|
30
|
+
5. **After the second predecessor pass and before the inline lint**, `edit` any known
|
|
31
|
+
predecessor spec to insert its supersession banner (see
|
|
32
|
+
[Marking superseded specs](superseding.md)). This position is fixed:
|
|
33
|
+
the banner is written after any slug rename, so it always cites the final path.
|
|
34
|
+
|
|
35
|
+
After writing the spec to `<project>/doc/specs/<filename>.md` (per [Filename Convention](../SKILL.md#filename-convention)) and before showing it to the user, run a self-review pass. Read all six bullets first, then act.
|
|
36
|
+
|
|
37
|
+
- **Placeholder scan.** Any `TODO`, `TBD`, `<fill in>`, `[example]`, `xxx`? Either resolve them or convert to explicit "Open Questions" with names.
|
|
38
|
+
- **Internal consistency.** Does Section 4 contradict Section 2? Are component names and field names consistent throughout? If the spec replaces a prior design, confirm the predecessor carries the supersession banner and its href resolves to this spec's final filename.
|
|
39
|
+
- **Documentation named.** Does the spec name all three classes (feature/user-facing introduced; materially amended; derived/memory invalidated), or an explicit "none" for each? Enforce the materiality bar in `documentation-impact.md` without restating it: each listed doc names the category it clears, none is a code-mirror, amend-over-create was applied, and skill/agent bodies are implementation surface, not doc-impact entries here.
|
|
40
|
+
- **Ticket contract present.** Does `## Acceptance criteria` exist with either verbatim ticket rows plus dispositions or one `none - <reason>` line? Presence is enforced here, at authoring, and nowhere later.
|
|
41
|
+
- **Scope check.** Does every paragraph serve the goal? Cut filler. If something is out of scope, say it's out of scope.
|
|
42
|
+
- **Ambiguity check.** Is every "we should..." backed by a concrete decision? Replace "we could probably" with "we will" or "we won't".
|
|
43
|
+
|
|
44
|
+
The first four are the inline **lint**: run them here and fix what they surface. The last two are the **critique pass**, dispatched per [Spec Council](#spec-council). After it returns, re-run the placeholder scan over the applied spec; if a predecessor banner exists, confirm its `<scope>` still matches and reconcile it; carry any ambiguity the critique could not resolve to the [User Review Gate](#user-review-gate).
|
|
45
|
+
|
|
46
|
+
## Spec Council
|
|
47
|
+
|
|
48
|
+
Before dispatching the worker below, resolve `documentation-impact.md` relative to this loaded reference as one absolute `<DOCUMENTATION_IMPACT_GUIDELINE>` path value. Pass that value in the worker task; do not add it to the spec.
|
|
49
|
+
|
|
50
|
+
After the inline lint and before the user review gate, **brainstorming owns the critique-pass gate**; council **apply mechanics** live in `/skill:roasting-the-spec` (single source of truth - link, don't restate). Resolve the council with `gauntlet_setting({ key: "specCouncil" })` - the tool returns the merged (repo-over-preset) value as `{ verdict, members, chair, malformed, warning, errors }`. **Do not** hand-roll a settings read. When `verdict` is `"council"`, the council *is* the critique pass - invoke `/skill:roasting-the-spec` automatically (no offer, no prompt), passing `members`/`chair`; also pass the verbatim human input (the original prompt, any ticket AC snapshot - the raw rows under the gather draft's `## Ticket acceptance criteria (verbatim)` heading, never the spec's section, which holds the author's dispositions - and the questionary answers that changed scope) - roasting-the-spec forwards it to members and chair as the `Human input (verbatim; off-limits for over-spec)` block; it applies its apply-set and returns the audit (Applied/Deferred/Rejected). When `verdict` is `"worker"`, dispatch the worker below. If `malformed` is true or `errors` is non-empty, emit the `warning`/error as one line, then branch strictly on `verdict` - `malformed` can accompany *either* verdict (e.g. a bad `chair` with valid `members` still returns `council`), so never infer the worker path from `malformed` alone. If `gauntlet_setting` is unavailable, stop and report - never fall back to a manual bash/JSON settings merge. The already-applied council edits (or the worker's in-place fixes) ride in the same worktree commit. The conceptual precedence rule lives in `../../verification-before-completion/reference/settings-precedence.md`.
|
|
51
|
+
|
|
52
|
+
When `verdict` is `"worker"`, dispatch one fresh `worker` that applies the scope + ambiguity checks and fixes them in place:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
subagent({ agent: "worker", context: "fresh", async: false, cwd: "<abs worktree path, from the using-git-worktrees Step 4 report>", task:
|
|
56
|
+
"Problem statement: <the problem the spec addresses + the user's stated intent>.\n" +
|
|
57
|
+
"Read the spec at <abs path to doc/specs/...>. Edit ONLY that file.\n" +
|
|
58
|
+
"The portable citation `reference/documentation-impact.md` in the spec is the pi-gauntlet guideline at <DOCUMENTATION_IMPACT_GUIDELINE>, not a consumer doc; do not flag it as an external reference, and preserve it - never remove it as redundant or replace it with the resolved absolute path.\n" +
|
|
59
|
+
"Apply two checks and fix what you find in place: (1) Scope - does every paragraph serve the goal? Cut filler;\n" +
|
|
60
|
+
"state out-of-scope explicitly. (2) Ambiguity - is every 'we should' a concrete decision?\n" +
|
|
61
|
+
"Replace 'we could probably' with 'we will'/'we won't'. Also inline any load-bearing\n" +
|
|
62
|
+
"external reference (ticket AC, commit SHA, doc) already given to you in the problem\n" +
|
|
63
|
+
"statement above; if the spec relies on one not provided here, flag it (do NOT fetch) in\n" +
|
|
64
|
+
"your summary. Return a summary of what you changed, and flag any ambiguity you could NOT\n" +
|
|
65
|
+
"safely resolve." })
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`worker`'s model resolves from `subagents.agentOverrides.worker.model` in `settings.json` (unset -> inherits the main loop); the dispatch passes no `model:`.
|
|
69
|
+
|
|
70
|
+
## User Review Gate
|
|
71
|
+
|
|
72
|
+
After self-review and the critique pass (council or worker, both already applied to the spec - see [Spec Council](#spec-council)), dispatch the spec-only summarizer over the **applied** spec, then commit the spec on the worktree branch and stop. The summary is folded into the one human gate, not a new gate.
|
|
73
|
+
|
|
74
|
+
Mint an absolute temp path outside the worktree (so it is never committed), then dispatch the summarizer on a fresh context, reading only the spec, writing to that path via file-only output (no `model:` - it inherits the main loop unless a preset sets `subagents.agentOverrides.spec-summarizer.model`):
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
SUMMARY_PATH=$(mktemp "${TMPDIR:-/tmp}/gauntlet-spec-summary.XXXXXX") # absolute, portable across GNU/BSD mktemp
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
subagent({ agent: "spec-summarizer", context: "fresh", async: false, cwd: "<abs worktree path, from the using-git-worktrees Step 4 report>",
|
|
82
|
+
output: "<SUMMARY_PATH>", outputMode: "file-only", task:
|
|
83
|
+
"Summarize the spec at <abs path to doc/specs/...> for the user review gate. Read ONLY that file." })
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`<SUMMARY_PATH>` above is a placeholder in the dispatch object; it means substitute the value of the shell variable `$SUMMARY_PATH` set above. The steps below use `$SUMMARY_PATH` (the shell form) once the value is in hand.
|
|
87
|
+
|
|
88
|
+
Then commit the spec - staging any predecessor spec edited per [Marking superseded specs](superseding.md) alongside it; a change request at the gate that renames, materially revises, or drops the spec also reconciles the predecessor's banner before recommitting. This commit is **unconditional**: the summary is only a gate aid, so a degraded or missing summary never blocks it. If the council path ran, include its audit (`Coverage:` when present, then `Applied:` / `Deferred:` / `Rejected:`, verbatim from `/skill:roasting-the-spec`'s return) in the **commit message body** - this is the durable, non-contractual record a finish-time revert reads back; the audit is never a committed spec section. Evaluate the summary in two stages (the **Degrade path** referenced in each is defined just below):
|
|
89
|
+
|
|
90
|
+
1. **From the dispatch tool result, before the `Read`.** If the result is **not** an `"Output saved to: <path> (<N> KB, <M> lines)"` reference (e.g. an exit-0 save error returns the full inline output plus an "Output file error" line - the prunable shape, no file to read), or the reference reports under ~500 bytes, or a size grossly disproportionate to the spec (under ~2% of its byte size), or over ~45 KB (the `Read` truncates at 50KB / 2000 lines, so a larger file cannot render whole) - skip the `Read` and take the degrade path. Use the reference's reported figures; do not re-derive them.
|
|
91
|
+
2. **The `Read` itself, as the last content-producing tool call before composing the gate.** `Read` `$SUMMARY_PATH` and paste its contents verbatim at the top of the gate. If the `Read` fails, returns 0 bytes, or reports truncation - take the degrade path. The `Read` must be last: pi-condense does not protect a `/tmp` read, so any turn boundary between the `Read` and the render lets the ~9KB read result be pruned, reproducing the bug.
|
|
92
|
+
|
|
93
|
+
**Degrade path** - reach the gate with a one-line "summary generation failed" note; never paraphrase from the file-only reference, never render a stub as the canonical summary.
|
|
94
|
+
|
|
95
|
+
Either way - summary rendered or degraded - then `rm "$SUMMARY_PATH"` (unconditional cleanup; harmless if the file was never created, since it lives outside the worktree under the OS temp dir).
|
|
96
|
+
|
|
97
|
+
Paste the summary verbatim, unedited in the template below; use adjacent lines for the audit, unresolved ambiguities, and every gap-footer entry:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
<spec-only summary read back from the temp file - pasted verbatim, unedited>
|
|
101
|
+
|
|
102
|
+
Spec written and committed to <project>/doc/specs/<filename>.md (worktree: <path>).
|
|
103
|
+
|
|
104
|
+
Coverage: <N> of <M> members reported; <slug>: <reason> (line present only when coverage was partial)
|
|
105
|
+
Applied: [<severity>] <cluster> - raised-by: [<slugs>] -> <edit>
|
|
106
|
+
Deferred: [<severity>] <cluster> - raised-by: [<slugs>] -> <where it belongs>
|
|
107
|
+
Rejected: [<severity>] <cluster> - raised-by: [<slugs>] -> <one-line reason>
|
|
108
|
+
(one line per item, exactly as returned by roasting-the-spec - `Applied: none` / `Deferred: none` / `Rejected: none` when a list is empty; omit the audit lines when the worker path ran, not the council)
|
|
109
|
+
|
|
110
|
+
<unresolved ambiguities; every gap-footer entry from the summary>
|
|
111
|
+
New predecessor candidates at spec-writing: <path> (<title>), ... - index rows are a hint; code is the source and an absent row proves nothing.
|
|
112
|
+
|
|
113
|
+
Please review. Approve to proceed, tell me what to change in the spec, or say "revert applied council edit <X>" to undo a specific applied edit. Reply "auto-apply amends" - every later amend-class change in this flow then applies without review, scope changes included; redraws and the spec gate still stop. "approve, auto-apply amends" does both.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If you believe the summary needs correcting, do **not** silently rewrite it - re-dispatch the summarizer or note the discrepancy as an adjacent line beneath the verbatim block.
|
|
117
|
+
|
|
118
|
+
**Revert valve.** "Revert applied council edit X" is a normal change request: revise the spec to undo edit X, re-dispatch the summarizer with a **fresh** temp path (per the re-dispatch rule below), and re-present the gate. This is cheap here - the spec is not yet plan- or code-bearing.
|
|
119
|
+
|
|
120
|
+
Wait for the user. On a change request (including a revert), revise the spec and re-present - mint a **fresh** temp path for the re-dispatched summarizer (never reuse a prior round's path, so stale content can never be mistaken for the new summary). On approval, proceed immediately to `/skill:writing-plans` with no further prompt; first read [Standing grants](amendment-surface.md#standing-grants) (stop if unreadable) and record any grant. The plan and execution mode are mechanical derivatives, so the only human gate here is spec approval itself. Don't land the spec on `main`; it stays in the worktree and ships in the same squash commit as the implementation.
|
|
121
|
+
|
|
122
|
+
Post-approval changes follow [Amending an approved spec](../SKILL.md#amending-an-approved-spec).
|
|
123
|
+
|
|
124
|
+
After approval, mark the brainstorm phase complete:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
phase_tracker({ action: "complete", phase: "brainstorm" })
|
|
128
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Ticket Handling
|
|
2
|
+
|
|
3
|
+
A ticket is guidance, not sole truth. Fetch it; propose scope, approach, or acceptance changes when code disagrees, and record deviations in the spec. Implied requirements in the ticket body (Context, Problem, Idea) land in the spec body as any other requirement; the ticket's explicit acceptance criteria land verbatim in the section below.
|
|
4
|
+
|
|
5
|
+
**Extract the ticket's ACs.** When the ticket body has a heading matching `/acceptance criteria/i`, every list item under it until the next heading is an AC (numbered, bullet, or checkbox) and no other list in the body is. When there is no such heading, every top-level checkbox row in the body is an AC, except rows under a `Post-deployment housekeeping`, `Out of scope`, or `Follow-up` heading. Otherwise the ticket has no ACs. A nested list under an AC row rides with its parent as one row; an AC heading holding prose and no list makes each paragraph one row. Carry checked and unchecked rows alike, all written `- [ ]`. Take the rows from the gather draft's `## Ticket acceptance criteria (verbatim)` heading; when the ticket was not fetched, the gate summary shows the `none` line so the user can paste the rows, which then become rows.
|
|
6
|
+
|
|
7
|
+
**Write the section in every spec**, after `## Problem`:
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
## Acceptance criteria
|
|
11
|
+
|
|
12
|
+
Ticket <ref>, <heading or "checkbox list">, rows verbatim:
|
|
13
|
+
|
|
14
|
+
- [ ] <row text copied verbatim>
|
|
15
|
+
<disposition>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The heading `## Acceptance criteria` names the ticket contract only; the spec's own requirements stay in Design. Disposition is exactly one of `in-scope`, `deviates: <why>`, `deferred: <where>`, `venue: <env> - <observation>`; default `in-scope`. Never edit the row text: a wrongly stated row is `deviates: <why>`, an ambiguous row stays `in-scope` with the chosen reading written as a Design clause. Name a `venue:` row's enabling change in Design. An `in-scope` row is a requirement as written; disposition reasons are never normative for the plan or the reviewer, so a `deviates:` reason that adopts part of a row restates that part as a Design clause. Defer a row only when the shipped change operates without it - cost is never a reason; a hard but direct AC stays `in-scope` and ships. Ask a `deviates:`/`deferred:` decision only when it changes what the user observes once the change ships, offering the dispositions themselves as the options (`A) in-scope B) deviates: <why> C) deferred: <where>`); a deviation caused by a workflow artifact (spec, plan, changelog, telemetry file) or a moved path is stated in the disposition, not asked. Name every disposition in the gate summary; `venue:` states where the observation can happen and is not a scope decision. A disposition changes in any later phase - a reviewer finding `recommended: rescope` at the finish gate, a wrong row noticed mid-implementation, or a ticket edited after approval when the user asks - through [Amending an approved spec](../SKILL.md#amending-an-approved-spec) (`amendment-surface.md`); the row text still never changes. With no ticket, or a ticket without ACs, the section body is the single line `none - no ticket`, `none - ticket has no acceptance criteria`, or `none - ticket not fetched (<reason>)`. Never author acceptance criteria on the ticket's behalf; that is `/skill:shape-ticket`'s job.
|
|
@@ -277,7 +277,7 @@ any handoff:
|
|
|
277
277
|
- File a ticket chosen -> shape-ticket runs its own gate first -> draft the
|
|
278
278
|
response citing the new ticket link -> gate 2 -> done.
|
|
279
279
|
- Brainstorm now chosen -> draft the response first ("confirmed, investigating
|
|
280
|
-
now - fix to follow") -> gate 2 -> **then** hand off to `/skill:brainstorming
|
|
280
|
+
now - fix to follow") -> gate 2 -> **then** hand off to [`/skill:brainstorming`](../brainstorming/SKILL.md).
|
|
281
281
|
- Hotfix now chosen -> hand off to `hotfix.md` first; on completion, draft the
|
|
282
282
|
response citing `fixed in <SHA>` or the PR link -> gate 2 (`send it`) -> done.
|
|
283
283
|
Gate 2 fires once. On abort, `hotfix.md` returns to the step-4 menu; step 5
|
|
@@ -343,7 +343,7 @@ action renders the verdict as a **summary to the human**, then the skill ends
|
|
|
343
343
|
shape-ticket is cancelled at its gate, render the summary without a ticket
|
|
344
344
|
link.
|
|
345
345
|
- Brainstorm now chosen -> render the summary -> **then** hand off to
|
|
346
|
-
`/skill:brainstorming
|
|
346
|
+
[`/skill:brainstorming`](../brainstorming/SKILL.md).
|
|
347
347
|
- Hotfix now chosen -> hand off to `hotfix.md`; on completion render the
|
|
348
348
|
summary citing `fixed in <SHA>` or the PR link -> done. On abort, return to
|
|
349
349
|
the step-4 menu.
|
|
@@ -32,6 +32,9 @@ Post-merge **detective control**: proves an issue's work actually shipped -
|
|
|
32
32
|
landed on the default branch, reached its delivery target, holds against its
|
|
33
33
|
acceptance criteria - before the tracker status advances. It is not a
|
|
34
34
|
quality gate; CI and the gauntlet gates already ran. It verifies **delivery**.
|
|
35
|
+
It takes no input from `/skill:gatekeep-pr`: nothing the pre-merge gate
|
|
36
|
+
rendered is read or trusted here. ACs are re-extracted from the ticket in
|
|
37
|
+
stage 0 and the shipped SHA is re-derived in stage 1.
|
|
35
38
|
|
|
36
39
|
**Core principle:** every ambiguity resolves toward "stop loudly, write
|
|
37
40
|
nothing." An unreadable ticket, an unresolvable deliverable set, a commit
|
|
@@ -373,6 +376,7 @@ unset (no body edits).
|
|
|
373
376
|
| "The ticket says done in a comment" | Ticket narrative is not evidence; only SHA-pinned code or target observations count |
|
|
374
377
|
| "Just move it to Done, the human can reopen" | Never a terminal status - acceptance is the human's move, not this skill's |
|
|
375
378
|
| "The AC was only synthesized, so the gap can't block" | Under `synthesized AC gaps: block`, a synthesized AC runs the same verdict matrix as an authored one - an unexplained gap blocks |
|
|
379
|
+
| "The PR gate already checked this AC" | The gate judged the mechanism pre-merge; this control observes delivery at the shipped SHA from the ticket's own ACs |
|
|
376
380
|
|
|
377
381
|
## Red flags - STOP
|
|
378
382
|
|
|
@@ -394,6 +398,8 @@ unset (no body edits).
|
|
|
394
398
|
- Striking an AC line the gate approval did not ratify as `proposed descope`
|
|
395
399
|
- Applying a body edit by replaying the gather-time snapshot instead of
|
|
396
400
|
patching the re-fetched body
|
|
401
|
+
- Using a PR body, PR review comment, or pre-merge gate report as the AC list
|
|
402
|
+
or as AC evidence
|
|
397
403
|
|
|
398
404
|
## Project overrides
|
|
399
405
|
|
|
@@ -1,207 +1,69 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gatekeep-pr
|
|
3
|
-
description: Use when gating a pull request before it merges - whether you authored it or are reviewing someone else's work.
|
|
3
|
+
description: Use when gating a pull request before it merges - whether you authored it or are reviewing someone else's work. Judges whether the diff delivers the mechanism each acceptance criterion needs (code, tests, docs) and conforms to the review rubric; what can be seen only after merge belongs to /skill:check-delivery. Consent-gated - every mutation (fixes, pushes, reviews, merges, tracker comments) waits for an explicit menu pick.
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
argument-hint: "<pr> [issue-ref] (e.g. 123, or 123 gh-45)"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# gatekeep-pr
|
|
9
9
|
|
|
10
|
-
Verify, don't trust
|
|
11
|
-
hallucinated references, and "tests pass" that were never rerun are the normal case,
|
|
12
|
-
not the exception - especially on generated code. Gather evidence, accept green CI on
|
|
13
|
-
the exact assessed head as verification evidence (run the project's own verification
|
|
14
|
-
command only as the fallback), review the diff against a rubric, and present a
|
|
15
|
-
deterministic, authorship-aware menu. Authorship sets which row carries
|
|
16
|
-
`[recommended]`; it never changes which rows are offered.
|
|
17
|
-
|
|
18
|
-
**Consent gate.** The only actions performed before a menu row is picked are:
|
|
19
|
-
read-only gathering, provisioning the worktree, and applying uncommitted, worktree-local
|
|
20
|
-
doc-drift fixes discovered as a blocking finding. Every other action - code fixes,
|
|
21
|
-
pushes, reviews, comments, merges - happens only on explicit selection.
|
|
22
|
-
|
|
23
|
-
**Residual risk.** Running the verification command executes PR code with the
|
|
24
|
-
operator's ambient credentials. There is no sandbox. Run this skill only against PRs
|
|
25
|
-
you are willing to execute.
|
|
10
|
+
Verify, don't trust: a PR description is a claim, and over-claimed coverage, hallucinated references, and "tests pass" that never ran are the normal case on generated code. Judge the mechanism only - whether code, tests, and docs at the assessed head make each promised behavior possible - and leave what can be seen only after merge (a staging run, production data, an external system) to `/skill:check-delivery`. Nothing mutates before a menu pick: steps 1-5 read, provision a worktree, and draft; fixes, pushes, reviews, comments, merges, and tracker writes happen only on explicit selection. Running the verification command executes PR code with your ambient credentials and no sandbox - gate only PRs you are willing to execute.
|
|
26
11
|
|
|
27
12
|
## Arguments
|
|
28
13
|
|
|
29
|
-
- PR number or URL
|
|
30
|
-
|
|
31
|
-
- Optional issue reference. If omitted: infer from `closingIssuesReferences`, then
|
|
32
|
-
branch name, PR title, body, or commits. None found -> judge the PR against its
|
|
33
|
-
stated intent only; never invent acceptance criteria.
|
|
34
|
-
|
|
35
|
-
## Configuration resolution
|
|
36
|
-
|
|
37
|
-
Apply per concern, first match wins, evaluated unconditionally - never delegated to
|
|
38
|
-
a wrapper skill:
|
|
39
|
-
|
|
40
|
-
1. **Repo root `REVIEW.md`** (rubric concerns only). Wins over the shipped
|
|
41
|
-
baseline and reviewer-persona defaults on any conflict.
|
|
42
|
-
2. **Gauntlet overrides file** (3-location discovery, first found wins): the
|
|
43
|
-
`## PR gate` section (verification command, `timeout minutes`, `requires credentials`, issue
|
|
44
|
-
fetch, worktree wrapper, merge policy, `local verification`, `ci checks`). An existing `## verification-before-completion`
|
|
45
|
-
section is an accepted equivalent source for the verification command.
|
|
46
|
-
3. **Repo documentation** - an explicitly documented command or tool (e.g. `AGENTS.md`'s
|
|
47
|
-
canonical test entrypoint, a documented worktree wrapper, a documented tracker CLI,
|
|
48
|
-
or documented merge policy/branch rules). Reading documentation is not inference.
|
|
49
|
-
Discovery-only: never tell consumers to add gatekeep-pr configuration here.
|
|
50
|
-
4. **Ask the user.** Never guess from lockfiles, file heuristics, or vibes.
|
|
51
|
-
|
|
52
|
-
The `## PR gate` overrides schema (all keys optional except the verification command,
|
|
53
|
-
which is required unless documented elsewhere):
|
|
54
|
-
|
|
55
|
-
```markdown
|
|
56
|
-
## PR gate
|
|
57
|
-
- verification command: <command> # required unless documented elsewhere
|
|
58
|
-
- timeout minutes: 15 # optional; default 15
|
|
59
|
-
- requires credentials: false # optional; true => skill reports "not run" as missing evidence
|
|
60
|
-
- local verification: always # optional; default (absent) = CI-first; "always" forces the local run even when exact-head CI is green
|
|
61
|
-
- ci checks: <comma-separated check names> # optional; narrows which checks count as evidence; absent = all checks on the assessed head
|
|
62
|
-
- worktree wrapper: <command> # optional
|
|
63
|
-
- issue fetch: <command with <ref> placeholder> # optional, replaces gh issue view
|
|
64
|
-
- merge policy: squash | merge-commit # optional
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**Thin-wrapper contract.** A consumer wrapper skill is a pure proxy: trigger phrases
|
|
68
|
-
plus "follow `/skill:gatekeep-pr`" - zero configuration data. All customization lives
|
|
69
|
-
in the repo's `REVIEW.md` (rubric) and the gauntlet overrides file's `## PR gate`
|
|
70
|
-
section (everything else); anything a wrapper carries beyond trigger phrases is
|
|
71
|
-
misplaced and belongs in one of those two homes instead.
|
|
72
|
-
|
|
73
|
-
Read the ladder from the **merge-base of the PR's base branch**, never from
|
|
74
|
-
the PR's head tree - a PR cannot weaken its own rubric or swap the command that will
|
|
75
|
-
gate it. Recipe: `MB=$(git merge-base origin/<baseRefName> <headRefOid>)`, then for
|
|
76
|
-
each ladder source `git show "$MB:<path>"` (e.g. `git show "$MB:REVIEW.md"`,
|
|
77
|
-
`git show "$MB:AGENTS.md"`). A plain cwd read (`cat REVIEW.md`, reading the file open
|
|
78
|
-
in the PR worktree) is invalid for any ladder source - it reads the PR's head, exactly
|
|
79
|
-
what this rule forbids - even when the assessment happens to run from inside the PR's
|
|
80
|
-
worktree. Exception: if the PR itself changes `REVIEW.md` or the overrides file, that
|
|
81
|
-
diff is review subject matter, surfaced as a finding - it is not applied to this run's
|
|
82
|
-
configuration.
|
|
83
|
-
|
|
84
|
-
## Progress tracking
|
|
85
|
-
|
|
86
|
-
Use `plan_tracker`, never `phase_tracker`. Init with the first four stages:
|
|
87
|
-
`gather`, `provision worktree`, `resolve evidence`, `claim-check`. While
|
|
88
|
-
`claim-check` is `in_progress`, `add` one task per material claim as the
|
|
89
|
-
Verifier enumerates them and record each verdict: a matched claim ->
|
|
90
|
-
`complete`, a contradicted claim -> `failed` (shown crossed, error color).
|
|
91
|
-
Once every claim is terminal and `claim-check` is closed, `add` `review` and
|
|
92
|
-
`consent menu` and continue. Never init stages ahead of the claims: the
|
|
93
|
-
tracker rejects a verdict recorded behind a still-pending stage. A
|
|
94
|
-
failed stage or claim stays `failed` while the skill stops at the menu -
|
|
95
|
-
never marked complete to move on. On a harness without the `plan_tracker`
|
|
96
|
-
tool: fall back to a plain checklist (or skip if none is available);
|
|
97
|
-
functionality is unchanged either way.
|
|
98
|
-
|
|
99
|
-
## Assess
|
|
100
|
-
|
|
101
|
-
Run four phases in order - gather, provision worktree, verify then review, integrate.
|
|
102
|
-
Read `reference/assessment.md` and `reference/findings.md` now.
|
|
103
|
-
|
|
104
|
-
## Verdict
|
|
105
|
-
|
|
106
|
-
Three states: **blocking findings** (failed gate, contradicted material claim, a
|
|
107
|
-
merge-proof unverifiable claim, `partial`/`missing` AC coverage, scope creep when an
|
|
108
|
-
issue is linked, committed doc drift, anything the merged rubric maps to blocking),
|
|
109
|
-
**follow-ups only** (never gate merge), or **clean**.
|
|
110
|
-
|
|
111
|
-
**Merge preconditions** (all must hold):
|
|
112
|
-
|
|
113
|
-
- gate green with every blocking finding fixed, not deferred
|
|
114
|
-
- verification evidence present per the brief's Evidence resolution table (a CI claim
|
|
115
|
-
or a green local run - a table-sanctioned CI skip is evidence, not missing;
|
|
116
|
-
"not run" blocks only when the table required a fallback run that didn't happen)
|
|
117
|
-
- `mergeable == MERGEABLE` (`UNKNOWN` after the one post-provision re-poll withholds
|
|
118
|
-
merge, same as `CONFLICTING`)
|
|
119
|
-
- no undispositioned failing check in the resolved set, no pending required check
|
|
120
|
-
- evidence pasted with clean provenance
|
|
121
|
-
- worktree clean and synced with the remote head (fixes pushed first)
|
|
122
|
-
- explicit selection with a head compare-and-swap that passes
|
|
14
|
+
- PR number or URL; omitted -> resolved from the current branch per `verification-brief.md` Section A.
|
|
15
|
+
- Optional issue reference; omitted -> resolved in step 1 (`verification-brief.md` Section A) and fetched in step 2; none found -> judge the PR's stated intent only, never invent acceptance criteria.
|
|
123
16
|
|
|
124
|
-
|
|
125
|
-
per `reference/post-selection-loop.md` `### Merge course`.
|
|
17
|
+
## Steps
|
|
126
18
|
|
|
127
|
-
|
|
19
|
+
Run every step inline; dispatch per `reference/assessment.md` when pi-cohort is present. Each step reads the sibling(s) its row names and produces exactly one output.
|
|
128
20
|
|
|
129
|
-
|
|
130
|
-
|
|
21
|
+
| Step | Read now | Output | Tracker stage |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| 1 Gather | `verification-brief.md` Section A | PR digest: metadata, diff, checks, comments, worktree discovery | `gather` |
|
|
24
|
+
| 2 Provision + configure | `reference/assessment.md` | provisioned worktree; config resolved from the merge-base; ticket fetched; AC rows extracted per `../brainstorming/reference/ticket-acceptance.md` | `provision` |
|
|
25
|
+
| 3 Verify | `verification-brief.md` Section B | evidence record (CI-first) and one disposition per material claim | `verify` |
|
|
26
|
+
| 4 Review | `verification-brief.md` Section C | reviewer findings and the internal comment ledger | `review` |
|
|
27
|
+
| 5 Integrate + report | `reference/findings.md`, then `reference/report.md` | AC outcomes, blockers, nits, drafted payloads, the rendered report | `report` |
|
|
28
|
+
| 6 Menu | `reference/decision-menu.md` | the menu under the verdict line, exactly one `[recommended]` | `menu` |
|
|
29
|
+
| 7 Loop | `reference/post-selection-loop.md` | the executed pick; re-entry until `merge` or `stop` | (re-opens the re-entered stage) |
|
|
131
30
|
|
|
132
|
-
|
|
133
|
-
## Outcome
|
|
134
|
-
<one line + the deciding factor>
|
|
31
|
+
Re-entry: a fix wave's own push re-enters step 4 after re-running step 3's claim check without a second verification pass (the wave's single pass already covered the pushed SHA); any other head move re-enters step 3; an unchanged head re-enters step 5.
|
|
135
32
|
|
|
136
|
-
##
|
|
137
|
-
<CI path: satisfying check name(s)/conclusion/sha/url; local path: verbatim command + raw_tail per run; claims checked; resolved-set check dispositions>
|
|
138
|
-
|
|
139
|
-
## Findings (blocking)
|
|
140
|
-
Blocking findings (P#):
|
|
141
|
-
P1. **<source_ref>** - <defect>. Fix: <concrete change> | Action: <disposition/what unblocks>. [code | test | spec | security | performance | quality]
|
|
142
|
-
Requirement/doc drift (linked issue, committed doc drift, or spec conflict):
|
|
143
|
-
L1. <doc-drift | spec-conflict | outdated-AC | missing-behavior> -> <action>
|
|
144
|
-
|
|
145
|
-
## Comment-thread replies
|
|
146
|
-
C1. <thread ref> -> <drafted reply> (already-addressed | reasonable | judgment-call)
|
|
147
|
-
C2. <thread ref> -> <superseded by C<new> | withdrawn | pending <run url> | reviewer failed (<conclusion>) <run url>>
|
|
148
|
-
|
|
149
|
-
## Non-blocking follow-ups
|
|
150
|
-
F1. **<source_ref>** - <action>. Owner: <pr-author | tracker | human>
|
|
151
|
-
|
|
152
|
-
## Decision
|
|
153
|
-
<action vocabulary + numbered courses>
|
|
154
|
-
|
|
155
|
-
## Drafted fixes / review
|
|
156
|
-
<payloads, each keyed by its finding ID>
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Consent table and courses per `reference/decision-menu.md`.
|
|
160
|
-
|
|
161
|
-
## Decide
|
|
162
|
-
|
|
163
|
-
Render `## Decision` from the consent table for the PR's author and state. Read
|
|
164
|
-
`reference/decision-menu.md` now.
|
|
165
|
-
|
|
166
|
-
## Act
|
|
167
|
-
|
|
168
|
-
The menu is a state machine that loops until merge or an explicit stop. Read
|
|
169
|
-
`reference/post-selection-loop.md` now.
|
|
33
|
+
## Progress tracking
|
|
170
34
|
|
|
171
|
-
|
|
35
|
+
Use `plan_tracker`, never `phase_tracker`. `init` with the first three stages of the table. In step 3 `add` one task per material claim and record each verdict: `complete` matched, `failed` contradicted, `skipped` unverifiable-pre-merge. Once every claim is terminal and `verify` is closed, `add` the remaining three stages - the tracker rejects a verdict recorded behind a still-pending stage. A failed stage or claim stays `failed` while the skill stops at the menu. Without a `plan_tracker` tool, keep a plain checklist; behavior is unchanged.
|
|
172
36
|
|
|
173
|
-
|
|
174
|
-
thread replies, commit subjects, tracker comments - re-read it against:
|
|
37
|
+
## Wording rules
|
|
175
38
|
|
|
176
|
-
|
|
177
|
-
- No headings or template scaffolding on payloads under ~150 words - bullets and
|
|
178
|
-
prose carry short content.
|
|
179
|
-
- Review findings are file:line-specific where one exists, else keyed to the
|
|
180
|
-
finding's `source_ref`, and end on the fix or asked action, not a recap.
|
|
181
|
-
- Empty sections say "None"; never invent content to fill a section.
|
|
39
|
+
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.
|
|
182
40
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
41
|
+
1. One item is one or two whole sentences: what is wrong, then why it matters. No fragments, no field separators.
|
|
42
|
+
2. Name the behavior, not the artifact: "retries forever" beats "attempts counter not incremented".
|
|
43
|
+
3. Locators trail in parentheses (`file:line`, check name, doc path), never inside the sentence.
|
|
44
|
+
4. No category tags, severity words, or IDs in prose - the section heading is the severity, the list number is the ID.
|
|
45
|
+
5. Report only non-conformance; passing checks, covered ACs, and matched claims print only under `show evidence`.
|
|
46
|
+
6. Omit empty sections.
|
|
47
|
+
7. `Delivers` is always present and names which ACs this PR covers and which observable half is checked after merge.
|
|
48
|
+
8. The verdict is one line in the fixed form.
|
|
49
|
+
9. Menu rows start with a verb a human types, carry one clause of consequence, and exactly one row is `[recommended]`; compose grammar lives in the hint line only.
|
|
50
|
+
10. ASCII only, American English, no hedges on checked facts, no intensifiers.
|
|
186
51
|
|
|
187
52
|
## Red flags - STOP
|
|
188
53
|
|
|
189
|
-
-
|
|
190
|
-
-
|
|
191
|
-
-
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
- Reading
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
- A
|
|
198
|
-
-
|
|
199
|
-
-
|
|
200
|
-
- A
|
|
201
|
-
- Batching a file-less `P#` (a claim or a gate command as `source_ref`, no draft touching a file) into a parallel dispatch - a claim `P#` with a drafted file edit is worktree-fixable and batches - dispatching parallel implementers over batches that share a file, or letting a fix-wave child run git commands or a verification pass in the shared worktree, or dispatching a fix-wave child with `worktree: true` - owner: `reference/post-selection-loop.md` `### Fix wave`
|
|
202
|
-
- A second execution of the verification command, a second push, or pushing fix commits after a red gate, within one fix wave - re-running Verify/Review to re-confirm claims and annotate IDs is not a second gate execution - owner: `reference/post-selection-loop.md` `### Fix wave`
|
|
203
|
-
- Posting or committing an external payload without the output done-check - owner: `## Output done-check`
|
|
54
|
+
- Any mutation (fix, push, review, comment, merge, tracker write) without an explicit menu pick - owner: the intro.
|
|
55
|
+
- A code or doc edit sitting in the worktree when a menu renders - owner: `reference/findings.md` `## Drafted payloads`.
|
|
56
|
+
- Blocking on an AC's observation half, or on a PR-body claim the gate cannot check - owner: `reference/findings.md` `## AC outcomes`.
|
|
57
|
+
- `impossible` without all four conditions and a source read this run - owner: `reference/findings.md` `## AC outcomes`.
|
|
58
|
+
- Deferring behavior the ticket promises to a later PR: it is a blocker or an explicit tracker split, nothing else - owner: `reference/findings.md` `## Namespaces`.
|
|
59
|
+
- 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`.
|
|
60
|
+
- Raw command output, drafted payloads, or internal IDs in the rendered report - owner: `reference/report.md`.
|
|
61
|
+
- An open-PR menu without `fix` (a merged or closed PR offers `show evidence` and `stop` only), without `show evidence`, with two `[recommended]`, or with `stop` not last - owner: `reference/decision-menu.md`.
|
|
62
|
+
- A second verification pass or a second push inside one fix wave - owner: `reference/post-selection-loop.md` `### Fix wave`.
|
|
63
|
+
- Approving your own PR - owner: `reference/decision-menu.md` `## Consent table`.
|
|
64
|
+
- Merging around an undispositioned failing check or a pending required check - owner: `reference/findings.md` `## Dispositions`.
|
|
65
|
+
- A claim verdict recorded behind a pending tracker stage - owner: `## Progress tracking`.
|
|
204
66
|
|
|
205
67
|
## Project overrides
|
|
206
68
|
|
|
207
|
-
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.
|
|
69
|
+
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.
|