pi-gauntlet 7.42.0 → 7.43.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 +6 -0
- package/README.md +8 -6
- package/package.json +1 -1
- package/skills/gatekeep-pr/SKILL.md +3 -3
- package/skills/gatekeep-pr/reference/batch.md +3 -1
- package/skills/gatekeep-pr/reference/post-selection-loop.md +1 -1
- package/skills/gatekeep-pr/reference/report.md +8 -2
- package/skills/gatekeep-pr/verification-brief.md +28 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v7.43.0 - 2026-10-30
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `/skill:gatekeep-pr` with no PR argument gates the viewer's open PR queue: it lists the origin repository's open PRs the viewer authored or is requested to review (drafts and PRs already approved or with changes requested excluded), sorts them by diff size, routes one match through the single-PR path and two to `parallel.maxTasks` through set routing, and stops with a `discovered, smallest first:` line over the cap or on Claude Code with two or more. Discovery stops with a `discovery failed:` line on a non-zero `gh pr list`, malformed output, or a query that fills `--limit 1000`, and never falls back to the current branch's PR. Every report carries a `Role:` line under `Delivers` naming the viewer's relationship to the PR (`author`, `requested reviewer`, `none`, or `unreadable`, with requested reviewers listed), refreshed with merge state before each render. (#104)
|
|
8
|
+
|
|
3
9
|
## v7.42.0 - 2026-10-30
|
|
4
10
|
|
|
5
11
|
### Changed
|
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ One finish choice spans all legs. PR, draft PR and squash deliver companions in
|
|
|
87
87
|
|
|
88
88
|
## Architecture
|
|
89
89
|
|
|
90
|
-
`gatekeep-pr` selects one course per run: `assess` posts open blockers as one review (`request-changes` on someone else's PR, `comment` on your own), posts nothing with zero blockers, and performs no repair or sync; `deliver` repairs blockers, syncs, pushes, watches CI, and re-reviews until readiness, an obstacle, or a cap exit. `deliver with nits` stores `deliver-nits` and includes current and later nits. A ready first report skips the course pick and renders the final menu directly. Delivery rebases your own non-bot branch with `--force-with-lease` unless its history contains merge commits; someone else's, bot-authored, and merge-containing heads merge base instead. Final `merge` and `approve` remain separate picks; approval is offered only on someone else's non-draft PR with zero blockers. See the [course loop](skills/gatekeep-pr/reference/post-selection-loop.md) and [menu templates](skills/gatekeep-pr/reference/menus.md). In pi, `/skill:gatekeep-pr 12 15 18 [--rebase [base]]` gates a set of PR numbers or same-repository URLs, with one fresh `pr-gatekeeper` child and one worktree per PR. The parent shows a summary and unchanged per-PR menus in input order, queues every pick until the last menu, then executes the queued work in parallel. The set must fit pi-cohort's `parallel.maxTasks` (default `8`); it is never chunked. With `--rebase`, the parent asks once per set for eligible other-author or unreadable-author heads, excluding no-op heads and heads with merge commits. Multi-PR mode rejects positional issue references and is pi-only
|
|
90
|
+
`gatekeep-pr` selects one course per run: `assess` posts open blockers as one review (`request-changes` on someone else's PR, `comment` on your own), posts nothing with zero blockers, and performs no repair or sync; `deliver` repairs blockers, syncs, pushes, watches CI, and re-reviews until readiness, an obstacle, or a cap exit. `deliver with nits` stores `deliver-nits` and includes current and later nits. A ready first report skips the course pick and renders the final menu directly. Delivery rebases your own non-bot branch with `--force-with-lease` unless its history contains merge commits; someone else's, bot-authored, and merge-containing heads merge base instead. Final `merge` and `approve` remain separate picks; approval is offered only on someone else's non-draft PR with zero blockers. See the [course loop](skills/gatekeep-pr/reference/post-selection-loop.md) and [menu templates](skills/gatekeep-pr/reference/menus.md). In pi, `/skill:gatekeep-pr 12 15 18 [--rebase [base]]` gates a set of PR numbers or same-repository URLs, with one fresh `pr-gatekeeper` child and one worktree per PR. The parent shows a summary and unchanged per-PR menus in input order, queues every pick until the last menu, then executes the queued work in parallel. The set must fit pi-cohort's `parallel.maxTasks` (default `8`); it is never chunked. With `--rebase`, the parent asks once per set for eligible other-author or unreadable-author heads, excluding no-op heads and heads with merge commits. Multi-PR mode rejects positional issue references and is pi-only. An explicit no-argument invocation on either harness discovers your open PRs in origin, authored by you or directly awaiting your review (not team requests), excludes drafts and the `APPROVED` and `CHANGES_REQUESTED` states, and sorts by additions plus deletions, then PR number, ascending. One match gates directly on the single-PR path; multiple matches enter pi's batch path, while Claude Code stops with the sorted `discovered, smallest first:` list. Every report shows the refreshed viewer `Role:` under `Delivers`, not in the batch summary row. See the [parent-child contract](skills/gatekeep-pr/reference/batch.md).
|
|
91
91
|
|
|
92
92
|
The course, target/scope baseline, repair and sync usage, and poll deadline live in one OS temporary continuation record, whose path appears in the tracker or checklist and `show evidence`. Gatekeep initializes independent repair-round and sync budgets to `2 x closureReview.maxFixRounds` (default `5`, no-tool fallback `2 x 5`). Only source-changing repair waves spend rounds; conflict-only syncs spend the separate sync budget, and description-only work, watches, and re-reviews spend neither. Obstacle `deliver` extends each cap by `2 x` the resolved value without resetting usage; a timeout continuation instead opens one more watch window without extending caps. Only the gate's own push automatically renews the CI window (`timeout minutes`, default `15`). The verify-phase runtime guard still uses `1 x` the resolved value and can block a gatekeep dispatch earlier.
|
|
93
93
|
|
|
@@ -95,7 +95,7 @@ Non-final `stop` removes an eligible tracked-clean, non-primary worktree, create
|
|
|
95
95
|
|
|
96
96
|
pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
|
|
97
97
|
|
|
98
|
-
- **21 skills** - the workflow logic. Sixteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates one tracker issue or repairs a comma/whitespace list of refs against a Context/Problem/Idea/Acceptance-Criteria template, with a grounded repo audit, an AC integrity check, a cheap council roast, and sequential per-ticket exact-diff write confirmations; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes), `gatekeep-pr` (model-invocable on an explicit ask that names the PR and the verb; the gates still need your selection - is consent-gated pre-merge verification of a PR against the scope contract at its head - the approved spec's acceptance-criteria dispositions and Design when the PR carries one, else the PR's stated intent; the ticket is cross-checked, never judged here (`check-delivery` owns it) - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; a pending commit status that GitHub does not report as blocking the gating actor (`mergeStateStatus` not `BLOCKED`) is not waited for - external-CI commit statuses included - while a running Actions check, an unknown merge state, and every other merge precondition still withhold; the project's verification command runs only as fallback), a rubric-based review, a compact bottom-up report (what the PR delivers, including rows deferred or deviating per spec, PR comments, nits, blockers, then a `mergeable` / `fixable` verdict) and course and terminal menus whose rows derive from the actor's permissions on the PR; nothing mutates (repairs, pushes, reviews, merges, tracker comments) until you pick a course or terminal row, except the opt-in `--rebase [base]` sync that rebases, reviews, and lease-pushes the head before verification, or holds the rebased head locally when a conflict stop's scoped tests fail, so a selected delivery course resolves it before the lease push; after your own merge two opt-in rows post the `AC coverage` block to the ticket or the PR; own-merge, approved, and closed-PR menus offer a recommended `cleanup` row that tears down the gate's worktree and branch and runs the overrides file's `## cleanup` steps - run it with `/skill:gatekeep-pr <pr> [--rebase [base]]`), `check-delivery` (model-invocable on an explicit ask that names the ticket and the verb; the gates still need your selection - is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`), `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `loop-implementation` (the plan-free implement driver that iterates a fresh `loop-implementer` over the spec's acceptance-criteria ledger when approval picks the loop engine), `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `forge-skill`, `linear` (reads/searches/comments on/manages Linear tickets via the `linearis` CLI; owns all linearis mechanics and the `## Issue tracker` overrides schema; tracker-facing skills route to it). Five more require explicit entry (`disable-model-invocation: true`): `brainstorming` starts the gated workflow on explicit consent - use `/skill:brainstorming` for reliable discovery, or opt in through reachable explicit prose or a human-selected handoff; after spec approval, downstream planning and implementation still chain automatically. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/hotfix/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage; the hotfix row hands off to `skills/chase-bug/hotfix.md` after the menu - run it with `/skill:chase-bug`. `gauntlet-performance` reads the committed run telemetry (current repo by default, `--dir <path>` adds others) through the parse-only `gauntlet-performance` CLI and answers with one example-led recommendation, 3-5 cornerstone numbers, a council assessment when available, and a menu of at most three actions (render a report file, open the recommendation as a ticket via `shape-ticket`, drill into one run); it writes nothing unless you pick render - run it with `/skill:gauntlet-performance [--dir <path>]... [--since <version>]`. `gauntlet-handoff` ends a session whose flow a fresh session will continue: it invokes pi-cohort's `handoff` skill (`--out <path>` or `--key <name>`, default key = the run worktree's branch with `/` flattened to `-`, default file `<tmpdir>/pi-handoff/<key>.md`), then appends the gauntlet process-state section (phase/plan tracker status) per the shared contract `skills/gauntlet-resume/reference/brief-contract.md` - run it with `/skill:gauntlet-handoff [--out <path> | --key <name>]`. `gauntlet-resume` is the only way back into an interrupted flow from a fresh session: it takes a `gauntlet-handoff` brief (a file path, pasted text, or - with no arguments - a pick from the briefs under `<tmpdir>/pi-handoff/`), a bare worktree that already holds a spec, or a spec tracked on main under a configured spec dir (a spec seed: it creates or reuses the worktree through `using-git-worktrees` and pins the spec), restores phase/plan tracker state through the legal arming sequence (`start brainstorm`, `skip` with `resume:` reasons, `plan_check` before implement-or-later), and never infers approval from artifacts - run it with `/skill:gauntlet-resume [<brief-file> | <spec>.md | <worktree-name-or-path>]`.
|
|
98
|
+
- **21 skills** - the workflow logic. Sixteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates one tracker issue or repairs a comma/whitespace list of refs against a Context/Problem/Idea/Acceptance-Criteria template, with a grounded repo audit, an AC integrity check, a cheap council roast, and sequential per-ticket exact-diff write confirmations; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes), `gatekeep-pr` (model-invocable on an explicit ask that names the PR and the verb; the gates still need your selection - is consent-gated pre-merge verification of a PR against the scope contract at its head - the approved spec's acceptance-criteria dispositions and Design when the PR carries one, else the PR's stated intent; the ticket is cross-checked, never judged here (`check-delivery` owns it) - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; a pending commit status that GitHub does not report as blocking the gating actor (`mergeStateStatus` not `BLOCKED`) is not waited for - external-CI commit statuses included - while a running Actions check, an unknown merge state, and every other merge precondition still withhold; the project's verification command runs only as fallback), a rubric-based review, a compact bottom-up report (what the PR delivers, including rows deferred or deviating per spec, PR comments, nits, blockers, then a `mergeable` / `fixable` verdict) and course and terminal menus whose rows derive from the actor's permissions on the PR; nothing mutates (repairs, pushes, reviews, merges, tracker comments) until you pick a course or terminal row, except the opt-in `--rebase [base]` sync that rebases, reviews, and lease-pushes the head before verification, or holds the rebased head locally when a conflict stop's scoped tests fail, so a selected delivery course resolves it before the lease push; after your own merge two opt-in rows post the `AC coverage` block to the ticket or the PR; own-merge, approved, and closed-PR menus offer a recommended `cleanup` row that tears down the gate's worktree and branch and runs the overrides file's `## cleanup` steps - run it with `/skill:gatekeep-pr [<pr>] [--rebase [base]]` (no argument: your open PRs)), `check-delivery` (model-invocable on an explicit ask that names the ticket and the verb; the gates still need your selection - is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`), `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `loop-implementation` (the plan-free implement driver that iterates a fresh `loop-implementer` over the spec's acceptance-criteria ledger when approval picks the loop engine), `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `forge-skill`, `linear` (reads/searches/comments on/manages Linear tickets via the `linearis` CLI; owns all linearis mechanics and the `## Issue tracker` overrides schema; tracker-facing skills route to it). Five more require explicit entry (`disable-model-invocation: true`): `brainstorming` starts the gated workflow on explicit consent - use `/skill:brainstorming` for reliable discovery, or opt in through reachable explicit prose or a human-selected handoff; after spec approval, downstream planning and implementation still chain automatically. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/hotfix/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage; the hotfix row hands off to `skills/chase-bug/hotfix.md` after the menu - run it with `/skill:chase-bug`. `gauntlet-performance` reads the committed run telemetry (current repo by default, `--dir <path>` adds others) through the parse-only `gauntlet-performance` CLI and answers with one example-led recommendation, 3-5 cornerstone numbers, a council assessment when available, and a menu of at most three actions (render a report file, open the recommendation as a ticket via `shape-ticket`, drill into one run); it writes nothing unless you pick render - run it with `/skill:gauntlet-performance [--dir <path>]... [--since <version>]`. `gauntlet-handoff` ends a session whose flow a fresh session will continue: it invokes pi-cohort's `handoff` skill (`--out <path>` or `--key <name>`, default key = the run worktree's branch with `/` flattened to `-`, default file `<tmpdir>/pi-handoff/<key>.md`), then appends the gauntlet process-state section (phase/plan tracker status) per the shared contract `skills/gauntlet-resume/reference/brief-contract.md` - run it with `/skill:gauntlet-handoff [--out <path> | --key <name>]`. `gauntlet-resume` is the only way back into an interrupted flow from a fresh session: it takes a `gauntlet-handoff` brief (a file path, pasted text, or - with no arguments - a pick from the briefs under `<tmpdir>/pi-handoff/`), a bare worktree that already holds a spec, or a spec tracked on main under a configured spec dir (a spec seed: it creates or reuses the worktree through `using-git-worktrees` and pins the spec), restores phase/plan tracker state through the legal arming sequence (`start brainstorm`, `skip` with `resume:` reasons, `plan_check` before implement-or-later), and never infers approval from artifacts - run it with `/skill:gauntlet-resume [<brief-file> | <spec>.md | <worktree-name-or-path>]`.
|
|
99
99
|
- **11 subagent personas** - the specialized child agents the skills dispatch via pi-cohort: `implementer`, `loop-implementer`, `code-reviewer`, `spec-reviewer`, `conformance-reviewer`, `spec-summarizer`, `plan-writer`, `spec-council-member`, `spec-council-synthesizer`, `spec-council-applier`, `pr-gatekeeper`. See [doc/personas.md](./doc/personas.md) for what each one does and why its permissions are scoped the way they are.
|
|
100
100
|
- **4 runtime extensions** - the enforcement layer. `plan-tracker` and `phase-tracker` are tools skills call to track progress (with a TUI widget); `verify-before-ship` is a hook that warns if you push or open a PR without a passing test run since your last edit; a phase-tracker flow guard reminds on implement-phase commits missing spec/code review. In a brainstorming-entered flow, phase-tracker rejects `implement` or `verify` completion while tracker tasks remain pending or in progress; see [its configuration reference](./doc/configuration.md#phase-tracker). phase-tracker also registers `plan_check`, which verifies a plan against its spec and against the grammar in [skills/writing-plans/reference/plan-contract.md](./skills/writing-plans/reference/plan-contract.md), including that each task's `Tests:` commands are selective and never the full suite, and that every test command carries a passing base-commit result; a pass stamps the plan and spec content hashes for implementation and returns a bounded task manifest; see the [manifest contract and size limit](./doc/configuration.md#phase-tracker). `telemetry` records one YAML record per gauntlet run (phase timing, models, personas, gate/fix rounds, diff at ship) that ships in the squash beside the spec - it is written only inside a brainstorming-entered flow, kept out of history until `finishing-a-development-branch` seals it once with `gauntlet-telemetry-seal` (a `telemetry:` commit under git; the working-copy snapshot in a plain jj workspace) - and blocks a brainstorm `write` into an already-shipped spec; see [its configuration reference](./doc/configuration.md#telemetry). See [doc/configuration.md](./doc/configuration.md) for the settings each one reads.
|
|
101
101
|
|
|
@@ -306,10 +306,12 @@ instead of the GitHub source. Stop before tracker writes.
|
|
|
306
306
|
activates, reads the reference file, reaches its tracker capability ladder
|
|
307
307
|
without erroring on missing pi tools. Stop at the first human gate; write
|
|
308
308
|
nothing to any tracker.
|
|
309
|
-
7. Invoke `/gauntlet:gatekeep-pr` in the scratch repo
|
|
310
|
-
Expected: the skill
|
|
311
|
-
|
|
312
|
-
|
|
309
|
+
7. Invoke `/gauntlet:gatekeep-pr` in the scratch repo.
|
|
310
|
+
Expected with no GitHub origin: the skill stops before provisioning with
|
|
311
|
+
`discovery failed: origin is not a GitHub repository`. With a GitHub origin
|
|
312
|
+
and no matching PR, expect `no open PRs authored by <login> or awaiting <login>'s review in <owner/repo>`
|
|
313
|
+
naming origin (`@me` when the viewer login is unreadable). Neither outcome
|
|
314
|
+
reports missing pi tools or mutates the repo.
|
|
313
315
|
8. Invoke `/gauntlet:check-delivery` with no deliverable reference. Expected:
|
|
314
316
|
the skill activates and asks for / reports a missing deliverable set - a
|
|
315
317
|
reported skip, not a pass, and no pi-tool error.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gatekeep-pr
|
|
3
3
|
description: Use only when explicitly asked to gatekeep, verify, or gate a named pull request before it merges - or on pi a set of them - ("gatekeep PR 123", "gatekeep PRs 123 124 125", a loop task naming the PR and the verb); post-merge delivery proof belongs to /skill:check-delivery.
|
|
4
|
-
argument-hint: "<pr> [issue-ref] [--rebase [base]] | <pr> <pr>... [--rebase [base]] (e.g. 123, 123 gh-45, 123 --rebase, 123 gh-45 --rebase release/2, 123 124 125 on pi only)"
|
|
4
|
+
argument-hint: "[no argument: my open PRs] | <pr> [issue-ref] [--rebase [base]] | <pr> <pr>... [--rebase [base]] (e.g. 123, 123 gh-45, 123 --rebase, 123 gh-45 --rebase release/2, 123 124 125 on pi only)"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# gatekeep-pr
|
|
@@ -10,8 +10,8 @@ Verify, don't trust: a PR description is a claim, and over-claimed coverage, hal
|
|
|
10
10
|
|
|
11
11
|
## Arguments
|
|
12
12
|
|
|
13
|
-
- Route two or more PR tokens (numbers or URLs, space-separated, before any `--rebase`) through the set-routing row before steps 1-7; reject a positional issue reference in a set with a one-line error. Apply `--rebase [base]` to every PR in the set; keep
|
|
14
|
-
- PR number or URL; omitted ->
|
|
13
|
+
- Route two or more PR tokens (numbers or URLs, space-separated, before any `--rebase`) through the set-routing row before steps 1-7; reject a positional issue reference in a set with a one-line error. Apply `--rebase [base]` to every PR in the set; keep one PR token on the single-PR path below; zero tokens discover per verification-brief.md Section A before this row runs and re-enter it with the discovered roster when the roster holds two or more; a trailing comma on a PR token is stripped before identity normalization, so a pasted discovered, smallest first: list is a valid set.
|
|
14
|
+
- PR number or URL; omitted -> discovered per verification-brief.md Section A during argument resolution (my open PRs in origin: authored or directly requested, no drafts or decided PRs, smallest first); one match gates on this path, two or more re-enter the set-routing row on pi and stop with the discovered list on Claude Code.
|
|
15
15
|
- Optional issue reference; omitted -> resolved in step 1 (`verification-brief.md` Section A) and fetched in step 2; none found -> select the scope contract in step 2 (spec at the head, else the PR's stated intent), never invent acceptance criteria.
|
|
16
16
|
- Optional `--rebase [base]`, parsed after `<pr> [issue-ref]`: the token after it, when present, is the base branch name (`123 --rebase gh-45` means base `gh-45`, not an issue ref); absent, the base is the digest's `baseRefName`. Step 2b fetches `origin/<base>` and validates it: a missing ref stops with a one-line error before any rebase or push. Without `--rebase` the run performs no additional fetch, rebase, or push before a menu pick and renders no sync line.
|
|
17
17
|
|
|
@@ -4,12 +4,14 @@ Use this contract only for two or more PR tokens. Keep the single-PR path and it
|
|
|
4
4
|
|
|
5
5
|
## Admit before effects
|
|
6
6
|
|
|
7
|
-
Reject with a one-line error before any fetch, confirmation, provisioning, or dispatch: positional issue references, duplicate identities (normalize number and URL to the same repository/number), URLs from different repositories or not matching origin, an oversized set, and Claude Code.
|
|
7
|
+
Reject with a one-line error before any fetch, confirmation, provisioning, or dispatch: positional issue references, duplicate identities (normalize number and URL to the same repository/number), URLs from different repositories or not matching origin, an oversized set, and Claude Code. For Claude Code print exactly: `multi-PR mode requires pi's nested dispatch`. Resolve each issue from its PR, never from a positional issue argument.
|
|
8
8
|
|
|
9
9
|
Read the active pi-cohort configuration's `parallel.maxTasks`, default `8`; gauntlet_setting is not its source. Never chunk the set. For an oversized set print exactly:
|
|
10
10
|
|
|
11
11
|
`multi-PR mode takes at most <max> PRs (pi-cohort parallel.maxTasks); got <n>`
|
|
12
12
|
|
|
13
|
+
For `source: discovered`, append exactly one `discovered, smallest first: <numbers comma-separated>` line after either cap or harness rejection, in supplied sorted order; for example after cap 4 got 6: `discovered, smallest first: 101, 97, 112, 88, 130, 104`. Print no discovered list for explicit sets. Preserve supplied token order through provisioning, summary rows, and queued menus; never trim.
|
|
14
|
+
|
|
13
15
|
Gather each PR with `gh pr view --json number,author,headRefOid,headRefName,baseRefName,isCrossRepository,headRepository,state,files`. Resolve trusted worktree configuration from the base merge-base, never from PR-controlled files.
|
|
14
16
|
|
|
15
17
|
## Provision serially
|
|
@@ -169,7 +169,7 @@ After every push or any mutation that can change readiness (fix wave pushed, PR
|
|
|
169
169
|
|
|
170
170
|
### Pre-menu refresh
|
|
171
171
|
|
|
172
|
-
Refresh read-only before step 5, first report included, and at each Re-render. Run one `gh pr view <N> --json headRefOid,state,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,body,baseRefName,number,title,author,isDraft,headRefName,isCrossRepository,files,additions,deletions,commits,reviews,closingIssuesReferences,headRepository,maintainerCanModify,url,mergeCommit` and one `gh run list -R <owner>/<repo> -c <headRefOid> --json databaseId,status,conclusion,workflowName,url`. Fold `gh pr view <N> --json headRefOid,body,baseRefName` into that read. Apply target/body freshness from Next action. While locally rewritten under a loop checkpoint compare remote to `repair.wave.sync.expected_remote_head`; preserve that expectation on mismatch and recover to `repair.wave.sync.pre_head` through Sync's restore/assert obstacle. An entry rewrite without a loop checkpoint keeps its own pre_head for comparison and recovery. An unmoved remote retains local-head source: pending until lease push; preserve the loop checkpoint through this read and any local-head assessment. On other head moves re-enter step 3. On an unchanged head replace merge state, reviewDecision, status_checks and
|
|
172
|
+
Refresh read-only before step 5, first report included, and at each Re-render. Run one `gh pr view <N> --json headRefOid,state,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,body,baseRefName,number,title,author,isDraft,headRefName,isCrossRepository,files,additions,deletions,commits,reviews,closingIssuesReferences,headRepository,maintainerCanModify,url,mergeCommit,reviewRequests` and one `gh run list -R <owner>/<repo> -c <headRefOid> --json databaseId,status,conclusion,workflowName,url`. Fold `gh pr view <N> --json headRefOid,body,baseRefName` into that read. Apply target/body freshness from Next action. While locally rewritten under a loop checkpoint compare remote to `repair.wave.sync.expected_remote_head`; preserve that expectation on mismatch and recover to `repair.wave.sync.pre_head` through Sync's restore/assert obstacle. An entry rewrite without a loop checkpoint keeps its own pre_head for comparison and recovery. An unmoved remote retains local-head source: pending until lease push; preserve the loop checkpoint through this read and any local-head assessment. On other head moves re-enter step 3. On an unchanged head replace merge state, reviewDecision, status_checks, actions_runs, and pr.review_requests together and re-derive `viewer.role` per Section A; reclassify via the brief's binding rule and re-resolve the Evidence resolution table. Pending to CI-sufficient dispatches a fresh helper in claim-check-only mode with a disposition for every material claim.
|
|
173
173
|
|
|
174
174
|
A failed refresh retains prior values, classifies every pending check as binding, records `merge state not refreshed (<reason>)`, retries once then exits through Exit check. This read never mints `C#` rows and never starts an independent watch. A failing resolved check mints one P# with its failing line from `gh run view <id> -R <repo> --log-failed` and drafted payload; apply the repeated-red/source-repair rule. An action_required run goes through Exit check.
|
|
175
175
|
|
|
@@ -18,6 +18,8 @@ Delivers: <one sentence: what the PR does. With source: spec, a second sentence
|
|
|
18
18
|
order ("3, 5 deferred per spec to <ref>"); deviating rows ("2 deviates per spec: <why>"); elsewhere rows grouped by repo ("6 elsewhere per spec: <repo>");
|
|
19
19
|
observation halves ("4's observable half (<what>) is checked after merge, not here").>
|
|
20
20
|
|
|
21
|
+
Role: <author | requested reviewer | none | unreadable>
|
|
22
|
+
|
|
21
23
|
PR comments: (replyable review comments, a pending reviewer run, a blocked or unknown merge state, a binding pending check, a failed refresh, or an incomplete source review - see the paragraph above)
|
|
22
24
|
- <reviewer>'s comment on <topic> <verdict clause>, so the drafted reply <what it says>. (<locator>)
|
|
23
25
|
- The reviewer run is still in progress, so merge waits. (<run url>)
|
|
@@ -39,7 +41,9 @@ Verdict: mergeable - <evidence clause> | fixable - <N> blockers | not ready - <w
|
|
|
39
41
|
<menu>
|
|
40
42
|
```
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
Print exactly one `Role:` directly under `Delivers` on every report from the refreshed `viewer.role` and `pr.review_requests`; append `(also requested: <entries>)` for requested reviewer, `(requested: <entries>)` otherwise, omitted when `<entries>` is empty. `<entries>`: the User and Team entries other than the viewer, API order (Keep API order, exclude the viewer by case-insensitive User login comparison, exclude nobody when the login is unreadable), User as login, Team as `slug`; render missing login/slug as `unknown`. Example: `Role: requested reviewer (also requested: robin, acme/reviewers)`.
|
|
45
|
+
|
|
46
|
+
Render `Sync:` only when `--rebase` was passed. Open the `Sync:` line with the digest's `sync` field value verbatim (for example `Sync: declined - other author's branch`). Put any explanation after that value as a second clause or sentence. Never paraphrase the status value into prose. Exempt `Sync:` and `Role:` from SKILL.md wording rule 5 (passing facts only under `show evidence`): name the resolved files even when the sync succeeded.
|
|
43
47
|
|
|
44
48
|
For obstacle reports, print exactly one `Evidence:` line naming the resolved evidence source and the assessed head, immediately before the verdict (for example `Evidence: CI (run 7001, test_unit and build_image green on 9c1e4f2)`). Use the resolved local verification summary instead when local evidence owns the assessment; do not invent a passing result when evidence is unavailable. Carry the same source summary into the obstacle menu's evidence hint. Exempt this compact source summary and the final template's `Evidence:` line from the evidence-only rules below and SKILL.md wording rule 5; keep the full record under `show evidence`.
|
|
45
49
|
|
|
@@ -51,7 +55,7 @@ For ordinary assessments, use `mergeable`, `fixable`, or `not ready`. Carry the
|
|
|
51
55
|
|
|
52
56
|
## What stays out
|
|
53
57
|
|
|
54
|
-
Verbatim command output stays in its `log_path` file and never prints; `show evidence` prints its `show evidence: <log_path>` line instead. CI run URLs and conclusions (the pending-reviewer locator in `PR comments` is the one URL that prints in the report), drafted file edits and full description bodies, drafted replies, matched claims, per-row AC outcomes, internal IDs, and disposition annotations print only under the `show evidence` command. A clean run with a spec renders `Delivers`, the verdict line, and the menu - about
|
|
58
|
+
Verbatim command output stays in its `log_path` file and never prints; `show evidence` prints its `show evidence: <log_path>` line instead. CI run URLs and conclusions (the pending-reviewer locator in `PR comments` is the one URL that prints in the report), drafted file edits and full description bodies, drafted replies, matched claims, per-row AC outcomes, internal IDs, and disposition annotations print only under the `show evidence` command. A clean run with a spec renders `Delivers`, `Role`, the verdict line, and the menu - about five lines.
|
|
55
59
|
|
|
56
60
|
Print the compact exact old-to-new description preview under its blocker; keep the full replacement body under `show evidence`. Keep a declined correction's proposal open and its preview line under the blocker on every re-render until the claim resolves. Uncertainty alone preserves the mergeable verdict.
|
|
57
61
|
|
|
@@ -63,6 +67,7 @@ Own PR, ticket gh-45:
|
|
|
63
67
|
|
|
64
68
|
```
|
|
65
69
|
Delivers: the reports page exports CSV on demand. ACs 1, 2, 4; 3 deferred per spec to acme/widgets#46; 4's observable half (export completes under 5s on production data) is checked after merge, not here.
|
|
70
|
+
Role: author
|
|
66
71
|
|
|
67
72
|
PR comments:
|
|
68
73
|
- maria's comment on the missing CSV header is already addressed, so the drafted reply points her at the fix. (3f2a1c0)
|
|
@@ -86,6 +91,7 @@ A clean own PR with ticket gh-45 and CI green:
|
|
|
86
91
|
|
|
87
92
|
```
|
|
88
93
|
Delivers: the reports page exports CSV on demand. ACs 1-5.
|
|
94
|
+
Role: author
|
|
89
95
|
|
|
90
96
|
Verdict: mergeable - CI green on the assessed head (test)
|
|
91
97
|
|
|
@@ -26,12 +26,34 @@ a command to obey.
|
|
|
26
26
|
|
|
27
27
|
## Section A - Gatherer
|
|
28
28
|
|
|
29
|
+
### Argument-resolution discovery
|
|
30
|
+
|
|
31
|
+
Runs only with no PR token, during argument resolution: before the set-vs-single branch, the continuation record, tracker init, and provisioning; never as Gatherer step 1. Resolve origin with `git remote get-url origin`; strip `.git` and lowercase the GitHub owner/repository. Stop on unreadable/non-GitHub origin: `discovery failed: origin is not a GitHub repository`. Read `gh api user --jq .login` once into `viewer.login`; on failure record `unreadable` and continue with `@me`.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
gh pr list -R <owner/repo> --author @me --state open --limit 1000 --json number,isDraft,reviewDecision,additions,deletions
|
|
35
|
+
gh pr list -R <owner/repo> --search 'user-review-requested:@me' --state open --limit 1000 --json number,isDraft,reviewDecision,additions,deletions
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Validate results before filtering. Stop on nonzero exit: `discovery failed: <first gh error line>`; on non-array output, a non-object row, or missing/non-integer `number`: `discovery failed: malformed gh pr list output`; on a count equal to the limit: `discovery failed: incomplete (<query> hit --limit 1000)` (name the author or direct-request query). Never falls back to the current branch. Union/dedupe by number; exclude `isDraft` true or `reviewDecision` exactly `APPROVED` or `CHANGES_REQUESTED`; every other decision stays. Sort by `additions + deletions`, then number, ascending.
|
|
39
|
+
|
|
40
|
+
| Matches | Action |
|
|
41
|
+
|---|---|
|
|
42
|
+
| 0 | Stop: `no open PRs authored by <login> or awaiting <login>'s review in <owner/repo>`; substitute `@me` for unreadable login. |
|
|
43
|
+
| 1 | Continue single-PR with origin token `https://github.com/<owner/repo>/pull/<N>`. |
|
|
44
|
+
| 2+ pi | Re-enter set routing with sorted origin URL tokens, `source: discovered`. |
|
|
45
|
+
| 2+ Claude Code | Print `multi-PR mode requires pi's nested dispatch`, then exactly one `discovered, smallest first: <numbers comma-separated>` line; stop. |
|
|
46
|
+
|
|
47
|
+
Origin URL tokens keep the repository identity through admission and gh pr view regardless of GH_REPO or gh repo set-default; user-review-requested:@me is direct-only, so team requests never enter the roster.
|
|
48
|
+
|
|
49
|
+
### Gather fixed commands
|
|
50
|
+
|
|
29
51
|
Read-only. Fixed `gh` command set - do not substitute ad hoc queries:
|
|
30
52
|
|
|
31
53
|
```bash
|
|
32
|
-
gh pr view <N> --json number,title,body,author,state,isDraft,headRefName,baseRefName,isCrossRepository,mergeable,headRefOid,statusCheckRollup,files,additions,deletions,commits,reviews,closingIssuesReferences,reviewDecision,headRepository,maintainerCanModify,mergeStateStatus,url,mergeCommit
|
|
54
|
+
gh pr view <N> --json number,title,body,author,state,isDraft,headRefName,baseRefName,isCrossRepository,mergeable,headRefOid,statusCheckRollup,files,additions,deletions,commits,reviews,closingIssuesReferences,reviewDecision,headRepository,maintainerCanModify,mergeStateStatus,url,mergeCommit,reviewRequests
|
|
33
55
|
gh run list -R <owner>/<repo> -c <headRefOid> --json databaseId,status,conclusion,workflowName,url # Actions runs on the assessed head: held-run detection (action_required with or without a rollup entry)
|
|
34
|
-
gh api user --jq .login #
|
|
56
|
+
gh api user --jq .login # viewer.login; a no-token run reuses discovery's value, unreadable included
|
|
35
57
|
gh api graphql -f query='query($o:String!,$r:String!,$n:Int!){ repository(owner:$o,name:$r){ viewerPermission pullRequest(number:$n){ viewerCanUpdateBranch } } }' -f o=<owner> -f r=<repo> -F n=<N> # viewer_permission, can_update_branch; a null field is recorded as `unreadable`
|
|
36
58
|
gh repo view <base-repository> --json nameWithOwner # resolved base repository context, never headRepository
|
|
37
59
|
gh pr diff <N>
|
|
@@ -52,7 +74,7 @@ the paginated calls complete. A comment fetch whose pagination fails part-way
|
|
|
52
74
|
is a refetch failure (`reference/post-selection-loop.md` `### Re-render`),
|
|
53
75
|
never a partial digest.
|
|
54
76
|
|
|
55
|
-
|
|
77
|
+
Issue reference: the explicit argument, else `closingIssuesReferences`, then the branch name, PR title, PR body, and commit subjects; none found -> `issue_ref: null`. The Gatherer only resolves the reference - fetching the ticket is step 2 (`reference/assessment.md` `## Fetch the ticket`), after the issue-fetch command resolves from the merge-base.
|
|
56
78
|
|
|
57
79
|
`mergeable` is reported as-is, including `UNKNOWN` - the Gatherer runs before
|
|
58
80
|
provisioning, so it never re-reads; step 2 re-reads once after provisioning (`reference/assessment.md`). Bot author noted
|
|
@@ -75,7 +97,8 @@ provisioning, so it never re-reads; step 2 re-reads once after provisioning (`re
|
|
|
75
97
|
- repair.wave: null | { pre_wave_head, pushed_head, selected_ids, selected_payloads, sync: null | { pre_head, expected_remote_head }, action: fix-nits?, affected_claims, round_start_head, counted: false | true, counted_head, checkpoint_history: [], stage: apply | review | push, no_progress: { failed_prerequisite, observed_value, result_path }? }
|
|
76
98
|
- approved_head: null | <sha> # set by reference/post-selection-loop.md when gh pr review --approve exits 0; selects the approved template
|
|
77
99
|
- cleanup_done: false | true # set by reference/cleanup.md after the cleanup pick runs
|
|
78
|
-
-
|
|
100
|
+
- pr.review_requests: [ { __typename: User, login } | { __typename: Team, name, slug } ] # raw reviewRequests entries
|
|
101
|
+
- viewer: { login, is_author, role }
|
|
79
102
|
- permissions: { viewer_permission, is_cross_repository, maintainer_can_modify, merge_state_status, can_update_branch, head_url, head_ref, head_pushable } # head_pushable is set in step 2 after provisioning (reference/assessment.md); merge_state_status is `BLOCKED`, `BEHIND`, `UNKNOWN`, `unreadable` (null), or any other GitHub value (`CLEAN`, `UNSTABLE`, `HAS_HOOKS`, `DIRTY`) and is written only from a `gh pr view` invocation that names `mergeStateStatus` (this call, the step-2 re-read, the step-2b re-gather (`reference/sync.md`), the pre-menu refresh before and after the single watch, compare-and-swap), never from an ad hoc GraphQL query or `gh pr list`, and never from a reply carrying `errors`; any field that cannot be read is the literal `unreadable`; menu availability derives from this block (reference/decision-menu.md ## Availability)
|
|
80
103
|
- status_checks: [ { name, kind, status, conclusion, required, url, workflowName } ] # kind: check_run | status_context | unreadable, from the rollup entry's __typename; evidence semantics: Section B Evidence resolution; workflowName from the CheckRun rollup entry (absent on StatusContext)
|
|
81
104
|
- actions_runs: [ { databaseId, status, conclusion, workflowName, url } ] # from the fixed gh run list call on the assessed head
|
|
@@ -97,7 +120,7 @@ and top-level comment ids, so a thread's inline comments are diffed once, as
|
|
|
97
120
|
inline comments.
|
|
98
121
|
|
|
99
122
|
`viewer_is_author` lives at `viewer.is_author` in the digest, computed as
|
|
100
|
-
`viewer.login == pr.author.login`. Each `status_checks` entry's `url` is the CheckRun `detailsUrl` / StatusContext
|
|
123
|
+
`viewer.login == pr.author.login`. Derive viewer.role: unreadable when viewer.login is unreadable; else author when is_author; else requested reviewer when a pending User reviewRequests entry's login equals viewer.login case-insensitively; else none. Pending reviewRequests only, never reviews history; approve availability keeps is_author. Each `status_checks` entry's `url` is the CheckRun `detailsUrl` / StatusContext
|
|
101
124
|
`targetUrl` already present in the fetched payload; when the payload omits it,
|
|
102
125
|
downstream CI claims record `url: unavailable` - absence never disqualifies the
|
|
103
126
|
check. GraphQL enums are case-folded; a StatusContext's `state` maps per Section B's Conclusion semantics. Missing `required` is
|