pi-gauntlet 7.29.0 → 7.30.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 +11 -0
- package/README.md +2 -2
- package/package.json +1 -1
- package/skills/brainstorming/SKILL.md +8 -4
- package/skills/brainstorming/gatherer.md +33 -2
- package/skills/brainstorming/reference/amendment-surface.md +1 -1
- package/skills/brainstorming/reference/pr-subject.md +51 -0
- package/skills/brainstorming/reference/spec-finalization.md +10 -3
- package/skills/brainstorming/reference/ticket-acceptance.md +2 -2
- package/skills/finishing-a-development-branch/SKILL.md +63 -7
- package/skills/gauntlet-handoff/SKILL.md +1 -1
- package/skills/gauntlet-resume/reference/brief-contract.md +17 -6
- package/skills/gauntlet-resume/reference/reconstruction.md +6 -0
- package/skills/using-git-worktrees/SKILL.md +3 -3
- package/skills/using-git-worktrees/reference/pr-head.md +74 -0
- package/skills/verification-before-completion/SKILL.md +3 -1
- package/skills/writing-plans/SKILL.md +5 -1
- package/skills/writing-plans/reference/plan-contract.md +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v7.30.0 - 2026-10-23
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Brainstorming accepts an open PR as its subject.** `/skill:brainstorming <ref>` resolves `#N`, `owner/repo#N`, or a PR URL to a pull request first and gathers from its title, body, diff, unresolved review threads, and linked ticket; constraints are read from the base branch's HEAD docs, not the fork point, and the spec carries a `## Rework record` naming what the rework keeps and changes, proposing a repair of the original over a rewrite where one satisfies the current rules (`skills/brainstorming/reference/pr-subject.md`). `using-git-worktrees` checks out the PR's head branch at the PR head SHA (`reference/pr-head.md`; a branch already checked out, an unreachable head, or a fork head stops before any write), spec and implementation commits append to the PR branch, and `finishing-a-development-branch` offers "push to the PR branch": it saves the pre-rework head under `refs/gauntlet/pre-rework/pr-<N>`, pushes without force, appends a `## Rework` block to the PR description with one line per review thread, and stops at the menu when the push would need force. `gauntlet-handoff` and `gauntlet-resume` carry the PR reference and pre-rework head so a fresh session resumes on the PR branch in the same worktree. Ticket and free-text subjects are unchanged. (#78)
|
|
8
|
+
- Eval samples `pr-subject-resolution`, `pr-subject-repair-over-rewrite`, `pr-subject-rule-added-later`, and `pr-subject-weakened-rule` under `eval/brainstorming/`, `pr-head` under `eval/using-git-worktrees/`, `pr-subject-threads` under `eval/writing-plans/`, `pr-subject-push` under `eval/finishing-a-development-branch/`, and `pr-subject-brief` under `eval/gauntlet-resume/`. (#78)
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- The withheld-push finishing menu reads a bare numeric reply by its displayed label (2-6), so `1` is refused while the push row is withheld. (#78)
|
|
13
|
+
|
|
3
14
|
## v7.29.0 - 2026-10-23
|
|
4
15
|
|
|
5
16
|
### Added
|
package/README.md
CHANGED
|
@@ -36,13 +36,13 @@ pi-gauntlet's only hard dependency is pi-cohort - every gate that dispatches a r
|
|
|
36
36
|
Concretely, one change through the gauntlet:
|
|
37
37
|
|
|
38
38
|
0. *(Optional)* Before there's even a spec, `/skill:shape-ticket` can create one tracker issue or repair a comma/whitespace list of issue refs - shaping each into a Context/Problem/Idea/Acceptance Criteria ticket, grounded by a repository audit, an AC integrity check, and a cheap council roast. Repair finishes preparation for all tickets before presenting exact-diff confirmations sequentially in ref order; each approval writes that ticket before the next gate, and may include one optional gated comment for a Reporter note or overlap evidence. The audit checks factual claims, Idea fit, AC mechanisms against cited repo guidance, and already-stated observable legs in configured sibling checkouts. It reports in-motion work and attempts a best-effort scenario through authorized current-system reads, without promising reproduction or a fix; missing access or nothing to observe is reported, not a new approval gate. Implementer detail moves into the gated Reporter note; brainstorming reads that note with the ticket so the spec retains the detail. 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
|
-
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
|
|
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. A leading GitHub reference (`#N`, `owner/repo#N`, or a `/pull/N` or `/issues/N` URL) is resolved as a PR first: an open PR, including a draft, starts rework on its existing in-repo branch; a non-PR follows the ticket path. Trailing text carries intent; mid-sentence references and other ticket/free-text subjects keep their existing paths. The PR diff is the starting state, judged against constraints from the fetched current base HEAD, not the fork point or the PR's proposed policy edits; see the [PR-subject contract](skills/brainstorming/reference/pr-subject.md) and [PR-head worktree owner](skills/using-git-worktrees/reference/pr-head.md). **`brainstorming`** sets up an isolated worktree (on the existing branch for PR rework), explores the codebase, and turns the subject 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:`, `elsewhere:` for a row another repo's part delivers), scope cuts come only from your answer to a cut question and are listed at the gate, the conformance gate checks the in-scope ones, and `/skill:check-delivery` verifies `venue:` rows before the prod 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.** Before approval, PR rework permits only the base merge, conflict resolution, and scoped conflict tests outside the spec directories; other subjects have no implementation code yet.
|
|
40
40
|
2. By default, **`writing-plans`** decomposes the approved spec into atomic, independently-verifiable tasks, grouped into parallel waves where they don't touch the same files. Experimental approval options 4/5 instead select **`loop-implementation`**: the plan phase is skipped and a stamped acceptance-criteria ledger replaces the task plan. Option 4 retains amendment review; option 5 grants auto-apply amends, with redraws still stopping. See [Loop engine operations](doc/configuration.md#loop-engine-operations).
|
|
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.
|
|
42
42
|
The loop alternative to step 3 runs one fresh `loop-implementer` per seed or row iteration, without implement-phase reviewers. It stops for a human decision on stagnation or a failed exit verification; passing full verification with every row closed enters the same verify gates.
|
|
43
43
|
|
|
44
44
|
4. **verify**: the parent first runs the plan's full verification command set (the ledger's `verification:` command for loop); only a passing result permits whole-diff code review, then the **conformance gate**. A review fix invalidates that result, so the parent reruns full verification before the next review or conformance gate. When the overrides file declares a happy path for the touched paths (see [Project-specific overrides](#project-specific-overrides)), the parent runs it once here, between code review and the conformance gate, and the reviewer reads its transcript as runtime evidence - a hang or a failed request shows up in the audit with the transcript quoted - as a gap when an origin clause ties to it, otherwise as a `happy-path: failed - unattributable` line - never as a silent green. The conformance subagent reads the finished code and docs against your *original words* from step 1, not the plan, and reports per-requirement: delivered, partial, missing, drifted, or unauthorized. Unauthorized rows - shipped surface no human input asked for, whether it crept in or was laundered through the spec - follow their recommendation like every other row: a contained removal auto-runs, anything another requirement leans on is deferred with a plain-language "I'd cut it / I'd keep it" recommendation. Inside a brainstorming-entered flow this gate is machine-blocked from being skipped. Compatible executable recommendations auto-run through an isolated fix-and-re-audit loop with no prompt; anything still open surfaces as a numbered decision brief - one item per decision, the problem in plain words first, lettered options each with a one-line consequence, and `Recommended: <letter> - <reason>` or `No recommendation - pick one`. Reply with one line per item (`1. B`), or bare `1` to take every recommendation (no-recommendation items are re-asked by number); a current `CONFORMS` / no-concerns result goes straight to the branch options with no extra conformance sign-off.
|
|
45
|
-
5. **`finishing-a-development-branch`**: PR, draft PR, squash, keep, or discard. Once a PR exists, run `/skill:gatekeep-pr <pr>` to verify it before merging - it judges the diff against the spec at the PR's head (the acceptance-criteria dispositions and Design you approved; the PR description when no spec applies) - rows the spec defers or deviates are settled, every other row needs its mechanism (code, tests, docs) - and against the rubric; whatever can be seen only after merge is left to step 6. **Human gate 2** - the only other decision you make.
|
|
45
|
+
5. **`finishing-a-development-branch`**: PR, draft PR, squash, keep, or discard; PR rework also offers a non-force push to the existing PR branch. That push preserves history and appends a `## Rework` block while retaining the original description bytes. Its `Before:` handle includes the full portable pre-rework SHA and the local `refs/gauntlet/pre-rework/pr-<N>` ref in the rework checkout. The [finishing owner](skills/finishing-a-development-branch/SKILL.md#pr-subject-row-1-push-to-the-pr-branch) defines the landing and body-update contract. Once a PR exists, run `/skill:gatekeep-pr <pr>` to verify it before merging - it judges the diff against the spec at the PR's head (the acceptance-criteria dispositions and Design you approved; the PR description when no spec applies) - rows the spec defers or deviates are settled, every other row needs its mechanism (code, tests, docs) - and against the rubric; whatever can be seen only after merge is left to step 6. **Human gate 2** - the only other decision you make.
|
|
46
46
|
6. *(Optional)* Once the merge lands, `/skill:check-delivery <ref>` can prove delivery - default-branch landing, delivery target, per-AC evidence - before the tracker status advances. Explicit ask only, no auto-chain: deploys commonly lag merges by minutes to hours, so an auto-run would routinely check too early.
|
|
47
47
|
|
|
48
48
|
Only the machine-owned `plan -> implement` and `verify -> ship` handoffs receive a branch-local one-shot nudge after an unexpected settled stop; it is fire-and-forget, does not bypass either human gate, and older Pi hosts without `agent_settled` retain existing behavior.
|
package/package.json
CHANGED
|
@@ -18,6 +18,8 @@ You **may** read code/docs, run the existing system to observe current behavior,
|
|
|
18
18
|
|
|
19
19
|
You may **not** write outside the resolved spec dirs; build, deploy, validate, or exercise the proposed change; run implementation skills; commit the spec on `main`; or start `/skill:writing-plans`.
|
|
20
20
|
|
|
21
|
+
For a PR subject, the base merge in `using-git-worktrees/reference/pr-head.md` - its merge commit, its conflict helper's edits to the conflicted files, and its scoped conflict tests - is the one pre-approval write and run outside the spec dirs; nothing else moves.
|
|
22
|
+
|
|
21
23
|
The line: current-system observation is research; exercising the proposed change waits for approval.
|
|
22
24
|
|
|
23
25
|
## Foreground dispatch policy
|
|
@@ -42,7 +44,7 @@ Work through the items below **in order**. After a user answer or completed side
|
|
|
42
44
|
phase_tracker({ action: "start", phase: "brainstorm" })
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
2. **Set up the worktree** - see [Worktree First](#worktree-first).
|
|
47
|
+
2. **Set up the worktree** - resolve a tracker reference first per `reference/pr-subject.md`; pass a PR subject's head to `/skill:using-git-worktrees`' PR-head path. Then see [Worktree First](#worktree-first).
|
|
46
48
|
3. **Gather context** - read [Ticket Handling](#ticket-handling), then follow [`gatherer.md`](gatherer.md) without a human stop.
|
|
47
49
|
4. **Understand the idea against the draft** - if `reference/ticket-acceptance.md` is not already in context this session (restored entry, or a redraw after a fresh start), read [Ticket Handling](#ticket-handling) before the rest of this step; then see [Understand the idea](#3-understand-the-idea).
|
|
48
50
|
5. **Propose 2-3 approaches** - see [Explore approaches](#4-explore-approaches).
|
|
@@ -63,7 +65,7 @@ Detection order: (1) infer from ticket labels, description, or paths; (2) use th
|
|
|
63
65
|
|
|
64
66
|
## Worktree First
|
|
65
67
|
|
|
66
|
-
The spec is the first commit in a dedicated worktree, never a separate commit on `main`.
|
|
68
|
+
The spec is the first commit in a dedicated worktree, never a separate commit on `main`. For a PR subject, the worktree is the PR's branch and the spec commit is appended to it.
|
|
67
69
|
|
|
68
70
|
Invoke `/skill:using-git-worktrees`; use `.worktrees/` or the project-native location. Carry its `Worktree ready at <full-path>` value: spec path `<full-path>/<spec dir>/<filename>.md`; every dispatch uses that `cwd`; git uses `git -C <full-path>`. Keep the process cwd unchanged.
|
|
69
71
|
|
|
@@ -87,7 +89,7 @@ If any test fails, offer no split. Never split by service, package, repo, layer,
|
|
|
87
89
|
|
|
88
90
|
### 3. Understand the idea
|
|
89
91
|
|
|
90
|
-
Clarify freely.
|
|
92
|
+
Clarify freely. For a PR subject, run the framing check against the PR's diff as the ask (`reference/pr-subject.md`).
|
|
91
93
|
|
|
92
94
|
`Read` the gathered draft unconditionally before question one. Treat it as a helper, not a fence: verify load-bearing claims from primary code, and confirm whether the codebase or ecosystem already solves the problem.
|
|
93
95
|
|
|
@@ -140,7 +142,7 @@ Propose 2-3 genuinely distinct approaches and name what separates them (the axis
|
|
|
140
142
|
|
|
141
143
|
### 5. Design for clarity and isolation
|
|
142
144
|
|
|
143
|
-
Prefer clear testable boundaries, YAGNI, existing conventions when they are sound - when the convention is the debt, say so and do not extend it - the owning schema/contract rather than parallel state, and explicit errors and edge cases.
|
|
145
|
+
Prefer clear testable boundaries, YAGNI, existing conventions when they are sound - when the convention is the debt, say so and do not extend it - the owning schema/contract rather than parallel state, and explicit errors and edge cases. Retain every existing user-approved design detail in approaches and design, including when drafting or replacing the spec.
|
|
144
146
|
|
|
145
147
|
### 6. Present the design in two rounds
|
|
146
148
|
|
|
@@ -162,6 +164,8 @@ Inside an opted-in flow, shared schemas, contracts, and invariants require a spe
|
|
|
162
164
|
|
|
163
165
|
Write under the routed spec dir: pick the routing prose's dir (overrides file, `AGENTS.md`) when it is one of the resolved dirs, else the one resolved dir from `gauntlet_setting({ key: "flowGuards" })` that already exists in the repo, else the first resolved dir (`doc/specs` under the default). Name ticketed files `YYYY-MM-DD-<ticket-id>-<topic>.md`, otherwise `YYYY-MM-DD-<topic>.md`. Use a filename-safe tracker slug (`E-12345`, `gh-123`), but native references in plan headers and commits. `<topic>` is 3-6 kebab-case words without `-design` or another suffix.
|
|
164
166
|
|
|
167
|
+
For a PR subject, apply `reference/pr-subject.md`: keep the bound-ticket filename; name an unbound spec `YYYY-MM-DD-pr-<N>-<topic>.md` from the PR title.
|
|
168
|
+
|
|
165
169
|
Mint the slug once during gather and reuse it. If questionary invalidates it, write to the new path and delete the uncommitted draft.
|
|
166
170
|
|
|
167
171
|
## Spec Self-Review (Before User Review Gate)
|
|
@@ -70,7 +70,8 @@ Scout (always dispatched):
|
|
|
70
70
|
> independently of context-builder, in pages of 50 until a short page. Match sections
|
|
71
71
|
> anywhere in each comment regardless of author; accept either ordering with
|
|
72
72
|
> `Overlap evidence:` and exclude that evidence part. Include every matched section's
|
|
73
|
-
> terms in the query
|
|
73
|
+
> terms in the query, keeping literal file paths intact rather than shortening them
|
|
74
|
+
> to stems. Run
|
|
74
75
|
> `node <SPEC_INDEX> --query '<keywords>' --limit 10` from the worktree root,
|
|
75
76
|
> keeping the keywords inside single quotes, and treat its rows as the candidate
|
|
76
77
|
> list; zero rows means the index found no evidence, not that no predecessor exists -
|
|
@@ -124,6 +125,29 @@ Scout (always dispatched):
|
|
|
124
125
|
> "Open questions that matter for the spec"
|
|
125
126
|
> section. Compact handoff, not a dump.
|
|
126
127
|
|
|
128
|
+
For a PR subject, supply this additional scout block as values from
|
|
129
|
+
`reference/pr-subject.md` (keep scout unconditional):
|
|
130
|
+
|
|
131
|
+
> PR title and body verbatim: `<title>`, `<body>`.
|
|
132
|
+
> PR-carried specs: `<paths and stated contracts>`.
|
|
133
|
+
> Changed paths: `<git diff --name-only <BASE_SHA>...<PRE_REWORK_HEAD> output>`.
|
|
134
|
+
> Read the diff itself from the worktree. Unresolved threads: `<full comment threads
|
|
135
|
+
> in order, with ids and locations from using-git-worktrees/reference/pr-head.md,
|
|
136
|
+
> or threads: not fetched (<reason>)>`.
|
|
137
|
+
> Merge result: `<merge line, contract exceptions, scoped test results>`.
|
|
138
|
+
> Authoritative base-HEAD constraints: `<git show <BASE_SHA>:<path> texts for
|
|
139
|
+
> AGENTS.md, first-found overrides, REVIEW.md, and all cited constraint documents;
|
|
140
|
+
> explicit missing-document results>`. These govern on every merge outcome,
|
|
141
|
+
> including clean; worktree policy edits are proposals under `changes:` or
|
|
142
|
+
> `dropped claims:`, never constraints.
|
|
143
|
+
> The PR is the starting state, not the target. Judge every PR-stated claim against
|
|
144
|
+
> the diff and supplied base rules. Name the smallest repair satisfying them;
|
|
145
|
+
> propose a rewrite only where no repair can. Render `## PR under rework` with
|
|
146
|
+
> `keeps:`, `changes:`, `dropped claims:`, `constraints added since fork:` (one line
|
|
147
|
+
> per base rule absent at the fork point), and one proposed disposition per
|
|
148
|
+
> unresolved thread: `fix | keep open | decline: <reason>`. Carry merge contract
|
|
149
|
+
> exceptions into `changes:`.
|
|
150
|
+
|
|
127
151
|
Context-builder (conditional):
|
|
128
152
|
|
|
129
153
|
> Extract external context for an upcoming design discussion. The request:
|
|
@@ -156,7 +180,10 @@ Context-builder (conditional):
|
|
|
156
180
|
|
|
157
181
|
## Context-builder trigger rule
|
|
158
182
|
|
|
159
|
-
|
|
183
|
+
For a resolved PR subject, dispatch context-builder only for the bound ticket
|
|
184
|
+
using `reference/pr-subject.md`; an unbound PR supplies intent, not ticket ACs.
|
|
185
|
+
Title wins a title/body-first-line ticket conflict; carry the other reference into
|
|
186
|
+
`## Problem` as context. For other subjects, dispatch context-builder when the initial prompt (or a file it explicitly references)
|
|
160
187
|
contains any of:
|
|
161
188
|
|
|
162
189
|
- an `http(s)://` URL;
|
|
@@ -196,6 +223,10 @@ convention; slug minted from the initial prompt):
|
|
|
196
223
|
## Codebase recon
|
|
197
224
|
<scout output, or the degraded text>
|
|
198
225
|
|
|
226
|
+
## PR under rework
|
|
227
|
+
<PR subject only: scout rework section and supplied PR/base/merge values per
|
|
228
|
+
reference/pr-subject.md; retain these values even when scout failed>
|
|
229
|
+
|
|
199
230
|
## External context
|
|
200
231
|
<context-builder output, degraded text, or unfetched-ref list; omit this section
|
|
201
232
|
only when the trigger rule never fired>
|
|
@@ -134,7 +134,7 @@ Details
|
|
|
134
134
|
|
|
135
135
|
Letter options in fixed order: `A) accept`, then `B) alt-1`, `C) alt-2` in index order, only for genuine alternatives. Give each option its one-line effect; tie the recommendation's reason to the end goal or a development practice. Record a letter as its shown option's token. Keep custom unlettered as shown. Keep an unavailable option visible and unlettered: `Not available: <option> - <missing prerequisite>`. Use exactly `Recommended: <letter> - <reason>` or `No recommendation - pick one`; the prepared-item schema requires a recommendation, so this amendment menu never renders the second form.
|
|
136
136
|
|
|
137
|
-
Reply grammar: one line per item, `<n>. <letter or free text>`; bare `1` applies every recommendation and re-asks any item without one by number, never re-rendering the menu (vacuous here: the prepared-item schema always supplies a recommendation); an omitted item keeps its recommendation; free text is `custom(<text>)` and may redirect anywhere ("keep the spec, fix the parser") - a redirect drops the item (still recorded in the batch commit body as `custom(<effect>)`) and returns the finding to its calling loop; a letter always picks its shown option, even when free text would spell its name. A legacy `2: <handle>=<choice>` reply is accepted silently as the same picks; the form is never rendered in a prompt. Invalid number or letter -> reprompt for that item only, keep every valid pick, never reopen the gate; a bare digit other than `1` is an invalid reply and never a grant (reprompt the same way). A bare letter or bare `1` mixed with numbered lines is invalid; free text matching an option's name remains `custom(<text>)`. Resolve every item before applying; retain original numbers during reprompts. Take no action before the reply. After the reply lands and the batch applies, print one confirmation line `Recorded: <handle>=<choice>, ...` covering the batch's decided items (
|
|
137
|
+
Reply grammar: one line per item, `<n>. <letter or free text>`; bare `1` applies every recommendation and re-asks any item without one by number, never re-rendering the menu (vacuous here: the prepared-item schema always supplies a recommendation); an omitted item keeps its recommendation; free text is `custom(<text>)` and may redirect anywhere ("keep the spec, fix the parser") - a redirect drops the item (still recorded in the batch commit body as `custom(<effect>)`) and returns the finding to its calling loop; a letter always picks its shown option, even when free text would spell its name. A legacy `2: <handle>=<choice>` reply is accepted silently as the same picks; the form is never rendered in a prompt. Invalid number or letter -> reprompt for that item only, keep every valid pick, never reopen the gate; a bare digit other than `1` is an invalid reply and never a grant (reprompt the same way). A bare letter or bare `1` mixed with numbered lines is invalid; free text matching an option's name remains `custom(<text>)`. Execute a custom instruction as given: apply its spec-edit portion, including documentation of a retained value. Treat it as a redirect only when the instruction directs work elsewhere, never merely because the reply is free text. Resolve every item before applying; retain original numbers during reprompts. Take no action before the reply. After the reply lands and the batch applies, print one confirmation line `Recorded: <handle>=<choice>, ...` covering the batch's decided items (print each custom choice as `<handle>=custom(<text>)`, retaining the literal `custom(...)` wrapper with the reply's free text verbatim inside it; grant-applied items record their recommended choice); this is the only place `<handle>=<choice>` appears to the human.
|
|
138
138
|
|
|
139
139
|
## 5. Apply, aftermath, commit
|
|
140
140
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# PR subject
|
|
2
|
+
|
|
3
|
+
## Resolve before provisioning
|
|
4
|
+
|
|
5
|
+
Match only a trimmed leading GitHub reference: `#N`, `owner/repo#N`, or a GitHub `/pull/N` or `/issues/N` URL, optionally followed by free text carried as intent. Keep mid-sentence mentions on the existing free-text/context-builder path. Keep Linear/Jira and other free-text subjects on their existing paths.
|
|
6
|
+
|
|
7
|
+
Complete classification in order, never in parallel: `gh issue view` can return a PR as an issue.
|
|
8
|
+
|
|
9
|
+
1. Run `gh pr view <N> [-R owner/repo] --json number,url,state,isDraft,title,body,headRefName,headRefOid,headRepository,isCrossRepository,baseRefName`. Accept exit 0 with `state: OPEN`, including `isDraft` true. For another state, stop: `PR #N is <state>; only an open PR can be reworked.`
|
|
10
|
+
2. Only a not-a-PR result reaches `gh issue view <N>` and the existing ticket path.
|
|
11
|
+
3. For neither, stop: `#N resolves to neither a pull request nor an issue in <owner/repo>.`
|
|
12
|
+
|
|
13
|
+
Parse the PR base repository from `url` and this checkout's repository from `git remote get-url origin`; compare lowercase owner/repo identities. For unequal identities stop before provisioning: `PR <owner/repo#N> belongs to <repo>, not this checkout (<origin owner/repo>).` Resolve bare `#N` in this checkout.
|
|
14
|
+
|
|
15
|
+
Bind the first tracker reference in the title, then the body's first line. Never bind from branch names, commit subjects, or `closingIssuesReferences`. Fetch a bound ticket, extract its AC rows using `reference/ticket-acceptance.md`, and dispatch context-builder for it. Preserve `none - ticket not fetched (<reason>)` on fetch failure. When title and first body line name different tickets, use the title's ticket and name the other in `## Problem` as context.
|
|
16
|
+
|
|
17
|
+
For an unbound PR, write `none - no ticket` under `## Acceptance criteria`; carry raw title/body as stated intent, not invented AC rows. Name its spec `YYYY-MM-DD-pr-<N>-<topic>.md`; emit the concrete filename with the actual date, PR number, and topic slug derived from the PR title. For a bound ticket keep `YYYY-MM-DD-<ticket-id>-<topic>.md`.
|
|
18
|
+
|
|
19
|
+
Pass exactly `{ number, url, title, headRefName, headRefOid, baseRefName, isCrossRepository, headRepository.nameWithOwner }` by value to provisioning in `using-git-worktrees/reference/pr-head.md`; write nothing during resolution.
|
|
20
|
+
|
|
21
|
+
## Gather from the PR and fetched base
|
|
22
|
+
|
|
23
|
+
Discover PR-carried specs with `git diff --name-only origin/<baseRefName>...<headRefOid> -- <each flowGuards.specDirs dir>` using the resolved spec directories. Read each as the PR's stated contract beside its title/body. Only when superseded, name it in `**Predecessor:**` and apply `reference/superseding.md`'s banner; that banner is the allowed spec-directory write.
|
|
24
|
+
|
|
25
|
+
On every merge outcome, including clean, no-op, and unresolved, read constraints using `git show <BASE_SHA>:<path>`: `AGENTS.md`, the first-found overrides file (check `.pi/gauntlet-overrides.md`, `gauntlet-overrides.md`, `doc/gauntlet-overrides.md` in order at BASE_SHA), `REVIEW.md`, and all cited constraint documents. Carry missing-document results explicitly. Use these fetched base-HEAD rules, never fork-point or worktree copies. Treat PR edits to policy documents as proposals recorded under `changes:` or `dropped claims:`, not governing constraints.
|
|
26
|
+
|
|
27
|
+
Dispatch scout always, and context-builder when a ticket is bound. Supply scout with the title/body verbatim, PR-carried specs, file list from `git diff --name-only <BASE_SHA>...<PRE_REWORK_HEAD>`, base-SHA constraint documents, merge result, and unresolved threads from the query owned by `using-git-worktrees/reference/pr-head.md`. Have scout read the diff itself from the worktree and the full comments of every thread. On query failure carry `threads: not fetched (<reason>)` and continue.
|
|
28
|
+
|
|
29
|
+
Instruct scout: treat the PR as the starting state, not the target; judge every stated claim against its diff and current base rules. Name the smallest repair satisfying those rules; propose a rewrite only when no repair can satisfy them. Render `## PR under rework` after `## Codebase recon`, with `keeps:`, `changes:`, `dropped claims:`, `constraints added since fork:` (one line per base-HEAD rule absent at the fork point), and one proposed disposition per unresolved thread: `fix | keep open | decline: <reason>`. Carry any merge contract exception into `changes:`. Run the framing check in `SKILL.md` `### 3` against the diff as the ask.
|
|
30
|
+
|
|
31
|
+
## Record in the spec
|
|
32
|
+
|
|
33
|
+
In `## Problem`, name `PR <owner/repo#N> - <title>`, its stated intent, every `constraints added since fork:` line as a constraint, and the existing `Framing:` line. Preserve the following grammar after `## Acceptance criteria`:
|
|
34
|
+
|
|
35
|
+
```markdown
|
|
36
|
+
## Rework record
|
|
37
|
+
|
|
38
|
+
PR: <owner/repo#N> - <title>
|
|
39
|
+
Pre-rework head: <40-char sha>
|
|
40
|
+
Base: <baseRefName> @ <sha7> - merge: <no-op | sha7 | unresolved - files>
|
|
41
|
+
Keeps: <what of the original survives>
|
|
42
|
+
Changes: <what the rework alters, repair over rewrite>
|
|
43
|
+
Dropped claims: <one `- <claim>` per PR-stated claim no longer true | none>
|
|
44
|
+
Threads:
|
|
45
|
+
- <path>:<line> <thread id> - fix | keep open | decline: <reason>
|
|
46
|
+
Scoped tests: none run | <file>: green | <file>: red - <tests>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Use `Threads: none` for a successful empty fetch and `Threads: not fetched (<reason>)` for failure. Preserve the query owner's outdated/path-only location fallback. Instantiate `Scoped tests: none run (<reason>)` when no documented file-scoped runner exists or `requires credentials: true`; otherwise record the scoped result, including failures. Name landed contract exceptions in `Changes:`. For an unresolved merge, open Design with `merge origin/<base> and resolve <files>` as eventual plan Task 1. Preserve the full pre-rework SHA so `git log` history remains checkable.
|
|
50
|
+
|
|
51
|
+
Preserve this record when `reference/spec-finalization.md` replaces the draft; dropping it fails inline lint. Carry the PR title/body verbatim beside bound-ticket rows in the council's `Human input`. Do not attach a rework record to ticket or free-text specs.
|
|
@@ -11,6 +11,13 @@ Spec-writing replaces the context draft, in this exact order:
|
|
|
11
11
|
Using `edit` at this step is a red flag. The header block (between the H1 and the
|
|
12
12
|
first `##`) carries `**Amend-grant:** none` directly below `**Goal:**`; a redraw's
|
|
13
13
|
rewrite carries `none` too - a redraw is a new approval, with no carry-over.
|
|
14
|
+
For a PR subject, follow `pr-subject.md`'s spec contract: carry the draft's
|
|
15
|
+
`## PR under rework` into `## Rework record` after `## Acceptance criteria`,
|
|
16
|
+
preserving its exact fixed-line grammar, 40-character pre-rework SHA, merge result,
|
|
17
|
+
keeps/changes/dropped claims, thread dispositions and fetch status, contract exceptions,
|
|
18
|
+
and scoped test results (including failures and reasons none ran). Carry the PR's
|
|
19
|
+
stated intent and constraints added since fork into Problem. Open Design with the
|
|
20
|
+
unresolved merge repair when present. Omit the record from a ticket or free-text spec.
|
|
14
21
|
3. **Immediately after the write**, confirm line 1 of the file is no longer
|
|
15
22
|
`# CONTEXT DRAFT - NOT A SPEC - fully replaced at spec-writing` - before
|
|
16
23
|
dispatching lint, critique, council, or summarizer. The phase-tracker commit
|
|
@@ -39,7 +46,7 @@ After writing the spec to `<project>/doc/specs/<filename>.md` (per [Filename Con
|
|
|
39
46
|
- **Placeholder scan.** Any `TODO`, `TBD`, `<fill in>`, `[example]`, `xxx`? Either resolve them or convert to explicit "Open Questions" with names.
|
|
40
47
|
- **Internal consistency.** Does Section 4 contradict Section 2? Does the header block carry `**Amend-grant:**` exactly once with the value `none` (the [predicate](amendment-surface.md#standing-grants))? Are component names and field names consistent throughout? If the spec replaces a prior design, confirm the predecessor carries the supersession banner and its href resolves to this spec's final filename.
|
|
41
48
|
- **Documentation named.** Does the spec name all three classes (feature/user-facing introduced; materially amended; derived/memory invalidated), or an explicit "none" for each? Enforce the materiality bar in `documentation-impact.md` without restating it: each listed doc names the category it clears, none is a code-mirror, amend-over-create was applied, and skill/agent bodies are implementation surface, not doc-impact entries here.
|
|
42
|
-
- **Ticket contract present.** Does `## Acceptance criteria` exist with either verbatim ticket rows plus dispositions or one `none - <reason>` line? Presence is enforced here, at authoring, and nowhere later.
|
|
49
|
+
- **Ticket contract present.** Does `## Acceptance criteria` exist with either verbatim ticket rows plus dispositions or one `none - <reason>` line? Presence is enforced here, at authoring, and nowhere later. For a PR subject, require the complete `## Rework record` per `pr-subject.md`; absence fails inline lint, including after a full replacement or redraw.
|
|
43
50
|
- **Scope check.** Does every paragraph serve the goal? Cut filler. If something is out of scope, say it's out of scope.
|
|
44
51
|
- **Ambiguity check.** Is every "we should..." backed by a concrete decision? Replace "we could probably" with "we will" or "we won't".
|
|
45
52
|
|
|
@@ -49,7 +56,7 @@ The first four are the inline **lint**: run them here and fix what they surface.
|
|
|
49
56
|
|
|
50
57
|
Before dispatching the worker below, resolve `documentation-impact.md` relative to this loaded reference as one absolute `<DOCUMENTATION_IMPACT_GUIDELINE>` path value. Pass that value in the worker task; do not add it to the spec.
|
|
51
58
|
|
|
52
|
-
After the inline lint and before the user review gate, **brainstorming owns the critique-pass gate**; council **apply mechanics** live in `/skill:roasting-the-spec` (single source of truth - link, don't restate). Resolve the council with `gauntlet_setting({ key: "specCouncil" })` - the tool returns the merged (repo-over-preset) value as `{ verdict, members, chair, malformed, warning, errors }`. **Do not** hand-roll a settings read. When `verdict` is `"council"`, the council *is* the critique pass - invoke `/skill:roasting-the-spec` automatically (no offer, no prompt), passing `members`/`chair`; also pass the verbatim human input (the original prompt, any ticket AC snapshot - the raw rows under the gather draft's `## Ticket acceptance criteria (verbatim)` heading, never the spec's section, which holds the author's dispositions - and, for every question that offered a disposition (the cut question and the unmatched-group question in `ticket-acceptance.md`), the full question and the user's answer) - roasting-the-spec forwards it to members, chair, and applier as the `Human input (verbatim; off-limits for over-spec)` block; its dispatched applier applies the spec edits and supplies the returned audit (Applied/Deferred/Rejected). When `verdict` is `"worker"`, dispatch the worker below. If `malformed` is true or `errors` is non-empty, emit the `warning`/error as one line, then branch strictly on `verdict` - `malformed` can accompany *either* verdict (e.g. a bad `chair` with valid `members` still returns `council`), so never infer the worker path from `malformed` alone. If `gauntlet_setting` is unavailable, stop and report - never fall back to a manual bash/JSON settings merge. The already-applied council edits (or the worker's in-place fixes) ride in the same worktree commit. The conceptual precedence rule lives in `../../verification-before-completion/reference/settings-precedence.md`.
|
|
59
|
+
After the inline lint and before the user review gate, **brainstorming owns the critique-pass gate**; council **apply mechanics** live in `/skill:roasting-the-spec` (single source of truth - link, don't restate). Resolve the council with `gauntlet_setting({ key: "specCouncil" })` - the tool returns the merged (repo-over-preset) value as `{ verdict, members, chair, malformed, warning, errors }`. **Do not** hand-roll a settings read. When `verdict` is `"council"`, the council *is* the critique pass - invoke `/skill:roasting-the-spec` automatically (no offer, no prompt), passing `members`/`chair`; for a PR subject include the PR title and body verbatim beside the bound ticket rows in `Human input`; also pass the verbatim human input (the original prompt, any ticket AC snapshot - the raw rows under the gather draft's `## Ticket acceptance criteria (verbatim)` heading, never the spec's section, which holds the author's dispositions - and, for every question that offered a disposition (the cut question and the unmatched-group question in `ticket-acceptance.md`), the full question and the user's answer) - roasting-the-spec forwards it to members, chair, and applier as the `Human input (verbatim; off-limits for over-spec)` block; its dispatched applier applies the spec edits and supplies the returned audit (Applied/Deferred/Rejected). When `verdict` is `"worker"`, dispatch the worker below. If `malformed` is true or `errors` is non-empty, emit the `warning`/error as one line, then branch strictly on `verdict` - `malformed` can accompany *either* verdict (e.g. a bad `chair` with valid `members` still returns `council`), so never infer the worker path from `malformed` alone. If `gauntlet_setting` is unavailable, stop and report - never fall back to a manual bash/JSON settings merge. The already-applied council edits (or the worker's in-place fixes) ride in the same worktree commit. The conceptual precedence rule lives in `../../verification-before-completion/reference/settings-precedence.md`.
|
|
53
60
|
|
|
54
61
|
When `verdict` is `"worker"`, dispatch one fresh `worker` that applies the scope + ambiguity checks and fixes them in place:
|
|
55
62
|
|
|
@@ -153,7 +160,7 @@ Wait for the user. Interpret funded replies with this table before routing chang
|
|
|
153
160
|
| budget token alone (`fund 3 fix rounds`) | re-present the gate asking for `1`, `2`, `4`, or `5`; write nothing |
|
|
154
161
|
| token with malformed N | re-present the gate quoting the token; write nothing, never imply a change request |
|
|
155
162
|
|
|
156
|
-
For every value to persist, read [Standing grants](amendment-surface.md#standing-grants) and run Value decoding. Decode before `edit` or `--amend`; never persist a malformed token. Use the decoded table value in the approval persistence below, including budget-only approvals.
|
|
163
|
+
For every value to persist, read [Standing grants](amendment-surface.md#standing-grants) and run Value decoding. Decode before `edit` or `--amend`; never persist a malformed token. Use the decoded table value in the approval persistence below, including budget-only approvals. In persistence narration, quote the exact resulting `**Amend-grant:**` value in full, including any funding suffix; never substitute an option name or "option-2 description plus suffix" for the persisted text.
|
|
157
164
|
|
|
158
165
|
On a change request (including a revert), revise the spec and re-present - mint a **fresh** temp path for the re-dispatched summarizer (never reuse a prior round's path, so stale content can never be mistaken for the new summary). On `3` or its label alone: print the audit verbatim from `git -C <abs worktree path> show -s --format=%b HEAD` (never from a held tool result; the body survives the grant's `--amend --no-edit`), then re-present the same gate - the briefing text of the gate message just rendered, reused verbatim (no summarizer re-dispatch, no read of the removed `$SUMMARY_PATH`; if that text is no longer in context, the one-line degrade note takes its place), the `Council:` line, the adjacent lines, the rendered option rows; nothing in the spec or the commit changes. `3` plus a change request is a change request. `3` plus `1`/`2`/`4`/`5` prints and re-presents, and the approval is read only from a clean `1`/`2`/`4`/`5` on the re-presented gate - a reply carrying `3` never grants. A gate-round recommit (change request or revert) re-runs the same heredoc commit with the audit as its body, so HEAD always carries it; on a revert of edit X, move X's `Applied:` line to `Rejected:` with `-> reverted at gate` and recompute the `Council:` counts from the revised audit. On approval - `1`, `approve`, or equivalent prose approves without a grant; `2`, `approve, auto-apply amends`, or equivalent prose approves and grants; `4` approves without a grant; `5` approves and grants using option 2's description - first read [Standing grants](amendment-surface.md#standing-grants) (stop if unreadable). On every approval, `edit` the spec's `**Amend-grant:**` value to the decoded table value for funded replies, otherwise the granting sentence for 2/5 or `none` for 1/4. Write exactly one `**Engine:** loop` for 4/5 or `**Engine:** waves` for 1/2 directly below `**Amend-grant:**` in the header block (readers: absent -> `waves`). Then `git -C <abs worktree path> add -- <spec path>` and `git -C <abs worktree path> commit --amend --no-edit -q`, keeping the council-audit body; confirm `git -C <abs worktree path> show HEAD:<spec path>` contains both fields with the selected values and satisfies the grant predicate and Value decoding. A reply that mixes approval with a change request ("2 but rename the section") is a change request: revise, re-present, and read the grant only from the reply to the re-presented gate. If the amend or the HEAD check fails, stop and report; never proceed as granted. The plan and execution mode are mechanical derivatives, so the only human gate here is spec approval itself. Don't land the spec on `main`; it stays in the worktree and ships in the same squash commit as the implementation.
|
|
159
166
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Ticket Handling
|
|
2
2
|
|
|
3
|
-
A ticket is guidance, not sole truth. Fetch it; propose scope, approach, or acceptance changes when code disagrees, and record deviations in the spec. Carry implied requirements and terms from the ticket body (Context, Problem, Idea) and every `Reporter note:` comment section into the spec as any other requirement; keep the ticket body's explicit acceptance criteria verbatim in the section below. Extract ACs from the body only, never comments. With no fetch path or a whole-ticket fetch failure, list the unfetched ref and use `none - ticket not fetched (<reason>)` in `## Acceptance criteria`; show that existing `none` line at the gate so the user can paste rows. On body success with comments marked `comments not fetched (<reason>)` or `comments incomplete after page <k> (<reason>)`, retain the fetched AC rows and carry an adjacent gate-summary line: `Implied requirements came from the body only - <comment status>; paste missing comment text.` Continue to the gate without a new stop.
|
|
3
|
+
A ticket is guidance, not sole truth. Fetch it; propose scope, approach, or acceptance changes when code disagrees, and record deviations in the spec. Carry implied requirements and terms from the ticket body (Context, Problem, Idea) and every `Reporter note:` comment section into the spec as any other requirement; keep the ticket body's explicit acceptance criteria verbatim in the section below. Retain concrete details from a requirement-carrying note (paths, source measurements, preserved entry points) within that requirement in Design, not only in a context or premise note. Preserve a source measurement as a description of the input, not a new target or limit. Extract ACs from the body only, never comments. With no fetch path or a whole-ticket fetch failure, list the unfetched ref and use `none - ticket not fetched (<reason>)` in `## Acceptance criteria`; show that existing `none` line at the gate so the user can paste rows. On body success with comments marked `comments not fetched (<reason>)` or `comments incomplete after page <k> (<reason>)`, retain the fetched AC rows and carry an adjacent gate-summary line: `Implied requirements came from the body only - <comment status>; paste missing comment text.` Continue to the gate without a new stop.
|
|
4
4
|
|
|
5
5
|
**Extract the ticket's ACs.** When the ticket body has a heading matching `/acceptance criteria/i`, every list item under it is an AC (numbered, bullet, or checkbox) until the next heading of that heading's level or higher, and no other list in the body is; a heading one level deeper inside the section is a repo group - it names the repo whose part delivers the rows under it and does not end extraction. When there is no such heading, every top-level checkbox row in the body is an AC, except rows under a `Post-deployment housekeeping`, `Out of scope`, or `Follow-up` heading. Otherwise the ticket has no ACs. A nested list under an AC row rides with its parent as one row; an AC heading holding prose and no list makes each paragraph one row. Carry checked and unchecked rows alike, all written `- [ ]`. Take the rows and their repo-group headings from the gather draft's `## Ticket acceptance criteria (verbatim)` heading; when the ticket was not fetched, the gate summary shows the `none` line so the user can paste the rows, which then become rows.
|
|
6
6
|
|
|
@@ -17,6 +17,6 @@ Ticket <ref>, <heading or "checkbox list">, rows verbatim:
|
|
|
17
17
|
<disposition>
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The heading `## Acceptance criteria` names the ticket contract only; the spec's own requirements stay in Design, and the section stays flat - a row's repo lives in its disposition token, never in a heading. Disposition is exactly one of `in-scope`, `deviates: <why>`, `deferred: <where>`, `venue: <env> - <observation>`, `elsewhere: <repo>`; default `in-scope`. Never edit the row text: an ambiguous row stays `in-scope` with the chosen reading written as a Design clause, and a moved path or a workflow artifact (spec, plan, changelog, telemetry file) is a Design clause too, never a disposition and never asked. A row under a repo group that is not this repo is `elsewhere: <repo>`, stated, never asked; a group matching no repo asks `A) this repo B) elsewhere: <name> C) repair the ticket - /skill:shape-ticket <ref>`. Replace `<name>` with the supplied unmatched group heading verbatim. Name a `venue:` row's enabling change in Design; `venue:` states where the observation can happen and is never `prd`, `prod`, or `production` - a row observable only in production is a wrong row. An `in-scope` row is a requirement as written; disposition reasons are never normative for the plan or the reviewer, so a `deviates:` reason that adopts part of a row restates that part as a Design clause. A `deferred:` destination is a tracker ref (`#N`, `owner/repo#N`, `ABC-123`), a spec path, or a URL; a prose destination with none of these is a gap at the PR gate.
|
|
20
|
+
The heading `## Acceptance criteria` names the ticket contract only; the spec's own requirements stay in Design, and the section stays flat - a row's repo lives in its disposition token, never in a heading. Disposition is exactly one of `in-scope`, `deviates: <why>`, `deferred: <where>`, `venue: <env> - <observation>`, `elsewhere: <repo>`; default `in-scope`. Never edit the row text: an ambiguous row stays `in-scope` with the chosen reading written as a Design clause, and a moved path or a workflow artifact (spec, plan, changelog, telemetry file) is a Design clause too, never a disposition and never asked. A row under a repo group that is not this repo is `elsewhere: <repo>`, stated, never asked; a group matching no repo asks `A) this repo B) elsewhere: <name> C) repair the ticket - /skill:shape-ticket <ref>`. Replace `<name>` with the supplied unmatched group heading verbatim in option B, not a request to name a repo. Name a `venue:` row's enabling change in Design; `venue:` states where the observation can happen and is never `prd`, `prod`, or `production` - a row observable only in production is a wrong row. An `in-scope` row is a requirement as written; disposition reasons are never normative for the plan or the reviewer, so a `deviates:` reason that adopts part of a row restates that part as a Design clause. A `deferred:` destination is a tracker ref (`#N`, `owner/repo#N`, `ABC-123`), a spec path, or a URL; a prose destination with none of these is a gap at the PR gate.
|
|
21
21
|
|
|
22
22
|
**Cut question.** `deviates:` and `deferred:` come only from the user's answer to this question; never propose one. Ask it, in the questionary format, when the user's prompt or an answer raises dropping or changing a row, or when code, a cited contract, or the user shows a row is wrong or impossible: `A) in-scope - <reading> B) deviates: <why> C) deferred: <where> D) repair the ticket - /skill:shape-ticket <ref> <row and evidence>`, `Recommendation:` A or D with the reason the row ships in this gauntlet; B and C are never recommended. On D, run `/skill:shape-ticket <ref> <row and evidence>` (repair mode per `shape-ticket/SKILL.md:43`, its own confirm gate), then re-fetch the ticket, replace the gather draft's `## Ticket acceptance criteria (verbatim)` block, and re-extract; a cancel at that gate returns to this question with the row unchanged. Carry the full question and the user's answer of every question that offered a disposition into the council's `Human input` block. The gate lists every `deferred:`, `deviates:`, and `venue:` row on its `Scope cuts:` line (`spec-finalization.md`). A disposition changes in any later phase - a reviewer finding `recommended: rescope` at the finish gate, a wrong row noticed mid-implementation, or a ticket edited after approval when the user asks - through [Amending an approved spec](../SKILL.md#amending-an-approved-spec) (`amendment-surface.md`); the row text still never changes. With no ticket, or a ticket without ACs, the section body is the single line `none - no ticket`, `none - ticket has no acceptance criteria`, or `none - ticket not fetched (<reason>)`. Never author acceptance criteria on the ticket's behalf; that is `/skill:shape-ticket`'s job.
|
|
@@ -34,7 +34,9 @@ Then call `phase_tracker({ action: "start", phase: "ship" })`.
|
|
|
34
34
|
|
|
35
35
|
**Hard verification gate.** Tests/format/lint must pass before presenting any options — including Discard. The user's stated intent to throw the branch away does not change whether the diff is in a verifiable state; verifying first surfaces accidental damage to unrelated code before the branch is gone forever. The skip rule below is the only exception.
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
Read the selected run spec before verification. Detect a PR subject only by its `## Rework record`, never by an open PR on `$FEATURE`. Read `PR:` and the full `Pre-rework head:` into `PRE_REWORK_HEAD` from that record; missing pre-head -> stop naming the spec path. Confirm with `gh pr view <N> --json number,url,headRefName,baseRefName,state` (use the record's repository): non-`OPEN` -> stop: `PR #N is <state>; the rework cannot be pushed to it.`; headRefName != `$FEATURE` -> stop naming both branches. Retain baseRefName for Step 3.
|
|
38
|
+
|
|
39
|
+
Recognize a ledger by line 1 exactly `# Ledger - loop engine`. For a ledger, use its `verification:` command throughout finish, including the minors round. For a PR subject with a task plan, use the union of every plan task's `Tests:` commands plus the executable lint/format commands in the header's `**Verification:**` line; treat `none - PR subject, scoped` as no header commands, not an empty task union. Capture this set and accepted-complete task evidence before stripping the plan. Apply the hard gate and skip rule below to this set. For every other subject with a task plan, run the plan header's `**Verification:**` set in the worktree: `(cd "$WORKTREE" && <command>)`. With no plan in this session, run the verification command(s) of the affected services from the gauntlet overrides file or `AGENTS.md` (look for "verification", "CI", or "test" sections).
|
|
38
40
|
|
|
39
41
|
**Skip rule.** Skip the run only when this set passed on a known clean commit in the verify phase of this session and no edit or write landed outside `<telemetry.dir>` since. Check the current tree: `git -C "$WORKTREE" diff --quiet <commit the run passed on> -- . ':!<telemetry.dir>'` must exit 0, and `git -C "$WORKTREE" status --porcelain --untracked-files=all -- . ':!<telemetry.dir>'` must exit 0 with empty output (`<telemetry.dir>` defaults to `.pi/gauntlet/telemetry`). These checks cover committed, staged, unstaged, and untracked changes outside telemetry. Otherwise run it once; a missing verified commit, a failed check, or uncertainty means run.
|
|
40
42
|
|
|
@@ -61,10 +63,12 @@ No documentation prompt here: Documentation impact is decided at spec time (`/sk
|
|
|
61
63
|
|
|
62
64
|
### Step 2: Detect Environment
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
For a PR subject, use the Step 4 PR menu. For other subjects: detached HEAD (`git -C "$WORKTREE" symbolic-ref -q HEAD` prints nothing) -> reduced 4-option menu (no merge), no cleanup. Otherwise the standard 5 options.
|
|
65
67
|
|
|
66
68
|
### Step 3: Determine Base Branch
|
|
67
69
|
|
|
70
|
+
For a PR subject, set `<base-branch>` to the confirmed `baseRefName` and skip the common-base probe below.
|
|
71
|
+
|
|
68
72
|
```bash
|
|
69
73
|
# Try common base branches
|
|
70
74
|
git -C "$WORKTREE" merge-base HEAD main 2>/dev/null || git -C "$WORKTREE" merge-base HEAD master 2>/dev/null
|
|
@@ -178,6 +182,26 @@ Amendments auto-applied (N):
|
|
|
178
182
|
|
|
179
183
|
Omit the block when N = 0.
|
|
180
184
|
|
|
185
|
+
**PR subject - preflight and six-row menu.** Fetch origin with `git -C "$WORKTREE" fetch origin`; stop on failure. Run these proofs in order, against this worktree's HEAD:
|
|
186
|
+
| Proof | Exit 0 | Exit 1 |
|
|
187
|
+
|---|---|---|
|
|
188
|
+
| `git merge-base --is-ancestor <PRE_REWORK_HEAD> HEAD` | Continue | Stop: `PR branch history was rewritten: <PRE_REWORK_HEAD7> is not an ancestor of HEAD; the rework must be re-merged, not rebased.` |
|
|
189
|
+
| `git merge-base --is-ancestor origin/<headRefName> HEAD` | Offer push | Withhold push: `push withheld: origin/<headRefName> is at <sha7>, local HEAD at <sha7>; a non-force push cannot land` |
|
|
190
|
+
Run each proof with `git -C "$WORKTREE"`. Treat every exit other than 0 or 1 as a command error and stop with its output. For a withheld push only, separately prove `git -C "$WORKTREE" merge-base --is-ancestor <PRE_REWORK_HEAD> origin/<headRefName>`: exit 0 appends `(origin moved past the rework's base <PRE_REWORK_HEAD7>)`; exit 1 adds nothing; other exits stop as command errors. Divergence alone proves no origin advance.
|
|
191
|
+
Read and apply [menu-layout](../brainstorming/reference/menu-layout.md) for rendering and numeric replies. Present:
|
|
192
|
+
```
|
|
193
|
+
Implementation complete. What would you like to do?
|
|
194
|
+
|
|
195
|
+
1. Push to the PR branch (PR #N, <headRefName>; appends the rework block to its description)
|
|
196
|
+
2. Push and create a Pull Request (PR #N already exists on this branch; gh refuses a second one)
|
|
197
|
+
3. Push and create a draft Pull Request (same: PR #N already exists)
|
|
198
|
+
4. Squash-merge to <base-branch> (no PR, no surviving branch; orphans PR #N - close it by hand)
|
|
199
|
+
5. Keep the branch as-is (I'll handle it later; nothing is pushed)
|
|
200
|
+
6. Discard this work (removes the worktree and local branch; the PR branch on origin is untouched)
|
|
201
|
+
|
|
202
|
+
Which option?
|
|
203
|
+
```
|
|
204
|
+
Withhold row 1 by omitting it and placing `Withheld: push - <reason>` under the list; retain numbers 2-6. On that withheld menu read a bare reply by its displayed label: `2`-`6` select those rows; `1` or any other number gets the clarifying question naming `2`-`6` (this one menu overrides menu-layout's count-based `1`-`N` range). Recompute preflight on return to the menu. Add no approval gate. Map rows 2-6 to the existing Options 1-5 below, including their confirmation and cleanup rules; row 6 never deletes origin's branch.
|
|
181
205
|
**Normal repo and named-branch worktree — present exactly these 5 options:**
|
|
182
206
|
|
|
183
207
|
Read and apply [menu-layout](../brainstorming/reference/menu-layout.md) before presenting these options and before acting on a numeric reply.
|
|
@@ -213,7 +237,7 @@ Rows 1-2 run the Option 1/2 blocks; row 3 runs the Keep block and row 4 the Disc
|
|
|
213
237
|
|
|
214
238
|
**Don't add explanation** - keep options concise. When the minors line lists findings and the block has no `whole-diff minors fix:` line, add only this line under the menu: `Or reply "fix minors" (or "fix minors F3, F9") for one Minor fix round.` This line is the only addition to the exact numbered options.
|
|
215
239
|
|
|
216
|
-
**Standalone extra reply - `fix minors`.** When the rendered `whole-diff minors` line lists findings, `fix minors` (all) or `fix minors F3, F9` (a subset by `Fn`) is a valid reply beside the numbered options. It dispatches one `implementer` round (`cwd` = the worktree; task = the selected finding lines verbatim; `SCOPED_TEST_COMMANDS` = the plan-header verification set),
|
|
240
|
+
**Standalone extra reply - `fix minors`.** When the rendered `whole-diff minors` line lists findings, `fix minors` (all) or `fix minors F3, F9` (a subset by `Fn`) is a valid reply beside the numbered options. It dispatches one `implementer` round (`cwd` = the worktree; task = the selected finding lines verbatim; `SCOPED_TEST_COMMANDS` = for PR subjects, the executable scoped union captured in Step 1, excluding `none - PR subject, scoped`; for other subjects, the plan-header verification set). For a ledger, supply its `verification:` command instead. For PR subjects, require successful evidence for every supplied command after the fix; failed or missing evidence stops before returning to the menu. Commit `whole-diff minors fix` and return to Step 3.5, where the freshness rule re-audits conformance as for any working-tree change and the regenerated block records the spent round (`whole-diff minors fix: <full SHA>`); Step 4 then re-renders. No code review follows this round: the whole-diff review is an unscoped first review, so its Minors are graded Minors. A block that already carries `whole-diff minors fix:` refuses the reply with "minors round already spent". Any numbered choice ships without them.
|
|
217
241
|
|
|
218
242
|
### Step 5: Execute Choice
|
|
219
243
|
|
|
@@ -242,7 +266,37 @@ node <bin>/gauntlet-telemetry-seal.mjs --worktree "$WORKTREE" --option <pr|squas
|
|
|
242
266
|
```
|
|
243
267
|
|
|
244
268
|
The seal prints one line per record (`sealed <path>`, `already sealed <path>`) or one bare outcome (`no telemetry run`, `telemetry disabled`) and exits 0; print its stdout verbatim in the ship completion message. Any nonzero exit stops the flow before the first landing command, quoting the bin's line: exit 2 (`no record at <path>`, `unparseable record <path>: <reason>`) means this gauntlet run's recorder never armed or its record is corrupt; exit 1 is a usage, environment, or git/jj failure (`seal failed <path>: <reason>` restored the pre-seal bytes). The user decides; never land without the seal.
|
|
245
|
-
|
|
269
|
+
#### PR-subject row 1: Push to the PR branch
|
|
270
|
+
Capture the scoped verification set and thread evidence before the strip. Refetch unresolved threads with the query owned by [pr-head](../using-git-worktrees/reference/pr-head.md); preserve recorded dispositions, use the table below, and omit threads now resolved on GitHub. Use the query's location rendering.
|
|
271
|
+
| Refetched thread / evidence | Resolution |
|
|
272
|
+
|---|---|
|
|
273
|
+
| Recorded `fix`, matching task title carries id, task accepted by spec and code review and `complete`, exactly one naming commit | `fixed in <sha7>` |
|
|
274
|
+
| Same accepted-complete task, zero or multiple naming commits | `fixed (task "<title>" complete; no single commit names <thread id>)` |
|
|
275
|
+
| Missing or incomplete task; recorded `keep open`; newly opened thread | `still open` |
|
|
276
|
+
| Recorded `decline` | `declined - <reason>` |
|
|
277
|
+
| Successful fetch, empty set | `Threads: none` |
|
|
278
|
+
| Fetch failure | `Threads: not fetched (<reason>)` |
|
|
279
|
+
Count naming commits with `git -C "$WORKTREE" log --first-parent --format=%h --grep '<thread id>' <merge-sha | PRE_REWORK_HEAD>..HEAD` (merge SHA from the record when present). A touched file, grep match, or first-parent filter alone is not completion proof.
|
|
280
|
+
Run the existing strip-and-seal block with `--option pr --base origin/<baseRefName>` and the selected spec; retain its stop-on-error behavior. This seal measures the whole PR, not rework-only; never use PRE_REWORK_HEAD as its base. Then:
|
|
281
|
+
```bash
|
|
282
|
+
git -C "$WORKTREE" update-ref refs/gauntlet/pre-rework/pr-<N> <PRE_REWORK_HEAD>
|
|
283
|
+
git -C "$WORKTREE" push --no-follow-tags origin HEAD:refs/heads/<headRefName>
|
|
284
|
+
```
|
|
285
|
+
Stop on update-ref failure. Report a rejected push once, skip body editing, and return to the menu without retrying or forcing. Preserve the worktree.
|
|
286
|
+
After a successful push, fetch the description fresh with `gh pr view <N> --json body` in the record's repository. Decode the JSON body without trimming or shell command substitution (which loses trailing newlines). Create a scratch body file with `mktemp` outside the repo; write the existing body bytes exactly, then one blank line, then this block:
|
|
287
|
+
```markdown
|
|
288
|
+
## Rework
|
|
289
|
+
|
|
290
|
+
Before: <PRE_REWORK_HEAD> (local ref `refs/gauntlet/pre-rework/pr-<N>` in the rework checkout; the SHA is the portable handle and stays on origin because the push was not forced)
|
|
291
|
+
Spec: <spec path> at <HEAD7>
|
|
292
|
+
Keeps: <from the record>
|
|
293
|
+
Changes: <from the record>
|
|
294
|
+
Dropped claims: <none | one "No longer true: <claim>" line per dropped claim>
|
|
295
|
+
Verification: scoped - <commands>; CI on this push holds the full run. Telemetry: whole PR against <baseRefName>.
|
|
296
|
+
Threads:
|
|
297
|
+
- <path>:<line> - <resolution from the table>
|
|
298
|
+
```
|
|
299
|
+
Put `supersedes the description above` on the block's second line only when every original claim is dropped. Use `Threads: none` or `Threads: not fetched (<reason>)` instead of the list for those outcomes. Run `gh pr edit <N> --body-file <scratch-file>` in the record's repository without another approval. On body fetch/edit failure, keep the push and print the block for manual paste with the error; never replace the description with just the block. Post no review-thread replies, merge no PR, and change no ticket state.
|
|
246
300
|
#### Option 1: Push and Create PR
|
|
247
301
|
|
|
248
302
|
Run the strip-and-seal block above first (plan stripped, telemetry record sealed), then:
|
|
@@ -354,6 +408,7 @@ Removal precedes branch deletion in both options; `git branch -d`/`-D` fails whi
|
|
|
354
408
|
|
|
355
409
|
| Option | Merge | Push | Keep Worktree | Cleanup Branch | Plan strip + record seal |
|
|
356
410
|
|---|---|---|---|---|---|
|
|
411
|
+
| PR row 1. Push to PR branch | - | yes (non-force) | yes | - | yes (whole PR; see row 1 recipe) |
|
|
357
412
|
| 1. Create PR | - | yes | yes | - | yes (guarded, on the branch before push) |
|
|
358
413
|
| 2. Create draft PR | - | yes | yes | - | yes (guarded, on the branch before push) |
|
|
359
414
|
| 3. Squash-merge locally | yes (squash) | - | - | yes (after Step 6 removal) | yes (guarded, on the branch before squash) |
|
|
@@ -370,7 +425,7 @@ A host-owned worktree (Step 6: no `home:` match, or the legacy "Otherwise") keep
|
|
|
370
425
|
|
|
371
426
|
**Open-ended questions**
|
|
372
427
|
- **Problem:** "What should I do next?" is ambiguous
|
|
373
|
-
- **Fix:**
|
|
428
|
+
- **Fix:** Use the Step 4 subject-specific menu
|
|
374
429
|
|
|
375
430
|
**Cleaning up worktree for a PR option (1 or 2)**
|
|
376
431
|
- **Problem:** Remove worktree user needs for PR iteration
|
|
@@ -402,7 +457,7 @@ A host-owned worktree (Step 6: no `home:` match, or the legacy "Otherwise") keep
|
|
|
402
457
|
|
|
403
458
|
## Completion
|
|
404
459
|
|
|
405
|
-
Once the chosen option (Options 1-4
|
|
460
|
+
Once the chosen option (Options 1-4 or PR-subject row 1 - not Discard) is executed successfully, mark the ship phase complete:
|
|
406
461
|
|
|
407
462
|
```
|
|
408
463
|
phase_tracker({ action: "complete", phase: "ship" })
|
|
@@ -417,6 +472,7 @@ Once the merge (and any deploy) has landed, `/skill:check-delivery <ticket-ref>`
|
|
|
417
472
|
- Merge without verifying tests on result
|
|
418
473
|
- Delete work without confirmation
|
|
419
474
|
- Force-push without explicit request
|
|
475
|
+
- Force-push a PR-subject rework; follow its row 1 recipe
|
|
420
476
|
- Remove a worktree before confirming merge success
|
|
421
477
|
- Clean up worktrees you didn't create (provenance check)
|
|
422
478
|
- Retry a failed `destroy:` with `git worktree remove --force`
|
|
@@ -429,7 +485,7 @@ Once the merge (and any deploy) has landed, `/skill:check-delivery <ticket-ref>`
|
|
|
429
485
|
- Verify, or apply the Step 1 skip rule, before offering options
|
|
430
486
|
- Print the `gauntlet-telemetry-seal.mjs` output verbatim in the ship completion message
|
|
431
487
|
- Derive `$PRIMARY` and `$FEATURE` from `<worktree-path>` before presenting the menu
|
|
432
|
-
-
|
|
488
|
+
- Use the Step 4 subject-specific menu
|
|
433
489
|
- Get typed confirmation for Option 5 (Discard)
|
|
434
490
|
- Clean up worktree for Options 3 & 5 (Squash-merge, Discard) only
|
|
435
491
|
- Target `$PRIMARY` with `git -C` for merge, worktree removal, and branch deletion
|
|
@@ -83,7 +83,7 @@ loop: tracker state is extension state no subagent can read.
|
|
|
83
83
|
- A phase `in_progress` (verify or ship included - resume stops at verify on its own)
|
|
84
84
|
-> append the process-state section exactly as `## Producers` in
|
|
85
85
|
`reference/brief-contract.md` lays it out: both status outputs verbatim
|
|
86
|
-
(`No plan active.` verbatim when there is no plan), the contract's artifact-specific fields, and the gate-history line. Recognize the loop alternative by ledger line 1; read the ledger from the run worktree for its durable last decision. Use only the contract's grammar; write no second state file. Append with a single
|
|
86
|
+
(`No plan active.` verbatim when there is no plan), the contract's artifact-specific fields, and the gate-history line. Recognize the loop alternative by ledger line 1; read the ledger from the run worktree for its durable last decision. Read the run worktree's spec; when it carries `## Rework record`, copy its PR identity (without the title) and full pre-rework head into the optional fields in the contract's producer layout. Without that record, use the ordinary layout. Use only the contract's grammar; write no second state file. Append with a single
|
|
87
87
|
`cat >> "<brief path>" <<'EOF' ... EOF` whose body is that block.
|
|
88
88
|
- Re-read the file tail and confirm it ends with the gate-history line from the
|
|
89
89
|
contract and nothing after.
|
|
@@ -27,7 +27,7 @@ Headings, fixed order. A consumer keys on headings, never prose.
|
|
|
27
27
|
| `## Repo state` | one field per line: `toplevel`, `worktree: yes <path>` or `worktree: no`, `branch` (`detached` when none), `HEAD`, `base` (`unknown` when no remote resolves), `dirty: <porcelain>` or `dirty: clean`, `diff-stat` (`unavailable` when base unknown), `test cmd`; any field `unavailable` when its command failed; heading `## Repo state: not a git repo` outside git | always |
|
|
28
28
|
| `## Decisions` | bullets; rejected alternatives marked `rejected:` | always |
|
|
29
29
|
| `## Skills loaded` | frontmatter `name`s; `## Skills loaded: none` when none | always |
|
|
30
|
-
| `## Process state` | `phase_tracker status` then `plan_tracker status` verbatim; `Active task: <name|none>`; the line `Gate history not restored - re-validate before advancing.` | only when a phase is `in_progress` and no hotfix flow is in context |
|
|
30
|
+
| `## Process state` | `phase_tracker status` then `plan_tracker status` verbatim; `Active task: <name|none>`; optional `PR: <owner/repo#N>` and `Pre-rework head: <40-char sha>` lines, present together only for a PR subject; the line `Gate history not restored - re-validate before advancing.` | only when a phase is `in_progress` and no hotfix flow is in context |
|
|
31
31
|
|
|
32
32
|
For a loop ledger (line 1 exactly `# Ledger - loop engine`), replace `Active task` with these two fields, retaining both tracker status outputs and the gate-history line:
|
|
33
33
|
|
|
@@ -51,8 +51,10 @@ inline. `## Repo state` is matched by prefix: `## Repo state` or
|
|
|
51
51
|
cohort's `handoff` skill wrote, which ends at `## Skills loaded`. Layout, byte-exact:
|
|
52
52
|
one blank line, the heading on its own line, a blank line, the `phase_tracker status`
|
|
53
53
|
output verbatim, a blank line, the `plan_tracker status` output verbatim, a blank line,
|
|
54
|
-
`Active task: <name|none>`, then
|
|
55
|
-
|
|
54
|
+
`Active task: <name|none>`, then, only for a PR subject, exactly two lines:
|
|
55
|
+
`PR: <owner/repo#N>` and `Pre-rework head: <40-char sha>`, then the gate-history line -
|
|
56
|
+
unfenced, nothing after.
|
|
57
|
+
For a task plan, set `Active task` to the first `→` task name, else `none` (also for `No plan active.`). For a line-1 ledger, read its path and last decision and use the loop alternative above, retaining the optional PR pair before the gate-history line.
|
|
56
58
|
|
|
57
59
|
Example appended block (the fence is documentation; the brief carries no fence):
|
|
58
60
|
|
|
@@ -112,6 +114,15 @@ Parse stops (print the offending line, make no tracker call):
|
|
|
112
114
|
|
|
113
115
|
## Process-state restore
|
|
114
116
|
|
|
117
|
+
Before any tracker write, read the optional PR identity and fetch its branch with
|
|
118
|
+
`gh pr view <N> --repo <owner/repo> --json headRefName`. Compare `headRefName` with
|
|
119
|
+
`git -C <worktree> branch --show-current`. A mismatch stops with
|
|
120
|
+
`brief names PR #N on <headRefName>, worktree is on <branch>`, substituting the observed PR number and both actual branch names, never literal placeholders; a failed fetch stops
|
|
121
|
+
with its error. Carry the paired full pre-rework head into reconstruction's
|
|
122
|
+
candidate selection. Without the optional pair, retain ordinary restoration.
|
|
123
|
+
Preserve the entry checks, standing-grant validation, plan repair, and task snapshot;
|
|
124
|
+
PR identity implies no approval or gate evidence.
|
|
125
|
+
|
|
115
126
|
Facts that fix the order (from the extensions):
|
|
116
127
|
|
|
117
128
|
- Arming happens only on `start brainstorm`; `reset` disarms; `skip` and `complete`
|
|
@@ -129,7 +140,7 @@ Per-stage call table, keyed by the brief's active phase (`→`). Use
|
|
|
129
140
|
`R = resume: <brief file or "pasted brief">` for plan/implement/verify skips and
|
|
130
141
|
`S = resume: <spec path>` for brainstorm skips. Resolve `<spec path>` as
|
|
131
142
|
`reconstruction.md` "Candidates" does, to an absolute path under the worktree: the single
|
|
132
|
-
`*.md` spec added after base under `flowGuards.specDirs`, or a spec tracked from base when
|
|
143
|
+
`*.md` spec added after the candidate base under `flowGuards.specDirs`, or a spec tracked from that base when
|
|
133
144
|
a plan added after base pairs with it by basename. Zero specs -> stop; more than one ->
|
|
134
145
|
human picks. The consumer carries this path to its entry check 6 and its post-restore
|
|
135
146
|
announcement without re-resolving it.
|
|
@@ -147,7 +158,7 @@ For a ledger brief, pair by the ledger's path-only `**Spec:**` header, not basen
|
|
|
147
158
|
|
|
148
159
|
`planPath` (task-plan implement onward): the brief carries none. Resolve as reconstruction does
|
|
149
160
|
(`reconstruction.md`, "Candidates", including its `flowGuards.specDirs` resolution): the
|
|
150
|
-
single plan added after base, paired with `<specDir>/<same basename>` whether that
|
|
161
|
+
single plan added after the candidate base, paired with `<specDir>/<same basename>` whether that
|
|
151
162
|
spec was added after base or tracked from base (`reconstruction.md` "Candidates");
|
|
152
163
|
resolve the selected plan to an absolute path under the worktree before `plan_check`.
|
|
153
164
|
Zero pairs -> stop; more than one -> human picks.
|
|
@@ -176,7 +187,7 @@ End a turn awaiting selection, restoration, or answers with phase `plan` retaine
|
|
|
176
187
|
|
|
177
188
|
### Citation repair
|
|
178
189
|
|
|
179
|
-
Record the plan's state before any write: tracked and clean when `git -C <worktree> ls-files --error-unmatch -- <plan path>` exits 0 and `git -C <worktree> status --porcelain -- <plan path>` prints nothing (index and working copy both match HEAD; a staged edit alone makes it dirty); otherwise copy the file to a temp path outside the
|
|
190
|
+
Record the plan's state before any write: tracked and clean when `git -C <worktree> ls-files --error-unmatch -- <plan path>` exits 0 and `git -C <worktree> status --porcelain -- <plan path>` prints nothing (index and working copy both match HEAD; a staged edit alone makes it dirty); otherwise copy the file to a temp path outside the repository before citation repair writes anything. Any non-empty porcelain output, including staged-only `M <plan path>`, takes this copy path even when tracked and the working copy equals HEAD. Never substitute `git checkout` for the dirty or untracked plan's snapshot or saved-copy restore.
|
|
180
191
|
|
|
181
192
|
Classify every finding against the table by its `check` and `reason`, gathering the row's evidence first. One finding with no row -> stop (below) before any write.
|
|
182
193
|
|
|
@@ -25,6 +25,12 @@ for a base ref before reading any artifact.
|
|
|
25
25
|
|
|
26
26
|
A pinned spec (seed route, `seed.md`) skips this section.
|
|
27
27
|
|
|
28
|
+
When the brief carries `Pre-rework head:`, use that full SHA as `<base>` for spec
|
|
29
|
+
and plan candidate scans instead of the merge-base from "Base"; the PR's earlier
|
|
30
|
+
spec remains input, not an added candidate, so it does not trigger a multi-spec pick.
|
|
31
|
+
Keep pairing, untracked candidates, task evidence, and human confirmation below.
|
|
32
|
+
Without the optional pair, including a bare worktree, use the ordinary base.
|
|
33
|
+
|
|
28
34
|
Resolve with `gauntlet_setting({ key: "flowGuards" })`; `<dirs>` below is its `specDirs` plus `planDirs` (each spec dir's sibling `plans` dir), space-separated.
|
|
29
35
|
|
|
30
36
|
```bash
|
|
@@ -17,7 +17,7 @@ Git worktrees create isolated workspaces sharing the same repository, allowing w
|
|
|
17
17
|
|
|
18
18
|
## Step 0 — Detect Existing Isolation (REQUIRED)
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
For a caller passing resolved PR values, read [reference/pr-head.md](reference/pr-head.md) now and follow it instead of Steps 0 and 1, before generic linked-worktree reuse. For every other caller, check whether you are **already** inside an isolated worktree. Creating a worktree inside another worktree, or inside a submodule, produces silent corruption.
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
read -r GIT_DIR GIT_COMMON <<<"$(git rev-parse --path-format=absolute --git-dir --git-common-dir | tr '\n' ' ')"
|
|
@@ -44,7 +44,7 @@ Use `$WORKTREE`, report it in the Step 4 shape (`Worktree ready at <that path>`)
|
|
|
44
44
|
|
|
45
45
|
## Step 1 — Announce, Don't Ask (skill-driven work defaults to a worktree)
|
|
46
46
|
|
|
47
|
-
For gauntlet-driven work — brainstorming, plans, implementation — the worktree is the default, not a question. Announce and proceed:
|
|
47
|
+
For a PR head, use [reference/pr-head.md](reference/pr-head.md) instead of this step. For gauntlet-driven work — brainstorming, plans, implementation — the worktree is the default, not a question. Announce and proceed:
|
|
48
48
|
|
|
49
49
|
> "Setting up an isolated worktree at `<path>` on branch `<branch>` for this work."
|
|
50
50
|
|
|
@@ -177,7 +177,7 @@ If `git symbolic-ref -q HEAD` returns nothing, you're on a detached HEAD. Do not
|
|
|
177
177
|
|
|
178
178
|
## Keeping a Worktree Current
|
|
179
179
|
|
|
180
|
-
For longer-running work the base branch advances:
|
|
180
|
+
For a PR-subject branch, follow [reference/pr-head.md](reference/pr-head.md): merge `origin/<baseRefName>`; never rebase it. For other longer-running work the base branch advances:
|
|
181
181
|
|
|
182
182
|
```bash
|
|
183
183
|
git -C "$WORKTREE" fetch origin
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# PR-head worktree
|
|
2
|
+
|
|
3
|
+
## Select home and stop before writes
|
|
4
|
+
|
|
5
|
+
For a caller passing PR values, follow this reference instead of `using-git-worktrees/SKILL.md` Steps 0 and 1. Derive ROOT from the absolute git common directory as in Step 0, applying its submodule guard. Resolve the worktree home through the existing overrides/native-tool/wrapper contract; default to `$ROOT/.worktrees/<name>`. Set `<name>` to `headRefName` with every `/` replaced by `-`. Never adopt the session's linked tree unless it is the selected home on `headRefName`.
|
|
6
|
+
|
|
7
|
+
Run `git -C "$ROOT" fetch origin`, then check these stops in order before creating or modifying any file in the primary or a worktree, or running `git worktree add`.
|
|
8
|
+
|
|
9
|
+
| Observable case | Exact stop |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `isCrossRepository` true | `PR #N's head lives on fork <headRepository.nameWithOwner>; rework needs an in-repo branch.` |
|
|
12
|
+
| `headRefName` listed by `git -C "$ROOT" worktree list --porcelain` at another path, including `.worktrees/pr-<N>` | `branch <headRefName> is checked out at <path>; finish or remove that worktree first.` |
|
|
13
|
+
| `git -C "$ROOT" rev-parse --verify -q <headRefOid>^{commit}` fails after fetch, or `origin/<headRefName>` differs from `headRefOid` | `PR #N head <headRefOid7> is not reachable (origin/<headRefName> is at <sha7>); the branch moved.` |
|
|
14
|
+
| Local branch exists and `git -C "$ROOT" merge-base --is-ancestor <headRefName> origin/<headRefName>` exits 1 | `local branch <headRefName> is at <sha7>, not an ancestor of origin/<headRefName> (<sha7>); rework needs the PR head.` |
|
|
15
|
+
|
|
16
|
+
## Provision the exact head
|
|
17
|
+
|
|
18
|
+
Apply the first matching row after all stops pass. Keep the process cwd unchanged and carry WORKTREE as a value.
|
|
19
|
+
|
|
20
|
+
| State | Action |
|
|
21
|
+
|---|---|
|
|
22
|
+
| Selected home is already on `headRefName` | Run Step 3's dirty-tree ask first; do not stash or clean automatically. Then run `git -C "$WORKTREE" merge --ff-only origin/<headRefName>` and require HEAD equal to `headRefOid`; otherwise stop naming both SHAs. |
|
|
23
|
+
| No worktree, local branch exists | Only after ancestry proof, run `git -C "$ROOT" update-ref refs/heads/<headRefName> origin/<headRefName>`, then `git -C "$ROOT" worktree add "<home>" <headRefName>`. Never use `git -C "$ROOT" branch -f`. |
|
|
24
|
+
| No worktree, no local branch | Run `git -C "$ROOT" worktree add "<home>" <headRefName>`. Git's unique-remote DWIM resolves exactly one matching remote-tracking branch as `--track -b <headRefName> "<home>" origin/<headRefName>`; do not substitute the generic new-branch `-b` creation path. |
|
|
25
|
+
|
|
26
|
+
For fresh creation, apply Step 3's source-clean ask and the existing home safety checks after the ordered stops. Respect the resolved home and native tool/wrapper, but use an overrides `create:` only when it takes `<branch>` as an existing branch and contains no `-b`/`-B`. Otherwise run the built-in checkout above and add `create: override skipped (contains -b)` to the report. Resolve tokens and surface wrapper failures through the existing contract.
|
|
27
|
+
|
|
28
|
+
Verify `git -C "$WORKTREE" rev-parse HEAD` equals `headRefOid`. On a post-create head race, leave the tree intact and stop naming its path and both SHAs. Capture `PRE_REWORK_HEAD=<headRefOid>` and `BASE_SHA=$(git -C "$ROOT" rev-parse origin/<baseRefName>)` as full SHAs. In the Step 4 report use `Base: <headRefName> @ <sha7>` and add immediately after it:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
PR: <owner/repo#N>
|
|
32
|
+
Pre-rework head: <sha>
|
|
33
|
+
Base SHA: <sha7>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Preserve pre-rework history
|
|
37
|
+
|
|
38
|
+
Advance by merge: preserve every commit reachable from PRE_REWORK_HEAD. Never `git rebase`, or use `reset` or `commit --amend` to replace a commit at or below that boundary. Keep the flow's appended-spec approval `commit --amend --no-edit` in `brainstorming/reference/spec-finalization.md` and appended-wave fold `reset --soft "$WAVE_BASE_SHA"` in `subagent-driven-development/SKILL.md` unchanged; require WAVE_BASE_SHA to descend from PRE_REWORK_HEAD.
|
|
39
|
+
|
|
40
|
+
## Merge the fetched base
|
|
41
|
+
|
|
42
|
+
Run `git -C "$WORKTREE" merge --no-ff --no-edit origin/<baseRefName>` and record the matching outcome:
|
|
43
|
+
|
|
44
|
+
| Outcome | Record and continuation |
|
|
45
|
+
|---|---|
|
|
46
|
+
| Base already an ancestor | `merge: no-op - head contains origin/<base>`; no commit. |
|
|
47
|
+
| Clean merge | `merge: <sha7>`; this merge is the first rework commit. |
|
|
48
|
+
| Conflicts | Follow the helper recipe below. |
|
|
49
|
+
|
|
50
|
+
Snapshot `git -C "$WORKTREE" status --porcelain` before helper dispatch. Get conflicted paths with `git -C "$WORKTREE" diff --name-only --diff-filter=U`. Dispatch one fresh foreground `implementer`, `cwd` the worktree, `async: false`, with that exact file list, fetched base, and SCOPED_TEST_COMMANDS. Require resolution of every listed file preserving both sides' intent, exactly the supplied scoped commands, and `git -C "$WORKTREE" add` for every resolved file. Require return `done`, or `done - contract exception: <why>` when resolution changes a PR or bound-ticket obligation. Forbid helper commits, aborts, and edits outside the list.
|
|
51
|
+
|
|
52
|
+
Read the first-found overrides file from BASE_SHA, not the conflicted tree: `git -C "$ROOT" show <BASE_SHA>:<overrides path>`. Use SCOPED_TEST_COMMANDS only from a documented file-scoped runner under `## PR gate` or `## verification-before-completion` with `requires credentials` not `true`. Missing runner or `requires credentials: true` means `none`, with the reason recorded as `none run (<reason>)`. Never infer file scope from a full-suite script such as `npm test`.
|
|
53
|
+
|
|
54
|
+
Continue only with an empty unmerged index (`git -C "$WORKTREE" diff --name-only --diff-filter=U`), every listed file staged (`git -C "$WORKTREE" diff --cached --name-only`), and the `git -C "$WORKTREE" status --porcelain` delta contained in the listed paths. Then complete with `git -C "$WORKTREE" commit --no-edit` and record `merge: <sha7>, <n> file(s) resolved, scoped tests <green | red in <file>: <tests> | none>`. Land a reported contract exception and name it in the spec's `## Rework record` `Changes:`.
|
|
55
|
+
|
|
56
|
+
For any failed helper/completion checks, run `git -C "$WORKTREE" merge --abort`, record `merge: unresolved - <files>`, and continue on the original unmerged head. Open the spec's Design with `merge origin/<base> and resolve <files>` as eventual Task 1. On every outcome, require the base-SHA constraint reads owned by `brainstorming/reference/pr-subject.md`.
|
|
57
|
+
|
|
58
|
+
Treat this merge, helper edits to the conflict list, and scoped conflict tests as the sole preapproval write/run exception outside spec directories. Run no other brainstorming tests, dispatch no reviewer, and push nothing; leave review of the merge to end-of-flow code review.
|
|
59
|
+
|
|
60
|
+
## Fetch unresolved review threads
|
|
61
|
+
|
|
62
|
+
Run this query; callers cite this owner rather than copying it:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
gh api graphql --paginate -f query='query($o:String!,$r:String!,$n:Int!,$endCursor:String){repository(owner:$o,name:$r){pullRequest(number:$n){reviewThreads(first:100,after:$endCursor){pageInfo{hasNextPage endCursor} nodes{id isResolved isOutdated path line originalLine comments(first:100){pageInfo{hasNextPage endCursor} totalCount nodes{url body author{login} createdAt}}}}}}}' -F o=<owner> -F r=<repo> -F n=<N>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Merge every reviewThreads page and filter to `isResolved == false`. For each thread whose comments report `hasNextPage: true` (with `totalCount` exceeding the first page), fetch the remaining pages by thread id with a separate comment cursor:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
gh api graphql --paginate -f query='query($id:ID!,$endCursor:String){node(id:$id){... on PullRequestReviewThread{comments(first:100,after:$endCursor){pageInfo{hasNextPage endCursor} nodes{url body author{login} createdAt}}}}}' -F id=<thread id>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Start that thread's follow-up query at its first comment page, then replace its initial comments with the complete paginated connection to avoid duplicates. Keep each thread's comment cursor separate from the reviewThreads cursor and fetch until its last page. Carry all comments in order: read the first request and every reply because replies can change the request. Render location as `<path>:<line>`, else `<path>:<originalLine> (outdated)`, else `<path>`. On fetch failure carry `threads: not fetched (<reason>)` to the gather draft and `Threads: not fetched (<reason>)` to the record; continue. On successful empty fetch record `Threads: none`.
|
|
@@ -46,7 +46,7 @@ BEFORE claiming any status or expressing satisfaction:
|
|
|
46
46
|
Skip any step = lying, not verifying
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
Evidence is proportionate to the claim: a task or wave claim is proven by the commands the plan declares for it
|
|
49
|
+
Evidence is proportionate to the claim: a task or wave claim is proven by the commands the plan declares for it - a scoped run is **complete** evidence for a scoped claim. For phase-completion and ship claims, use the project's full verification entrypoint (tests + style + format), run once at verify before the conformance gate. For an approved spec carrying `## Rework record`, instead prove the scoped claim with the union of every plan task's `Tests:` commands plus the header's documented lint and format commands; treat `none - PR subject, scoped` as no header command, not an executable command. Keep freshness, conformance and phase gates intact; an open PR without that spec record does not select this policy.
|
|
50
50
|
|
|
51
51
|
## Common Failures
|
|
52
52
|
|
|
@@ -160,6 +160,8 @@ Defaults recognise `make ci`, `make test`, `npm test`, `pnpm test`, `yarn test`,
|
|
|
160
160
|
|
|
161
161
|
Before running the verification gate, call `phase_tracker({ action: "start", phase: "verify" })`.
|
|
162
162
|
|
|
163
|
+
Run the plan header's full verification command set at verify. For an approved spec carrying `## Rework record`, instead run the union of every task's `Tests:` commands plus the header's documented lint and format commands, omitting task `none:` entries and the non-executable header sentinel `none - PR subject, scoped`. Read all task blocks, including the merge task; the lint/format-only header alone is not the verification set. Do not run the full test entrypoint on this PR-subject path or copy task commands into the header. Keep ordinary ticket/free-text verification unchanged and pass through the same freshness, conformance and phase gates; change no settings, runner or implement-phase gate.
|
|
164
|
+
|
|
163
165
|
When all verification passes, finish and await the required `plan_tracker` updates before marking verify complete. Reconcile accepted work on its existing indices; never clear or reinitialize to obtain closure. In a direct verification path, complete only after those updates have actually returned.
|
|
164
166
|
|
|
165
167
|
```
|
|
@@ -178,12 +178,16 @@ Each step is **one action, 2-5 minutes**:
|
|
|
178
178
|
---
|
|
179
179
|
```
|
|
180
180
|
|
|
181
|
+
**PR-subject header.** Detect a PR subject only from `## Rework record` in the approved spec. For that subject, replace the header's full verification command set with only the overrides' documented lint and format commands. With neither documented, write `**Verification:** none - PR subject, scoped`; this sentinel is not a command. Keep every task's `Tests:` command out of the header: copying it there makes it a full-suite duplicate rejected by `plan_check`. Keep the original spelling; resolve duplication by separating the task tests from header lint/format, not by disguising commands. Read the PR specialization in [reference/plan-contract.md](reference/plan-contract.md#pr-subject-verification).
|
|
182
|
+
|
|
181
183
|
The full verification entrypoint appears only on the `**Verification:**` line — see [reference/plan-contract.md § Header-only entrypoint](reference/plan-contract.md). The verify phase reads it from the plan; execution runs `Tests:` commands only. Execution runs it in the worktree via the subshell form `(cd "<abs worktree path>" && <command>)`; the process cwd stays in the primary checkout, and dispatch `cwd` is the worktree path. The `**Happy path:**` line is optional: present only when File Structure selected a row, with the row label, the row's command in backticks, and the row's `Timeout` as `(~<duration>)` (omit the suffix when the cell is absent or malformed). Like `Verification`, the happy-path command appears only on this header line - never in a task's `Tests:` or `Run:` block and never as free text in wave scope; `plan_check` enforces both.
|
|
182
184
|
|
|
183
185
|
## Task Structure
|
|
184
186
|
|
|
185
187
|
Each task uses `- [ ]` checkbox steps so execution tools (and humans) can track progress.
|
|
186
188
|
|
|
189
|
+
**PR-subject tasks.** Read the approved spec's `## Rework record`. When its base merge is `unresolved`, make merging the named base and resolving the listed files Task 1, before thread fixes; preserve the original commits. Make each `fix` thread exactly one task whose title carries that thread id. Name the thread's request in its `Tests:` block through the scoped command and `via:` seam that exercises it. Keep `keep open` and `decline: <reason>` as recorded dispositions, not repair tasks. Apply the existing file-disjoint wave, spec-anchor, baseline and checker rules to these tasks without changing executor or spec-commit mechanics.
|
|
190
|
+
|
|
187
191
|
```markdown
|
|
188
192
|
### Task N: [Component Name]
|
|
189
193
|
|
|
@@ -276,7 +280,7 @@ If a decision is genuinely open, put it in an explicit **Open Questions** sectio
|
|
|
276
280
|
The plan-writer runs Baseline, the deterministic checker, then the judgment checks before replying.
|
|
277
281
|
|
|
278
282
|
- **Baseline.** Execute the numbered procedure below for task `Tests:` commands only; leave header `**Verification:**` to verify. Never author baseline evidence without execution.
|
|
279
|
-
1. Read provenance: `BASE=$(git -C "<abs worktree path>" rev-parse --short HEAD)` and `git -C "<abs worktree path>" status --porcelain --untracked-files=all`. Match every `XY <path>` entry (including `??`) against the worktree-relative plan and spec paths, plus only the parent-supplied `In-flight:` paths on an `Amend:` re-dispatch; never infer that set. Also allow untracked paths already recorded in existing baseline bullets' ` - artifacts:` suffixes in the plan at the plan path, excluding every plan `Create:` or `Test:` path. Keep those suffixes on retained bullets. Any other entry blocks all commands: collect `- Baseline: worktree dirty on <BASE>: <paths>`. Allowed in-flight paths outside the spec and plan directories are source edits: collect `- Baseline: in-flight source edits on <BASE>: <paths>` and run nothing. Allow doc-only workflow edits. For plain jj (no `.git`, VCS kind `jj`), use `BASE=$(jj -R "<abs worktree path>" log -r @- --no-graph -T 'commit_id.short()')` and `jj -R "<abs worktree path>" diff --summary`; classify one-letter status and relative paths identically (`A` includes new files). Never revert or clean anything.
|
|
283
|
+
1. Read provenance: `BASE=$(git -C "<abs worktree path>" rev-parse --short HEAD)` and `git -C "<abs worktree path>" status --porcelain --untracked-files=all`. Match every `XY <path>` entry (including `??`) against the worktree-relative plan and spec paths, plus only the parent-supplied `In-flight:` paths on an `Amend:` re-dispatch; never infer that set. Also allow untracked paths already recorded in existing baseline bullets' ` - artifacts:` suffixes in the plan at the plan path, excluding every plan `Create:` or `Test:` path. Keep those suffixes on retained bullets. Any other entry blocks all commands: collect `- Baseline: worktree dirty on <BASE>: <paths>`. Allowed in-flight paths outside the spec and plan directories are source edits: collect `- Baseline: in-flight source edits on <BASE>: <paths>` and run nothing. Allow doc-only workflow edits. For plain jj (no `.git`, VCS kind `jj`), use `BASE=$(jj -R "<abs worktree path>" log -r @- --no-graph -T 'commit_id.short()')` and `jj -R "<abs worktree path>" diff --summary`; classify one-letter status and relative paths identically (`A` includes new files). Never revert or clean anything. Record a short baseline provenance note with the initial per-file inventory, BASE, and which exact paths were admitted before running commands; retain it even when a later run is contaminated or blocked.
|
|
280
284
|
2. On Findings/Amend, retain a bullet only for unchanged command text on the same base; rerun commands with missing/invalid bullets, changed text, or different recorded SHA. `Findings: rerun baseline` reruns all commands. Never rewrite recorded SHAs without execution. For each command, split on the contract's separators (`&&`, `||`, `;`, `|`) and classify anchor tokens (a `Test:` path alone or with `::`/`#`/`:` filters) and selectors independently:
|
|
281
285
|
|
|
282
286
|
| Command anchors/selectors | Baseline action |
|
|
@@ -47,6 +47,10 @@ The header value's backtick spans (else the raw value) are split on `&&`, `||`,
|
|
|
47
47
|
|
|
48
48
|
The optional `**Happy path:**` line's backticked command is a second header entrypoint under the same rule: its segments join the header segment set, and its whole command may not appear in wave prose.
|
|
49
49
|
|
|
50
|
+
## PR-subject verification
|
|
51
|
+
|
|
52
|
+
Detect this specialization only from `## Rework record` in the approved spec. Put only the overrides' documented lint and format commands in `**Verification:**`, or the literal `none - PR subject, scoped` when neither is documented. Treat the sentinel as no header command. Keep scoped tests in task `Tests:` blocks, never copy them into the header or change their spelling to evade `header-entrypoint` or `tests-block` rejection. Retain baseline evidence and all existing checker grammar. At verify, run the union of every task's `Tests:` commands plus the header's lint/format commands; omit `none:` entries and the sentinel from executable commands. This policy specializes the command set, not freshness, conformance or phase gates. Without the record, keep the ordinary full verification entrypoint.
|
|
53
|
+
|
|
50
54
|
## Happy path line (`header-happy-path`)
|
|
51
55
|
|
|
52
56
|
Optional. When present, the header line reads `**Happy path:** <label> - \`<command>\`` with an optional ` (~<duration>)` suffix, `<duration>` matching `\d+(s|m|h)`. A present line that does not parse is a finding; absence is never a finding. The label names the row of the overrides file's `## Happy path` table the plan selected; the verify phase reads the line from the plan and re-derives the row from the real diff.
|