@gobing-ai/spur 0.4.15 → 0.4.17

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 (107) 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/workflows/task-pipeline.yaml +66 -54
  6. package/package.json +11 -10
  7. package/plugins/sp/README.md +4 -4
  8. package/plugins/sp/agents/expert-spur.md +3 -0
  9. package/plugins/sp/agents/super-planner.md +5 -1
  10. package/plugins/sp/agents/super-reviewer.md +43 -12
  11. package/plugins/sp/commands/dev-find-conflict.md +18 -6
  12. package/plugins/sp/commands/dev-fixall.md +7 -2
  13. package/plugins/sp/commands/dev-idea.md +6 -1
  14. package/plugins/sp/commands/dev-run.md +3 -0
  15. package/plugins/sp/commands/dev-runall.md +6 -3
  16. package/plugins/sp/commands/dev-verify.md +1 -1
  17. package/plugins/sp/plugin.json +1 -1
  18. package/plugins/sp/skills/code-implementation/SKILL.md +8 -8
  19. package/plugins/sp/skills/code-improvement/SKILL.md +3 -3
  20. package/plugins/sp/skills/code-review/references/verification-before-completion.md +5 -4
  21. package/plugins/sp/skills/code-verification/SKILL.md +4 -4
  22. package/plugins/sp/skills/code-verification/references/verdict-schema.md +27 -11
  23. package/plugins/sp/skills/conflict-finding/SKILL.md +46 -16
  24. package/plugins/sp/skills/conflict-finding/references/comparison-protocol.md +4 -2
  25. package/plugins/sp/skills/conflict-finding/references/finding-contract.md +2 -2
  26. package/plugins/sp/skills/conflict-finding/references/remediation-routing.md +22 -3
  27. package/plugins/sp/skills/fleet-join/SKILL.md +2 -0
  28. package/plugins/sp/skills/functional-review/SKILL.md +1 -1
  29. package/plugins/sp/skills/functional-review/references/verdict-schema.md +1 -1
  30. package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
  31. package/plugins/sp/skills/spur-check/SKILL.md +1 -1
  32. package/plugins/sp/skills/spur-cli/SKILL.md +23 -2
  33. package/plugins/sp/skills/spur-cli/references/agent.md +12 -0
  34. package/plugins/sp/skills/spur-cli/references/decision/lifecycle.md +166 -0
  35. package/plugins/sp/skills/spur-cli/references/decision.md +146 -16
  36. package/plugins/sp/skills/spur-cli/references/features.md +12 -0
  37. package/plugins/sp/skills/spur-cli/references/rules.md +2 -0
  38. package/plugins/sp/skills/spur-cli/references/tasks.md +13 -0
  39. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +1 -1
  40. package/plugins/sp/skills/spur-cli/references/workflows/workflow-fit-and-tuning.md +3 -2
  41. package/plugins/sp/skills/spur-cli/references/workflows.md +9 -0
  42. package/plugins/sp/skills/spur-composer/SKILL.md +20 -1
  43. package/plugins/sp/skills/spur-dev/SKILL.md +16 -16
  44. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +5 -4
  45. package/plugins/sp/skills/spur-dev/references/decision-points.md +97 -0
  46. package/plugins/sp/skills/spur-dev/references/dev-operations.md +9 -9
  47. package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +1 -1
  48. package/plugins/sp/skills/spur-dev/references/execution-batch.md +13 -3
  49. package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +4 -4
  50. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +41 -29
  51. package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +33 -0
  52. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +11 -10
  53. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +3 -2
  54. package/plugins/sp/skills/spur-dev/references/glossary.md +12 -3
  55. package/plugins/sp/skills/spur-doctor/SKILL.md +23 -0
  56. package/spur.js +7378 -6052
  57. package/web/_astro/{BoardApp.Bjdp3XWV.js → BoardApp.CC7Mwswv.js} +65 -65
  58. package/web/_astro/{BoardApp.DCDZxLlQ.js → BoardApp.mWyrWCAR.js} +1 -1
  59. package/web/_astro/{TaskDetail.B3vBxynO.js → TaskDetail.CtAXuiv8.js} +1 -1
  60. package/web/_astro/{arc.DcuHTB_T.js → arc.Duf4u60i.js} +1 -1
  61. package/web/_astro/{architectureDiagram-3BPJPVTR.ClOFWBON.js → architectureDiagram-3BPJPVTR.JoymtqxN.js} +1 -1
  62. package/web/_astro/{blockDiagram-GPEHLZMM.otYyr7Zb.js → blockDiagram-GPEHLZMM.BvmhcioC.js} +1 -1
  63. package/web/_astro/{c4Diagram-AAUBKEIU.BCjpc9LP.js → c4Diagram-AAUBKEIU.CfaWkgoQ.js} +1 -1
  64. package/web/_astro/channel.DtEPXXcH.js +1 -0
  65. package/web/_astro/{chunk-2J33WTMH.D5Wpnpt_.js → chunk-2J33WTMH.B7uR02cD.js} +1 -1
  66. package/web/_astro/{chunk-4BX2VUAB.DkQGtWNz.js → chunk-4BX2VUAB.SwiEauYR.js} +1 -1
  67. package/web/_astro/{chunk-55IACEB6.B7dqjAip.js → chunk-55IACEB6.6ZRCK8PO.js} +1 -1
  68. package/web/_astro/{chunk-727SXJPM.BDQvnKE2.js → chunk-727SXJPM.Cxra_G3N.js} +1 -1
  69. package/web/_astro/{chunk-AQP2D5EJ.D92doBX5.js → chunk-AQP2D5EJ.Cxd7gZeX.js} +1 -1
  70. package/web/_astro/{chunk-FMBD7UC4.C968oI5G.js → chunk-FMBD7UC4.DCLhFkVc.js} +1 -1
  71. package/web/_astro/{chunk-ND2GUHAM.AkkYC1bY.js → chunk-ND2GUHAM.B9AmKcv6.js} +1 -1
  72. package/web/_astro/{chunk-QZHKN3VN.sCc-rKKo.js → chunk-QZHKN3VN.DOjCvl6S.js} +1 -1
  73. package/web/_astro/{classDiagram-4FO5ZUOK.pOQ9u0mY.js → classDiagram-4FO5ZUOK.BMiT_mNf.js} +1 -1
  74. package/web/_astro/{classDiagram-v2-Q7XG4LA2.pOQ9u0mY.js → classDiagram-v2-Q7XG4LA2.BMiT_mNf.js} +1 -1
  75. package/web/_astro/{cose-bilkent-S5V4N54A.CRaeD6FY.js → cose-bilkent-S5V4N54A.mLBCEGjI.js} +1 -1
  76. package/web/_astro/{cynefin-OW5HDTMX.BiCPBu54.js → cynefin-OW5HDTMX.CjDAY0qn.js} +1 -1
  77. package/web/_astro/{dagre-BM42HDAG.C1-q3vkT.js → dagre-BM42HDAG._G_sP8fP.js} +1 -1
  78. package/web/_astro/{diagram-2AECGRRQ.BSVOv30O.js → diagram-2AECGRRQ.39OcfSuz.js} +1 -1
  79. package/web/_astro/{diagram-5GNKFQAL.CHMkjJ-V.js → diagram-5GNKFQAL.D7v_eNC4.js} +1 -1
  80. package/web/_astro/{diagram-KO2AKTUF.CKY9M564.js → diagram-KO2AKTUF.Da1x-lhg.js} +1 -1
  81. package/web/_astro/{diagram-LMA3HP47.B9yNJiTP.js → diagram-LMA3HP47.C8EnzbEb.js} +1 -1
  82. package/web/_astro/{diagram-OG6HWLK6.Dk8AUGsk.js → diagram-OG6HWLK6.DPnBj69F.js} +1 -1
  83. package/web/_astro/{erDiagram-TEJ5UH35.BQHR89TZ.js → erDiagram-TEJ5UH35.CXMu2TIh.js} +1 -1
  84. package/web/_astro/{flowDiagram-I6XJVG4X.oNkWVgoK.js → flowDiagram-I6XJVG4X.ZklePVtQ.js} +1 -1
  85. package/web/_astro/{ganttDiagram-6RSMTGT7.Kz2U2nu9.js → ganttDiagram-6RSMTGT7.BhYOkdqk.js} +1 -1
  86. package/web/_astro/{gitGraphDiagram-PVQCEYII.DHIZ_wPq.js → gitGraphDiagram-PVQCEYII.CADyX8a1.js} +1 -1
  87. package/web/_astro/{infoDiagram-5YYISTIA.D0NJLcv9.js → infoDiagram-5YYISTIA.BsdmwjHt.js} +1 -1
  88. package/web/_astro/{ishikawaDiagram-YF4QCWOH.CFEfTWRG.js → ishikawaDiagram-YF4QCWOH.CzjZ3Crd.js} +1 -1
  89. package/web/_astro/{journeyDiagram-JHISSGLW.Dc7IE7I4.js → journeyDiagram-JHISSGLW.Bxj-ZH_t.js} +1 -1
  90. package/web/_astro/{kanban-definition-UN3LZRKU.D5v0xO9k.js → kanban-definition-UN3LZRKU.Cbg3wVvX.js} +1 -1
  91. package/web/_astro/{linear.wR5KzXnE.js → linear.DJNUrBI9.js} +1 -1
  92. package/web/_astro/{mermaid.core.BDQ2FoPd.js → mermaid.core.DVHQV3SF.js} +4 -4
  93. package/web/_astro/{mindmap-definition-RKZ34NQL.W6_INsia.js → mindmap-definition-RKZ34NQL.DyomosRU.js} +1 -1
  94. package/web/_astro/{pieDiagram-4H26LBE5.61ihbgkK.js → pieDiagram-4H26LBE5.DajtFknN.js} +1 -1
  95. package/web/_astro/{quadrantDiagram-W4KKPZXB.B5lEpFLo.js → quadrantDiagram-W4KKPZXB.Bjq6SjGe.js} +1 -1
  96. package/web/_astro/{requirementDiagram-4Y6WPE33.CmhVBVX0.js → requirementDiagram-4Y6WPE33.ubBVqGLP.js} +1 -1
  97. package/web/_astro/{sankeyDiagram-5OEKKPKP.D7Vvj9Wf.js → sankeyDiagram-5OEKKPKP.I4q46xd-.js} +1 -1
  98. package/web/_astro/{sequenceDiagram-3UESZ5HK.B1vPLixM.js → sequenceDiagram-3UESZ5HK.DsCgZIa8.js} +1 -1
  99. package/web/_astro/{stateDiagram-AJRCARHV.BnACmrGi.js → stateDiagram-AJRCARHV.DcYjYSqT.js} +1 -1
  100. package/web/_astro/{stateDiagram-v2-BHNVJYJU.CW4pnmc3.js → stateDiagram-v2-BHNVJYJU.Dt8yPqiS.js} +1 -1
  101. package/web/_astro/{timeline-definition-PNZ67QCA.CkzMCPnC.js → timeline-definition-PNZ67QCA.0YTkoa5F.js} +1 -1
  102. package/web/_astro/{vennDiagram-CIIHVFJN.CY4aNdAR.js → vennDiagram-CIIHVFJN.BNl0l1hs.js} +1 -1
  103. package/web/_astro/{wardleyDiagram-YWT4CUSO.BtoU9UFk.js → wardleyDiagram-YWT4CUSO.BYSX6cfn.js} +1 -1
  104. package/web/_astro/{xychartDiagram-2RQKCTM6._9ijUUAs.js → xychartDiagram-2RQKCTM6.DzxxpixK.js} +1 -1
  105. package/web/index.html +1 -1
  106. package/worker/laya_worker.py +219 -0
  107. package/web/_astro/channel.qgOLXjI_.js +0 -1
@@ -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.
@@ -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
@@ -219,8 +219,8 @@ or irreversible HITL gates.
219
219
 
220
220
  Scope the operation to all tasks under a feature id (`^[A-Z][1-9]*$`). On feature-advancing
221
221
  commands (`dev-wrapall`) it also advances the feature through legal lifecycle edges with guards
222
- honored. On `dev-review` it takes a comma list (`--feature <id>[,<id>]`) — sugar for the union of
223
- the `feature:<id>` sets, resolved once and frozen.
222
+ honored. On `dev-review` and `dev-find-conflict` it takes a comma list (`--feature <id>[,<id>]`) —
223
+ sugar for the union of the `feature:<id>` sets, resolved once and frozen.
224
224
 
225
225
  ### `--check <cmd>` — validation command for iterate-and-check loops
226
226
 
@@ -250,9 +250,10 @@ all dimensions.
250
250
  **Anchor:** `#flag-scope`.
251
251
 
252
252
  Limit the operation to a file or directory path (`dev-arch`, `dev-debug`, `dev-fixall`,
253
- `dev-gitmsg`, `dev-gtd`, `dev-refactor`, `dev-review`, `dev-simplify`) to bound the working set.
254
- On `dev-review` it takes a comma list of paths — normalized, nested and duplicate paths merged,
255
- one advisory sub-review per surviving path.
253
+ `dev-find-conflict`, `dev-gitmsg`, `dev-gtd`, `dev-refactor`, `dev-review`, `dev-simplify`) to
254
+ bound the working set. On `dev-review` and `dev-find-conflict` it takes a comma list of paths —
255
+ normalized, nested and duplicate paths merged; `dev-review` runs one advisory sub-review per
256
+ surviving path, `dev-find-conflict` seeds one audit with all of them.
256
257
 
257
258
  ### `--all` — widen the operation to everything in its domain
258
259
 
@@ -275,9 +276,9 @@ is the contract; divergence between `--dry-run` and the real run is a bug.
275
276
 
276
277
  **Anchor:** `#flag-tasks`.
277
278
 
278
- Batch operation (`dev-refineall`, `dev-review`, `dev-runall`, `dev-verifyall`). An
279
+ Batch operation (`dev-find-conflict`, `dev-refineall`, `dev-review`, `dev-runall`, `dev-verifyall`). An
279
280
  explicit selector — WBS list, status pseudo-list (`todo`, `wip`), `feature:<id>`, or `ready` —
280
- resolving to the set the batch runs over. On `dev-review` the selector is restricted to the
281
+ resolving to the set the batch runs over. On `dev-review` and `dev-find-conflict` the selector is restricted to the
281
282
  review-safe forms: comma WBS list and `feature:<id>` — status pseudo-lists and `ready` are
282
283
  rejected (they select work to do, not work to review). Required on `dev-runall` and
283
284
  `dev-verifyall`, where `--feature` is an optional restrictor. On `dev-refineall` it is instead
@@ -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.
@@ -58,6 +58,7 @@ record saves the returned table under `docs/reports/`; the doctor creates no art
58
58
  | rule | `spur rule trace --json`, `spur rule validate` |
59
59
  | workflow | `spur workflow validate --json` (findings by `level`), `spur workflow profile <workflow> --json` |
60
60
  | agent spec | `spur agent list --specs --json` |
61
+ | decision | `spur decision status --json`, `spur decision status --reliability --json`, `spur decision show <id> --json` |
61
62
  | history | A `sp:history-anatomy` report ([../history-anatomy/SKILL.md](../history-anatomy/SKILL.md)), never raw history records |
62
63
  | plan/design Markdown | The file itself, the project constitution, the relevant spur-dev template, and inbound index/links; no new CLI needed |
63
64
 
@@ -135,6 +136,28 @@ optimization**, and the change comes from the §10 table:
135
136
  - A proposal that changes a shared workflow goes through §7 of the composition ladder
136
137
  ([spur-composer](../spur-composer/SKILL.md)), including its recorded operator consent.
137
138
 
139
+ ## Decision flags
140
+
141
+ Decision evidence is `spur decision status --json` (catalog and per-maker readiness) and
142
+ `spur decision status --reliability [--since <iso>] --json` (per decision × maker). Each flag is a
143
+ predicate over those fields, so compute it with `jq` and never estimate from prose. Each flag becomes
144
+ one row with action class **workflow optimization**. A catalog or config change routes through
145
+ `sp:spur-composer` and the decision lifecycle
146
+ ([decision/lifecycle.md](../spur-cli/references/decision/lifecycle.md)).
147
+
148
+ | Evidence | Flag | Proposed change |
149
+ | --- | --- | --- |
150
+ | `status`: `loadErrors[]` or `duplicateIds[]` non-empty | `catalog-error` | Fix the named catalog file; a layer collision is renamed, not suppressed |
151
+ | `status` `makers[]`: `evidence.recorded > 0` and `evidence.accepted == 0` | `maker-never-accepted` | Re-point `decisions.makers.<id>` for the decisions in `serves`, after `--probe` confirms the maker answers |
152
+ | `status` `makers[]`: `configuredBy` non-empty and `evidence.recorded == 0` | `maker-unrecorded` | Run `spur decision status --probe`; propose only when the probe fails |
153
+ | `--reliability` `groups[]`: `samples >= 10` and `acceptedRate < 0.5` | `low-accept-rate` | Read the dominant `fallbacks` reason: `low-confidence` → tune criteria or `minConfidence`, or change the maker; `no-backend` / errors → maker config; invalid answers → the criteria vocabulary |
154
+ | A workflow step's shell command (not a YAML comment) runs `spur decision run` — read it from `spur workflow show <workflow> --json` | `shell-decision-run` | Convert to a typed `decide` step plus a projection. The shell call ignores both workflow switches |
155
+
156
+ - `samples < 10` is not evidence: the row says so instead of raising `low-accept-rate`.
157
+ - A run's rows under `.spur/run/*.decision` explain one route; the reliability report is the only
158
+ rate evidence. Never compute a rate from row files.
159
+ - A decision whose `source: default` rows are expected (switch off, `reason: disabled`) is a no-op.
160
+
138
161
  ## Reflection map over history findings
139
162
 
140
163
  For each history-anatomy finding (`key`, `category`, `trend`, `ownerSurface`), assign **exactly