pi-gauntlet 5.18.7 → 5.20.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.
@@ -181,9 +181,11 @@ Rows 1-2 run the Option 1/2 blocks; row 3 runs the Keep block and row 4 the Disc
181
181
 
182
182
  ### Step 5: Execute Choice
183
183
 
184
- #### Strip the plan, keep the record (Options 1-3)
184
+ #### Strip the plan, seal the record (Options 1-3)
185
185
 
186
- Run this on the feature branch before any landing path. The spec and its telemetry record (`<telemetry.dir>/<spec path with .md -> .yaml>`, default `.pi/gauntlet/telemetry/doc/specs/<spec>.yaml`) are deliverables and ship in the squash; only the plan is stripped. `<bin>` is `<directory of this skill's SKILL.md>/../../bin`, resolved from the skill's `<location>` in the system prompt.
186
+ Run this on the feature branch before any landing path. The spec and its telemetry record (`<telemetry.dir>/<spec path with .md -> .yaml>`, default `.pi/gauntlet/telemetry/doc/specs/<spec>.yaml`) are deliverables and ship in the squash; only the plan is stripped. The record is an untracked, git-excluded file until this step commits it. `<bin>` is `<directory of this skill's SKILL.md>/../../bin`, resolved from the skill's `<location>` in the system prompt.
187
+
188
+ Read the plan's `**Spec:**` header (repo-relative, backticks stripped) before the strip; that value is `--spec`.
187
189
 
188
190
  ```bash
189
191
  # Plans are ephemeral - if one was committed on this branch, remove it before landing.
@@ -192,15 +194,16 @@ if git -C "$WORKTREE" ls-files --error-unmatch "$PLAN_PATH" >/dev/null 2>&1; the
192
194
  git -C "$WORKTREE" rm "$PLAN_PATH" && git -C "$WORKTREE" commit -m "Remove ephemeral plan doc"
193
195
  fi
194
196
 
195
- # The telemetry record is a deliverable - restore it if a strip or a stray delete removed it.
196
- node <bin>/gauntlet-telemetry-salvage.mjs --worktree "$WORKTREE" --base <base-branch>
197
+ # Seal the telemetry record: stamp shipped, compute the diff, commit it once.
198
+ # --option is pr for Options 1-2 and squash for Option 3; --spec is the plan header's **Spec:** value (omit when no plan is known).
199
+ node <bin>/gauntlet-telemetry-seal.mjs --worktree "$WORKTREE" --option <pr|squash> --base <base-branch> --spec <spec path>
197
200
  ```
198
201
 
199
- The salvage prints one line per spec on the branch (`present`, `present <path> (marked shipped)`, `restored <path> from <sha>`, `restored <path> from <sha> (marked shipped)`, `no telemetry run`, `never written`, `restore failed <path>: <reason>`) and always exits 0. `(marked shipped)` means the record was still `in_progress` with no ship phase (the recorder lost its binding) and the salvage committed `status: shipped` + `shipped_at` as one `telemetry:` commit; it rides the squash or push like any branch commit. Print its stdout verbatim in the ship completion message. A `restore failed` line is reported, never retried, and never blocks the ship - the record stays recoverable from the branch ref.
202
+ 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 failure (`seal failed <path>: <reason>` restored the pre-seal bytes). The user decides; never land without the seal.
200
203
 
201
204
  #### Option 1: Push and Create PR
202
205
 
203
- Run the strip-and-salvage block above first (plan stripped, telemetry record kept), then:
206
+ Run the strip-and-seal block above first (plan stripped, telemetry record sealed), then:
204
207
 
205
208
  ```bash
206
209
  # Push branch
@@ -231,11 +234,11 @@ When the spec's `## Acceptance criteria` has at least one `venue:` or `deferred:
231
234
 
232
235
  #### Option 2: Push and Create Draft PR
233
236
 
234
- Run the strip-and-salvage block above first (plan stripped, telemetry record kept), then Option 1's push and `gh pr create` commands with `--draft` added. The PR body is unchanged. Do not clean up the worktree.
237
+ Run the strip-and-seal block above first (plan stripped, telemetry record sealed), then Option 1's push and `gh pr create` commands with `--draft` added. The PR body is unchanged. Do not clean up the worktree.
235
238
 
236
239
  #### Option 3: Squash-merge to base
237
240
 
238
- Run the strip-and-salvage block above first (plan stripped, telemetry record kept), then:
241
+ Run the strip-and-seal block above first (plan stripped, telemetry record sealed), then:
239
242
 
240
243
  ```bash
241
244
  git -C "$PRIMARY" checkout <base-branch>
@@ -245,7 +248,7 @@ git -C "$PRIMARY" commit -m "<imperative summary> (ref <ticket-id>)"
245
248
  (cd "$PRIMARY" && <the Step 1 set>)
246
249
  ```
247
250
 
248
- The plan was already removed on the branch, so the staged squash tree carries the spec, the telemetry record, and the implementation - never the plan.
251
+ The plan was already removed and the telemetry record sealed on the branch, so the staged squash tree carries the spec, the telemetry record, and the implementation - never the plan.
249
252
 
250
253
  The post-squash re-verify is not optional - `git merge --squash` can surface conflict-resolution mistakes the worktree-side run couldn't catch.
251
254
 
@@ -255,7 +258,7 @@ Cleanup worktree (Step 6), then, if Step 6 removed the worktree, `git -C "$PRIMA
255
258
 
256
259
  #### Option 4: Keep As-Is
257
260
 
258
- Report: "Keeping branch <name>. Worktree preserved at <path>."
261
+ Report: "Keeping branch <name>. Worktree preserved at <path>." The telemetry record stays untracked and in_progress in the worktree; a later finishing run on this worktree seals it.
259
262
 
260
263
  **Don't cleanup worktree.**
261
264
 
@@ -273,7 +276,7 @@ Type 'discard' to confirm.
273
276
 
274
277
  Wait for exact confirmation.
275
278
 
276
- If confirmed: Cleanup worktree (Step 6), then, if Step 6 removed the worktree, `git -C "$PRIMARY" branch -D "$FEATURE"`.
279
+ If confirmed: Cleanup worktree (Step 6), then, if Step 6 removed the worktree, `git -C "$PRIMARY" branch -D "$FEATURE"`. The record is git-excluded, so git worktree remove needs no --force; it goes with the worktree.
277
280
 
278
281
  ### Step 6: Cleanup Workspace
279
282
 
@@ -294,7 +297,7 @@ Removal precedes branch deletion in both options; `git branch -d`/`-D` fails whi
294
297
 
295
298
  ## Quick Reference
296
299
 
297
- | Option | Merge | Push | Keep Worktree | Cleanup Branch | Plan strip + record salvage |
300
+ | Option | Merge | Push | Keep Worktree | Cleanup Branch | Plan strip + record seal |
298
301
  |---|---|---|---|---|---|
299
302
  | 1. Create PR | - | yes | yes | - | yes (guarded, on the branch before push) |
300
303
  | 2. Create draft PR | - | yes | yes | - | yes (guarded, on the branch before push) |
@@ -334,13 +337,13 @@ A host-owned worktree (Step 6 "Otherwise") keeps both the worktree and the branc
334
337
  - **Problem:** Accidentally delete work
335
338
  - **Fix:** Require typed "discard" confirmation
336
339
 
337
- **Skipping the strip-and-salvage block in Options 1-3 (any path that lands on base)**
340
+ **Skipping the strip-and-seal block in Options 1-3 (any path that lands on base)**
338
341
  - **Problem:** Plan docs are ephemeral and shouldn't land on `<base-branch>`; the telemetry record is a deliverable and must. Skipping the block ships the plan, or drops the record the spec index reads.
339
342
  - **Fix:** Run the block on `$WORKTREE` before the squash or the push. The plan stays in the branch's git history (`git -C "$PRIMARY" log --all -- doc/plans/...`). Spec and telemetry record stay on `<base-branch>`; plan does not.
340
343
 
341
344
  **Widening the plan strip to the telemetry record**
342
345
  - **Problem:** `.pi/gauntlet/telemetry/**` looks like scaffolding next to the plan and gets deleted in the same commit - main then has no record for the run.
343
- - **Fix:** Never `git rm` under the telemetry dir. The salvage restores a stripped record, but the deletion should not happen in the first place.
346
+ - **Fix:** Never `git rm` under the telemetry dir. Until the seal the record is untracked and git-excluded, so a plan strip cannot reach it; after the seal it is a committed deliverable.
344
347
 
345
348
  ## Completion
346
349
 
@@ -363,12 +366,12 @@ Once the merge (and any deploy) has landed, `/skill:check-delivery <ticket-ref>`
363
366
  - Clean up worktrees you didn't create (provenance check)
364
367
  - Run any step without the `<worktree-path>` argument
365
368
  - Auto-proceed past an undispositioned carried-open gap
366
- - Skip the strip-and-salvage block before the Option 3 squash or the Option 1/2 push
369
+ - Skip the strip-and-seal block before the Option 3 squash or the Option 1/2 push
367
370
  - Delete the telemetry record (`.pi/gauntlet/telemetry/**` or the configured `telemetry.dir`) on any path
368
371
 
369
372
  **Always:**
370
373
  - Verify, or apply the Step 1 skip rule, before offering options
371
- - Print the `gauntlet-telemetry-salvage.mjs` output verbatim in the ship completion message
374
+ - Print the `gauntlet-telemetry-seal.mjs` output verbatim in the ship completion message
372
375
  - Derive `$PRIMARY` and `$FEATURE` from `<worktree-path>` before presenting the menu
373
376
  - Present exactly 5 options (or 4 for detached HEAD)
374
377
  - Get typed confirmation for Option 5 (Discard)
@@ -67,19 +67,6 @@ Orchestrator step.
67
67
  local reproduction, never implying the local command ran; `<sha>` is the assessed
68
68
  `headRefOid`, `<url>` degrades to `unavailable` when absent. Provenance checks on
69
69
  `worktree_root`/`run_cwd` bind only to the local path.
70
- - **Telemetry record:** run
71
- `node <bin>/gauntlet-telemetry-salvage.mjs --worktree <provisioned path> --base
72
- origin/<baseRefName> --check`. The `--check` flag makes the probe detect-only: it
73
- never mutates. `present` / `no telemetry run` / `never written` land in
74
- `## Evidence` as one line each. `stripped <path> in <sha>` mints a blocking `P#`
75
- (`source_ref`: `gauntlet-telemetry-salvage`) whose drafted fix is "run the salvage
76
- without `--check`" - the spec and its telemetry record are deliverables that ship
77
- in the squash. On a cell with no push row (fork overlay, report-only states) the
78
- same finding is a non-blocking follow-up instead: the record stays recoverable
79
- from the PR head ref after merge, and blocking would stop a ship the gate cannot
80
- repair. `unfinished <path>` (record still `in_progress` with no ship phase) also
81
- lands in `## Evidence` as one line and is non-blocking: pre-landing `in_progress`
82
- is normal, and the merge course's salvage run stamps it.
83
70
  - **Evidence:** on the CI path, list each satisfying check's name, conclusion,
84
71
  assessed SHA, and run URL - there is no command or `raw_tail` to paste. On the
85
72
  local path, paste each run's `command` and `raw_tail` verbatim, fenced - never
@@ -12,8 +12,7 @@ Actions (compose freely in the custom row):
12
12
  reviewed doc edits exist
13
13
  in the worktree)
14
14
  merge-squash | merge-commit (preconditions per Verdict;
15
- never bundled with a push,
16
- except the telemetry: restore commit)
15
+ never bundled with a push)
17
16
  merge-squash anyway | merge-commit anyway (custom row only: overrides a
18
17
  reviewer-withheld merge - the literal
19
18
  `anyway` accepts the named reason;
@@ -14,17 +14,17 @@ For a `fix <set>` selection, filter the selected set to worktree-fixable `P#`s f
14
14
 
15
15
  Batch the remaining worktree-fixable set by the union of files each finding's drafted edit in `## Drafted fixes / review` touches - fall back to the `source_ref` file only when a finding has no draft. Findings whose drafts share a file share a batch.
16
16
 
17
- Use one child contract for every batch, whether there is one or many: dispatch `implementer` children with `subagent({ agent: "implementer", context: "fresh", cwd: <PR worktree> })`. The orchestrator owns commit, gate, and push - never a child. Every dispatched child gets `cwd` = the PR worktree; `worktree: true` is forbidden per `assessment.md` `## Inline-first execution`. Each child is edit-only - no git commands, no verification runs - and must never delete `.pi/gauntlet/telemetry/**` or anything under the configured telemetry dir (a fix that "cleans up" the run's telemetry record is a defect in the fix, not a cleanup). Each child's task is that batch's `P#` lines plus the drafted edit already keyed to each ID in `## Drafted fixes / review` - the child applies the consented payload, it does not re-solve the finding.
17
+ Use one child contract for every batch, whether there is one or many: dispatch `implementer` children with `subagent({ agent: "implementer", context: "fresh", cwd: <PR worktree> })`. The orchestrator owns commit, gate, and push - never a child. Every dispatched child gets `cwd` = the PR worktree; `worktree: true` is forbidden per `assessment.md` `## Inline-first execution`. Each child is edit-only - no git commands, no verification runs. Each child's task is that batch's `P#` lines plus the drafted edit already keyed to each ID in `## Drafted fixes / review` - the child applies the consented payload, it does not re-solve the finding.
18
18
 
19
19
  At a cutoff of 2 worktree-fixable findings or fewer, the orchestrator applies the fix inline instead of dispatching - the no-cohort path stays available at any batch count per `assessment.md` `## Inline-first execution`. Past that cutoff, when more than one batch results, dispatch the batches' children in parallel, all under the same contract.
20
20
 
21
- Once every dispatched or inline batch returns, commit the golden course as one local commit set - the code fixes plus any already-applied reviewed doc edits selected alongside them (one commit, or one per batch sequentially; subjects name the fixes). Re-resolve the evidence for the new head once (the brief's stale-head row: prior evidence is stale; the local command executes only on a fallback/opt-out resolution). Before the push, run `node <bin>/gauntlet-telemetry-salvage.mjs --worktree <provisioned path> --base origin/<baseRefName>` (no `--check`); a `restored` or `(marked shipped)` commit rides the wave's single push and the pushed SHA becomes the assessed head under the course's-own-push rule in `### Compare-and-swap`. Print its stdout in the re-rendered report's `## Evidence`. On green, push once - gate and push are per-wave invariants, never per-fix or per-batch. On red, do not push: leave the commit(s) local, re-render with the unresolved `P#`s still open, and warn that unpushed fix commits sit in the worktree exactly like unpushed doc edits (per `### Teardown`).
21
+ Once every dispatched or inline batch returns, commit the golden course as one local commit set - the code fixes plus any already-applied reviewed doc edits selected alongside them (one commit, or one per batch sequentially; subjects name the fixes). Re-resolve the evidence for the new head once (the brief's stale-head row: prior evidence is stale; the local command executes only on a fallback/opt-out resolution). On green, push once - gate and push are per-wave invariants, never per-fix or per-batch. On red, do not push: leave the commit(s) local, re-render with the unresolved `P#`s still open, and warn that unpushed fix commits sit in the worktree exactly like unpushed doc edits (per `### Teardown`).
22
22
 
23
23
  Doc fixes (`push-docs` alone) follow the same rule: stage and commit (subject names what is documented), re-run the gate, and push only on green. Execute reviews, replies, and tracker actions via `gh pr review` / `gh api` / the tracker tool, non-interactively, with the drafted payload for the selected IDs.
24
24
 
25
25
  ### Merge course
26
26
 
27
- Merge always executes as `gh pr merge --match-head-commit <assessed-sha>`. Push and merge are never bundled into one selection, with one scoped exception: the selected merge course first runs the salvage (no `--check`) via `node <bin>/gauntlet-telemetry-salvage.mjs --worktree <provisioned path> --base origin/<baseRefName>`. `present` -> merge as-is. `restored <path> from <sha>` -> push that single `telemetry: restore` commit as part of this course, re-fetch `headRefOid`, and pass the new SHA to `--match-head-commit`. A line ending `(marked shipped)` (`present` or `restored`) is handled the same way: push that single `telemetry:` commit, re-fetch `headRefOid`, and pass the new SHA. `restore failed` -> merge proceeds, the reason is printed, and the follow-up names recovery from the PR head ref. A merge selection while any precondition (SKILL.md `## Verdict`) fails is refused, naming the failing precondition, and the menu re-renders - never a dead end, never a silent merge.
27
+ Merge always executes as `gh pr merge --match-head-commit <assessed-sha>`. Push and merge are never bundled into one selection. A merge selection while any precondition (SKILL.md `## Verdict`) fails is refused, naming the failing precondition, and the menu re-renders - never a dead end, never a silent merge.
28
28
 
29
29
  ### Re-render
30
30
 
@@ -18,7 +18,7 @@ The CLI parses and aggregates; you reason. Never open a telemetry YAML record yo
18
18
 
19
19
  ## Read the digest
20
20
 
21
- `runs` has one row per record; `shipped*` marks a truncated run (no ship phase recorded - salvage stamped it at landing; its `wall` is `-` and it feeds no aggregate). `by version` groups by pi-gauntlet version: `n` counts every row, `shipped` counts the rows behind the p50/max columns. `grants` is `fix_round_grants` - the fix-round proxy (human-granted extra review rounds); schema 1 has no code-review round count.
21
+ `runs` has one row per record; `shipped*` marks a truncated run (no ship phase recorded - an older salvage stamped it at landing; its `wall` is `-` and it feeds no aggregate). `by version` groups by pi-gauntlet version: `n` counts every row, `shipped` counts the rows behind the p50/max columns. `grants` is `fix_round_grants` - the fix-round proxy (human-granted extra review rounds); schema 1 has no code-review round count.
22
22
 
23
23
  ## Reply - exactly this, in this order
24
24
 
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: gauntlet-resume
3
- description: Use when a human wants to continue an interrupted gauntlet flow in a fresh session - from a gauntlet-handoff brief (file, pasted, or picked from the default handoff directory) or from a bare worktree that already holds a spec. Human-only; the sole resume entry point. Restores phase/plan tracker state through the legal arming sequence, never creates a worktree, never infers approval.
3
+ description: Use when a human wants to continue an interrupted gauntlet flow in a fresh session - from a gauntlet-handoff brief (file, pasted, or picked from the default handoff directory), from a bare worktree that already holds a spec, or from a spec tracked on main (creates or reuses its worktree via `/skill:using-git-worktrees`). Human-only; the sole resume entry point. Restores phase/plan tracker state through the legal arming sequence, never infers approval.
4
4
  disable-model-invocation: true
5
- argument-hint: "[<brief-file>] [<worktree-name-or-path>]"
5
+ argument-hint: "[<brief-file> | <spec>.md | <worktree-name-or-path>]"
6
6
  ---
7
7
 
8
8
  > **Related skills:** Continues into `/skill:writing-plans`, `/skill:subagent-driven-development`, or `/skill:verification-before-completion` depending on the restored stage. `/skill:brainstorming` is where new ideas go - a free-form prompt is not a resume input.
@@ -11,48 +11,61 @@ argument-hint: "[<brief-file>] [<worktree-name-or-path>]"
11
11
 
12
12
  ## Overview
13
13
 
14
- Re-enter an interrupted gauntlet flow in a fresh session. Two inputs: a handoff brief
15
- produced by `/skill:gauntlet-handoff` (grammar in `reference/brief-contract.md`), or a bare
14
+ Re-enter an interrupted gauntlet flow in a fresh session. Three inputs: a handoff brief
15
+ produced by `/skill:gauntlet-handoff` (grammar in `reference/brief-contract.md`), a bare
16
16
  worktree whose spec/plan artifacts are reconstructed into tracker state
17
- (`reference/reconstruction.md`). Every check runs before any tracker mutation; every
18
- stop names the offending path, field, or line.
17
+ (`reference/reconstruction.md`), a spec seed (`reference/seed.md`). Every check runs
18
+ before any tracker mutation; every stop names the offending path, field, or line.
19
19
 
20
20
  **Announce at start:** "I'm using the gauntlet-resume skill to continue an interrupted flow."
21
21
 
22
22
  ## Boundaries
23
23
 
24
24
  - Reads: anything.
25
- - Writes: `phase_tracker` / `plan_tracker` state, only after every entry check passes
26
- and every human question is answered. Nothing on disk.
27
- - Never: `git worktree add`; infer approval from artifact presence; restore gate history,
28
- closure-review evidence, or fix rounds; start a later phase directly (that does not arm
29
- the flow).
25
+ - Writes: `phase_tracker` / `plan_tracker` state after every check passes and every
26
+ human question is answered; on the seed route, what `/skill:using-git-worktrees`
27
+ writes. Never a spec copy, rename, or marker commit.
28
+ - Never: `git worktree add` directly; worktree creation by resume itself only on
29
+ the seed route, only through `/skill:using-git-worktrees`; infer approval from
30
+ artifact presence; restore
31
+ gate history, closure-review evidence, or fix rounds; start a later phase directly
32
+ (that does not arm the flow).
30
33
 
31
34
  ## Arguments
32
35
 
33
- `/skill:gauntlet-resume [<brief>] [<worktree>]` - zero to two positional tokens, plus
34
- optional pasted text after the command line.
36
+ `/skill:gauntlet-resume [<token>] [<worktree>]` - zero to two positional tokens, plus
37
+ optional pasted text after the command line. Count tokens first; then first match wins.
38
+ Spec dirs resolve per `reference/reconstruction.md` "Candidates" (`flowGuards.specDirs`
39
+ precedence).
35
40
 
36
- | Form | Meaning |
41
+ | Input | Route |
37
42
  |---|---|
38
- | (no tokens, no pasted text) | discovery: `<tmpdir>` via `node -p "require('os').tmpdir()"`; candidates are the regular files directly under `<tmpdir>/pi-handoff/` ending `.md` (non-recursive) whose line 1 starts `# Handoff:`; sorted by mtime, newest first; displayed one per line as `<n>. <title line> - <worktree: field value> - <mtime ISO-8601>` with `worktree: unavailable` when the field is absent; the human picks `<n>` (a single candidate is still confirmed); none -> STOP "no handoff briefs found under <tmpdir>/pi-handoff" |
39
- | `<brief-file>` | a single token that is an absolute path, contains a path separator, or ends in `.md`; used as given, never widened to a scan; missing, unreadable, or line 1 not `# Handoff:` -> STOP with that path |
40
- | pasted text whose first line starts `# Handoff:` | inline brief (equivalent to a file) |
41
- | `<worktree>` alone | any other single token (no path separator, not ending `.md`): bare name resolved as `<primary>/.worktrees/<name>`; must already be a git worktree. An absolute worktree path is given only in the two-token `<brief> <worktree>` form |
42
- | `<brief> <worktree>` | brief plus an explicit worktree override (required when the brief's worktree field is `no`/`unavailable`/not a git repo; must equal the brief's worktree after `realpath` otherwise) |
43
- | anything else | not a resume input - stop with "this is a new idea - run /skill:brainstorming" |
44
-
45
- `<primary>` is the checkout owning `.worktrees/`: `dirname "$(git rev-parse --path-format=absolute --git-common-dir)"` run in the session cwd - absolute from any primary subdirectory and from inside a linked worktree (`--show-toplevel` would return the linked worktree there). A bare `<name>` resolves as `<primary>/.worktrees/<name>`. A pasted brief that needs an override uses the file form. This skill never runs `git worktree add`.
46
-
47
- Classification runs before anything else: a token that is an absolute path, contains a
48
- path separator, or ends in `.md` is a `<brief-file>` - never a worktree name, never
49
- widened to a scan. Any other single token is tried as `<worktree>`. A picked or given
50
- brief then runs entry checks 1-5 unchanged, so a stale or foreign-repo brief stops there.
51
- Free-form text still lands on the "anything else" row.
43
+ | no tokens, no pasted text | discovery: `<tmpdir>` via `node -p "require('os').tmpdir()"`; candidates are the regular files directly under `<tmpdir>/pi-handoff/` ending `.md` (non-recursive) whose line 1 starts `# Handoff:`; sorted by mtime, newest first; displayed one per line as `<n>. <title line> - <worktree: field value> - <mtime ISO-8601>` with `worktree: unavailable` when the field is absent; the human picks `<n>` (a single candidate is still confirmed); none -> STOP "no handoff briefs found under <tmpdir>/pi-handoff" |
44
+ | pasted text, line 1 starts `# Handoff:` | brief |
45
+ | two tokens, first an existing file with line 1 `# Handoff:` | brief with worktree override: required when the brief's worktree field is `no`/`unavailable`/not a git repo; must equal the brief's worktree after `realpath` otherwise |
46
+ | two tokens, first a spec seed | stop: `a spec seed takes no worktree: <second token>` |
47
+ | one token, existing regular file, line 1 starts `# Handoff:` | brief |
48
+ | one token, existing regular file ending `.md`, `realpath` under `<primary>/<specDir>` | spec seed - `reference/seed.md` |
49
+ | one token, existing regular file, anything else | stop: `not a handoff brief and not under <specDirs>: <path>` |
50
+ | one token, existing directory that is a git worktree root (`git -C <dir> rev-parse --show-toplevel` equals its `realpath`) other than `<primary>` | worktree |
51
+ | one token, missing path (ends `.md` or contains a separator) | stop: `not found: <path>` |
52
+ | one token, bare name | worktree at `<primary>/.worktrees/<name>`; missing or not a git worktree -> entry check 2 stop |
53
+ | anything else | stop: "this is a new idea - run /skill:brainstorming" |
54
+
55
+ A relative token resolves against the session cwd; a bare `name.md` absent there is
56
+ tried at `<primary>/<specDir>/name.md` per resolved spec dir in order, first hit wins.
57
+ `<primary>` is the checkout owning `.worktrees/`:
58
+ `dirname "$(git rev-parse --path-format=absolute --git-common-dir)"` run in the session
59
+ cwd - absolute from any primary subdirectory and from inside a linked worktree
60
+ (`--show-toplevel` would return the linked worktree there). A pasted brief that needs
61
+ an override uses the file form. A brief then runs entry checks 1-5, so a stale or
62
+ foreign-repo brief stops there.
52
63
 
53
64
  ## Entry checks
54
65
 
55
- In order. All before any tracker mutation; entry check 1 is read-only.
66
+ In order. All before any tracker mutation; entry check 1 is read-only. A spec
67
+ seed runs check 1 here, then `reference/seed.md`, which runs check 3 itself;
68
+ checks 2, 4, 5 do not apply.
56
69
 
57
70
  1. **Idle session.** `phase_tracker({ action: "status" })`. Any phase not pending ->
58
71
  stop: "session already carries flow state - reset is your call".
@@ -91,6 +104,7 @@ In order. All before any tracker mutation; entry check 1 is read-only.
91
104
  | brief without process state, `worktree: no` | invoke `/skill:brainstorming` with `## Intent` as the idea, in the current directory; resume creates no worktree - brainstorming's own Worktree First applies (a plain handoff is a new flow) |
92
105
  | brief without process state, worktree present | `reference/reconstruction.md`, with `## Intent` and `## Decisions` carried into every confirmation prompt |
93
106
  | bare worktree | `reference/reconstruction.md`; prompts state that no brief context is available (never invent Intent/Decisions) |
107
+ | spec seed | `reference/seed.md` |
94
108
 
95
109
  **Hotfix route.** `skills/chase-bug/hotfix.md` consumes only a hotfix record at
96
110
  `$TMPDIR/hotfix-<slug>.md`. If `## Decisions` or `## Intent` names an existing record
@@ -113,11 +127,11 @@ owning skill **without** its reset-bearing entry:
113
127
 
114
128
  ## Red flags — STOP
115
129
 
116
- - Any `phase_tracker` or `plan_tracker` mutation before entry checks 1-5 pass and every
117
- human question is answered.
130
+ - Any `phase_tracker` or `plan_tracker` mutation before the route's entry checks pass and
131
+ every human question is answered.
118
132
  - `start <phase>` for anything other than brainstorm as the first arming call.
119
133
  - `complete` on a prior phase during restore (priors are `skip`ped with a `resume:` reason).
120
- - Running `git worktree add`, or `cd`-ing to "fix" a cwd mismatch.
134
+ - Running `git worktree add` directly, or `cd`-ing to "fix" a cwd mismatch.
121
135
  - Accepting a free-form prompt as a brief.
122
136
 
123
137
  ## Project overrides
@@ -53,7 +53,7 @@ Example appended block (the fence is documentation; the brief carries no fence):
53
53
  ## Process state
54
54
 
55
55
  Phases:
56
- ⊘ brainstorm (resume: pasted brief)
56
+ ⊘ brainstorm (resume: <spec path>)
57
57
  ⊘ plan (resume: pasted brief)
58
58
  → implement(W2)
59
59
  ○ verify
@@ -117,21 +117,25 @@ Facts that fix the order (from the extensions):
117
117
  - `plan_tracker init` on an in-progress implement with every task `complete`/`skipped`
118
118
  auto-completes implement.
119
119
 
120
- Per-stage call table, keyed by the brief's active phase (`→`). `R` is the reason string
121
- `resume: <brief file or "pasted brief">`.
120
+ Per-stage call table, keyed by the brief's active phase (`→`). Use
121
+ `R = resume: <brief file or "pasted brief">` for plan/implement/verify skips and
122
+ `S = resume: <spec path>` for brainstorm skips. Resolve `<spec path>` to the absolute
123
+ path of the single `*.md` spec added after base in the worktree under `flowGuards.specDirs`
124
+ (as enumerated in `reconstruction.md`, "Candidates"). Zero specs -> stop; more than
125
+ one -> human picks.
122
126
 
123
127
  | Active | Calls, in order |
124
128
  |---|---|
125
129
  | brainstorm | `start brainstorm`; `substep` if the brief shows one |
126
- | plan | `start brainstorm`; `skip brainstorm R`; `start plan`; `substep` if shown |
127
- | implement | `start brainstorm`; `skip brainstorm R`; `start plan`; `plan_check({ planPath })`; on FAIL print findings and stop with plan in_progress, no init; on PASS `skip plan R`; `start implement`; `substep` if shown; `plan_tracker init` |
130
+ | plan | `start brainstorm`; `skip brainstorm S`; `start plan`; `substep` if shown |
131
+ | implement | `start brainstorm`; `skip brainstorm S`; `start plan`; `plan_check({ planPath })`; on FAIL print findings and stop with plan in_progress, no init; on PASS `skip plan R`; `start implement`; `substep` if shown; `plan_tracker init` |
128
132
  | verify | as implement through `skip plan R`, then `skip implement R`; `start verify`; `substep` if shown; `plan_tracker init` |
129
133
  | ship | as verify. Restoration stops at verify in_progress: `complete verify` needs a fresh conformance dispatch and `skip verify` would bypass a real gate. Announce that the closure review re-runs before ship |
130
134
 
131
- `planPath`: the brief carries none. Resolve as reconstruction does
135
+ `planPath` (implement onward): the brief carries none. Resolve as reconstruction does
132
136
  (`reconstruction.md`, "Candidates", including its `flowGuards.specDirs` resolution): the
133
- single spec/plan pair added after base in the worktree, paired by identical basename
134
- (`<specDir>/<name>.md` <-> `<sibling plans dir>/<name>.md`, the writing-plans contract);
137
+ single plan added after base, paired with `<specDir>/<same basename>` whether that
138
+ spec was added after base or tracked from base (`reconstruction.md` "Candidates");
135
139
  resolve the selected plan to an absolute path under the worktree before `plan_check`.
136
140
  Zero pairs -> stop; more than one -> human picks.
137
141
 
@@ -23,6 +23,8 @@ for a base ref before reading any artifact.
23
23
 
24
24
  ## Candidates
25
25
 
26
+ A pinned spec (seed route, `seed.md`) skips this section.
27
+
26
28
  Spec/plan directories: `piGauntlet.flowGuards.specDirs` plus each one's sibling `plans` directory. Resolve with the precedence `doc/configuration.md` documents for every `piGauntlet.*` key: the session cwd's `.pi/settings.json` if it defines `flowGuards`,
27
29
  else the active pi profile's `settings.json`, else the default `["doc/specs"]` (sibling
28
30
  `doc/plans`). An empty array is the default. `<dirs>` below is that resolved list,
@@ -36,15 +38,17 @@ git -C <worktree> ls-files --others --exclude-standard -- <dirs>
36
38
  Candidates are files under those directories added after base, plus untracked files
37
39
  there. Paths returned by these commands are relative to `<worktree>`; resolve them to
38
40
  absolute paths under `<worktree>` before reading artifacts, showing paths in prompts,
39
- or calling `plan_check`. A spec and a plan pair by identical basename
40
- (`<specDir>/<name>.md` <-> `<sibling plans dir>/<name>.md`). The plan commit is the first
41
+ or calling `plan_check`. A candidate plan pairs with
42
+ `<worktree>/<specDir>/<same basename>` whether that spec is a candidate or tracked
43
+ from base; count a base-tracked spec so paired as a spec in the route table below.
44
+ The plan commit is the first
41
45
  post-base commit that added the plan file: `git -C <worktree> log --diff-filter=A
42
46
  --format=%H --reverse <base>..HEAD -- <plan>`, first line. An uncommitted plan has no
43
47
  plan commit; treat every task as `pending`.
44
48
 
45
49
  | Candidates | Route |
46
50
  |---|---|
47
- | no spec | stop; offer `/skill:brainstorming`; no tracker call |
51
+ | no spec | stop; offer `/skill:brainstorming` or pass the spec: `/skill:gauntlet-resume <specDir>/<name>.md`; no tracker call |
48
52
  | more than one spec | the human picks one, then continue below with that spec |
49
53
  | one spec, no plan | "Spec without plan" |
50
54
  | one spec with plan | "Spec with plan" |
@@ -71,6 +75,9 @@ Show, and ask the human to confirm or edit both in one reply:
71
75
  Uncommitted plan (no
72
76
  plan commit): skip this query entirely - there is no range to search - and show
73
77
  "plan uncommitted; no task evidence" in its place; every task is proposed `pending`.
78
+ Plan commit lookup empty while `git -C <worktree> cat-file -e <base>:<plan>` exits 0
79
+ (plan at or before base): skip the log query, show
80
+ `plan predates base; no post-base task evidence`, every task proposed `pending`.
74
81
  2. Uncommitted files: `git -C <worktree> status --porcelain`.
75
82
  3. Proposed task statuses: `complete` iff at least one matching commit, else `pending`.
76
83
  4. Proposed stage: `implement` if any task is `pending`, else `verify`.
@@ -0,0 +1,47 @@
1
+ # Spec seed (gauntlet-resume supplementary)
2
+
3
+ Consumed only by `SKILL.md` in this directory, for a one-token `.md` argument classified
4
+ as a spec seed. `<seed>` is its `realpath`; `<rel>` is `<seed>` relative to `<primary>`.
5
+ Entry check 1 (idle session) runs first. Then, in order; every stop names the path.
6
+
7
+ 1. **Primary session.** `git rev-parse --git-dir --git-common-dir` in the session cwd
8
+ prints two paths; their `realpath`s must agree. Otherwise stop:
9
+ `seed from the primary checkout`.
10
+ 2. **Tracked.** `git -C <primary> ls-files --error-unmatch <rel>` exits 0; otherwise
11
+ stop: `not tracked: <seed> - commit it first`. Line 1 of `<seed>` equal to
12
+ `# CONTEXT DRAFT - NOT A SPEC - fully replaced at spec-writing` -> stop:
13
+ `context draft, not a spec: <seed> - finish brainstorming`.
14
+ 3. **Not shipped.** Read `<primary>/<telemetry.dir>/<rel with .md -> .yaml>`
15
+ (`piGauntlet.telemetry.dir`, default `.pi/gauntlet/telemetry`). A `shipped_at:` or
16
+ `abandoned_at:` line carrying a value -> stop:
17
+ `spec already shipped at <ts> - write a superseding spec`. No record, or
18
+ `in_progress`: continue; the extension folds this run into the record on
19
+ `plan_check` pass.
20
+ 4. **Name.** `<name>` = basename of `<rel>` minus `.md`, minus a leading `YYYY-MM-DD-`:
21
+ `2026-09-17-gh-31-gauntlet-resume.md` -> `gh-31-gauntlet-resume`. Same shape as
22
+ brainstorming's Filename Convention slug; wrappers receive it as `<name>`.
23
+ 5. **Reuse or create.** `git -C <primary> worktree list --porcelain`. A block whose
24
+ `branch` line is `refs/heads/<name>` or ends in `/<name>` -> `<full-path>` is that
25
+ block's `worktree` line; skip creation (layout-agnostic: wrapper sibling dirs,
26
+ wrapper branch prefixes such as `<user>/<name>`, and `.worktrees/` alike); more than
27
+ one match -> the human picks. No block -> invoke `/skill:using-git-worktrees` with branch `<name>` and carry its
28
+ `Worktree ready at <full-path>`; its Step 1a applies project `## using-git-worktrees`
29
+ overrides, its Step 3 runs the clean-base check and dirty ask. Wrapper arguments
30
+ beyond `<name>` are that skill's ask, never inferred here. Any stop it raises is this
31
+ route's stop, verbatim. Never invent a second name.
32
+ 6. **Same repository.** Entry check 3 against `<full-path>`.
33
+ 7. **Pinned copy.** `<full-path>/<rel>` exists, is readable, and its line 1 is not the
34
+ context-draft marker; otherwise stop naming that path. Never copy `<seed>` in.
35
+ 8. **Continue** in `reconstruction.md` with the spec pinned at `<full-path>/<rel>`,
36
+ skipping Candidates: `<full-path>/<sibling plans dir>/<basename of rel>` exists ->
37
+ "Spec with plan"; otherwise "Spec without plan". Prompts say "no brief context
38
+ available".
39
+
40
+ The seed route writes no spec copy, rename, or marker commit: the spec stays where main
41
+ tracks it, amends ride the squash as ordinary diffs, and `finishing-a-development-branch`
42
+ strips only the plan. `gauntlet-telemetry-salvage` prints `no spec on branch` for an
43
+ unamended seed throughout the flow (it selects specs from `git diff --name-only
44
+ <base>...HEAD`, which never lists a file tracked at base), so the extension's live ship
45
+ stamp is the only writer of `shipped_at`; the record still binds on `plan_check` pass.
46
+ Before a plan exists beside the spec, re-pass the seed to resume; after, plain `<worktree>` resume and
47
+ `gauntlet-handoff` -> `gauntlet-resume <brief>` restore the flow.