@gobing-ai/spur 0.4.0 → 0.4.1

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.
Files changed (154) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/decisions/gates.yaml +36 -0
  3. package/config/decisions/history-anatomy.yaml +35 -0
  4. package/config/decisions/idea-pipeline.yaml +38 -0
  5. package/config/plugin-scripts.json +15 -0
  6. package/config/rules/docs/sourced-api-claims.yaml +60 -0
  7. package/config/rules/recommended-pre-check.yaml +8 -3
  8. package/config/rules/structure/scratch-evidence-pointer.yaml +35 -0
  9. package/config/script-placement-baseline.json +2 -2
  10. package/config/workflows/feature-lifecycle.yaml +9 -2
  11. package/config/workflows/history-anatomy.yaml +22 -0
  12. package/config/workflows/idea-pipeline.yaml +75 -0
  13. package/config/workflows/task-pipeline.yaml +216 -57
  14. package/config/workflows/wrapup-pipeline.yaml +106 -13
  15. package/package.json +9 -9
  16. package/plugins/sp/README.md +11 -1
  17. package/plugins/sp/agents/super-planner.md +11 -0
  18. package/plugins/sp/agents/super-reviewer.md +14 -0
  19. package/plugins/sp/bunfig.toml +8 -0
  20. package/plugins/sp/commands/dev-brainstorm.md +29 -16
  21. package/plugins/sp/commands/dev-find-way.md +80 -0
  22. package/plugins/sp/commands/dev-idea.md +6 -0
  23. package/plugins/sp/commands/dev-parallel.md +8 -2
  24. package/plugins/sp/commands/dev-plan.md +6 -0
  25. package/plugins/sp/commands/dev-review-session.md +3 -1
  26. package/plugins/sp/commands/dev-run.md +12 -2
  27. package/plugins/sp/commands/dev-runall.md +18 -10
  28. package/plugins/sp/hooks/context-session-start.ts +1 -1
  29. package/plugins/sp/lib/idea-handoff.generated.mjs +41 -5
  30. package/plugins/sp/lib/inline-run-app.ts +28 -0
  31. package/plugins/sp/lib/inline-run.generated.d.mts +5 -0
  32. package/plugins/sp/lib/inline-run.generated.mjs +333 -45
  33. package/plugins/sp/lib/plan-projection.generated.d.mts +28 -0
  34. package/plugins/sp/lib/plan-projection.generated.mjs +255 -0
  35. package/plugins/sp/lib/quality-gate.generated.d.mts +47 -1
  36. package/plugins/sp/lib/quality-gate.generated.mjs +30489 -82
  37. package/plugins/sp/lib/residual-scan.generated.d.mts +19 -0
  38. package/plugins/sp/lib/residual-scan.generated.mjs +66 -0
  39. package/plugins/sp/lib/run-summary-core.ts +561 -0
  40. package/plugins/sp/lib/transcript.ts +121 -6
  41. package/plugins/sp/plugin.json +1 -1
  42. package/plugins/sp/references/roles.md +1 -1
  43. package/plugins/sp/scripts/batch-plan.mjs +335 -0
  44. package/plugins/sp/scripts/batch-plan.ts +100 -0
  45. package/plugins/sp/scripts/batch-preflight.mjs +51 -3
  46. package/plugins/sp/scripts/batch-preflight.ts +72 -1
  47. package/plugins/sp/scripts/commit-guard.mjs +216 -0
  48. package/plugins/sp/scripts/commit-guard.ts +249 -0
  49. package/plugins/sp/scripts/inline-run-dispatch.mjs +130 -0
  50. package/plugins/sp/scripts/inline-run-dispatch.ts +135 -0
  51. package/plugins/sp/scripts/inline-run-setup.mjs +551 -80
  52. package/plugins/sp/scripts/inline-run-setup.ts +52 -78
  53. package/plugins/sp/scripts/persist-out-check.mjs +90 -41
  54. package/plugins/sp/scripts/persist-out-check.ts +112 -57
  55. package/plugins/sp/scripts/quality-gate.mjs +30407 -73
  56. package/plugins/sp/scripts/quality-gate.ts +21 -5
  57. package/plugins/sp/scripts/residual-scan.mjs +86 -31
  58. package/plugins/sp/scripts/residual-scan.ts +28 -30
  59. package/plugins/sp/scripts/run-summary.mjs +421 -14
  60. package/plugins/sp/scripts/run-summary.ts +41 -177
  61. package/plugins/sp/scripts/session-timeline.mjs +109 -12
  62. package/plugins/sp/scripts/session-timeline.ts +71 -19
  63. package/plugins/sp/scripts/wrapup-steps.mjs +150 -2
  64. package/plugins/sp/scripts/wrapup-steps.ts +203 -1
  65. package/plugins/sp/skills/brainstorm/SKILL.md +9 -47
  66. package/plugins/sp/skills/branch-workflow/SKILL.md +1 -0
  67. package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +1 -0
  68. package/plugins/sp/skills/code-implementation/SKILL.md +48 -1
  69. package/plugins/sp/skills/code-verification/SKILL.md +3 -4
  70. package/plugins/sp/skills/code-verification/references/secu-review.md +3 -0
  71. package/plugins/sp/skills/code-verification/references/verdict-schema.md +68 -0
  72. package/plugins/sp/skills/fleet-join/SKILL.md +1 -1
  73. package/plugins/sp/skills/session-review/SKILL.md +38 -7
  74. package/plugins/sp/skills/source-driven-development/SKILL.md +5 -0
  75. package/plugins/sp/skills/spec-decomposition/references/decomposition.md +5 -3
  76. package/plugins/sp/skills/spur-cli/SKILL.md +5 -2
  77. package/plugins/sp/skills/spur-cli/references/agent.md +20 -15
  78. package/plugins/sp/skills/spur-cli/references/decision.md +7 -6
  79. package/plugins/sp/skills/spur-cli/references/message.md +7 -7
  80. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +19 -3
  81. package/plugins/sp/skills/spur-cli/references/tasks.md +10 -7
  82. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +7 -0
  83. package/plugins/sp/skills/spur-cli/references/workflows.md +7 -2
  84. package/plugins/sp/skills/spur-composer/SKILL.md +1 -1
  85. package/plugins/sp/skills/spur-dev/SKILL.md +18 -14
  86. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +6 -3
  87. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +49 -14
  88. package/plugins/sp/skills/spur-dev/references/dev-operations.md +37 -16
  89. package/plugins/sp/skills/spur-dev/references/execution-batch-continuation.md +68 -0
  90. package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +194 -0
  91. package/plugins/sp/skills/spur-dev/references/execution-batch.md +113 -1020
  92. package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +130 -0
  93. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +6 -0
  94. package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +471 -0
  95. package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +379 -0
  96. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +35 -5
  97. package/plugins/sp/skills/spur-dev/references/glossary.md +2 -2
  98. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +343 -163
  99. package/plugins/sp/skills/spur-dev/references/structured-trace-emission.md +178 -0
  100. package/plugins/sp/skills/wayfinder/SKILL.md +10 -14
  101. package/schemas/state-machine-workflow.schema.json +23 -0
  102. package/spur.js +20728 -16630
  103. package/web/_astro/{BoardApp.VeoxxLBy.js → BoardApp.D66k_s_T.js} +1 -1
  104. package/web/_astro/{BoardApp.Bzr4OXrW.js → BoardApp.D6sjAJr_.js} +173 -173
  105. package/web/_astro/{TaskDetail.LAyR_Pvn.js → TaskDetail.BynLnMNc.js} +1 -1
  106. package/web/_astro/{arc.f4e0OYLg.js → arc._BUadrdH.js} +1 -1
  107. package/web/_astro/{architectureDiagram-3BPJPVTR.SSIvxi-Z.js → architectureDiagram-3BPJPVTR.Dh7xS1Pp.js} +1 -1
  108. package/web/_astro/{blockDiagram-GPEHLZMM.DSXIHOFf.js → blockDiagram-GPEHLZMM.DFDVpfXm.js} +1 -1
  109. package/web/_astro/{c4Diagram-AAUBKEIU.DG9Ubu85.js → c4Diagram-AAUBKEIU.V7_3_glh.js} +1 -1
  110. package/web/_astro/channel.DZVfto-r.js +1 -0
  111. package/web/_astro/{chunk-2J33WTMH.C7QU88Qh.js → chunk-2J33WTMH.De1yx7Jz.js} +1 -1
  112. package/web/_astro/{chunk-4BX2VUAB.26Z94xBj.js → chunk-4BX2VUAB.BDhHFuxx.js} +1 -1
  113. package/web/_astro/{chunk-55IACEB6.DYRiBkqw.js → chunk-55IACEB6.DDLkWnmC.js} +1 -1
  114. package/web/_astro/{chunk-727SXJPM.D5Vfv5pe.js → chunk-727SXJPM.CwfiLnA7.js} +1 -1
  115. package/web/_astro/{chunk-AQP2D5EJ.DXHV47bN.js → chunk-AQP2D5EJ.CtGDmUnM.js} +1 -1
  116. package/web/_astro/{chunk-FMBD7UC4.D1suAfOs.js → chunk-FMBD7UC4.BOLjpw73.js} +1 -1
  117. package/web/_astro/{chunk-ND2GUHAM.D6BmdHEY.js → chunk-ND2GUHAM.BDhQls6O.js} +1 -1
  118. package/web/_astro/{chunk-QZHKN3VN.rnPU-Ak-.js → chunk-QZHKN3VN.76qBynDF.js} +1 -1
  119. package/web/_astro/{classDiagram-4FO5ZUOK.CvEfXIo1.js → classDiagram-4FO5ZUOK.N0mpPHT0.js} +1 -1
  120. package/web/_astro/{classDiagram-v2-Q7XG4LA2.CvEfXIo1.js → classDiagram-v2-Q7XG4LA2.N0mpPHT0.js} +1 -1
  121. package/web/_astro/{cose-bilkent-S5V4N54A.DkMisLSm.js → cose-bilkent-S5V4N54A.CKknFfjB.js} +1 -1
  122. package/web/_astro/{cynefin-OW5HDTMX.C77Q-pF6.js → cynefin-OW5HDTMX.Cw3ZWBAh.js} +1 -1
  123. package/web/_astro/{dagre-BM42HDAG.YaV8ce27.js → dagre-BM42HDAG.D3yIKCRD.js} +1 -1
  124. package/web/_astro/{diagram-2AECGRRQ.CUyGEKge.js → diagram-2AECGRRQ.D51dO83Z.js} +1 -1
  125. package/web/_astro/{diagram-5GNKFQAL.CRgd8dgj.js → diagram-5GNKFQAL.Bb-FViDj.js} +1 -1
  126. package/web/_astro/{diagram-KO2AKTUF.Bmzys9hq.js → diagram-KO2AKTUF.D3mN8S6x.js} +1 -1
  127. package/web/_astro/{diagram-LMA3HP47.BvmJY4Lw.js → diagram-LMA3HP47.dMMyPcbJ.js} +1 -1
  128. package/web/_astro/{diagram-OG6HWLK6.0hEhD30d.js → diagram-OG6HWLK6.AzbvzY4C.js} +1 -1
  129. package/web/_astro/{erDiagram-TEJ5UH35.Bjt8lrnm.js → erDiagram-TEJ5UH35.BR5I4OZb.js} +1 -1
  130. package/web/_astro/{flowDiagram-I6XJVG4X.CJZTjRDV.js → flowDiagram-I6XJVG4X.DFqvhGkn.js} +1 -1
  131. package/web/_astro/{ganttDiagram-6RSMTGT7._VqoVafc.js → ganttDiagram-6RSMTGT7.ByJbhH6J.js} +1 -1
  132. package/web/_astro/{gitGraphDiagram-PVQCEYII.CEDb7tVo.js → gitGraphDiagram-PVQCEYII.CInHjQR3.js} +1 -1
  133. package/web/_astro/index.COh_kBxN.css +1 -0
  134. package/web/_astro/{infoDiagram-5YYISTIA.CgwifPpK.js → infoDiagram-5YYISTIA.Cm0dGVjJ.js} +1 -1
  135. package/web/_astro/{ishikawaDiagram-YF4QCWOH.B99wx2J1.js → ishikawaDiagram-YF4QCWOH.C3nOP6Sj.js} +1 -1
  136. package/web/_astro/{journeyDiagram-JHISSGLW.2hRwJbEo.js → journeyDiagram-JHISSGLW.4IvLa2MW.js} +1 -1
  137. package/web/_astro/{kanban-definition-UN3LZRKU.BahJkKNC.js → kanban-definition-UN3LZRKU.DS87Cl-k.js} +1 -1
  138. package/web/_astro/{linear.DguUUe6V.js → linear.MzmRrNER.js} +1 -1
  139. package/web/_astro/{mermaid.core.CvgfmqVr.js → mermaid.core.fK-WNswS.js} +4 -4
  140. package/web/_astro/{mindmap-definition-RKZ34NQL.B3qEA3x9.js → mindmap-definition-RKZ34NQL.BqipOHhY.js} +1 -1
  141. package/web/_astro/{pieDiagram-4H26LBE5.FlWA-_ru.js → pieDiagram-4H26LBE5.0nBiPqFG.js} +1 -1
  142. package/web/_astro/{quadrantDiagram-W4KKPZXB.9bVn35X7.js → quadrantDiagram-W4KKPZXB.Szj7Zpx5.js} +1 -1
  143. package/web/_astro/{requirementDiagram-4Y6WPE33.ChykIhct.js → requirementDiagram-4Y6WPE33.D4UR6TWo.js} +1 -1
  144. package/web/_astro/{sankeyDiagram-5OEKKPKP.Z2Y3hkYb.js → sankeyDiagram-5OEKKPKP.DAE7BdOs.js} +1 -1
  145. package/web/_astro/{sequenceDiagram-3UESZ5HK.J7JsHWDt.js → sequenceDiagram-3UESZ5HK.BP9ZVq25.js} +1 -1
  146. package/web/_astro/{stateDiagram-AJRCARHV.DAPbiCSS.js → stateDiagram-AJRCARHV.BQW7mIxk.js} +1 -1
  147. package/web/_astro/{stateDiagram-v2-BHNVJYJU.D2jvSi0q.js → stateDiagram-v2-BHNVJYJU.PbK4nDih.js} +1 -1
  148. package/web/_astro/{timeline-definition-PNZ67QCA.psW2ci29.js → timeline-definition-PNZ67QCA.Ci_GvUpo.js} +1 -1
  149. package/web/_astro/{vennDiagram-CIIHVFJN.DlILYVmg.js → vennDiagram-CIIHVFJN.DNw1Y5qx.js} +1 -1
  150. package/web/_astro/{wardleyDiagram-YWT4CUSO.xNWwLJnn.js → wardleyDiagram-YWT4CUSO.CwlkaaNe.js} +1 -1
  151. package/web/_astro/{xychartDiagram-2RQKCTM6.EU_BuH7V.js → xychartDiagram-2RQKCTM6.MI6ZuiH_.js} +1 -1
  152. package/web/index.html +2 -2
  153. package/web/_astro/channel.CUFdtWhm.js +0 -1
  154. package/web/_astro/index.Dg_3bOaJ.css +0 -1
@@ -39,11 +39,7 @@ metadata:
39
39
  It converts vague intent into shipped work by _orchestrating_, not by doing the work itself: it runs
40
40
  the gates (feature-check, batch-create) and the execution pipeline with human-in-the-loop control,
41
41
  and **dispatches deep competency skills** for each unit of work — it never inlines them. Every write
42
- to the corpus goes through a CLI verb that validates before writing — the spine knows _how to drive
43
- the lifecycle_; the competency skills know _how to do each job_; the CLI knows _what is valid_.
44
-
45
- The skill was decomposed **by function** (ADR-028): design, decomposition, implementation, testing,
46
- and verification each became a standalone competency skill, leaving this spine to orchestrate them.
42
+ to the corpus goes through a CLI verb that validates before writing.
47
43
 
48
44
  **Ownership (ADR-054).** This spine owns multi-step lifecycle orchestration — intake, gates,
49
45
  decomposition, pipeline runs, HITL pauses. CLI noun/verb/flag semantics, including
@@ -104,6 +100,19 @@ run. Resume with `spur workflow continue --answer-text <answer>` — the guard a
104
100
  Full procedure: **[references/execution-workflow.md](references/execution-workflow.md)**.
105
101
  Host-session procedure: **[references/inline-pipeline-driver.md](references/inline-pipeline-driver.md)**.
106
102
 
103
+ ## Bootstrap reads
104
+
105
+ Read this `SKILL.md` plus your mode's files below before the first dispatch; everything else under
106
+ `references/` is on demand, and the per-task delegate `inline-pipeline-driver.md` is read at dispatch
107
+ (budgets: `plugins/sp/tests/bootstrap-budget.test.ts`, task 1128).
108
+
109
+ - sequential-inline: `references/execution-batch.md`
110
+ - --worktree: `references/execution-batch.md`, `references/execution-worktree-setup.md`
111
+ - --mode parallel: `references/execution-batch.md`, `references/execution-parallel-isolation.md`
112
+
113
+ Byte budgets for these sums live in `plugins/sp/tests/bootstrap-budget.test.ts`
114
+ (`BOOTSTRAP_BUDGETS_BYTES`, task 1128); the test fails the build when a mode's bootstrap grows.
115
+
107
116
  ## Step routing
108
117
 
109
118
  Each step delegates to a CLI verb and is documented in exactly one reference file. Read the
@@ -201,10 +210,8 @@ path <wbs> --json` only when another tool needs the absolute path. Never search
201
210
 
202
211
  ## Additional Resources
203
212
 
204
- **Every reference file and its step is listed once, in [Step routing](#step-routing) above — this
205
- section adds what that table has no room for: per-file content summaries and items with no single
206
- step (glossary, config companions).** Read Step routing to find "which file for step X"; read below
207
- for "what's actually in file Y" or for resources that sit outside the step sequence.
213
+ **Every reference file and its step is listed once, in [Step routing](#step-routing) above.** This
214
+ section adds per-file content summaries and items with no single step (glossary, config companions).
208
215
 
209
216
  - Job transfer: [dump/resume](references/dev-operations.md#11a-job-dump).
210
217
 
@@ -212,12 +219,9 @@ for "what's actually in file Y" or for resources that sit outside the step seque
212
219
  corpus, gate, verdict, noun/verb, half, HITL, WBS, section-write contract — canonical term +
213
220
  Avoid list. Owns term definitions only; `cross-cutting.md` owns the process rules that use them.
214
221
  - [references/flag-glossary.md](references/flag-glossary.md) — the shared-flag glossary (one
215
- canonical entry per flag used by two or more `/sp:dev-*` commands) and the `--next` chain
216
- contract. Moved verbatim from `dev-operations.md` (task 0408) so command files can deep-link
217
- flag entries while this spine reads the operation catalog linearly.
222
+ canonical entry per flag used by two or more `/sp:dev-*` commands) and the `--next` chain contract.
218
223
  - [references/gate-checklists.md](references/gate-checklists.md) — checkbox checklists for the
219
- five gates (feature-check, batch-create, precheck, review, verify). Each checklist is a
220
- `- [ ]` list of prerequisites an agent verifies before entering the gate.
224
+ five gates (feature-check, batch-create, precheck, review, verify).
221
225
  - [references/section-batching.md](references/section-batching.md) — the evidence-section
222
226
  **one-writer protocol** (F92 0593 R1/R2): implement owns `Solution`, the review coordinator owns
223
227
  `Review`, deterministic `record` owns `Testing`; skills query `spur task sections` /
@@ -100,9 +100,12 @@ scenario, it matches by title. Rules:
100
100
  - **No synonyms in cross-references.** The title in the feature file and the title in the
101
101
  task's AC reference must be byte-identical.
102
102
  - **Avoid gate vocabulary in titles.** `spur task check` (L4.gate-language) rejects task sections
103
- containing `HITL`, `approval`/`approved`, `merged`/`merge event`, `content-gate`, `GATED`, or
104
- `capstone` as standalone words; task AC bullets copy scenario titles verbatim, so a title using
105
- them fails every child task. Write "pause for an operator answer" instead of "HITL approval".
103
+ containing `HITL`, `merge event`, `content-gate`, `GATED`, or `capstone` as standalone words;
104
+ ambiguous words (`approval`, `approved`, `merged`) warn only when the same sentence also carries
105
+ a gating cue (`until`, `after`, `once`, `before`, `pending`, `blocked`, `wait for`, `requires`)
106
+ — plain composition prose like "the stages merged back into one step" stays silent. Task AC
107
+ bullets copy scenario titles verbatim, so a title using the unconditional tokens fails every
108
+ child task. Write "pause for an operator answer" instead of "HITL approval".
106
109
 
107
110
  ## Verdict AC ↔ feature scenario linkage
108
111
 
@@ -245,25 +245,36 @@ stage is required, select the subprocess path (`--agent auto` or `--agent <name>
245
245
 
246
246
  The workflow-backed dev commands (`dev-run`, `dev-runall`, `dev-refineall`, `dev-verifyall`) share one
247
247
  startup order. The order is load-bearing and applies on both the inline driver and the subprocess
248
- path; skill-only operations (refine/verify batches with no nested workflow) display their owned
248
+ path. Runs that resolve a workflow definition publish the generated plan as their first action
249
+ (1105 R1); skill-only operations (refine/verify batches with no nested workflow) display their owned
249
250
  procedure and do not fabricate a workflow YAML.
250
251
 
251
- 1. **Publish a compact bootstrap checklist immediately** (host-preparation rows, never copied
252
- workflow states): `A, Quick readiness` · `B, Prepare Git` · `C, Publish workflow plan` ·
253
- `D, Comprehensive checking`.
254
- 2. **Quick deterministic readiness (R2), before isolation.** Evaluate `quickReadiness`
252
+ 1. **Publish the generated plan first (1105 R1), before readiness and isolation.** Resolve the
253
+ selected workflow through the same resolver execution uses and run `spur workflow show
254
+ <resolved-file> --no-logo --format todo --json`; the projection reads the definition and executes
255
+ nothing, so publishing it first is safe. Publish every `.plan` row's `text` verbatim (`A Prepare`,
256
+ `B Implement`, `B1 … · precheck`) as the visible host list — never hand-write rows or copy state
257
+ tables into prose. `.plan` is `null` for unannotated workflows: those keep the flat `steps[]`
258
+ inventory with `columnLabel` labels; the skill-only refine/verify batches keep the bootstrap rows
259
+ below.
260
+ 2. **Quick deterministic readiness (R2) — plan row A1, before isolation.** Evaluate `quickReadiness`
255
261
  (`plugins/sp/scripts/batch-preflight.ts`) with the operation, status, filtered-set size, and the
256
262
  selected matrix required/present sections + content-policy findings. This is an admission decision
257
263
  (runnable / needs-refinement / blocked / skipped / invalid), never an implementation certificate.
258
- 3. **Isolation (R3), only when `--worktree` is valid.** After quick readiness and the required Git
259
- safety checks, create/adopt and switch to the execution tree; confirm absolute cwd, branch, base
260
- SHA, and ownership. An invalid/empty target, unsupported mode, ambiguous ownership, or stale target
261
- stops without creating a tree or discarding work. All subsequent tools, agents, corpus writes, and
262
- run artifacts use the confirmed execution tree.
263
- 4. **Publish the workflow inventory (R4), before reading the YAML.** `spur workflow show
264
- <resolved-file> --no-logo --format todo --json`; validate with `parseWorkflowInventory` and bind to
265
- the run's `__definitionDigest` with `assertInventoryIdentity`. Drift or projection failure stops the
266
- run before any comprehensive/model work — never execute with a misleading plan.
264
+ 3. **Isolation (R3) — plan row A2, only when `--worktree` is valid.** After quick readiness and the
265
+ required Git safety checks, create/adopt and switch to the execution tree; confirm absolute cwd,
266
+ branch, base SHA, and ownership. An invalid/empty target, unsupported mode, ambiguous ownership, or
267
+ stale target stops without creating a tree or discarding work. All subsequent tools, agents, corpus
268
+ writes, and run artifacts use the confirmed execution tree.
269
+ 4. **Bind the published plan to the run digest (R4) — plan row A3.** Validate the step-1 projection
270
+ with `parseWorkflowInventory` and bind it to the run's `__definitionDigest` with
271
+ `assertInventoryIdentity`. Drift or projection failure stops the run before any
272
+ comprehensive/model work — never execute with a misleading plan.
273
+
274
+ **Bootstrap rows without a generated plan (1105 R1).** `dev-refineall` and `dev-verifyall` have no
275
+ workflow plan (their phases are map I13 fog), so until phases exist they keep publishing a compact
276
+ host-preparation checklist immediately, never copied workflow states: A Quick readiness, B Prepare
277
+ Git, C Publish workflow plan, D Comprehensive checking.
267
278
  5. **Load execution detail and run comprehensive checks (R7).** Only after the plan is visible (and
268
279
  after isolation when requested) load the full YAML for the active stage and run the owning
269
280
  comprehensive gates at their boundaries. Prefer deterministic checks; invoke semantic model work
@@ -300,6 +311,12 @@ keeps a malformed task out of `testing`/`done`.
300
311
  lifecycle-*run* creation because it is already a run and a nested one would orphan. The structural
301
312
  gate still runs — `→ testing` and `→ done` invoke `spur task check` regardless of the flag.
302
313
 
314
+ **Worktree interaction (1149 R1/R3).** When an interactive `--next` chain runs inside an isolated
315
+ git worktree (`--worktree`), the un-suppressed transitions create a `task-lifecycle` row in the
316
+ worktree DB. When persist-out runs at landing, the terminal row is classified as non-fatal
317
+ bookkeeping (`external-key-conflict-bookkeeping`) so it does not block teardown, and the receiving
318
+ lifecycle row in the invoking tree is automatically reconciled to `done`.
319
+
303
320
  > **Behavior corrected 2026-08-07.** `--no-lifecycle` previously suppressed enforcement as a side
304
321
  > effect of suppressing the run record, because the FSM guards live inside the lifecycle workflow.
305
322
  > Combined with `--force-done` (which waives the verify **verdict** only) it left nothing: a task
@@ -542,6 +559,24 @@ Do not re-run the full suite per iteration, and do not `spur-check` before you h
542
559
  target. **Target:** full `spur-check` runs ≤2 per task (one during iteration, one final) instead of
543
560
  4 across a chain.
544
561
 
562
+ **Isolation rerun for load-flakes (task 1112 review).** Under concurrent fleet load, subprocess-heavy
563
+ tests can exceed bun's 5s default timeout. Five such timeouts were seen during 1112, and each one
564
+ passed when run alone. A full gate that fails *only* on timeouts in tests outside the change scope
565
+ does not earn another full-gate run:
566
+
567
+ 1. Rerun each timed-out test alone: `(cd <workspace> && bun test <file> --test-name-pattern <test>)`.
568
+ 2. **Green alone** → classify it as a load-flake. Cite the gate failure (test, elapsed ms) and the
569
+ isolated pass receipt in the verify evidence. The original full-gate run stands as the single
570
+ final gate.
571
+ 3. **Red alone**, or a failure that is not a timeout → it is a real failure. Fix it.
572
+ 4. Give the test an explicit per-test timeout and a WHY comment (see
573
+ `plugins/sp/tests/inline-run-close-reason.test.ts:100-102`) as soon as EITHER (a) the same test
574
+ load-flakes in two separate runs, OR (b) it times out once **outside the change scope** and then
575
+ passes green alone on three consecutive isolated reruns. Waiting for a second gate run to license
576
+ the fix cost 21 minutes on 2026-10-08 (task 1128, the 1058 two-tree canary: 5145 ms then 5967 ms
577
+ against bun's 5000 ms default, green 3/3 alone). Never raise the global timeout, skip the test,
578
+ or loop full-gate reruns.
579
+
545
580
  ## Auto-Decision Principles
546
581
 
547
582
  Seven principles governing `--auto` mode. `--auto` sets `profile=auto` in the workflow vars; the
@@ -84,9 +84,10 @@ each would be scope creep for one-liner procedures.
84
84
  | 11 | handover | `dev-handover` | `inline` | structured doc generation | `"<blocker description>"` |
85
85
  | 11a | job-dump | `dev-job-dump` | `Skill()` | `sp:spur-dev` (`job-dump`) | `--file <path>` |
86
86
  | 11b | job-resume | `dev-job-resume` | `Skill()` | `sp:spur-dev` (`job-resume`) | `--file <path>` |
87
- | 12 | brainstorm | `dev-brainstorm` | `Skill()` | `sp:brainstorm` (`dev-brainstorm`) | `<topic> [--depth <basic\|detailed\|comprehensive>] [--options <n>] [--agent <inline\|auto\|name>] [--skip-discovery] [--wayfind] [--task [<feature-id>]] [--feature [<parent-id>]] [--next]` |
88
- | 13 | runall | `dev-runall` | `Skill()` → agent | `sp:spur-dev` (`runall`) → `sp:super-planner` | `--tasks <selector> [--feature <id>] [--mode <sequential\|parallel>] [--keep-going] [--auto] [--agent <inline\|auto\|name>] [--json] [--wrap] [--next] [--continue] [--worktree [<name>]] [--no-summary]` |
89
- | 13a | parallel | `dev-parallel` | `Skill()` | `sp:parallel-execution` | `--tasks <selector> [--feature <id>] [--mode <fan-out\|review-panel\|investigation>] [--agent <inline\|auto\|name>] [--json]` |
87
+ | 12 | brainstorm | `dev-brainstorm` | `Skill()` | `sp:brainstorm` (`dev-brainstorm`) | `<topic> [--depth <basic\|detailed\|comprehensive>] [--options <n>] [--agent <inline\|auto\|name>] [--skip-discovery] [--task [<feature-id>]] [--feature [<parent-id>]] [--next]` |
88
+ | 12a | find-way | `dev-find-way` | `Skill()` | `sp:wayfinder` (worktree-isolated) | `<idea> \| <feature-id> [<wbs>] [--agent <inline\|auto\|name>] [--auto] [--worktree [<name>]] [--wrap]` |
89
+ | 13 | runall | `dev-runall` | `Skill()` → agent | `sp:spur-dev` (`runall`) → `sp:super-planner` | `--tasks <selector> [--feature <id>] [--mode <sequential\|parallel>] [--keep-going] [--auto] [--agent <inline\|auto\|name>] [--json] [--wrap] [--next] [--continue] [--worktree [<name>]] [--no-summary] [--defer-gate]` |
90
+ | 13a | parallel | `dev-parallel` | `Skill()` | `sp:parallel-execution` | `--tasks <selector> [--feature <id>] [--mode <fan-out\|review-panel\|investigation>] [--agent <inline\|auto\|name>] [--json] [--defer-gate]` |
90
91
  | 14 | wrap | `dev-wrap` | `Skill()` | `spur workflow run` (wrapup-pipeline) | `<wbs> [--agent <inline\|auto\|name>] [--auto] [--merge] [--dry-run]` |
91
92
  | 15 | wrapall | `dev-wrapall` | `Skill()` | `spur workflow run` (wrapup-pipeline) | `[--since <iso>] [--feature <id>] [--status <s>] [--agent <inline\|auto\|name>] [--auto] [--merge] [--dry-run]` |
92
93
  | 16 | idea | `dev-idea` | `Skill()` | inline driver (`idea-pipeline`) or async workflow | `"<idea>" \| --from-file <path> [--skip-design] [--agent <inline\|auto\|name>] [--auto]` |
@@ -165,18 +166,29 @@ must not be changed without updating the backing skill.
165
166
 
166
167
  #### Execution summary
167
168
 
168
- Default on for full-mode `dev-run` and `dev-runall`; `--no-summary` skips it. At command start record
169
- `SINCE=$(date -u +%Y-%m-%dT%H:%M:%SZ)`. When the run settles (done, failed or paused), write each run's
170
- `spur workflow progress <run-id> --json` to `$TMPDIR/<run-id>-progress.json` and print, verbatim under an
171
- `### Execution summary` heading:
172
- `node "$(superskill script path sp run-summary.mjs)" --since "$SINCE" --progress <file> --markdown`
173
- (`dev-runall`: one `--progress <wbs>=<file>` per attempted run). One file renders one row per state visit;
174
- several render one row per run; a `driver overhead` row carries host work outside every stage window so rows
175
- sum to `Total` (omitted when parallel runs overlap). Columns: Stage | Status | Time | Wait | Tool calls |
176
- Token (total / non-cached) — total counts every input class plus output; non-cached drops cache reads.
177
- Stage windows with no host transcript record (subprocess executors) render `n/a`, never 0. The summary is
178
- reporting only: a failure prints `Execution summary: n/a (<reason>)` and never changes the run's outcome.
179
- Not printed for `--mode implement` (no workflow run).
169
+ Produced by the run's own close (1146 R1), not by a trailing step: `inline-run-setup --close` writes
170
+ `.spur/run/<runId>-summary.md` + `.json` and reports `summaryFile` in its stdout JSON. The driver's only
171
+ job is to print that file's contents under an `### Execution summary` heading, and to pass `--no-summary`
172
+ through to `--close`. `--no-summary` is a `--close` flag: anywhere else it is a usage error.
173
+
174
+ `/sp:dev-runall` shows one summary per run — each produced by that run's own close, so each window is its own
175
+ `runs.started_at` → close time and no block reuses a batch-wide window — plus one batch roll-up:
176
+
177
+ ```
178
+ node "$(superskill script path sp run-summary.mjs)" --rollup <runId>-summary.json --rollup <runId2>-summary.json
179
+ ```
180
+
181
+ which renders one row per run (that run's own Total) and a bold total of the sums; when run windows overlap it
182
+ also states the wall span from the first start to the last end.
183
+
184
+ Columns: Stage | Status | Time | Wait | Tool calls | Token (total / non-cached) — total counts every input
185
+ class plus output; non-cached drops cache reads. The actor split under the table partitions the same window —
186
+ operator wait (with its longest single wait), model, shell, subagent, other tools and idle — and those rows sum
187
+ exactly to the window; gate time is shown as an informational `of which gate` row sourced only from this run's
188
+ check receipt (`receipt.runId === runId`), otherwise `n/a (<reason>)`. Any value with no source renders
189
+ `n/a (<reason>)`, never 0. The summary is reporting only: a failure prints
190
+ `Execution summary: n/a (<reason>)` and never changes the run's outcome. Not printed for `--mode implement`
191
+ (no workflow run).
180
192
 
181
193
  ### 5. refine
182
194
 
@@ -441,11 +453,20 @@ gate commands, pending questions and approval requirements.>
441
453
  Report the new task WBS and file path; the task lands at `todo`, ready for `/sp:dev-refine`.
442
454
 
443
455
  - **Delegation:** `Skill(skill="sp:brainstorm", args="dev-brainstorm --context <decision-tree> --options <n>")`
456
+ - **Scope boundary:** brainstorm never charts a multi-session map. A foggy destination stops the run with a recommendation to use `/sp:dev-find-way` (§ 12a).
457
+
458
+ ### 12a. find-way
459
+
460
+ - **Purpose:** Wayfinding — chart a multi-session investigation map for a foggy destination (`<idea>`), or resolve exactly one ticket of an existing map (`<feature-id> [<wbs>]`).
461
+ - **Isolation (mandatory):** every invocation runs in a git worktree + branch per [execution-batch.md § Worktree isolation](execution-batch.md#worktree-isolation---worktree-name) as a run of one — marker `command: dev-find-way`, `selector` `chart:<slug>` or `<feature-id>:<wbs>`, branch `sp/wayfind-<slug|wbs>-<short-id>`. Omitted `--worktree` equals bare `--worktree` (create); `--worktree <name>` adopts. No in-place or branch-switch mode.
462
+ - **Parallel sessions:** frontier selection excludes tickets held by other `dev-find-way` markers (`active`/`retained`) in the invoking tree's `.spur/run/`, because a `wip` claim is invisible outside its worktree until the merge.
463
+ - **`--wrap`:** work mode only — `/sp:dev-wrap <wbs>` inside the worktree after the ticket reaches `done`, before the WT-3b commit; skipped with a reason in chart mode.
464
+ - **Delegation:** `Skill(skill="sp:wayfinder", args="$ARGUMENTS")` inside the worktree.
444
465
 
445
466
  ### 13. runall
446
467
 
447
468
  - **Purpose:** Run a batch of tasks through their pipelines in dependency-correct order — resolve a set, topo-sort, run each via `task-pipeline.yaml`, inspect verdicts, apply the failure policy, emit a batch report.
448
- - **Inputs:** `--tasks <selector>` (required — explicit WBS list, status pseudo-list, `feature:<id>`, or `ready`). `--mode <sequential|parallel>` (default `sequential`; `parallel` fans out a proven-independent subset per `execution-batch.md` § Parallel Execution). `--keep-going` skips a failed task's in-batch dependents and continues independents (default halts on first failure). `--auto` sets `profile=auto` on each per-task run (skips the HITL approve gate). `--feature <id>` is sugar for `--tasks feature:<id>`; when the effective selector is feature-derived, the batch runs `spur feature check <id> --strict --json` **once** before task resolution — a non-zero strict check aborts with verdict `aborted`, zero attempted tasks, and the structured findings (task 0510 R2); scoped: `L4.scenario-unverified` (expected pre-run state of any not-yet-run feature) is reported verbatim but does not abort — any other strict error aborts. Explicit WBS/status/`ready` selectors add no feature check. The orchestrator loop itself continues in this session; interactive sequential omit/`inline` uses the host driver — host-controlled with eligible `agent.run` stages dispatching once to a native subagent and host fallback (task 0508) — while `--agent auto`/a name, parallel mode, and headless invocation keep the isolated per-task workflow subprocess boundary. `--agent <inline|auto|name>` pins the executor for the per-task stages (see [SSOT](cross-cutting.md#inline-default-execution-surface)); the value crosses into per-task `vars.agent`, not the orchestrator. `--json` emits the report as JSON. `--wrap` triggers `wrapup-pipeline.yaml` **once for the batch** over the `done` subset only (execution-batch.md Step 6: `vars.feature` only when every frozen task is `done`/`cancelled`; empty done subset skips with a reason), `--next` chains each task to terminal status then runs the same batch-once wrap, `--continue` resumes from checkpoint. `--no-summary` skips the [execution summary](#execution-summary) printed after the batch report (one row per attempted run).
469
+ - **Inputs:** `--tasks <selector>` (required — explicit WBS list, status pseudo-list, `feature:<id>`, or `ready`). `--mode <sequential|parallel>` (default `sequential`; `parallel` fans out a proven-independent subset per `execution-batch.md` § Parallel Execution). `--keep-going` skips a failed task's in-batch dependents and continues independents (default halts on first failure). `--auto` sets `profile=auto` on each per-task run (skips the HITL approve gate). `--feature <id>` is sugar for `--tasks feature:<id>`; when the effective selector is feature-derived, the batch runs `spur feature check <id> --fix --json` then `spur feature check <id> --strict --json` **once** before task resolution — a non-zero strict check aborts with verdict `aborted`, zero attempted tasks, and the structured findings (task 0510 R2); scoped: `L4.scenario-unverified` and `L4.verifying-incomplete-tasks` (expected pre-run states of a not-yet-run or reopened feature) are reported verbatim but do not abort — the non-aborting set is `NON_ABORTING_PREFLIGHT_CODES` in `plugins/sp/scripts/batch-preflight.ts` and `--fix` repairs are listed under `autoRepairs` — any other strict error aborts. Explicit WBS/status/`ready` selectors add no feature check. The orchestrator loop itself continues in this session; interactive sequential omit/`inline` uses the host driver — host-controlled with eligible `agent.run` stages dispatching once to a native subagent and host fallback (task 0508) — while `--agent auto`/a name, parallel mode, and headless invocation keep the isolated per-task workflow subprocess boundary. `--agent <inline|auto|name>` pins the executor for the per-task stages (see [SSOT](cross-cutting.md#inline-default-execution-surface)); the value crosses into per-task `vars.agent`, not the orchestrator. `--json` emits the report as JSON. `--wrap` triggers `wrapup-pipeline.yaml` **once for the batch** over the `done` subset only (execution-batch.md Step 6: `vars.feature` only when every frozen task is `done`/`cancelled`; empty done subset skips with a reason), `--next` chains each task to terminal status then runs the same batch-once wrap, `--continue` resumes from checkpoint. `--no-summary` skips the [execution summary](#execution-summary) printed after the batch report (one row per attempted run).
449
470
  - **Three orthogonal axes (do not confuse):** `--keep-going` = batch failure policy (halt vs skip dependents); `--continue` = resume from checkpoint against the batch's original frozen identity (execution-batch.md § Batch continuation, task 0919); `--next` = per-task lifecycle chaining (advance status on a verdict — `dev-verify`/`dev-verifyall` only). `routing-table.md` offers `--continue` and `--next` as competing options for the same situation only when the batch was interrupted mid-run; otherwise they address different problems.
450
471
  - **Backing:** `sp:spur-dev` skill, `runall` operation → delegates the driver loop to the **`sp:super-planner`** agent (the batch orchestrator).
451
472
  - **Behavior:** The orchestrator reads [execution-batch.md](execution-batch.md) and drives: resolve selector → freeze set → topo-sort by `dependencies[]` (Kahn, WBS-ascending tie-break; cycle aborts) → resolve out-of-set deps by status (done → allow, else → block subtree) → run each task via `spur workflow run task-pipeline.yaml --async` + `spur workflow trace` polling → inspect terminal state + `.spur/run/<wbs>-verdict.json` → stop-the-batch default or `--keep-going` subtree skip → emit batch report. Per-task pipeline is invoked **verbatim** — no new FSM, no step edits. `--auto`/`--agent` are the only flags that cross the orchestrator→pipeline boundary (both into per-task `--vars`).
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: execution-batch-continuation
3
+ description: "--continue resume of an interrupted batch (task 1128 split): original frozen identity re-binding (BC-1), checkpoints-as-hints reconciliation (BC-2) and ordering/write-ownership/terminal-mix rules (BC-3). Read it with --continue."
4
+ see_also:
5
+ - execution-batch
6
+ - execution-workflow
7
+ ---
8
+
9
+ ## Batch continuation (`--continue`) — identity binding + checkpoint reconciliation (task 0919)
10
+
11
+ `--continue` resumes an interrupted batch against the batch's **original identity** — never
12
+ whatever a fresh selector resolution or a newer unrelated checkpoint would suggest.
13
+
14
+ ### BC-1 — Re-bind the original frozen identity (R1; AC1/AC5)
15
+
16
+ Resume identity comes from persisted batch artifacts, in priority order:
17
+
18
+ 1. **WT-3 marker** (worktree batches): the marker's `command` + `selector` and worktree
19
+ name/branch re-derive the original launch (the WT-6 fallback already resolves this way).
20
+ 2. **Persisted batch report** (`.spur/run/worktree-<marker-id>-batch-report.md`, or the
21
+ invoking-tree Step 5 report of a non-worktree batch): its `Plan:` row IS the frozen ordered
22
+ membership — the resumed loop iterates exactly those WBS rows.
23
+
24
+ Re-running the selector is a **validation, not a re-definition**: tasks that newly match the
25
+ selector but are absent from the frozen plan are reported `not-admitted` and never executed —
26
+ freshly listed tasks do not join a resumed batch implicitly. A frozen task whose dependencies
27
+ changed after freeze may invalidate its admission: report `blocked (admission invalidated —
28
+ re-plan required)` and stop for operator decision. The authorized frozen set is never silently
29
+ rewritten (Design).
30
+
31
+ ### BC-2 — Checkpoints are hints (R2; AC2)
32
+
33
+ Do **not** pick the resume point by mtime alone: `ls -t … | head -1` over `.spur/memory/sessions/`
34
+ is identity-blind, so an unrelated later session (different feature or task) must not become
35
+ authoritative. Select candidate checkpoints by identity first, newest first within the match:
36
+
37
+ - frontmatter `workflow` is `task-pipeline` (or the batch's own workflow), and
38
+ - `feature_id` equals the batch's feature selector, or `task_wbs` is a member of the frozen plan.
39
+
40
+ Checkpoints matching neither rule are ignored regardless of recency. A matched checkpoint only
41
+ **hints** where the loop left off (`phase`, `next_action` — surface them to the operator); the
42
+ driver then reconciles against authoritative state before skipping or repeating any task:
43
+
44
+ - **Skip** requires ALL of: task file status `done` AND a persisted PASS verdict artifact
45
+ (`.spur/run/<wbs>-verdict.json`, or the worktree-persisted
46
+ `.spur/run/worktree-<marker-id>-verdicts/<wbs>-verdict.json`) consistent with the task's
47
+ current metadata. Anything less is not a valid skip.
48
+ - **Stale or mismatched evidence** — checkpoint claims done but the verdict artifact is missing,
49
+ the task file moved backwards, or the recorded `source_commit`/`digest` no longer matches —
50
+ yields outcome `recheck`: re-run that task's pipeline. When reconciliation cannot proceed
51
+ safely (lost worktree, unresolvable marker), report `blocked` with the reason. Never treat an
52
+ unverified claim as done.
53
+
54
+ ### BC-3 — Ordering, write ownership, terminal mix, evidence (R3/R4; AC3/AC4)
55
+
56
+ Sequential dependency-correct execution remains the default; opt-in `--mode parallel` keeps the
57
+ existing proven-independence requirements with one writer per tree (Step 3). Mixed terminal
58
+ results resume under the unchanged failure policy (Step 4). The Step 5 report keeps per-task
59
+ outcomes distinct — `done | failed | blocked | skipped | not-attempted` plus the resume-only
60
+ `recheck` and `not-admitted` — and the batch verdict stays `halted`/`aborted`: a resumed,
61
+ partially-complete batch is never reported `clean`. Worktree evidence survives cleanup via the
62
+ invoking-tree persistence in Step 5 (task 0720 R3); a persistence failure routes to **WT-5**
63
+ (retain tree + branch), so partial outcomes are never silently lost and never read as a completed
64
+ batch.
65
+
66
+ See [cross-cutting.md](cross-cutting.md) § "Session Checkpoint Convention" for the canonical
67
+ frontmatter fields and the per-task owner-mismatch semantics
68
+ (`packages/app/src/workflow/checkpoint-contract.ts`).
@@ -0,0 +1,194 @@
1
+ ---
2
+ name: execution-batch-report
3
+ description: "Batch end of the driver loop (task 1128 split): the Step 5 structured Batch Report template, the zero-task rule, the worktree evidence-persistence contract, and Step 6 Batch wrap (--wrap/--next) including the guarded close-out commit. Read it when Step 5 runs; the loop itself stays in execution-batch.md."
4
+ see_also:
5
+ - execution-batch
6
+ - execution-workflow
7
+ ---
8
+
9
+ # Batch report and batch wrap
10
+
11
+ Read at Step 5 and once at batch end (task 1128 R1).
12
+
13
+ ## Step 5 — Batch report (R5.2)
14
+
15
+ When the batch finishes — clean (all `done`), halted (default failure policy), parked (`paused`:
16
+ one or more tasks sit on an operator question (escalate, 0933) or an approval gate), or aborted
17
+ (cycle / unknown selector) — emit a structured report. The report is the orchestrator's sole
18
+ output; it does not mutate the corpus (the pipeline's `record` step already wrote per-task
19
+ results). A `paused` task is non-terminal — the report marks it `paused` (never `done`) and names
20
+ the resume command. Unless `--no-summary`, follow it with the measured
21
+ [execution summary](dev-operations.md#execution-summary), one `--progress <wbs>=<file>` per attempted run.
22
+
23
+ ```
24
+ ## Batch Report — <selector>
25
+
26
+ **Selector:** <value>
27
+ **Plan:** <n> tasks (ordered: <wbs-list>) · <m> blocked · <p> not-attempted
28
+ **Mode:** stop-the-batch | --keep-going | --auto
29
+ **Verdict:** clean | halted | aborted
30
+
31
+ | WBS | Status | Reason |
32
+ |-----|--------|--------|
33
+ | 0040 | done | — |
34
+ | 0042 | failed | verify verdict PARTIAL (see .spur/run/0042-verdict.json) |
35
+ | 0050 | not-attempted | batch halted after 0042 (stop-the-batch) |
36
+ | 0051 | skipped | dependency 0040 failed (--keep-going) |
37
+ | 0060 | blocked | unmet out-of-set dep: 0099 is wip |
38
+
39
+ **Next:** <one-line action — pick up halted run / resolve 0099 / all green, feature H1 complete>
40
+
41
+ **Excluded from wrap** (only under `--wrap`/`--next`, when some batch tasks are not `done`):
42
+
43
+ ```
44
+ | WBS | Status | Recovery |
45
+ |-----|--------|--------|
46
+ | 0042 | failed | C6 recovery: /sp:dev-run 0042 (residual report: .spur/run/0042-residual-report.md) |
47
+ | 0050 | not-attempted | /sp:dev-next 0050 |
48
+ ```
49
+
50
+ A task with a residual report (failing `residual-sweep` check in its verdict artifact) uses the
51
+ C6 recovery line (re-run the pipeline); every other excluded task uses the next-router A-row
52
+ command for its status (F96 task 0952 R2).
53
+
54
+ The per-task outcome vocabulary: `done` | `failed` | `blocked` | `skipped` | `not-attempted`,
55
+ plus the resume-only `recheck` (stale/mismatched evidence — pipeline re-run), `not-admitted`
56
+ (post-freeze selector match, never executed — task 0919 BC-1/BC-2), and the parallel-only
57
+ `integration-conflict` (rebase conflict retained for manual integration — task 0931 R4,
58
+ [§ Parallel isolation](#parallel-isolation---mode-parallel)).
59
+ The batch verdict: `clean` (all attempted tasks `done`) | `halted` (a failure stopped the batch) |
60
+ `aborted` (cycle or selector error before any run).
61
+
62
+ **Zero-task rule (task 0701 R7b).** A selector that resolves to an **empty set after the status
63
+ filter** is an `aborted` verdict (`aborted (empty set after filter)`), matching dev-operations.md
64
+ §5a. Under `--worktree`, **WT-2 is skipped entirely**: no worktree is cut and no WT-3 marker is
65
+ written for a batch with nothing to run. The early-exit report carries zero per-task rows,
66
+ `Steps: 0 derived, 0 executed`, and the `aborted` verdict; no WT-3b commit step and no WT-4/WT-5
67
+ terminal action runs. A contract test pins this
68
+ (`plugins/sp/tests/dogfood-testing/execution-batch-contract.test.ts`).
69
+
70
+ **Evidence persistence (worktree batches — task 0720 R3).** Copy-out is mandatory.
71
+ A worktree batch's Step 5 report, verdict artifacts, and the batch's own
72
+ `.spur/run` records live in the worktree while the batch runs — exactly the tree
73
+ create-mode WT-4 deletes. Before any WT-4 removal, persist them into the **invoking** tree, which
74
+ survives removal:
75
+
76
+ - Write the emitted batch report to `.spur/run/worktree-<marker-id>-batch-report.md`.
77
+ - Copy each attempted task's `.spur/run/<wbs>-verdict.json` from the worktree to
78
+ `.spur/run/worktree-<marker-id>-verdicts/<wbs>-verdict.json`.
79
+ - Make the report's per-task verdict references use those persisted invoking-tree paths, not the
80
+ worktree-local paths that removal deletes.
81
+
82
+ Evidence persistence precedes destructive cleanup: a persistence failure (unreadable verdict file,
83
+ disk-full, missing directory) routes to **WT-5** — the worktree and branch are retained so a green
84
+ batch can never destroy its own evidence. Reuse mode retains its operator-owned tree but still
85
+ persists the Step 5 report under the invoking tree; the reused tree's `.spur/run/` remains the live
86
+ copy while that tree lives on. The per-run provenance — the worktree DB's run/action rows and the
87
+ `.spur/memory/runs/<runId>.md` + `.state.json` records — is persisted mechanically by WT-4a's
88
+ `inline-run-setup.ts --persist-out --from <worktree> [--task-file <merged-task>]...` call,
89
+ not by hand.
90
+
91
+ **Stage records are worktree-local too (0948 R9, E7 Finding 5; persisted by 0975 R1).** Each task's
92
+ own per-stage run record (`.spur/memory/runs/<runId>.md` + `.state.json`) and the worktree DB's run rows are
93
+ written inside the worktree and **are removed with it** in create mode — the E7 batch lost exactly
94
+ this evidence. Copying them out is no longer a manual audit-time duty: WT-4a (create-mode block
95
+ below) runs `inline-run-setup.ts --persist-out --from "$WT_PATH"` **before** WT-4b holder cleanup,
96
+ which copies the run/action/phase/transition/workflow-state rows and both record files into the
97
+ invoking tree.
98
+
99
+ **Cited evidence rides the same call (0984 R1/R2).** The driver forwards each merged task file with
100
+ repeatable `--task-file <path>` (paths resolved in the invoking tree after the FF merge, e.g.
101
+ `spur task show <wbs> --json` → `.filePath`), and persist-out then copies/verifies every literal
102
+ `.spur/run/<file>` that file cites — WBS verdicts, check receipts, test-gate logs, run-ID records —
103
+ so a merged task file never anchors a path that died with the tree. Abbreviated references
104
+ (`fadca099-…`, `run-*-ac87.log`, `{batch-report.md,…}`) are not literal files and carry no
105
+ obligation; neither do root-qualified paths (`knowledge-kit/.spur/run/…`, `/abs/.spur/run/…`),
106
+ which cite another project's evidence — cite foreign run artifacts that way, never bare. A citation missing in BOTH trees, a divergent cited file (never overwritten — reconcile
107
+ by hand), an unreadable task file, or more than 64 distinct cited files fails the pass → WT-5.
108
+
109
+ **Durable planes ride it too (E71).** Persist-out copies canonical task verdicts, feature run/latest receipts, nested run artifacts and owned sessions before teardown. Artifact and task-run-link rows are exported with run rows, and stored path references are redirected to the invoking tree. Conflicting or unreadable **owned** retained evidence refuses teardown. A divergent copy of evidence a forwarded task does **not** own (its WBS is not a forwarded task's and its receipt `runId` is not a worktree run row) is `foreign-divergent` (1139 R5): it is skipped, reported as `evidenceSkipped[{name, reason:'foreign-divergent', newer:'invoking'|'worktree'}]`, and the invoking-tree copy is never overwritten — another task's newer verdict can no longer block this batch's teardown. A divergent **owned** file still fails with `durable evidence conflicts`. `persist-out-check` accepts the same foreign-divergent set from the success JSON and does not recompute it.
110
+
111
+ **Owned evidence rides it too (1012).** With at least one `--task-file`, persist-out also treats as
112
+ copy obligations the worktree's `.spur/run/` direct children named `<wbs>-…` (the WBS is each
113
+ forwarded task file's leading four digits before `_`) or `<runId>-…` (every run row in the worktree
114
+ DB, whichever task it ran) — `<wbs>-verdict.json`, check receipts, route reasons — whether or not
115
+ the task file cites them. They join the cited set: same copy / byte-identical no-op /
116
+ divergent-refuse handling. The 64-file cap bounds citations alone; owned names are bounded per
117
+ owner (each `<wbs>-` / `<runId>-` prefix gets its own 64-file budget, task 1034), so the bound
118
+ scales with the batch and one runaway owner refuses by name before any write. `<runId>.md` /
119
+ `<runId>.state.json` stay with the record copy (a conflict is reported and the delegate refuses teardown). Files
120
+ matching neither a citation nor an ownership prefix are left behind. An absent worktree `.spur/run/`
121
+ means nothing is owned; any other listing failure (not a directory, permission denied) fails the
122
+ pass before the invoking tree is written → WT-5. Without `--task-file` nothing is enumerated.
123
+
124
+ The shapes are pinned (task 0975 R1; `record-missing`, citation behavior per 0984; `evidenceSkipped` per 1139 R5): idempotent on re-persist;
125
+ success exits 0 printing
126
+ `{"ok":true,"persisted":<n>,"skipped":[{"id":<run-id>,"reason":"id-exists"|"external-key-conflict"|"record-conflict:<file>"|"record-missing:<file>"|"cited-directory:<name>"|"cited-symlink:<name>"|"cited-non-file:<name>"}],"evidenceSkipped":[{"name":<file>,"reason":"foreign-divergent","newer":"invoking"|"worktree"}]}`
127
+ (`evidenceSkipped` is omitted when empty; the same object is written to `<invoking-tree>/.spur/run/persist-out.json` for `persist-out-check` to read)
128
+ — an `external-key-conflict` skip leaves the target run unchanged **and fails the pass (1049)**: the delegate exits 1 printing `{"ok":false,"error":…}` naming the skipped source run ids, because that (workflow, external key) identity already belongs to a different receiving run — the batch was not persisted, so reconcile the source worktree by hand (it stays the provenance owner of record) before any teardown: auditable reconciliation names the original archived DB snapshot and the skipped source run identities, verifies the archive by file hash and by merged-commit ancestry of the source branch, and treats any residual deletion as explicit operator-authorized cleanup under the strict canonical evidence rules above. Task 1149 R1 grades a terminal duplicate lifecycle row (`task-lifecycle`/`feature-lifecycle`) as `external-key-conflict-bookkeeping` (non-fatal), so guarded transitions driven inside the worktree do not block teardown; the receiving lifecycle row is reconciled automatically during persist-out. An `id-exists` replay repairs missing owned artifacts and task links without duplicating them. A
129
+ `record-conflict:<file>` never overwrites a divergent invoking-tree record and causes the delegate to exit 1, retaining the worktree. A
130
+ `record-missing:<file>` skip is a known `task-lifecycle`/`feature-lifecycle` row with no record file
131
+ at all (its inserted DB row still counts in `persisted` — 0984 R5). Any failure
132
+ exits 1 printing `{"ok":false,"error":<message>}` (a worktree DB run id that is not a single safe
133
+ filename component is rejected before any target write). Any persist-out failure
134
+ routes to **WT-5** — worktree and branch retained — the same copy-out-first contract as the
135
+ verdict persistence above. After a green persist-out, `spur workflow progress --json` in the
136
+ invoking tree shows the merged run `done` with its per-action rows.
137
+
138
+ **Batch roll-up (1146 R3).** After the last run closes, print one `### Execution summary` block per run
139
+ (each from that run's own `summaryFile`, so each window is its own `runs.started_at` → close time), then
140
+ the batch roll-up built from the per-run files:
141
+
142
+ ```bash
143
+ node "$(superskill script path sp run-summary.mjs)" --rollup <runId>-summary.json --rollup <runId2>-summary.json
144
+ ```
145
+
146
+ One row per run carrying that run's own Total, a bold total of the sums, and — when run windows overlap —
147
+ a wall-span line from the first start to the last end. No run block reuses a batch-wide window.
148
+
149
+ ## Step 6 — Batch wrap (`--wrap` / `--next`) (F96 task 0952 R1)
150
+
151
+ Run **once for the batch**, after the Step 5 report — never per task (dev-operations.md §runall
152
+ agrees; the old "per task" flag-row wording in dev-runall.md was a contradiction, now fixed).
153
+
154
+ The wrap receives only what it would accept:
155
+
156
+ 1. `vars.tasks` = the JSON-encoded array of batch WBS whose terminal status is `done`. A task that
157
+ is `failed`/`blocked`/`skipped`/`not-attempted`/`recheck`/`not-admitted` is **excluded** —
158
+ `wrapup task-resolve` refuses non-done members (wrapup-steps.ts task-resolve), so the driver
159
+ simply stops handing the wrap tasks it would refuse.
160
+ 2. `vars.feature` = the batch feature **only when every task in the frozen batch is `done` or
161
+ `cancelled`**. Otherwise omit it and print `feature lifecycle not advanced: <n> task(s)
162
+ unfinished` — advancing a feature while some of its batch tasks are unfinished would overstate
163
+ completion. Learnings/metrics capture still happens for the done subset.
164
+ 3. When the done subset is **empty**, skip the wrap entirely with the reason (e.g. `batch wrap
165
+ skipped: no done tasks`) instead of invoking wrapup-pipeline on an empty set.
166
+
167
+ **Repo-wide tripwire (1037).** After the doc-sync exits converge, the pipeline's `doc-tripwire` hop
168
+ runs the TRUSTED CONFIG ONLY `docTripwireCmd` over the still-uncommitted wrap diff before
169
+ metrics-record. The default probes `package.json` for a `test-repo-wide` script and runs
170
+ `bun run test-repo-wide` only when it is declared (a no-op in other projects), so the batch driver
171
+ passes no extra vars. Batch callers override it like any wrap var (`docTripwireCmd` in `--vars`);
172
+ an empty string disables the check while still recording PASS. A FAIL routes the wrap to `failed`
173
+ with already-written learnings/docs preserved — fix the flagged working-diff violation and re-run
174
+ the wrap.
175
+
176
+ Filtering lives here, in the batch driver — no change to wrapup-pipeline.yaml or wrapup-steps.ts;
177
+ the wrap's refusal of non-done tasks remains the hard invariant.
178
+
179
+ **Close-out commit (1129 R2/R5).** In sequential mode the wrap's writes (learnings, metrics,
180
+ doc-sync) land in the invoking tree and are committed as ONE close-out commit after the wrap exits.
181
+ Stage them through the guard — never a free-form `git add` — so a concurrent writer's file cannot
182
+ ride into the close-out commit (incident `36f274590`). `$RUN_ID` is the id Step 3 fixed before
183
+ `commit-guard start` (execution-batch.md § Step 3); an unset id makes the guard exit 1 — fail closed:
184
+
185
+ ```bash
186
+ GUARD=plugins/sp/scripts/commit-guard.ts; [ -f config/plugin-scripts.json -a -f "$GUARD" ] || GUARD="$(superskill script path sp commit-guard.mjs 2>/dev/null)"
187
+ bun "$GUARD" check --run "$RUN_ID" # 1129 R3: a non-empty foreign list goes in the batch report
188
+ bun "$GUARD" stage --run "$RUN_ID" -- <files the wrap wrote> \
189
+ || { echo "close-out halt: commit-guard refused a path (foreign, unmerged or conflict-marked); nothing committed" >&2; exit 1; }
190
+ git commit -m "chore(wrap): <command> <selector> close-out writes"
191
+ ```
192
+
193
+ > **Forbidden:** `git add -A` and `git add .` — here as in every driver commit step. In the
194
+ > worktree batch the same rule rides in the WT-3b block above.