@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
@@ -218,7 +218,7 @@ inventory, findings, unresolved, coverage, cost, remediation, errors
218
218
  {
219
219
  "schema_version": 1,
220
220
  "command": "dev-find-conflict",
221
- "scope": "docs/00_ADR.md",
221
+ "scope": "scope:docs/00_ADR.md",
222
222
  "mode": "adaptive",
223
223
  "pillars": ["authority"],
224
224
  "authority_map": {},
@@ -236,7 +236,7 @@ inventory, findings, unresolved, coverage, cost, remediation, errors
236
236
  | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
237
237
  | `schema_version` | integer, `1`. The envelope contract version — not a semantic-reasoning version. |
238
238
  | `command` | string, `dev-find-conflict`. |
239
- | `scope` | string. The resolved audit scope (path, WBS, feature ID, symbol, command, or `"<project>"`). |
239
+ | `scope` | string. The frozen target as `<kind>:<id>[,<id>]` — `tasks:0486,0487`, `feature:H11,H12`, `scope:apps,docs` — or `"<project>"` when no selector was given. |
240
240
  | `mode` | string, `adaptive` \| `full`. |
241
241
  | `pillars` | string[]. The pillars actually audited (subset of `source`, `tasks`, `features`, `authority`). |
242
242
  | `authority_map` | object. Claim-type → authoritative artifact/rule, with each precedence edge citing its project rule or fallback (see [./authority-resolution.md](authority-resolution.md)). |
@@ -13,7 +13,8 @@ opt-in, gated workflow. This file is the SSOT for *when a write is allowed*, *wh
13
13
 
14
14
  The governing rule, carried through everything below: **no mutation in audit mode, and no automatic
15
15
  mutation merely because `--resolve` is present.** Every write requires (a) a presented repair set,
16
- (b) explicit operator confirmation, (c) a freshness revalidation of the supporting evidence, and
16
+ (b) explicit operator confirmation (interactive, or the explicit `--auto` pre-approval of eligible
17
+ items — §2.2a), (c) a freshness revalidation of the supporting evidence, and
17
18
  (d) dispatch through the artifact owner's verified harness surface. Ambiguity or partial failure is
18
19
  reported, never silently continued.
19
20
 
@@ -23,7 +24,7 @@ reported, never silently continued.
23
24
  |-----------|-----------|
24
25
  | Audit mode is read-only | Without `--resolve`, no source, corpus (task/feature), or numbered-document mutation of any kind. |
25
26
  | `--resolve` is not a write | It only *opens* the proposal → confirmation → owner-routed workflow. It never authorizes automatic repair. |
26
- | Confirmation precedes every write | No repair executes until the operator explicitly approves the specific proposed repair set. |
27
+ | Confirmation precedes every write | No repair executes until the operator explicitly approves the specific proposed repair set — interactively, or by `--auto` pre-approval of its eligible subset (§2.2a). |
27
28
  | Freshness precedes mutation | The supporting evidence anchors are re-read and compared against the finding's fingerprint before any write. |
28
29
  | Owner surface, not raw edits | Each approved repair routes through the artifact's owner (Spur CLI, `sp:doc-evolve`, Spur dev lifecycle, Superskill lifecycle) — never a direct file write where an owner surface exists. |
29
30
  | Idempotent and partial-failure aware | Already-matching artifacts resolve without a write; one repair's failure neither marks others successful nor silently rolls forward. |
@@ -93,6 +94,23 @@ is:
93
94
  A declined or deferred repair is left **untouched** and reported as such; it is not re-attempted
94
95
  implicitly in the same run.
95
96
 
97
+ ### 2.2a `--auto` pre-approval
98
+
99
+ `--auto` (only valid with `--resolve`) is the operator's explicit, up-front confirmation of the
100
+ **eligible** subset of the repair set — it replaces the interactive pause for that subset only. The
101
+ repair set is still presented (§2.1) before anything is applied. An item is eligible only when all
102
+ hold:
103
+
104
+ - `status` is `open` — never `needs-authority-decision` (authority is resolved, not ambiguous/missing);
105
+ - `confidence` is `high`;
106
+ - `repair_owner` resolves to a verified owner surface in §3 (no manual/unknown owner).
107
+
108
+ Ineligible items are the HITL that remains: authority decisions and medium/low-confidence repairs
109
+ **still pause** for the operator, exactly as without `--auto`. In a non-interactive run (no operator
110
+ to answer), they are recorded `deferred` and left untouched. The remediation report marks each
111
+ approved item `approved_by: auto` or `approved_by: operator`, so the audit trail distinguishes the two.
112
+ `--auto` never skips freshness revalidation (§2.3), owner routing (§3), or partial-failure handling (§5).
113
+
96
114
  ### 2.3 Revalidate evidence freshness
97
115
 
98
116
  Between the audit and any write, the world may have changed. Immediately before dispatching each
@@ -245,6 +263,7 @@ These are the explicit boundaries for remediation. Each is a hard violation, not
245
263
  | Anti-pattern | Why it is prohibited |
246
264
  |--------------|----------------------|
247
265
  | **Automatic mutation merely because `--resolve` is present** | `--resolve` only opens the workflow; it never authorizes automatic repair. Confirmation + freshness + owner surface are all required. |
266
+ | **`--auto` beyond its eligible subset** | `--auto` pre-approves only §2.2a-eligible items; applying an authority decision or a medium/low-confidence repair under it is a violation. |
248
267
  | **Changing correct authority for projection drift** | A stale projection is repaired against its governing contract. Correct authority only when defective and authorized; then update affected projections. |
249
268
  | **Broad cleanup outside confirmed findings** | Only the artifacts named by confirmed, freshness-checked findings are touched. No opportunistic refactors or doc "improvements" while repairing. |
250
269
  | **Ambiguity silently resolved** | Ambiguous/missing authority stops for an operator decision; it is never forced through a global ranking or a guessed owner. |
@@ -260,7 +279,7 @@ Before dispatching any write, confirm each of the following:
260
279
 
261
280
  - [ ] Audit mode performed **no** governed mutation; the report is a pure envelope.
262
281
  - [ ] `--resolve` was present, and the **repair set was presented** (keyed by finding ID + fingerprint).
263
- - [ ] The operator **explicitly confirmed** the specific selected repair set.
282
+ - [ ] The operator **explicitly confirmed** the specific selected repair set, or `--auto` pre-approved only §2.2a-eligible items.
264
283
  - [ ] Evidence **freshness revalidated** per finding at dispatch; `stale-evidence` items returned to audit.
265
284
  - [ ] Each approved repair routed through its **owner surface** (§3), never a raw write where an owner exists.
266
285
  - [ ] **Idempotent** already-matching items marked `resolved` without a write.
@@ -5,6 +5,8 @@ description: >-
5
5
  "join the fleet", "become a fleet guest", "pull fleet inbox work in this session", or when a
6
6
  session should receive fleet messages without being supervised. Runs `spur agent join`, then
7
7
  loops `spur agent wait --inbox`, and releases the lease with `spur agent leave`.
8
+ metadata:
9
+ version: "1.0"
8
10
  ---
9
11
  # fleet-join — a live session as a fleet guest (G73, task 1081)
10
12
 
@@ -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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: spur-cli-decision
3
- description: "spur-cli noun reference: operate `spur decision` as the read/serve surface over the decision catalog - list registered decisions, show one served contract (parameters, criteria vocabulary, effective maker), run a decision to a served outcome (never writes a workflow resultFile), and status the catalog layers with per-maker readiness marks (registered, configured, recorded, probed). Backed by @gobing-ai/ts-ai-decision 0.5.22 hub; offline by default via the built-in `typesafe` maker. Introduced by task 1093; readiness marks and `--probe` by feature P11."
3
+ description: "spur-cli noun reference: operate `spur decision` as the read/serve surface over the decision catalog - list registered decisions, show one served contract (parameters, criteria vocabulary, effective maker), run a decision to a served outcome (never writes a workflow resultFile), and status the catalog layers with per-maker readiness marks (registered, configured, recorded, probed). Backed by the @gobing-ai/ts-ai-decision hub; with no reachable backend every decision serves its declared fallback. Lifecycle (author, evaluate, triage, tune) lives in decision/lifecycle.md."
4
4
  see_also:
5
5
  - spur-cli
6
6
  ---
@@ -25,14 +25,16 @@ Decisions resolve first-wins across three layers:
25
25
  | `registered` | folders listed in config `decisions.paths` | Operator-added catalogs |
26
26
  | `shared` | `decisions/` under the bundled config root | Shipped catalogs (`config/decisions/` in-repo) |
27
27
 
28
- The bundled shared catalog ships `task-triage`, `failure-class`, `review-failure-class`,
28
+ The bundled shared catalog ships `task-semantic-risk`, `failure-class`,
29
29
  `gate-evidence`, `idea-recommendation`, `needs-design`, `anatomy-validation-verdict` and
30
30
  `maker-liveness` (the last served only by `spur decision status --probe`; no workflow references
31
- it). Duplicate ids across layers keep the higher layer; duplicates inside one file are a load error.
31
+ it). Layers win **per file basename** (a project `gates.yaml` replaces the shipped `gates.yaml`
32
+ whole); the same id in two winning files of different basenames is a `duplicateIds` catalog error.
32
33
 
33
34
  **Config keys** (under `decisions:` in the global `~/.config/spur/config.yaml` or project `.spur/config.yaml`):
34
35
  `paths` (extra catalog folders forming the `registered` layer), `maker` (default DecisionMaker
35
- for every decision point), `makers` (per-decision-id overrides). An unregistered maker name is a
36
+ for every decision point), `makers` (per-decision-id overrides), `log` (`full` | `metadata` | `off`,
37
+ how much of each served decision the ledger keeps). An unregistered maker name is a
36
38
  config error, never a silent fallback (design §3.6).
37
39
 
38
40
  ## Verb map
@@ -43,6 +45,7 @@ config error, never a silent fallback (design §3.6).
43
45
  | `show <id>` | One served contract: type, parameters, criteria, fallback, minConfidence, effective maker + source | `--json` |
44
46
  | `run <id>` | Serve one outcome (closed vocabulary; **never writes a resultFile**) | `--param <pairs...>`, `--evidence <files...>`, `--maker <name>`, `--json` |
45
47
  | `status` | Sectioned readiness report: one status line, errors, aligned `Makers` and `Decisions` tables (registration, configuration source, recorded evidence), `Catalog` block | `--probe`, `--reliability [--since <iso>]`, `--json` |
48
+ | `outcome <invocation-id>` | Record what actually happened after a served decision — acceptance is not accuracy (task 1263). First write wins | `<outcome>`, `--review-severity <wbs>`, `--gate-status <run-id>`, `--source <text>`, `--json` |
46
49
 
47
50
  All verbs support `--json` (bare payload) and `--json-envelope` (`{ok, data|error}` envelope,
48
51
  ADR-091). Failure output for `--json` commands uses the canonical error envelope only under
@@ -51,6 +54,62 @@ ADR-091). Failure output for `--json` commands uses the canonical error envelope
51
54
  **Exit codes:** `status` exits 1 on any catalog load error or maker-config error; `show` exits 1 on unknown id; `list` exits 0
52
55
  (design §3.4 — load errors surface via `status`) except for an invalid `--layer` value (exit 1).
53
56
  Error envelopes use `NOT_FOUND` for an unknown id and `VALIDATION_FAILED` for every other caller mistake.
57
+ `outcome` exits 1 for an unknown invocation id (there is no decision to score) and 2 for a malformed
58
+ outcome (it must match `^[a-z0-9-]{1,32}$`) or for naming zero/several outcome sources.
59
+
60
+ ## Acceptance versus accuracy (`outcome` + `--reliability`)
61
+
62
+ `decision.end` says **what was answered**; it never says whether the answer was right. A maker can
63
+ be accepted on every call and still add no information: `review-failure-class` answered its own
64
+ fallback 15/15 times at confidence 1.0 before task 1262 retired it. Tuning `minConfidence`, choosing
65
+ a maker, or judging a shadow maker therefore needs (value, outcome) pairs.
66
+
67
+ **Recording one.** A decide step now writes the invocation's ledger key into its result row
68
+ (`invocationId`, task 1263 R1) — the same id the `decision.*` events and the `decision_logs` row
69
+ carry. Once the outcome is known, record it:
70
+
71
+ ```bash
72
+ # an explicit label (lowercase slug): what a human or a later check observed
73
+ spur decision outcome <invocation-id> fixed --source "quality gate recheck"
74
+ # derived from a task's Review findings: the worst finding, resolved rows included (p1-p4, or none)
75
+ spur decision outcome <invocation-id> --review-severity 1263
76
+ # derived from a gate visit: PASS -> fixed, anything else (or a missing token) -> not-fixed
77
+ spur decision outcome <invocation-id> --gate-status <run-id>
78
+ ```
79
+
80
+ First write wins: a replay exits 0 with `recorded: false` and the outcome that already stands. The
81
+ row lands in `system_events` beside `decision.end`, on the same `run_id`, so the report joins it by
82
+ `invocationId`.
83
+
84
+ **Scoring one.** `decisions.outcomeMap` in config (project or global layer) holds Spur's reading of
85
+ Spur's own artifacts — per decision id, which recorded outcomes count as correct for each served
86
+ value (`String(value)` keys, so a yes/no decision uses `"true"`/`"false"`). The shipped defaults
87
+ score `failure-class` (`fix` → `fixed`, `stop` → `not-fixed`) and `task-semantic-risk`
88
+ (`"false"` → `none`/`p4`/`p3`, `"true"` → `p1`/`p2`).
89
+
90
+ `spur decision status --reliability` then reports, per (decision × maker) group:
91
+
92
+ | Field | Meaning |
93
+ | --- | --- |
94
+ | `samples`, `accepted`, `acceptedRate` | `decision.end` rows; acceptance only |
95
+ | `outcomes` | recorded outcomes by label over those samples |
96
+ | `accuracy` | correct accepted answers ÷ accepted answers **with an outcome**; null when the decision has no map entry or no accepted sample recorded one |
97
+ | `fallbackAccuracy` | the same ratio over fallback (`source: default`) samples |
98
+
99
+ `accuracy: null` is deliberate: an unmapped decision or an unobserved one is unknown, never zero.
100
+ Acceptance and accuracy answer different questions — a high `acceptedRate` with `accuracy: null`
101
+ means "the maker answered and we have not looked at whether it was right yet".
102
+
103
+ **Reading a sampled maker.** Sampled makers report unanimity, not calibration: with two options,
104
+ 2-of-3 agreement is ~0.08 confidence and the 0.8 floor only accepts when every sample agreed
105
+ (ts-libs `docs/design/llm-agent-decision-backend.md` § Confidence granularity). A 1.0 confidence on
106
+ that kind of maker therefore means "the samples agreed", not "the answer is calibrated".
107
+
108
+ **Retuning `minConfidence` from the report.** Read a group's `accuracy` and `fallbackAccuracy`
109
+ together with `fallbacks` by reason. Accepted-but-wrong answers point at raising the floor (or
110
+ changing the maker); fallbacks that were right point at lowering it. Change the floor in the
111
+ catalog entry (or `defaults.minConfidence`), record the new samples, and compare the same two
112
+ numbers — never one of them alone.
54
113
 
55
114
  ## Readiness marks (`status`, feature P11)
56
115
 
@@ -77,6 +136,57 @@ error surfaced as fallback, declined — is still a **successful serve** (exit 0
77
136
  **before** the backend: unknown id, unknown parameter, missing required parameter, type-invalid
78
137
  parameter, unregistered `--maker`, unreadable evidence file.
79
138
 
139
+ ## Executor failure rescue (`executor-failure-class`)
140
+
141
+ The agent executor escalates on `FAILURE_RULES` matches only (`packages/app/src/services/failure-classification.ts`).
142
+ A failure no rule matches — a reworded rate limit, "credits depleted", a proxy error body — ends
143
+ the run as a task defect until somebody adds a regex. `executor-failure-class` covers that residue:
144
+ `resource-exhaustion` / `auth` / `task-defect`, fallback `task-defect`, `minConfidence: 0.85`
145
+ (a false `resource-exhaustion` costs a failover attempt; a false `task-defect` equals today's
146
+ behaviour, so uncertainty must resolve downward).
147
+
148
+ **It ships off.** `workflows.executorFailureDecisionMaker: true` is the opt-in; without it the executor
149
+ makes no model call and the context carries no rescue seam at all. Turning it on is an operator
150
+ call backed by replay evidence (`spur decision run executor-failure-class --evidence <tail>` over
151
+ real unmatched tails), not a default.
152
+
153
+ The rescue runs only when every deterministic check declined: non-zero exit without a timeout
154
+ signal, `undefined` from `classifyDispatch`, no permission-denial evidence (a denial stays terminal),
155
+ no confirmed quota event, and non-blank output. It sees the failure text **redacted first, then
156
+ tailed** to 4096 characters — tailing first could cut a secret at the boundary and send the
157
+ fragment off-box, so never reorder that.
158
+
159
+ **Evidence leaves the machine with a hosted maker.** The tail is failure output from whatever the
160
+ agent printed, so a hosted maker (`clef`) sees it. Two consequences:
161
+
162
+ - Prefer a **probability-native** maker for this id (`decisions.makers.executor-failure-class`):
163
+ sampled makers accept only on unanimity (ts-libs `docs/design/llm-agent-decision-backend.md`
164
+ § Confidence granularity), so the 0.85 floor does not grade them.
165
+ - `laya-local` keeps the evidence on-box (it needs Apple Silicon, and since task 1262 R1 the bundled
166
+ CLI ships its worker, so `workerScript` resolves without a source checkout).
167
+
168
+ Every rescue is attributed `caller: executor` with the failing run's id, so it shows up in
169
+ `decision.*` events, `decision_logs` and `spur decision status --reliability` with no extra work.
170
+ To promote recurring text into a deterministic rule, list the accepted rescues:
171
+
172
+ ```bash
173
+ sqlite3 .spur/spur.db "
174
+ SELECT o.decision_id, json_extract(o.payload_json, '$.data.outcome') AS answer,
175
+ json_extract(s.payload_json, '$.data.workflowName') AS workflow, o.run_id
176
+ FROM system_events o
177
+ JOIN system_events s
178
+ ON s.event_name = 'decision.start'
179
+ AND json_extract(s.payload_json, '$.data.invocationId')
180
+ = json_extract(o.payload_json, '$.data.invocationId')
181
+ WHERE o.event_name = 'decision.end'
182
+ AND json_extract(o.payload_json, '$.data.caller') = 'executor'
183
+ AND json_extract(o.payload_json, '$.data.source') = 'model'
184
+ ORDER BY o.occurred_at DESC;"
185
+ ```
186
+
187
+ Add the `FAILURE_RULES` entry by hand, with a test — the rescue stays the safety net for what the
188
+ table still misses.
189
+
80
190
  ## Parameters and evidence
81
191
 
82
192
  `--param k=v` is repeatable and validated against the decision's declared parameters: values for
@@ -95,23 +205,41 @@ keys). An unreadable evidence file exits 1 before any backend call.
95
205
  Makers resolve `flag → config-decision → config-default → catalog-decision → catalog-default`;
96
206
  `decision show` reports the effective maker as `{name, source}` with that source precedence
97
207
  (operator config outranks the shipped catalog because only the machine owner knows which backends
98
- exist there). The final `catalog-default` maker is the hub built-in `typesafe` — decisions served
99
- without a configured backend still produce deterministic closed-vocabulary outcomes, which is why
100
- `run` is usable in tests and scripts with no model access.
208
+ exist there). The final `catalog-default` maker is the hub built-in `typesafe`, a **hosted** maker
209
+ that needs `TYPESAFE_API_KEY`. Without a reachable backend `run` still exits 0 with the declared
210
+ fallback (`source: default`, reason `no-backend`), which is why it is usable in tests and scripts
211
+ with no model access — the outcome is deterministic, not model-judged.
212
+
213
+ **Available makers:** the four upstream built-ins (`typesafe`, `fm-local`, `laya-local`,
214
+ `llm-agent`) plus Spur's hosted `clef` (Cloudflare Workers AI via `@gobing-ai/ts-decision-clef`).
215
+
216
+ - `llm-agent` samples an installed coding agent: by default the first installed tier-1 agent, 3
217
+ one-shot samples, accepted only when every sample agrees. Spur passes it no driver options, so
218
+ each ask costs several agent runs; name it per decision (`decisions.makers.<id>`) rather than as
219
+ the project-wide `decisions.maker`.
220
+ - `clef` registers only when both `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_AUTH_TOKEN` are set in
221
+ the environment; without them it is absent from `registeredMakers`, so naming it in config or
222
+ `--maker` is a config error, never a silent fallback. Its model defaults to `clef-flash` (a
223
+ catalog `model` selects `clef`).
224
+
225
+ ## Workflow consumption
101
226
 
102
- **Available makers:** the three upstream built-ins (`typesafe`, `fm-local`, `laya-local`) plus
103
- Spur's hosted `clef` (Cloudflare Workers AI via `@gobing-ai/ts-decision-clef`). `clef` registers
104
- only when both `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_AUTH_TOKEN` are set in the environment;
105
- without them it is absent from `registeredMakers`, so naming it in config or `--maker` is a config
106
- error, never a silent fallback. Its model defaults to `clef-flash` (a catalog `model` selects
107
- `clef`).
227
+ Workflows consume a decision through the catalog-reference `decide` action
228
+ (`{id, decision, params?, evidence? | instructions?, resultFile}`); the inline
229
+ `question`/`method`/`default` form is deprecated. `workflows.decideDecisionMaker` (default off)
230
+ gates model calls there — off, every `decide` serves its fallback. `hitl.confirm`/`hitl.select`
231
+ with `decision: {mode: evidence, …}` route through `gate-evidence` under the separate
232
+ `workflows.hitlDecisionMaker` switch (default off — the gate defers to the operator, or under
233
+ `profile=auto` to its declared fallback). Neither switch affects `spur decision run`. Shape, adoption classes and
234
+ guards: [decision/lifecycle.md](decision/lifecycle.md) §1, §3.
108
235
 
109
236
  ## Examples
110
237
 
111
238
  ```bash
112
239
  spur decision list --json | jq -r '.[].id'
113
- spur decision show task-triage # inspect contract before serving
114
- spur decision run task-triage --param wbs=1093 --json
240
+ spur decision show task-semantic-risk # inspect contract before serving
241
+ spur decision run task-semantic-risk --param wbs=1093 \
242
+ --evidence .spur/run/1093-diffstat.json --evidence docs/tasks/1093_*.md --json
115
243
  spur decision run failure-class --param wbs=1093 \
116
244
  --evidence .spur/run/<runId>-test-output.txt # redacted evidence -> instructions
117
245
  spur decision status --json | jq '.loadErrors' # audit catalog health
@@ -124,7 +252,9 @@ spur decision status --json | jq '.makers[] | {name, registered, recorded: .evid
124
252
 
125
253
  - Design: `docs/design/decision-catalog.md` (§2 catalog authoring, §3.4 CLI surface),
126
254
  `docs/design/decision-observability-and-adoption.md` (§3.4 reliability report, §3.4.1 readiness view)
127
- - Hub: `@gobing-ai/ts-ai-decision` 0.5.22 (`DecisionService`, catalog schema, maker registry)
255
+ - Lifecycle: [decision/lifecycle.md](decision/lifecycle.md) (create, wire, evaluate, triage, enhance)
256
+ - Hub: `@gobing-ai/ts-ai-decision`, version pinned by the root `workspaces.catalog` (`DecisionService`,
257
+ catalog schema, maker registry)
128
258
  - App service: `packages/app/src/decision/decision-service.ts` (makers, `probeMaker`),
129
259
  `packages/app/src/decision/decision-status-readiness.ts` (readiness marks, probe loop)
130
260
  - Shipped catalogs: `config/decisions/*.yaml`
@@ -285,6 +285,18 @@ spur feature sync H2 --folder docs/custom-tasks --json # non-default tasks fol
285
285
  `{ featureId, from, to, reason, requiresConfirm?, gateBlocked?, gateFindings?, hops? }`.
286
286
  - **Exit codes:** `0` success (including NOOP), `1` error, `2` invalid usage (no id and no `--all`).
287
287
 
288
+ ## Lifecycle playbook
289
+
290
+ | Stage | How | Gate / evidence |
291
+ | --- | --- | --- |
292
+ | **Create** | `spur feature create <name> [--parent <id>]`; place it MECE in the tree ([features/hierarchy-mece.md](features/hierarchy-mece.md)) | `spur feature check <id> --json` exits 0 |
293
+ | **Evaluate** | AC quality ([features/acceptance-criteria.md](features/acceptance-criteria.md)), [traceability](#traceability-habits), roadmap fit ([features/roadmap-priority.md](features/roadmap-priority.md)) | `sp:spur-doctor` report cites `check` rows |
294
+ | **Triage** | Structural finding → `check --fix`; stale roster → `refresh`; status drift → `sync --dry-run` then `sync` | `check` clean; `sync --dry-run` empty |
295
+ | **Enhance** | `update --section` for AC/scope; `move --dry-run` before re-parenting a subtree | Every task still links to a live AC |
296
+
297
+ - A feature is a capability, not a work list; tasks own execution.
298
+ - Re-parent with `move`, never by renaming IDs by hand.
299
+
288
300
  ## What this skill is NOT
289
301
 
290
302
  - **Not the planning loop.** Intake → create → AC generation → check-loop → decomposition →
@@ -22,6 +22,8 @@ Operating the gate well is a full lifecycle — not just running it. This skill
22
22
  | **Run & fix** | Gate the diff, interpret findings, self-correct, re-run until green | this file |
23
23
  | **Author** | Add a constraint by writing a new rule when a standard/anti-pattern emerges | [rules/authoring-rules.md](rules/authoring-rules.md) |
24
24
  | **Fine-tune** | Dial in quality: severity, glob scoping, exemptions, preset `disable`/`overrides`, layering | [rules/fine-tuning.md](rules/fine-tuning.md) |
25
+ | **Evaluate** | `spur rule trace --last <n> --json` for hit rates and noise; `spur rule list --preset <name> --json` for what is enforced | this file, [rules/operations.md](rules/operations.md) |
26
+ | **Triage** | Start from `spur rule trace <run-id> --json`: false positive → scope/exempt; true positive → fix the code, never the rule | [rules/fine-tuning.md](rules/fine-tuning.md) |
25
27
  | **Validate & extend** | Validate files/presets, smoke-test, add custom evaluators/resolvers/formatters | [rules/validation-and-extension.md](rules/validation-and-extension.md) |
26
28
 
27
29
  ## When to use