pi-gauntlet 6.2.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +10 -10
- package/package.json +1 -1
- package/skills/brainstorming/SKILL.md +28 -170
- package/skills/brainstorming/gatherer.md +3 -2
- package/skills/brainstorming/reference/amendment-surface.md +9 -3
- package/skills/brainstorming/reference/documentation-impact.md +4 -2
- package/skills/brainstorming/reference/spec-finalization.md +128 -0
- package/skills/brainstorming/reference/ticket-acceptance.md +18 -0
- package/skills/chase-bug/SKILL.md +2 -2
- package/skills/check-delivery/SKILL.md +6 -0
- package/skills/gatekeep-pr/SKILL.md +43 -181
- package/skills/gatekeep-pr/reference/assessment.md +53 -106
- package/skills/gatekeep-pr/reference/decision-menu.md +97 -205
- package/skills/gatekeep-pr/reference/findings.md +67 -117
- package/skills/gatekeep-pr/reference/post-selection-loop.md +38 -27
- package/skills/gatekeep-pr/reference/report.md +96 -0
- package/skills/gatekeep-pr/review-baseline.md +6 -5
- package/skills/gatekeep-pr/verification-brief.md +20 -55
- package/skills/gauntlet-resume/SKILL.md +2 -2
- package/skills/gauntlet-resume/reference/reconstruction.md +6 -3
- package/skills/writing-plans/SKILL.md +1 -1
|
@@ -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.
|
|
@@ -1,59 +1,70 @@
|
|
|
1
|
-
# gatekeep-pr:
|
|
1
|
+
# gatekeep-pr: step 7 - loop
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Read from SKILL.md step 7. Execute only the selected pick, then re-enter: a fix wave's own push re-enters step 4; any other head move re-enters step 3; an unchanged head re-enters step 5. Loop until `merge` or `stop`. Merge preconditions, the output done-check, and teardown live here.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### Merge preconditions
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
All must hold before `merge` executes; a `merge` pick while one fails is refused naming it, and the menu re-renders:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- every blocker fixed and pushed, or dispositioned `flaky` by the user; no `impossible` row in `drafted` or `proposed` unless the pick is `merge anyway - accept AC<n> as impossible`
|
|
10
|
+
- verification evidence present for the assessed head per the brief's Evidence resolution table - a CI claim or a green local run; a table-sanctioned CI skip is evidence, and `not run` blocks only when the table required a fallback run that did not happen
|
|
11
|
+
- evidence provenance clean (`findings.md` `## Provenance`): `worktree_root`, every `run_cwd`, and `head_sha` match on the local path
|
|
12
|
+
- `mergeable == MERGEABLE` (`UNKNOWN` after step 2's single re-poll withholds like `CONFLICTING`)
|
|
13
|
+
- no undispositioned failing check in the resolved set, no pending required check
|
|
14
|
+
- no retained, unreviewed comment delta (`### Re-render` step 4)
|
|
15
|
+
- worktree tracked-clean and synced with the remote head (fixes pushed first)
|
|
16
|
+
- the compare-and-swap below passes
|
|
10
17
|
|
|
11
|
-
###
|
|
18
|
+
### Compare-and-swap
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
Before every external write, re-fetch `headRefOid`, `state`, and `mergeable`. Any change since assessment invalidates the current state - re-sync the worktree, re-enter step 3, and re-render the menu. Exception: a pick's own push updates the assessed head to the pushed SHA as part of that pick's execution - this self-inflicted head move does not invalidate the pick; the next compare-and-swap runs against the new head on the next external write. Before a merge executes (plain or `anyway`), run the full comment refetch and reconciliation (`### Re-render` steps 1-5), not just placeholder detection. If the head changed, re-enter step 3 instead. A new or changed-body delta since the consent render aborts the selected merge, plain or `anyway`: show the reconciled report and request a fresh pick even when no blocker resulted. A newly `pending` row, a queued/in-progress reviewer run, or a failed refetch (`comments not refreshed (<reason>)`) refuses a plain merge and re-renders; `anyway` overrides only those existing pending/refetch-failure overlays and prints what it overrode, never a new blocker or unreviewed delta.
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
### Fix wave
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
For a `fix` pick, take the drafted payloads (`findings.md` `## Drafted payloads`) for the named blockers - all open blockers by default, the nit payloads when no blocker is open; `fix nits` takes nit payloads only, `fix + nits` both. A finding closed by disposition is skipped. A finding whose payload touches no file (a failing check, a claim with no drafted edit) is reported as not fixable by this verb and stays open.
|
|
18
25
|
|
|
19
|
-
|
|
26
|
+
Batch payloads by the union of files each touches; payloads that share a file share a batch. At two payloads or fewer, apply inline. Past that, dispatch `implementer` children with `subagent({ agent: "implementer", context: "fresh", cwd: <PR worktree> })`, one per batch, in parallel when more than one batch results; each child is edit-only (no git commands, no verification runs) and applies the consented payload rather than re-solving the finding; `worktree: true` is forbidden (`assessment.md` `## Inline first; dispatch when pi-cohort is present`). The orchestrator owns commit, verification, and push.
|
|
20
27
|
|
|
21
|
-
Once every
|
|
28
|
+
Once every batch returns, commit as one local commit set (one commit, or one per batch; subjects name the fixes, doc and code alike). Run the verification pass once at the resulting SHA - one verification pass per wave, never per fix or per batch; this is the retained contract. On green, push once; the evidence is now current for the pushed head, so the loop re-enters step 4 after its own push (claim re-check, comment refresh, review of the delta), never step 3. On red, do not push: leave the commits local, re-render with the blockers still open, and say that unpushed fix commits sit in the worktree (`### Teardown`). On a fork PR, `push` is not available: commit locally, report the branch name, and re-enter step 5.
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
Execute `review`, `reply`, `approve`, and `propose ticket change` via `gh pr review`, `gh api`, `gh issue comment`, or the resolved tracker tool, non-interactively, with the drafted payload - after the output done-check below.
|
|
24
31
|
|
|
25
32
|
### Merge course
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
`merge` executes as `gh pr merge --match-head-commit <assessed-sha>` with the resolved merge policy. Push and merge are never one pick.
|
|
28
35
|
|
|
29
36
|
### Re-render
|
|
30
37
|
|
|
31
|
-
After every push or any mutation that can change readiness (fix wave pushed,
|
|
38
|
+
After every push or any mutation that can change readiness (fix wave pushed, PR head moved), re-run the claim-check and the review on the synced worktree: claims are re-checked against the new head and findings re-rendered without a second verification pass - the wave's single pass already covered this head; a blocker confirmed resolved leaves the rendered list while its internal ID stays in the ledger; new findings continue each sequence. Then refetch comments - the last read before the menu renders:
|
|
32
39
|
|
|
33
40
|
1. Re-run the Section A comment fetches (`../verification-brief.md`: both `--paginate` calls, plus the GraphQL `reviewThreads` query when the initial gather used it), one `gh run view` per placeholder row, and the reviewer-run `gh run list` when a reviewer workflow is known. Read-only.
|
|
34
|
-
2. Diff the fresh set against the `C#` ledger (`findings.md` `##
|
|
41
|
+
2. Diff the fresh set against the `C#` ledger (`findings.md` `## Namespaces`) by `id` and `updated_at`:
|
|
35
42
|
- same `id`, same `updated_at` -> unchanged: keep the existing `C#`.
|
|
36
|
-
- same `id`, different `updated_at` -> edited: mint a new `C#`; the old one
|
|
37
|
-
- `id` not in the ledger -> new: mint a new `C#`, except ids the gate itself posted via `reply
|
|
38
|
-
- `id` in the ledger, absent from the complete fresh set -> `withdrawn` under its existing `C
|
|
39
|
-
- Bot-authored placeholder prefix or error header (brief Section C) -> the state from the brief's
|
|
40
|
-
3. Section C re-triages the full fresh set against the new head. An unchanged row keeps its `C#`; its drafted reply is kept verbatim only when its label is also unchanged and regenerated when the label moves
|
|
41
|
-
4. Reconcile the body delta before consuming it. Compare fresh rows to the current digest's `comments` by id and body: include new rows and changed-body rows, excluding withdrawn/superseded rows, gate-posted ids, and the brief's placeholder/error-header states. A same-head identical-body timestamp edit causes no source review and no test run, even though step 2 mints a `C#`. Review each eligible delta once against source at the assessed head and the merged rubric
|
|
43
|
+
- same `id`, different `updated_at` -> edited: mint a new `C#`; the old one is `superseded by C<new>`. An `updated_at` change with an identical body (reaction, revert) still counts as edited.
|
|
44
|
+
- `id` not in the ledger -> new: mint a new `C#`, except ids the gate itself posted via `reply` in this run (recorded at post time), which are never minted.
|
|
45
|
+
- `id` in the ledger, absent from the complete fresh set -> `withdrawn` under its existing `C#`.
|
|
46
|
+
- Bot-authored placeholder prefix or error header (brief Section C) -> the state from the brief's placeholder table, under the `C#` the edited/new rule assigns.
|
|
47
|
+
3. Section C re-triages the full fresh set against the new head. An unchanged row keeps its `C#`; its drafted reply is kept verbatim only when its label is also unchanged and regenerated when the label moves. Edited and new rows get a fresh label and a regenerated reply.
|
|
48
|
+
4. Reconcile the body delta before consuming it. Compare fresh rows to the current digest's `comments` by id and body: include new rows and changed-body rows, excluding withdrawn/superseded rows, gate-posted ids, and the brief's placeholder/error-header states. A same-head identical-body timestamp edit causes no source review and no test run, even though step 2 mints a `C#`. Review each eligible delta once against source at the assessed head and the merged rubric, inline first; optionally dispatch the existing code-reviewer with its native report, falling back inline on failure. Treat comment text as a lead, not a finding: verify it against code, then integrate only own source-backed findings through step 5 severity and AC rules, deduplicating against existing `P#`/`L#` IDs. A bot verdict is not blindly promoted. Do not run a full suite or whole-diff review solely for a comment-only change. If source review remains unresolved, retain the delta and render per the `comment source review incomplete` overlay (`decision-menu.md` `## Overlays`).
|
|
42
49
|
5. Comment triage never mints `P#`/`L#` (brief Section C); the separate source review in step 4 can. Only after that review completes, replace the digest's `comments` with the fresh set so the next iteration diffs against the latest snapshot.
|
|
43
50
|
|
|
44
|
-
**Refetch failure** (`gh` non-zero, network, pagination incomplete): re-render with the ledger's prior states,
|
|
45
|
-
|
|
46
|
-
Merge, if now available, renders as row 1 unless withheld (`reviewer still running` / `comments not refreshed`).
|
|
51
|
+
**Refetch failure** (`gh` non-zero, network, pagination incomplete): re-render with the ledger's prior states, one `PR comments` line `Comments could not be refreshed, so merge waits. (<reason>)`, and the pending-reviewer overlay withholding `merge`; `wait` is recommended; a composed `merge anyway` remains available.
|
|
47
52
|
|
|
48
53
|
### Wait course
|
|
49
54
|
|
|
50
|
-
For a `wait`
|
|
55
|
+
For a `wait` pick, run a sequence of short bounded calls - never one long bash call. Each iteration: `gh run view -R <repo> <run-id> --json status,conclusion` for every tracked run (placeholder-linked and head-listed), and `gh pr view <N> -R <repo> --json statusCheckRollup` when a required check is pending; when any row has no parsable URL, or its run is completed while the prefix persists, one comment refetch as well; then sleep 30 s. Use each polling refetch only to observe run/placeholder state; leave the digest and `C#` ledger untouched until the completion/timeout reconciliation below. Check the deadline between iterations: the resolved `timeout minutes` (default 15, the same knob as the local verification run). Stop when every tracked run is completed and no required check is pending and no row is in the "completed `success`, prefix persists" state, or the deadline passes.
|
|
56
|
+
|
|
57
|
+
Then re-fetch `statusCheckRollup`, `headRefOid`, `state`, `mergeable`. If the head advanced or state/mergeability changed, route through compare-and-swap re-assessment before reusing evidence or reviewing comments; otherwise re-resolve the brief's Evidence table on the fresh rollup; run the verification command only when the re-resolved table selects the Fallback row and no evidence exists yet for this head - otherwise the existing evidence stands. On completion or timeout, run the refetch (steps 1-5 above) and re-render; do not re-run claim-check or whole-diff review solely because the head did not move. On timeout: rows in the completed-`success`/prefix-persists state become `reviewer failed (stale placeholder)` (brief Section C placeholder table); every other `pending` row stays `pending`, merge stays withheld, `wait` renders as row 1 again.
|
|
51
58
|
|
|
52
|
-
|
|
59
|
+
### Output done-check
|
|
60
|
+
|
|
61
|
+
Before posting or committing any external payload - review bodies, replies, commit subjects, tracker comments - re-read it against SKILL.md `## Wording rules` and any `## comms style` rules: ASCII only; no headings or template scaffolding under ~150 words; findings `file:line`-specific where one exists; ends on the fix or asked action, not a recap; never invents content to fill a section.
|
|
53
62
|
|
|
54
63
|
### Teardown
|
|
55
64
|
|
|
56
65
|
| | Created worktree | Reused worktree |
|
|
57
66
|
|---|---|---|
|
|
58
67
|
| Merge success | tear down | tear down (the sync precondition guarantees no local-only work is stranded, and the branch is gone remotely) |
|
|
59
|
-
| Non-merge stop | offer teardown, never autonomous;
|
|
68
|
+
| Non-merge stop | offer teardown, never autonomous; say when unpushed fix commits would be discarded | leave as found; say so explicitly when unpushed fix commits remain, and let the user choose leave-or-discard |
|
|
69
|
+
|
|
70
|
+
Drafted payloads that were never applied are dropped with the run; the worktree was never dirtied by them.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# gatekeep-pr: step 5 - report
|
|
2
|
+
|
|
3
|
+
Read from SKILL.md step 5, after `findings.md`. Input: the integration output. Output: the rendered report, then the menu (`decision-menu.md`). SKILL.md `## Wording rules` bind every line.
|
|
4
|
+
|
|
5
|
+
## Order
|
|
6
|
+
|
|
7
|
+
Render bottom-up for a terminal: least important first, verdict and menu last. Empty sections are omitted - never "None". A failed comment refresh, an incomplete comment source review (`post-selection-loop.md` `### Re-render`), or a pending required check renders its one line under `PR comments` as well.
|
|
8
|
+
|
|
9
|
+
Section order is fixed:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Delivers: <one or two sentences: what the PR does; with a ticket: "The PR covers the whole <ref>." |
|
|
13
|
+
"The PR covers AC1-2 of <ref>; AC3's observable half (<what>) is checked after merge, not here." |
|
|
14
|
+
"The PR covers AC1 of <ref>; AC2 belongs to <split ref>.">
|
|
15
|
+
|
|
16
|
+
Ticket changes: (one item per unresolved `impossible` row)
|
|
17
|
+
- AC<n> asks for <X>, and <cited constraint>. Proposed wording: "<new AC text>". (drafted | proposed <comment url>; <source>)
|
|
18
|
+
|
|
19
|
+
PR comments: (replyable review comments, a pending reviewer run or required check, a failed refresh, or an incomplete source review - see the paragraph above)
|
|
20
|
+
- <reviewer>'s comment on <topic> <verdict clause>, so the drafted reply <what it says>. (<locator>)
|
|
21
|
+
- The reviewer run is still in progress, so merge waits. (<run url>)
|
|
22
|
+
- A required check is still pending, so merge waits. (<check name>)
|
|
23
|
+
|
|
24
|
+
Nits:
|
|
25
|
+
- <1-2 sentences>. (<file:line>)
|
|
26
|
+
|
|
27
|
+
Blockers: (numbered; menu picks reference these numbers)
|
|
28
|
+
1. <1-2 sentences: what is wrong, why it matters>. (<file:line> | <check name> | <doc path>)
|
|
29
|
+
|
|
30
|
+
Verdict: mergeable - <evidence clause> | fixable - <N> blockers | fixable - <withhold reason>
|
|
31
|
+
|
|
32
|
+
<menu>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Verdict
|
|
36
|
+
|
|
37
|
+
Two states: `mergeable` or `fixable`. `mergeable` carries the evidence clause from `findings.md` `## Provenance`: `CI green on the assessed head (<check name>)` or `verification command passed locally`. `fixable - <N> blockers` when `Blockers` is non-empty; `fixable - <withhold reason>` when it is empty but a merge prerequisite is unmet: `ticket change pending on AC<n>` (for example `ticket change pending on AC4`), `reviewer run in progress`, `required check pending`, `failed gate` (listed for spec parity; a red gate mints a blocker per `findings.md` `## Namespaces`, so `Blockers` is non-empty), `comments not refreshed`, `comment source review incomplete`, `verification not run` (the command needed credentials or no command resolved, with nothing else blocking), `mergeable unknown`, `merge conflict` (for `mergeable == CONFLICTING`), `verification evidence pending` (brief Section B Pending row: zero `success`, a check still pending).
|
|
38
|
+
|
|
39
|
+
`<N> blockers` reads `1 blocker` for one.
|
|
40
|
+
|
|
41
|
+
## What stays out
|
|
42
|
+
|
|
43
|
+
Verbatim command output, CI run URLs and conclusions (the pending-reviewer locator in `PR comments` is the one URL that prints in the report), drafted edits, drafted replies, matched claims, covered ACs, internal IDs, and disposition annotations print only under the `show evidence` pick. A clean run with a linked ticket renders `Delivers`, the verdict line, and the menu - about four lines.
|
|
44
|
+
|
|
45
|
+
`show evidence` prints, in this order: the evidence record (CI: each satisfying check's name, conclusion, SHA, run URL; local: each run's command and its captured tail, fenced, labeled as captured output); claim dispositions; AC outcomes per row; check dispositions; drafted payloads keyed by the blocker or nit number they fix; drafted replies keyed by the `PR comments` item they answer.
|
|
46
|
+
|
|
47
|
+
## Worked example
|
|
48
|
+
|
|
49
|
+
Own PR, ticket gh-45:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
Delivers: the reports page exports CSV on demand. The PR covers AC1-2 of gh-45; AC3
|
|
53
|
+
(export completes under 5s on production data) is checked after merge, not here.
|
|
54
|
+
|
|
55
|
+
Ticket changes:
|
|
56
|
+
- AC4 asks for the customer's credit score in the export, and the vendor API this
|
|
57
|
+
service reads returns no such field.
|
|
58
|
+
Proposed wording: "Exports include the customer's risk tier." (drafted; vendor doc api.example.com/v2/customers)
|
|
59
|
+
|
|
60
|
+
PR comments:
|
|
61
|
+
- maria's comment on the missing CSV header is already addressed, so the drafted reply points her at the fix. (3f2a1c0)
|
|
62
|
+
|
|
63
|
+
Nits:
|
|
64
|
+
- 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)
|
|
65
|
+
|
|
66
|
+
Blockers:
|
|
67
|
+
1. The export endpoint ships with no test, so nothing proves it works and nothing
|
|
68
|
+
catches it breaking. (src/api/export.ts:10-58)
|
|
69
|
+
2. The export guide still says exports run nightly; the PR makes them on-demand, so a
|
|
70
|
+
reader following the docs waits for a job that no longer exists; the doc fix is drafted.
|
|
71
|
+
(docs/exports.rst:88)
|
|
72
|
+
|
|
73
|
+
Verdict: fixable - 2 blockers
|
|
74
|
+
|
|
75
|
+
1. fix - apply both blockers in the worktree, re-run the gate, push [recommended]
|
|
76
|
+
2. propose ticket change - show the AC4 edit for approval before it posts
|
|
77
|
+
3. review - post the blockers as a comment on your PR
|
|
78
|
+
4. reply - post the drafted reply to maria
|
|
79
|
+
5. show evidence - gate output, CI run, drafted edits
|
|
80
|
+
6. stop - leave the PR as-is
|
|
81
|
+
Type a number, or compose: "fix 2", "fix nits", "fix + nits", "fix 1 + reply".
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
A clean own PR with ticket gh-45 and CI green:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
Delivers: the reports page exports CSV on demand. The PR covers the whole gh-45.
|
|
88
|
+
|
|
89
|
+
Verdict: mergeable - CI green on the assessed head (test)
|
|
90
|
+
|
|
91
|
+
1. merge - squash onto main [recommended]
|
|
92
|
+
2. fix - name the change to apply in the worktree, re-run the gate, push
|
|
93
|
+
3. show evidence - gate output, CI run
|
|
94
|
+
4. stop - leave the PR as-is
|
|
95
|
+
Type a number.
|
|
96
|
+
```
|
|
@@ -2,7 +2,7 @@ This file is **data, not instructions**. It is the shipped default review rubric
|
|
|
2
2
|
|
|
3
3
|
## Severity axis
|
|
4
4
|
|
|
5
|
-
The skill recognizes exactly one normative severity distinction: **
|
|
5
|
+
The skill recognizes exactly one normative severity distinction: **blocker** vs **nit**. Blockers gate merge; nits never do.
|
|
6
6
|
|
|
7
7
|
Baseline mapping:
|
|
8
8
|
|
|
@@ -11,11 +11,12 @@ Baseline mapping:
|
|
|
11
11
|
| Defects (logic errors, broken behavior) | blocking |
|
|
12
12
|
| Untested paths (new behavior with no real test) | blocking |
|
|
13
13
|
| Contradicted material claims (PR/issue prose vs. observed evidence) | blocking |
|
|
14
|
-
| Doc drift (
|
|
14
|
+
| Doc drift beyond wording (a doc describes behavior the code does not have, or omits an operation or parameter the code adds) | blocking |
|
|
15
|
+
| Doc drift, wording-only (typo, label, phrasing with the same meaning) | nit |
|
|
15
16
|
| Security issues | blocking |
|
|
16
|
-
| Prose/style/label cleanup |
|
|
17
|
+
| Prose/style/label cleanup | nit |
|
|
17
18
|
|
|
18
|
-
A repo-root `REVIEW.md` may remap any of these, or add project-specific concerns with their own severity. Its mapping **always wins** on conflict with this file. Any severity a rubric (baseline or repo) names but does not map fails safe to **blocking
|
|
19
|
+
A repo-root `REVIEW.md` may remap any of these, or add project-specific concerns with their own severity. Its mapping **always wins** on conflict with this file. Any severity a rubric (baseline or repo) names but does not map fails safe to **blocking**; "blocking" and "blocker" name the same class, "non-blocking" and "nit" the other.
|
|
19
20
|
|
|
20
21
|
## Review properties
|
|
21
22
|
|
|
@@ -28,7 +29,7 @@ Generic properties evaluated on every reviewed change, independent of language o
|
|
|
28
29
|
| Conventions | Matches the style and structure of neighboring code, not just internal consistency |
|
|
29
30
|
| Reuse | Uses existing helpers/utilities instead of re-implementing equivalent logic |
|
|
30
31
|
| Performance | No N+1 queries, no repeated expensive work inside loops, no unbounded fetches |
|
|
31
|
-
| Testing | Tests cover behavior, not implementation details; assertions are real (they can fail); a new code path shipped without a real test is **blocking
|
|
32
|
+
| Testing | Tests cover behavior, not implementation details; assertions are real (they can fail); a new executable code path shipped without a real test is **blocking**; a documentation-only obligation is judged against the promised doc text |
|
|
32
33
|
| Docs | Documentation agrees with the code it describes and with the PR/issue prose describing the change |
|
|
33
34
|
| Security | No secrets in the diff, no missing authorization checks, no injection vectors |
|
|
34
35
|
|