@gobing-ai/spur 0.3.90 → 0.3.92

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 (130) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/pipeline-budgets.json +9 -2
  3. package/config/plugin-scripts.json +17 -1
  4. package/config/workflows/decision-routing-example.yaml +134 -0
  5. package/config/workflows/feature-lifecycle.yaml +14 -5
  6. package/config/workflows/feature-verification.yaml +35 -27
  7. package/config/workflows/history-anatomy.yaml +14 -25
  8. package/config/workflows/idea-pipeline.yaml +17 -5
  9. package/config/workflows/task-pipeline.yaml +187 -4
  10. package/config/workflows/wayfinder-resolution.yaml +2 -0
  11. package/config/workflows/wrapup-pipeline.yaml +49 -5
  12. package/package.json +9 -9
  13. package/plugins/sp/README.md +1 -0
  14. package/plugins/sp/agents/expert-spur.md +2 -2
  15. package/plugins/sp/agents/super-planner.md +14 -5
  16. package/plugins/sp/commands/dev-dogfood.md +4 -4
  17. package/plugins/sp/commands/dev-fixall.md +8 -5
  18. package/plugins/sp/commands/dev-run.md +6 -0
  19. package/plugins/sp/commands/dev-runall.md +12 -6
  20. package/plugins/sp/commands/dev-verify.md +9 -0
  21. package/plugins/sp/commands/dev-verifyall.md +5 -0
  22. package/plugins/sp/lib/idea-handoff.generated.mjs +301 -300
  23. package/plugins/sp/lib/inline-run.generated.d.mts +17 -0
  24. package/plugins/sp/lib/inline-run.generated.mjs +1460 -0
  25. package/plugins/sp/plugin.json +1 -1
  26. package/plugins/sp/references/environment-lens.md +1 -1
  27. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +136 -0
  28. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +196 -2
  29. package/plugins/sp/scripts/feature-verification-steps.mjs +174 -0
  30. package/plugins/sp/scripts/feature-verification-steps.ts +275 -0
  31. package/plugins/sp/scripts/history-anatomy-cache.mjs +104 -4
  32. package/plugins/sp/scripts/history-anatomy-cache.ts +137 -13
  33. package/plugins/sp/scripts/inline-pipeline-parity-check.ts +2 -0
  34. package/plugins/sp/scripts/inline-run-setup.mjs +349 -0
  35. package/plugins/sp/scripts/inline-run-setup.ts +192 -75
  36. package/plugins/sp/scripts/record-feature-sync.mjs +63 -0
  37. package/plugins/sp/scripts/record-feature-sync.ts +84 -0
  38. package/plugins/sp/scripts/residual-scan.mjs +476 -0
  39. package/plugins/sp/scripts/residual-scan.ts +614 -0
  40. package/plugins/sp/scripts/surface-drift-inventory.ts +71 -6
  41. package/plugins/sp/scripts/task-evidence-precheck.ts +8 -3
  42. package/plugins/sp/scripts/task-size-precheck.ts +8 -3
  43. package/plugins/sp/scripts/validate-flag-contracts.ts +3 -3
  44. package/plugins/sp/skills/branch-workflow/SKILL.md +1 -0
  45. package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +2 -0
  46. package/plugins/sp/skills/code-implementation/SKILL.md +17 -0
  47. package/plugins/sp/skills/code-verification/SKILL.md +21 -0
  48. package/plugins/sp/skills/code-verification/references/verdict-schema.md +1 -0
  49. package/plugins/sp/skills/dogfood-testing/SKILL.md +5 -3
  50. package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +63 -26
  51. package/plugins/sp/skills/dogfood-testing/references/report-template.md +33 -10
  52. package/plugins/sp/skills/history-anatomy/references/modes.md +5 -3
  53. package/plugins/sp/skills/next-feature/references/ranking-rubric.md +1 -1
  54. package/plugins/sp/skills/next-router/references/routing-table.md +7 -0
  55. package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
  56. package/plugins/sp/skills/session-review/SKILL.md +12 -2
  57. package/plugins/sp/skills/spur-cli/references/agent.md +11 -2
  58. package/plugins/sp/skills/spur-cli/references/features.md +1 -1
  59. package/plugins/sp/skills/spur-cli/references/projects.md +3 -1
  60. package/plugins/sp/skills/spur-cli/references/self.md +5 -1
  61. package/plugins/sp/skills/spur-cli/references/workflows.md +42 -20
  62. package/plugins/sp/skills/spur-dev/SKILL.md +11 -4
  63. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +25 -3
  64. package/plugins/sp/skills/spur-dev/references/dev-operations.md +2 -2
  65. package/plugins/sp/skills/spur-dev/references/execution-batch.md +285 -57
  66. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +14 -5
  67. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +19 -4
  68. package/plugins/sp/skills/spur-dev/references/glossary.md +9 -1
  69. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +51 -16
  70. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +5 -0
  71. package/plugins/sp/skills/wayfinder/SKILL.md +1 -1
  72. package/spur.js +23422 -19364
  73. package/web/_astro/BoardApp.CerSBgis.js +192 -0
  74. package/web/_astro/BoardApp.eoTz0pZs.js +1 -0
  75. package/web/_astro/{TaskDetail.DwTmbQp5.js → TaskDetail.DCqiC-OZ.js} +1 -1
  76. package/web/_astro/arc.CPwg6Rw0.js +1 -0
  77. package/web/_astro/{architectureDiagram-3BPJPVTR.jvdDahWM.js → architectureDiagram-3BPJPVTR.DM_vp_hO.js} +1 -1
  78. package/web/_astro/{blockDiagram-GPEHLZMM.zSg4AmFD.js → blockDiagram-GPEHLZMM.DXVIiv0p.js} +1 -1
  79. package/web/_astro/{c4Diagram-AAUBKEIU.BkUIUQWH.js → c4Diagram-AAUBKEIU.BbF_zCxW.js} +1 -1
  80. package/web/_astro/channel.MYZLKNwy.js +1 -0
  81. package/web/_astro/{chunk-2J33WTMH.DvfQ_f50.js → chunk-2J33WTMH.CAgQHpPC.js} +1 -1
  82. package/web/_astro/{chunk-4BX2VUAB.DuI4gQqX.js → chunk-4BX2VUAB.BN-5tpw4.js} +1 -1
  83. package/web/_astro/{chunk-55IACEB6.D3BWBOpF.js → chunk-55IACEB6.CnPkEEr0.js} +1 -1
  84. package/web/_astro/{chunk-727SXJPM.3QSi0a9M.js → chunk-727SXJPM.BQzQeMVm.js} +4 -4
  85. package/web/_astro/{chunk-AQP2D5EJ.xazCQrAF.js → chunk-AQP2D5EJ.B6xNyDnL.js} +1 -1
  86. package/web/_astro/{chunk-FMBD7UC4.B2g6u4rA.js → chunk-FMBD7UC4.C7f9Ih78.js} +1 -1
  87. package/web/_astro/{chunk-ND2GUHAM.wWwWs99t.js → chunk-ND2GUHAM.CNV1dFXT.js} +1 -1
  88. package/web/_astro/{chunk-QZHKN3VN.BD5g3qa9.js → chunk-QZHKN3VN.Cudn2TkJ.js} +1 -1
  89. package/web/_astro/{classDiagram-4FO5ZUOK.C7CzCdsX.js → classDiagram-4FO5ZUOK.D1NwP50q.js} +1 -1
  90. package/web/_astro/{classDiagram-v2-Q7XG4LA2.C7CzCdsX.js → classDiagram-v2-Q7XG4LA2.D1NwP50q.js} +1 -1
  91. package/web/_astro/{cose-bilkent-S5V4N54A.Xyiau0gw.js → cose-bilkent-S5V4N54A.B1wSL-Xb.js} +1 -1
  92. package/web/_astro/{cynefin-OW5HDTMX.BeC5MWas.js → cynefin-OW5HDTMX.BmK52w8G.js} +1 -1
  93. package/web/_astro/{dagre-BM42HDAG.yZbMN9vc.js → dagre-BM42HDAG.Bfy5CTDT.js} +2 -2
  94. package/web/_astro/diagram-2AECGRRQ.DhNnvUvX.js +43 -0
  95. package/web/_astro/diagram-5GNKFQAL.lTX5KwnS.js +10 -0
  96. package/web/_astro/{diagram-KO2AKTUF.CR6k3Y3G.js → diagram-KO2AKTUF.CW_vMJ4z.js} +3 -3
  97. package/web/_astro/{diagram-LMA3HP47.x7mwu8jz.js → diagram-LMA3HP47.B_8ZGF67.js} +1 -1
  98. package/web/_astro/{diagram-OG6HWLK6.D8aTTvUr.js → diagram-OG6HWLK6.BppnHsdS.js} +1 -1
  99. package/web/_astro/{erDiagram-TEJ5UH35.BoBqcKXQ.js → erDiagram-TEJ5UH35.BEuHXcjJ.js} +5 -5
  100. package/web/_astro/{flowDiagram-I6XJVG4X.D3mTQdrU.js → flowDiagram-I6XJVG4X.CH-UlnGr.js} +4 -4
  101. package/web/_astro/{ganttDiagram-6RSMTGT7.H-cqgIh-.js → ganttDiagram-6RSMTGT7.BO81S85v.js} +1 -1
  102. package/web/_astro/{gitGraphDiagram-PVQCEYII.B6s9zbfC.js → gitGraphDiagram-PVQCEYII.XnPxPPZN.js} +1 -1
  103. package/web/_astro/index.Hjbr15fG.css +1 -0
  104. package/web/_astro/{infoDiagram-5YYISTIA.BzgCoV6P.js → infoDiagram-5YYISTIA.JyjYRu_T.js} +1 -1
  105. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BZzVhy1-.js → ishikawaDiagram-YF4QCWOH.BBRBF-Fo.js} +5 -5
  106. package/web/_astro/{journeyDiagram-JHISSGLW.BV3195Py.js → journeyDiagram-JHISSGLW.C_iymSyp.js} +1 -1
  107. package/web/_astro/{kanban-definition-UN3LZRKU.BjRd2DWz.js → kanban-definition-UN3LZRKU.DdfW-Oqt.js} +7 -7
  108. package/web/_astro/{linear.BILTgS5N.js → linear.C2_IkbZT.js} +1 -1
  109. package/web/_astro/mermaid.core.GAOYeSR0.js +303 -0
  110. package/web/_astro/{mindmap-definition-RKZ34NQL.BiEjaI4-.js → mindmap-definition-RKZ34NQL.DAZIxQSK.js} +2 -2
  111. package/web/_astro/{pieDiagram-4H26LBE5.i_8V5pIn.js → pieDiagram-4H26LBE5.CN8sIhKM.js} +3 -3
  112. package/web/_astro/{quadrantDiagram-W4KKPZXB.BWaW3MHn.js → quadrantDiagram-W4KKPZXB.3dGcX5GP.js} +1 -1
  113. package/web/_astro/{requirementDiagram-4Y6WPE33.CzddBbtg.js → requirementDiagram-4Y6WPE33.BV2y4dd6.js} +3 -3
  114. package/web/_astro/{sankeyDiagram-5OEKKPKP.X2ww0e-D.js → sankeyDiagram-5OEKKPKP.Cqo15Tvo.js} +4 -4
  115. package/web/_astro/{sequenceDiagram-3UESZ5HK.DSA4kTcc.js → sequenceDiagram-3UESZ5HK.CROCPMJB.js} +1 -1
  116. package/web/_astro/{stateDiagram-AJRCARHV.D0DtFSpR.js → stateDiagram-AJRCARHV.RfXZrkFE.js} +1 -1
  117. package/web/_astro/{stateDiagram-v2-BHNVJYJU.BfQq0zQv.js → stateDiagram-v2-BHNVJYJU.CPXmbBs9.js} +1 -1
  118. package/web/_astro/{timeline-definition-PNZ67QCA.Dmlrgi1m.js → timeline-definition-PNZ67QCA.DdgKTiO8.js} +3 -3
  119. package/web/_astro/{vennDiagram-CIIHVFJN.D5mpl00Z.js → vennDiagram-CIIHVFJN.CPNVSHF1.js} +5 -5
  120. package/web/_astro/{wardleyDiagram-YWT4CUSO.Df4BdzO4.js → wardleyDiagram-YWT4CUSO.CQhA0Jyr.js} +3 -3
  121. package/web/_astro/{xychartDiagram-2RQKCTM6.DiTRreKN.js → xychartDiagram-2RQKCTM6.n61BWyy4.js} +1 -1
  122. package/web/index.html +2 -2
  123. package/web/_astro/BoardApp.CDUcHlTJ.js +0 -188
  124. package/web/_astro/BoardApp.CaCGU_uX.js +0 -1
  125. package/web/_astro/arc.BzF71EFI.js +0 -1
  126. package/web/_astro/channel.SSVY0JPQ.js +0 -1
  127. package/web/_astro/diagram-2AECGRRQ.Cmo2zQM-.js +0 -43
  128. package/web/_astro/diagram-5GNKFQAL.D033eSVi.js +0 -10
  129. package/web/_astro/index.CcU5weKX.css +0 -1
  130. package/web/_astro/mermaid.core.DBy_WKeW.js +0 -301
@@ -6,13 +6,18 @@
6
6
  # through the normal `spur task update <wbs> <status>` verb so the lifecycle guards
7
7
  # (0055) apply identically. Run linkage is written to `task_run_links` (kind=pipeline).
8
8
  #
9
- # Shape: precheck → implement → test[→test-fix↔test-recheck] → review → approve(HITL)
9
+ # Shape: precheck → implement[→escalate] → test[→test-fix↔test-recheck] → review → approve(HITL)
10
10
  # → verify → record → done
11
11
  # (precheck failure short-circuits to `failed`; approve routes to `failed` on
12
12
  # operator rejection or `cancelled` on operator cancel — R1, bug-750).
13
13
  # `test` is the project quality gate (shell + bounded /sp:dev-fixall), not
14
14
  # /sp:dev-unit (coverage gap-fill; router C3/C5).
15
15
  #
16
+ # F96 residual sweep (0950): precheck captures the resume-safe base commit; verify
17
+ # scans and folds residuals between the verdict and the proof bind (blocking leftovers
18
+ # downgrade PASS → PARTIAL and take the existing remediation edge); done settles
19
+ # deferrals; failed renders the recovery report. No new state, edge, or model query.
20
+ #
16
21
  # Vars (passed as a JSON object via `--vars`):
17
22
  # wbs — task WBS (required)
18
23
  # profile — "auto" skips HITL approve (R4)
@@ -21,6 +26,7 @@
21
26
  # implementTimeoutMs — implement agent.run budget (ms)
22
27
  # qualityGateCmd — project gate (default: bun run spur-check)
23
28
  # qualityGateMaxFixAttempts — max /sp:dev-fixall hops after a red gate (default: 2)
29
+ # maxEscalations — max operator-question pauses per implement chain (default: 2)
24
30
  #
25
31
  # Seeded by `spur init`. agent.run inputs are pure slash commands (ADR-043).
26
32
 
@@ -90,6 +96,10 @@ vars:
90
96
  # Answer captured by the approve gate's hitl.confirm (R1): "yes" | "no" | "cancel".
91
97
  # Empty by default; only meaningful once the approve state has been entered.
92
98
  __hitlAnswer: ""
99
+ # Operator answer captured by the escalate hop's hitl.input (0933). Empty by
100
+ # default; set by `spur workflow continue --answer-text` after the pause and read
101
+ # by the escalate→implement / escalate→failed guards. Non-empty = answered.
102
+ __hitlInput: ""
93
103
  # Proof-state bracket (task 0612, ADR-071; restructured by task 0703). `proofDigest` is the
94
104
  # canonical capture taken at quality-gate ENTRY — immediately before the evidence-producing
95
105
  # final chain (quality → review → verify) — and re-captured at `test-recheck` when bounded
@@ -134,6 +144,14 @@ vars:
134
144
  # Max /sp:dev-fixall attempts after a red quality-gate probe/recheck (bounded; no thrash).
135
145
  # Attempt counter: .spur/run/<wbs>-test-fix-attempt. Default 2 = two fixall hops before failed.
136
146
  qualityGateMaxFixAttempts: "2"
147
+ # Max operator-question pauses (0933) before the implement chain routes to failed.
148
+ # Escalation counter: .spur/run/<wbs>-escalation-count. Default 2 = two answered
149
+ # questions; a third pause routes to failed with a report note.
150
+ maxEscalations: "2"
151
+ # Runtime-written, 0933: the escalate hop's file.read.into-var fills this from
152
+ # .spur/run/<wbs>-question.md; the hitl.input prompt below references it. Declared
153
+ # here (empty) so the static var-reference validator sees the template source.
154
+ escalationQuestion: ""
137
155
  # Post-implement auto-format. Overridable like qualityGateCmd so a non-Bun seeded
138
156
  # project can point it at its own formatter; invoked best-effort (a missing or
139
157
  # failing formatter must never abort a run — the quality gate is the real gate).
@@ -156,6 +174,12 @@ vars:
156
174
  # (default) = on; set to "off" to bypass:
157
175
  # `--vars '{"implementScopeGuard":"off"}'`.
158
176
  implementScopeGuard: ""
177
+ # 0931 R5: parallel batches defer the per-task feature sync so a task branch never
178
+ # touches feature files or docs/features/INDEX.md. When "true", the record step's
179
+ # post-record shell appends a deferral note and skips the sync; the parallel batch
180
+ # orchestrator runs the sync + `spur feature refresh` once per touched feature on the
181
+ # base ref after integration. Sequential/inline keep the default "false" (unchanged).
182
+ deferFeatureSync: "false"
159
183
 
160
184
  states:
161
185
  - id: precheck
@@ -189,6 +213,12 @@ states:
189
213
  options:
190
214
  command: >-
191
215
  mkdir -p .spur/run; S=plugins/sp/scripts/task-evidence-precheck.ts; [ -f "$S" ] || S="$(superskill script path sp task-evidence-precheck.ts 2>/dev/null)"; if [ -f "$S" ]; then bun "$S" "$wbs" --spur-bin "$spurBin"; else echo "task-evidence-precheck failed closed — checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'." >&2; echo "FAIL" > ".spur/run/$wbs-precheck-evidence.status"; fi; exit 0
216
+ # (e) F96 R1 (0950): capture the run's base commit once — a resumed or re-entered run
217
+ # keeps its original base so residual scans stay anchored to the same diff.
218
+ - kind: shell
219
+ options:
220
+ command: >-
221
+ mkdir -p .spur/run; [ -f ".spur/run/$wbs-base.sha" ] || git rev-parse HEAD > ".spur/run/$wbs-base.sha"; exit 0
192
222
  # (e) route-reason lookup and routes log; proportional-routing tests locate it
193
223
  # (0759 R1/R5 run-scoped artifact; 0804 R8 run-id safety — one line, no in-scalar `#`).
194
224
  - kind: shell
@@ -222,6 +252,20 @@ states:
222
252
  that command DRIVES this pipeline, so calling it here recurses.
223
253
  --mode implement is the single-step implement entry.
224
254
  onEnter:
255
+ # 0933 R27 (guard-lines compression): the transcript append lives HERE, on
256
+ # (re-)entry, not in the escalate→implement guard. On first entry there is no
257
+ # pending question (no-op); on a resume entry the guard already confirmed a
258
+ # non-empty $__hitlInput and a fresh question file, so this shell records the
259
+ # Q/A pair (## Q<n>/## A<n>, R3) and consumes the question file before the
260
+ # agent.run re-dispatches — which also disarms the implement→escalate edge.
261
+ - kind: shell
262
+ options:
263
+ command: >-
264
+ test -n "$__hitlInput" -a -s .spur/run/$wbs-question.md || exit 0;
265
+ qn="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)";
266
+ printf '## Q%s\n%s\n\n## A%s\n%s\n' "$qn" "$(cat .spur/run/$wbs-question.md 2>/dev/null)" "$qn" "$__hitlInput" >> .spur/run/$wbs-escalation.md;
267
+ rm -f .spur/run/$wbs-question.md;
268
+ exit 0
225
269
  - kind: agent.run
226
270
  options:
227
271
  agent: ${vars.implementAgent}
@@ -232,13 +276,23 @@ states:
232
276
  # resumes the implement session instead of re-reading the task cold.
233
277
  session: reuse
234
278
  # lives in /sp:dev-run --mode implement → sp:code-implementation, not YAML prose.
235
- input: /sp:dev-run --mode implement ${vars.wbs} --auto
279
+ # 0933 R28: --escalation-file names the Q/A transcript the implement
280
+ # agent appends to when pausing and reads back on re-dispatch; absent
281
+ # on a first attempt means "no prior escalations".
282
+ input: /sp:dev-run --mode implement ${vars.wbs} --auto --escalation-file .spur/run/${vars.wbs}-escalation.md
236
283
  timeoutMs: ${vars.implementTimeoutMs}
237
284
  # R3 (task 0424): empty-implement no-op guard — the agent.run action
238
285
  # fails the step when exit 0 produced zero non-corpus file changes, so
239
286
  # a silent no-op routes the run to `failed` here instead of drifting
240
287
  # into test/review and being caught a full pass later.
241
288
  requireDiff: true
289
+ # 0933 R26: escalation contract — the agent.run option names the QUESTION
290
+ # file (the pause signal, deleted pre-dispatch for freshness); a paused
291
+ # attempt (agent wrote its question there and exited 0) succeeds with
292
+ # data.escalated=true and skips requireDiff for THAT attempt only. The
293
+ # Q/A transcript (.spur/run/<wbs>-escalation.md) is separate: it reaches
294
+ # the agent via --escalation-file in the input below.
295
+ escalationFile: .spur/run/${vars.wbs}-question.md
242
296
  # 0706 R6: this stage mutates the working tree unattended under the
243
297
  # auto profile, so it declares minimum execution-capability
244
298
  # requirements. Dispatch fails closed (before spawn) when the
@@ -273,6 +327,39 @@ states:
273
327
  options:
274
328
  command: "$formatCmd ; exit 0"
275
329
 
330
+ # ── escalate hop (operator-question pause, 0933) ──────────────────────────
331
+ # The implement agent paused on an operator question: it wrote
332
+ # .spur/run/<wbs>-question.md and exited 0 (agent.run reported
333
+ # data.escalated=true, skipping requireDiff for that attempt). This hop bounds
334
+ # the asks (counter), surfaces the question verbatim through the HITL responder
335
+ # (the run pauses here), and — after `spur workflow continue --answer-text <a>`
336
+ # delivers __hitlInput — resumes implement with the Q/A transcript
337
+ # (.spur/run/<wbs>-escalation.md) named in the implement input via
338
+ # --escalation-file. The transcript append + question-file consumption happen in
339
+ # the escalate→implement guard so a stale question can never re-trigger the hop
340
+ # after the answered attempt.
341
+ - id: escalate
342
+ description: >-
343
+ Operator-question pause (0933): the implement agent asked a question
344
+ headlessly; surface it to the operator and resume implement with the answer.
345
+ onEnter:
346
+ # Bounded asks: increment the per-task escalation counter before pausing.
347
+ - kind: shell
348
+ options:
349
+ command: >-
350
+ mkdir -p .spur/run; n="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)"; echo $((n + 1)) > .spur/run/$wbs-escalation-count; exit 0
351
+ # The agent's question, verbatim, becomes the pause prompt.
352
+ - kind: file.read.into-var
353
+ options:
354
+ file: .spur/run/${vars.wbs}-question.md
355
+ var: escalationQuestion
356
+ # Pause for the operator (responder pause:true stops the run after this
357
+ # onEnter; `spur workflow continue --answer-text <answer>` writes
358
+ # __hitlInput and re-evaluates the escalate guards).
359
+ - kind: hitl.input
360
+ options:
361
+ prompt: "${vars.escalationQuestion}"
362
+
276
363
  # ── test hop (quality gate + bounded auto-fix) ─────────────────────────────
277
364
  # NOT /sp:dev-unit. That command (sp:code-testing) *extends/generates* tests toward
278
365
  # a coverage target; it is not the project quality gate. Coverage gap-fill remains
@@ -358,6 +445,14 @@ states:
358
445
  options:
359
446
  command: >-
360
447
  mkdir -p .spur/run; A=".spur/run/$wbs-test-fix-attempt"; n=$(cat "$A" 2>/dev/null || echo 0); printf '%s\n' "$((n + 1))" > "$A"; [ ! -f ".spur/run/$wbs-verdict.json" ] || { echo '--- verify verdict (remediation input, task 0703 R4) ---'; cat ".spur/run/$wbs-verdict.json"; } >> ".spur/run/$wbs-test-gate.log"; exit 0
448
+ # (d) F96 R3 (0950): hand the residual list to the remediation loop — dev-fixall
449
+ # treats residual items as fix targets and may defer P3/markers to
450
+ # residual-deferrals.json (see dev-fixall.md). Fold already merged the anchors
451
+ # into <wbs>-test-gate.findings; this carries the structured artifact too.
452
+ - kind: shell
453
+ options:
454
+ command: >-
455
+ [ ! -f ".spur/run/$wbs-residuals.json" ] || { echo '--- residual artifact (F96 fix targets; deferrals go to residual-deferrals.json, P3/markers only) ---'; cat ".spur/run/$wbs-residuals.json"; } >> ".spur/run/$wbs-test-gate.log"; exit 0
361
456
  # R3 (0482): project the extracted gate anchors into a var so the dispatch input
362
457
  # can NAME the failing file:line, not merely point at a log. A vars template cannot
363
458
  # run a shell, so the read is an action, not an inline `$(cat ...)` substitution.
@@ -464,6 +559,8 @@ states:
464
559
  - kind: hitl.confirm
465
560
  options:
466
561
  prompt: "Approve task ${vars.wbs} to proceed to verification?"
562
+ decision:
563
+ mode: never
467
564
 
468
565
  - id: verify
469
566
  description: >
@@ -528,6 +625,16 @@ states:
528
625
  - kind: shell
529
626
  options:
530
627
  command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
628
+ # (d) F96 R2 (0950): residual-scan.ts owns the sweep; shell only resolves it.
629
+ # ONE hard action (scan+fold): a scanner crash fails verify closed — the
630
+ # verify→failed catch-all routes a missing/malformed verdict. Runs AFTER
631
+ # `task verdict` and BEFORE the jq bind so a blocking residual turns PASS
632
+ # into PARTIAL (fold rewrites the verdict artifact) and takes the existing
633
+ # verify→test-fix edge while attempts remain.
634
+ - kind: shell
635
+ options:
636
+ command: >-
637
+ S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ ! -f "$S" ]; then echo "residual-scan failed closed — scanner not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'" >&2; exit 1; fi; case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" scan "$wbs" --spur-bin "$spurBin" && "$RUNNER" "$S" fold "$wbs" --spur-bin "$spurBin"
531
638
  # (e) one jq mutation binds the verdict to the proof digest (0703 R3; runId 0730 §B.2 /
532
639
  # 0757 R4; definitionDigest 0759 R5; honest review stamp 0785 R4; soft action + hard guard).
533
640
  - kind: shell
@@ -582,10 +689,16 @@ states:
582
689
  # (d) feature-sync-bounded.ts owns the sync; shell adds the orphan note and fallbacks
583
690
  # (0411 retry-suppression; 0328 / ADR-0322). Best-effort `exit 0` — feature status sync is a
584
691
  # follow-up, not a completion gate; `record → done` runs `spur task check`.
692
+ # 0931 R5: with deferFeatureSync "true" (parallel mode) the deferral note lands in the
693
+ # task report and the sync is skipped entirely, so task branches never touch feature
694
+ # corpus files; the batch orchestrator performs the deferred sync on the base ref.
695
+ # The sync itself is owned by record-feature-sync.ts (ADR-115: the guard plus the old
696
+ # inline chain cannot share one shell); resolution follows the standard in-repo-first,
697
+ # superskill-staged fallback used by every pipeline checker.
585
698
  - kind: shell
586
699
  options:
587
700
  command: >-
588
- FID=$($spurBin task show $wbs --json 2>/dev/null | jq -r '.feature_id // .frontmatter.feature_id // empty' 2>/dev/null); if [ -z "$FID" ]; then echo "Orphan task $wbs — no feature_id linked — proposal: consider linking to a parent feature." >> ".spur/run/$wbs-report.txt"; elif [ -f plugins/sp/scripts/feature-sync-bounded.ts ]; then bun plugins/sp/scripts/feature-sync-bounded.ts "$FID" --spur-bin "$spurBin" --json; elif M="$(superskill script path sp feature-sync-bounded.mjs 2>/dev/null)" && [ -f "$M" ]; then node "$M" "$FID" --spur-bin "$spurBin" --json; else $spurBin feature sync "$FID" --json; fi; exit 0
701
+ S=plugins/sp/scripts/record-feature-sync.ts; [ -f "$S" ] || S="$(superskill script path sp record-feature-sync.mjs 2>/dev/null)"; [ "$deferFeatureSync" = "true" ] && echo "feature sync deferred to batch integration" >> ".spur/run/$wbs-report.txt" || if [ -f "$S" ]; then bun "$S" --spur-bin "$spurBin"; else echo "feature sync skipped — record-feature-sync not found in plugins/sp/scripts/ nor staged" >> ".spur/run/$wbs-report.txt"; fi; exit 0
589
702
 
590
703
  - id: done
591
704
  description: >
@@ -593,6 +706,13 @@ states:
593
706
  guard runs `spur task check` before certifying; a genuinely non-compliant
594
707
  task routes to `failed` instead of a silent bad `done`.
595
708
  onEnter:
709
+ # (d) F96 R4 (0950): residual-scan.ts owns the settle; shell only resolves it.
710
+ # Soft best-effort (exit 0) — runs after certification and must never change
711
+ # the outcome; failure prints the re-run command.
712
+ - kind: shell
713
+ options:
714
+ command: >-
715
+ S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ -f "$S" ]; then case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" settle "$wbs" --spur-bin "$spurBin" || echo "residual-settle failed — re-run: residual-scan settle $wbs" >&2; else echo "residual-scan not staged — settle skipped — re-run: residual-scan settle $wbs" >&2; fi; exit 0
596
716
  # (c) command.gate owns the done transition with classified transient retry.
597
717
  - kind: command.gate
598
718
  options:
@@ -618,7 +738,28 @@ states:
618
738
  - id: failed
619
739
  description: >
620
740
  Terminal — precheck, quality-gate exhaustion, verify non-PASS, record check
621
- failure, or operator rejection; reported, not advanced.
741
+ failure, or operator rejection; reported, not advanced. Also receives an
742
+ escalation-bound pause or an operator give-up (0933).
743
+ onEnter:
744
+ # 0933 R30 (guard-lines compression): the escalation-bound report note lives
745
+ # here as a conditional — no-op unless the run reached failed with a pending
746
+ # question at (or above) the ask bound (bound pause or final give-up). The
747
+ # unanswered question itself is appended to the task report (report.txt, R2).
748
+ - kind: shell
749
+ options:
750
+ command: >-
751
+ n="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)";
752
+ test "$n" -ge "$maxEscalations" -a -s .spur/run/$wbs-question.md || exit 0;
753
+ printf '\n## Escalation bound reached\n\nThe implement step asked an operator question %s times (bound %s) and ended without a resumable answer. Unanswered question:\n\n' "$n" "$maxEscalations" >> .spur/run/$wbs-report.txt;
754
+ cat .spur/run/$wbs-question.md >> .spur/run/$wbs-report.txt;
755
+ exit 0
756
+ # (d) F96 R5 (0950): residual-scan.ts owns the report; shell only resolves it.
757
+ # Soft (exit 0): a run that exhausts its fix budget on residuals leaves the
758
+ # report + recovery line while the task stays `wip`.
759
+ - kind: shell
760
+ options:
761
+ command: >-
762
+ S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ -f "$S" ]; then case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" report "$wbs" --spur-bin "$spurBin" || echo "residual-report failed — re-run: residual-scan report $wbs" >&2; else echo "residual-scan not staged — report skipped — re-run: residual-scan report $wbs" >&2; fi; exit 0
622
763
 
623
764
  - id: cancelled
624
765
  description: Terminal — pipeline cancelled by operator at the approval gate (R1).
@@ -642,12 +783,54 @@ transitions:
642
783
  guard:
643
784
  kind: always
644
785
 
786
+ # ── implement routing: escalation first (0933 R26/R30), then the linear body ──
787
+ # Declaration order matters: the escalation bound is checked FIRST — a paused
788
+ # attempt that already exhausted its maxEscalations asks routes to failed (with a
789
+ # report note appended in the same guard) instead of asking forever; then the
790
+ # question-presence hop; then the normal always edge. The bound guard requires a
791
+ # fresh question file so a COMPLETED implement after max asks still routes to test.
792
+ - from: implement
793
+ to: failed
794
+ description: Escalation bound exhausted — the agent paused again after maxEscalations operator answers.
795
+ # 0933 R30 (guard-lines compression): thin predicate; the report note is written
796
+ # by the failed state's onEnter when it observes a bound-exhausted pause.
797
+ guard:
798
+ kind: shell
799
+ options:
800
+ command: >-
801
+ n="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)";
802
+ test "$n" -ge "$maxEscalations" -a -s .spur/run/$wbs-question.md
803
+ - from: implement
804
+ to: escalate
805
+ description: Implement agent paused on an operator question (non-empty question file) — pause for an answer.
806
+ guard:
807
+ kind: shell
808
+ options:
809
+ command: 'test -s .spur/run/$wbs-question.md'
645
810
  # ── linear body ──
646
811
  - from: implement
647
812
  to: test
648
813
  description: Implementation done — quality-gate probe.
649
814
  guard:
650
815
  kind: always
816
+ # escalate branching (0933 R27): an answered pause resumes implement — the transcript
817
+ # append and question consumption happen in implement's onEnter (guards stay thin
818
+ # under ADR-115 guard-lines caps); an empty answer is an operator give-up → failed
819
+ # (question + transcript preserved as evidence).
820
+ - from: escalate
821
+ to: implement
822
+ description: Operator answered — re-enter implement, which records the Q/A transcript and consumes the question.
823
+ guard:
824
+ kind: shell
825
+ options:
826
+ command: 'test -n "$__hitlInput"'
827
+ - from: escalate
828
+ to: failed
829
+ description: Empty operator answer — give-up routes to failed (question + transcript preserved as evidence).
830
+ guard:
831
+ kind: shell
832
+ options:
833
+ command: 'test -z "$__hitlInput"'
651
834
  # Soft probe branching (declaration order: PASS first, then FAIL, then defense).
652
835
  - from: test
653
836
  to: verify
@@ -163,6 +163,8 @@ states:
163
163
  - kind: hitl.confirm
164
164
  options:
165
165
  prompt: "Approve research resolution for task ${vars.wbs}?"
166
+ decision:
167
+ mode: never
166
168
 
167
169
  - id: record
168
170
  description: >
@@ -15,6 +15,7 @@
15
15
  #
16
16
  # Shape: start -> task-resolve -> doc-sync -> learnings-append -> metrics-record
17
17
  # -> feature-transition (conditional: if vars.feature set)
18
+ # -> feature-verify (post-transition feature check gate, 0915 F1)
18
19
  # -> branch-cleanup (conditional: if vars.merge=true)
19
20
  # -> done
20
21
  # doc-sync routes a contract violation to `repair` (cheap, no
@@ -295,6 +296,30 @@ states:
295
296
  printf 'FAIL\n' > ".spur/run/$__runId-wrapup-sync.status";
296
297
  fi
297
298
 
299
+ - id: feature-verify
300
+ description: >
301
+ Post-feature-transition verification hop (D63 task 0915, review finding
302
+ F1): wrapup's doc-sync and the feature transition mutate the corpus AFTER
303
+ the feature-scoped verification pass ran. The proof digest deliberately
304
+ excludes docs/tasks*/docs/features* (shared evidence, concurrent writers),
305
+ so the bound receipt stays valid — but the feature's completion boundary
306
+ must still observe the post-wrapup state. This hop re-runs the feature
307
+ check gate (`featureGateCmd`). When the configured command is the done-
308
+ boundary variant (`feature check --as done`), it validates the bound
309
+ evidence receipt (feature identity, verifier definition digest, terminal
310
+ recording run, artifact registration, checked-input digest) against the
311
+ current feature contract; a plain gate command observes the post-wrapup
312
+ corpus state but does not enforce the receipt (0915 re-review P3). A FAIL
313
+ fails the wrapup loudly instead of letting a stale PASS ride; only a
314
+ verified gate writes PASS (0783 R4).
315
+ onEnter:
316
+ - kind: shell
317
+ options:
318
+ command: >-
319
+ sh -c "$featureGateCmd" &&
320
+ printf 'PASS\n' > ".spur/run/$__runId-wrapup-feature-verify.status" ||
321
+ printf 'FAIL\n' > ".spur/run/$__runId-wrapup-feature-verify.status"
322
+
298
323
  - id: branch-cleanup
299
324
  description: >
300
325
  Irreversible-operation HITL gate, consent-only (0770). If vars.merge=true,
@@ -308,6 +333,8 @@ states:
308
333
  - kind: hitl.confirm
309
334
  options:
310
335
  prompt: "Branch cleanup for the validated task list (.spur/run/${vars.__runId}-wrapup-tasks.json). This is IRREVERSIBLE (merge or delete). Confirm to proceed?"
336
+ decision:
337
+ mode: never
311
338
 
312
339
  - id: done
313
340
  description: >
@@ -472,19 +499,36 @@ transitions:
472
499
  options:
473
500
  command: 'test "$(cat .spur/run/$__runId-wrapup-sync.status 2>/dev/null)" = FAIL'
474
501
  - from: feature-transition
502
+ to: feature-verify
503
+ description: Sync PASS — re-run the feature check gate against the post-wrapup state.
504
+ guard:
505
+ kind: shell
506
+ options:
507
+ command: 'test "$(cat .spur/run/$__runId-wrapup-sync.status 2>/dev/null)" = PASS'
508
+ - from: feature-verify
509
+ to: failed
510
+ description: >
511
+ Post-wrapup feature check failed (0915 F1): the bound receipt no longer
512
+ validates against the current feature contract. Already-written
513
+ learnings/metrics stay on disk.
514
+ guard:
515
+ kind: shell
516
+ options:
517
+ command: 'test "$(cat .spur/run/$__runId-wrapup-feature-verify.status 2>/dev/null)" = FAIL'
518
+ - from: feature-verify
475
519
  to: branch-cleanup
476
- description: Sync PASS — merge is requested.
520
+ description: Post-wrapup feature check PASS — merge is requested.
477
521
  guard:
478
522
  kind: shell
479
523
  options:
480
- command: 'test "$(cat .spur/run/$__runId-wrapup-sync.status 2>/dev/null)" = PASS && test "$merge" = true'
481
- - from: feature-transition
524
+ command: 'test "$(cat .spur/run/$__runId-wrapup-feature-verify.status 2>/dev/null)" = PASS && test "$merge" = true'
525
+ - from: feature-verify
482
526
  to: done
483
- description: Sync PASS — no merge requested.
527
+ description: Post-wrapup feature check PASS — no merge requested.
484
528
  guard:
485
529
  kind: shell
486
530
  options:
487
- command: 'test "$(cat .spur/run/$__runId-wrapup-sync.status 2>/dev/null)" = PASS && test "$merge" != true'
531
+ command: 'test "$(cat .spur/run/$__runId-wrapup-feature-verify.status 2>/dev/null)" = PASS && test "$merge" != true'
488
532
 
489
533
  # ── branch-cleanup: HITL exhaustive routing (yes / no / cancel → done) ──
490
534
  # No irreversible git op is wired yet; confirmation is recorded, then wrap
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/spur",
3
- "version": "0.3.90",
3
+ "version": "0.3.92",
4
4
  "description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
5
5
  "keywords": [
6
6
  "spur",
@@ -53,14 +53,14 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@commander-js/extra-typings": "^14.0.0",
56
- "@gobing-ai/ts-db": "^0.5.0",
57
- "@gobing-ai/ts-ai-runner": "^0.5.0",
58
- "@gobing-ai/ts-dual-workflow-engine": "^0.5.0",
59
- "@gobing-ai/ts-infra": "^0.5.0",
60
- "@gobing-ai/ts-llm-jsonl-importer": "^0.5.0",
61
- "@gobing-ai/ts-rule-engine": "^0.5.0",
62
- "@gobing-ai/ts-runtime": "^0.5.0",
63
- "@gobing-ai/ts-utils": "^0.5.0",
56
+ "@gobing-ai/ts-db": "^0.5.5",
57
+ "@gobing-ai/ts-ai-runner": "^0.5.5",
58
+ "@gobing-ai/ts-dual-workflow-engine": "^0.5.5",
59
+ "@gobing-ai/ts-infra": "^0.5.5",
60
+ "@gobing-ai/ts-llm-jsonl-importer": "^0.5.5",
61
+ "@gobing-ai/ts-rule-engine": "^0.5.5",
62
+ "@gobing-ai/ts-runtime": "^0.5.5",
63
+ "@gobing-ai/ts-utils": "^0.5.5",
64
64
  "@types/bun": "1.3.14",
65
65
  "@types/figlet": "^1.7.0",
66
66
  "@types/node-notifier": "8.0.5",
@@ -629,6 +629,7 @@ pipeline owns one lifecycle phase:
629
629
  | `idea-pipeline.yaml` | Idea/planning → feature + tasks | `/sp:dev-idea`, `/sp:dev-plan` |
630
630
  | `wrapup-pipeline.yaml` | Post-execution wrap-up | `/sp:dev-wrap`, `/sp:dev-wrapall` |
631
631
  | `wayfinder-resolution.yaml` | Wayfinder ticket resolution loop | `spur workflow run` (free-form) |
632
+ | `decision-routing-example.yaml` | DecisionMaker routing example (never / evidence / omitted modes, defer → operator pause) | `spur workflow run` (authoring sample) |
632
633
 
633
634
  ### Lifecycle operations
634
635
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: expert-spur
3
- description: |
4
- Use PROACTIVELY for "create tasks for this feature", "update all task statuses", "audit task traceability", "create a feature with acceptance criteria", "harden the rule catalog", "author a batch of workflows", "compose a workflow", "tune a rule", "apply accepted doctor proposals", "evaluate spur artifact health", "reflect over history findings", or "expert-spur". Multi-step corpus work across `spur task`, `feature`, `rule`, `workflow`, and agent specs: batch creation, status sweeps, section campaigns, traceability audits, rule hardening, workflow authoring/refactoring, composition and tuning (sp:spur-composer), and evaluation/reflection proposal passes (sp:spur-doctor). For one deterministic operation, run the CLI directly. Recurring evolution loops and multi-agent coordination belong to sp:super-planner — never this agent.
3
+ description: |-
4
+ Use PROACTIVELY for "create tasks for this feature", "update all task statuses", "audit task traceability", or "expert-spur". Runs multi-step corpus campaigns across tasks, features, rules, workflows, and agent specs: creation, status/section updates, audits, and hardening. Uses sp:spur-composer for workflow composition, rule tuning, and accepted proposals; sp:spur-doctor for artifact evaluation and history reflection. Run single operations via CLI; recurring loops and multi-agent coordination belong to sp:super-planner.
5
5
 
6
6
  <example>
7
7
  Context: Batch task status update across a feature.
@@ -86,7 +86,10 @@ You own the spaces **between** task runs:
86
86
  - **Parallelize only when requested** by applying `sp:parallel-execution` to a proven-independent
87
87
  subset (Step 3 optional path). Serialize when dependency, file-overlap, or budget checks fail.
88
88
  Preflight still runs per WBS before fan-out; recovery stays sequential.
89
- - **Inspect** each terminal state + `.spur/run/<wbs>-verdict.json` (Step 3.3).
89
+ - **Inspect** each terminal state via `spur workflow trace "$RUN" --follow --timeout 600000` (a
90
+ timeout prints one checkpoint and exits 1; the run continues, never cancelled or relaunched) plus
91
+ `.spur/run/<wbs>-verdict.json`, accepted only when the trace's `.run.runId` equals the dispatched
92
+ run and the verdict's mtime ≥ the trace's `.run.startedAt` — otherwise `stale-evidence` (Step 3.3).
90
93
  - **One-shot recovery (optional)** - on non-PASS / stuck status, consult next-router **once** for that
91
94
  WBS (`recoveryHint` / dry-run plan): print the child command, or dispatch once only when the batch
92
95
  was started with `--auto` and cardinality is 1. Never self-loop until done.
@@ -264,7 +267,10 @@ Report using the batch-report template from execution-batch.md §5:
264
267
  **Next:** <one-line action>
265
268
  ```
266
269
 
267
- Per-task outcome vocabulary: `done` | `failed` | `blocked` | `skipped` | `not-attempted`.
270
+ Per-task outcome vocabulary: `done` | `failed` | `blocked` | `skipped` | `paused` (0933: parked on
271
+ an operator question — escalate hop — or an approval gate; non-terminal, never `done`) |
272
+ `not-attempted`, plus the parallel-only `integration-conflict`
273
+ ([execution-batch.md § Parallel isolation](../skills/spur-dev/references/execution-batch.md#parallel-isolation---mode-parallel)).
268
274
  Batch verdict: `clean` (all attempted tasks `done`) | `halted` (a failure stopped the batch) |
269
275
  `aborted` (cycle or selector error before any run).
270
276
 
@@ -272,9 +278,12 @@ With `--json`, emit the same shape as a JSON object for machine consumption.
272
278
 
273
279
  ## Out of scope (deferred)
274
280
 
275
- - **Parallel execution** - needs git-worktree isolation; v1 is sequential.
276
- - **Interactive within-step escalation** - waits for the workspace module + inbox module +
277
- `spur agent` team mode. You surface blockers only at the batch boundary.
281
+ - **Parallel execution** - `--mode parallel` isolates each task in its own worktree with
282
+ rebase-and-FF integration; see [execution-batch.md § Parallel isolation](../skills/spur-dev/references/execution-batch.md#parallel-isolation---mode-parallel).
283
+ - **Interactive within-step escalation** — implemented (0933): the pipeline's `escalate` hop
284
+ pauses on the implement agent's operator question; the operator answers via
285
+ `spur workflow continue --answer-text` and the run resumes implement with the Q/A transcript
286
+ (bounded by `maxEscalations`). See [execution-batch.md Step 3](../skills/spur-dev/references/execution-batch.md#step-3--the-driver-loop-r3-r4).
278
287
 
279
288
  ## Platform Notes
280
289
 
@@ -14,11 +14,11 @@ Wraps the **sp:dogfood-testing** skill.
14
14
  | Flag | Description | Default |
15
15
  | --- | --- | --- |
16
16
  | `<testee>` | Skill / command / CLI to exercise end-to-end. | required |
17
- | `--agent` `<inline\|auto\|name>` | Who runs the model-bearing dogfood work. | omit |
18
- | `--max-retry` `<n>` | Max auto-fix retries per stage. | 3 |
17
+ | `--agent` `<inline\|auto\|name>` | **Testee-scoped** agent the testee runs under — forwarded into the testee invocation; the dogfood driver always runs in the current session. | omit (forward nothing) |
18
+ | `--max-retry` `<n>` | Max auto-fix retries per step. `0` = observe-only. Mandatory (as `0` or `N`) for pipeline-driving testees and testees with a mutating `--fix` mode. | 2 |
19
19
  | `--save` | Compatibility no-op; saving is now default. Retained until evidenced retirement. | off |
20
- | `--task` | Record outcomes against a task. | omitted |
21
- | `--chain-follow` | Follow the testee's chained follow-ups. | off |
20
+ | `--task` | **Creates** a new review-template task for the findings (`spur task create --template review`) — it does not attach to or update the task under test. | off |
21
+ | `--chain-follow` | **Reads existing chained-leg evidence** (verdict artifacts, task-file diffs, review tables) after a chained leg completes, for attribution — it never executes the chained leg itself. Without it the driver stops at the testing boundary. | off |
22
22
  | `--full` | Full report verbosity (all sections). | off |
23
23
 
24
24
  For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag-glossary.md).
@@ -27,9 +27,12 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
27
27
 
28
28
  ## Implementation
29
29
 
30
- Under the pipeline, the `test-recheck` state runs the full gate immediately after this hop — that is
31
- the deciding run. When `--gate-log` is set (the pipeline signal), fixall runs **no full gate at
32
- all**: targeted probes (`bun test <file> --test-name-pattern <test>`) during fix loops, then one
33
- `bun run lint` before returning. Invoked standalone, it keeps the single confirming run (R4, task
34
- 0483). `qualityGateCmd` itself is unchanged so `test-recheck` still runs the full gate.
30
+ Follow the inline procedure in [dev-operations.md](../skills/spur-dev/references/dev-operations.md#10-fixall) (fixall). Pipeline signal: when `--gate-log` is set (the `test-fix` hop), run no full gate — the `test-recheck` state immediately after is the deciding run (R4, task 0483).
31
+
32
+ When dispatched from the pipeline's test-fix stage (F96, task 0950), the gate log carries a
33
+ `residual artifact` block (`<wbs>-residuals.json`) and the findings file already
34
+ contains the merged residual anchors: treat those items as fix targets, in order,
35
+ alongside gate anchors. The fixer may write `.spur/run/<wbs>-residual-deferrals.json`
36
+ — one `{id, reason}` entry per item — but only for P3 findings or diff markers it
37
+ cannot fix inside the task; the done stage settles deferrals into follow-up tasks.
35
38
 
@@ -41,6 +41,12 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
41
41
  **Flags:**
42
42
 
43
43
  - `--auto` | `--agent <inline|auto|name>` — Skip objective HITL confirmations (taste/irreversible gates still pause). `--agent` names who does the model-bearing work. Interactive omit/`inline` keeps the controller and implement-only stages in this session; full mode reads `task-pipeline.yaml` as the SSOT and interprets its actions/guards through the inline driver, whose eligible `agent.run` stages dispatch once to a native subagent and otherwise run in the host (0508 eligibility — task 0687 resolved-inline) It records `stage <id> executed inline in session <session-id>` or `stage <id> executed via subagent <agent-id> (host session <session-id>)` in the run log. `auto` or a name is merged into `vars.agent` and `vars.implementAgent` and keeps the existing subprocess workflow. Headless `spur workflow run` / `spur agent run` is unchanged. See the [execution-surface contract](../skills/spur-dev/references/cross-cutting.md#inline-default-execution-surface).
44
+ - `--escalation-file <path>` (implement step only, 0933) — names the Q/A escalation transcript
45
+ (default `.spur/run/<wbs>-escalation.md`). Absent on a first attempt means "no prior
46
+ escalations". When the implement agent needs an operator decision it appends its question to
47
+ `.spur/run/<wbs>-question.md` and exits 0 — the pipeline's `escalate` hop surfaces the question,
48
+ the operator answers via `spur workflow continue --answer-text`, and the guard appends the Q/A
49
+ pair to this transcript before re-entering implement, where the agent reads it and resumes.
44
50
 
45
51
  `--worktree` `[<name>]` (run the task's pipeline in an isolated git worktree — FF-merge onto the
46
52
  base ref on full success, retain intact on any failure/halt/non-FF; bare form creates a fresh tree,
@@ -20,10 +20,11 @@ Wraps the **sp:spur-dev** skill.
20
20
  | `--auto` | Skip objective HITL gates. | off |
21
21
  | `--agent` `<inline\|auto\|name>` | Who runs each task's pipeline stages. Interactive sequential omit/`inline` uses the host-session driver with unified inline semantics (task 0687 — see below)). `auto`, a name, parallel mode, and headless invocation use subprocesses. | omit |
22
22
  | `--json` | Emit structured JSON. | off |
23
- | `--wrap` | Run the wrap hop per task. The `--agent` selector is preserved into each `/sp:dev-wrap <wbs>` handoff when supplied; omission remains omission. | off |
23
+ | `--wrap` | Run the wrap hop **once for the batch** over the `done` subset only (Step 6 of execution-batch.md): `vars.feature` is passed only when every frozen task is `done`/`cancelled`; an empty done subset skips the wrap with a reason. The `--agent` selector is preserved into the `/sp:dev-wrap` handoff when supplied; omission remains omission. | off |
24
24
  | `--next` | Chain-to-completion via the next-router. | off |
25
25
  | `--continue` | Resume an interrupted batch. | off |
26
26
  | `--worktree` `[<name>]` | Run the batch in an isolated git worktree; FF-merge on success, retain on failure. Bare `--worktree` creates a fresh tree; `--worktree <name>` adopts an existing worktree by name/path/branch. | off |
27
+ | `--concurrency` `<n>` | Parallel-mode worker bound: at most `<n>` task pipelines run at once (task 0931); a dependent starts only after its in-set dependencies are integrated onto the base ref. No-op in sequential mode (ignored). | 2 |
27
28
 
28
29
  For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag-glossary.md).
29
30
 
@@ -41,7 +42,9 @@ structured findings, before any task pipeline action, task 0510 R2; scoped: `L4.
41
42
  (the expected pre-run state of any not-yet-run feature) is reported verbatim but does not abort —
42
43
  any other strict error aborts), `--mode`
43
44
  `<sequential|parallel>` (default `sequential`; `parallel` fans out a proven-independent subset —
44
- see `execution-batch.md` § Parallel Execution), `--keep-going`
45
+ see `execution-batch.md` § Parallel isolation), `--concurrency <n>`
46
+ (parallel-mode worker bound — at most <n> task pipelines at once, default 2; a dependent task starts
47
+ only after its in-set dependencies are **integrated** onto the base ref), `--keep-going`
45
48
  (batch failure policy — skip a failed task's in-batch dependents, continue independents; default
46
49
  halts on first failure), `--auto`
47
50
  (sets `profile=auto` on each per-task run, skipping the HITL approve gate), `--agent <inline|auto|name>`
@@ -56,9 +59,10 @@ FF-merge onto the base ref on full success, retain intact on any failure/halt/no
56
59
  creates a fresh tree, `<name>` form adopts an existing worktree by name/path/branch; see
57
60
  `execution-batch.md` § Worktree isolation).
58
61
 
59
- **`--worktree` is sequential-only.** `--worktree --mode parallel` is **rejected**. This flag gives
60
- the batch *one* worktree for the whole run; per-task worktrees and parallel isolation remain task
61
- 0142 Slice A. Run parallel batches without `--worktree`, or run them sequentially with it.
62
+ **`--worktree` and parallel mode.** `--worktree --mode parallel` is **rejected** — parallel mode
63
+ already isolates each task in its own worktree (see `execution-batch.md` § Parallel isolation), and
64
+ reuse mode (`--worktree <name>`) has no per-task meaning. Run parallel batches without
65
+ `--worktree`, or run them sequentially with it.
62
66
 
63
67
  **`--worktree` corpus visibility.** While the batch runs in a worktree, corpus writes (task
64
68
  statuses, kanban) land in the worktree copy; your main tree still shows pre-run statuses until the
@@ -75,7 +79,9 @@ advancing the feature lifecycle). **was: `--next` deliberately omitted; the old
75
79
  **Three orthogonal axes** (do not confuse): `--keep-going`
76
80
  = batch failure policy (does a failure halt the batch or skip dependents?);
77
81
  `--continue` = resume from
78
- checkpoint (pick up an interrupted batch); `--next`
82
+ checkpoint against the batch's original frozen identity — persisted plan membership, worktree
83
+ marker, identity-filtered checkpoints as hints (execution-batch.md § Batch continuation, task
84
+ 0919); `--next`
79
85
  = chain each task to terminal status + batch-once wrap. See `dev-operations.md` § runall for the
80
86
  full distinction.
81
87