pi-gauntlet 5.16.1 → 5.16.2
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 +4 -0
- package/package.json +1 -1
- package/skills/gatekeep-pr/SKILL.md +58 -441
- package/skills/gatekeep-pr/reference/assessment.md +129 -0
- package/skills/gatekeep-pr/reference/decision-menu.md +127 -0
- package/skills/gatekeep-pr/reference/findings.md +93 -0
- package/skills/gatekeep-pr/reference/post-selection-loop.md +38 -0
- package/skills/gatekeep-pr/verification-brief.md +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v5.16.2 - 2026-09-22
|
|
4
|
+
|
|
5
|
+
- gatekeep-pr: `SKILL.md` is a flow-ordered body under 250 lines; the assessment phases, finding IDs and dispositions, consent table and courses, and the post-selection loop move to `skills/gatekeep-pr/reference/{assessment,findings,decision-menu,post-selection-loop}.md`, each rule owned once. The CI telemetry-salvage probe reads `reference/post-selection-loop.md`. (#43)
|
|
6
|
+
|
|
3
7
|
## v5.16.1 - 2026-09-20
|
|
4
8
|
|
|
5
9
|
- gauntlet-handoff follows the shipped pi-cohort 7.1.0 `handoff` skill: a skill cannot expand `/skill:handoff`, so step 2 reads cohort's `skills/handoff/SKILL.md` from the session skill list and follows its procedure; the brief path comes from cohort's `Handoff written:` report line (`Handoff not written:` is a STOP) instead of being recomputed; the minimum is stated as pi-cohort >= 7.1.0 in README and the brief contract. (#40)
|
package/package.json
CHANGED
|
@@ -9,19 +9,19 @@ argument-hint: "<pr> [issue-ref] (e.g. 123, or 123 gh-45)"
|
|
|
9
9
|
|
|
10
10
|
Verify, don't trust. A PR description is a claim, not proof: over-claimed coverage,
|
|
11
11
|
hallucinated references, and "tests pass" that were never rerun are the normal case,
|
|
12
|
-
not the exception - especially on generated code.
|
|
13
|
-
verification evidence (
|
|
14
|
-
the fallback),
|
|
15
|
-
|
|
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
16
|
`[recommended]`; it never changes which rows are offered.
|
|
17
17
|
|
|
18
|
-
**Consent gate.** The only actions
|
|
18
|
+
**Consent gate.** The only actions performed before a menu row is picked are:
|
|
19
19
|
read-only gathering, provisioning the worktree, and applying uncommitted, worktree-local
|
|
20
20
|
doc-drift fixes discovered as a blocking finding. Every other action - code fixes,
|
|
21
|
-
pushes, reviews, comments, merges - happens only on
|
|
21
|
+
pushes, reviews, comments, merges - happens only on explicit selection.
|
|
22
22
|
|
|
23
23
|
**Residual risk.** Running the verification command executes PR code with the
|
|
24
|
-
operator's ambient credentials. There is no sandbox.
|
|
24
|
+
operator's ambient credentials. There is no sandbox. Run this skill only against PRs
|
|
25
25
|
you are willing to execute.
|
|
26
26
|
|
|
27
27
|
## Arguments
|
|
@@ -34,10 +34,10 @@ you are willing to execute.
|
|
|
34
34
|
|
|
35
35
|
## Configuration resolution
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
Apply per concern, first match wins, evaluated unconditionally - never delegated to
|
|
38
38
|
a wrapper skill:
|
|
39
39
|
|
|
40
|
-
1. **Repo root `REVIEW.md`** (rubric concerns only).
|
|
40
|
+
1. **Repo root `REVIEW.md`** (rubric concerns only). Wins over the shipped
|
|
41
41
|
baseline and reviewer-persona defaults on any conflict.
|
|
42
42
|
2. **Gauntlet overrides file** (3-location discovery, first found wins): the
|
|
43
43
|
`## PR gate` section (verification command, `timeout minutes`, `requires credentials`, issue
|
|
@@ -46,8 +46,8 @@ a wrapper skill:
|
|
|
46
46
|
3. **Repo documentation** - an explicitly documented command or tool (e.g. `AGENTS.md`'s
|
|
47
47
|
canonical test entrypoint, a documented worktree wrapper, a documented tracker CLI,
|
|
48
48
|
or documented merge policy/branch rules). Reading documentation is not inference.
|
|
49
|
-
Discovery-only:
|
|
50
|
-
4. **Ask the user.** Never
|
|
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
51
|
|
|
52
52
|
The `## PR gate` overrides schema (all keys optional except the verification command,
|
|
53
53
|
which is required unless documented elsewhere):
|
|
@@ -70,7 +70,7 @@ in the repo's `REVIEW.md` (rubric) and the gauntlet overrides file's `## PR gate
|
|
|
70
70
|
section (everything else); anything a wrapper carries beyond trigger phrases is
|
|
71
71
|
misplaced and belongs in one of those two homes instead.
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
Read the ladder from the **merge-base of the PR's base branch**, never from
|
|
74
74
|
the PR's head tree - a PR cannot weaken its own rubric or swap the command that will
|
|
75
75
|
gate it. Recipe: `MB=$(git merge-base origin/<baseRefName> <headRefOid>)`, then for
|
|
76
76
|
each ladder source `git show "$MB:<path>"` (e.g. `git show "$MB:REVIEW.md"`,
|
|
@@ -89,154 +89,17 @@ Use `plan_tracker`, never `phase_tracker`. Init with the first four stages:
|
|
|
89
89
|
Verifier enumerates them and record each verdict: a matched claim ->
|
|
90
90
|
`complete`, a contradicted claim -> `failed` (shown crossed, error color).
|
|
91
91
|
Once every claim is terminal and `claim-check` is closed, `add` `review` and
|
|
92
|
-
`consent menu` and continue.
|
|
93
|
-
|
|
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
94
|
failed stage or claim stays `failed` while the skill stops at the menu -
|
|
95
95
|
never marked complete to move on. On a harness without the `plan_tracker`
|
|
96
96
|
tool: fall back to a plain checklist (or skip if none is available);
|
|
97
97
|
functionality is unchanged either way.
|
|
98
98
|
|
|
99
|
-
##
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
**Phase 1 - Gather.** Run verification-brief.md Section A in full: the fixed `gh`
|
|
104
|
-
command set (`gh pr view`, `gh api user`, `gh pr diff`, both paginated comment
|
|
105
|
-
endpoints, review threads, issue fetch, `git worktree list --porcelain` for
|
|
106
|
-
discovery only), producing the normative gather digest.
|
|
107
|
-
|
|
108
|
-
**Phase 2 - Provision worktree** (the orchestrator's mutation - a state machine):
|
|
109
|
-
|
|
110
|
-
- A worktree already exists on the expected branch (`headRefName` for in-repo PRs,
|
|
111
|
-
a fork-local `pr-<N>` branch for fork PRs), at any path -> reuse it unconditionally.
|
|
112
|
-
In-repo PRs: `git fetch origin` + `git pull --ff-only` (the local branch tracks
|
|
113
|
-
`origin/<headRefName>`). Fork PRs: the local `pr-<N>` branch has no upstream, so
|
|
114
|
-
sync with `git fetch origin pull/<N>/head` + `git merge --ff-only FETCH_HEAD`
|
|
115
|
-
instead. Either way, on divergence, dirt, or local-only commits -> STOP and surface.
|
|
116
|
-
Never force, never create a duplicate.
|
|
117
|
-
- The default path `.worktrees/pr-<N>` exists but holds a different branch -> STOP
|
|
118
|
-
and surface; never repurpose.
|
|
119
|
-
- Nothing exists -> create at `.worktrees/pr-<N>` (an overrides worktree wrapper may
|
|
120
|
-
relocate it), following `using-git-worktrees` conventions (gitignore-first). In-repo
|
|
121
|
-
PRs: `git fetch origin` + `git worktree add .worktrees/pr-<N> <headRefName>`. Fork
|
|
122
|
-
PRs: `git fetch origin pull/<N>/head:pr-<N>` first, then add on that local branch.
|
|
123
|
-
Verify post-checkout that HEAD == the digest's `headRefOid`.
|
|
124
|
-
|
|
125
|
-
Record create-vs-reuse; it drives the non-merge teardown rule below.
|
|
126
|
-
|
|
127
|
-
After provisioning, re-poll `mergeable` once (`gh pr view --json mergeable`) if Section
|
|
128
|
-
A reported `UNKNOWN` - still `UNKNOWN` after this single re-poll is treated as not
|
|
129
|
-
merge-ready and surfaced (see the merge preconditions below).
|
|
130
|
-
|
|
131
|
-
**Phase 3 - Verify, then Review** (sequential, same worktree - deliberate: the
|
|
132
|
-
verification command may write to the tree while the Reviewer reads it):
|
|
133
|
-
|
|
134
|
-
- Run verification-brief.md Section B: resolve the verification evidence per its
|
|
135
|
-
Evidence resolution table (green exact-head CI is the default evidence); run
|
|
136
|
-
the resolved verification command only when the table selects a fallback or
|
|
137
|
-
opt-out row, under its safety contract - self-contained and non-interactive (no prompts; run under a
|
|
138
|
-
non-interactive environment), bounded by a timeout (default 15 minutes, `timeout
|
|
139
|
-
minutes` override) via the first available mechanism: the harness's own bash
|
|
140
|
-
timeout parameter, else the `timeout`/`gtimeout` CLI when installed, else a
|
|
141
|
-
background-and-kill fallback - then material-claim checking against the PR body.
|
|
142
|
-
After a local run, the orchestrator asserts tracked-only cleanliness (`git status --porcelain
|
|
143
|
-
--untracked-files=no` empty, equivalently `git diff --quiet && git diff --cached
|
|
144
|
-
--quiet`; HEAD unmoved) - untracked gate artifacts, including the Verifier's
|
|
145
|
-
`log_path`, are expected and do not fail this check as long as `log_path` sits
|
|
146
|
-
under a gitignored path inside the worktree. Any tracked change invalidates the
|
|
147
|
-
run - re-provision and re-run once.
|
|
148
|
-
- Run verification-brief.md Section C: review the source behind the diff against the
|
|
149
|
-
merged rubric (shipped `review-baseline.md` overlaid by base-branch `REVIEW.md`),
|
|
150
|
-
triage existing comments. The Reviewer emits its native output format only - AC
|
|
151
|
-
coverage is not part of its contract.
|
|
152
|
-
|
|
153
|
-
**Phase 4 - Integrate** (orchestrator):
|
|
154
|
-
|
|
155
|
-
- **Provenance:** `worktree_root` matches the provisioned path, every `run_cwd` is
|
|
156
|
-
inside it, `head_sha` matches the digest's `headRefOid`. On mismatch, re-fetch the
|
|
157
|
-
PR head once and re-sync + re-run Phase 3 if it advanced; a second mismatch, or any
|
|
158
|
-
path mismatch, is treated as missing evidence - not merge-ready. The claim stated in output names its source. Local path: precisely "reproduced
|
|
159
|
-
locally under the project's documented verification command" - nothing
|
|
160
|
-
stronger; never worded to imply a deployed, staging, or CI environment.
|
|
161
|
-
CI path (`source: ci`): precisely
|
|
162
|
-
`verified by CI: <check name(s)> succeeded on <sha> (run <url>)`
|
|
163
|
-
- never phrased as local reproduction, never implying the local command ran;
|
|
164
|
-
`<sha>` is the assessed `headRefOid`, `<url>` degrades to `unavailable` when
|
|
165
|
-
absent. Provenance checks on `worktree_root`/`run_cwd` bind only to the local
|
|
166
|
-
path.
|
|
167
|
-
- **Telemetry record:** run `node <bin>/gauntlet-telemetry-salvage.mjs --worktree
|
|
168
|
-
<provisioned path> --base origin/<baseRefName> --check` (`<bin>` = `<directory of
|
|
169
|
-
this skill's SKILL.md>/../../bin`). Detect-only: it never mutates. `present` / `no
|
|
170
|
-
telemetry run` / `never written` land in `## Evidence` as one line each. `stripped
|
|
171
|
-
<path> in <sha>` mints a blocking `P#` (`source_ref`:
|
|
172
|
-
`gauntlet-telemetry-salvage`) whose drafted fix is "run the salvage without
|
|
173
|
-
`--check`" - the spec and its telemetry record are deliverables that ship in the
|
|
174
|
-
squash. On a cell with no push row (fork overlay, report-only states) the same
|
|
175
|
-
finding is a non-blocking follow-up instead: the record stays recoverable from the
|
|
176
|
-
PR head ref after merge, and blocking would stop a ship the gate cannot repair.
|
|
177
|
-
`unfinished <path>` (record still `in_progress` with no ship phase) also lands in `## Evidence` as one line and is non-blocking: pre-landing `in_progress` is normal, and the merge course's salvage run stamps it.
|
|
178
|
-
- **Evidence:** On the CI path, list each satisfying check's name, conclusion, assessed SHA, and run URL - there is no command or raw_tail to paste. On the local path, paste each run's `command` and `raw_tail` verbatim, fenced - never
|
|
179
|
-
paraphrased. Any authored summary is labeled as a summary and never substitutes for
|
|
180
|
-
`raw_tail`.
|
|
181
|
-
- **Severity translation:** Critical -> blocking, Moderate -> blocking, Minor ->
|
|
182
|
-
non-blocking follow-up. A repo `REVIEW.md` severity mapping overrides this; any
|
|
183
|
-
severity it names but does not map is fail-safe **blocking**, noted in the output.
|
|
184
|
-
- **AC coverage:** the orchestrator computes `met` / `partial` / `missing` per
|
|
185
|
-
acceptance criterion from the issue's ACs, the diff, and the Reviewer's findings -
|
|
186
|
-
it is an integration product, not raw persona output. Only `met` is merge-ready;
|
|
187
|
-
`partial` or `missing` is blocking. Skipped entirely when no issue is linked.
|
|
188
|
-
- **Claims:** a failed local gate is a hard merge failure. A `contradicted` material
|
|
189
|
-
claim is a blocking finding. An `unverifiable-pre-merge` claim used as merge proof
|
|
190
|
-
(appears in the PR body's evidence/result/test-plan content) is blocking; stated as
|
|
191
|
-
an explicit post-merge observation instead, it is a non-blocking follow-up.
|
|
192
|
-
- **CI checks:** any blocking conclusion in the resolved check set (required or
|
|
193
|
-
not - see the brief's Evidence resolution table) withholds merge from every
|
|
194
|
-
pre-composed course until the user explicitly dispositions it, and mints a
|
|
195
|
-
`P#`. Three dispositions: **flaky** (proceed via the custom row), **real** (it
|
|
196
|
-
blocks until green), **CI-infrastructure-broken** (the checks themselves are
|
|
197
|
-
untrustworthy: triggers the fallback local run, and merge stays withheld until
|
|
198
|
-
that fallback produces green evidence). A **pending** required check (still
|
|
199
|
-
running - the normal case, not a defect) is **wait-until-green, not
|
|
200
|
-
dispositionable**: it mints no `P#`, is never dispositioned, and the withhold
|
|
201
|
-
auto-lifts the moment it turns green - or, if it instead fails, converts into
|
|
202
|
-
an undispositioned failing check with its own `P#` at that point. While
|
|
203
|
-
pending, the report notes it under Evidence and every merge course simply does
|
|
204
|
-
not render (a pending-only PR is not a blocking verdict - findings groups can
|
|
205
|
-
all read "None" - the recommended course falls to `stop` or `review-comment`,
|
|
206
|
-
never a merge course, until it resolves). The evidence decision is
|
|
207
|
-
independent: a green check elsewhere in the resolved set still satisfies
|
|
208
|
-
verification evidence while a pending required check withholds merge. The
|
|
209
|
-
CI-sufficient path changes no consent surface: still read-only, no auto-merge,
|
|
210
|
-
no posting, no menu change beyond the third disposition.
|
|
211
|
-
- **Doc drift:** when the review finds committed doc drift as a **blocking** finding,
|
|
212
|
-
the orchestrator applies the doc fixes itself, in the provisioned worktree (created
|
|
213
|
-
or reused), as part of assessment - real edits, uncommitted, worktree-local. The
|
|
214
|
-
result is presented in `## Findings`, the edits themselves under
|
|
215
|
-
`## Drafted fixes / review`. Pushing them is a separate, later menu selection.
|
|
216
|
-
Follow-ups alone never trigger doc fixes - only blocking drift does.
|
|
217
|
-
|
|
218
|
-
## Inline-first execution
|
|
219
|
-
|
|
220
|
-
> This section is an optional optimization. Delete it and the rest of the skill still
|
|
221
|
-
> works: the orchestrator can run every phase above itself, inline, with no subagent
|
|
222
|
-
> system.
|
|
223
|
-
|
|
224
|
-
The inline path is primary: the orchestrator runs the brief's sections itself, in
|
|
225
|
-
order, self-contained. When pi-cohort is available, delegation is an optimization
|
|
226
|
-
layered on top, never a hard dependency:
|
|
227
|
-
|
|
228
|
-
- **Gatherer** -> `scout` builtin, as a prior sync run producing the gather digest.
|
|
229
|
-
- **Verifier** -> `worker` builtin, dispatched with the report-only constraint
|
|
230
|
-
prepended to its task ("report only - do not edit, fix, or commit anything").
|
|
231
|
-
- **Reviewer** -> the existing `code-reviewer` agent, emitting its native output
|
|
232
|
-
format (never overridden at call time).
|
|
233
|
-
|
|
234
|
-
Verifier and Reviewer share the provisioned worktree via `cwd`, dispatched
|
|
235
|
-
**sequentially** (Verify before Review, per Phase 3) - never `worktree: true`, which
|
|
236
|
-
would provision a separate isolated worktree and break the shared-tree contract this
|
|
237
|
-
skill depends on. A subagent that fails, or violates its section's output schema, is
|
|
238
|
-
re-dispatched once demanding the schema; a second failure means that section runs
|
|
239
|
-
inline instead.
|
|
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.
|
|
240
103
|
|
|
241
104
|
## Verdict
|
|
242
105
|
|
|
@@ -245,42 +108,23 @@ merge-proof unverifiable claim, `partial`/`missing` AC coverage, scope creep whe
|
|
|
245
108
|
issue is linked, committed doc drift, anything the merged rubric maps to blocking),
|
|
246
109
|
**follow-ups only** (never gate merge), or **clean**.
|
|
247
110
|
|
|
248
|
-
**Merge preconditions** (all must hold):
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
| Author | State | Offered rows (first = `[recommended]`) |
|
|
267
|
-
|---|---|---|
|
|
268
|
-
| you | clean / follow-ups only | merge (squash); merge (merge-commit); do not merge (leave it); post no-blockers comment |
|
|
269
|
-
| you | blocking | apply code fixes (named finding subset): skill edits in worktree, commits, re-runs gate, pushes - then merge re-offered; push applied doc fixes; do not act; post review-comment of findings |
|
|
270
|
-
| someone else | clean / follow-ups only | approve; merge (squash, offered-unrecommended); post no-blockers comment |
|
|
271
|
-
| someone else | blocking | post request-changes review; apply fixes on their branch (courtesy option 2); reply to existing threads; post comment |
|
|
272
|
-
| bot author | any | someone-else's rows for the same state, review actions recommended |
|
|
273
|
-
| fork (any) | any | post review (request-changes / comment / approve per state) - push and merge rows absent |
|
|
274
|
-
| any | draft PR | assessment rows only; merge and approve rows absent until ready-for-review |
|
|
275
|
-
| any | merged / closed | report-only; no mutation rows |
|
|
276
|
-
|
|
277
|
-
The consent table above remains the single oracle for what may be offered; the
|
|
278
|
-
Decision rendering section defines how its rows render as actions and numbered
|
|
279
|
-
courses. Rows GitHub would refuse (branch protection, missing permissions,
|
|
280
|
-
`viewerPermission` too low) are listed as unavailable with the reason. Approving
|
|
281
|
-
your own PR is not offered. Nothing executes until explicit selection.
|
|
282
|
-
|
|
283
|
-
## Output
|
|
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
|
|
123
|
+
|
|
124
|
+
Define `<bin>` = `<directory of this skill's SKILL.md>/../../bin`. Merge execution
|
|
125
|
+
per `reference/post-selection-loop.md` `### Merge course`.
|
|
126
|
+
|
|
127
|
+
## Report
|
|
284
128
|
|
|
285
129
|
The rendered report is terse by design: deciding factor, evidence lines, ID'd
|
|
286
130
|
findings, menu. No restating diffs, no narration, no recap prose.
|
|
@@ -305,238 +149,23 @@ Requirement/doc drift (linked issue, committed doc drift, or spec conflict):
|
|
|
305
149
|
F1. **<source_ref>** - <action>. Owner: <pr-author | tracker | human>
|
|
306
150
|
|
|
307
151
|
## Decision
|
|
308
|
-
<action vocabulary + numbered courses
|
|
152
|
+
<action vocabulary + numbered courses>
|
|
309
153
|
|
|
310
154
|
## Drafted fixes / review
|
|
311
155
|
<payloads, each keyed by its finding ID>
|
|
312
156
|
```
|
|
313
157
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
- `<source_ref>` is a `file:line` where one exists, else the disputed thing (a
|
|
317
|
-
quoted PR-body claim, a failing gate command, a required check name).
|
|
318
|
-
- **Precedence:** Phase 4 and the merged rubric decide blocking vs. follow-up (the
|
|
319
|
-
severity translation, AC coverage, claims, and required-check rules above); this
|
|
320
|
-
section only chooses **which namespace** (`P#` / `L#` / `F#`) renders that
|
|
321
|
-
decision. Category tags and the triage bar below never override an upstream
|
|
322
|
-
blocking classification - a Phase-4 Moderate is always blocking (`P#` or `L#`
|
|
323
|
-
per Total mapping), never demoted to `F#` by tag or by judgment call.
|
|
324
|
-
- **Total mapping:** every blocking element of the Verdict maps to a `P#` or `L#` -
|
|
325
|
-
a blocking verdict with "None" in both groups is a rendering bug. Concretely:
|
|
326
|
-
failed gate -> `P#` `[test]` referencing the gate command; contradicted or
|
|
327
|
-
merge-proof-unverifiable material claim -> `P#` `[spec]` referencing the claim;
|
|
328
|
-
scope creep with a linked issue -> `L#` `spec-conflict`; committed doc drift ->
|
|
329
|
-
`L#` `doc-drift`; `partial` AC coverage -> `L#` `outdated-AC`; `missing` AC
|
|
330
|
-
coverage -> `L#` `missing-behavior`. `L#` covers exactly the drift the Verdict
|
|
331
|
-
already blocks on (committed doc drift, AC coverage, spec conflict); it widens
|
|
332
|
-
nothing. Code-level spec bugs (the diff contradicts the spec) are `P#` `[spec]`;
|
|
333
|
-
requirement/doc mismatches (the spec or docs are stale relative to intent) are
|
|
334
|
-
`L#`.
|
|
335
|
-
- **Failing checks close by disposition, not by fix:** an undispositioned failing check in the resolved set
|
|
336
|
-
is `P#` `[test]` referencing the check name; it is never a target
|
|
337
|
-
of a worktree `fix`. The user's Phase-4 disposition annotates the same ID rather
|
|
338
|
-
than closing it outright: dispositioned **flaky** -> annotate
|
|
339
|
-
`(dispositioned: flaky)`; this annotation excepts the `P#` from the unfixed-blocker
|
|
340
|
-
set - it no longer counts against "every `P#` blocks" or the merge precondition
|
|
341
|
-
"every blocking finding fixed", and the merge path is Phase 4's explicit flaky
|
|
342
|
-
disposition via the custom row. Dispositioned **real** -> annotate
|
|
343
|
-
`(dispositioned: real)` and the `P#` keeps blocking until the check is green.
|
|
344
|
-
Dispositioned **CI-infrastructure-broken** -> annotate
|
|
345
|
-
`(dispositioned: ci-infrastructure-broken)`; the fallback local run executes,
|
|
346
|
-
and the `P#` keeps blocking until that fallback is green.
|
|
347
|
-
- **Severity is decided at triage, not by the category tag:** a finding lands in
|
|
348
|
-
`P#` only when it must be fixed before merge (correctness, security, material
|
|
349
|
-
performance trap, a convention the repo enforces); improvements that don't
|
|
350
|
-
change merge correctness are `F#`, whatever their category. `[quality]` on a
|
|
351
|
-
`P#` is a category, never a downgrade - every `P#` blocks. This triage bar governs
|
|
352
|
-
findings the orchestrator originates itself; it never re-triages a classification
|
|
353
|
-
Phase 4 already made (see Precedence above).
|
|
354
|
-
- `C#` replies are verdict-neutral drafts: they never block and never gate merge;
|
|
355
|
-
nothing posts until selected.
|
|
356
|
-
- `F#` items carry an owner so follow-ups don't evaporate; when no tracker tool
|
|
357
|
-
resolved, the report itself is their durable home.
|
|
358
|
-
- **IDs are append-only for the run's lifetime:** minted at first assessment,
|
|
359
|
-
never renumbered, never reused. A resolved finding keeps its ID annotated
|
|
360
|
-
`(fixed in <sha>)`; later rounds continue each namespace's sequence.
|
|
361
|
-
- Empty groups say "None".
|
|
362
|
-
|
|
363
|
-
"Drafted fixes / review" holds, per finding ID, the concrete edit (for `fix`), the
|
|
364
|
-
reviewed doc-drift edit (for `push-docs`, keyed to its `L#`), or the reply text
|
|
365
|
-
(for `reply`) - each keyed to its finding ID, one selection mapping 1:1 to its
|
|
366
|
-
payload. A posted review body is not itself a finding: it is composed at post time
|
|
367
|
-
from the ID'd `P#`/`L#` findings being addressed - one summary sentence, then the
|
|
368
|
-
numbered findings, ending on the fix or asked action - and occupies its own
|
|
369
|
-
non-finding slot of this section.
|
|
370
|
-
|
|
371
|
-
## Decision rendering
|
|
372
|
-
|
|
373
|
-
`## Decision` has two parts: the action vocabulary, then the numbered courses.
|
|
374
|
-
|
|
375
|
-
**Action vocabulary** (bare verbs; availability constraints inline):
|
|
376
|
-
|
|
377
|
-
```markdown
|
|
378
|
-
Actions (compose freely in the custom row):
|
|
379
|
-
fix <P#s|all> apply blocking fixes in worktree, re-run gate, push (in-repo PRs only)
|
|
380
|
-
push-docs push already-applied doc-drift edits (only when uncommitted
|
|
381
|
-
reviewed doc edits exist
|
|
382
|
-
in the worktree)
|
|
383
|
-
merge-squash | merge-commit (preconditions per Verdict;
|
|
384
|
-
never bundled with a push,
|
|
385
|
-
except the telemetry: restore commit)
|
|
386
|
-
request-changes | review-comment | approve (approve: never own PR)
|
|
387
|
-
reply <C#s> post drafted thread replies
|
|
388
|
-
tracker <act> tracker action (only when a tracker tool resolved)
|
|
389
|
-
stop leave the PR as-is / report-only exit
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
A `+ tracker <act>` suffix is available on any mutation course when a tracker tool
|
|
393
|
-
resolved.
|
|
394
|
-
|
|
395
|
-
**Selection grammar:** ID sets accept `all`, ranges (`P1-P4`), comma lists
|
|
396
|
-
(`P1,P3`), and exclusions (`all but P2`).
|
|
397
|
-
|
|
398
|
-
**Numbered courses** - a normative rendering of the consent table (never a second
|
|
399
|
-
offer source): per author x state cell, exactly one `[recommended]` course first,
|
|
400
|
-
the custom row always last. Courses are **atomic across pushes**: no course,
|
|
401
|
-
pre-composed or custom, bundles a push-producing action (`fix`, `push-docs`) with
|
|
402
|
-
`merge-*`; after a fix wave the menu re-renders with merge as row 1.
|
|
403
|
-
|
|
404
|
-
| Author | State | Courses (first = `[recommended]`) |
|
|
405
|
-
|---|---|---|
|
|
406
|
-
| you | clean / follow-ups only | 1. merge-squash; 2. merge-commit; 3. stop; 4. review-comment (post no-blockers note) |
|
|
407
|
-
| you | blocking | 1. fix (worktree-fixable P#s only - `all` covers only those) [+ push-docs when uncommitted doc edits exist]; 2. push-docs (alone, when doc edits exist); 3. stop; 4. review-comment (post findings). When no P# is worktree-fixable (blocking is failing-check-only or L#-only), course 1 (fix) is not rendered: push-docs becomes first when doc edits exist, else stop is first |
|
|
408
|
-
| you | blocking, post-fix re-render (gate green, preconditions hold) | 1. merge-squash; 2. merge-commit; 3. stop; 4. review-comment |
|
|
409
|
-
| someone else | clean / follow-ups only | 1. approve; 2. merge-squash (offered-unrecommended); 3. review-comment (no-blockers note) |
|
|
410
|
-
| someone else | blocking | 1. request-changes; 2. fix all (courtesy, their branch - omitted when nothing is worktree-fixable); 3. reply <C#s> (omitted when the `C#` group is None); 4. review-comment |
|
|
411
|
-
| bot author | any | someone-else's rows for the same state; review actions recommended |
|
|
412
|
-
| any | draft | 1. request-changes / review-comment / reply <C#s> (omit the reply course when the `C#` group is None) / stop - `[recommended]` follows the same authorship rule as the non-draft cells, **except** on your own draft PR `request-changes` is never recommended (you cannot request changes on your own PR any more than you can approve it); the fallback recommendation there is `review-comment` when findings exist, else `stop`. Custom present but cannot compose `merge-*`/`approve`/`fix`/`push-docs` until ready-for-review |
|
|
413
|
-
| any | merged / closed | 1. stop; report-only, no other mutation courses at all; Custom present but cannot compose `merge-*`/`approve`/`fix`/`push-docs`/`request-changes`/`review-comment`/`reply`/`tracker` - nothing remains actionable |
|
|
414
|
-
|
|
415
|
-
**Fork overlay:** the consent-table fork row renders as an overlay on the authorship
|
|
416
|
-
cells (push/merge/fix absent; approve also dropped when the viewer authored the PR) -
|
|
417
|
-
it is not a distinct authorship cell. It overlays whichever authorship row above
|
|
418
|
-
applies (you vs. someone else), removing `fix`, `push-docs`, and `merge-*` (never
|
|
419
|
-
available on a fork). When you authored the fork PR, `approve` is
|
|
420
|
-
also dropped (never offered on your own PR) - fork|you|clean renders
|
|
421
|
-
`review-comment`/`stop` only; fork|you|blocking renders
|
|
422
|
-
`request-changes`/`review-comment`/`stop` (the someone-else courtesy fix-on-their-
|
|
423
|
-
branch course is also absent, since it is your own PR). A fork PR authored by someone
|
|
424
|
-
else uses the someone-else cells above with `fix`/`push-docs`/`merge-*` removed.
|
|
425
|
-
|
|
426
|
-
**CI-check gate on merge courses:** an undispositioned failing check in the resolved
|
|
427
|
-
set, or a pending **required** check, withholds every pre-composed course containing `merge-*` (per the
|
|
428
|
-
Verdict merge preconditions) - none render, whatever the author/state cell says. A
|
|
429
|
-
pending check mints no `P#` and is wait-until-green, not dispositionable (see Phase
|
|
430
|
-
4); a failing one mints a `P#` and takes a disposition (flaky / real / CI-infrastructure-broken). A **flaky** disposition does
|
|
431
|
-
not restore merge to a pre-composed course; merge proceeds only via the custom row
|
|
432
|
-
naming the disposition explicitly. A **real** disposition, or an unresolved pending
|
|
433
|
-
check, keeps every merge course withheld until the check is green; a **CI-infrastructure-broken** disposition keeps them withheld until the triggered fallback run is green - a pending-only
|
|
434
|
-
render is not itself a blocking verdict (findings groups may all read "None"); the
|
|
435
|
-
recommended course falls to `stop` or `review-comment` in the meantime. This never
|
|
436
|
-
falls through to the clean cell's recommended `merge-squash` - a failing resolved-set
|
|
437
|
-
check or a pending required check means the PR is not in the clean state to begin with.
|
|
438
|
-
|
|
439
|
-
Rows a cell offers but GitHub would refuse (branch protection, missing permission)
|
|
440
|
-
render listed-but-unavailable with the reason. Zero mutation courses is a legal
|
|
441
|
-
render (merged/closed) - the menu still appears, carrying findings and `stop`.
|
|
442
|
-
|
|
443
|
-
Example render (golden fixture 1 - own PR, blocking findings including committed doc
|
|
444
|
-
drift, so uncommitted reviewed doc edits exist):
|
|
158
|
+
Consent table and courses per `reference/decision-menu.md`.
|
|
445
159
|
|
|
446
|
-
|
|
447
|
-
Pick one:
|
|
448
|
-
1. fix all (P1-P10) + push-docs [recommended]
|
|
449
|
-
2. push-docs (docs only, hold code fixes)
|
|
450
|
-
3. stop (leave as-is)
|
|
451
|
-
4. review-comment (post findings, act later)
|
|
452
|
-
5. Custom - compose: e.g. "fix P1-P8,P10 + push-docs" or "reply C1 + tracker comment"
|
|
453
|
-
```
|
|
160
|
+
## Decide
|
|
454
161
|
|
|
455
|
-
|
|
162
|
+
Render `## Decision` from the consent table for the PR's author and state. Read
|
|
163
|
+
`reference/decision-menu.md` now.
|
|
456
164
|
|
|
457
|
-
|
|
458
|
-
Pick one:
|
|
459
|
-
1. merge-squash [recommended]
|
|
460
|
-
2. merge-commit
|
|
461
|
-
3. stop (leave as-is)
|
|
462
|
-
4. review-comment
|
|
463
|
-
5. Custom
|
|
464
|
-
```
|
|
165
|
+
## Act
|
|
465
166
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
The menu is a state machine, not a one-shot report:
|
|
469
|
-
|
|
470
|
-
1. **Compare-and-swap before every external write:** re-fetch `headRefOid`, `state`,
|
|
471
|
-
`mergeable`. Any change since assessment invalidates the current state - re-sync
|
|
472
|
-
the worktree, re-run Phase 3, re-render the menu. **Exception:** a course's own
|
|
473
|
-
push updates the assessed head to the pushed SHA as part of that course's
|
|
474
|
-
execution - this self-inflicted head move does not invalidate the course; the
|
|
475
|
-
next CAS check runs against the new head on the next external write.
|
|
476
|
-
2. Execute only the selected course. **Fix wave** (`fix <set>`): first filter the
|
|
477
|
-
selected set to worktree-fixable `P#`s - drop any `P#` closed by disposition
|
|
478
|
-
(an undispositioned failing-check `P#` is never a `fix` target; a **flaky**
|
|
479
|
-
disposition already excepts it) - and route file-less `P#`s (a claim or a gate
|
|
480
|
-
command as `source_ref`, no draft touching a file) to run inline/sequentially,
|
|
481
|
-
never as part of a parallel file-batch.
|
|
482
|
-
|
|
483
|
-
For the remaining worktree-fixable set, batch by the **union of files each
|
|
484
|
-
finding's drafted edit in `## Drafted fixes / review` touches** (fallback to
|
|
485
|
-
the `source_ref` file only when a finding has no draft) - findings whose
|
|
486
|
-
drafts share a file share a batch.
|
|
487
|
-
|
|
488
|
-
**Child contract (same for 1 batch or many):** children are `implementer`
|
|
489
|
-
dispatches - `subagent({ agent: "implementer", context: "fresh", cwd: <PR
|
|
490
|
-
worktree> })`, matching Inline-first execution's persona-naming style; this is
|
|
491
|
-
the pi-cohort optimization path, inline is always valid per that section. The
|
|
492
|
-
orchestrator owns commit, gate, and push - never a child. Every dispatched
|
|
493
|
-
child gets `cwd` = the PR worktree, **`worktree: true` forbidden** (a separate
|
|
494
|
-
isolated worktree breaks the shared-tree contract - see Inline-first
|
|
495
|
-
execution); is **edit-only, no git commands, no verification runs**, and must
|
|
496
|
-
never delete `.pi/gauntlet/telemetry/**` or anything under the configured
|
|
497
|
-
telemetry dir (a fix that "cleans up" the run's telemetry record is a defect in
|
|
498
|
-
the fix - the record is a deliverable); and its task is that batch's `P#` lines
|
|
499
|
-
**plus the drafted edit already keyed to each
|
|
500
|
-
ID** in `## Drafted fixes / review` - the child applies the consented payload,
|
|
501
|
-
it does not re-solve the finding. Below the cutoff (<= 2 worktree-fixable findings), the orchestrator
|
|
502
|
-
applies inline instead of dispatching - the no-cohort path stays available at
|
|
503
|
-
any batch count per Inline-first execution. Above the cutoff, when more than
|
|
504
|
-
one batch results, dispatch the batches' children **in parallel**, all under
|
|
505
|
-
the same contract.
|
|
506
|
-
|
|
507
|
-
Once every dispatched/inline batch returns, the orchestrator commits the golden
|
|
508
|
-
course as one local commit set - the code fixes plus any already-applied
|
|
509
|
-
reviewed doc edits selected alongside them (one commit, or one per batch
|
|
510
|
-
sequentially; subjects name the fixes) - then re-resolves the evidence for the new head **once** (the brief's stale-head row: prior evidence is stale; the local command executes only on a fallback/opt-out resolution). Before the push, run
|
|
511
|
-
`node <bin>/gauntlet-telemetry-salvage.mjs --worktree <provisioned path> --base
|
|
512
|
-
origin/<baseRefName>` (no `--check`); a `restored` or `(marked shipped)` commit rides the wave's single
|
|
513
|
-
push and the pushed SHA becomes the assessed head under the course's-own-push rule
|
|
514
|
-
in step 1. Print its stdout in the re-rendered report's `## Evidence`. **On
|
|
515
|
-
green**, push **once**; gate and push are per-wave invariants, never per-fix or
|
|
516
|
-
per-batch. **On red**, do not push: leave the commit(s) local, re-render with
|
|
517
|
-
the unresolved `P#`s still open, and warn that unpushed fix commits sit in the
|
|
518
|
-
worktree exactly like unpushed doc edits (see Teardown). Doc fixes (`push-docs`
|
|
519
|
-
alone) follow the same green-gate-then-push rule: stage + commit (subject names
|
|
520
|
-
what is documented), re-run the gate, push only on green. Reviews, replies, and
|
|
521
|
-
tracker actions -> `gh pr review` / `gh api` / the tracker tool, non-interactive,
|
|
522
|
-
with the drafted payload for the selected IDs.
|
|
523
|
-
3. After any mutation that can change readiness (fix wave pushed, docs pushed, PR
|
|
524
|
-
head moved), re-run the claim-check and Review on the synced worktree: claims
|
|
525
|
-
are re-checked against the new head and findings are re-rendered, but
|
|
526
|
-
the verification command itself is **not** re-executed here - step 2's evidence re-resolution
|
|
527
|
-
already was the wave's one and only gate pass. Re-render the report:
|
|
528
|
-
each selected `P#`/`L#` confirmed resolved is annotated `(fixed in <sha>)`
|
|
529
|
-
under its original ID; unresolved ones stay open unchanged; new findings
|
|
530
|
-
continue the sequence. Merge, if now available, renders as row 1.
|
|
531
|
-
4. Loop until the user selects merge or an explicit stop/no-action row.
|
|
532
|
-
|
|
533
|
-
**Teardown:** merge success -> tear down the worktree, whether it was reused or
|
|
534
|
-
created (the sync precondition guarantees no local-only work is stranded, and the
|
|
535
|
-
branch is gone remotely). A non-merge stop: offer teardown of a **created** worktree
|
|
536
|
-
(never autonomous; warn if unpushed doc edits would be discarded); a **reused**
|
|
537
|
-
worktree is left as found - if unpushed doc edits **or unpushed fix commits from a
|
|
538
|
-
red-gate hold** remain in it, say so explicitly and let the user choose
|
|
539
|
-
leave-or-discard.
|
|
167
|
+
The menu is a state machine that loops until merge or an explicit stop. Read
|
|
168
|
+
`reference/post-selection-loop.md` now.
|
|
540
169
|
|
|
541
170
|
## Output done-check
|
|
542
171
|
|
|
@@ -556,33 +185,21 @@ overrides file - see Project overrides.
|
|
|
556
185
|
|
|
557
186
|
## Red flags - STOP
|
|
558
187
|
|
|
559
|
-
- Approving your own PR
|
|
560
|
-
- Any mutation (fix, push, review, merge) without an explicit menu selection
|
|
561
|
-
- Pasting paraphrased evidence instead of verbatim `raw_tail`
|
|
562
|
-
- A provenance mismatch (worktree, `run_cwd`, or `head_sha`) noticed and ignored
|
|
563
|
-
- Merging around an undispositioned blocking finding or failing-check `P#`
|
|
564
|
-
- Reading configuration (rubric, verification command, or ladder sources) from the
|
|
565
|
-
|
|
566
|
-
-
|
|
567
|
-
-
|
|
568
|
-
|
|
569
|
-
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
- A
|
|
573
|
-
|
|
574
|
-
- A pre-composed course, or a custom row, composing an action the overlay or the
|
|
575
|
-
cell lists as unavailable
|
|
576
|
-
- Batching a file-less `P#` (a claim or a gate command as `source_ref`, no draft touching a file)
|
|
577
|
-
into a parallel dispatch - a claim `P#` with a drafted file edit is
|
|
578
|
-
worktree-fixable and may batch - dispatching parallel implementers over
|
|
579
|
-
batches that share a file, or letting a fix-wave child run git commands or a
|
|
580
|
-
verification pass in the shared worktree, or dispatching a fix-wave child with
|
|
581
|
-
`worktree: true`
|
|
582
|
-
- A second execution of the verification command, a second push, or pushing fix
|
|
583
|
-
commits after a red gate, within one fix wave - re-running Verify/Review to
|
|
584
|
-
re-confirm claims and annotate IDs (step 3) is not a second gate execution
|
|
585
|
-
- Posting or committing an external payload without the output done-check
|
|
188
|
+
- Approving your own PR - owner: `reference/decision-menu.md` `## Consent table`
|
|
189
|
+
- Any mutation (fix, push, review, merge) without an explicit menu selection - owner: **Consent gate** (intro)
|
|
190
|
+
- Pasting paraphrased evidence instead of verbatim `raw_tail` - owner: `reference/assessment.md` `## Phase 4 - Integrate`
|
|
191
|
+
- A provenance mismatch (worktree, `run_cwd`, or `head_sha`) noticed and ignored - owner: `reference/assessment.md` `## Phase 4 - Integrate`
|
|
192
|
+
- Merging around an undispositioned blocking finding or failing-check `P#` - owner: `reference/findings.md` `## Dispositions`
|
|
193
|
+
- Reading configuration (rubric, verification command, or ladder sources) from the PR's head instead of the base branch's merge-base - owner: `## Configuration resolution`
|
|
194
|
+
- Renumbering or reusing a finding ID between menu rounds - owner: `reference/findings.md` `## IDs`
|
|
195
|
+
- Presenting findings without IDs, or a blocking verdict with no `P#`/`L#` - owner: `reference/findings.md` `## IDs`
|
|
196
|
+
- A `## Decision` rendered without its action vocabulary - owner: `reference/decision-menu.md` `## Actions`
|
|
197
|
+
- Treating `[quality]` or `[performance]` as a downgrade signal on a `P#` - only an explicit Phase-4 flaky disposition excepts a failing-check `P#` from the unfixed-blocker set, never a category tag - owner: `reference/findings.md` `## Triage`
|
|
198
|
+
- A course (pre-composed or custom) bundling a push-producing action with `merge-*` - owner: `reference/decision-menu.md` `## Courses`
|
|
199
|
+
- A pre-composed course, or a custom row, composing an action the overlay or the cell lists as unavailable - owner: `reference/decision-menu.md` `## Fork overlay`
|
|
200
|
+
- 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`
|
|
201
|
+
- 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`
|
|
202
|
+
- Posting or committing an external payload without the output done-check - owner: `## Output done-check`
|
|
586
203
|
|
|
587
204
|
## Project overrides
|
|
588
205
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# gatekeep-pr: assessment
|
|
2
|
+
|
|
3
|
+
Read from SKILL.md `## Assess`. Four phases run in order; Phases 1-3 are read-only.
|
|
4
|
+
|
|
5
|
+
## Phase 1 - Gather
|
|
6
|
+
|
|
7
|
+
Run `../verification-brief.md` Section A in full: the fixed `gh` command set
|
|
8
|
+
(`gh pr view`, `gh api user`, `gh pr diff`, both paginated comment endpoints,
|
|
9
|
+
review threads, issue fetch, `git worktree list --porcelain` for discovery
|
|
10
|
+
only). It produces the normative gather digest.
|
|
11
|
+
|
|
12
|
+
## Phase 2 - Provision worktree
|
|
13
|
+
|
|
14
|
+
The orchestrator's mutation - a state machine.
|
|
15
|
+
|
|
16
|
+
| State | In-repo PR | Fork PR | On divergence |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| A worktree exists on the expected branch (`headRefName` for in-repo PRs, a fork-local `pr-<N>` branch for fork PRs), at any path | Reuse unconditionally; sync with `git fetch origin` + `git pull --ff-only` (the local branch tracks `origin/<headRefName>`) | Reuse unconditionally; the local `pr-<N>` branch has no upstream - sync with `git fetch origin pull/<N>/head` + `git merge --ff-only FETCH_HEAD` | STOP and surface on divergence, dirt, or local-only commits; never force, never create a duplicate |
|
|
19
|
+
| The default path `.worktrees/pr-<N>` exists but holds a different branch | STOP and surface; never repurpose | STOP and surface; never repurpose | - |
|
|
20
|
+
| Nothing exists (an overrides worktree wrapper can relocate it, following `using-git-worktrees` conventions, gitignore-first) | Create at `.worktrees/pr-<N>`; `git fetch origin` + `git worktree add .worktrees/pr-<N> <headRefName>`; verify post-checkout that HEAD == the digest's `headRefOid` | Create at `.worktrees/pr-<N>`; `git fetch origin pull/<N>/head:pr-<N>` first, then add on that local branch; verify post-checkout that HEAD == the digest's `headRefOid` | - |
|
|
21
|
+
|
|
22
|
+
Record create-vs-reuse; it drives the non-merge teardown rule in `post-selection-loop.md`
|
|
23
|
+
`### Teardown`.
|
|
24
|
+
|
|
25
|
+
After provisioning, re-poll `mergeable` once (`gh pr view --json mergeable`) when
|
|
26
|
+
Section A reported `UNKNOWN`. Still `UNKNOWN` after this single re-poll is treated as
|
|
27
|
+
not merge-ready and surfaced (merge preconditions per SKILL.md `## Verdict`).
|
|
28
|
+
|
|
29
|
+
## Phase 3 - Verify, then review
|
|
30
|
+
|
|
31
|
+
Sequential, same worktree - deliberate: the verification command can write to the tree
|
|
32
|
+
while the Reviewer reads it.
|
|
33
|
+
|
|
34
|
+
Run `../verification-brief.md` Section B: resolve the verification evidence per its
|
|
35
|
+
Evidence resolution table (green exact-head CI is the default evidence). Run the
|
|
36
|
+
resolved verification command only when the table selects a fallback or opt-out row,
|
|
37
|
+
under its safety contract: self-contained and non-interactive (no prompts, under a
|
|
38
|
+
non-interactive environment), bounded by a timeout (default 15 minutes, `timeout
|
|
39
|
+
minutes` override) via the first available mechanism - the harness's own bash timeout
|
|
40
|
+
parameter, else the `timeout`/`gtimeout` CLI when installed, else a background-and-kill
|
|
41
|
+
fallback. Then check material claims against the PR body.
|
|
42
|
+
|
|
43
|
+
After a local run, assert tracked-only cleanliness: `git status --porcelain
|
|
44
|
+
--untracked-files=no` empty, equivalently `git diff --quiet && git diff --cached
|
|
45
|
+
--quiet`; HEAD unmoved. Untracked gate artifacts, including the Verifier's `log_path`,
|
|
46
|
+
are expected and do not fail this check as long as `log_path` sits under a gitignored
|
|
47
|
+
path inside the worktree. Any tracked change invalidates the run: re-provision and
|
|
48
|
+
re-run once.
|
|
49
|
+
|
|
50
|
+
Run `../verification-brief.md` Section C: review the source behind the diff against
|
|
51
|
+
the merged rubric - shipped `../review-baseline.md` overlaid by base-branch
|
|
52
|
+
`REVIEW.md` - and triage existing comments. The Reviewer emits its native output
|
|
53
|
+
format only; AC coverage is not part of its contract.
|
|
54
|
+
|
|
55
|
+
## Phase 4 - Integrate
|
|
56
|
+
|
|
57
|
+
Orchestrator step.
|
|
58
|
+
|
|
59
|
+
- **Provenance:** `worktree_root` matches the provisioned path, every `run_cwd` sits
|
|
60
|
+
inside it, `head_sha` matches the digest's `headRefOid`. On mismatch, re-fetch the
|
|
61
|
+
PR head once and re-sync + re-run Phase 3 when it advanced; a second mismatch, or
|
|
62
|
+
any path mismatch, counts as missing evidence - not merge-ready. The claim stated
|
|
63
|
+
in output names its source. Local path: precisely "reproduced locally under the
|
|
64
|
+
project's documented verification command" - nothing stronger; never worded to
|
|
65
|
+
imply a deployed, staging, or CI environment. CI path (`source: ci`): precisely
|
|
66
|
+
`verified by CI: <check name(s)> succeeded on <sha> (run <url>)` - never phrased as
|
|
67
|
+
local reproduction, never implying the local command ran; `<sha>` is the assessed
|
|
68
|
+
`headRefOid`, `<url>` degrades to `unavailable` when absent. Provenance checks on
|
|
69
|
+
`worktree_root`/`run_cwd` bind only to the local path.
|
|
70
|
+
- **Telemetry record:** run
|
|
71
|
+
`node <bin>/gauntlet-telemetry-salvage.mjs --worktree <provisioned path> --base
|
|
72
|
+
origin/<baseRefName> --check`. The `--check` flag makes the probe detect-only: it
|
|
73
|
+
never mutates. `present` / `no telemetry run` / `never written` land in
|
|
74
|
+
`## Evidence` as one line each. `stripped <path> in <sha>` mints a blocking `P#`
|
|
75
|
+
(`source_ref`: `gauntlet-telemetry-salvage`) whose drafted fix is "run the salvage
|
|
76
|
+
without `--check`" - the spec and its telemetry record are deliverables that ship
|
|
77
|
+
in the squash. On a cell with no push row (fork overlay, report-only states) the
|
|
78
|
+
same finding is a non-blocking follow-up instead: the record stays recoverable
|
|
79
|
+
from the PR head ref after merge, and blocking would stop a ship the gate cannot
|
|
80
|
+
repair. `unfinished <path>` (record still `in_progress` with no ship phase) also
|
|
81
|
+
lands in `## Evidence` as one line and is non-blocking: pre-landing `in_progress`
|
|
82
|
+
is normal, and the merge course's salvage run stamps it.
|
|
83
|
+
- **Evidence:** on the CI path, list each satisfying check's name, conclusion,
|
|
84
|
+
assessed SHA, and run URL - there is no command or `raw_tail` to paste. On the
|
|
85
|
+
local path, paste each run's `command` and `raw_tail` verbatim, fenced - never
|
|
86
|
+
paraphrased. Any authored summary is labeled as a summary and never substitutes for
|
|
87
|
+
`raw_tail`.
|
|
88
|
+
- **Severity translation:** Critical -> blocking, Moderate -> blocking, Minor ->
|
|
89
|
+
non-blocking follow-up. A repo `REVIEW.md` severity mapping overrides this; any
|
|
90
|
+
severity it names but does not map is fail-safe **blocking**, noted in the output.
|
|
91
|
+
- **AC coverage:** the orchestrator computes `met` / `partial` / `missing` per
|
|
92
|
+
acceptance criterion from the issue's ACs, the diff, and the Reviewer's findings -
|
|
93
|
+
an integration product, not raw persona output. Only `met` is merge-ready;
|
|
94
|
+
`partial` or `missing` is blocking. Skip entirely when no issue is linked.
|
|
95
|
+
- **Claims:** a failed local gate is a hard merge failure. A `contradicted` material
|
|
96
|
+
claim is a blocking finding. An `unverifiable-pre-merge` claim used as merge proof
|
|
97
|
+
(appears in the PR body's evidence/result/test-plan content) is blocking; stated as
|
|
98
|
+
an explicit post-merge observation instead, it is a non-blocking follow-up.
|
|
99
|
+
- **CI checks:** disposition a failing or pending check per `findings.md`
|
|
100
|
+
`## Dispositions`.
|
|
101
|
+
- **Doc drift:** when the review finds committed doc drift as a **blocking** finding,
|
|
102
|
+
apply the doc fixes in the provisioned worktree (created or reused), as part of
|
|
103
|
+
assessment - real edits, uncommitted, worktree-local. Present the result in
|
|
104
|
+
`## Findings`, the edits themselves under `## Drafted fixes / review`. Pushing them
|
|
105
|
+
is a separate, later menu selection. Follow-ups alone never trigger doc fixes; only
|
|
106
|
+
blocking drift does.
|
|
107
|
+
|
|
108
|
+
## Inline-first execution
|
|
109
|
+
|
|
110
|
+
> This section is an optional optimization. Delete it and the rest of the skill still
|
|
111
|
+
> works: the orchestrator can run every phase in this file itself, inline, with no
|
|
112
|
+
> subagent system.
|
|
113
|
+
|
|
114
|
+
The inline path is primary: the orchestrator runs the brief's sections itself, in
|
|
115
|
+
order, self-contained. When pi-cohort is available, delegation is an optimization
|
|
116
|
+
layered on top, never a hard dependency.
|
|
117
|
+
|
|
118
|
+
| Phase role | Persona | Detail |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| Gatherer | `scout` builtin | dispatched as a prior sync run producing the gather digest |
|
|
121
|
+
| Verifier | `worker` builtin | dispatched with the report-only constraint prepended to its task ("report only - do not edit, fix, or commit anything") |
|
|
122
|
+
| Reviewer | the existing `code-reviewer` agent | emits its native output format (never overridden at call time) |
|
|
123
|
+
|
|
124
|
+
Verifier and Reviewer share the provisioned worktree via `cwd`, dispatched
|
|
125
|
+
**sequentially** (Verify before Review, per `## Phase 3 - Verify, then review`) - never `worktree: true`,
|
|
126
|
+
which would provision a separate isolated worktree and break the shared-tree contract
|
|
127
|
+
this skill depends on. A subagent that fails, or violates its section's output
|
|
128
|
+
schema, is re-dispatched once demanding the schema; a second failure means that
|
|
129
|
+
section runs inline instead.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# gatekeep-pr: decision menu
|
|
2
|
+
|
|
3
|
+
Read from SKILL.md `## Decide`. `## Decision` in the report has two parts: the
|
|
4
|
+
action vocabulary, then the numbered courses.
|
|
5
|
+
|
|
6
|
+
## Actions
|
|
7
|
+
|
|
8
|
+
```markdown
|
|
9
|
+
Actions (compose freely in the custom row):
|
|
10
|
+
fix <P#s|all> apply blocking fixes in worktree, re-run gate, push (in-repo PRs only)
|
|
11
|
+
push-docs push already-applied doc-drift edits (only when uncommitted
|
|
12
|
+
reviewed doc edits exist
|
|
13
|
+
in the worktree)
|
|
14
|
+
merge-squash | merge-commit (preconditions per Verdict;
|
|
15
|
+
never bundled with a push,
|
|
16
|
+
except the telemetry: restore commit)
|
|
17
|
+
request-changes | review-comment | approve (approve: never own PR)
|
|
18
|
+
reply <C#s> post drafted thread replies
|
|
19
|
+
tracker <act> tracker action (only when a tracker tool resolved)
|
|
20
|
+
stop leave the PR as-is / report-only exit
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A `+ tracker <act>` suffix is available on any mutation course when a tracker tool
|
|
24
|
+
resolved.
|
|
25
|
+
|
|
26
|
+
Selection grammar: ID sets accept `all`, ranges (`P1-P4`), comma lists
|
|
27
|
+
(`P1,P3`), and exclusions (`all but P2`).
|
|
28
|
+
|
|
29
|
+
## Consent table
|
|
30
|
+
|
|
31
|
+
Deterministic - this table is the golden-scenario oracle.
|
|
32
|
+
|
|
33
|
+
| Author | State | Offered rows (first = `[recommended]`) |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| you | clean / follow-ups only | merge (squash); merge (merge-commit); do not merge (leave it); post no-blockers comment |
|
|
36
|
+
| you | blocking | apply code fixes (named finding subset): skill edits in worktree, commits, re-runs gate, pushes - then merge re-offered; push applied doc fixes; do not act; post review-comment of findings |
|
|
37
|
+
| someone else | clean / follow-ups only | approve; merge (squash, offered-unrecommended); post no-blockers comment |
|
|
38
|
+
| someone else | blocking | post request-changes review; apply fixes on their branch (courtesy option 2); reply to existing threads; post comment |
|
|
39
|
+
| bot author | any | someone-else's rows for the same state, review actions recommended |
|
|
40
|
+
| fork (any) | any | post review (request-changes / comment / approve per state) - push and merge rows absent |
|
|
41
|
+
| any | draft PR | assessment rows only; merge and approve rows absent until ready-for-review |
|
|
42
|
+
| any | merged / closed | report-only; no mutation rows |
|
|
43
|
+
|
|
44
|
+
This table is the single oracle for what is offered; `## Courses` renders its
|
|
45
|
+
rows as actions and numbered courses. Rows GitHub would refuse (branch protection,
|
|
46
|
+
missing permissions, `viewerPermission` too low) render listed-but-unavailable with
|
|
47
|
+
the reason. Approving your own PR is never offered. Nothing executes until explicit
|
|
48
|
+
selection.
|
|
49
|
+
|
|
50
|
+
## Courses
|
|
51
|
+
|
|
52
|
+
A normative rendering of the consent table (never a second offer source): per
|
|
53
|
+
author x state cell, exactly one `[recommended]` course renders first, the custom
|
|
54
|
+
row renders last. Courses are atomic across pushes: no course, pre-composed or
|
|
55
|
+
custom, bundles a push-producing action (`fix`, `push-docs`) with `merge-*`; after
|
|
56
|
+
a fix wave the menu re-renders with merge as row 1.
|
|
57
|
+
|
|
58
|
+
| Author | State | Courses (first = `[recommended]`) |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| you | clean / follow-ups only | 1. merge-squash; 2. merge-commit; 3. stop; 4. review-comment (post no-blockers note) |
|
|
61
|
+
| you | blocking | 1. fix (worktree-fixable P#s only - `all` covers only those) [+ push-docs when uncommitted doc edits exist]; 2. push-docs (alone, when doc edits exist); 3. stop; 4. review-comment (post findings). When no P# is worktree-fixable (blocking is failing-check-only or L#-only), course 1 (fix) does not render: push-docs becomes first when doc edits exist, else stop is first |
|
|
62
|
+
| you | blocking, post-fix re-render (gate green, preconditions hold) | 1. merge-squash; 2. merge-commit; 3. stop; 4. review-comment |
|
|
63
|
+
| someone else | clean / follow-ups only | 1. approve; 2. merge-squash (offered-unrecommended); 3. review-comment (no-blockers note) |
|
|
64
|
+
| someone else | blocking | 1. request-changes; 2. fix all (courtesy, their branch - omitted when nothing is worktree-fixable); 3. reply <C#s> (omitted when the `C#` group is None); 4. review-comment |
|
|
65
|
+
| bot author | any | someone-else's rows for the same state; review actions recommended |
|
|
66
|
+
| any | draft | 1. request-changes / review-comment / reply <C#s> (omit the reply course when the `C#` group is None) / stop - `[recommended]` follows the same authorship rule as the non-draft cells, except on your own draft PR `request-changes` is never recommended (you cannot request changes on your own PR any more than you can approve it); the fallback recommendation there is `review-comment` when findings exist, else `stop`. Custom present but cannot compose `merge-*`/`approve`/`fix`/`push-docs` until ready-for-review |
|
|
67
|
+
| any | merged / closed | 1. stop; report-only, no other mutation courses at all; Custom present but cannot compose `merge-*`/`approve`/`fix`/`push-docs`/`request-changes`/`review-comment`/`reply`/`tracker` - nothing remains actionable |
|
|
68
|
+
|
|
69
|
+
## Fork overlay
|
|
70
|
+
|
|
71
|
+
The consent-table fork row renders as an overlay on the authorship cells
|
|
72
|
+
(push/merge/fix absent; approve also dropped when the viewer authored the PR) - it
|
|
73
|
+
is not a distinct authorship cell. It overlays the applicable authorship cell (you
|
|
74
|
+
or someone else), removing `fix`, `push-docs`, and `merge-*` (never available on a
|
|
75
|
+
fork). When you authored the fork PR, `approve` is also dropped (never offered on
|
|
76
|
+
your own PR) - fork|you|clean renders `review-comment`/`stop` only; fork|you|blocking
|
|
77
|
+
renders `request-changes`/`review-comment`/`stop` (the someone-else courtesy
|
|
78
|
+
fix-on-their-branch course is also absent, since it is your own PR). A fork PR
|
|
79
|
+
authored by someone else uses the someone-else cells with `fix`/`push-docs`/
|
|
80
|
+
`merge-*` removed.
|
|
81
|
+
|
|
82
|
+
## CI-check gate
|
|
83
|
+
|
|
84
|
+
An undispositioned failing check in the resolved set, or a pending required check,
|
|
85
|
+
withholds every pre-composed course containing `merge-*` (merge preconditions per
|
|
86
|
+
SKILL.md `## Verdict`) - none render, whatever the author/state cell says.
|
|
87
|
+
Disposition and pending-check definitions per `findings.md` `## Dispositions`.
|
|
88
|
+
|
|
89
|
+
| Disposition | Merge courses |
|
|
90
|
+
|---|---|
|
|
91
|
+
| Flaky | Not restored to a pre-composed course; merge proceeds only via the custom row naming the disposition explicitly |
|
|
92
|
+
| Real, or an unresolved pending check | Withheld until the check is green |
|
|
93
|
+
| CI-infrastructure-broken | Withheld until the triggered fallback run is green |
|
|
94
|
+
|
|
95
|
+
A pending-only render is not itself a blocking verdict (findings groups can all
|
|
96
|
+
read "None"); the recommended course falls to `stop` or `review-comment` in the
|
|
97
|
+
meantime. This never falls through to the clean cell's recommended `merge-squash` -
|
|
98
|
+
a failing resolved-set check or a pending required check means the PR is not in the
|
|
99
|
+
clean state to begin with.
|
|
100
|
+
|
|
101
|
+
## Fixtures
|
|
102
|
+
|
|
103
|
+
Refused rows render per `## Consent table`. Zero mutation courses is a legal
|
|
104
|
+
render (merged/closed) - the menu still appears, carrying findings and `stop`.
|
|
105
|
+
|
|
106
|
+
Example render (golden fixture 1 - own PR, blocking findings including committed
|
|
107
|
+
doc drift, so uncommitted reviewed doc edits exist):
|
|
108
|
+
|
|
109
|
+
```markdown
|
|
110
|
+
Pick one:
|
|
111
|
+
1. fix all (P1-P10) + push-docs [recommended]
|
|
112
|
+
2. push-docs (docs only, hold code fixes)
|
|
113
|
+
3. stop (leave as-is)
|
|
114
|
+
4. review-comment (post findings, act later)
|
|
115
|
+
5. Custom - compose: e.g. "fix P1-P8,P10 + push-docs" or "reply C1 + tracker comment"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Golden fixture 2 - the post-fix re-render after course 1's gate re-run passes:
|
|
119
|
+
|
|
120
|
+
```markdown
|
|
121
|
+
Pick one:
|
|
122
|
+
1. merge-squash [recommended]
|
|
123
|
+
2. merge-commit
|
|
124
|
+
3. stop (leave as-is)
|
|
125
|
+
4. review-comment
|
|
126
|
+
5. Custom
|
|
127
|
+
```
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# gatekeep-pr: findings
|
|
2
|
+
|
|
3
|
+
Read from SKILL.md `## Assess`. Phase 4 mints the IDs the report and menu carry.
|
|
4
|
+
|
|
5
|
+
## IDs
|
|
6
|
+
|
|
7
|
+
`<source_ref>` is a `file:line` where one exists, else the disputed thing (a
|
|
8
|
+
quoted PR-body claim, a failing gate command, a required check name).
|
|
9
|
+
|
|
10
|
+
Precedence: Phase 4 and the merged rubric decide blocking vs. follow-up (the
|
|
11
|
+
severity translation, AC coverage, claims, and required-check rules). This
|
|
12
|
+
section only chooses which namespace (`P#` / `L#` / `F#`) renders that
|
|
13
|
+
decision. Category tags and the triage bar never override an upstream
|
|
14
|
+
blocking classification - a Phase-4 Moderate is always blocking (`P#` or `L#`
|
|
15
|
+
per Total mapping), never demoted to `F#` by tag or by judgment call.
|
|
16
|
+
|
|
17
|
+
Total mapping: every blocking element of the Verdict maps to a `P#` or `L#` -
|
|
18
|
+
a blocking verdict with "None" in both groups is a rendering bug. Map: failed
|
|
19
|
+
gate -> `P#` `[test]` referencing the gate command; contradicted or
|
|
20
|
+
merge-proof-unverifiable material claim -> `P#` `[spec]` referencing the
|
|
21
|
+
claim; scope creep with a linked issue -> `L#` `spec-conflict`; committed doc
|
|
22
|
+
drift -> `L#` `doc-drift`; `partial` AC coverage -> `L#` `outdated-AC`;
|
|
23
|
+
`missing` AC coverage -> `L#` `missing-behavior`. `L#` covers exactly the
|
|
24
|
+
drift the Verdict already blocks on (committed doc drift, AC coverage, spec
|
|
25
|
+
conflict); it widens nothing.
|
|
26
|
+
|
|
27
|
+
`P#` vs `L#` boundary: code-level spec bugs (the diff contradicts the spec)
|
|
28
|
+
are `P#` `[spec]`; requirement/doc mismatches (the spec or docs are stale
|
|
29
|
+
relative to intent) are `L#`.
|
|
30
|
+
|
|
31
|
+
`C#` replies are verdict-neutral drafts: they never block and never gate
|
|
32
|
+
merge; nothing posts until selected.
|
|
33
|
+
|
|
34
|
+
`F#` items carry an owner (pr-author | tracker | human) so follow-ups don't
|
|
35
|
+
evaporate; when no tracker tool resolved, the report itself is their durable
|
|
36
|
+
home.
|
|
37
|
+
|
|
38
|
+
IDs are append-only for the run's lifetime: minted at first assessment, never
|
|
39
|
+
renumbered, never reused. A resolved finding keeps its ID annotated
|
|
40
|
+
`(fixed in <sha>)`; later rounds continue each namespace's sequence.
|
|
41
|
+
|
|
42
|
+
Empty groups say "None".
|
|
43
|
+
|
|
44
|
+
## Triage
|
|
45
|
+
|
|
46
|
+
A finding lands in `P#` only when it must be fixed before merge (correctness,
|
|
47
|
+
security, material performance trap, a convention the repo enforces);
|
|
48
|
+
improvements that don't change merge correctness are `F#`, whatever their
|
|
49
|
+
category. `[quality]` and `[performance]` on a `P#` are categories, never a
|
|
50
|
+
downgrade - every `P#` blocks. This triage bar governs findings the
|
|
51
|
+
orchestrator originates itself; it never re-triages a classification Phase 4
|
|
52
|
+
already made (see Precedence in `## IDs`).
|
|
53
|
+
|
|
54
|
+
## Dispositions
|
|
55
|
+
|
|
56
|
+
Any blocking conclusion in the resolved check set (required or not - per
|
|
57
|
+
`../verification-brief.md` Section B, Evidence resolution table) withholds
|
|
58
|
+
merge from every pre-composed course until the user explicitly dispositions
|
|
59
|
+
it, and mints a `P#`.
|
|
60
|
+
|
|
61
|
+
An undispositioned failing check in the resolved set is `P#` `[test]`
|
|
62
|
+
referencing the check name; it is never a target of a worktree `fix`. Close
|
|
63
|
+
failing checks by disposition, not by fix: the user's Phase-4 disposition
|
|
64
|
+
annotates the same ID rather than closing it outright.
|
|
65
|
+
|
|
66
|
+
| Disposition | Annotation on the `P#` | Counts against unfixed-blocker set | Merge course | Fallback local run |
|
|
67
|
+
|---|---|---|---|---|
|
|
68
|
+
| undispositioned failing check | none yet | yes | withheld from every pre-composed course | none |
|
|
69
|
+
| flaky | `(dispositioned: flaky)` | excepted - no longer counts against "every `P#` blocks" or "every blocking finding fixed" | only the custom row naming the disposition explicitly; no pre-composed course restores | none |
|
|
70
|
+
| real | `(dispositioned: real)` | still counts - `P#` keeps blocking | withheld until the check is green | none |
|
|
71
|
+
| CI-infrastructure-broken | `(dispositioned: ci-infrastructure-broken)` | still counts - `P#` keeps blocking; the checks themselves are untrustworthy | withheld until the fallback run is green | triggers the fallback local run, and merge stays withheld until that fallback produces green evidence |
|
|
72
|
+
| pending required check | mints no `P#`, is never dispositioned | not applicable - not dispositionable | withheld; auto-lifts the moment it turns green, or converts to an undispositioned failing check with its own `P#` on failure | none |
|
|
73
|
+
|
|
74
|
+
A pending required check is wait-until-green, not dispositionable. While
|
|
75
|
+
pending, the report notes it under Evidence.
|
|
76
|
+
|
|
77
|
+
The evidence decision is independent of the merge decision: a green check
|
|
78
|
+
elsewhere in the resolved set still satisfies verification evidence while a
|
|
79
|
+
pending required check withholds merge. The CI-sufficient path changes no
|
|
80
|
+
consent surface: still read-only, no auto-merge, no posting, no menu change
|
|
81
|
+
beyond the third disposition.
|
|
82
|
+
|
|
83
|
+
## Payloads
|
|
84
|
+
|
|
85
|
+
"Drafted fixes / review" holds, per finding ID, the concrete edit (for
|
|
86
|
+
`fix`), the reviewed doc-drift edit (for `push-docs`, keyed to its `L#`), or
|
|
87
|
+
the reply text (for `reply`) - each keyed to its finding ID, one selection
|
|
88
|
+
mapping 1:1 to its payload.
|
|
89
|
+
|
|
90
|
+
A posted review body is not itself a finding: compose it at post time from
|
|
91
|
+
the ID'd `P#`/`L#` findings being addressed - one summary sentence, then the
|
|
92
|
+
numbered findings, ending on the fix or asked action - and give it its own
|
|
93
|
+
non-finding slot of this section.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# gatekeep-pr: post-selection loop
|
|
2
|
+
|
|
3
|
+
## Post-selection loop
|
|
4
|
+
|
|
5
|
+
Read from SKILL.md `## Act`. Treat the menu as a state machine: execute only the selected course, re-render, and loop until the user selects merge or an explicit stop/no-action row.
|
|
6
|
+
|
|
7
|
+
### Compare-and-swap
|
|
8
|
+
|
|
9
|
+
Before every external write, re-fetch `headRefOid`, `state`, and `mergeable`. Any change since assessment invalidates the current state - re-sync the worktree, re-run Phase 3 per `assessment.md` `## Phase 3 - Verify, then review`, and re-render the menu. Exception: a course's own push updates the assessed head to the pushed SHA as part of that course's execution - this self-inflicted head move does not invalidate the course; the next compare-and-swap check runs against the new head on the next external write.
|
|
10
|
+
|
|
11
|
+
### Fix wave
|
|
12
|
+
|
|
13
|
+
For a `fix <set>` selection, filter the selected set to worktree-fixable `P#`s first: drop any `P#` closed by disposition (per `findings.md` `## Dispositions`). Route file-less `P#`s (a claim or a gate command as `source_ref`, no draft touching a file) to run inline and sequentially, never as part of a parallel batch. A claim `P#` with a drafted file edit is worktree-fixable and batches.
|
|
14
|
+
|
|
15
|
+
Batch the remaining worktree-fixable set by the union of files each finding's drafted edit in `## Drafted fixes / review` touches - fall back to the `source_ref` file only when a finding has no draft. Findings whose drafts share a file share a batch.
|
|
16
|
+
|
|
17
|
+
Use one child contract for every batch, whether there is one or many: dispatch `implementer` children with `subagent({ agent: "implementer", context: "fresh", cwd: <PR worktree> })`. The orchestrator owns commit, gate, and push - never a child. Every dispatched child gets `cwd` = the PR worktree; `worktree: true` is forbidden per `assessment.md` `## Inline-first execution`. Each child is edit-only - no git commands, no verification runs - and must never delete `.pi/gauntlet/telemetry/**` or anything under the configured telemetry dir (a fix that "cleans up" the run's telemetry record is a defect in the fix, not a cleanup). Each child's task is that batch's `P#` lines plus the drafted edit already keyed to each ID in `## Drafted fixes / review` - the child applies the consented payload, it does not re-solve the finding.
|
|
18
|
+
|
|
19
|
+
At a cutoff of 2 worktree-fixable findings or fewer, the orchestrator applies the fix inline instead of dispatching - the no-cohort path stays available at any batch count per `assessment.md` `## Inline-first execution`. Past that cutoff, when more than one batch results, dispatch the batches' children in parallel, all under the same contract.
|
|
20
|
+
|
|
21
|
+
Once every dispatched or inline batch returns, commit the golden course as one local commit set - the code fixes plus any already-applied reviewed doc edits selected alongside them (one commit, or one per batch sequentially; subjects name the fixes). Re-resolve the evidence for the new head once (the brief's stale-head row: prior evidence is stale; the local command executes only on a fallback/opt-out resolution). Before the push, run `node <bin>/gauntlet-telemetry-salvage.mjs --worktree <provisioned path> --base origin/<baseRefName>` (no `--check`); a `restored` or `(marked shipped)` commit rides the wave's single push and the pushed SHA becomes the assessed head under the course's-own-push rule in `### Compare-and-swap`. Print its stdout in the re-rendered report's `## Evidence`. On green, push once - gate and push are per-wave invariants, never per-fix or per-batch. On red, do not push: leave the commit(s) local, re-render with the unresolved `P#`s still open, and warn that unpushed fix commits sit in the worktree exactly like unpushed doc edits (per `### Teardown`).
|
|
22
|
+
|
|
23
|
+
Doc fixes (`push-docs` alone) follow the same rule: stage and commit (subject names what is documented), re-run the gate, and push only on green. Execute reviews, replies, and tracker actions via `gh pr review` / `gh api` / the tracker tool, non-interactively, with the drafted payload for the selected IDs.
|
|
24
|
+
|
|
25
|
+
### Merge course
|
|
26
|
+
|
|
27
|
+
Merge always executes as `gh pr merge --match-head-commit <assessed-sha>`. Push and merge are never bundled into one selection, with one scoped exception: the selected merge course first runs the salvage (no `--check`) via `node <bin>/gauntlet-telemetry-salvage.mjs --worktree <provisioned path> --base origin/<baseRefName>`. `present` -> merge as-is. `restored <path> from <sha>` -> push that single `telemetry: restore` commit as part of this course, re-fetch `headRefOid`, and pass the new SHA to `--match-head-commit`. A line ending `(marked shipped)` (`present` or `restored`) is handled the same way: push that single `telemetry:` commit, re-fetch `headRefOid`, and pass the new SHA. `restore failed` -> merge proceeds, the reason is printed, and the follow-up names recovery from the PR head ref. A merge selection while any precondition (SKILL.md `## Verdict`) fails is refused, naming the failing precondition, and the menu re-renders - never a dead end, never a silent merge.
|
|
28
|
+
|
|
29
|
+
### Re-render
|
|
30
|
+
|
|
31
|
+
After any mutation that can change readiness (fix wave pushed, docs pushed, PR head moved), re-run the claim-check and Review on the synced worktree: claims are re-checked against the new head and findings are re-rendered, but do not re-execute the verification command here - the fix wave's evidence re-resolution already was the wave's one gate pass. Annotate each selected `P#`/`L#` confirmed resolved as `(fixed in <sha>)` under its original ID; unresolved ones stay open unchanged; new findings continue the sequence. Merge, if now available, renders as row 1.
|
|
32
|
+
|
|
33
|
+
### Teardown
|
|
34
|
+
|
|
35
|
+
| | Created worktree | Reused worktree |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| Merge success | tear down | tear down (the sync precondition guarantees no local-only work is stranded, and the branch is gone remotely) |
|
|
38
|
+
| Non-merge stop | offer teardown, never autonomous; warn if unpushed doc edits would be discarded | leave as found; say so explicitly when unpushed doc edits or red-gate fix commits remain, and let the user choose leave-or-discard |
|
|
@@ -55,7 +55,7 @@ invent ACs.
|
|
|
55
55
|
|
|
56
56
|
`mergeable` is reported as-is, including `UNKNOWN` - the Gatherer runs before
|
|
57
57
|
provisioning, so it never re-polls; the orchestrator re-polls once after
|
|
58
|
-
provisioning the worktree (
|
|
58
|
+
provisioning the worktree (per `reference/assessment.md` `## Phase 2 - Provision worktree`) and treats a still-`UNKNOWN`
|
|
59
59
|
result as not merge-ready. Bot author noted
|
|
60
60
|
(`author_is_bot`). Capture each status check's `isRequired` where exposed (digest field: `required`).
|
|
61
61
|
|
|
@@ -81,7 +81,7 @@ conclusion, with `ERROR` blocking and `PENDING` pending. Missing `required` is
|
|
|
81
81
|
treated as non-required. `ci checks:` matches check name, workflow name, or
|
|
82
82
|
status context, trimmed, case-insensitive. What checks mean for verification evidence is owned by
|
|
83
83
|
Section B's Evidence resolution table; what they mean for merge is owned by the
|
|
84
|
-
orchestrator's required-check rule (
|
|
84
|
+
orchestrator's required-check rule (`reference/findings.md` `## Dispositions`) - two independent
|
|
85
85
|
consumers of the same data.
|
|
86
86
|
|
|
87
87
|
## Section B - Verifier
|