@gobing-ai/spur 0.4.14 → 0.4.16

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 (121) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/config.global.yaml +21 -8
  3. package/config/decisions/executor.yaml +53 -0
  4. package/config/decisions/task-pipeline.yaml +44 -28
  5. package/config/pipeline-budgets.json +0 -14
  6. package/config/workflow-candidates.json +18 -0
  7. package/config/workflows/feature-lifecycle.yaml +9 -16
  8. package/config/workflows/idea-pipeline.yaml +158 -740
  9. package/config/workflows/task-pipeline.yaml +66 -54
  10. package/config/workflows/wrapup-pipeline.yaml +91 -623
  11. package/package.json +11 -10
  12. package/plugins/sp/README.md +9 -5
  13. package/plugins/sp/agents/expert-spur.md +3 -0
  14. package/plugins/sp/agents/super-planner.md +5 -1
  15. package/plugins/sp/agents/super-reviewer.md +43 -12
  16. package/plugins/sp/commands/dev-fixall.md +7 -2
  17. package/plugins/sp/commands/dev-idea.md +15 -6
  18. package/plugins/sp/commands/dev-plan.md +1 -1
  19. package/plugins/sp/commands/dev-pr-review.md +6 -6
  20. package/plugins/sp/commands/dev-run.md +3 -0
  21. package/plugins/sp/commands/dev-runall.md +6 -3
  22. package/plugins/sp/commands/dev-verify.md +1 -1
  23. package/plugins/sp/commands/dev-wrap.md +1 -1
  24. package/plugins/sp/commands/dev-wrapall.md +4 -4
  25. package/plugins/sp/plugin.json +1 -1
  26. package/plugins/sp/skills/code-implementation/SKILL.md +8 -8
  27. package/plugins/sp/skills/code-improvement/SKILL.md +3 -3
  28. package/plugins/sp/skills/code-review/references/verification-before-completion.md +5 -4
  29. package/plugins/sp/skills/code-verification/SKILL.md +4 -4
  30. package/plugins/sp/skills/code-verification/references/verdict-schema.md +27 -11
  31. package/plugins/sp/skills/functional-review/SKILL.md +1 -1
  32. package/plugins/sp/skills/functional-review/references/verdict-schema.md +1 -1
  33. package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
  34. package/plugins/sp/skills/pr-reviewing/SKILL.md +36 -18
  35. package/plugins/sp/skills/spec-decomposition/references/decomposition.md +2 -1
  36. package/plugins/sp/skills/spur-check/SKILL.md +1 -1
  37. package/plugins/sp/skills/spur-cli/SKILL.md +23 -2
  38. package/plugins/sp/skills/spur-cli/references/agent.md +12 -0
  39. package/plugins/sp/skills/spur-cli/references/builder.md +2 -2
  40. package/plugins/sp/skills/spur-cli/references/decision/lifecycle.md +166 -0
  41. package/plugins/sp/skills/spur-cli/references/decision.md +146 -16
  42. package/plugins/sp/skills/spur-cli/references/features.md +19 -0
  43. package/plugins/sp/skills/spur-cli/references/rules.md +2 -0
  44. package/plugins/sp/skills/spur-cli/references/tasks.md +14 -1
  45. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +1 -1
  46. package/plugins/sp/skills/spur-cli/references/workflows/workflow-fit-and-tuning.md +3 -2
  47. package/plugins/sp/skills/spur-cli/references/workflows.md +9 -0
  48. package/plugins/sp/skills/spur-composer/SKILL.md +20 -1
  49. package/plugins/sp/skills/spur-dev/SKILL.md +16 -16
  50. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +2 -1
  51. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +2 -2
  52. package/plugins/sp/skills/spur-dev/references/decision-points.md +97 -0
  53. package/plugins/sp/skills/spur-dev/references/dev-operations.md +18 -18
  54. package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +1 -1
  55. package/plugins/sp/skills/spur-dev/references/execution-batch.md +19 -10
  56. package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +4 -4
  57. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +41 -29
  58. package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +34 -2
  59. package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +4 -4
  60. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +3 -3
  61. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +3 -2
  62. package/plugins/sp/skills/spur-dev/references/glossary.md +12 -3
  63. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +7 -6
  64. package/plugins/sp/skills/spur-doctor/SKILL.md +23 -0
  65. package/plugins/sp/skills/wayfinder/SKILL.md +11 -1
  66. package/spur.js +25617 -24290
  67. package/web/_astro/{BoardApp.Bjdp3XWV.js → BoardApp.CC7Mwswv.js} +65 -65
  68. package/web/_astro/{BoardApp.DCDZxLlQ.js → BoardApp.mWyrWCAR.js} +1 -1
  69. package/web/_astro/{TaskDetail.B3vBxynO.js → TaskDetail.CtAXuiv8.js} +1 -1
  70. package/web/_astro/{arc.DcuHTB_T.js → arc.Duf4u60i.js} +1 -1
  71. package/web/_astro/{architectureDiagram-3BPJPVTR.ClOFWBON.js → architectureDiagram-3BPJPVTR.JoymtqxN.js} +1 -1
  72. package/web/_astro/{blockDiagram-GPEHLZMM.otYyr7Zb.js → blockDiagram-GPEHLZMM.BvmhcioC.js} +1 -1
  73. package/web/_astro/{c4Diagram-AAUBKEIU.BCjpc9LP.js → c4Diagram-AAUBKEIU.CfaWkgoQ.js} +1 -1
  74. package/web/_astro/channel.DtEPXXcH.js +1 -0
  75. package/web/_astro/{chunk-2J33WTMH.D5Wpnpt_.js → chunk-2J33WTMH.B7uR02cD.js} +1 -1
  76. package/web/_astro/{chunk-4BX2VUAB.DkQGtWNz.js → chunk-4BX2VUAB.SwiEauYR.js} +1 -1
  77. package/web/_astro/{chunk-55IACEB6.B7dqjAip.js → chunk-55IACEB6.6ZRCK8PO.js} +1 -1
  78. package/web/_astro/{chunk-727SXJPM.BDQvnKE2.js → chunk-727SXJPM.Cxra_G3N.js} +1 -1
  79. package/web/_astro/{chunk-AQP2D5EJ.D92doBX5.js → chunk-AQP2D5EJ.Cxd7gZeX.js} +1 -1
  80. package/web/_astro/{chunk-FMBD7UC4.C968oI5G.js → chunk-FMBD7UC4.DCLhFkVc.js} +1 -1
  81. package/web/_astro/{chunk-ND2GUHAM.AkkYC1bY.js → chunk-ND2GUHAM.B9AmKcv6.js} +1 -1
  82. package/web/_astro/{chunk-QZHKN3VN.sCc-rKKo.js → chunk-QZHKN3VN.DOjCvl6S.js} +1 -1
  83. package/web/_astro/{classDiagram-4FO5ZUOK.pOQ9u0mY.js → classDiagram-4FO5ZUOK.BMiT_mNf.js} +1 -1
  84. package/web/_astro/{classDiagram-v2-Q7XG4LA2.pOQ9u0mY.js → classDiagram-v2-Q7XG4LA2.BMiT_mNf.js} +1 -1
  85. package/web/_astro/{cose-bilkent-S5V4N54A.CRaeD6FY.js → cose-bilkent-S5V4N54A.mLBCEGjI.js} +1 -1
  86. package/web/_astro/{cynefin-OW5HDTMX.BiCPBu54.js → cynefin-OW5HDTMX.CjDAY0qn.js} +1 -1
  87. package/web/_astro/{dagre-BM42HDAG.C1-q3vkT.js → dagre-BM42HDAG._G_sP8fP.js} +1 -1
  88. package/web/_astro/{diagram-2AECGRRQ.BSVOv30O.js → diagram-2AECGRRQ.39OcfSuz.js} +1 -1
  89. package/web/_astro/{diagram-5GNKFQAL.CHMkjJ-V.js → diagram-5GNKFQAL.D7v_eNC4.js} +1 -1
  90. package/web/_astro/{diagram-KO2AKTUF.CKY9M564.js → diagram-KO2AKTUF.Da1x-lhg.js} +1 -1
  91. package/web/_astro/{diagram-LMA3HP47.B9yNJiTP.js → diagram-LMA3HP47.C8EnzbEb.js} +1 -1
  92. package/web/_astro/{diagram-OG6HWLK6.Dk8AUGsk.js → diagram-OG6HWLK6.DPnBj69F.js} +1 -1
  93. package/web/_astro/{erDiagram-TEJ5UH35.BQHR89TZ.js → erDiagram-TEJ5UH35.CXMu2TIh.js} +1 -1
  94. package/web/_astro/{flowDiagram-I6XJVG4X.oNkWVgoK.js → flowDiagram-I6XJVG4X.ZklePVtQ.js} +1 -1
  95. package/web/_astro/{ganttDiagram-6RSMTGT7.Kz2U2nu9.js → ganttDiagram-6RSMTGT7.BhYOkdqk.js} +1 -1
  96. package/web/_astro/{gitGraphDiagram-PVQCEYII.DHIZ_wPq.js → gitGraphDiagram-PVQCEYII.CADyX8a1.js} +1 -1
  97. package/web/_astro/{infoDiagram-5YYISTIA.D0NJLcv9.js → infoDiagram-5YYISTIA.BsdmwjHt.js} +1 -1
  98. package/web/_astro/{ishikawaDiagram-YF4QCWOH.CFEfTWRG.js → ishikawaDiagram-YF4QCWOH.CzjZ3Crd.js} +1 -1
  99. package/web/_astro/{journeyDiagram-JHISSGLW.Dc7IE7I4.js → journeyDiagram-JHISSGLW.Bxj-ZH_t.js} +1 -1
  100. package/web/_astro/{kanban-definition-UN3LZRKU.D5v0xO9k.js → kanban-definition-UN3LZRKU.Cbg3wVvX.js} +1 -1
  101. package/web/_astro/{linear.wR5KzXnE.js → linear.DJNUrBI9.js} +1 -1
  102. package/web/_astro/{mermaid.core.BDQ2FoPd.js → mermaid.core.DVHQV3SF.js} +4 -4
  103. package/web/_astro/{mindmap-definition-RKZ34NQL.W6_INsia.js → mindmap-definition-RKZ34NQL.DyomosRU.js} +1 -1
  104. package/web/_astro/{pieDiagram-4H26LBE5.61ihbgkK.js → pieDiagram-4H26LBE5.DajtFknN.js} +1 -1
  105. package/web/_astro/{quadrantDiagram-W4KKPZXB.B5lEpFLo.js → quadrantDiagram-W4KKPZXB.Bjq6SjGe.js} +1 -1
  106. package/web/_astro/{requirementDiagram-4Y6WPE33.CmhVBVX0.js → requirementDiagram-4Y6WPE33.ubBVqGLP.js} +1 -1
  107. package/web/_astro/{sankeyDiagram-5OEKKPKP.D7Vvj9Wf.js → sankeyDiagram-5OEKKPKP.I4q46xd-.js} +1 -1
  108. package/web/_astro/{sequenceDiagram-3UESZ5HK.B1vPLixM.js → sequenceDiagram-3UESZ5HK.DsCgZIa8.js} +1 -1
  109. package/web/_astro/{stateDiagram-AJRCARHV.BnACmrGi.js → stateDiagram-AJRCARHV.DcYjYSqT.js} +1 -1
  110. package/web/_astro/{stateDiagram-v2-BHNVJYJU.CW4pnmc3.js → stateDiagram-v2-BHNVJYJU.Dt8yPqiS.js} +1 -1
  111. package/web/_astro/{timeline-definition-PNZ67QCA.CkzMCPnC.js → timeline-definition-PNZ67QCA.0YTkoa5F.js} +1 -1
  112. package/web/_astro/{vennDiagram-CIIHVFJN.CY4aNdAR.js → vennDiagram-CIIHVFJN.BNl0l1hs.js} +1 -1
  113. package/web/_astro/{wardleyDiagram-YWT4CUSO.BtoU9UFk.js → wardleyDiagram-YWT4CUSO.BYSX6cfn.js} +1 -1
  114. package/web/_astro/{xychartDiagram-2RQKCTM6._9ijUUAs.js → xychartDiagram-2RQKCTM6.DzxxpixK.js} +1 -1
  115. package/web/index.html +1 -1
  116. package/worker/laya_worker.py +219 -0
  117. package/config/workflows/feature-verification.yaml +0 -98
  118. package/config/workflows/pr-review.yaml +0 -209
  119. package/config/workflows/wayfinder-resolution.yaml +0 -302
  120. package/plugins/sp/skills/wayfinder/references/pipeline-resolution.md +0 -30
  121. package/web/_astro/channel.qgOLXjI_.js +0 -1
@@ -147,7 +147,7 @@ must not be changed without updating the backing skill.
147
147
  - **Purpose:** Batch verification of a set of tasks (or all tasks under a feature) against their requirements and AC. Produces per-task verdicts + a summary report with aggregate statistics (counts, table, overall batch verdict). With `--fix all`, also evaluates **feature shippable readiness** once for the set.
148
148
  - **Inputs:** `--tasks <selector>` (required unless `--feature`). `--feature <id>` (convenience for `--tasks feature:<id>`). Shared verify flags from `dev-verify` (`--agent <inline|auto|name>`, `--fix`, `--focus`, `--bdd`, `--auto`, `--force`, **`--skip-shippable`**). `--next` (per-task lifecycle chaining: on a PASS verdict transition `testing → done` through the FSM with the target-aware `--as done` guard honored; PARTIAL/FAIL does not transition; transitions run **before** the shippable gate so `spur feature check` sees final statuses). `--json` for machine-readable summary report.
149
149
  - **Backing:** `sp:spur-dev` skill, `verifyall` operation (resolves the set using the shared selector grammar, dispatches per-task verify via `sp:code-verification` verify mode, writes per-task artifacts, aggregates and emits the batch summary report, then optional shippable gate).
150
- - **Behavior:** Resolve + freeze the set (supports `--feature` sugar). For each task: apply status guard, requirements traceability + AC + SECUA review, emit the verdict artifact (per-task fix pass under `--fix`). `## Testing` is written by the deterministic `record` step from the artifact (F92 0593 R1). After the batch: **shippable gate once** when active (see below). Emit a structured summary report (markdown or `--json`). Per-task behavior matches single `dev-verify` (except shippable is batch-once). **Batch verdict rollup is deterministic** — computed by `spur task verifyall-aggregate --from-file <batch-input.json> --json` (a tested service module, not agent discretion). **Per-task outcome grammar:** `PASS` / `PARTIAL` / `FAIL` for implemented tasks; `NOT-STARTED` for tasks that have not entered implementation (status `backlog`/`todo`/`blocked` — reachable only via `--force`). **Rollup rule:** all-NOT-STARTED → `UNKNOWN`; any `FAIL` → `FAIL`; any `PARTIAL` or `UNKNOWN` → `PARTIAL`; all `PASS` → `PASS`. NOT-STARTED rows are _excluded_ from the FAIL/PARTIAL rollup (they cannot manufacture a batch failure) but are _reported explicitly_ in the summary ("N NOT-STARTED, excluded from rollup"). This closes the 0341 dogfood gap where a healthy feature with 5 PASS + 2 unstarted tasks read as FAIL. **Shippable FAIL:** treat the batch as not clean — force rollup to at least **PARTIAL** and set `"shippable": false` under `--json` even if every task outcome is PASS.
150
+ - **Behavior:** Resolve + freeze the set (supports `--feature` sugar). For each task: apply status guard, requirements traceability + AC + SECUA review, emit the verdict artifact (per-task fix pass under `--fix`). `## Testing` is written by the deterministic `spur task record` close from the artifact (F92 0593 R1). After the batch: **shippable gate once** when active (see below). Emit a structured summary report (markdown or `--json`). Per-task behavior matches single `dev-verify` (except shippable is batch-once). **Batch verdict rollup is deterministic** — computed by `spur task verifyall-aggregate --from-file <batch-input.json> --json` (a tested service module, not agent discretion). **Per-task outcome grammar:** `PASS` / `PARTIAL` / `FAIL` for implemented tasks; `NOT-STARTED` for tasks that have not entered implementation (status `backlog`/`todo`/`blocked` — reachable only via `--force`). **Rollup rule:** all-NOT-STARTED → `UNKNOWN`; any `FAIL` → `FAIL`; any `PARTIAL` or `UNKNOWN` → `PARTIAL`; all `PASS` → `PASS`. NOT-STARTED rows are _excluded_ from the FAIL/PARTIAL rollup (they cannot manufacture a batch failure) but are _reported explicitly_ in the summary ("N NOT-STARTED, excluded from rollup"). This closes the 0341 dogfood gap where a healthy feature with 5 PASS + 2 unstarted tasks read as FAIL. **Shippable FAIL:** treat the batch as not clean — force rollup to at least **PARTIAL** and set `"shippable": false` under `--json` even if every task outcome is PASS.
151
151
  - **Shippable readiness (default on with `--fix all`):** Active when `--fix all` and feature context exists (`--feature` or unique shared `feature_id`) and not `--skip-shippable`. Procedure: `sp:code-verification` Step 13 once after all per-task legs. Without `--fix all`, do not run the hard gate (optional note: use `--fix all` for ship evaluation).
152
152
  - **Cache discipline (batch):** freeze the `spur task list --feature <id> --json` (or selector) capture once at resolve; reuse that snapshot for every per-task verify leg. Do not re-list the set mid-batch. Re-read a task body only when that task's sections changed (e.g. after a `--fix` write). Prefer re-reading only cited `file:line` anchors over re-tokenizing full Solution sections when prior Testing is already present.
153
153
  - **Dogfood / mutation composition:** prefer step-split when dogfooding verifyall with `--fix all` and/or `--next` — first observe-only verifyall, then a separate fix pass, then `--next` only if status transitions are still needed. See `sp:dogfood-testing` §step-splitting.
@@ -159,7 +159,7 @@ must not be changed without updating the backing skill.
159
159
  - **Inputs:** `<wbs>` (required). `--mode <full|implement>` selects the execution mode. `implement` invokes `sp:code-implementation` inline by default. Interactive `full` resolves the selector uniformly (task 0687): omit ≡ explicit `--agent inline`; full mode reads `task-pipeline.yaml` and drives its actions/guards in the host session — host-controlled and non-subprocess, with 0508 eligibility applying to the resolved-inline selector (eligible `agent.run` stages dispatch once to a native subagent, host fallback)). `--agent auto`, a name, or headless invocation launches the workflow subprocess. `--agent <inline|auto|name>` selects the execution surface (see [SSOT](cross-cutting.md#inline-default-execution-surface)). `--auto` skips the HITL approve gate / confirmations and propagates down the `--next` chain. `--next` controls chaining only and never changes the mode; a pipeline implement stage must invoke `/sp:dev-run <wbs> --mode implement`. On implement success with `--next`, transition `todo → wip → testing` through the FSM (guards honored — no `--no-lifecycle`) + chain to `/sp:dev-verify <wbs> --auto --next`. On a guard failure, stop as review-pending. **Partial-deliverable rule:** if the task ships only part of its requirements (e.g. an R1/R2 split with the rest in a follow-up task), the `## Solution` section must state that explicitly and the verify verdict will record the scope. `--worktree [<name>]` runs the full pipeline inside an isolated git worktree (create or reuse; FF-merge on success, retain on failure) — the batch lifecycle in [execution-batch.md § Worktree isolation](execution-batch.md#worktree-isolation---worktree-name) applied to a batch of one; rejected with `--mode implement`. `--no-summary` skips the [execution summary](#execution-summary) printed after a full-mode run. `--wrap` hands off to `/sp:dev-wrap <wbs>` after the main step; the `--agent` selector is preserved into that handoff when supplied (omission remains omission), and the wrap hop reports its own trigger-3 subprocess override per the wrap contract.
160
160
  - **Backing:** `sp:spur-dev` skill — `run` operation for the full pipeline (the spine drives it); `sp:code-implementation` competency skill for the implement step (the spine dispatches to it).
161
161
  - **Modes:**
162
- - **`full`** (default): Drive the full pipeline — precheck → implement → test → review → approve(HITL) → verify → record → done. Interactive omit/inline runs `spur workflow run task-pipeline.yaml --vars '{"wbs":"<wbs>","executor":"host"}'` and performs each returned work item (eligible stages may use a native subagent); explicit/headless executor selection runs the same definition without the `executor` var (with `profile: auto` when `--auto`). Both monitor/surface HITL and preserve the YAML gates. `--next` never changes this mode.
162
+ - **`full`** (default): Drive the full pipeline — precheck → implement → gate ⇄ remediate → review → done, with the repair, stop and approval routes taken from decision rows ([decision-points.md](decision-points.md)). Interactive omit/inline runs `spur workflow run task-pipeline.yaml --vars '{"wbs":"<wbs>","executor":"host"}'` and performs each returned work item (eligible stages may use a native subagent); explicit/headless executor selection runs the same definition without the `executor` var (with `profile: auto` when `--auto`). Both monitor/surface HITL and preserve the YAML gates. `--next` never changes this mode.
163
163
  - **`implement`** (explicit `--mode implement` only): Execute only the implement step. Read the task's `## Requirements` / `## Design` / `## Plan`, write the code that satisfies them, author the `## Solution` change-map section (file:line + what/why per changed file) via `spur task update <wbs> --section Solution --from-file`. This is the implement step the pipeline calls — it is NOT the pipeline driver. With `--next`: on success, transition `todo → wip → testing` through the FSM (guards honored — no `--no-lifecycle`) + chain to `/sp:dev-verify <wbs> --auto --next`; on a guard failure, stop as review-pending. **Partial-deliverable rule:** if the task ships only part of its requirements (e.g. an R1/R2 split with the rest in a follow-up task), the `## Solution` and `## Review` sections MUST carry a `⚠️ PARTIAL` marker naming the deferred part and the follow-up WBS — see `plugins/sp/commands/dev-run.md` → "Section ownership".
164
164
  - **Delegation:** `Skill(skill="sp:spur-dev", args="run $ARGUMENTS")` for both full-mode paths (the `executor` var picks host session vs child process); `Skill(skill="sp:code-implementation", args="$ARGUMENTS")` for implement mode.
165
165
 
@@ -366,13 +366,13 @@ check receipt (`receipt.runId === runId`), otherwise `n/a (<reason>)`. Any value
366
366
 
367
367
  ### 6. plan
368
368
 
369
- - **Purpose:** Plan a feature from a description — intake → feature create → AC generation → feature check gate → decomposition → batch-create (with **Design by default**).
369
+ - **Purpose:** Plan a feature from a description — intake → feature create → AC generation → decomposition → batch-create (with **Design by default**).
370
370
  - **Inputs:** `"<description>"` (required). `--feature <id>` links to an existing feature. `--parent <feature-id>` nests under a parent. Omitted/`inline` drives `idea-pipeline.yaml` in the host session; `auto` or a name launches the async workflow worker. **Design package flags (unified with `/sp:dev-idea`):**
371
371
  - **Default:** author task `design` on every batch item + feature satellite when the seam heuristic fires (**ties lean design**). There is **no** `--design` force flag.
372
372
  - `--skip-design` — skip feature satellite **and** omit task `design` fields (scaffold only; refine fills later). Sole design opt-out.
373
373
  - `--auto` — accept the recommendation at every operator gate, taste gates included (same contract as § 16 idea).
374
374
  - **Backing:** `sp:spur-dev` skill, `plan` operation. Stage floor: the `planner` role per [`roles.md`](../../../references/roles.md) — this file names roles, never tiers (0538 R4).
375
- - **Behavior:** Clarify scope → `spur feature create` → author BDD AC → `spur feature check` gate → decompose into task-batch JSON **including `design` (unless `--skip-design`)** → `spur task batch-create` gate. Design package details: [planning-workflow.md](planning-workflow.md) Step 5.5.
375
+ - **Behavior:** Clarify scope → `spur feature create` → author BDD AC → decompose into task-batch JSON **including `design` (unless `--skip-design`)**. The pipeline then runs `spur feature check` on the recorded AC (`ac-generate`) and `spur task batch-create` (`batch-create-run`) as deterministic steps that route on their recorded result — neither is an operator gate. Design package details: [planning-workflow.md](planning-workflow.md) Step 5.5.
376
376
  - **Delegation:** `Skill(skill="sp:spur-dev", args="plan $ARGUMENTS")`
377
377
 
378
378
  ### 7. docs
@@ -489,10 +489,10 @@ gate commands, pending questions and approval requirements.>
489
489
 
490
490
  ### 14. wrap
491
491
 
492
- - **Purpose:** Wrap up a single completed task — capture learnings, record metrics, sync docs, and optionally advance the feature / clean up the branch.
492
+ - **Purpose:** Wrap up a single completed task — capture learnings, record metrics, sync docs, and optionally clean up the branch.
493
493
  - **Inputs:** `<wbs>` (required, positional). `--agent <inline|auto|name>` names the wrap's model-bearing executor (default: `inline`, resolving identically when omitted; task 0687); wrap is workflow-backed (headless), so omit ≡ explicit `inline` (task 0687): tier substitution under objective trigger 3 (durable auditable run record required) plus one warning naming the substituted executor. `auto` tier-resolves an executor, and a name pins that executor into `vars.agent` (see [SSOT](cross-cutting.md#inline-default-execution-surface)). `--auto` skips objective confirmations (the branch-cleanup HITL gate still pauses — irreversible). `--merge` triggers branch cleanup (irreversible HITL gate).
494
494
  - **Backing:** `spur workflow run wrapup-pipeline.yaml` — direct workflow invocation (no backing skill; the pipeline IS the procedure).
495
- - **Behavior:** Resolves the executor (`agent.default` for omit/`inline`, tier-resolved for `auto`, unchanged for a name), emits a pre-dispatch notice naming the subprocess override — `execution surface: subprocess`, `reason: trigger 3 — durable auditable run record required`, `requested agent: <selector>`, `executor: <resolved>` — then builds `--vars '{"tasks":"[\"<wbs>\"]","agent":"<resolved>","profile":"interactive|auto","merge":"true|false"}'` and invokes the wrapup pipeline. The pipeline runs: task-resolve → doc-sync → learnings-validate → learnings-append → doc-tripwire → metrics-record → (feature-transition) → (branch-cleanup) → done. `doc-tripwire` (1037) runs the TRUSTED CONFIG ONLY `docTripwireCmd` over the still-uncommitted wrap diff after the doc-sync exits converge — the default runs `bun run test-repo-wide` only when `package.json` declares the script (a no-op in other projects); override it via `--vars`, and an empty string disables the check while still recording PASS; a FAIL fails the wrap with already-written learnings/docs preserved. Task statuses are NOT mutated. Branch cleanup is an irreversible HITL gate that always pauses, even under `--auto`.
495
+ - **Behavior:** Resolves the executor (`agent.default` for omit/`inline`, tier-resolved for `auto`, unchanged for a name), emits a pre-dispatch notice naming the subprocess override — `execution surface: subprocess`, `reason: trigger 3 — durable auditable run record required`, `requested agent: <selector>`, `executor: <resolved>` — then builds `--vars '{"tasks":"[\"<wbs>\"]","agent":"<resolved>","profile":"interactive|auto","merge":"true|false"}'` and invokes the wrapup pipeline. The pipeline runs: task-resolve → doc-sync → learnings-validate → learnings-append → doc-tripwire → metrics-record → (branch-cleanup) → done. `doc-tripwire` (1037) runs the TRUSTED CONFIG ONLY `docTripwireCmd` over the still-uncommitted wrap diff after the doc-sync exits converge — the default runs `bun run test-repo-wide` only when `package.json` declares the script (a no-op in other projects); override it via `--vars`, and an empty string disables the check while still recording PASS; a FAIL fails the wrap with already-written learnings/docs preserved. Task and feature statuses are NOT mutated. Branch cleanup is an irreversible HITL gate that always pauses, even under `--auto`.
496
496
  - **Vars string typing:** `tasks` is a JSON-encoded **string**, not a JSON array — `spur workflow run --vars` accepts only string values (`--vars values must be strings`); the pipeline's guards parse the string with `jq length`. `jq -nc` guarantees the shape:
497
497
 
498
498
  ```bash
@@ -505,15 +505,15 @@ gate commands, pending questions and approval requirements.>
505
505
 
506
506
  ### 15. wrapall
507
507
 
508
- - **Purpose:** Wrap up a batch of completed tasks — capture learnings, record metrics, sync docs, advance a feature through legal lifecycle edges, and optionally clean up branches.
509
- - **Inputs:** `--since <iso-date>` filters done tasks by frontmatter `updated_at >= date` (v1 approximation). `--feature <id>` selects all tasks under a feature AND advances the feature through legal lifecycle edges (`backlog → active → verifying → done`, guards honored). `--status <s>` (default: `done`) filters by task status. `--agent <inline|auto|name>` names the wrap's model-bearing executor (default: `inline`, resolving identically when omitted; task 0687); wrap is workflow-backed (headless), so omit ≡ explicit `inline` (task 0687): tier substitution under objective trigger 3 (durable auditable run record required) plus one warning naming the substituted executor. `auto` tier-resolves an executor, and a name pins that executor into `vars.agent` (see [SSOT](cross-cutting.md#inline-default-execution-surface)). `--auto` skips objective confirmations. `--merge` triggers branch cleanup (irreversible HITL gate).
508
+ - **Purpose:** Wrap up a batch of completed tasks — capture learnings, record metrics, sync docs, and optionally clean up branches.
509
+ - **Inputs:** `--since <iso-date>` filters done tasks by frontmatter `updated_at >= date` (v1 approximation). `--feature <id>` selects all tasks under a feature; it no longer advances the feature — wrap-up owns post-task knowledge work only (1249 R1/R5), so follow the batch with `spur feature sync <id>` if a transition is wanted. `--status <s>` (default: `done`) filters by task status. `--agent <inline|auto|name>` names the wrap's model-bearing executor (default: `inline`, resolving identically when omitted; task 0687); wrap is workflow-backed (headless), so omit ≡ explicit `inline` (task 0687): tier substitution under objective trigger 3 (durable auditable run record required) plus one warning naming the substituted executor. `auto` tier-resolves an executor, and a name pins that executor into `vars.agent` (see [SSOT](cross-cutting.md#inline-default-execution-surface)). `--auto` skips objective confirmations. `--merge` triggers branch cleanup (irreversible HITL gate).
510
510
  - **Backing:** `spur workflow run wrapup-pipeline.yaml` — direct workflow invocation.
511
- - **Behavior:** Resolves the task list via `spur task list --json` (filtered by `--feature`, `--since`, `--status`), resolves the executor (omission and explicit `--agent inline` tier-substitute identically with a warning per task 0687, `auto` tier-resolves, a name pins), emits a pre-dispatch notice naming the subprocess override — `execution surface: subprocess`, `reason: trigger 3 — durable auditable run record required`, `requested agent: <selector>`, `executor: <resolved>` — then builds `--vars '{"tasks":"[...]","feature":"<id>","agent":"<resolved>","profile":"interactive|auto","merge":"true|false"}'` and invokes the wrapup pipeline. The pipeline runs the same states as `wrap` — including the `doc-tripwire` hop (1037), whose TRUSTED CONFIG ONLY `docTripwireCmd` runs the repo-wide tripwires over the still-uncommitted wrap diff and can be overridden or disabled (empty string) via `--vars` — but with the full task list and optional feature transition. Task statuses are NOT mutated. Feature transitions go through `spur feature update` so lifecycle guards apply. Branch cleanup is an irreversible HITL gate.
511
+ - **Behavior:** Resolves the task list via `spur task list --json` (filtered by `--feature`, `--since`, `--status`), resolves the executor (omission and explicit `--agent inline` tier-substitute identically with a warning per task 0687, `auto` tier-resolves, a name pins), emits a pre-dispatch notice naming the subprocess override — `execution surface: subprocess`, `reason: trigger 3 — durable auditable run record required`, `requested agent: <selector>`, `executor: <resolved>` — then builds `--vars '{"tasks":"[...]","agent":"<resolved>","profile":"interactive|auto","merge":"true|false"}'` and invokes the wrapup pipeline. The pipeline runs the same states as `wrap` — including the `doc-tripwire` hop (1037), whose TRUSTED CONFIG ONLY `docTripwireCmd` runs the repo-wide tripwires over the still-uncommitted wrap diff and can be overridden or disabled (empty string) via `--vars` — but with the full task list. Task and feature statuses are NOT mutated. Branch cleanup is an irreversible HITL gate.
512
512
  - **Vars string typing:** `tasks` is a JSON-encoded **string**, not a JSON array — `--vars` values must be strings (the CLI rejects raw arrays); `jq -nc` passes the array text through as a string value:
513
513
 
514
514
  ```bash
515
- VARS=$(jq -nc --arg tasks "$TASKS" --arg feature "$FEATURE" --arg agent "$AGENT" --arg profile "$PROFILE" --arg merge "$MERGE" \
516
- '{tasks:$tasks, feature:$feature, agent:$agent, profile:$profile, merge:$merge}')
515
+ VARS=$(jq -nc --arg tasks "$TASKS" --arg agent "$AGENT" --arg profile "$PROFILE" --arg merge "$MERGE" \
516
+ '{tasks:$tasks, agent:$agent, profile:$profile, merge:$merge}')
517
517
  spur workflow run wrapup-pipeline.yaml --vars "$VARS"
518
518
  ```
519
519
 
@@ -538,7 +538,7 @@ gate commands, pending questions and approval requirements.>
538
538
  fails the run when that file is empty or missing, and every model-bearing stage prompt treats
539
539
  it as the authoritative ask (R2).
540
540
  - **Backing:** `idea-pipeline.yaml` on the host executor (`vars.executor: host`, advanced by `spur workflow continue`) for omitted/`inline`, or `spur workflow run idea-pipeline.yaml --async` for `auto`/name.
541
- - **Behavior:** Builds vars from the table above and drives the idea pipeline. Flow: discovery → **idea-eval** (taste; reject → cancelled) → feature-create → ac-generate → feature-check → system-design (conditional) → design-approval (taste) → decompose → batch-create (`--skip-ready`) → ready-prepare (ready checklist per created task + ready-evidence sidecar, 0788) → handoff. STOPS at handoff — no task execution, no pipeline nesting. Headless runs use one `trace --follow`; cancellation is reported stopped only when `workflow cancel --json` returns `killed: true`.
541
+ - **Behavior:** Builds vars from the table above and drives the idea pipeline. Flow: discovery → **idea-eval** (taste; reject → cancelled) → feature-create → ac-generate → system-design (conditional) → design-approval (taste) → decompose → batch-create-run (`--skip-ready`) → ready-prepare (ready checklist per created task + ready-evidence sidecar, 0788) → handoff-finalize → handoff. STOPS at handoff — no task execution, no pipeline nesting. Headless runs use one `trace --follow`; cancellation is reported stopped only when `workflow cancel --json` returns `killed: true`.
542
542
  - **Delegation:** Host executor (this session answers each work item) by default; explicit executor selection uses the async workflow worker.
543
543
  - **Idea-evaluation gate:** After discovery, operator reviews `.spur/run/idea-eval-report.md` ([idea-evaluation.md](idea-evaluation.md)). Approve continues; reject/cancel → no feature. Under `--auto`, follows the report's recommendation (`drop` → cancelled; missing recommendation → pauses). Enhanced idea is a sidecar — `vars.idea` is not overwritten.
544
544
  - **Design package (`--skip-design` only):**
@@ -569,7 +569,7 @@ These define their procedure directly in the command file. No `Skill()` delegati
569
569
  is the procedure. The backing is a combination of git CLI, `spur` CLI, and agent reasoning.
570
570
 
571
571
  **Gate ownership.** A project quality gate (`spur self exec autofix|check|lint`, typecheck, tests,
572
- rule runs) runs only where an operation's own contract names it: the pipeline `test` hop
572
+ rule runs) runs only where an operation's own contract names it: the pipeline `gate` state
573
573
  (`run`/`runall`), `fixall`, `gtd`, `fixgha`, `unit`, and the `--check <cmd>` loops. The scribe
574
574
  operations — `changelog`, `gitmsg`, `handover`, `job-dump` — produce text or a commit, not code, so
575
575
  they run **no gate by default**, and a generic "verify before you finish" rule from `AGENTS.md` or
@@ -683,7 +683,7 @@ host instructions does not add one. An opt-in gate is explicit: `gitmsg --check
683
683
  ### 10. fixall
684
684
 
685
685
  - **Purpose:** Fix all lint, type, and test errors systematically across the working tree.
686
- - **Inputs:** `--scope <path>` (default: entire working tree) — limits fixes to a file or directory. `--gate-log <path>` (R3, task 0482) — before fixing, read this captured validation-run log and start at the `file:line` anchors its findings name, rather than re-deriving the failure from a fresh gate run. `--findings <anchors>` (R3, task 0482) — space-separated `file:line` anchors already extracted from that log by the `test` hop; when present these ARE the failing set, so fix them in order and do not run the gate to discover what broke.
686
+ - **Inputs:** `--scope <path>` (default: entire working tree) — limits fixes to a file or directory. `--gate-log <path>` (R3, task 0482) — before fixing, read this captured validation-run log and start at the `file:line` anchors its findings name, rather than re-deriving the failure from a fresh gate run. `--findings <anchors>` (R3, task 0482) — space-separated `file:line` anchors already extracted from that log by the `gate` state; when present these ARE the failing set, so fix them in order and do not run the gate to discover what broke.
687
687
  - **Backing:** `inline` — lint + test fix loop.
688
688
  - **Behavior:** 0. **Start at the anchors, never at a discovery run.** If `--findings <anchors>` is given, that space-separated `file:line` list IS the failing set — open those locations first, in order, and fix them; do not run the gate to find out what broke. If only `--gate-log <path>` is given, read that log first and identify the failing findings (lint/test errors with their `file:line` anchors) before running the loop — the captured log is the authoritative source. Either way the first action of this hop is a read, not a gate run (R3, task 0482).
689
689
  1. Inspect the project's formatter command, then settle formatter-only diffs. Without `--scope`, use the project formatter (here `spur self exec format`). With `--scope`, use a formatter invocation whose only path operands are inside the selected scope — for Biome, `bunx biome check --write "$SCOPE"`. Never append a path to a script already containing `.`: `biome check . --write <path>` still writes across the repository. Preserve quoted paths and apply the same scope to every later formatting pass. If no scoped formatter is available, report that limitation and leave out-of-scope files untouched. Here `spur self exec lint` checks formatting without rewriting it and also runs typecheck; formatting errors fail that check.
@@ -695,9 +695,9 @@ host instructions does not add one. An opt-in gate is explicit: `gitmsg --check
695
695
  7. If tests are green, proceed to the applicable standalone confirmation or pipeline handoff below.
696
696
  8. **Test fix loop:** for each in-scope failure, diagnose (test bug vs implementation bug), apply the fix, re-run the **failing test only** (`bun test <file> --test-name-pattern "<test>"`). Report outside-scope blockers without editing them. Do NOT re-run the full suite per fix — it is the dominant loop cost (task 0436 R2).
697
697
  9. **Confirming run — standalone invocation only (at most once).** After all fixes, repeat the scope-safe formatting invocation from step 1, then run the selected validation command **at most once** to confirm (here the default project gate is `spur self exec check`). If it passes, the hop is done. **Skip this step entirely when `--gate-log` is set** (see step 10) — under the pipeline nothing consumes its verdict.
698
- 10. **Pipeline-awareness (R4, task 0483; confirming run dropped 2026-08-31).** `--gate-log` is set only by the pipeline's `test-fix` hop, so treat it as the pipeline signal. There, `test-recheck` runs the full `${vars.qualityGateCmd}` gate immediately after this hop returns — that is the **deciding** run, the only one that writes PASS to `.spur/run/<wbs>-test-gate.status`. A confirming run inside this hop decides nothing and costs a second full gate (~105 s here) to answer a question `test-recheck` is about to answer anyway. So under `--gate-log`: **run no full gate at all.** Your self-check is what step 8 already gives you — the failing tests you re-ran individually — plus **one `spur self exec lint`** (~7 s: Biome + typecheck) to catch type or lint breakage your fixes introduced. Then return and let `test-recheck` judge. `test-recheck` opens with the same cheap `${vars.gateProbeCmd}` probe, so a still-red tree is caught in seconds rather than by a full suite. Historical anti-pattern this replaces: 0482 ran the gate 3× plus a standalone `bun run test`, and `test-recheck` then ran it a 5th time.
698
+ 10. **Pipeline-awareness (R4, task 0483; confirming run dropped 2026-08-31).** `--gate-log` is set only by the pipeline's `remediate` hop, so treat it as the pipeline signal. There, the `gate` state's recheck visit runs the full `${vars.qualityGateCmd}` gate immediately after this hop returns — that is the **deciding** run, the only one that writes PASS to `.spur/run/<wbs>-test-gate.status`. A confirming run inside this hop decides nothing and costs a second full gate (~105 s here) to answer a question the gate recheck is about to answer anyway. So under `--gate-log`: **run no full gate at all.** Your self-check is what step 8 already gives you — the failing tests you re-ran individually — plus **one `spur self exec lint`** (~7 s: Biome + typecheck) to catch type or lint breakage your fixes introduced. Then return and let the gate recheck judge. It opens with the same cheap `${vars.gateProbeCmd}` probe, so a still-red tree is caught in seconds rather than by a full suite. Historical anti-pattern this replaces: 0482 ran the gate 3× plus a standalone `bun run test`, and the recheck then ran it a 5th time.
699
699
  11. Report: list what was fixed (file + one-line summary per fix). If any error could not be resolved, report it explicitly — do not suppress.
700
- - **Invariants:** Never bypass with `--no-verify`, `--force`, or new `biome-ignore`/`eslint-disable` suppressions. Never skip or `.skip` a test to make the suite green. Fix the root cause, not the symptom. Here lint checks formatting and types; it does not prove that the full test gate passed. Keep every write inside `--scope`. **Never re-run the full gate more than once per confirming pass** (R4) — use targeted probes during the fix loops and let the pipeline's `test-recheck` state be the deciding run.
700
+ - **Invariants:** Never bypass with `--no-verify`, `--force`, or new `biome-ignore`/`eslint-disable` suppressions. Never skip or `.skip` a test to make the suite green. Fix the root cause, not the symptom. Here lint checks formatting and types; it does not prove that the full test gate passed. Keep every write inside `--scope`. **Never re-run the full gate more than once per confirming pass** (R4) — use targeted probes during the fix loops and let the pipeline's `gate` recheck be the deciding run.
701
701
  - **MANDATORY Exit Condition — standalone only.** At step 9, execute the following once; do not add another confirming run:
702
702
  1. Run validation command: `eval "$VALIDATION_CMD"`
703
703
  2. Capture exit code: `EXIT_CODE=$?`
@@ -706,7 +706,7 @@ host instructions does not add one. An opt-in gate is explicit: `gitmsg --check
706
706
 
707
707
  If EXIT_CODE != 0: NOT completed. Continue the bounded fix loop for in-scope failures; report outside-scope blockers.
708
708
 
709
- **Pipeline exit condition (`--gate-log` set):** return the fixes and the targeted-test/lint evidence from step 10 to `test-recheck`. Do not run the standalone validation command or claim a full-gate PASS; `test-recheck` owns that verdict.
709
+ **Pipeline exit condition (`--gate-log` set):** return the fixes and the targeted-test/lint evidence from step 10 to the `gate` recheck. Do not run the standalone validation command or claim a full-gate PASS; the recheck owns that verdict.
710
710
 
711
711
  **Hallucination Red Flags — STOP if you think:**
712
712
  - "The errors look fixed" — check exit code, not appearance
@@ -735,7 +735,7 @@ host instructions does not add one. An opt-in gate is explicit: `gitmsg --check
735
735
  └─────────────────────────────────────────────────┘
736
736
  ```
737
737
 
738
- The 7 phases describe standalone execution: Phases 1–2 capture the gate, Phase 3 settles auto-fixable formatting within scope, Phases 4–6 are the per-group root-cause fix loops, Phase 7 is the final verification run. With `--gate-log`, use the supplied evidence instead of capturing the gate again, and hand off to `test-recheck` instead of running Phase 7's full validation.
738
+ The 7 phases describe standalone execution: Phases 1–2 capture the gate, Phase 3 settles auto-fixable formatting within scope, Phases 4–6 are the per-group root-cause fix loops, Phase 7 is the final verification run. With `--gate-log`, use the supplied evidence instead of capturing the gate again, and hand off to the `gate` recheck instead of running Phase 7's full validation.
739
739
 
740
740
  - **Fix Priority:**
741
741
 
@@ -15,7 +15,7 @@ Read at Step 5 and once at batch end (task 1128 R1).
15
15
  When the batch finishes — clean (all `done`), halted (default failure policy), parked (`paused`:
16
16
  one or more tasks sit on an operator question (escalate, 0933) or an approval gate), or aborted
17
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
18
+ output; it does not mutate the corpus (the pipeline's `done` state already recorded per-task
19
19
  results). A `paused` task is non-terminal — the report marks it `paused` (never `done`) and names
20
20
  the resume command. Unless `--no-summary`, follow it with the measured
21
21
  [execution summary](dev-operations.md#execution-summary), one `--progress <wbs>=<file>` per attempted run.
@@ -112,7 +112,8 @@ bun run apps/cli/src/index.ts feature check <id> --strict --json
112
112
  live tasks (a warning in `FeatureCheckService` until `done`); `--strict` elevates both to error,
113
113
  so they are reported verbatim but do **not** abort the batch; every other error finding (L1–L3
114
114
  structural, `L4.malformed-verdict-artifact`, `L4.uncovered-feature-scenario`) still aborts. The
115
- terminal feature-transition gate enforces scenario verification after the batch runs, so pre-run
115
+ feature-lifecycle done-boundary gate (reached via `spur feature sync <id>`, the forward hop from
116
+ task-pipeline's done close) enforces scenario verification after the batch runs, so pre-run
116
117
  unverified scenarios and incomplete tasks are transient, not defects (dogfood 2026-08-11,
117
118
  feature I2; 2026-10-08, feature H1). Extend the set by editing that constant, never this prose.
118
119
  - **Auto-repairs are reported.** Structural repairs applied by `--fix` are listed under
@@ -461,14 +462,12 @@ in next-router; this only maps status → primary TABLE A hop for recovery.
461
462
 
462
463
  ### 3.3c Feature-sync retry suppression (task 0411; 1004 R3)
463
464
 
464
- During a batch, the per-task `record` step and the wrap-up `feature-transition` step each invoke
465
- feature status sync. When a feature is L4-gate-blocked (e.g. not all linked tasks are `done`), the
466
- identical blocked proposal repeats on every call with no intervening input change. The service fixes
467
- this, not the engine.
465
+ During a batch, the per-task `done` state invokes feature status sync. When a feature is
466
+ L4-gate-blocked (e.g. not all linked tasks are `done`), the identical blocked proposal repeats on
467
+ every call with no intervening input change. The service fixes this, not the engine.
468
468
 
469
- Both `task-pipeline.yaml` (`record` step) and `wrapup-pipeline.yaml` (`feature-transition` step)
470
- invoke `spur feature sync <feature-id> --json` directly — retry suppression lives inside the
471
- `FeatureService.syncFeature` implementation:
469
+ `task-pipeline.yaml`'s `done` state invokes `spur feature sync <feature-id> --json` directly —
470
+ retry suppression lives inside the `FeatureService.syncFeature` implementation:
472
471
 
473
472
  1. On a **blocked** result (`gateBlocked` checked first — a partial hop can have `applied: true`
474
473
  while still gate-blocked — then an unapplied from≠to deferral), the service persists
@@ -483,7 +482,7 @@ invoke `spur feature sync <feature-id> --json` directly — retry suppression li
483
482
  never reads or writes the state.
484
483
 
485
484
  **Batch driver contract:** the orchestrator does **nothing extra** — the suppression lives inside
486
- the pipeline's `record` step and the wrap-up's `feature-transition` step. The driver still
485
+ the pipeline's `done` state. The driver still
487
486
  launches `task-pipeline.yaml` verbatim (R4.1). Suppression is transparent: the sync emits the same
488
487
  `FeatureSyncResult` JSON shape (`suppressed: true` added on replay), so downstream report logic is
489
488
  unchanged. The only observable difference is fewer redundant `feature sync` derivations.
@@ -531,6 +530,16 @@ belongs to a subagent or the operator, not to the batch controller's report loop
531
530
  By default, the **first** pipeline failure halts the batch. Remaining tasks in the plan are reported
532
531
  as `not-attempted`. The report lists succeeded, failed, and not-attempted tasks.
533
532
 
533
+ **Run-failed / task-done (observed 2026-10-19, feature P1).** A run can fail *after* the task is
534
+ already finished: the `done` state's close commands run last, and a lint or anchor rule can refuse
535
+ the transition on an otherwise green task. Resolve it the honest way — fix the finding through the
536
+ owning surface, re-run the same close command, and confirm the task reads `done` with a PASS verdict
537
+ — then record the task as `done (run-failed-recovered)` with the failing command in the report.
538
+ That is **not** a `failed` outcome: the failure policy applies to a task that did not reach its
539
+ contract, not to a run whose last recorded state was superseded. Surface it in the report either
540
+ way (never silently continue), and never re-run the pipeline just to flip a run row from `failed` to
541
+ `done` — a second run re-executes model stages for a task that is already closed.
542
+
534
543
  ### 4.2 `--keep-going` (R3.2)
535
544
 
536
545
  With `--keep-going`, a failed task does **not** halt the batch. Instead:
@@ -650,7 +659,7 @@ Before launching a full `spur-check:full`:
650
659
  | R4.3 (`--agent` merged into per-task vars) | Step 3.2 |
651
660
  | R5.1 (orchestrator boundary) | "Zero engine code" preamble + Step 3 |
652
661
  | R5.2 (structured batch report) | Step 5 |
653
- | 0411 (bounded feature-sync retry suppression) | Step 3.3c — wrapper lives in pipeline `record` + wrap-up `feature-transition`; driver unchanged |
662
+ | 0411 (bounded feature-sync retry suppression) | Step 3.3c — wrapper lives in pipeline `record`; driver unchanged |
654
663
  | 0510 R2 (feature-derived strict preflight) | Step 1 — "Feature-derived strict preflight (R2, task 0510)" |
655
664
  | 0510 R5 (metadata-only host controller) | Step 3.4 + projected `task show` / trace snippets in Step 1, 2.3, 3.1 |
656
665
 
@@ -29,7 +29,7 @@ while ready or running:
29
29
  RUN[t] = (cd "$WT" && spur workflow run task-pipeline.yaml \
30
30
  --vars '{"wbs":"<wbs>","deferFeatureSync":"true"[,"deferQualityGate":"true"],...}' --async --json)
31
31
  # deferQualityGate is added ONLY under the opt-in --defer-gate flag (1111 R3):
32
- # the task's `test` hop then runs the light tier and writes DEFERRED.
32
+ # the task's `gate` state then runs the light tier and writes DEFERRED.
33
33
  wait for any RUN terminal # trace poll --follow --timeout 600000; stale-evidence rule applies
34
34
  on done: WT-3b commit on $BRANCH → integrate(t)
35
35
  on failed: WT-5 retain (marker retained); failure policy — stop-the-batch default / --keep-going subtree skip
@@ -92,9 +92,9 @@ per-task with `/sp:dev-run <wbs> --worktree <branch>`.
92
92
 
93
93
  ### Generated regions — defer the sync, regenerate once (R5)
94
94
 
95
- The only per-task writer of feature files is the `record` step's post-record feature sync
95
+ The only per-task writer of feature files is the `done` state's post-record feature sync
96
96
  (`task-pipeline.yaml`). Parallel launches set
97
- the pipeline var `deferFeatureSync: "true"` (default `"false"`): the record step appends
97
+ the pipeline var `deferFeatureSync: "true"` (default `"false"`): the done state appends
98
98
  `feature sync deferred to batch integration` to the task report and skips the sync, so task
99
99
  branches never touch feature files or `docs/features/INDEX.md`. After the last integration, on the
100
100
  base ref, the orchestrator runs `spur feature sync <f> --json` (service-level suppression) plus `spur feature refresh --feature <f>`
@@ -103,7 +103,7 @@ inline runs keep the default `"false"` and are unchanged. Any rebase conflict
103
103
  path or any other — is an R4 `integration-conflict`; there is no path-based exception.
104
104
 
105
105
  **Deferred gate (`--defer-gate`, task 1111 R3/R4).** The opt-in flag adds
106
- `deferQualityGate: "true"` to the same per-task `--vars`, so each task's `test` hop runs the light
106
+ `deferQualityGate: "true"` to the same per-task `--vars`, so each task's `gate` state runs the light
107
107
  tier and writes `DEFERRED` instead of a full-gate `PASS` (see
108
108
  [flag-glossary](flag-glossary.md#flag-defer-gate)). The orchestrator then runs the project
109
109
  `qualityGateCmd` **once** on the integrated `BASE_REF` **before** the deferred feature sync:
@@ -10,15 +10,17 @@ see_also:
10
10
 
11
11
  ```
12
12
  pick task (spur task list --json)
13
- → interactive omit/inline: host driver reads task-pipeline.yaml and walks it in-session
13
+ → interactive omit/inline: spur workflow run task-pipeline.yaml with executor=host
14
14
  → explicit/headless executor: spur workflow run task-pipeline.yaml
15
15
  → on HITL pause: surface to operator → resume the selected driver
16
16
  ```
17
17
 
18
- The execution half runs a single task through the `task-pipeline.yaml` FSM. In an interactive
19
- omit/inline invocation, the skill's host driver interprets that YAML directly. Explicit executors
20
- and headless invocations use the workflow engine. Both surfaces preserve the same actions, guards,
21
- artifacts, HITL gates, and terminal states.
18
+ The execution half runs a single task through the `task-pipeline.yaml` FSM, always on the workflow
19
+ engine. In an interactive omit/inline invocation the engine runs with `executor=host`: it executes
20
+ every deterministic action (shell, `command.gate`, `decide`) and every guard itself, and hands each
21
+ model stage back to this session as a work item. Explicit executors and headless invocations run the
22
+ model stages as subprocesses. Both surfaces share the same actions, guards, artifacts, decision
23
+ rows, HITL gates and terminal states.
22
24
 
23
25
  > **Single-task vs batch.** This file covers the **single-task** execution half — one task through
24
26
  > `task-pipeline.yaml`. For **batch** execution (a set of tasks in dependency-correct order), see
@@ -32,11 +34,11 @@ This file owns **how operations sequence** in the pipeline. What each operation
32
34
 
33
35
  > **`/sp:dev-run` drives the pipeline — it is NEVER a pipeline step.** The command
34
36
  > `/sp:dev-run <wbs>` means "run this whole pipeline" (default `--mode full`). The pipeline's
35
- > internal stages call `/sp:dev-run --mode implement`, shell quality gate + optional
36
- > `/sp:dev-fixall`, `/sp:dev-review`, `/sp:dev-verify` — never `/sp:dev-run` in full mode.
37
+ > internal stages call `/sp:dev-run --mode implement`, the typed quality gate + optional
38
+ > `/sp:dev-fixall`, and `/sp:dev-review` — never `/sp:dev-run` in full mode.
37
39
  > Calling `/sp:dev-run --mode full` from inside the `implement` step would recurse into another
38
40
  > full pipeline run. The `implement` step is the **implement operation** (dev-operations.md §4);
39
- > the verify step is `sp:code-verification`.
41
+ > requirement/AC certification happens inside `review` (D65 merged the former `verify` stage).
40
42
 
41
43
  ## The pipeline's internal stages
42
44
 
@@ -45,10 +47,11 @@ one thing and yields, so the **pipeline (not the agent) owns the loop**.
45
47
 
46
48
  | Stage | Operation | Defined in |
47
49
  | ------- | ----------- | ------------ |
48
- | `implement` | `/sp:dev-run --mode implement <wbs>` — write the code that satisfies the task; author `## Solution`. | [dev-operations.md §4 run](dev-operations.md) → `sp:code-implementation` |
49
- | `test` → (`test-fix` ↔ `test-recheck`) → `review` \| `failed` | **Project quality gate** (not `/sp:dev-unit`). Soft shell probe of `${vars.qualityGateCmd}` (default `spur self exec check`) — green path pays **one** full gate run. On FAIL: bounded `/sp:dev-fixall` loop (`qualityGateMaxFixAttempts`, default 2) with soft recheck; exhausted attempts route to pipeline `failed`. `/sp:dev-unit` remains **coverage gap-fill** (router C3/C5 / standalone). | [dev-operations.md §10 fixall](dev-operations.md); unit op still §1 |
50
- | `review` | `/sp:dev-review --tasks <wbs>` — SECUA-framework review of the diff. | [dev-operations.md §2 review](dev-operations.md) |
51
- | `verify` | `sp:code-verification` — requirements traceability + verdict. | [dev-operations.md §3 verify](dev-operations.md) |
50
+ | `implement` | `/sp:dev-run --mode implement <wbs>` — write the code that satisfies the task; author `## Solution`. May pause through `escalate` (operator question). | [dev-operations.md §4 run](dev-operations.md) → `sp:code-implementation` |
51
+ | `gate` | **Typed quality gate** (not `/sp:dev-unit`): `spur task gate <wbs> run\|recheck` over `${vars.qualityGateCmd}` (default `spur self exec check`) under the host-wide lock, with tree-hash receipt reuse. The first visit runs `run`; every visit after a remediation runs `recheck`. Also resolves the review lane (`task-triage`) and classifies a red gate (`failure-class`). | `spur task gate` ([tasks reference](../../spur-cli/references/tasks/verbs.md)) |
52
+ | `remediate` | `/sp:dev-fixall "${vars.qualityGateCmd}" --gate-log … --findings …` — the bounded repair hop for a red gate **or** a fixable non-PASS review; re-enters `gate`. One shared counter (`qualityGateMaxFixAttempts`, default 2) bounds both lanes. `/sp:dev-unit` stays coverage gap-fill (router C3/C5 / standalone). | [dev-operations.md §10 fixall](dev-operations.md) |
53
+ | `review` | `/sp:dev-review --tasks <wbs> --auto --focus <functional\|all>` — SECUA + requirement/AC traceability; `spur task verdict --from-answer` certifies the answer, `review-failure-class` classifies a non-PASS, then the approval decision point answers. | [dev-operations.md §2 review](dev-operations.md) |
54
+ | `done` | Deterministic close: `spur task record` writes `## Testing` from the verdict, then `spur task update <wbs> done --no-lifecycle` runs the completion check. | [dev-operations.md §3 verify](dev-operations.md) (standalone re-certification) |
52
55
 
53
56
  Interactive omit/`inline` executes these model stages in the host session through the engine loop:
54
57
  the engine owns every guard and transition, the host performs each returned work item and records
@@ -144,7 +147,7 @@ Synchronous invocation (`--json` without `--async`) is acceptable **only** for s
144
147
  On the subprocess path, when `--agent <value>` is set (passed through from the thin wrapper), merge it into the vars as
145
148
  **both** `agent` and `implementAgent` (task 0483 R2):
146
149
  `--vars '{"wbs":"<wbs>","agent":"<value>","implementAgent":"<value>"}'`. The pipeline YAML reads
147
- `${vars.agent}` for review/verify/test-fix and `${vars.implementAgent}` for implement — setting
150
+ `${vars.agent}` for remediate/review and `${vars.implementAgent}` for implement — setting
148
151
  both keys ensures the pinned executor reaches every hop. The full value-semantics contract (one
149
152
  rule, value table, objective triggers, and headless `inline` substitution (tier resolution + one warning) per ADR-087)
150
153
  lives in [cross-cutting.md](cross-cutting.md#inline-default-execution-surface) — the SSOT.
@@ -161,34 +164,39 @@ pipeline (bug-742).
161
164
  The pipeline (`kind: state-machine`) runs the work loop:
162
165
 
163
166
  ```
164
- precheck → implement → test [→ test-fix → test-recheck] → review → approve(HITL) → verify → record → done
167
+ precheck → implement[⇄ escalate] → gate[⇄ remediate] → review → done | failed
165
168
  ```
166
169
 
167
- Two branches reach the bounded repair hop, not one (session finding after 1088):
170
+ Two branches reach the bounded `remediate` hop, and each is routed by a recorded decision row, not
171
+ by this session's judgment:
168
172
 
169
- - `test`/`test-recheck` FAIL → `test-fail-triage` (0943's failure-class router) → `test-fix`;
170
- - `review` without a `Verdict: PASS` in its answer → `review-fail-triage` (the review-side twin) →
171
- `test-fix`, bounded by the SAME `qualityGateMaxFixAttempts` counter. A FAIL review therefore has
172
- an on-graph, bounded path to remediation instead of dead-ending the run, and the fix re-enters
173
- quality → review → verify on a freshly captured proof digest.
173
+ - a red `gate` → `failure-class` (`fix` → `remediate`, `stop` → `failed`);
174
+ - a review that did not certify PASS → `review-failure-class` (`fix` → `remediate`, `stop` →
175
+ `failed`), bounded by the SAME `qualityGateMaxFixAttempts` counter. The repair re-enters
176
+ `gate` (recheck) → `review` on the remediated tree.
177
+
178
+ Every decision point, its fallback and its consumer are listed in
179
+ [decision-points.md](decision-points.md); read the rows it names instead of re-judging them.
174
180
 
175
181
  The completion gate reads deterministic evidence only: the review stage's **verdict artifact** (`.spur/run/<wbs>-verdict.json`, derived by `spur task verdict --from-answer`) and the **tree-hash gate receipt** (`.spur/run/<wbs>-check-receipt.json`, reused while the tree is unchanged). The ADR-071 proof chain this paragraph used to describe — proof digests, `verify → record`, review-inside-the-bracket — was deleted by the D65 pipeline rewrite; `record` now runs inside `done`'s onEnter and `verify` merged into `review`. Two grades are read, and only as cross-checks against the answer's own rows: the review answer states one `Confidence: HIGH|MEDIUM|LOW` line (ADR-141) and the review gate recomputes it from the finding dispositions, rejecting a disagreement. Nothing grades the *verifier's* opinion: an open P1–P3 finding blocks `done` on its own, and what protects a hand-driven `task update <wbs> done` is unchanged — the gate must show a PASS receipt for this tree and a recorded review artifact.
176
182
 
177
183
  Agentic steps use the pure slash inputs declared by each YAML `agent.run` action (ADR-043). The
178
184
  workflow engine dispatches them; the interactive driver invokes their backing skills in-session.
179
- The `test` hop is primarily
180
- **deterministic shell** (quality gate); only the optional `test-fix` hop is agentic
185
+ The `gate` state is
186
+ **deterministic** (quality gate plus decision points); only the optional `remediate` hop is agentic
181
187
  (`/sp:dev-fixall`). The skill monitors the run:
182
188
 
183
- - **On HITL pause** (`approve` state): surface the review output to the operator. On the subprocess
184
- path use `spur workflow continue <run-id> --yes`; on the inline path retain the current state and
185
- resume the host driver with the operator's answer.
189
+ - **On HITL pause** (`escalate`, or the approval decision point inside `review`): surface the
190
+ question, or the review answer and verdict, to the operator. Resume with `spur workflow continue
191
+ <run-id> --answer-text <answer>` (or `--yes` for the approval). The approval answer lands in
192
+ `.spur/run/<wbs>-approval.status`; a `no`/`cancel` ends the run `failed` with terminal reason
193
+ `cancelled`, a recorded denial rather than a check failure.
186
194
  - **On guard failure** (`precheck`): the task's check findings block progress — fix the
187
195
  task first.
188
- - **On completion** (`done`): the pipeline's `record` step has already written the verdict
196
+ - **On completion** (`done`): the `done` state's onEnter has already written the verdict
189
197
  transcript into the task's `## Testing` via `spur task record <wbs>` (matrix-compliant tables;
190
198
  `## Review` was authored by the review step and is only backfilled bare, never overwritten —
191
- F92 0593 R1; never transitions to `done` — the gate stays in the workflow).
199
+ F92 0593 R1) and moved the task to `done` through the verb's own completion check.
192
200
 
193
201
  ## `--next` chain — advance to the next step
194
202
 
@@ -400,6 +408,10 @@ After a completed task, decide next action:
400
408
 
401
409
  ## Skipping HITL
402
410
 
403
- Passing `--vars '{"profile":"auto"}'` to `spur workflow run` (a var choice, not a YAML fork) skips
404
- the `approve` HITL gate — use for low-risk, well-understood tasks where operator review adds no value.
411
+ Passing `--vars '{"profile":"auto"}'` to `spur workflow run` (a var choice, not a YAML fork) makes the
412
+ approval decision point answer itself instead of prompting: its evidence binding answers from the
413
+ recorded review evidence, through the `gate-evidence` decision when `workflows.hitlDecisionMaker`
414
+ is on. It is not a bypass — an auto run still ends `failed`/`cancelled` when the maker answers
415
+ `no`; a deferred answer (switch off, no reachable maker, or insufficient evidence) is not a denial. Use it for low-risk,
416
+ well-understood tasks where operator review adds no value.
405
417
  (Combine with `wbs` in one object: `--vars '{"wbs":"0042","profile":"auto"}'`.)
@@ -118,6 +118,39 @@ WT_PATH="$(cd "../<worktree-dir>" && pwd)" # hoisted: needed by WT-4a AND WT-4
118
118
  # task's creation), so a manual DB edit is never required:
119
119
  spur workflow persist-out --from "$WT_PATH" "${TASK_FILE_ARGS[@]}" \
120
120
  || { echo "halt: worktree run-record persist-out failed - worktree retained (WT-5)" >&2; write_marker retained; exit 1; }
121
+
122
+ **Two refusals this step raises, and how to clear each without touching foreign evidence.**
123
+
124
+ 1. **`durable evidence conflicts: <name>`** — the worktree owns a receipt (`*-feature-verification.json`)
125
+ whose canonical target already holds *different* bytes. The conflict policy is fail-closed on
126
+ purpose: overwriting would destroy the invoking tree's copy. When the worktree receipt is the
127
+ newer, authoritative one (e.g. the feature transition this batch performed), archive the
128
+ superseded copy out of the canonical path and re-run — never delete it, and never copy the
129
+ worktree file in with `cp`:
130
+
131
+ ```bash
132
+ mkdir -p .spur/memory/evidence/superseded
133
+ mv ".spur/memory/evidence/<name>" ".spur/memory/evidence/superseded/<name>.<iso-timestamp>.json"
134
+ # then re-run the persist-out command above; the newer receipt lands at the canonical path
135
+ ```
136
+
137
+ When the *invoking* copy is the newer one, do nothing: `persist-check` reports it as foreign and
138
+ divergent, which is not a blocker.
139
+ 2. **`persist-check … BLOCKED n unforwarded durable verdict/receipt`** — the worktree holds
140
+ `*-verdict.json` files for tasks this batch did not run, because **WT-2 stages the invoking tree's
141
+ evidence into the worktree before the first task**. Forwarding them back (`--task-file`) is wrong
142
+ when the invoking tree's copies are newer: persist-out then refuses with `cited run evidence …
143
+ diverges`, and it would write stale bytes over fresh ones. Compare mtimes and delete the staged
144
+ worktree copies, then re-run `persist-check` with only this batch's `--task-file` arguments:
145
+
146
+ ```bash
147
+ for w in <staged-wbs>; do
148
+ [ .spur/run/$w-verdict.json -nt "$WT_PATH/.spur/run/$w-verdict.json" ] \
149
+ && rm -f "$WT_PATH/.spur/run/$w-verdict.json"
150
+ done
151
+ ```
152
+
153
+ Both steps are reads plus a delete of a *copy* whose source still holds it — no evidence is lost.
121
154
  #
122
155
  # WT-4b — bounded CWD-holder cleanup (task 0720 R1). $WT_PATH above is the EXACT
123
156
  # absolute worktree path; a relative path or a stale entry matches the wrong processes.
@@ -361,8 +394,7 @@ skipped persist-out (or the pre-removal assertion fired too late), verdicts rema
361
394
  from the task records — `spur task show <wbs> --json` carries the recorded verdict and its
362
395
  proof block, so a lost `<wbs>-verdict.json` is regenerated by re-recording or copying from
363
396
  the task store. Feature run/latest receipts are re-runnable, not recovered: rerun the
364
- feature-verification workflow in the invoking tree —
365
- `spur workflow run feature-verification.yaml --vars '{"featureId":"<id>"}'` — which rewrites
397
+ feature-verification pass in the invoking tree — `spur feature verify <id>` — which rewrites
366
398
  the receipt files it owns. Divergent files are never auto-overwritten; reconcile by hand.
367
399
 
368
400
  ```
@@ -208,10 +208,10 @@ the worktree directory before launching the loop.
208
208
  #### Evidence staging before the first task (create and reuse mode)
209
209
 
210
210
  `.spur/memory/evidence/` and `.spur/run/` are **untracked per-tree** planes, so a fresh worktree
211
- starts with neither while the invoking tree holds every earlier task's verdict. Both
212
- `preflightFeature` (`spur task wrapup resolve` → `spur feature check --strict --as done`
213
- with cwd = the worktree) and `runMetrics` resolve verdict artifacts relative to the tree they run
214
- in, so without this step an already-`done` linked task reads as missing evidence
211
+ starts with neither while the invoking tree holds every earlier task's verdict. Feature completion
212
+ checks (`spur feature check --strict --as done`) and wrap-up metrics resolve verdict artifacts relative
213
+ to the tree they run in; wrap-up task resolution itself checks task identity and terminal status only.
214
+ Without this step an already-`done` linked task reads as missing evidence
215
215
  (`L4.evidence-not-recoverable`, `L4.scenario-unverified`) and its metrics row degrades to
216
216
  `UNKNOWN`.
217
217
 
@@ -151,7 +151,7 @@ halt-on-first-failure. Never silently retried; the failure is still reported.
151
151
  **Applies to:** `/sp-dev-runall --mode parallel`, and `--mode auto` when it resolves to parallel.
152
152
  **Default:** off — every task pipeline runs its own FULL project gate inside its worktree.
153
153
 
154
- With `--defer-gate`, each task's `test` / `test-recheck` hop runs the **light tier** (changed-scope
154
+ With `--defer-gate`, each task's `gate` state (every visit) runs the **light tier** (changed-scope
155
155
  format, per-workspace typecheck, related tests) and writes `DEFERRED` — never `PASS` — to
156
156
  `.spur/run/<wbs>-test-gate.status`. The orchestrator then owes **one integrated full gate** on the
157
157
  base ref over the merged slices, **before** the deferred feature sync; on FAIL the batch verdict is
@@ -164,8 +164,8 @@ Two properties are load-bearing and are asserted structurally:
164
164
  fails inside its own worktree instead of at the end of the batch (the reason ADR-124 rejected an
165
165
  unconditional single end-of-run gate).
166
166
  - **The full tier is still the only `PASS` writer.** Only the integrated run can claim a green
167
- project gate; the per-task token is `DEFERRED`, and the `test → triage` /
168
- `test-recheck → triage` guards accept it only while `deferQualityGate = "true"`.
167
+ project gate; the per-task token is `DEFERRED`, and the deferred `gate → review`
168
+ guard accepts it only while `deferQualityGate = "true"`.
169
169
 
170
170
  `--defer-gate` with `--mode sequential` (or omitted `--mode`) is rejected — the flag exists to move
171
171
  one full gate from N worktrees to the one place the integrated tree exists. Under `--mode auto` it
@@ -98,9 +98,10 @@ Entered before `task-pipeline.yaml` `review` state dispatches `sp:code-verificat
98
98
 
99
99
  ## verify gate
100
100
 
101
- Entered before `task-pipeline.yaml` `verify` state produces a task verdict.
101
+ Entered before the `task-pipeline.yaml` `review` state certifies a task verdict (D65 merged the
102
+ former `verify` state into `review`; standalone `/sp:dev-verify` applies the same list).
102
103
 
103
- - [ ] The verify answer file (`.spur/run/<wbs>-verify-answer.txt`) is lint-clean before
104
+ - [ ] The answer file (`.spur/run/<runId>-review-answer.txt` in the pipeline) is lint-clean before
104
105
  verdict derivation: `spur task verdict <wbs> --from-answer …` (0726 R3) lints the
105
106
  file first and rejects missing/duplicate/unknown R IDs, AC identities that are not an
106
107
  exact task checklist label or linked-feature scenario title, invalid status/evidence-type
@@ -80,9 +80,18 @@ Avoid: *prompt* (reserved for LLM input text), *interrupt* (implies an exception
80
80
  pause point).
81
81
 
82
82
  **DecisionMaker** — optional provider-backed responder for executed `hitl.confirm`/`hitl.select`
83
- actions (ADR-123), enabled via `workflows.hitlDecisionMaker: true` and `TYPESAFE_API_KEY`.
84
- Evidence answers clear the answer variable and record `statusVar: accepted/deferred`; unresolved
85
- cases defer or delegate to the human. Offline readiness: `spur self status`.
83
+ actions (ADR-123), enabled via `workflows.hitlDecisionMaker: true`. Evidence-mode confirm gates
84
+ answer through the catalog decision `gate-evidence`, so the effective maker (and its credentials)
85
+ comes from `decisions.*` config. Evidence answers clear the answer variable and record
86
+ `statusVar: accepted/deferred`; unresolved cases defer or delegate to the human. Readiness:
87
+ `spur decision status --probe`.
88
+
89
+ **decision point** — a recorded, closed-vocabulary judgment inside a workflow: a `decide` action
90
+ (or an evidence-mode HITL gate) that names a catalog decision id and writes a schemaVersion-1
91
+ `.decision` row whose `value` the next guard reads. It always has a deterministic fallback, so it
92
+ works with no model. Inventory: [decision-points.md](decision-points.md).
93
+ Avoid: *decision brief* (the operator-facing HITL summary format in
94
+ [decision-brief.md](decision-brief.md) — prose for a human, not a catalog answer).
86
95
 
87
96
  **WBS** (work-breakdown-structure ID) — the four-digit task identifier (e.g. `0187`) that
88
97
  names a task file and its position in the corpus. WBS IDs are assigned once and never reused.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: planning-workflow
3
- description: "Extracted section: the planning half — intake → feature create → AC generation → feature check gate → decomposition → batch-create gate → refine. The full step-by-step procedure for turning a vague description into a validated, decomposed feature."
3
+ description: "Extracted section: the planning half — intake → feature create → AC generation → decomposition → batch-create → refine. The full step-by-step procedure for turning a vague description into a validated, decomposed feature."
4
4
  see_also:
5
5
  - spur-dev
6
6
  - decomposition
@@ -13,18 +13,19 @@ see_also:
13
13
  vague description
14
14
  → intake (clarify scope, constraints — prompt work)
15
15
  → spur feature create … ; AC authored/generated (spur agent run, bdd templates)
16
- → GATE: spur feature check (BDD validator; loop until clean)
16
+ → ac-generate runs `spur feature check` (BDD validator; loop until clean)
17
17
  → decomposition (prompt work) → task-batch JSON
18
- → GATE: task-batch.schema.json + spur task batch-create (atomic: all-or-nothing)
18
+ → batch-create-run runs `task-batch.schema.json` + `spur task batch-create` (atomic: all-or-nothing)
19
19
  → design doc (conditional: seam heuristic under default; skip with --skip-design) → docs/design/<slug>.md + 04 index
20
20
  ```
21
21
 
22
22
 
23
23
  The planning half transforms a description into a validated feature file with acceptance
24
- criteria, then decomposes it into a batch of tasks. Two CLI gates make LLM regressions
25
- unable to corrupt the corpus: `spur feature check` validates the AC, and
24
+ criteria, then decomposes it into a batch of tasks. Two deterministic validation steps make LLM
25
+ regressions unable to corrupt the corpus: `spur feature check` validates the AC, and
26
26
  `task-batch.schema.json` validates the decomposition shape before `spur task batch-create`
27
- writes anything.
27
+ writes anything. Both run inside the pipeline (`ac-generate`, `batch-create-run`) and route on
28
+ their recorded result — neither is an operator gate.
28
29
 
29
30
  ## Step 1: Intake
30
31