pi-gauntlet 7.7.0 → 7.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## v7.7.2 - 2026-10-08
4
+
5
+ ### Changed
6
+
7
+ - `gatekeep-pr`: `fix` applies open blockers only; nits move behind a `fix nits` verb whose payloads are drafted at the pick, and the report counts open nits. Each fix helper gets a scoped test command resolved from the merge-base overrides or `AGENTS.md`, never the verification command. The pre-push review lists only the wave's own findings; the next round carries open closure lines, in-delta Critical/Moderate, and outside-delta Critical findings.
8
+
9
+ ## v7.7.1 - 2026-10-07
10
+
11
+ ### Changed
12
+
13
+ - **shape-ticket: model invocation allowed; tracker writes still require the explicit confirmation gate.** `disable-model-invocation: true` is gone from `skills/shape-ticket/SKILL.md`, so another skill or a downstream command can route "file a ticket" to it (Claude Code's Skill tool refused the call before, and `skillOverrides` cannot loosen a plugin skill). The description now triggers on file/create/shape a ticket, open a tracker issue, repair/clean up `ABC-123`. Who starts the pipeline changed; who approves the write did not.
14
+
3
15
  ## v7.7.0 - 2026-10-07
4
16
 
5
17
  - **Test economy in TDD, implementer, and code review.** The TDD skill's RED step carries six declinable defaults (extend before add, one scenario per test, parametrize equivalent cases, minimal synthetic input, shared expensive setup, cheapest honest tier); `agents/implementer.md` and the SDD self-review carry the imperative view, `agents/code-reviewer.md` and the review template the check view (economy findings are Minor `shrink:`/`delete:`, lost coverage on consolidation is Critical); anti-pattern 4 is scoped to external API responses; writing-plans prefers the existing test file as `Test:`. Two new eval targets, `eval/implementer` and `eval/code-reviewer`, measure the change on five synthetic ledger-import samples (Python and RSpec).
package/README.md CHANGED
@@ -35,7 +35,7 @@ pi-gauntlet's only hard dependency is pi-cohort - every gate that dispatches a r
35
35
 
36
36
  Concretely, one change through the gauntlet:
37
37
 
38
- 0. *(Optional)* Before there's even a spec, `/skill:shape-ticket` can create or repair a single tracker issue - shaping a raw ask into a Context/Problem/Idea/Acceptance Criteria ticket, gated by an AC integrity check, a cheap council roast, and one human-confirmed write that may include one optional gated Reporter-note comment. A failed roast is retried once, then surfaced inline at the gate if it fails again. It's a tool, not a phase: no worktree, no plan/phase tracker, runs from any repo state. It never activates on its own (`disable-model-invocation: true`) - invoke it explicitly. Similarly, `/skill:chase-bug` triages a raw bug report into an evidenced verdict - and can hand off to shape-ticket, brainstorming, or a bounded hotfix - before any spec exists.
38
+ 0. *(Optional)* Before there's even a spec, `/skill:shape-ticket` can create or repair a single tracker issue - shaping a raw ask into a Context/Problem/Idea/Acceptance Criteria ticket, gated by an AC integrity check, a cheap council roast, and one human-confirmed write that may include one optional gated Reporter-note comment. A failed roast is retried once, then surfaced inline at the gate if it fails again. It's a tool, not a phase: no worktree, no plan/phase tracker, runs from any repo state. The agent may start it on its own when the ask is "file a ticket" or another skill routes there; the write still waits for your yes on the presented diff. Similarly, `/skill:chase-bug` triages a raw bug report into an evidenced verdict - and can hand off to shape-ticket, brainstorming, or a bounded hotfix - before any spec exists.
39
39
  1. Opt in with `/skill:brainstorming` and describe the change. The command is the reliable discovery-and-entry path; explicit prose requesting brainstorming/the gauntlet also supplies consent when the skill is already loaded or an available instruction or route identifies it. An ordinary implementation request or an agent recommendation is not consent. **`brainstorming`** sets up an isolated worktree, explores the codebase, and turns your description into a written spec - when its recon finds a cited case that the ask is the wrong change (misdiagnosed, wrong-sized, already solved, a band-aid, or cutting across a sound pattern - including a repo convention that is itself debt) and can name the alternative, question one is a framing question (`as framed`, `pivot: <alternative>`, or `smaller or none`); otherwise it opens with one sentence naming what it checked, and every approach it proposes ends with a `Pattern:` line naming what it follows or cuts across; when the run starts from a ticket, the spec carries the ticket's acceptance criteria verbatim, each with a disposition (`in-scope`, `deviates:`, `deferred:`, `venue:`), the conformance gate checks the in-scope ones, and `/skill:check-delivery` verifies `venue:` rows after deploy. A multi-model critique runs on it automatically. If the spec replaces a known prior spec, brainstorming marks the predecessor with a `> **Superseded by:**` banner under its title (default format, syntax overridable via `.pi/gauntlet-overrides.md`; candidates come from brainstorming's scout recon, never a mechanical sweep). **You read and approve the spec - human gate 1.** No implementation code exists yet.
40
40
  2. **`writing-plans`** decomposes the approved spec into atomic, independently-verifiable tasks, grouped into parallel waves where they don't touch the same files.
41
41
  3. **`subagent-driven-development`** executes the plan one task at a time, each in a fresh subagent, behind spec-compliance review then code-quality review. TDD-locked: red, green, refactor. Independent implementation, review, and council batches remain parallel, but their dispatches are foreground: the orchestrator waits for terminal results before accepting work or advancing a phase.
@@ -47,7 +47,7 @@ Only the machine-owned `plan -> implement` and `verify -> ship` handoffs receive
47
47
 
48
48
  ```mermaid
49
49
  flowchart LR
50
- T["shape-ticket<br/>(optional, explicit)"]
50
+ T["shape-ticket<br/>(optional)"]
51
51
  R([explicit opt-in]) --> B[brainstorm<br/>+ spec]
52
52
  T -.-> R
53
53
  B --> G1{{human gate 1:<br/>approve spec}}
@@ -69,7 +69,7 @@ Everything between gate 1 and gate 2 - task breakdown, implementation, both revi
69
69
 
70
70
  pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
71
71
 
72
- - **20 skills** - the workflow logic. Twelve activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `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). Eight 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. `shape-ticket` creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write - run it with `/skill:shape-ticket`. `gatekeep-pr` 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 a verb menu whose rows derive from the actor's permissions on the PR; nothing mutates (fixes, pushes, reviews, merges, tracker comments) until you pick a 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 the normal `fix` row 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 - run it with `/skill:gatekeep-pr <pr> [--rebase [base]]`. `check-delivery` 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>`. `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>]`.
72
+ - **20 skills** - the workflow logic. Thirteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes), `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `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). Seven 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. `gatekeep-pr` 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 a verb menu whose rows derive from the actor's permissions on the PR; nothing mutates (fixes, pushes, reviews, merges, tracker comments) until you pick a 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 the normal `fix` row 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 - run it with `/skill:gatekeep-pr <pr> [--rebase [base]]`. `check-delivery` 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>`. `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>]`.
73
73
  - **7 subagent personas** - the specialized child agents the skills dispatch via pi-cohort: `implementer`, `code-reviewer`, `spec-reviewer`, `conformance-reviewer`, `spec-summarizer`, `spec-council-member`, `spec-council-synthesizer`. See [doc/personas.md](./doc/personas.md) for what each one does and why its permissions are scoped the way they are.
74
74
  - **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; a pass stamps the plan for implementation. `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.
75
75
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "7.7.0",
3
+ "version": "7.7.2",
4
4
  "description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
5
5
  "author": "Jacek Juraszek",
6
6
  "type": "module",
@@ -28,7 +28,7 @@ Verify (step 3) and Review (step 4) each run as a fresh helper with `cwd` the PR
28
28
  | 4 Review | `verification-brief.md` Section C | reviewer findings and the internal comment ledger | `review` |
29
29
  | 5 Integrate + report | `reference/post-selection-loop.md` `### Pre-menu refresh`, then `reference/findings.md`, then `reference/report.md` | AC outcomes, blockers, nits, drafted payloads, the rendered report | `report` |
30
30
  | 6 Menu | `reference/decision-menu.md` | the menu under the verdict line, exactly one `[recommended]` | `menu` |
31
- | 7 Loop | `reference/post-selection-loop.md` (a `fix` pick continues in `reference/fix-wave.md`) | the executed pick; re-entry until `stop` | (re-opens the re-entered stage) |
31
+ | 7 Loop | `reference/post-selection-loop.md` (a `fix` or `fix nits` pick continues in `reference/fix-wave.md`) | the executed pick; re-entry until `stop` | (re-opens the re-entered stage) |
32
32
 
33
33
  Re-entry: a fix wave's own push re-enters step 4 through the own-push sequence (`reference/fix-wave.md` `## Evidence after push`, then `reference/post-selection-loop.md` `### Re-render`); any other head move re-enters step 3; an unchanged head re-enters step 5 through `reference/post-selection-loop.md` `### Pre-menu refresh`. A loop re-entry never re-runs step 2b; the sync runs once per invocation.
34
34
 
@@ -63,7 +63,7 @@ These bind every rendered report, menu, and external payload (review bodies, rep
63
63
  - Judging a ticket row the spec does not carry, or treating a spec `deferred: <ref>` row as a gap - owner: `reference/findings.md` `## AC outcomes`.
64
64
  - Reading the rubric, the verification command, or any ladder source from the PR's head instead of the base branch's merge-base - owner: `reference/assessment.md` `## Configuration`.
65
65
  - Raw command output, drafted payloads, or internal IDs in the rendered report - owner: `reference/report.md`.
66
- - An open-PR menu, other than the conflict menu, an own-merge or merge-queued menu, or a `--rebase` terminal stop (`stop` and `show evidence` only, `reference/sync.md`), without `fix` while a helper facility exists and the fix-round cap is neither `0` nor reached (a PR already merged or closed at step 1 offers `show evidence` and `stop` only); any menu without `show evidence`, with two `[recommended]`, or with `stop` not last - owner: `reference/decision-menu.md`.
66
+ - An open-PR menu, other than the conflict menu, an own-merge or merge-queued menu, or a `--rebase` terminal stop (`stop` and `show evidence` only, `reference/sync.md`), without `fix` while an open blocker exists, or without `fix nits` while a nit exists, when a helper facility exists and the fix-round cap is neither `0` nor reached (a PR already merged or closed at step 1 offers `show evidence` and `stop` only); any menu without `show evidence`, with two `[recommended]`, or with `stop` not last - owner: `reference/decision-menu.md`.
67
67
  - A local verification run while a binding check is pending, or a second push inside one round - owner: `reference/fix-wave.md` `## Evidence after push`.
68
68
  - The orchestrator resolving a merge conflict itself, or editing or committing a tracked file during a fix wave - owner: `reference/fix-wave.md` `## Conflicts` and `## Wave`.
69
69
  - A helper's duty run in the orchestrator's own context - owner: `## Harness notes`.
@@ -4,11 +4,12 @@ Read from SKILL.md step 6. Input: the report's verdict and the PR state. Output:
4
4
 
5
5
  ## Verbs
6
6
 
7
- `fix`, `push`, `review`, `approve`, `approve workflow run`, `update branch`, `merge`, `merge anyway`, `reply`, `post coverage to ticket`, `post coverage to PR`, `show evidence`, `wait`, `stop`.
7
+ `fix`, `fix nits`, `push`, `review`, `approve`, `approve workflow run`, `update branch`, `merge`, `merge anyway`, `reply`, `post coverage to ticket`, `post coverage to PR`, `show evidence`, `wait`, `stop`.
8
8
 
9
9
  Rows are `<n>. <verb> - <consequence>`; every row, `stop` included, carries its consequence clause. `stop` is always last, before the compose hint. `show evidence` is always offered and never `[recommended]`. A row the actor cannot execute - by `## Availability` below, or because the forge would refuse it (branch protection, a withhold) - is omitted and named in the compose line's `Not offered:` sentence; it is never `[recommended]`. Exactly one row is `[recommended]`.
10
10
 
11
- - `fix` - apply the drafted payloads for the named blockers (default: all open blockers; with no open blockers, the nit payloads) through fresh implementer helpers in the provisioned worktree, review the wave before any push, push when `push` is available (`fix-wave.md`); on a `rebased locally` head, lease-push once every carried blocker is resolved (`fix-wave.md` `## Evidence after push`); `fix nits` applies nit payloads only, `fix + nits` blockers and nits; with no drafted payload at all, the human names the change
11
+ - `fix` - apply the drafted payloads for the named blockers (open blockers by default) through fresh implementer helpers in the provisioned worktree, review the wave before any push, push when `push` is available (`fix-wave.md`); on a `rebased locally` head, lease-push once every carried blocker is resolved (`fix-wave.md` `## Evidence after push`); `fix + nits` composes this verb with `fix nits`
12
+ - `fix nits` - apply the nit payloads drafted at this pick (`findings.md` `## Drafted payloads`) through fresh implementer helpers in the provisioned worktree, review the wave before any push, push when `push` is available (`fix-wave.md`); `fix + nits` typed with zero open blockers runs as this verb
12
13
  - `push` - push local fix commits (renders only when unpushed commits exist)
13
14
  - `review` - post the blockers as a GitHub review: request-changes on someone else's PR, a comment on your own
14
15
  - `approve` - approve the PR (never your own)
@@ -23,7 +24,7 @@ Rows are `<n>. <verb> - <consequence>`; every row, `stop` included, carries its
23
24
  - `wait` - poll the reviewer run, every **binding** pending check in the resolved set (required or not), `mergeStateStatus` while it is `BLOCKED`, `UNKNOWN`, or `unreadable`, and the comment set, then re-render
24
25
  - `stop` - leave the PR as-is; on a `rebased locally` head run `git reset --hard <pre_head>` before `### Teardown`, discarding the rewrite and any unpushed fix commits, and assert `HEAD == <pre_head>` with a clean tree; a mismatch is the existing hard stop with the error, and the remote stays untouched
25
26
 
26
- Compose hint: `Type a number, or compose: "fix 2", "fix nits", "fix + nits", "fix 1 + reply". Not offered: push (needs push to <head_url>:<head_ref>), merge (needs WRITE on <owner>/<repo>).` The first sentence lists only compositions whose every verb is a rendered row: no `Nits` section, no `fix nits`; no `reply` row, no `fix 1 + reply`; no composable row, `Type a number.` alone. The second sentence names every omitted row as `<verb> (<why it is omitted>)` and is dropped when nothing is omitted. `merge anyway` renders as its own row when `## Availability` allows it, so the rendered-row rule does not apply to it. 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`).
27
+ Compose hint: `Type a number, or compose: "fix 2", "fix nits", "fix + nits", "fix 1 + reply". Not offered: push (needs push to <head_url>:<head_ref>), merge (needs WRITE on <owner>/<repo>).` The first sentence lists only compositions whose every verb is a rendered row: `fix nits` and `fix + nits` appear only when both the `fix` and `fix nits` rows render; no `reply` row, no `fix 1 + reply`; no composable row, `Type a number.` alone. The second sentence names every omitted row as `<verb> (<why it is omitted>)` and is dropped when nothing is omitted. `merge anyway` renders as its own row when `## Availability` allows it, so the rendered-row rule does not apply to it. A composed line never bundles a push-producing verb (`fix`, `fix nits`, `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`).
27
28
 
28
29
  A composed line naming an omitted row is refused by name and the menu re-renders; the `merge anyway` row is the only override.
29
30
 
@@ -33,8 +34,9 @@ Rows derive from the digest's `permissions` block (`../verification-brief.md` Se
33
34
 
34
35
  | Row | Available when |
35
36
  |---|---|
36
- | `fix` | a helper facility exists (`../SKILL.md` `## Harness notes`) and the fix-round cap is not `0` and the round cap is not reached (`fix-wave.md` `## Wave`) |
37
- | `push` | `head_pushable` is true and unpushed wave commits exist and the last pre-push review had no Critical or Moderate finding |
37
+ | `fix` | an open blocker exists (a failing-check `P#` included; the wave reports a blocker with no file-level payload as not fixable, `post-selection-loop.md` `### Fix wave`), a helper facility exists (`../SKILL.md` `## Harness notes`), and the fix-round cap is neither `0` nor reached (`fix-wave.md` `## Wave`) |
38
+ | `fix nits` | a nit exists, a helper facility exists (`../SKILL.md` `## Harness notes`), and the fix-round cap is neither `0` nor reached (`fix-wave.md` `## Wave`); a `fix` with no open blocker, or a `fix nits` with no nit, is dropped from the row set and never named in `Not offered:` |
39
+ | `push` | `head_pushable` is true and unpushed wave commits exist and the last pre-push review's carried set (`fix-wave.md` `## Review before push`) held no Critical or Moderate |
38
40
  | `merge` | `viewer_permission` is `WRITE`, `MAINTAIN`, or `ADMIN`, and the merge preconditions hold (`post-selection-loop.md`) |
39
41
  | `merge anyway` | its own overlay's withhold is the only unmet merge prerequisite (`post-selection-loop.md` `### Merge preconditions`) and `viewer_permission` is `WRITE`, `MAINTAIN`, or `ADMIN`; otherwise omitted and named in `Not offered:` |
40
42
  | `approve workflow run` | `viewer_permission` is `WRITE`, `MAINTAIN`, or `ADMIN`, and a held run exists on the assessed head |
@@ -50,12 +52,12 @@ A `fixable` verdict with zero blockers (a withhold reason) uses the mergeable ro
50
52
 
51
53
  | Author | Verdict | Rows |
52
54
  |---|---|---|
53
- | you | mergeable | `merge`; `fix`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
54
- | you | fixable | `fix`; `review`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
55
- | someone else | mergeable | `approve`; `fix`; `merge`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
56
- | someone else | fixable | `review`; `fix`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
55
+ | you | mergeable | `merge`; `fix nits`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
56
+ | you | fixable | `fix`; `fix nits`; `review`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
57
+ | someone else | mergeable | `approve`; `fix nits`; `merge`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
58
+ | someone else | fixable | `review`; `fix`; `fix nits`; `reply` (when a drafted reply exists); `show evidence`; `stop` |
57
59
 
58
- `push` joins any row set after `fix` when unpushed fix commits sit in the worktree.
60
+ `push` joins any row set after `fix` or `fix nits` when unpushed fix commits sit in the worktree.
59
61
 
60
62
  ## Withhold reason resolver
61
63
 
@@ -74,14 +76,14 @@ Overlays modify the consent row; they are never a second offer source, except `o
74
76
  | own merge | this run's `merge` pick ran and the post-merge read (`post-selection-loop.md` `### Merge course`) returned `state: MERGED` | the menu is `post coverage to ticket` (when `issue` is non-null and `scope.rows` is non-empty), `post coverage to PR`, `show evidence`, `stop`, with `stop` `[recommended]`; each post row renders once and leaves the menu after its post succeeds; a failed post keeps its row and prints the `gh` error; no compare-and-swap runs before a post |
75
77
  | merge queued | this run's `merge` pick ran and the post-merge read returned a state other than `MERGED` | the menu is `wait` (re-run the post-merge read, then re-render), `show evidence`, `stop`, with `wait` `[recommended]`; one `PR comments` line `The merge is queued, so coverage posts wait. (<state>)` |
76
78
  | merged or closed PR | `state` was not `OPEN` at step 1 | the report renders; the menu is `show evidence` and `stop` only |
77
- | draft PR | `isDraft` | `merge` and `approve` are omitted (`Not offered: merge (draft)`, plus `approve (draft)` when the consent row holds `approve`) 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` |
79
+ | draft PR | `isDraft` | `merge` and `approve` are omitted (`Not offered: merge (draft)`, plus `approve (draft)` when the consent row holds `approve`) and never carry `[recommended]`; `review` is recommended on someone else's fixable draft, `fix nits` on their mergeable draft when a nit exists, else `stop`; on your own, `fix` when a blocker exists, else `stop` |
78
80
  | held run | an `action_required` conclusion on an Actions run of the assessed head (`../verification-brief.md` Evidence resolution, Held run) with no `local run: held run not approvable` evidence yet for that head | `approve workflow run` renders as row 1 when available (`## Availability`) and is `[recommended]` when `Blockers` is empty, else `[recommended]` stays on the consent row's first row; `merge` is omitted (`Not offered: merge (workflow run awaiting approval)`); once the held-run-not-approvable local run exists, this overlay no longer applies and `merge` follows the preconditions |
79
81
  | merge state | `merge_state_status` is `BLOCKED`, `UNKNOWN`, or `unreadable`, or the pre-menu refresh failed (`post-selection-loop.md` `### Pre-menu refresh`) - independent of any pending check, so a green-CI state-only block fires it | one `PR comments` line from `## Withhold reason resolver` (reason 1 or 2); `wait` as row 1; `[recommended]` goes to `approve` when the consent row renders it (someone else's PR, resolver reason 1, `reviewDecision` `REVIEW_REQUIRED`) - recommending a row attributes nothing to a rule - else to `wait` when `Blockers` is empty; `merge` omitted with the resolver's `Not offered` text; no `anyway` row |
80
82
  | verification evidence pending | the Evidence resolution table resolved Pending for the assessed head (`../verification-brief.md` Section B) | puts `wait` as row 1 and, when `Blockers` is empty, `[recommended]`; `merge` is omitted with `## Withhold reason resolver` reason 3's text; consent rows otherwise unchanged |
81
83
  | CI check | an undispositioned failing check in the resolved set, or a binding pending check (`findings.md` `## Dispositions`); a held run is not a binding pending check here (the `held run` overlay owns it) | on a failing check, the hint line offers `check <name> flaky \| real \| ci-broken`; `merge` is omitted (`Not offered: merge (<check name> failing)`); `flaky` restores `merge` on the next render; `real` and `ci-infrastructure-broken` keep it omitted until green; a binding pending check renders one `PR comments` line and omits `merge` with the text of `## Withhold reason resolver` reason 3, and puts `wait` as row 1 and, when `Blockers` is empty, `[recommended]`; under both this and the `merge state` overlay the higher one owns the reason and the single `PR comments` line; it mints no disposition hint (not dispositionable) |
82
84
  | 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` is omitted (`Not offered: merge (reviewer still running)` or `merge (comments not refreshed)`); `merge anyway` renders as its own row when `## Availability` allows it, overrides only this overlay, and does not bypass an unreviewed delta or a blocker; a `reviewer failed (<conclusion>)` row changes nothing |
83
- | 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` is omitted (`Not offered: merge (comment source review incomplete)`) with no `anyway` row; `reply` and `review` are dropped (the delta is unreviewed); `fix`, `show evidence`, `stop` stay; `stop` is `[recommended]` |
84
- | head not pushable | `head_pushable` is false or `unreadable` (a fork head, a branch this actor cannot push, or an unreadable head) | `push` is omitted (`Not offered: push (needs push to <head_url>:<head_ref>)`); `fix` stays and applies to the local worktree branch (`assessment.md` provisioning), its consequence clause reading "open a PR from that branch, or hand the patch to the author"; `merge` follows `## Availability` |
85
+ | 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` is omitted (`Not offered: merge (comment source review incomplete)`) with no `anyway` row; `reply` and `review` are dropped (the delta is unreviewed); `fix`, `fix nits`, `show evidence`, `stop` stay; `stop` is `[recommended]` |
86
+ | head not pushable | `head_pushable` is false or `unreadable` (a fork head, a branch this actor cannot push, or an unreadable head) | `push` is omitted (`Not offered: push (needs push to <head_url>:<head_ref>)`); `fix` and `fix nits` stay and apply to the local worktree branch (`assessment.md` provisioning), their consequence clauses reading "open a PR from that branch, or hand the patch to the author"; `merge` follows `## Availability` |
85
87
  | bot author | `author_is_bot` | the someone-else rows |
86
88
 
87
89
  ## Fixtures
@@ -99,20 +101,21 @@ PR comments:
99
101
 
100
102
  Nits:
101
103
  - 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)
104
+ 1 nit open - fix nits to take them
102
105
 
103
106
  Verdict: fixable - reviewer run in progress
104
107
 
105
108
  1. wait - poll the reviewer run, then re-render [recommended]
106
- 2. fix - apply the nit payload in the worktree, review the wave, push
109
+ 2. fix nits - apply the nit payload in the worktree, review the wave, push
107
110
  3. reply - post the drafted reply to maria
108
111
  4. show evidence - gate output, CI run
109
112
  5. stop - leave the PR as-is
110
- Type a number, or compose: "fix nits". Not offered: merge (reviewer still running).
113
+ Type a number. Not offered: merge (reviewer still running).
111
114
  ```
112
115
 
113
116
  Fixture 3 - a different PR: your own, every spec row covered, no nits, no drafted replies; the reviewer bot's run was the only withhold and `wait` just returned.
114
117
 
115
- (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`.
118
+ (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], `show evidence`, `stop`.
116
119
 
117
120
  (b) The run concluded `success` and the verdict comment raises a retry bug; source review confirms it and mints a blocker:
118
121
 
@@ -66,6 +66,6 @@ How each disposition changes the menu: `decision-menu.md` `## Overlays`, CI chec
66
66
 
67
67
  ## Drafted payloads
68
68
 
69
- 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 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. A `P#` carried by a `rebased locally` sync record is drafted like any blocker, from the helper's test output and `git show <stopped commit>`; a `P#` with no draftable edit stays open and `fix` reports it as not fixable. The human sees the draft at the `fix` consent and decides whether code or test expectations change; the implementer never decides it.
69
+ Step 5 drafts, never applies. For every blocker with a file-level fix - code and doc drift alike - draft the concrete edit as a payload keyed to the finding's internal ID. Draft nit payloads on a `fix nits` or `fix + nits` pick, which is the consent: print them in the `show evidence` payload shape and dispatch the wave in the same pick with no second confirmation; before that pick `show evidence` prints only the payloads that exist. 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`, `fix nits`, or `fix + nits` pick (the same path for code and docs) and dropped at teardown otherwise. A `P#` carried by a `rebased locally` sync record is drafted like any blocker, from the helper's test output and `git show <stopped commit>`; a `P#` with no draftable edit stays open and `fix` reports it as not fixable. The human sees the draft at the `fix` consent and decides whether code or test expectations change; the implementer never decides it.
70
70
 
71
71
  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,6 +1,6 @@
1
1
  # gatekeep-pr: fix wave
2
2
 
3
- Read from `post-selection-loop.md` `### Fix wave` once the payloads for a `fix` pick are selected. Input: the selected payloads (`findings.md` `## Drafted payloads`), the pre-wave findings list, and the digest. Output: pushed commits with current evidence, or unpushed commits with the menu re-rendered. The orchestrator edits no tracked file and runs no git write other than `fetch`, `merge --ff-only`, `push`, and `reset --hard <pre_head>` after a refused lease or a remote head move on a `rebased locally` head (`post-selection-loop.md` `### Compare-and-swap`); every edit and every commit belongs to a fresh helper (`../SKILL.md` `## Harness notes`).
3
+ Read from `post-selection-loop.md` `### Fix wave` once the payloads for a `fix` or `fix nits` pick are selected. Input: the selected payloads (`findings.md` `## Drafted payloads`), the dispatched findings, and the digest. Output: pushed commits with current evidence, or unpushed commits with the menu re-rendered. The orchestrator edits no tracked file and runs no git write other than `fetch`, `merge --ff-only`, `push`, and `reset --hard <pre_head>` after a refused lease or a remote head move on a `rebased locally` head (`post-selection-loop.md` `### Compare-and-swap`); every edit and every commit belongs to a fresh helper (`../SKILL.md` `## Harness notes`).
4
4
 
5
5
  ## Conflicts
6
6
 
@@ -26,13 +26,13 @@ A worktree holding unpushed wave commits never shows `update branch`. The orches
26
26
 
27
27
  ## Wave
28
28
 
29
- `pre_wave_head` was recorded before the first `## Conflicts` check. A round is one pass over the open payloads plus one `## Review before push`. The round cap is `closureReview.maxFixRounds`, read with `gauntlet_setting({ key: "closureReview" })` when that tool exists, else 3; a cap of `0` omits `fix` from the menu, named as `fix (maxFixRounds is 0)` in the `Not offered:` sentence. The round count is per run; at the cap `fix` is omitted, named `fix (round cap reached)` in `Not offered:`.
29
+ `pre_wave_head` was recorded before the first `## Conflicts` check. A round is one pass over the open payloads plus one `## Review before push`. The round cap is `closureReview.maxFixRounds`, read with `gauntlet_setting({ key: "closureReview" })` when that tool exists, else 3; a cap of `0` omits `fix` and `fix nits` from the menu, named as `fix, fix nits (maxFixRounds is 0)` in the `Not offered:` sentence. The round count is per run; at the cap `fix` and `fix nits` are omitted, named `fix, fix nits (round cap reached)` in `Not offered:`.
30
30
 
31
31
  For each payload in review order, dispatch one fresh implementer helper with `cwd` the PR worktree. Its task holds:
32
32
 
33
33
  - the finding's evidence pack (`findings.md` `## Drafted payloads` shape) and the instruction to apply the consented payload - or, for a reviewer finding that has no drafted payload, the reviewer's finding text - never to re-solve the finding;
34
- - the scoped test commands: the test it writes, or the test file the payload touches, and for a `P#` carried by a `rebased locally` sync record the failing test file named in that record - never the resolved `verification command`;
35
- - the commit rule: commit on the PR branch only when the scoped test passes, one commit per payload, subject naming the fix; otherwise discard its edits (`git checkout -- <its files>`, remove files it created) and return `open - <why>`;
34
+ - `SCOPED_TEST_COMMANDS`, resolved once per wave from the merge-base copies of the overrides file, then `AGENTS.md` (`git show "$MB:<path>"`, the trust rule of `assessment.md` `## Configuration`): a scoped runner is a documented test command carrying a `<paths>` or `<files>` placeholder, or a command the doc labels scoped, in any section of either file (`## PR gate`, `## Project`, `## routing`, `## test-driven-development`, `## verification-before-completion` alike); keep its cwd and flags verbatim; with several runners take the one whose directory prefix matches the payload's test file; substitute the test files the payload touches or writes, and for a `P#` carried by a `rebased locally` sync record the failing test file named in that record; no runner or no test file -> `none`. Never the resolved `verification command`, whatever a consumer sentence says about fix waves - that command runs only where `../verification-brief.md` Section B selects a local-run row; `none` -> the helper reports `no scoped test` and the pre-push reviewer is its only gate;
35
+ - the commit rule: commit on the PR branch only when the scoped test passes, or when `SCOPED_TEST_COMMANDS` is `none`, one commit per payload, subject naming the fix; otherwise discard its edits (`git checkout -- <its files>`, remove files it created) and return `open - <why>`;
36
36
  - the report shape: the scoped test's failing run before the edit and passing run after it; a doc-only payload with no test reports `no scoped test` and its diff, and the reviewer below is its only gate.
37
37
 
38
38
  After each helper returns, read `git -C <worktree> status --porcelain` and `git -C <worktree> rev-parse HEAD`. A `done` return shows exactly one new commit and a clean tree; an `open` return shows no new commit and a clean tree. Any other state - staged, unstaged, or untracked residue, or a moved HEAD on `open` - stops the round: dispatch no further implementer, and re-render the menu naming the files and the payload. An `open` payload is never reported as fixed, whatever the reviewer reports. The orchestrator never commits or checks out files, and resets only to `<pre_head>` after a refused lease or a remote head move (`## Evidence after push`, `post-selection-loop.md` `### Compare-and-swap`).
@@ -41,9 +41,9 @@ After each helper returns, read `git -C <worktree> status --porcelain` and `git
41
41
 
42
42
  When HEAD equals `pre_wave_head` after a round (every payload returned `open`), skip the review and the push and re-render the menu with the `open` reasons.
43
43
 
44
- After the round's payloads, dispatch one fresh reviewer helper, `cwd` the PR worktree, read-only, over `<pushed_head>..HEAD`, where `pushed_head` is the digest's `headRefOid` (the assessed head), so commits a previous round left unpushed are always inside the reviewed range; `pre_wave_head` serves only the empty-round test. Its task carries the pre-wave findings list, numbered with this skill's finding ids, under `## Previous review report (re-review trigger)`, and the output of `git diff <pushed_head> HEAD` under `## Fix delta`, and asks for the reviewer's native report plus one closure line per pre-wave finding, accepted anywhere after the findings list: `<finding id>: resolved` or `<finding id>: open - <why>`. When the round holds a `merge base` commit, `## Fix delta` is `git diff <pushed_head> <merge-sha>^1`, then `git show --remerge-diff <merge-sha>`, then `git diff <merge-sha> HEAD`. Ignore a `TRAJECTORY:` line in the report.
44
+ After the round's payloads, dispatch one fresh reviewer helper, `cwd` the PR worktree, read-only, over `<pushed_head>..HEAD`, where `pushed_head` is the digest's `headRefOid` (the assessed head), so commits a previous round left unpushed are always inside the reviewed range; `pre_wave_head` serves only the empty-round test. Its task carries the findings whose payloads this wave dispatched, under their `P#`/`L#` ids, under `## Previous review report (re-review trigger)`, and the output of `git diff <pushed_head> HEAD` under `## Fix delta`, and asks for the reviewer's native report plus one closure line per listed finding, accepted anywhere after the findings list: `<finding id>: resolved` or `<finding id>: open - <why>`. When the round holds a `merge base` commit, `## Fix delta` is `git diff <pushed_head> <merge-sha>^1`, then `git show --remerge-diff <merge-sha>`, then `git diff <merge-sha> HEAD`. Ignore a `TRAJECTORY:` line in the report.
45
45
 
46
- Mark a finding resolved only from a `resolved` closure line; the orchestrator never marks one. Push only when the report has no Critical or Moderate finding. Otherwise re-dispatch implementers with the report verbatim for the `open` payloads and the new Critical or Moderate findings - one more round, up to the cap. At the cap, the commits stay unpushed on the PR branch; the menu re-renders with the reviewer's verdict line and its Critical and Moderate titles, and `push` is omitted, named as `push (reviewer blocked the wave)` in the `Not offered:` sentence.
46
+ Mark a finding resolved only from a `resolved` closure line; the orchestrator never marks one. The carried set is every `open` closure line of this wave's ids, every new Critical or Moderate finding inside `## Fix delta`, and every new Critical finding outside it; a new finding entering the set is minted a `P#` before dispatch and listed under it in the next round's reviewer task. An in-delta Minor translates to a nit (`findings.md` `## Namespaces`); a `[Minor] (outside fix delta)` finding, or an outside-delta finding the report tags Moderate, prints under `show evidence` only. Push only when the carried set holds no Critical or Moderate. Otherwise dispatch one fresh implementer, serially, per carried item - the payload for an `open` id, the reviewer's finding text for a new finding - one more round, up to the cap. At the cap, the commits stay unpushed on the PR branch; the menu re-renders with the reviewer's verdict line and the carried set's Critical and Moderate titles, and `push` is omitted, named as `push (reviewer blocked the wave)` in the `Not offered:` sentence.
47
47
 
48
48
  ## Evidence after push
49
49
 
@@ -24,7 +24,7 @@ Before every external write, re-fetch `headRefOid`, `state`, `mergeable`, and `m
24
24
 
25
25
  ### Fix wave
26
26
 
27
- 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.
27
+ For a `fix` pick, take the drafted payloads (`findings.md` `## Drafted payloads`) for the named blockers - all open blockers by default; `fix nits` takes nit payloads only, drafted at this pick; `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.
28
28
 
29
29
  Apply per `fix-wave.md`: the local conflict check, one fresh implementer helper per payload with scoped tests only, the pre-push reviewer with its closure lines, the push, and the evidence poll. The orchestrator never edits a tracked file and never commits. When `head_pushable` is false, the wave's commits stay in the local `pr-<N>` worktree: report the branch name and re-enter step 5.
30
30
 
@@ -21,7 +21,7 @@ PR comments: (replyable review comments, a pending reviewer run, a b
21
21
  - The reviewer run is still in progress, so merge waits. (<run url>)
22
22
  - <the line from decision-menu.md `## Withhold reason resolver`>
23
23
 
24
- Nits:
24
+ Nits: (after the list, one line `<N> nits open - fix nits to take them` (`1 nit open` for one); rendered only while the `fix nits` row renders.)
25
25
  - <1-2 sentences>. (<file:line>)
26
26
 
27
27
  Blockers: (numbered; menu picks reference these numbers)
@@ -60,6 +60,7 @@ PR comments:
60
60
 
61
61
  Nits:
62
62
  - 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)
63
+ 1 nit open - fix nits to take them
63
64
 
64
65
  Blockers:
65
66
  1. The export endpoint ships with no test, so nothing proves it works and nothing
@@ -71,10 +72,11 @@ Blockers:
71
72
  Verdict: fixable - 2 blockers
72
73
 
73
74
  1. fix - apply both blockers in the worktree, review the wave, push [recommended]
74
- 2. review - post the blockers as a comment on your PR
75
- 3. reply - post the drafted reply to maria
76
- 4. show evidence - gate output, CI run, drafted edits
77
- 5. stop - leave the PR as-is
75
+ 2. fix nits - apply the nit payload in the worktree, review the wave, push
76
+ 3. review - post the blockers as a comment on your PR
77
+ 4. reply - post the drafted reply to maria
78
+ 5. show evidence - gate output, CI run, drafted edits
79
+ 6. stop - leave the PR as-is
78
80
  Type a number, or compose: "fix 2", "fix nits", "fix + nits", "fix 1 + reply".
79
81
  ```
80
82
 
@@ -86,8 +88,7 @@ Delivers: the reports page exports CSV on demand. ACs 1-5.
86
88
  Verdict: mergeable - CI green on the assessed head (test)
87
89
 
88
90
  1. merge - squash onto main [recommended]
89
- 2. fix - name the change to apply in the worktree, review the wave, push
90
- 3. show evidence - gate output, CI run
91
- 4. stop - leave the PR as-is
91
+ 2. show evidence - gate output, CI run
92
+ 3. stop - leave the PR as-is
92
93
  Type a number.
93
94
  ```
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: shape-ticket
3
- description: Use when creating a new tracker issue from a request, repairing or cleaning up an existing tracker issue, or converting a vague ask into an actionable ticket with real acceptance criteria. Also explicit invocation via /skill:shape-ticket.
4
- disable-model-invocation: true
3
+ description: Use when asked to file, create, or shape a ticket, open a tracker issue, or repair or clean up an existing one (ticket IDs like ABC-123) - including when another skill or command routes ticket authoring here.
5
4
  ---
6
5
 
7
6
  # Shape Ticket
@@ -21,6 +20,8 @@ disable-model-invocation: true
21
20
 
22
21
  Every path that writes ends at the **same single confirmation gate** - no write happens without an explicit yes on the exact presented diff. The no-op path stops before any gate opens; the hard-stop path aborts and never opens one either.
23
22
 
23
+ Model-initiated invocation is allowed: another skill, a command, or an ask matching the description starts this pipeline without a human typing the command. That changes who starts the pipeline, never who approves the write - the human answers the gate.
24
+
24
25
  ## Overview
25
26
 
26
27
  One process, two entry points: **create** a new tracker issue from a prompt, or **repair** an existing one by re-fetching it and proposing a full replacement. Repair is never a silent patch - it is always shown old->new, links and tracker fields preserved. Running this skill on any ticket trues it up; repeated use is a self-healing backlog pass.