pi-gauntlet 6.2.1 → 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 +10 -0
- package/README.md +6 -6
- package/package.json +1 -1
- 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
|
@@ -1,226 +1,118 @@
|
|
|
1
|
-
# gatekeep-pr:
|
|
2
|
-
|
|
3
|
-
Read from SKILL.md
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
merge-squash anyway | merge-commit anyway (custom row only: overrides a
|
|
17
|
-
reviewer-withheld merge - the literal
|
|
18
|
-
`anyway` accepts the named reason;
|
|
19
|
-
GitHub-refused rows stay uncomposable)
|
|
20
|
-
wait poll the reviewer run and comment set, then re-render
|
|
21
|
-
request-changes | review-comment | approve (approve: never own PR)
|
|
22
|
-
reply <C#s> post drafted thread replies
|
|
23
|
-
tracker <act> tracker action (only when a tracker tool resolved)
|
|
24
|
-
stop leave the PR as-is / report-only exit
|
|
25
|
-
```
|
|
1
|
+
# gatekeep-pr: step 6 - menu
|
|
2
|
+
|
|
3
|
+
Read from SKILL.md step 6. Input: the report's verdict and the PR state. Output: the menu appended under the verdict line. Nothing executes until a pick; the pick runs per `post-selection-loop.md`.
|
|
4
|
+
|
|
5
|
+
## Verbs
|
|
6
|
+
|
|
7
|
+
`fix`, `push`, `review`, `approve`, `merge`, `merge anyway`, `reply`, `propose ticket change`, `show evidence`, `wait`, `stop`.
|
|
8
|
+
|
|
9
|
+
Rows are `<n>. <verb> - <consequence>`; every row, `stop` and `(not available: ...)` rows included, carries its consequence clause. `stop` is always last, before the compose hint. `show evidence` is always offered and never `[recommended]`. A row GitHub would refuse (branch protection, missing permission, `viewerPermission` too low) renders `(not available: <reason>)` and is never `[recommended]`. Exactly one row is `[recommended]`.
|
|
26
10
|
|
|
27
|
-
|
|
28
|
-
|
|
11
|
+
- `fix` - apply the drafted payloads for the named blockers (default: all open blockers; with no open blockers, the nit payloads) in the provisioned worktree, run the verification pass once at the resulting SHA, push when `push` is available; `fix nits` applies nit payloads only, `fix + nits` blockers and nits; with no drafted payload at all, the human names the change
|
|
12
|
+
- `push` - push local fix commits (renders only when unpushed commits exist)
|
|
13
|
+
- `review` - post the blockers as a GitHub review: request-changes on someone else's PR, a comment on your own
|
|
14
|
+
- `approve` - approve the PR (never your own)
|
|
15
|
+
- `merge` - `gh pr merge --match-head-commit <assessed-sha>` with the resolved `merge policy` (default squash); preconditions per `post-selection-loop.md` `### Merge preconditions`
|
|
16
|
+
- `merge anyway - accept AC<n> as impossible` - merge while an `impossible` row withholds it; lifts exactly that AC's withhold
|
|
17
|
+
- `merge anyway` - merge while the pending-reviewer overlay withholds it; prints what it overrode
|
|
18
|
+
- `reply` - post the drafted replies under `PR comments` (`reply <n>` for one)
|
|
19
|
+
- `propose ticket change` - show the drafted AC text verbatim; post it as a tracker comment on an explicit confirmation reply, via the resolved tracker verb (`gh issue comment`, the overrides' tracker mapping, or `/skill:linear`); re-fetch the ticket first and re-render instead of posting when the AC row text drifted; no write path -> copy-paste block
|
|
20
|
+
- `show evidence` - print the evidence record, claim and AC outcomes, dispositions, drafted payloads and replies (`report.md` `## What stays out`)
|
|
21
|
+
- `wait` - poll the reviewer run, the pending required checks, and the comment set, then re-render
|
|
22
|
+
- `stop` - leave the PR as-is
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
Compose hint: `Type a number, or compose: "fix 2", "fix nits", "fix + nits", "fix 1 + reply".` A composed line never bundles a push-producing verb (`fix`, `push`) with `merge`. When a failing check withholds `merge`, the hint line also offers `check <name> flaky | real | ci-broken`, which records the disposition on that check (`findings.md` `## Dispositions`): `flaky` lifts the blocker, `real` keeps it until green, `ci-broken` triggers the fallback local run (`ci-broken` records `ci-infrastructure-broken`).
|
|
25
|
+
|
|
26
|
+
A composed line naming a `(not available: ...)` row is refused by name and the menu re-renders; the two `merge anyway` forms are the only overrides.
|
|
32
27
|
|
|
33
28
|
## Consent table
|
|
34
29
|
|
|
35
|
-
|
|
30
|
+
Authorship moves only `[recommended]`, never which rows are offered. The first row is `[recommended]`; a `(not available: ...)` row is skipped, so the first available row carries it; when every other row is `show evidence`, `stop` is `[recommended]`.
|
|
31
|
+
|
|
32
|
+
A `fixable` verdict with zero blockers (a withhold reason) uses the mergeable rows; `merge` renders `(not available: <withhold reason>)` - the overlay's reason when one applies, else the verdict's. On such a withhold, `[recommended]` goes to `wait` under the pending-reviewer or pending-required-check overlay, else to `propose ticket change` while an `impossible` row is `drafted`, else to `stop`.
|
|
36
33
|
|
|
37
|
-
| Author |
|
|
34
|
+
| Author | Verdict | Rows |
|
|
38
35
|
|---|---|---|
|
|
39
|
-
| you |
|
|
40
|
-
| you |
|
|
41
|
-
| someone else |
|
|
42
|
-
| someone else |
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
the reason. Approving your own PR is never offered. Nothing executes until explicit
|
|
52
|
-
selection. The fork, pending-reviewer, and CI-check overlays below modify the cell's rows; they are never a second offer source.
|
|
53
|
-
|
|
54
|
-
## Courses
|
|
55
|
-
|
|
56
|
-
A normative rendering of the consent table (never a second offer source): per
|
|
57
|
-
author x state cell, exactly one `[recommended]` course renders first, the custom
|
|
58
|
-
row renders last. Courses are atomic across pushes: no course, pre-composed or
|
|
59
|
-
custom, bundles a push-producing action (`fix`, `push-docs`) with `merge-*`; after
|
|
60
|
-
a fix wave the menu re-renders with merge as row 1 unless withheld (`reviewer still running` / `comments not refreshed`).
|
|
61
|
-
|
|
62
|
-
| Author | State | Courses (first = `[recommended]`) |
|
|
36
|
+
| you | mergeable | `merge`; `fix`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
|
|
37
|
+
| you | fixable | `fix`; `review`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
|
|
38
|
+
| someone else | mergeable | `approve`; `fix`; `merge`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
|
|
39
|
+
| someone else | fixable | `review`; `fix`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
|
|
40
|
+
|
|
41
|
+
`propose ticket change` joins any row set after the `fix` rows whenever an `impossible` row is `drafted`. `push` joins any row set after `fix` when unpushed fix commits sit in the worktree.
|
|
42
|
+
|
|
43
|
+
## Overlays
|
|
44
|
+
|
|
45
|
+
Overlays modify the consent row; they are never a second offer source. When two apply, the one higher in this table wins the `merge` reason and `[recommended]`.
|
|
46
|
+
|
|
47
|
+
| Overlay | Trigger | Effect |
|
|
63
48
|
|---|---|---|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
73
|
-
## Fork overlay
|
|
74
|
-
|
|
75
|
-
The consent-table fork row renders as an overlay on the authorship cells
|
|
76
|
-
(push/merge/fix absent; approve also dropped when the viewer authored the PR) - it
|
|
77
|
-
is not a distinct authorship cell. It overlays the applicable authorship cell (you
|
|
78
|
-
or someone else), removing `fix`, `push-docs`, and `merge-*` (never available on a
|
|
79
|
-
fork). When you authored the fork PR, `approve` is also dropped (never offered on
|
|
80
|
-
your own PR) - fork|you|clean renders `review-comment`/`stop` only; fork|you|blocking
|
|
81
|
-
renders `request-changes`/`review-comment`/`stop` (the someone-else courtesy
|
|
82
|
-
fix-on-their-branch course is also absent, since it is your own PR). A fork PR
|
|
83
|
-
authored by someone else uses the someone-else cells with `fix`/`push-docs`/
|
|
84
|
-
`merge-*` removed.
|
|
85
|
-
|
|
86
|
-
## Pending-reviewer overlay
|
|
87
|
-
|
|
88
|
-
While any `C#` row is `pending`, a reviewer run on the assessed head is
|
|
89
|
-
queued/in progress, or the last comment refetch failed
|
|
90
|
-
(`post-selection-loop.md` `### Re-render`), every pre-composed
|
|
91
|
-
`merge-squash` / `merge-commit` course renders listed-but-unavailable with
|
|
92
|
-
the reason: `reviewer still running` or `comments not refreshed`. This is a
|
|
93
|
-
menu-level gate modelled on the `flaky` disposition's custom-row path, never
|
|
94
|
-
a `## Verdict` precondition: `### Merge course` does not refuse the override.
|
|
95
|
-
Only the custom row's `merge-squash anyway` / `merge-commit anyway` executes
|
|
96
|
-
merge in that state, under the normal Merge course rules. Apply the comment-delta consent and incomplete-review rules in `post-selection-loop.md` `### Compare-and-swap` and `### Re-render`; `anyway` does not bypass an unreviewed delta or a blocking finding.
|
|
97
|
-
|
|
98
|
-
`wait` is `[recommended]` in cells whose recommended course would otherwise
|
|
99
|
-
be `merge-*` or `approve` (clean / follow-ups only, and the post-fix
|
|
100
|
-
re-render); in blocking cells the existing first course (`fix`,
|
|
101
|
-
`request-changes`) stays recommended and `wait` renders as row 2. Draft and
|
|
102
|
-
merged/closed cells do not offer `wait`. A `reviewer failed (<conclusion>)`
|
|
103
|
-
row changes nothing: the cell renders as it would without it.
|
|
104
|
-
|
|
105
|
-
The overlay applies on the initial assessment too: a PR gated while the
|
|
106
|
-
reviewer is mid-run withholds pre-composed merge from the first menu.
|
|
107
|
-
|
|
108
|
-
Precedence: when the CI-check gate below also applies, its rendering wins -
|
|
109
|
-
merge rows are absent and the CI-check gate line names both reasons.
|
|
110
|
-
|
|
111
|
-
## CI-check gate
|
|
112
|
-
|
|
113
|
-
An undispositioned failing check in the resolved set, or a pending required check,
|
|
114
|
-
withholds every pre-composed course containing `merge-*` (merge preconditions per
|
|
115
|
-
SKILL.md `## Verdict`) - none render, whatever the author/state cell says.
|
|
116
|
-
Disposition and pending-check definitions per `findings.md` `## Dispositions`.
|
|
117
|
-
|
|
118
|
-
| Disposition | Merge courses |
|
|
119
|
-
|---|---|
|
|
120
|
-
| Flaky | Not restored to a pre-composed course; merge proceeds only via the custom row naming the disposition explicitly |
|
|
121
|
-
| Real, or an unresolved pending check | Withheld until the check is green |
|
|
122
|
-
| CI-infrastructure-broken | Withheld until the triggered fallback run is green |
|
|
123
|
-
|
|
124
|
-
A pending-only render is not itself a blocking verdict (findings groups can all
|
|
125
|
-
read "None"); the recommended course falls to `stop` or `review-comment` in the
|
|
126
|
-
meantime. This never falls through to the clean cell's recommended `merge-squash` -
|
|
127
|
-
a failing resolved-set check or a pending required check means the PR is not in the
|
|
128
|
-
clean state to begin with.
|
|
49
|
+
| merged or closed PR | `state` is not `OPEN` | the report renders; the menu is `show evidence` and `stop` only |
|
|
50
|
+
| draft PR | `isDraft` | `merge` and `approve` render `(not available: draft)` and never carry `[recommended]`; `review` is recommended on someone else's fixable draft and `fix` on their mergeable draft; on your own, `fix` when a blocker exists, else `stop` |
|
|
51
|
+
| CI check | an undispositioned failing check in the resolved set, or a pending required check (`findings.md` `## Dispositions`) | on a failing check, the hint line offers `check <name> flaky \| real \| ci-broken`; `merge` renders `(not available: <check name> failing)`; `flaky` restores `merge` on the next render; `real` and `ci-infrastructure-broken` keep it withheld until green; a pending required check renders one `PR comments` line (`A required check is still pending, so merge waits. (<check name>)`), puts `wait` as row 1 and, when `Blockers` is empty, `[recommended]`, and renders `merge` `(not available: required check pending)`; it mints no disposition hint (not dispositionable) |
|
|
52
|
+
| pending reviewer | a `pending` ledger row, a queued or in-progress reviewer run on the assessed head, or a failed comment refetch (`post-selection-loop.md` `### Re-render`) | puts `wait` as row 1 and, when `Blockers` is empty, `[recommended]`; `merge` renders `(not available: reviewer still running)` or `(not available: comments not refreshed)`; a composed `anyway` (`merge anyway`) overrides only this overlay and does not bypass an unreviewed delta or a blocker; a `reviewer failed (<conclusion>)` row changes nothing |
|
|
53
|
+
| comment source review incomplete | the `### Re-render` step-4 source review of a comment delta did not finish (`post-selection-loop.md`) | one `PR comments` line `The comment source review did not finish, so merge waits. (<reason>)`; `merge` renders `(not available: comment source review incomplete)` with no `anyway` override; `reply` and `review` are dropped (the delta is unreviewed); `fix`, `show evidence`, `stop` stay; `stop` is `[recommended]` |
|
|
54
|
+
| impossible AC | an `impossible` row in `drafted` or `proposed` while every other merge prerequisite holds | `merge` renders `(not available: ticket change pending on AC<n>)`; `merge anyway - accept AC<n> as impossible` renders and lifts exactly that withhold - blockers, an unreviewed delta, pending checks, and GitHub-refused states stay in force |
|
|
55
|
+
| fork PR | `isCrossRepository` | `push` and `merge` render `(not available: fork)`; `fix` stays and applies to the local `pr-<N>` worktree, its consequence clause reading "open a PR from `pr-<N>`, or hand the patch to the author"; `approve` is dropped on your own fork PR |
|
|
56
|
+
| bot author | `author_is_bot` | the someone-else rows |
|
|
129
57
|
|
|
130
58
|
## Fixtures
|
|
131
59
|
|
|
132
|
-
|
|
133
|
-
render (merged/closed) - the menu still appears, carrying findings and `stop`.
|
|
60
|
+
Fixture 1 - own PR, fixable, one nit, one drafted ticket change, one drafted reply: the menu in `report.md` `## Worked example`.
|
|
134
61
|
|
|
135
|
-
|
|
136
|
-
doc drift, so uncommitted reviewed doc edits exist):
|
|
62
|
+
Fixture 2 - the re-render after fixture 1's `fix` pushed; the reviewer bot is mid-run on the new head:
|
|
137
63
|
|
|
138
|
-
```markdown
|
|
139
|
-
Pick one:
|
|
140
|
-
1. fix all (P1-P10) + push-docs [recommended]
|
|
141
|
-
2. push-docs (docs only, hold code fixes)
|
|
142
|
-
3. stop (leave as-is)
|
|
143
|
-
4. review-comment (post findings, act later)
|
|
144
|
-
5. Custom - compose: e.g. "fix P1-P8,P10 + push-docs" or "reply C1 + tracker comment"
|
|
145
64
|
```
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
65
|
+
Delivers: the reports page exports CSV on demand. The PR covers AC1-2 of gh-45; AC3
|
|
66
|
+
(export completes under 5s on production data) is checked after merge, not here.
|
|
67
|
+
|
|
68
|
+
Ticket changes:
|
|
69
|
+
- AC4 asks for the customer's credit score in the export, and the vendor API this
|
|
70
|
+
service reads returns no such field.
|
|
71
|
+
Proposed wording: "Exports include the customer's risk tier." (drafted; vendor doc api.example.com/v2/customers)
|
|
72
|
+
|
|
73
|
+
PR comments:
|
|
74
|
+
- maria's comment on the missing CSV header is already addressed, so the drafted reply points her at the fix. (3f2a1c0)
|
|
75
|
+
- The reviewer run is still in progress, so merge waits. (https://github.com/<owner>/<repo>/actions/runs/<run-id>)
|
|
76
|
+
|
|
77
|
+
Nits:
|
|
78
|
+
- The export pages results with its own loop instead of the shared paging helper, so a paging bug fixed once would need fixing twice. (src/api/export.ts:31, lib/page.ts)
|
|
79
|
+
|
|
80
|
+
Verdict: fixable - reviewer run in progress
|
|
81
|
+
|
|
82
|
+
1. wait - poll the reviewer run, then re-render [recommended]
|
|
83
|
+
2. merge - squash onto main (not available: reviewer still running)
|
|
84
|
+
3. fix - apply the nit payload in the worktree, re-run the gate, push
|
|
85
|
+
4. propose ticket change - show the AC4 edit for approval before it posts
|
|
86
|
+
5. reply - post the drafted reply to maria
|
|
87
|
+
6. show evidence - gate output, CI run
|
|
88
|
+
7. stop - leave the PR as-is
|
|
89
|
+
Type a number, or compose: "merge anyway", "fix nits".
|
|
164
90
|
```
|
|
165
91
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
reviewer check <name> failed - inert (reviewer failure never withholds)
|
|
172
|
-
|
|
173
|
-
## Comment-thread replies
|
|
174
|
-
C1. <thread ref> -> superseded by C3
|
|
175
|
-
C2. <thread ref> -> superseded by C4
|
|
176
|
-
C3. <thread ref> -> superseded by C5
|
|
177
|
-
C4. <thread ref> -> <drafted reply> (reasonable)
|
|
178
|
-
C5. <thread ref> -> reviewer failed (error) https://github.com/<owner>/<repo>/actions/runs/<run-id>
|
|
179
|
-
|
|
180
|
-
Pick one:
|
|
181
|
-
1. merge-squash [recommended]
|
|
182
|
-
2. merge-commit
|
|
183
|
-
3. stop (leave as-is)
|
|
184
|
-
4. review-comment
|
|
185
|
-
5. Custom
|
|
186
|
-
```
|
|
92
|
+
Fixture 3 - a different PR: your own, ticket fully covered, no nits, no drafted replies; the reviewer bot's run was the only withhold and `wait` just returned.
|
|
93
|
+
|
|
94
|
+
(a) The run concluded `failure`: the `PR comments` line disappears, the reviewer check is inert, the verdict is `mergeable - CI green on the assessed head (test)`, and the menu is `merge` [recommended], `fix`, `show evidence`, `stop`.
|
|
95
|
+
|
|
96
|
+
(b) The run concluded `success` and the verdict comment raises a retry bug; source review confirms it and mints a blocker:
|
|
187
97
|
|
|
188
|
-
(b) The run concluded `success`; the reviewer check moved from pending to
|
|
189
|
-
`success` in the refreshed rollup and the comment carries the verdict. Reconcile C5 against source at the assessed head. For a confirmed retry bug missed by the previous source review, mint source-backed P11 and withhold merge; C5's triage label remains verdict-neutral:
|
|
190
|
-
|
|
191
|
-
```markdown
|
|
192
|
-
## Findings (blocking)
|
|
193
|
-
Blocking findings (P#):
|
|
194
|
-
P11. **<source_ref>** - Retry attempts never increment. Fix: increment attempts on failure and throw after the retry limit. | Action: fix P11. [code]
|
|
195
|
-
## Comment-thread replies
|
|
196
|
-
C1. <thread ref> -> superseded by C3
|
|
197
|
-
C2. <thread ref> -> superseded by C4
|
|
198
|
-
C3. <thread ref> -> superseded by C5
|
|
199
|
-
C4. <thread ref> -> <drafted reply> (reasonable)
|
|
200
|
-
C5. <thread ref> -> <drafted reply> (reasonable)
|
|
201
|
-
Pick one:
|
|
202
|
-
1. fix P11 [recommended]
|
|
203
|
-
2. stop
|
|
204
|
-
3. review-comment
|
|
205
|
-
4. Custom
|
|
206
98
|
```
|
|
99
|
+
PR comments:
|
|
100
|
+
- The reviewer bot's retry concern holds up against the source, so the drafted reply confirms it. (src/retry.ts)
|
|
101
|
+
|
|
102
|
+
Blockers:
|
|
103
|
+
1. Retries never count up, so a failing call retries forever instead of giving up
|
|
104
|
+
after the limit. (src/retry.ts:41)
|
|
207
105
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
C5. <thread ref> -> <drafted reply> (judgment-call)
|
|
217
|
-
|
|
218
|
-
Pick one:
|
|
219
|
-
1. merge-squash [recommended]
|
|
220
|
-
2. merge-commit
|
|
221
|
-
3. stop (leave as-is)
|
|
222
|
-
4. review-comment
|
|
223
|
-
5. Custom
|
|
106
|
+
Verdict: fixable - 1 blocker
|
|
107
|
+
|
|
108
|
+
1. fix - apply the blocker in the worktree, re-run the gate, push [recommended]
|
|
109
|
+
2. review - post the blocker as a comment on your PR
|
|
110
|
+
3. reply - post the drafted reply
|
|
111
|
+
4. show evidence - gate output, CI run, drafted edit
|
|
112
|
+
5. stop - leave the PR as-is
|
|
113
|
+
Type a number, or compose: "fix 1 + reply".
|
|
224
114
|
```
|
|
225
115
|
|
|
226
|
-
|
|
116
|
+
When source review disproves the comment, no blocker is minted; the mergeable menu renders with `reply` for the drafted reply.
|
|
117
|
+
|
|
118
|
+
Fixture 4 - the pre-merge refetch finds a new human comment after a `merge` pick: the merge aborts even when the concern is false, the comment is reviewed against source, and the menu re-renders for a fresh pick. A same-head identical-body timestamp edit mints a ledger row but triggers no source review or test run.
|
|
@@ -1,120 +1,70 @@
|
|
|
1
|
-
# gatekeep-pr:
|
|
2
|
-
|
|
3
|
-
Read from SKILL.md
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
`F#` items carry an owner (pr-author | tracker | human) so follow-ups don't
|
|
51
|
-
evaporate; when no tracker tool resolved, the report itself is their durable
|
|
52
|
-
home.
|
|
53
|
-
|
|
54
|
-
IDs are append-only for the run's lifetime: minted at first assessment, never
|
|
55
|
-
renumbered, never reused. A resolved finding keeps its ID annotated
|
|
56
|
-
`(fixed in <sha>)`; later rounds continue each namespace's sequence.
|
|
57
|
-
|
|
58
|
-
Empty groups say "None".
|
|
59
|
-
|
|
60
|
-
## Triage
|
|
61
|
-
|
|
62
|
-
A finding lands in `P#` only when it must be fixed before merge (correctness,
|
|
63
|
-
security, material performance trap, a convention the repo enforces);
|
|
64
|
-
improvements that don't change merge correctness are `F#`, whatever their
|
|
65
|
-
category. `[quality]` and `[performance]` on a `P#` are categories, never a
|
|
66
|
-
downgrade - every `P#` blocks. This triage bar governs findings the
|
|
67
|
-
orchestrator originates itself; it never re-triages a classification Phase 4
|
|
68
|
-
already made (see Precedence in `## IDs`).
|
|
1
|
+
# gatekeep-pr: step 5 - integrate
|
|
2
|
+
|
|
3
|
+
Read from SKILL.md step 5, before `report.md`. Inputs: the digest, the step-2 AC rows, the step-3 evidence and claim dispositions, the step-4 reviewer output and comment ledger. Output: AC outcomes, blockers, nits, drafted payloads - the report's content, not its rendering.
|
|
4
|
+
|
|
5
|
+
## Provenance
|
|
6
|
+
|
|
7
|
+
Local evidence: `worktree_root` matches the provisioned path, every `run_cwd` sits inside it, `head_sha` matches the digest's `headRefOid`. On mismatch, re-fetch the PR head once and re-sync + re-run steps 3-4 when it advanced; a second mismatch, or any path mismatch, is missing evidence. The evidence clause names its source exactly: local -> `verification command passed locally`; CI -> `CI green on the assessed head (<check name>)`, never worded as a local run.
|
|
8
|
+
|
|
9
|
+
## AC outcomes
|
|
10
|
+
|
|
11
|
+
Inputs: the ticket AC rows (step 2), the source behind the diff at the assessed `headRefOid`, tests in the diff and existing tests the diff reaches, docs in the diff and docs the diff makes stale, CI per the brief's Evidence resolution table. PR body, PR comments, and a spec inside the PR are leads to verify, never evidence.
|
|
12
|
+
|
|
13
|
+
Split each AC row once into a **mechanism half** (code + test + doc that make the behavior possible) and, when the row names an observation that needs an environment, dataset, deployed target, or external system that repository tests cannot reach, an **observation half**. Behavior a unit test can assert ("retries three times then fails", "rejects a nil name") is mechanism, never an observation half. A `venue:` disposition in the PR's spec is a lead to compare against the ticket's own AC text, never proof and never an exemption. Judge the mechanism half only; the observation half is checked after merge, not here, and blocks nothing.
|
|
14
|
+
|
|
15
|
+
| Outcome | Condition | Renders as | Blocks |
|
|
16
|
+
|---|---|---|---|
|
|
17
|
+
| `covered` | evidence matches what the AC promises: executable behavior needs the code path plus a real test that exercises it; a documentation-only AC is judged against the promised doc text and demands no test; in both cases docs that describe the behavior agree with it | counted in `Delivers` | no |
|
|
18
|
+
| `gap` | any part of the mechanism absent in this PR | one `Blockers` item | yes - a mechanism `gap` is a blocker |
|
|
19
|
+
| `not judged here` | the observation half; the mechanism half of the same row is still judged `covered`/`gap` | one `Delivers` clause ("<row>'s observable half is checked after merge, not here"); nothing is written, listed, or handed to check-delivery | no |
|
|
20
|
+
| `impossible` | a `gap` whose fix is on the ticket - all four conditions below hold | one `Ticket changes` item with a drafted replacement AC text, in state `drafted` or `proposed` | withholds `merge` until the ticket body changes or the human picks `merge anyway - accept AC<n> as impossible` |
|
|
21
|
+
|
|
22
|
+
`impossible` requires all of: (1) no change to this repository can satisfy the mechanism half; (2) the constraint is cited - a vendor/platform doc URL, a dependency's released API at `file:line` or in its changelog, a repo policy at `file:line`, or a second AC in the same ticket whose quoted text contradicts this one; (3) the cited source was read this run; (4) the reason is none of: cost, effort, "needs another PR", "needs a deploy first" (that is `not judged here`), a `deviates:`/`deferred:` disposition in the PR's spec, "the AC is ambiguous" (an ambiguous row stays judged as written). Anything failing a condition is `gap`. Passes: the AC asks the export to include the customer's credit score and the vendor API the repository reads returns no such field (vendor doc URL cited). Fails: the AC asks for the user's local timezone and the browser sends no timezone header - a request parameter is a repository-side mechanism, so this is `gap`.
|
|
23
|
+
|
|
24
|
+
**Impossible-AC lifecycle.** Three states in order: `drafted` (the proposal exists in the run), `proposed` (`propose ticket change` posted it as a tracker comment; a comment is not an edit), `resolved` (a human edited the ticket body). Every step-5 re-entry re-fetches the ticket and re-extracts the AC rows; a changed row is re-judged on the current head, so a human edit to the ticket body lifts the withhold without a PR head change. `Ticket changes` keeps one item per unresolved row, labeled `drafted` or `proposed`, and drops it only after the re-extracted row no longer meets the four conditions.
|
|
25
|
+
|
|
26
|
+
**No ticket** (none linked, or fetch failed): no AC rows; `Delivers` states the PR's intent as read from its title and body; `not judged here`, `impossible`, `Ticket changes`, and scope creep do not apply.
|
|
27
|
+
|
|
28
|
+
**Whole or part.** With a ticket linked, `Delivers` names coverage: *whole* when every row is `covered` or is `not judged here` with its mechanism half `covered`; *part, acceptable* when every uncovered row is either an observation half or **explicitly split** - the ticket body or a human-authored ticket comment names another tracker ref for that row, read from the tracker this run. Only the tracker waives an obligation: a spec `deferred: <where>`, a linked later PR, or a `proposed` (not yet `resolved`) ticket change is a lead to check the tracker, never a waiver. Any other uncovered row is `gap`: "a later PR will add X" in the PR body, an unchecked box with no tracker split, a `deferred:` the ticket does not confirm.
|
|
29
|
+
|
|
30
|
+
**Claims.** The Verifier's three dispositions stand. `contradicted` is a blocker. `unverifiable-pre-merge` is not evidence and renders nothing: a PR whose only proof of a new path is "verified on stg" is blocked by the untested-path rubric row, not by a claim rule.
|
|
31
|
+
|
|
32
|
+
## Namespaces
|
|
33
|
+
|
|
34
|
+
Every finding is one of two:
|
|
35
|
+
|
|
36
|
+
| Namespace | Contents | Gates merge |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| blocker | code defects, security, untested new path, `contradicted` claim, AC `gap`, scope creep against a linked ticket (diff content traceable to no AC and no stated intent), doc drift beyond wording (a doc now describes behavior the code does not have, or omits an operation or parameter the code adds), failed gate or undispositioned failing check | yes |
|
|
39
|
+
| nit | wording-only doc drift (typo, label, phrasing with the same meaning), style, reuse of an existing helper, naming | no; take-or-leave at the menu; untracked after the run |
|
|
40
|
+
|
|
41
|
+
Behavior the ticket promises is a blocker or an explicit tracker split - never deferred to a PR nobody opened.
|
|
42
|
+
|
|
43
|
+
**Severity translation.** Reviewer Critical and Moderate -> blocker; Minor -> nit. A repo `REVIEW.md` mapping overrides this; a severity it names but does not map is fail-safe blocker, noted in `show evidence`.
|
|
44
|
+
|
|
45
|
+
**Triage bar** for findings the orchestrator originates itself: blocker only when it must be fixed before merge (correctness, security, a material performance trap, a convention the repo enforces); everything else is a nit, whatever its category. The bar never re-triages a classification the severity translation already made.
|
|
46
|
+
|
|
47
|
+
**Internal IDs.** `P#` (blocker or nit on code, a claim, a check), `L#` (AC `gap`, doc drift, scope creep), and the comment ledger's `C#` survive as keys for the post-push re-render diff and the fix wave; the human never sees them. IDs are append-only for the run: minted once, never renumbered, never reused. A fixed blocker leaves the rendered list on the next render; its ID stays in the ledger.
|
|
48
|
+
|
|
49
|
+
**`C#` ledger.** Each ledger row carries its comment `id` and the `updated_at` it was minted against; the post-push diff (`post-selection-loop.md` `### Re-render`) runs against this ledger, never against the report text. Row states: a triage label (`already-addressed` / `reasonable` / `judgment-call`) with a drafted reply; `superseded by C<new>`; `withdrawn`; `pending`; `reviewer failed (<conclusion>)`. The last four carry no reply and are not replyable; `reply` skips them.
|
|
69
50
|
|
|
70
51
|
## Dispositions
|
|
71
52
|
|
|
72
|
-
Any blocking conclusion in the resolved check set (required or not -
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
annotates the same ID rather than closing it outright.
|
|
91
|
-
|
|
92
|
-
| Disposition | Annotation on the `P#` | Counts against unfixed-blocker set | Merge course | Fallback local run |
|
|
93
|
-
|---|---|---|---|---|
|
|
94
|
-
| undispositioned failing check | none yet | yes | withheld from every pre-composed course | none |
|
|
95
|
-
| 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 |
|
|
96
|
-
| real | `(dispositioned: real)` | still counts - `P#` keeps blocking | withheld until the check is green | none |
|
|
97
|
-
| 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 |
|
|
98
|
-
| 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 |
|
|
99
|
-
| reviewer check failed (matches a `reviewer failed` `C#`) | mints no `P#`, is never dispositioned | not applicable - inert | not withheld; GitHub-enforced restrictions still apply | none |
|
|
100
|
-
|
|
101
|
-
A pending required check is wait-until-green, not dispositionable. While
|
|
102
|
-
pending, the report notes it under Evidence.
|
|
103
|
-
|
|
104
|
-
The evidence decision is independent of the merge decision: a green check
|
|
105
|
-
elsewhere in the resolved set still satisfies verification evidence while a
|
|
106
|
-
pending required check withholds merge. The CI-sufficient path changes no
|
|
107
|
-
consent surface: still read-only, no auto-merge, no posting, no menu change
|
|
108
|
-
beyond the third disposition.
|
|
109
|
-
|
|
110
|
-
## Payloads
|
|
111
|
-
|
|
112
|
-
"Drafted fixes / review" holds, per finding ID, the concrete edit (for
|
|
113
|
-
`fix`), the reviewed doc-drift edit (for `push-docs`, keyed to its `L#`), or
|
|
114
|
-
the reply text (for `reply`) - each keyed to its finding ID, one selection
|
|
115
|
-
mapping 1:1 to its payload.
|
|
116
|
-
|
|
117
|
-
A posted review body is not itself a finding: compose it at post time from
|
|
118
|
-
the ID'd `P#`/`L#` findings being addressed - one summary sentence, then the
|
|
119
|
-
numbered findings, ending on the fix or asked action - and give it its own
|
|
120
|
-
non-finding slot of this section.
|
|
53
|
+
Any blocking conclusion in the resolved check set (required or not - `../verification-brief.md` Section B, Evidence resolution table) withholds `merge` until the user dispositions it, and mints a `P#` - except the reviewer check, whose exception the brief's Section B defines (one `show evidence` line `reviewer check <name> failed - inert`). An undispositioned failing check is never a target of `fix`; close it by disposition. A pending required check mints nothing and is not dispositionable: merge waits until it turns green, or it converts to a failing check with its own `P#`.
|
|
54
|
+
|
|
55
|
+
| Disposition | Annotation on the `P#` |
|
|
56
|
+
|---|---|
|
|
57
|
+
| undispositioned failing check | none yet |
|
|
58
|
+
| flaky | `(dispositioned: flaky)` |
|
|
59
|
+
| real | `(dispositioned: real)` |
|
|
60
|
+
| CI-infrastructure-broken | `(dispositioned: ci-infrastructure-broken)` |
|
|
61
|
+
|
|
62
|
+
Only `flaky` lifts the blocker; an undispositioned check, `real`, and `ci-infrastructure-broken` keep it until the check - or, for `ci-infrastructure-broken`, the fallback local run (brief Section B, Failed CI row) - is green.
|
|
63
|
+
|
|
64
|
+
How each disposition changes the menu: `decision-menu.md` `## Overlays`, CI check row.
|
|
65
|
+
|
|
66
|
+
## Drafted payloads
|
|
67
|
+
|
|
68
|
+
Step 5 drafts, never applies. For every blocker and nit with a file-level fix - code and doc drift alike - draft the concrete edit as a payload keyed to the finding's internal ID. For every `impossible` row, draft the replacement AC text. For every replyable `C#`, draft the reply. The worktree stays tracked-clean (`git status --porcelain --untracked-files=no` empty) at every menu render; a payload is applied only on a `fix` pick (the same path for code and docs) and dropped at teardown otherwise.
|
|
69
|
+
|
|
70
|
+
A posted review body is composed at post time from the blockers being addressed - one summary sentence, then the numbered items, ending on the fix or asked action.
|