@gobing-ai/spur 0.4.15 → 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 (101) 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 +1 -1
  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-fixall.md +7 -2
  12. package/plugins/sp/commands/dev-idea.md +6 -1
  13. package/plugins/sp/commands/dev-run.md +3 -0
  14. package/plugins/sp/commands/dev-runall.md +6 -3
  15. package/plugins/sp/commands/dev-verify.md +1 -1
  16. package/plugins/sp/plugin.json +1 -1
  17. package/plugins/sp/skills/code-implementation/SKILL.md +8 -8
  18. package/plugins/sp/skills/code-improvement/SKILL.md +3 -3
  19. package/plugins/sp/skills/code-review/references/verification-before-completion.md +5 -4
  20. package/plugins/sp/skills/code-verification/SKILL.md +4 -4
  21. package/plugins/sp/skills/code-verification/references/verdict-schema.md +27 -11
  22. package/plugins/sp/skills/functional-review/SKILL.md +1 -1
  23. package/plugins/sp/skills/functional-review/references/verdict-schema.md +1 -1
  24. package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
  25. package/plugins/sp/skills/spur-check/SKILL.md +1 -1
  26. package/plugins/sp/skills/spur-cli/SKILL.md +23 -2
  27. package/plugins/sp/skills/spur-cli/references/agent.md +12 -0
  28. package/plugins/sp/skills/spur-cli/references/decision/lifecycle.md +166 -0
  29. package/plugins/sp/skills/spur-cli/references/decision.md +146 -16
  30. package/plugins/sp/skills/spur-cli/references/features.md +12 -0
  31. package/plugins/sp/skills/spur-cli/references/rules.md +2 -0
  32. package/plugins/sp/skills/spur-cli/references/tasks.md +13 -0
  33. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +1 -1
  34. package/plugins/sp/skills/spur-cli/references/workflows/workflow-fit-and-tuning.md +3 -2
  35. package/plugins/sp/skills/spur-cli/references/workflows.md +9 -0
  36. package/plugins/sp/skills/spur-composer/SKILL.md +20 -1
  37. package/plugins/sp/skills/spur-dev/SKILL.md +16 -16
  38. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +2 -2
  39. package/plugins/sp/skills/spur-dev/references/decision-points.md +97 -0
  40. package/plugins/sp/skills/spur-dev/references/dev-operations.md +8 -8
  41. package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +1 -1
  42. package/plugins/sp/skills/spur-dev/references/execution-batch.md +13 -3
  43. package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +4 -4
  44. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +41 -29
  45. package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +33 -0
  46. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +3 -3
  47. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +3 -2
  48. package/plugins/sp/skills/spur-dev/references/glossary.md +12 -3
  49. package/plugins/sp/skills/spur-doctor/SKILL.md +23 -0
  50. package/spur.js +7378 -6052
  51. package/web/_astro/{BoardApp.Bjdp3XWV.js → BoardApp.CC7Mwswv.js} +65 -65
  52. package/web/_astro/{BoardApp.DCDZxLlQ.js → BoardApp.mWyrWCAR.js} +1 -1
  53. package/web/_astro/{TaskDetail.B3vBxynO.js → TaskDetail.CtAXuiv8.js} +1 -1
  54. package/web/_astro/{arc.DcuHTB_T.js → arc.Duf4u60i.js} +1 -1
  55. package/web/_astro/{architectureDiagram-3BPJPVTR.ClOFWBON.js → architectureDiagram-3BPJPVTR.JoymtqxN.js} +1 -1
  56. package/web/_astro/{blockDiagram-GPEHLZMM.otYyr7Zb.js → blockDiagram-GPEHLZMM.BvmhcioC.js} +1 -1
  57. package/web/_astro/{c4Diagram-AAUBKEIU.BCjpc9LP.js → c4Diagram-AAUBKEIU.CfaWkgoQ.js} +1 -1
  58. package/web/_astro/channel.DtEPXXcH.js +1 -0
  59. package/web/_astro/{chunk-2J33WTMH.D5Wpnpt_.js → chunk-2J33WTMH.B7uR02cD.js} +1 -1
  60. package/web/_astro/{chunk-4BX2VUAB.DkQGtWNz.js → chunk-4BX2VUAB.SwiEauYR.js} +1 -1
  61. package/web/_astro/{chunk-55IACEB6.B7dqjAip.js → chunk-55IACEB6.6ZRCK8PO.js} +1 -1
  62. package/web/_astro/{chunk-727SXJPM.BDQvnKE2.js → chunk-727SXJPM.Cxra_G3N.js} +1 -1
  63. package/web/_astro/{chunk-AQP2D5EJ.D92doBX5.js → chunk-AQP2D5EJ.Cxd7gZeX.js} +1 -1
  64. package/web/_astro/{chunk-FMBD7UC4.C968oI5G.js → chunk-FMBD7UC4.DCLhFkVc.js} +1 -1
  65. package/web/_astro/{chunk-ND2GUHAM.AkkYC1bY.js → chunk-ND2GUHAM.B9AmKcv6.js} +1 -1
  66. package/web/_astro/{chunk-QZHKN3VN.sCc-rKKo.js → chunk-QZHKN3VN.DOjCvl6S.js} +1 -1
  67. package/web/_astro/{classDiagram-4FO5ZUOK.pOQ9u0mY.js → classDiagram-4FO5ZUOK.BMiT_mNf.js} +1 -1
  68. package/web/_astro/{classDiagram-v2-Q7XG4LA2.pOQ9u0mY.js → classDiagram-v2-Q7XG4LA2.BMiT_mNf.js} +1 -1
  69. package/web/_astro/{cose-bilkent-S5V4N54A.CRaeD6FY.js → cose-bilkent-S5V4N54A.mLBCEGjI.js} +1 -1
  70. package/web/_astro/{cynefin-OW5HDTMX.BiCPBu54.js → cynefin-OW5HDTMX.CjDAY0qn.js} +1 -1
  71. package/web/_astro/{dagre-BM42HDAG.C1-q3vkT.js → dagre-BM42HDAG._G_sP8fP.js} +1 -1
  72. package/web/_astro/{diagram-2AECGRRQ.BSVOv30O.js → diagram-2AECGRRQ.39OcfSuz.js} +1 -1
  73. package/web/_astro/{diagram-5GNKFQAL.CHMkjJ-V.js → diagram-5GNKFQAL.D7v_eNC4.js} +1 -1
  74. package/web/_astro/{diagram-KO2AKTUF.CKY9M564.js → diagram-KO2AKTUF.Da1x-lhg.js} +1 -1
  75. package/web/_astro/{diagram-LMA3HP47.B9yNJiTP.js → diagram-LMA3HP47.C8EnzbEb.js} +1 -1
  76. package/web/_astro/{diagram-OG6HWLK6.Dk8AUGsk.js → diagram-OG6HWLK6.DPnBj69F.js} +1 -1
  77. package/web/_astro/{erDiagram-TEJ5UH35.BQHR89TZ.js → erDiagram-TEJ5UH35.CXMu2TIh.js} +1 -1
  78. package/web/_astro/{flowDiagram-I6XJVG4X.oNkWVgoK.js → flowDiagram-I6XJVG4X.ZklePVtQ.js} +1 -1
  79. package/web/_astro/{ganttDiagram-6RSMTGT7.Kz2U2nu9.js → ganttDiagram-6RSMTGT7.BhYOkdqk.js} +1 -1
  80. package/web/_astro/{gitGraphDiagram-PVQCEYII.DHIZ_wPq.js → gitGraphDiagram-PVQCEYII.CADyX8a1.js} +1 -1
  81. package/web/_astro/{infoDiagram-5YYISTIA.D0NJLcv9.js → infoDiagram-5YYISTIA.BsdmwjHt.js} +1 -1
  82. package/web/_astro/{ishikawaDiagram-YF4QCWOH.CFEfTWRG.js → ishikawaDiagram-YF4QCWOH.CzjZ3Crd.js} +1 -1
  83. package/web/_astro/{journeyDiagram-JHISSGLW.Dc7IE7I4.js → journeyDiagram-JHISSGLW.Bxj-ZH_t.js} +1 -1
  84. package/web/_astro/{kanban-definition-UN3LZRKU.D5v0xO9k.js → kanban-definition-UN3LZRKU.Cbg3wVvX.js} +1 -1
  85. package/web/_astro/{linear.wR5KzXnE.js → linear.DJNUrBI9.js} +1 -1
  86. package/web/_astro/{mermaid.core.BDQ2FoPd.js → mermaid.core.DVHQV3SF.js} +4 -4
  87. package/web/_astro/{mindmap-definition-RKZ34NQL.W6_INsia.js → mindmap-definition-RKZ34NQL.DyomosRU.js} +1 -1
  88. package/web/_astro/{pieDiagram-4H26LBE5.61ihbgkK.js → pieDiagram-4H26LBE5.DajtFknN.js} +1 -1
  89. package/web/_astro/{quadrantDiagram-W4KKPZXB.B5lEpFLo.js → quadrantDiagram-W4KKPZXB.Bjq6SjGe.js} +1 -1
  90. package/web/_astro/{requirementDiagram-4Y6WPE33.CmhVBVX0.js → requirementDiagram-4Y6WPE33.ubBVqGLP.js} +1 -1
  91. package/web/_astro/{sankeyDiagram-5OEKKPKP.D7Vvj9Wf.js → sankeyDiagram-5OEKKPKP.I4q46xd-.js} +1 -1
  92. package/web/_astro/{sequenceDiagram-3UESZ5HK.B1vPLixM.js → sequenceDiagram-3UESZ5HK.DsCgZIa8.js} +1 -1
  93. package/web/_astro/{stateDiagram-AJRCARHV.BnACmrGi.js → stateDiagram-AJRCARHV.DcYjYSqT.js} +1 -1
  94. package/web/_astro/{stateDiagram-v2-BHNVJYJU.CW4pnmc3.js → stateDiagram-v2-BHNVJYJU.Dt8yPqiS.js} +1 -1
  95. package/web/_astro/{timeline-definition-PNZ67QCA.CkzMCPnC.js → timeline-definition-PNZ67QCA.0YTkoa5F.js} +1 -1
  96. package/web/_astro/{vennDiagram-CIIHVFJN.CY4aNdAR.js → vennDiagram-CIIHVFJN.BNl0l1hs.js} +1 -1
  97. package/web/_astro/{wardleyDiagram-YWT4CUSO.BtoU9UFk.js → wardleyDiagram-YWT4CUSO.BYSX6cfn.js} +1 -1
  98. package/web/_astro/{xychartDiagram-2RQKCTM6._9ijUUAs.js → xychartDiagram-2RQKCTM6.DzxxpixK.js} +1 -1
  99. package/web/index.html +1 -1
  100. package/worker/laya_worker.py +219 -0
  101. package/web/_astro/channel.qgOLXjI_.js +0 -1
@@ -27,12 +27,17 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
27
27
 
28
28
  ## Implementation
29
29
 
30
- Follow the inline procedure in [dev-operations.md](../skills/spur-dev/references/dev-operations.md#10-fixall) (fixall). Pipeline signal: when `--gate-log` is set (the `test-fix` hop), run no full gate — the `test-recheck` state immediately after is the deciding run (R4, task 0483).
30
+ Follow the inline procedure in [dev-operations.md](../skills/spur-dev/references/dev-operations.md#10-fixall) (fixall). Pipeline signal: when `--gate-log` is set (the `remediate` hop), run no full gate — the `gate` state's recheck immediately after is the deciding run (R4, task 0483).
31
31
 
32
- When dispatched from the pipeline's test-fix stage (F96, task 0950), the gate log carries a
32
+ When dispatched from the pipeline's `remediate` hop (F96, task 0950), the gate log carries a
33
33
  `residual artifact` block (`<wbs>-residuals.json`) and the findings file already
34
34
  contains the merged residual anchors: treat those items as fix targets, in order,
35
35
  alongside gate anchors. The fixer may write `.spur/run/<wbs>-residual-deferrals.json`
36
36
  — one `{id, reason}` entry per item — but only for P3 findings or diff markers it
37
37
  cannot fix inside the task; the done stage settles deferrals into follow-up tasks.
38
38
 
39
+ The `remediate` hop is entered only after a `fix` decision (`failure-class` on a red gate,
40
+ `review-failure-class` on a non-PASS review). A `stop` decision ends the run before this command
41
+ runs, so do not invoke it by hand to overrule a `stop`
42
+ ([decision points](../skills/spur-dev/references/decision-points.md)).
43
+
@@ -44,7 +44,7 @@ trace records the answering source. `--auto` takes the recommended option at eac
44
44
 
45
45
  | Gate | Pauses when | Recommendation comes from | `--auto` takes |
46
46
  | --- | --- | --- | --- |
47
- | idea-eval | after discovery | eval report `## Recommendation` (`proceed` / `reshape` / `drop`) | `proceed`/`reshape` → continue; `drop` → cancel; missing → still asks |
47
+ | idea-eval | after discovery | eval report `## Recommendation` (`proceed` / `reshape` / `drop`); when unparseable, a model answer from the `idea-recommendation` decision | `proceed`/`reshape` → continue; `drop` → cancel; neither → the gate asks, and under `--auto` its `gate-evidence` decision answers (a deferred answer denies) |
48
48
  | design-approval | after system-design (skipped by `--skip-design`) | recorded design check | PASS → approve; FAIL → still asks |
49
49
 
50
50
  The AC check and the batch create are deterministic pipeline steps, not gates: `ac-generate`
@@ -52,6 +52,11 @@ runs `spur feature check` and routes on the recorded result (a FAIL retries the
52
52
  and `batch-create-run` runs `spur task batch-create` and routes on its own recorded result.
53
53
  Neither ever pauses, under any profile.
54
54
 
55
+ The rescue decisions and the gate answers are catalog decision points; their rows and switches
56
+ are in [decision points](../skills/spur-dev/references/decision-points.md). With both switches off
57
+ (the default) no model is called and a `--auto` run with no parseable recommendation stops at
58
+ idea-eval as a denial rather than creating a feature.
59
+
55
60
  Flag → vars: `--auto` sets `profile=auto`, `idea_approved=true`, `design_approved=true`;
56
61
  `--skip-design` sets `design=skip`.
57
62
 
@@ -50,6 +50,9 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
50
50
  - Implement step only (`--mode implement`): `Skill(skill="sp:code-implementation", args="$ARGUMENTS")`
51
51
  - After a full-mode run settles (done, failed or paused), print the
52
52
  [execution summary](../skills/spur-dev/references/dev-operations.md#execution-summary) unless `--no-summary`.
53
+ - Then report the run's decision points (triage lane, failure classes, approval) from their rows
54
+ ([reporting a run](../skills/spur-dev/references/decision-points.md#reporting-a-run)). A `failed` or `remediate` route is explained by the row
55
+ that chose it; quote its value, source and reason, never a fresh judgment.
53
56
 
54
57
  **Flags:**
55
58
 
@@ -26,7 +26,7 @@ Wraps the **sp:spur-dev** skill.
26
26
  | `--worktree` `[<name>]` | Run the batch in an isolated git worktree; FF-merge on success, retain on failure. Bare `--worktree` creates a fresh tree; `--worktree <name>` adopts an existing worktree by name/path/branch. | off |
27
27
  | `--no-summary` | Skip the measured execution summary (one row per task run: time, wait, tool calls, total / non-cached tokens) printed after the batch report. | off (summary printed) |
28
28
  | `--concurrency` `<n>` | Parallel-mode worker bound: at most `<n>` task pipelines run at once (task 0931); a dependent starts only after its in-set dependencies are integrated onto the base ref. No-op in sequential mode (ignored). | 2 |
29
- | `--defer-gate` | Opt-in parallel-batch gate policy (task 1111): each task's `test` hop runs the light tier and writes `DEFERRED`; the batch runs one integrated full gate on the base ref before the feature sync. Requires `--mode parallel`, or `--mode auto` resolved to parallel (dropped with a note otherwise); default off. | off |
29
+ | `--defer-gate` | Opt-in parallel-batch gate policy (task 1111): each task's `gate` state runs the light tier and writes `DEFERRED`; the batch runs one integrated full gate on the base ref before the feature sync. Requires `--mode parallel`, or `--mode auto` resolved to parallel (dropped with a note otherwise); default off. | off |
30
30
 
31
31
  For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag-glossary.md).
32
32
 
@@ -82,8 +82,8 @@ FF-merge on success. This is expected, not a bug.
82
82
 
83
83
  **`--next` (batch-once wrap).** `--next`
84
84
  is chain-to-completion with propagation. On `dev-runall`, each task in the batch runs its
85
- `task-pipeline.yaml` to terminal status (the pipeline already drives precheck → implement → test →
86
- review → approve → verify → record → done); when the batch is complete, the wrap hop runs **once
85
+ `task-pipeline.yaml` to terminal status (the pipeline already drives precheck → implement → gate ⇄ remediate →
86
+ review → done); when the batch is complete, the wrap hop runs **once
87
87
  for the batch** — mirroring the batch-once shippable gate `dev-verifyall` uses — rather than once
88
88
  per task. Without `--next`, `--wrap` is wrap-without-chaining (the single batch wraps without
89
89
  advancing the feature lifecycle). **was: `--next` deliberately omitted; the old no-`--next` rationale argued against the old per-task-transition meaning and does not carry.**
@@ -111,3 +111,6 @@ full distinction.
111
111
  - Explicit executor (any mode, including `auto`) or parallel mode: `Skill(skill="sp:spur-dev", args="runall $ARGUMENTS")` → `sp:super-planner` agent.
112
112
  - After the batch report, print the [execution summary](../skills/spur-dev/references/dev-operations.md#execution-summary) over every attempted run unless
113
113
  `--no-summary`.
114
+ - A failed task's report row names the decision row that ended it (`failure-class` or
115
+ `review-failure-class` = `stop`, or approval `DENIED`) per
116
+ [reporting a run](../skills/spur-dev/references/decision-points.md#reporting-a-run); the batch failure policy then applies unchanged.
@@ -45,7 +45,7 @@ See `sp:code-verification` § Shippable readiness gate.
45
45
  run `spur task residual <wbs> scan` + `fold` (observe-only; folds the verdict's `residual-sweep` check,
46
46
  PASS → PARTIAL when a blocking residual exists) — under every `--fix` mode — then, only on a
47
47
  downgrade, re-run `spur task record <wbs> --verdict-file .spur/run/<wbs>-verdict.json` so Testing
48
- carries the final verdict. Same order as the pipeline `record` state (0983): scanning before
48
+ carries the final verdict. Same order as the pipeline `done` state's record close (0983): scanning before
49
49
  record reads unticked-but-proven boxes and folds a clean PASS to PARTIAL. When the task reaches
50
50
  `done` through `--next`, run `spur task residual <wbs> settle` (best-effort). On a folded PARTIAL: the bounded remediation loop has
51
51
  already run — a residual-failed task is routed to router C6 (HITL STOP), never another
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "sp",
3
- "version": "0.4.15",
3
+ "version": "0.4.16",
4
4
  "description": "Spur — a local-first harness engineering toolkit that wraps mainstream coding agents with constraint checking, workflow orchestration, and history analytics."
5
5
  }
@@ -103,7 +103,7 @@ surfaces is what keeps that gate quiet.
103
103
 
104
104
  ## Implement scope: do not run the project quality gate
105
105
 
106
- During implement, the pipeline's `test` hop runs `${vars.qualityGateCmd}` (the full project gate:
106
+ During implement, the pipeline's `gate` state runs `${vars.qualityGateCmd}` (the full project gate:
107
107
  `spur self exec check`) immediately after this step and is the gate that actually
108
108
  decides pass/fail. Running it inside implement is pure redundancy — it cannot change the outcome and
109
109
  only burns wall clock and context budget.
@@ -118,9 +118,9 @@ only burns wall clock and context budget.
118
118
  re-select the execution tree inside the call (`cd -- "$TREE"` plus the identity check) instead of
119
119
  relying on a `cd` a previous call left behind.
120
120
  - **NEVER run** `spur self exec test`, `spur self exec check`, `bun run check`, or any other full-suite /
121
- project-gate command from inside implement. These belong to the pipeline's `test` hop.
121
+ project-gate command from inside implement. These belong to the pipeline's `gate` state.
122
122
  - **Full-suite budget: at most 2 per task** (task 0436 R2) — counted across the whole task run
123
- (implement probes + the pipeline `test` hop + verify/recheck), not per step. When a check fails,
123
+ (implement probes + the pipeline `gate` state and its rechecks), not per step. When a check fails,
124
124
  run the narrow target (`bun test <file> --test-name-pattern <test>`) to green before any full
125
125
  suite; reach for the second full run only when the narrow target cannot reproduce the failure.
126
126
  - **Consolidate dogfood runs**: one combined real-data execution that exercises all scenarios,
@@ -128,7 +128,7 @@ only burns wall clock and context budget.
128
128
  rerunning the same dogfood command with one flag changed, stop and fold the variants into a
129
129
  single run — repeated identical commands are loop-detector findings and pure cost.
130
130
  - If a targeted probe reveals a failure you cannot fix within implement scope, note it in
131
- `## Solution` and let the `test` hop's fixall handle it — do not pre-empt the gate.
131
+ `## Solution` and let the `gate` state's `remediate` hop handle it — do not pre-empt the gate.
132
132
 
133
133
  ### Public-surface probe (task 1135 R1/R6/R8)
134
134
 
@@ -155,7 +155,7 @@ changed no public surface, report the single line
155
155
  - the paired-script parity test when `package.json` changed (a half-updated `spur-check` /
156
156
  `spur-check:full` chain).
157
157
 
158
- The single full project check stays the pipeline `test` hop's job (see the section above); these are
158
+ The single full project check stays the pipeline `gate` state's job (see the section above); these are
159
159
  changed-path checks, not that gate.
160
160
 
161
161
  ## Changed-path targeted checks (dependency-aware verification, task 0510 R3 / task 1142 R3)
@@ -164,14 +164,14 @@ changed-path checks, not that gate.
164
164
  surface can break a downstream consumer. The matrix below is dependency-aware — domain → app →
165
165
  CLI — so a shared change verifies its consumers without recreating the full project check inside
166
166
  implement. **It augments narrow behavior tests; it never authorizes `spur self exec check`,
167
- `spur self exec test`, or another full project check inside implement** — the pipeline's `test` hop owns
167
+ `spur self exec test`, or another full project check inside implement** — the pipeline's `gate` state owns
168
168
  that single full gate.
169
169
 
170
170
  **Worker iteration check order (task 1142 R3):**
171
171
  1. The **changed-path matrix** below (narrow behavior tests + affected consumers);
172
172
  2. `spur task gate <wbs> light` (biome on changed files, per-workspace typecheck, rule presets `rules:pre`/`rules:post`, related tests).
173
173
 
174
- Neither step takes the full project gate. The full gate is named only for the pipeline's `test` and `test-recheck` hops.
174
+ Neither step takes the full project gate. The full gate is named only for the pipeline's `gate` state (first visit and rechecks).
175
175
 
176
176
  | Changed surface | Required targeted tests | Required typechecks |
177
177
  | --- | --- | --- |
@@ -189,7 +189,7 @@ Neither step takes the full project gate. The full gate is named only for the pi
189
189
  (a flag the plugin layer consumes) actually changes, so an unconditional parity suite does not
190
190
  creep into every plugin edit.
191
191
  - Run the applicable rows, then stop: the single full project check belongs to the pipeline's
192
- `test` hop (`task-pipeline.yaml` `${vars.qualityGateCmd}`).
192
+ `gate` state (`task-pipeline.yaml` `${vars.qualityGateCmd}`).
193
193
  - **Mirrored surfaces: an edit lands on all of them.** When the change is one instance of a repeated
194
194
  pattern — the same wiring rule on two runbooks, a signature in both a generator and its generated
195
195
  `.d.mts`, a command chain in both `spur-check` and `spur-check:full` — grep for the siblings and
@@ -89,8 +89,8 @@ and the deepening direction. Full definitions and examples in
89
89
  | **minor** | advisory | Local friction: a module slightly too shallow, coupling that's awkward but not coordinated. |
90
90
  | **advisory** | advisory | Deepening opportunity: the code works and is testable, but would be cleaner with a deeper module. Always non-blocking. |
91
91
 
92
- **Under the pipeline** (`/sp:dev-review` in a task run), `blocker` and `major` block the
93
- `approve(HITL)` gate. `minor` and `advisory` are recorded but do not block. **Standalone** reviews
92
+ **Under the pipeline** (`/sp:dev-review` in a task run), `blocker` and `major` block review
93
+ certification (a non-PASS review goes to the `review-failure-class` decision). `minor` and `advisory` are recorded but do not block. **Standalone** reviews
94
94
  are advisory-only — the operator decides what to act on.
95
95
 
96
96
  ---
@@ -185,7 +185,7 @@ Each candidate is a structured finding:
185
185
  When invoked as the `--focus architecture` dimension of `/sp:dev-review`:
186
186
 
187
187
  - The scope is the task's diff (pipeline) or the `path` arg (standalone).
188
- - `blocker`/`major` candidates block the `approve(HITL)` gate alongside any SECUA blockers from
188
+ - `blocker`/`major` candidates block review certification alongside any SECUA blockers from
189
189
  `sp:code-verification`.
190
190
  - The candidate list is returned as a **review fragment**; the review coordinator
191
191
  (`sp:super-reviewer` — the invoking session under `/sp:dev-review`) merges it into the combined
@@ -42,10 +42,11 @@ Before reporting a task as complete, a test as passing, a bug as fixed, or a fea
42
42
 
43
43
  ## Under the pipeline
44
44
 
45
- `task-pipeline.yaml`'s `verify` step (Phase 8) and `record` step enforce this gate. The `verify`
46
- step runs `sp:code-verification` verify mode, which produces a `VerifyVerdict` artifact; the
47
- `record` step transcribes it to the task's `## Testing` section. A `done` transition requires a
48
- PASS verdict.
45
+ `task-pipeline.yaml` enforces this gate deterministically. The `gate` state runs `spur task gate`
46
+ and a red result goes through the `failure-class` decision to `remediate`; the `review` state
47
+ certifies the review answer with `spur task verdict`, which writes the `VerifyVerdict` artifact.
48
+ `review → done` requires that PASS plus the approval decision point, and `done`'s `spur task record`
49
+ close transcribes the verdict to the task's `## Testing` section.
49
50
 
50
51
  Under manual execution (no pipeline), the agent must still run the gates and paste the evidence.
51
52
  "Manual" is not an exemption — it just means the agent, not the pipeline, runs the commands.
@@ -29,7 +29,7 @@ The **verifier** in the Spur execution loop. A coding agent reports "done" with
29
29
  this skill is the deterministic counterweight that proves — or disproves — the claim against the
30
30
  task's own requirements and Acceptance Criteria, then emits the canonical verdict artifact
31
31
  through CLI verbs (section writes are owned by the review coordinator and the deterministic
32
- `record` step — F92 0593 R1).
32
+ `spur task record` close in `done` — F92 0593 R1).
33
33
 
34
34
  It backs two commands:
35
35
 
@@ -321,7 +321,7 @@ spur task residual <wbs> fold
321
321
  > **Do not write `## Review` directly, ever.** The `## Review` section is owned by the
322
322
  > `review` coordinator (`/sp:dev-review` → `sp:super-reviewer`), which merges
323
323
  > `functional-review` + `code-verification` review mode + `code-improvement` fragments. The
324
- > `record` step backfills `## Review` from the verdict artifact **only** if the section is bare
324
+ > `spur task record` close backfills `## Review` from the verdict artifact **only** if the section is bare
325
325
  > (`sectionIsBare` guard, `task-section-bodies.ts`) — a standalone compatibility fallback, never an
326
326
  > overwrite of authored Review. Writing `## Review` here destroys the review step's
327
327
  > three-dimensional findings.
@@ -546,7 +546,7 @@ Flags: `--agent <inline|auto|name>` (execution surface — inline default, with
546
546
 
547
547
  ## When to use
548
548
 
549
- - **Verify a task before `done`** — the pipeline's `verify` step, or a manual `/sp:dev-verify`.
549
+ - **Verify a task before `done`** — the pipeline's `review` state certifies it (`spur task verdict`), or a manual `/sp:dev-verify`.
550
550
  - **Audit completed work** — `--force` re-verifies a `done` task (compliance, post-merge).
551
551
  - **Focused code review** — `/sp:dev-review` for SECUA findings on a diff.
552
552
 
@@ -581,7 +581,7 @@ Do **not** use this skill for:
581
581
  rubric.
582
582
  - `plugins/sp/references/roles.md` — the Layer-1 role→tier table; this skill's verify/review modes
583
583
  run under the `reviewer` role (0538 R4: this file points at roles.md, it does not restate tiers).
584
- - `task-pipeline.yaml` — the `verify → record` gate that consumes the verdict.
584
+ - `task-pipeline.yaml` — the `review → done` gate that consumes the verdict.
585
585
  - **`sp:spur-dev`** — the execution-half umbrella that drives the pipeline this skill gates.
586
586
  - [references/code-improvement.md](references/code-improvement.md) — architecture-improvement lens
587
587
  for module depth, seam placement, locality, coupling, and testability.
@@ -64,6 +64,14 @@ no level (ADR-131, 1196), no operator `ackLowConfidence`-style var exists, and h
64
64
  findings carry no per-finding grade. A verifier that can write a PASS can still write a wrong
65
65
  `HIGH` — which is exactly why the gate derives the level instead of trusting it.
66
66
 
67
+ **A review run carries two answer artifacts, one `Confidence:` line each (1254).** The `## Review`
68
+ section states the disposition-derived level (`deriveReviewConfidence`); the captured answer handed
69
+ to `spur task verdict --from-answer` states the evidence-derived level (`deriveVerifyConfidence`)
70
+ under the table above and carries exactly one `Confidence:` line. The two legitimately disagree — a
71
+ PASS with executable AC and one carried P4 is section `MEDIUM`, answer `HIGH` — so the captured
72
+ answer must not repeat the section's line (`confidence-duplicate` rejects the whole answer). The
73
+ review stage's prompt owns that instruction; this schema owns the shape it must produce.
74
+
67
75
  ## Compatibility alias: `scenario` row key
68
76
 
69
77
  Task 0410 hardened the verdict reader. Producers SHOULD use the canonical `id` field for every
@@ -241,25 +249,33 @@ Wave C verification can emit the following additive `checks[]` rows:
241
249
 
242
250
  ## How the gate reads it
243
251
 
244
- `task-pipeline.yaml`, transition `verify → record`:
252
+ In `task-pipeline.yaml` the `review` state writes this artifact: `spur task verdict <wbs>
253
+ --from-answer` lints the review answer and derives `.spur/run/<wbs>-verdict.json`. A fold step then
254
+ writes `.spur/run/<wbs>-review.status` = PASS only when the typed verdict is PASS, the artifact's own
255
+ `verdict` is PASS (`jq -r '.verdict // empty'`) and `spur task residual <wbs> review-gate` is clean.
256
+ The `review → done` guard reads that status **and** the approval decision point's token:
245
257
 
246
258
  ```yaml
247
259
  guard:
248
260
  kind: shell
249
261
  options:
250
- command: 'test "$(jq -r .verdict .spur/run/${vars.wbs}-verdict.json)" = PASS'
262
+ command: >-
263
+ test "$(cat ".spur/run/$wbs-review.status" 2>/dev/null)" = PASS &&
264
+ test "$(cat ".spur/run/$wbs-approval.status" 2>/dev/null)" = APPROVED
251
265
  ```
252
266
 
253
- with a sibling `verify → failed` guarded on the negation. So a missing file, malformed JSON, or any
254
- non-`PASS` verdict routes the run to `failed` rather than `done` — the pipeline cannot certify
255
- completion without an explicit PASS artifact.
267
+ A missing file, malformed JSON or any non-`PASS` verdict leaves the status FAIL, which the
268
+ `review-failure-class` decision routes to `remediate` (`fix`) or `failed` (`stop`). The pipeline
269
+ cannot certify completion without an explicit PASS artifact.
256
270
 
257
271
  ## Lifecycle
258
272
 
259
- - **Written:** Step 9 of verify mode, *after* the verdict is final (never partially).
260
- - **Read:** by the workflow gate on the `verify → record` transition.
261
- - **Location:** `.spur/run/` (the run-scratch dir the pipeline's `record` step also uses).
262
- - **Lifetime:** per execution attempt; overwritten on the next verify of the same WBS.
273
+ - **Written:** by `spur task verdict` in the pipeline's `review` state, or by Step 9 of standalone
274
+ verify mode, *after* the verdict is final (never partially).
275
+ - **Read:** by the review fold and the `review → done` guard, then by `done`'s `spur task record`
276
+ close, which transcribes it.
277
+ - **Location:** `.spur/run/`.
278
+ - **Lifetime:** per execution attempt; overwritten on the next certification of the same WBS.
263
279
 
264
280
  ## Optional check severity (task 0592, feature F92)
265
281
 
@@ -304,6 +320,6 @@ The prose shape above is executed by a single runtime-validated contract:
304
320
  failure can never yield PASS.
305
321
  - A row-less artifact aggregates to UNKNOWN — a stored PASS that does not recompute to PASS
306
322
  (including a row-less PASS) is treated as non-PASS at the done gate. The done-transition choke
307
- point (`done-transition-guard.ts` `evaluateDoneTransition`) is the final authority; workflow JSON
308
- routing may select `verify → record/failed` but cannot weaken the final transition.
323
+ point (`done-transition-guard.ts` `evaluateDoneTransition`) is the final authority; workflow
324
+ routing may select `review → done/failed` but cannot weaken the final transition.
309
325
  - `--force-done --reason` on `spur task update <wbs> done` remains the sole auditable override.
@@ -295,7 +295,7 @@ Include the per-requirement traceability table in the report:
295
295
  **Under the pipeline**, `sp:functional-review` is a component of `/sp:dev-review`: it returns its
296
296
  fragment to the coordinator (`sp:super-reviewer` — the invoking session under `/sp:dev-review`),
297
297
  which writes the combined `## Review`. The
298
- `record` step transcribes only `## Testing` from the verdict artifact and backfills `## Review`
298
+ `done` state's `spur task record` close transcribes only `## Testing` from the verdict artifact and backfills `## Review`
299
299
  only when the section is bare (`sectionIsBare` guard, `task-section-bodies.ts`); it never overwrites the
300
300
  coordinator's authored Review. Keep the priority-table lead stable in the fragment so the L3 gate
301
301
  stays satisfied through `record` → `done`.
@@ -130,4 +130,4 @@ all core requirements MET → PASS
130
130
  | `VerifyVerdict` | `sp:code-verification` | Is the code SECUA-correct and AC-complete? | any core req/AC UNMET → FAIL; any blocker correctness/security → FAIL; any PARTIAL → PARTIAL; else PASS |
131
131
 
132
132
  A complete `/sp:dev-review --focus all` pipeline may produce both artifacts; they are consumed by
133
- the pipeline's `record` step and written to the task's `## Testing` section.
133
+ the `done` state's `spur task record` close and written to the task's `## Testing` section.
@@ -125,7 +125,7 @@ token, deterministic).
125
125
  means the workspace holds unfinished task residue, so fixall/unit reruns would either clean it
126
126
  unintentionally or re-certify a folded verdict. C6 fires before any fix/unit dispatch; recovery is
127
127
  the operator re-running the pipeline (`/sp:dev-run <wbs>`), which re-enters the normal
128
- verify → test-fix remediation budget.
128
+ gate ⇄ remediate budget.
129
129
 
130
130
  **Explicit non-probes in v1:** no freeform chat history; no always-on full `bun run test` for every
131
131
  call; no git dirtiness as a route (optional advisory print only).
@@ -92,7 +92,7 @@ preserved by construction. `recheck` stays the no-progress probe path for fix lo
92
92
 
93
93
  ## Composition
94
94
 
95
- - **Pipeline:** `sp:spur-dev` runs `run` at `test` and `recheck` at `test-recheck`; light mode
95
+ - **Pipeline:** `sp:spur-dev` runs `run` on the `gate` state's first visit and `recheck` on later visits (after `remediate`); light mode
96
96
  belongs to implement/fix edits, not to the gate state.
97
97
  - **Fix loops:** `/sp:dev-fixall --gate-log` consumes `<wbs>-test-gate.log` (and the bounded
98
98
  `<wbs>-test-gate.findings` anchors) after a red gate; it never writes receipts. A green fixall
@@ -50,7 +50,7 @@ Pick the noun, read its reference. Each Tier A and Tier B reference owns that no
50
50
  | **Tier B** | **self** | Self-management verbs: scaffold (`init`), project SDLC actions (`exec`), database maintenance (`maintain`), schema migrations (`migrate`), local web server (`serve`), status overview (`status`); `self init` runs post-scaffold validation probes & layout classification | [references/self.md](references/self.md) |
51
51
  | **Tier B** | **history** | Import agent histories, aggregate forensic artifacts, render reports, and run the checkpoint-resumed daily pipeline | [references/history.md](references/history.md) |
52
52
  | **Tier B** | **projects** | Manage the local multi-project registry and start/stop project servers | [references/projects.md](references/projects.md) |
53
- | **Tier B** | **decision** | Decision-catalog transport: list visible decisions, show a served contract, run a decision to a served outcome, audit catalog health | [references/decision.md](references/decision.md) |
53
+ | **Tier B** | **decision** | Decision catalog: list visible decisions, show a served contract, run a decision to a served outcome, audit catalog health and maker reliability; author and tune catalog entries | [references/decision.md](references/decision.md) |
54
54
  | **Tier C** | **help** | Commander-generated help command; not a Spur noun | Generated `--help` |
55
55
 
56
56
  **Execute-First Contract:** Load the noun reference first and execute Tier A or Tier B commands
@@ -69,6 +69,26 @@ Each noun's per-topic detail lives one level deeper under `references/<noun>/` (
69
69
  `references/tasks/verbs.md`, `references/tasks/section-editing.md`, `references/features/acceptance-criteria.md`,
70
70
  `references/rules/operations.md`, `references/workflows/authoring-workflows.md`).
71
71
 
72
+ ## Lifecycle playbooks
73
+
74
+ Authorable nouns carry a `## Lifecycle playbook` (rules: `## Lifecycle map`) in one shared stage
75
+ vocabulary — **Create → Evaluate → Triage → Enhance** — each row naming the command and the gate
76
+ that proves the stage, plus best practices. The playbook links the noun's subfiles; it never
77
+ restates them.
78
+
79
+ | Noun | Playbook |
80
+ | --- | --- |
81
+ | task | [references/tasks.md](references/tasks.md#lifecycle-playbook) |
82
+ | feature | [references/features.md](references/features.md#lifecycle-playbook) |
83
+ | rule | [references/rules.md](references/rules.md#lifecycle-map) |
84
+ | workflow | [references/workflows.md](references/workflows.md#lifecycle-playbook) |
85
+ | agent spec | [references/agent.md](references/agent.md#lifecycle-playbook-agent-specs) |
86
+ | decision | [references/decision/lifecycle.md](references/decision/lifecycle.md) |
87
+
88
+ Operational nouns (builder, message, self, history, projects) run verbs rather than author
89
+ artifacts, so they have no playbook. Cross-noun selection and composition live in
90
+ `sp:spur-composer`; read-only evaluation reports in `sp:spur-doctor`.
91
+
72
92
  ## When to use
73
93
 
74
94
  Use this skill to:
@@ -144,7 +164,8 @@ and spreading it; full contract in `docs/04_DESIGN.md` §1.0.1.
144
164
  - **[references/message.md](references/message.md)** - durable inter-agent messaging (`send`,
145
165
  `inbox`, `reply`, `watch`).
146
166
  - **[references/decision.md](references/decision.md)** - decision catalog (`list`, `show`, `run`,
147
- `status`); offline by default via the built-in `typesafe` maker.
167
+ `status`); with no reachable backend each decision serves its declared fallback. Authoring and
168
+ tuning: [references/decision/lifecycle.md](references/decision/lifecycle.md).
148
169
  - **[references/self.md](references/self.md)** - `spur self init|exec|maintain|migrate|serve|status` CLI verbs
149
170
  (the five legacy top-level nouns remain hidden aliases). `self init` runs post-scaffold init
150
171
  validation (Phase 1.5/1.6 probes).
@@ -400,6 +400,18 @@ failed drains marked the session poisoned. The next drain opens a fresh session.
400
400
  only. A settled (delivered) inbox message is never redelivered — resuming a session or resetting
401
401
  one never re-sends settled work; only never-started deliveries release and redeliver (0831/0834).
402
402
 
403
+ ## Lifecycle playbook (agent specs)
404
+
405
+ | Stage | How | Gate / evidence |
406
+ | --- | --- | --- |
407
+ | **Create** | Prefer an `agent.fleet.members` entry; hand-author `.spur/agents/<id>.yaml` only for a spec the fleet cannot express | `spur agent list --specs --json` shows the row with the intended `source` |
408
+ | **Evaluate** | `spur agent doctor [agent] --json` for the executor; `spur agent status --json` for the live process and member session | Executor ready; spec resolves |
409
+ | **Triage** | Run failed → `spur agent trace <runId> --json`; stuck occupant → `spur agent wait <specId> --until <state> --timeout <ms>`; supervisor unreachable → `spur self serve` | Lineage names the failing dispatch |
410
+ | **Enhance** | Change one field (executor, model, role) and re-run the same prompt | Compare the two `trace` records |
411
+
412
+ - The fleet declaration wins on an id clash; do not keep a same-id file "as a backup".
413
+ - Coordinate through `spur message` / `spur agent wait`, never terminal scraping.
414
+
403
415
  ## What this skill is NOT
404
416
 
405
417
  - **Not the dispatch decision.** *When* to use `spur agent run` vs a native subagent is the
@@ -0,0 +1,166 @@
1
+ ---
2
+ name: spur-cli-decision-lifecycle
3
+ description: "spur decision lifecycle: author a catalog entry, wire it into a workflow, evaluate a maker with recorded evidence, triage fallbacks and catalog errors, and tune criteria, floors and makers."
4
+ see_also:
5
+ - spur-cli
6
+ - spur-composer
7
+ ---
8
+
9
+ # Decision lifecycle — create, evaluate, triage, enhance
10
+
11
+ The verb catalog is [../decision.md](../decision.md). This file is the per-noun procedure: how a
12
+ decision point is born, proven, diagnosed and improved. Contracts it links rather than restates:
13
+ [decision catalog design](../../../../../../docs/design/decision-catalog.md) (§3.1 SSOT, §3.2 layers,
14
+ §3.6 maker precedence) and
15
+ [decision observability](../../../../../../docs/design/decision-observability-and-adoption.md) (§3.4
16
+ reliability, §4 workflow audit, §5 staged adoption). The upstream format authority is the
17
+ `@gobing-ai/ts-ai-decision` README and its `schemas/decision-catalog.schema.json`.
18
+
19
+ ## 1. Decide it is a decision at all
20
+
21
+ A catalog decision is a **total classification**: a closed vocabulary, a declared fallback, and a
22
+ recorded outcome. Use the §4 audit classes before authoring anything:
23
+
24
+ | Class | Use when | Shape |
25
+ | --- | --- | --- |
26
+ | **keep-deterministic** | An exact check answers it (status file, exit code, count, regex) | No decision; a shell guard or rule |
27
+ | **rescue-only** | A deterministic parse answers most inputs; free-form output sometimes defeats it | Parse first, call the decision only on what the parse cannot classify |
28
+ | **adopt** | The input is judgement over prose/diff evidence and a safe default exists | Catalog-reference `decide` step |
29
+ | **keep-human** | It is an operator taste gate | `hitl.confirm`/`hitl.select`; opt-in `decision.mode: evidence` routes through `gate-evidence` |
30
+
31
+ A model is a regression wherever an exact check exists. A decision with no safe fallback is a gate,
32
+ not a decision.
33
+
34
+ ## 2. Create
35
+
36
+ 1. **Select first.** `spur decision list --json` across every layer; `spur decision show <id> --json`
37
+ on near matches. An existing id whose criteria fit is reused, never cloned under a new id.
38
+ 2. **Pick the layer** (the composer ladder, [spur-composer](../../../spur-composer/SKILL.md)):
39
+ scratch → `.spur/decisions/<file>.yaml` (project) → shared `config/decisions/<file>.yaml` (spur
40
+ repository only, recorded operator consent + `build:bundle`). Winners are chosen **per file
41
+ basename** before the hub loads, so a project file named like a shipped one replaces that whole
42
+ shipped file — copy every id you still need, or use a new basename.
43
+ 3. **Author the entry** (format version 1; unknown keys are rejected at every level):
44
+
45
+ ```yaml
46
+ version: 1
47
+ defaults:
48
+ minConfidence: 0.8 # repo convention for pipeline decisions; upstream default is 0.7
49
+ decisions:
50
+ review-scope: # ^[a-z][a-z0-9_-]*$ — stable id, it keys the ledger
51
+ type: choice # choice | score | noul
52
+ description: Which review depth does this diff need? # documentation only, never sent
53
+ parameters:
54
+ wbs:
55
+ type: string # string | number | boolean | enum | json
56
+ description: Task WBS the diff belongs to.
57
+ criteria: # choice: >= 2 labels, each label's meaning in one sentence
58
+ light: Docs-only or test-only diff with no runtime surface.
59
+ full: Any runtime, contract, schema or security-relevant change.
60
+ fallback: full # must be a declared label; the safe answer on any backend failure
61
+ ```
62
+
63
+ - A parameter with no `default` is **required**. `instructions` is reserved: it is the implicit
64
+ channel `--evidence` and workflow `evidence:` feed. Never declare it.
65
+ - `fallback` is the outcome on `no-backend`, `timeout`, `error` and `low-confidence`. Choose the
66
+ answer that is **safe when wrong** (`full`, `fix`, `defer`, `standard`), not the most common one.
67
+ - Leave `maker` out of shipped catalogs. Operator config outranks the catalog
68
+ (`flag → decisions.makers.<id> → decisions.maker → catalog`) because only the machine owner
69
+ knows which backends exist there.
70
+ - Spur's `DecisionService` resolves the effective maker as one name. Upstream maker chains
71
+ (`maker: [a, b]`) and `shadow` exist in the schema but are not surfaced by `decision show`
72
+ or `status` today; prove them with `run` before relying on them.
73
+ 4. **Gate it:** `spur decision status --json` must show no `loadErrors` / `duplicateIds` and exit 0;
74
+ `spur decision show <id> --json` must render the parameters, criteria and fallback you meant.
75
+
76
+ ## 3. Wire into a workflow (optional)
77
+
78
+ Use the catalog-reference `decide` form; the inline `question`/`method`/`default` form is
79
+ deprecated (composition lint and the runner warn once per site):
80
+
81
+ ```yaml
82
+ - kind: decide
83
+ options:
84
+ id: review-scope # step id; one resultFile per step
85
+ decision: review-scope # catalog id
86
+ params: { wbs: '${vars.wbs}' }
87
+ evidence: # redacted + bounded to 2000 chars, joined into instructions
88
+ - .spur/run/${vars.wbs}-diffstat.json
89
+ resultFile: .spur/run/${vars.wbs}-review-scope.decision
90
+ ```
91
+
92
+ - Guards read the schemaVersion-1 `resultFile` row (`value`, `source`, `degraded`, `confidence`).
93
+ Route on `source == "model"` only where a degraded fallback must be distinguishable.
94
+ - `workflows.decideDecisionMaker` gates the workflow action. Off (the default) → every `decide`
95
+ serves its fallback with no model call. `spur decision run` ignores the switch.
96
+ - `evidence` and `instructions` are mutually exclusive; `params.instructions` fails the action.
97
+ - Validate with `spur workflow validate <file> --json` and `spur workflow run <file> --dry-run`.
98
+
99
+ ## 4. Evaluate
100
+
101
+ Evidence before adoption — the S4a–c slices each landed only with recorded `run` evidence for the
102
+ effective maker (observability §5).
103
+
104
+ | Question | Evidence (read-only unless noted) |
105
+ | --- | --- |
106
+ | Does the contract say what I meant? | `spur decision show <id> --json` |
107
+ | Does the catalog load cleanly? | `spur decision status --json` → `ok`, `loadErrors`, `duplicateIds`, `errors` |
108
+ | Is the maker registered / configured / ever used? | `spur decision status` readiness marks (`ST`, `CONFIGURED BY`, `RECORDED`, `ACCEPTED`) |
109
+ | Does the maker answer right now? | `spur decision status --probe` (calls each effective maker once; writes nothing) |
110
+ | How well has it served? | `spur decision status --reliability [--since <iso>] --json` → per `decisionId × maker`: `samples`, `acceptedRate`, `fallbacks{reason}`, `medianConfidence`, p50/p95 duration |
111
+ | Does it classify known cases correctly? | `spur decision run <id> --param … --evidence <fixture> --json` per labelled fixture (records a ledger row) |
112
+
113
+ Build a small labelled fixture set — at least one clear case per label plus one ambiguous case — and
114
+ run it against each candidate maker with `--maker <name>`. Compare `value` to the label, not just
115
+ `source: model`: an accepted wrong answer is worse than a fallback.
116
+
117
+ **Read confidence per maker type.** Probability-native makers (`typesafe`, `laya-local`, `clef`)
118
+ return a model distribution. Sampled makers (`fm-local`) return agreement over k samples, so
119
+ `accepted` means "all samples agreed" and 1.0 is unanimity, not calibration. Choose a
120
+ probability-native maker where the floor must discriminate.
121
+
122
+ ## 5. Triage
123
+
124
+ | Symptom | Likely cause | Next step |
125
+ | --- | --- | --- |
126
+ | `status` exits 1, `loadErrors` names a file | Schema violation (unknown key, fallback not a declared label, bad `${params.*}` ref) | Fix the file; the whole catalog file is skipped until it loads |
127
+ | `duplicateIds` non-empty | Same id in two winning files of different basenames | Rename or delete one; any `run`/`decide` of that id fails meanwhile |
128
+ | `run` exits 1 | Caller mistake: unknown id, undeclared/missing/invalid param, unregistered `--maker`, unreadable evidence | Read the message; nothing reached a backend |
129
+ | `source: default`, `reason: no-backend` | Maker cannot be constructed (missing credentials, wrong host) | `status --probe`; set credentials or override `decisions.makers.<id>` |
130
+ | `reason: timeout` | Cold local model or unreachable host | Re-probe; prefer a warm or hosted maker for pipeline-critical ids |
131
+ | `reason: error` | Backend rejected the call or returned an invalid answer | Check `decision_logs.error`; on `typesafe`, parameterless decisions hit the known `state: null` 422 until the ts-libs bump (design §5) |
132
+ | `reason: low-confidence`, repeated | Criteria labels overlap, evidence is too thin, or a sampled maker disagrees with itself | Sharpen criteria (§6), add evidence, or switch to a probability-native maker |
133
+ | `RECORDED > 0`, `ACCEPTED 0` | Maker is wired but has never once succeeded | Treat as broken, not healthy; triage by `fallbacks` reason |
134
+ | Config names a maker `status` calls unregistered | Typo, or `clef` without `CLOUDFLARE_ACCOUNT_ID`/`CLOUDFLARE_AUTH_TOKEN` | Loud by design — fix the name or the environment |
135
+ | A `decide` step always degrades | `workflows.decideDecisionMaker` is off | Intended default; enable only after §4 evidence |
136
+
137
+ ## 6. Enhance
138
+
139
+ Tune one lever at a time and re-run the same fixture set; a change with no before/after evidence
140
+ pair is a preference.
141
+
142
+ | Lever | When | Where |
143
+ | --- | --- | --- |
144
+ | **Criteria wording** | Low confidence or wrong labels on clear cases | Make labels mutually exclusive and observable ("touches runtime code"), not evaluative ("risky") |
145
+ | **Evidence** | The model cannot see what decides the answer | Add or trim workflow `evidence` files; keep each well under the 2000-char bound |
146
+ | **Parameters** | The answer depends on a structured fact | Declare a typed parameter instead of burying it in evidence |
147
+ | **`minConfidence`** | Fallback rate is too high with correct answers, or too low with wrong ones | Per-decision field; lower only with fixture evidence that low-confidence answers were right |
148
+ | **Maker** | Reliability differs by backend | Operator config `decisions.makers.<id>` (not the shipped catalog) |
149
+ | **Fallback** | The safe-when-wrong answer changed | Change only with the owning workflow's guard reviewed in the same change |
150
+ | **Adoption class** | A deterministic parse now covers the input | Demote to rescue-only or keep-deterministic |
151
+
152
+ Never rename a shipped id: the ledger, Board Decisions tab and workflow `decision:` references all
153
+ key on it. Add a new id and retire the old one through the workflow change.
154
+
155
+ ## 7. Best practices
156
+
157
+ - **Determinism first, model second.** Every adopted decision keeps a deterministic route or a safe
158
+ fallback so the pipeline behaves identically with the switch off.
159
+ - **One question per id.** A decision that needs "and" in its description is two decisions.
160
+ - **Labels are a contract.** Guards and downstream shell read the label strings; treat a label
161
+ rename as a breaking change.
162
+ - **Probe is not evidence.** `--probe` proves liveness; only `--reliability` and labelled `run`
163
+ results prove quality, and the probe never writes the rows it would inflate.
164
+ - **Never route pipeline correctness on `maker-liveness`.** It serves only `status --probe`.
165
+ - **Measure before you migrate.** Land the catalog entry, gather `run` evidence, then adopt in a
166
+ workflow — one decision point per change.