@gobing-ai/spur 0.3.90 → 0.3.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/pipeline-budgets.json +9 -2
  3. package/config/plugin-scripts.json +17 -1
  4. package/config/workflows/decision-routing-example.yaml +134 -0
  5. package/config/workflows/feature-lifecycle.yaml +14 -5
  6. package/config/workflows/feature-verification.yaml +35 -27
  7. package/config/workflows/history-anatomy.yaml +14 -25
  8. package/config/workflows/idea-pipeline.yaml +17 -5
  9. package/config/workflows/task-pipeline.yaml +187 -4
  10. package/config/workflows/wayfinder-resolution.yaml +2 -0
  11. package/config/workflows/wrapup-pipeline.yaml +49 -5
  12. package/package.json +9 -9
  13. package/plugins/sp/README.md +1 -0
  14. package/plugins/sp/agents/expert-spur.md +2 -2
  15. package/plugins/sp/agents/super-planner.md +14 -5
  16. package/plugins/sp/commands/dev-dogfood.md +4 -4
  17. package/plugins/sp/commands/dev-fixall.md +8 -5
  18. package/plugins/sp/commands/dev-run.md +6 -0
  19. package/plugins/sp/commands/dev-runall.md +12 -6
  20. package/plugins/sp/commands/dev-verify.md +9 -0
  21. package/plugins/sp/commands/dev-verifyall.md +5 -0
  22. package/plugins/sp/lib/idea-handoff.generated.mjs +301 -300
  23. package/plugins/sp/lib/inline-run.generated.d.mts +17 -0
  24. package/plugins/sp/lib/inline-run.generated.mjs +1460 -0
  25. package/plugins/sp/plugin.json +1 -1
  26. package/plugins/sp/references/environment-lens.md +1 -1
  27. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +136 -0
  28. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +196 -2
  29. package/plugins/sp/scripts/feature-verification-steps.mjs +174 -0
  30. package/plugins/sp/scripts/feature-verification-steps.ts +275 -0
  31. package/plugins/sp/scripts/history-anatomy-cache.mjs +104 -4
  32. package/plugins/sp/scripts/history-anatomy-cache.ts +137 -13
  33. package/plugins/sp/scripts/inline-pipeline-parity-check.ts +2 -0
  34. package/plugins/sp/scripts/inline-run-setup.mjs +349 -0
  35. package/plugins/sp/scripts/inline-run-setup.ts +192 -75
  36. package/plugins/sp/scripts/record-feature-sync.mjs +63 -0
  37. package/plugins/sp/scripts/record-feature-sync.ts +84 -0
  38. package/plugins/sp/scripts/residual-scan.mjs +476 -0
  39. package/plugins/sp/scripts/residual-scan.ts +614 -0
  40. package/plugins/sp/scripts/surface-drift-inventory.ts +71 -6
  41. package/plugins/sp/scripts/task-evidence-precheck.ts +8 -3
  42. package/plugins/sp/scripts/task-size-precheck.ts +8 -3
  43. package/plugins/sp/scripts/validate-flag-contracts.ts +3 -3
  44. package/plugins/sp/skills/branch-workflow/SKILL.md +1 -0
  45. package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +2 -0
  46. package/plugins/sp/skills/code-implementation/SKILL.md +17 -0
  47. package/plugins/sp/skills/code-verification/SKILL.md +21 -0
  48. package/plugins/sp/skills/code-verification/references/verdict-schema.md +1 -0
  49. package/plugins/sp/skills/dogfood-testing/SKILL.md +5 -3
  50. package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +63 -26
  51. package/plugins/sp/skills/dogfood-testing/references/report-template.md +33 -10
  52. package/plugins/sp/skills/history-anatomy/references/modes.md +5 -3
  53. package/plugins/sp/skills/next-feature/references/ranking-rubric.md +1 -1
  54. package/plugins/sp/skills/next-router/references/routing-table.md +7 -0
  55. package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
  56. package/plugins/sp/skills/session-review/SKILL.md +12 -2
  57. package/plugins/sp/skills/spur-cli/references/agent.md +11 -2
  58. package/plugins/sp/skills/spur-cli/references/features.md +1 -1
  59. package/plugins/sp/skills/spur-cli/references/projects.md +3 -1
  60. package/plugins/sp/skills/spur-cli/references/self.md +5 -1
  61. package/plugins/sp/skills/spur-cli/references/workflows.md +42 -20
  62. package/plugins/sp/skills/spur-dev/SKILL.md +11 -4
  63. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +25 -3
  64. package/plugins/sp/skills/spur-dev/references/dev-operations.md +2 -2
  65. package/plugins/sp/skills/spur-dev/references/execution-batch.md +285 -57
  66. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +14 -5
  67. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +19 -4
  68. package/plugins/sp/skills/spur-dev/references/glossary.md +9 -1
  69. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +51 -16
  70. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +5 -0
  71. package/plugins/sp/skills/wayfinder/SKILL.md +1 -1
  72. package/spur.js +23422 -19364
  73. package/web/_astro/BoardApp.CerSBgis.js +192 -0
  74. package/web/_astro/BoardApp.eoTz0pZs.js +1 -0
  75. package/web/_astro/{TaskDetail.DwTmbQp5.js → TaskDetail.DCqiC-OZ.js} +1 -1
  76. package/web/_astro/arc.CPwg6Rw0.js +1 -0
  77. package/web/_astro/{architectureDiagram-3BPJPVTR.jvdDahWM.js → architectureDiagram-3BPJPVTR.DM_vp_hO.js} +1 -1
  78. package/web/_astro/{blockDiagram-GPEHLZMM.zSg4AmFD.js → blockDiagram-GPEHLZMM.DXVIiv0p.js} +1 -1
  79. package/web/_astro/{c4Diagram-AAUBKEIU.BkUIUQWH.js → c4Diagram-AAUBKEIU.BbF_zCxW.js} +1 -1
  80. package/web/_astro/channel.MYZLKNwy.js +1 -0
  81. package/web/_astro/{chunk-2J33WTMH.DvfQ_f50.js → chunk-2J33WTMH.CAgQHpPC.js} +1 -1
  82. package/web/_astro/{chunk-4BX2VUAB.DuI4gQqX.js → chunk-4BX2VUAB.BN-5tpw4.js} +1 -1
  83. package/web/_astro/{chunk-55IACEB6.D3BWBOpF.js → chunk-55IACEB6.CnPkEEr0.js} +1 -1
  84. package/web/_astro/{chunk-727SXJPM.3QSi0a9M.js → chunk-727SXJPM.BQzQeMVm.js} +4 -4
  85. package/web/_astro/{chunk-AQP2D5EJ.xazCQrAF.js → chunk-AQP2D5EJ.B6xNyDnL.js} +1 -1
  86. package/web/_astro/{chunk-FMBD7UC4.B2g6u4rA.js → chunk-FMBD7UC4.C7f9Ih78.js} +1 -1
  87. package/web/_astro/{chunk-ND2GUHAM.wWwWs99t.js → chunk-ND2GUHAM.CNV1dFXT.js} +1 -1
  88. package/web/_astro/{chunk-QZHKN3VN.BD5g3qa9.js → chunk-QZHKN3VN.Cudn2TkJ.js} +1 -1
  89. package/web/_astro/{classDiagram-4FO5ZUOK.C7CzCdsX.js → classDiagram-4FO5ZUOK.D1NwP50q.js} +1 -1
  90. package/web/_astro/{classDiagram-v2-Q7XG4LA2.C7CzCdsX.js → classDiagram-v2-Q7XG4LA2.D1NwP50q.js} +1 -1
  91. package/web/_astro/{cose-bilkent-S5V4N54A.Xyiau0gw.js → cose-bilkent-S5V4N54A.B1wSL-Xb.js} +1 -1
  92. package/web/_astro/{cynefin-OW5HDTMX.BeC5MWas.js → cynefin-OW5HDTMX.BmK52w8G.js} +1 -1
  93. package/web/_astro/{dagre-BM42HDAG.yZbMN9vc.js → dagre-BM42HDAG.Bfy5CTDT.js} +2 -2
  94. package/web/_astro/diagram-2AECGRRQ.DhNnvUvX.js +43 -0
  95. package/web/_astro/diagram-5GNKFQAL.lTX5KwnS.js +10 -0
  96. package/web/_astro/{diagram-KO2AKTUF.CR6k3Y3G.js → diagram-KO2AKTUF.CW_vMJ4z.js} +3 -3
  97. package/web/_astro/{diagram-LMA3HP47.x7mwu8jz.js → diagram-LMA3HP47.B_8ZGF67.js} +1 -1
  98. package/web/_astro/{diagram-OG6HWLK6.D8aTTvUr.js → diagram-OG6HWLK6.BppnHsdS.js} +1 -1
  99. package/web/_astro/{erDiagram-TEJ5UH35.BoBqcKXQ.js → erDiagram-TEJ5UH35.BEuHXcjJ.js} +5 -5
  100. package/web/_astro/{flowDiagram-I6XJVG4X.D3mTQdrU.js → flowDiagram-I6XJVG4X.CH-UlnGr.js} +4 -4
  101. package/web/_astro/{ganttDiagram-6RSMTGT7.H-cqgIh-.js → ganttDiagram-6RSMTGT7.BO81S85v.js} +1 -1
  102. package/web/_astro/{gitGraphDiagram-PVQCEYII.B6s9zbfC.js → gitGraphDiagram-PVQCEYII.XnPxPPZN.js} +1 -1
  103. package/web/_astro/index.Hjbr15fG.css +1 -0
  104. package/web/_astro/{infoDiagram-5YYISTIA.BzgCoV6P.js → infoDiagram-5YYISTIA.JyjYRu_T.js} +1 -1
  105. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BZzVhy1-.js → ishikawaDiagram-YF4QCWOH.BBRBF-Fo.js} +5 -5
  106. package/web/_astro/{journeyDiagram-JHISSGLW.BV3195Py.js → journeyDiagram-JHISSGLW.C_iymSyp.js} +1 -1
  107. package/web/_astro/{kanban-definition-UN3LZRKU.BjRd2DWz.js → kanban-definition-UN3LZRKU.DdfW-Oqt.js} +7 -7
  108. package/web/_astro/{linear.BILTgS5N.js → linear.C2_IkbZT.js} +1 -1
  109. package/web/_astro/mermaid.core.GAOYeSR0.js +303 -0
  110. package/web/_astro/{mindmap-definition-RKZ34NQL.BiEjaI4-.js → mindmap-definition-RKZ34NQL.DAZIxQSK.js} +2 -2
  111. package/web/_astro/{pieDiagram-4H26LBE5.i_8V5pIn.js → pieDiagram-4H26LBE5.CN8sIhKM.js} +3 -3
  112. package/web/_astro/{quadrantDiagram-W4KKPZXB.BWaW3MHn.js → quadrantDiagram-W4KKPZXB.3dGcX5GP.js} +1 -1
  113. package/web/_astro/{requirementDiagram-4Y6WPE33.CzddBbtg.js → requirementDiagram-4Y6WPE33.BV2y4dd6.js} +3 -3
  114. package/web/_astro/{sankeyDiagram-5OEKKPKP.X2ww0e-D.js → sankeyDiagram-5OEKKPKP.Cqo15Tvo.js} +4 -4
  115. package/web/_astro/{sequenceDiagram-3UESZ5HK.DSA4kTcc.js → sequenceDiagram-3UESZ5HK.CROCPMJB.js} +1 -1
  116. package/web/_astro/{stateDiagram-AJRCARHV.D0DtFSpR.js → stateDiagram-AJRCARHV.RfXZrkFE.js} +1 -1
  117. package/web/_astro/{stateDiagram-v2-BHNVJYJU.BfQq0zQv.js → stateDiagram-v2-BHNVJYJU.CPXmbBs9.js} +1 -1
  118. package/web/_astro/{timeline-definition-PNZ67QCA.Dmlrgi1m.js → timeline-definition-PNZ67QCA.DdgKTiO8.js} +3 -3
  119. package/web/_astro/{vennDiagram-CIIHVFJN.D5mpl00Z.js → vennDiagram-CIIHVFJN.CPNVSHF1.js} +5 -5
  120. package/web/_astro/{wardleyDiagram-YWT4CUSO.Df4BdzO4.js → wardleyDiagram-YWT4CUSO.CQhA0Jyr.js} +3 -3
  121. package/web/_astro/{xychartDiagram-2RQKCTM6.DiTRreKN.js → xychartDiagram-2RQKCTM6.n61BWyy4.js} +1 -1
  122. package/web/index.html +2 -2
  123. package/web/_astro/BoardApp.CDUcHlTJ.js +0 -188
  124. package/web/_astro/BoardApp.CaCGU_uX.js +0 -1
  125. package/web/_astro/arc.BzF71EFI.js +0 -1
  126. package/web/_astro/channel.SSVY0JPQ.js +0 -1
  127. package/web/_astro/diagram-2AECGRRQ.Cmo2zQM-.js +0 -43
  128. package/web/_astro/diagram-5GNKFQAL.D033eSVi.js +0 -10
  129. package/web/_astro/index.CcU5weKX.css +0 -1
  130. package/web/_astro/mermaid.core.DBy_WKeW.js +0 -301
@@ -7,7 +7,7 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "sp",
10
- "version": "0.3.90",
10
+ "version": "0.3.92",
11
11
  "source": "./plugins/sp"
12
12
  }
13
13
  ]
@@ -36,10 +36,10 @@
36
36
  "decision": null
37
37
  },
38
38
  "history-anatomy": {
39
- "modelQueries": 4,
39
+ "modelQueries": 3,
40
40
  "wallClockMs": null,
41
41
  "tokenCostUsd": null,
42
- "source": "Coverage entry (0826 R2): the live definition's model-query count (extractResolvedWorkflowFacts, 2026-09-11). No real-run measurement yet: wall-clock and cost are unenforced until measured, never 0.",
42
+ "source": "Coverage entry (0826 R2): the live definition's model-query count (extractResolvedWorkflowFacts, 2026-09-11). No real-run measurement yet: wall-clock and cost are unenforced until measured, never 0. 0920 recount 2026-09-23: 4 -> 3 — the resolve-scope model hop was removed; scope/window validation is deterministic in the history-anatomy-cache paths command.",
43
43
  "decision": null
44
44
  },
45
45
  "wayfinder-resolution": {
@@ -48,6 +48,13 @@
48
48
  "tokenCostUsd": null,
49
49
  "source": "Coverage entry (0826 R2): the live definition's model-query count (extractResolvedWorkflowFacts, 2026-09-11). No real-run measurement yet: wall-clock and cost are unenforced until measured, never 0.",
50
50
  "decision": null
51
+ },
52
+ "decision-routing-example": {
53
+ "modelQueries": 0,
54
+ "wallClockMs": null,
55
+ "tokenCostUsd": null,
56
+ "source": "Coverage entry (0911): authoring example (config/workflows/decision-routing-example.yaml) enumerating `decision:` modes. Measured 0 model queries — the producer is a shell action, so the example runs with no provider (live count via loadQueryCounts, 2026-09-20). Not a pipeline humans run; wall-clock and cost unenforced, never 0.",
57
+ "decision": null
51
58
  }
52
59
  }
53
60
  }
@@ -48,7 +48,13 @@
48
48
  },
49
49
  {
50
50
  "rel": "inline-run-setup.ts",
51
- "contract": "repo-only"
51
+ "contract": "standard",
52
+ "twin": "inline-run-setup.mjs"
53
+ },
54
+ {
55
+ "rel": "feature-verification-steps.ts",
56
+ "contract": "standard",
57
+ "twin": "feature-verification-steps.mjs"
52
58
  },
53
59
  {
54
60
  "rel": "idea-coverage-check.ts",
@@ -63,11 +69,21 @@
63
69
  "contract": "standard",
64
70
  "twin": "pr-reviewing.mjs"
65
71
  },
72
+ {
73
+ "rel": "record-feature-sync.ts",
74
+ "contract": "standard",
75
+ "twin": "record-feature-sync.mjs"
76
+ },
66
77
  {
67
78
  "rel": "quality-gate.ts",
68
79
  "contract": "standard",
69
80
  "twin": "quality-gate.mjs"
70
81
  },
82
+ {
83
+ "rel": "residual-scan.ts",
84
+ "contract": "standard",
85
+ "twin": "residual-scan.mjs"
86
+ },
71
87
  {
72
88
  "rel": "script-contract-check.ts",
73
89
  "contract": "repo-only"
@@ -0,0 +1,134 @@
1
+ # DecisionMaker routing example (task 0911, D7). Demonstrates the three `decision:` modes
2
+ # on hitl.* actions; copy the pattern into your own workflow instead of running this file.
3
+ #
4
+ # never — the action always asks the human (DecisionMaker is bypassed even when
5
+ # `workflow.hitlDecisionMaker: true`). Used for gates that must stay human-only.
6
+ # evidence — the DecisionMaker answers from recorded action evidence of the listed producer
7
+ # states: it picks one of the offered choices when confidence >= 0.9, or defers
8
+ # (answer var is cleared, status var records `deferred`) when evidence is missing,
9
+ # stale, or inconclusive. Requires a non-paused state, a statusVar distinct from
10
+ # the answer var, and producer states that exist in this workflow.
11
+ # (omitted) — legacy 0910 semantics: DecisionMaker may confirm/select without evidence and
12
+ # without provenance. Kept for compatibility; prefer an explicit mode.
13
+ #
14
+ # The run is safe and local: one shell producer emits a fixed failure summary, the choose step
15
+ # reads it as evidence, and the operator gate has no side effects. No provider is required —
16
+ # without `workflow.hitlDecisionMaker: true` (or without a key) the evidence step defers and
17
+ # `never` behaves exactly like an unconfigured gate. See `spur self status` -> `decisionMaker`
18
+ # for offline readiness. Optional registered-summary evidence (`summaryArtifact`) is documented
19
+ # in docs/help/how_to_enable_jev_in_spur.md; this example deliberately creates no artifact.
20
+ "$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
21
+ kind: state-machine
22
+ name: decision-routing-example
23
+ version: "1"
24
+ initialState: assess
25
+ description: >
26
+ Worked example of DecisionMaker decision routing (0911 D7): a shell producer records a fixed
27
+ recovery summary as action evidence, a non-pausing hitl.select lets the DecisionMaker choose
28
+ retry or stop from that evidence (deferring with provenance when it is inconclusive), an
29
+ accepted retry runs exactly one attempt and then escalates, and the never-mode pause=true
30
+ hitl.confirm gate always waits for the operator with explicit yes/no/cancel branches.
31
+ Illustrative only — copy the patterns rather than running this file.
32
+ vars:
33
+ recoveryChoice: ""
34
+ decisionStatus: ""
35
+ # Default answer var the never-mode gate's yes/no/cancel branches read (matches the stock gates).
36
+ __hitlAnswer: ""
37
+ states:
38
+ - id: assess
39
+ description: >
40
+ Producer state: one shell action whose redacted output becomes the evidence the decide
41
+ state's DecisionMaker reads. One producer state carries one evidence-bearing action.
42
+ onEnter:
43
+ - kind: shell
44
+ options:
45
+ command: >-
46
+ printf 'Failure summary: verification failed twice on the flaky fixture; no data loss;
47
+ retry is safe, or stop and hand the decision to the operator.'
48
+ - id: decide
49
+ description: >
50
+ Evidence-mode select (non-paused): DecisionMaker picks a recovery step from the assess
51
+ state's recorded evidence. Low confidence, missing or stale evidence defers and writes the
52
+ status variable instead of answering, so no implicit approval is ever produced.
53
+ onEnter:
54
+ - kind: hitl.select
55
+ options:
56
+ prompt: "Choose the next safe recovery step using the recorded failure summary."
57
+ options: [retry, stop]
58
+ var: recoveryChoice
59
+ decision:
60
+ mode: evidence
61
+ statusVar: decisionStatus
62
+ evidenceNodes: [assess]
63
+ - id: retry
64
+ description: >
65
+ The single bounded retry an accepted `retry` choice buys: this state runs once and routes
66
+ to the operator gate, so an accepted answer can never loop back into the decision.
67
+ onEnter:
68
+ - kind: shell
69
+ options:
70
+ command: "printf 'retry attempt: re-running the failed verification step once'"
71
+ - id: humanGate
72
+ description: >
73
+ Never-mode confirm (paused): always waits for the operator, whichever branch reached it.
74
+ `spur workflow continue --answer yes|no|cancel` records the explicit operator answer.
75
+ pause: true
76
+ onEnter:
77
+ - kind: hitl.confirm
78
+ options:
79
+ prompt: "Publish the recovered result, stop, or cancel the run?"
80
+ decision:
81
+ mode: never
82
+ - id: published
83
+ description: Operator approved the recovered result; terminal marker state.
84
+ - id: stop
85
+ description: Recovery stopped deliberately — requested by the decision or rejected by the operator.
86
+ - id: cancelled
87
+ description: Operator cancelled the run at the gate; terminal marker state.
88
+ transitions:
89
+ # Accepted decision branches first: the state machine takes the first passing edge.
90
+ - from: assess
91
+ to: decide
92
+ guard: { kind: always }
93
+ - from: decide
94
+ to: retry
95
+ guard:
96
+ kind: shell
97
+ options:
98
+ command: 'test "$recoveryChoice" = "retry"'
99
+ - from: decide
100
+ to: stop
101
+ guard:
102
+ kind: shell
103
+ options:
104
+ command: 'test "$recoveryChoice" = "stop"'
105
+ # Declared defer edge: evidence mode wrote `deferred` and cleared the answer var.
106
+ - from: decide
107
+ to: humanGate
108
+ guard:
109
+ kind: shell
110
+ options:
111
+ command: 'test "$decisionStatus" = "deferred"'
112
+ - from: retry
113
+ to: humanGate
114
+ guard: { kind: always }
115
+ # Explicit yes / no / cancel branches on the default answer var, matching the stock gates.
116
+ - from: humanGate
117
+ to: published
118
+ guard:
119
+ kind: shell
120
+ options:
121
+ command: 'test "$__hitlAnswer" = "yes"'
122
+ - from: humanGate
123
+ to: stop
124
+ guard:
125
+ kind: shell
126
+ options:
127
+ command: 'test "$__hitlAnswer" = "no"'
128
+ - from: humanGate
129
+ to: cancelled
130
+ guard:
131
+ kind: shell
132
+ options:
133
+ command: 'test "$__hitlAnswer" = "cancel"'
134
+ terminalStates: [published, stop, cancelled]
@@ -40,9 +40,17 @@ states:
40
40
  onEnter:
41
41
  # Caller wiring (task 0880, ADR-119): entering verification RUNS the
42
42
  # feature-scoped pass instead of only passively reading its status file.
43
+ # 0948 R1: pass BOTH vars the inner workflow needs. `--vars` was documented as
44
+ # replace-not-merge and a partial override silently blanked `spurBin`; the engine
45
+ # merges declared defaults today (0948 R2), but the caller stays explicit so the
46
+ # nested run is self-sufficient under either semantic.
43
47
  - kind: shell
44
48
  options:
45
- command: '$spurBin workflow run feature-verification.yaml --vars "{\"featureId\":\"$featureId\"}"'
49
+ # Pass featureId and spurBin together. A partial --vars map used to be
50
+ # applied as a replacement, so the inner run lost spurBin and loadModule
51
+ # fell into source mode (0948 R1). The nested JSON is shell-expanded:
52
+ # $spurBin inside the double quotes keeps a multi-word invocation intact.
53
+ command: '$spurBin workflow run feature-verification.yaml --vars "{\"featureId\":\"$featureId\",\"spurBin\":\"$spurBin\"}"'
46
54
  - id: blocked
47
55
  description: Impediment; work suspended.
48
56
  - id: done
@@ -68,13 +76,14 @@ transitions:
68
76
  - from: verifying
69
77
  to: done
70
78
  description: >
71
- Feature verified — complete. Requires the feature-scoped verification pass
72
- (ADR-119) to have recorded PASS, then strict check (AC validated,
73
- traceability clean).
79
+ Feature verified — complete. The strict check at the done boundary also
80
+ validates the bound verification receipt (D63 task 0915): current, PASS,
81
+ matching feature identity and verifier contract, digest-chained to the
82
+ checked inputs. Stale/missing/failed evidence denies the hop.
74
83
  guard:
75
84
  kind: shell
76
85
  options:
77
- command: 'test "$(cat .spur/run/$featureId-feature-verification.status 2>/dev/null)" = PASS && $spurBin feature check $featureId --strict --as done'
86
+ command: '$spurBin feature check $featureId --strict --as done'
78
87
 
79
88
  # Rework: verifying → active (mandatory History entry)
80
89
  - from: verifying
@@ -1,29 +1,34 @@
1
- # Feature-scoped verification pass (ADR-119, feature D62, task 0872).
1
+ # Feature-scoped verification pass (ADR-119, feature D62, task 0872; D63 task
2
+ # 0915 remediation folds the evidence contract into a workflow-owned script).
2
3
  #
3
4
  # Owns a lifecycle boundary no per-task graph owns: the repo-wide checks whose
4
- # invariant spans the repository rather than a single task's diff — corpus
5
- # consistency, contract baselines, dependency/schema drift, the frozen History
6
- # surface, and the repo-wide test set. They run once per feature, deliberately
7
- # the slow pass; `feature-lifecycle`'s verifying entry invokes this workflow (task
8
- # 0880 caller wiring), and its verifying→done guard refuses to complete the
9
- # feature until this pass records PASS (ADR-119 consequence: a feature is not
10
- # done until it passes).
5
+ # invariant spans the repository rather than a single task's diff. They run
6
+ # once per feature, deliberately the slow pass; `feature-lifecycle`'s verifying
7
+ # entry invokes this workflow (task 0880 caller wiring), and its verifying→done
8
+ # guard refuses to complete the feature until this pass records PASS (ADR-119
9
+ # consequence: a feature is not done until it passes).
11
10
  #
12
- # Run: spur workflow run feature-verification.yaml --vars '{"featureId":"D62"}'
11
+ # Run: spur workflow run feature-verification.yaml --vars '{"featureId":"D63"}'
13
12
  #
14
- # Shape: verify -> done | failed. The shell action writes the verdict to
15
- # `.spur/run/<featureId>-feature-verification.status` and always exits 0; the
16
- # transition guard reads the status so a missing, corrupt or FAIL verdict routes
17
- # to `failed` (fail-closed), never a silent PASS.
13
+ # Shape: verify -> done | failed. The onEnter step runs the standard script
14
+ # `feature-verification-steps.ts` (no public CLI verb, D63 task 0915): it
15
+ # resolves this very definition for the verifier identity (name, source path,
16
+ # layer, definition digest), records the RUNNING receipt (run-scoped +
17
+ # feature-latest copies), registers the run-scoped receipt as a run artifact,
18
+ # runs the configured verification command via the safe launch splitter, and
19
+ # completes the receipt PASS/FAIL with the after-pass proof-input digest. A
20
+ # changed tree during the pass records FAIL.
18
21
  #
19
22
  # Reliability (aligned with task-pipeline / ADR-043): no agent.run nodes; the
20
- # verification command is a trusted config var executed via `sh -c` (same
21
- # surface as task-pipeline's qualityGateCmd — never interpolate untrusted input).
23
+ # verification command comes from `vars.verificationCmd` below and is never
24
+ # interpolated through a shell. The always-exit-0 onEnter means missing,
25
+ # corrupt or FAIL evidence routes to `failed` via the guard (fail-closed),
26
+ # never a silent PASS; infrastructure errors exit nonzero and surface.
22
27
  "$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
23
28
  kind: state-machine
24
29
  name: feature-verification
25
30
  version: "1"
26
- description: "Feature-scoped verification pass (ADR-119): runs the repo-wide check set once per feature and records PASS/FAIL. Invoked by feature-lifecycle's verifying entry."
31
+ description: "Feature-scoped verification pass (ADR-119): runs the repo-wide check set once per feature and records a bound PASS/FAIL evidence receipt. Invoked by feature-lifecycle's verifying entry."
27
32
  iterationBound: 2
28
33
  initialState: verify
29
34
  terminalStates:
@@ -35,37 +40,40 @@ vars:
35
40
  featureId: "X"
36
41
  spurBin: "spur"
37
42
  verificationCmd: "bun run spur-check-feature"
43
+ __runId: ""
38
44
 
39
45
  states:
40
46
  - id: verify
41
47
  description: >
42
- Run the repo-wide check set, record the verdict, always exit 0.
48
+ Run the repo-wide check set via the standard verification script, which
49
+ records the bound evidence receipt (verifier identity, checked-input
50
+ digest, run identity) and the coarse status file, always exit 0 so the
51
+ transition guard routes missing/corrupt/FAIL to `failed`.
43
52
  onEnter:
44
53
  - kind: shell
45
54
  options:
46
55
  command: >-
47
- mkdir -p .spur/run;
48
- sh -c "$verificationCmd" > ".spur/run/$featureId-feature-verification.log" 2>&1
49
- && printf 'PASS\n' > ".spur/run/$featureId-feature-verification.status"
50
- || printf 'FAIL\n' > ".spur/run/$featureId-feature-verification.status";
51
- exit 0
56
+ bun plugins/sp/scripts/feature-verification-steps.ts verify
57
+ --feature-id "$featureId"
58
+ --run-id "$__runId"
59
+ --spur-bin "$spurBin"
52
60
 
53
61
  - id: done
54
- description: Terminal — repo-wide checks passed.
62
+ description: Terminal — repo-wide checks passed and the receipt is bound.
55
63
 
56
64
  - id: failed
57
- description: Terminal — repo-wide checks failed or the verdict is missing/corrupt.
65
+ description: Terminal — repo-wide checks failed or the evidence is missing/corrupt.
58
66
 
59
67
  transitions:
60
68
  - from: verify
61
69
  to: done
62
- description: Repo-wide checks passed — the feature-scoped verification pass records PASS.
70
+ description: Repo-wide checks passed — the script completed the receipt with PASS.
63
71
  guard:
64
72
  kind: shell
65
73
  options:
66
- command: 'test "$(cat .spur/run/$featureId-feature-verification.status 2>/dev/null)" = PASS'
74
+ command: 'test "$(cat .spur/run/$__runId-feature-verification.status 2>/dev/null)" = PASS'
67
75
  - from: verify
68
76
  to: failed
69
- description: Repo-wide checks failed (or the verdict is missing/corrupt) — stop at failed.
77
+ description: Repo-wide checks failed (or the evidence is missing/corrupt) — stop at failed.
70
78
  guard:
71
79
  kind: always
@@ -11,7 +11,7 @@
11
11
  # would exceed the shell composition threshold and be flagged as an owned-capability candidate.
12
12
  #
13
13
  # Shape:
14
- # start -> resolve-scope -> resolve-paths -> analyze -> cache-probe
14
+ # start -> resolve-paths -> analyze -> cache-probe
15
15
  # (hit -> refresh-provenance -> publish -> published)
16
16
  # (miss -> render -> enrich -> structure-gate -> validate -> stamp -> publish)
17
17
  # (structure-gate FAIL -> correct (max 2 total) -> structure-gate; exhausted -> failed)
@@ -28,7 +28,7 @@
28
28
  #
29
29
  # Vars (all must be declared here — the vars: block is the only safe shape; `spur workflow
30
30
  # validate` and the skill-structure test enforce it):
31
- # mode — "daily" (default) | "ad-hoc" (validated in resolve-scope)
31
+ # mode — "daily" (default) | "ad-hoc" (validated deterministically by the helper `paths` command)
32
32
  # date — YYYY-MM-DD for --date (daily); empty for ad-hoc
33
33
  # since — inclusive ISO lower bound (ad-hoc; also normalizes daily via the DST-aware rule)
34
34
  # until — inclusive ISO upper bound (ad-hoc)
@@ -39,7 +39,7 @@
39
39
  # focus — ad-hoc focus string (required in ad-hoc mode, rejected in daily)
40
40
  # recompute — "true" forces the full analyze/render/enrich/validate path (cache disposition
41
41
  # forced-recompute)
42
- # output — explicit report output path; default run directory
42
+ # output — explicit report output path; default docs/report/<date>-history-anatomy.md
43
43
  # agent — executor for the agent.run stages (enrich/validate)
44
44
  # spurBin — PATH-independent spur invocation (overridden by CLI at run start)
45
45
  # __runId — run-scoped id for explicit artifact paths (allocated in start)
@@ -85,28 +85,22 @@ states:
85
85
  description: >
86
86
  Allocate the run-scoped id and root. Every analyze/render path in this workflow writes to
87
87
  an explicit unique path under this run id — no stage reads the mutable latest.json pointer.
88
+ The retained identity is `.spur/run/<runId>-history-anatomy-run.id` (0948 R8). The fixed
89
+ `history-anatomy-run.id` name is only a latest pointer and is overwritten by the next run.
88
90
  onEnter:
89
91
  - kind: shell
90
92
  options:
91
93
  command: >-
92
94
  mkdir -p .spur/run;
93
95
  if [ -z "$__runId" ]; then __runId=$(uuidgen | tr 'A-Z' 'a-z' | cut -c1-8); fi;
94
- echo "$__runId" > .spur/run/history-anatomy-run.id
96
+ echo "$__runId" > ".spur/run/$__runId-history-anatomy-run.id";
97
+ cp ".spur/run/$__runId-history-anatomy-run.id" .spur/run/history-anatomy-run.id
98
+ # 0948 R8 retention disposition: `history-anatomy-run.id` is a SINGLE fixed-name
99
+ # pointer that is overwritten every run — it does not accumulate, so it needs no
100
+ # reclamation path (unlike the run-record pair and legacy `.log` files, which
101
+ # `spur workflow clean --logs` owns). It is deliberately NOT a run record and is
102
+ # exempt from the catalog record-name sweep (see run-record-catalog.test.ts).
95
103
 
96
- - id: resolve-scope
97
- description: >
98
- Dispatch the skill's mode validation (0658 references/modes.md): daily is the default and
99
- rejects focus/since/until/output; ad-hoc requires a non-empty focus plus two ordered
100
- inclusive bounds and rejects --date/--recompute. Writes the normalized selector artifact.
101
- onEnter:
102
- - kind: agent.run
103
- options:
104
- agent: ${vars.agent}
105
- input: "Validate the mode arguments per sp:history-anatomy references/modes.md and write the normalized selector to .spur/run/${vars.__runId}-selector.json. mode=${vars.mode} date=${vars.date} since=${vars.since} until=${vars.until} focus=${vars.focus}. Reject conflicting arguments, naming the offending one; a rejection marks the run failed."
106
- # Declared Layer-1 role (0538 R2): mode validation is a reviewer-standard judgment.
107
- role: reviewer
108
- expectFile: .spur/run/${vars.__runId}-selector.json
109
- timeoutMs: ${vars.stepTimeoutMs}
110
104
 
111
105
  - id: resolve-paths
112
106
  description: >
@@ -122,6 +116,7 @@ states:
122
116
  h=$(superskill script path sp history-anatomy-cache.mjs);
123
117
  node "$h" paths --helper "$h" --report-dir "$reportDir" --date "$date"
124
118
  --output "$output" --mode "$mode" --since "$since" --until "$until"
119
+ --focus "$focus" --recompute "$recompute" --run-id "$__runId"
125
120
  --out .spur/run/$__runId-paths.txt
126
121
 
127
122
  - id: analyze
@@ -338,14 +333,8 @@ states:
338
333
 
339
334
  transitions:
340
335
  - from: start
341
- to: resolve-scope
342
- description: Scope resolved.
343
- guard:
344
- kind: always
345
-
346
- - from: resolve-scope
347
336
  to: resolve-paths
348
- description: Mode valid — resolve helper/skill/target paths once.
337
+ description: Mode/window grammar validated and paths resolved once (deterministic).
349
338
  guard:
350
339
  kind: always
351
340
 
@@ -145,6 +145,8 @@ states:
145
145
  - kind: hitl.confirm
146
146
  options:
147
147
  prompt: "Review the idea evaluation report (.spur/run/${vars.__runId}-idea-eval-report.md). Approve to create a feature, or reject to cancel? (Reject creates no feature.)"
148
+ decision:
149
+ mode: never
148
150
 
149
151
  - id: feature-create
150
152
  description: >
@@ -282,6 +284,8 @@ states:
282
284
  - kind: hitl.confirm
283
285
  options:
284
286
  prompt: "Feature check for ${vars.featureId}. Review the AC and confirm to proceed? Requirement coverage status: $(cat .spur/run/${vars.__runId}-idea-coverage.status 2>/dev/null || echo unknown) — reason: $(cat .spur/run/${vars.__runId}-idea-coverage.reason 2>/dev/null || echo n/a) (.spur/run/${vars.__runId}-idea-coverage.status[.reason]). (Failures route back to ac-generate for revision, capped at 3 retries.)"
287
+ decision:
288
+ mode: never
285
289
 
286
290
  - id: system-design
287
291
  description: >
@@ -358,6 +362,8 @@ states:
358
362
  - kind: hitl.confirm
359
363
  options:
360
364
  prompt: "Review the system design for feature ${vars.featureId}. Approve to proceed to decomposition? To reject, first record your feedback in .spur/run/${vars.__runId}-idea-design-review.md under the `## Operator feedback` heading, then answer no."
365
+ decision:
366
+ mode: never
361
367
 
362
368
  - id: decompose
363
369
  description: >
@@ -416,6 +422,8 @@ states:
416
422
  - kind: hitl.confirm
417
423
  options:
418
424
  prompt: "Batch-create for feature ${vars.featureId}. Review the task batch and confirm to proceed? (Failures route back to decompose for revision, capped at 3 retries.)"
425
+ decision:
426
+ mode: never
419
427
 
420
428
  - id: batch-create-run
421
429
  description: >
@@ -453,10 +461,12 @@ states:
453
461
  plan, ac, decisions, dependencies, premises) so the deterministic task
454
462
  check passes, then writes the run-scoped ready evidence sidecar
455
463
  (.spur/run/${vars.__runId}-idea-ready.json) with one row per task: wbs,
456
- status (ready|failed|skipped), planningDigest, and seven check rows.
457
- Handoff-finalize verifies presence, digest and checklist evidence before
458
- recommending auto runall; missing or failing evidence never fails the
459
- run — it degrades the recommendation to ready-depth refineall.
464
+ status (ready|failed|skipped), planningDigest, and seven check rows,
465
+ with the premises row carrying tree-verified path:line citations
466
+ (0947). Handoff-finalize verifies presence, digest, feature binding and
467
+ checklist evidence before recommending auto runall; missing or failing
468
+ evidence never fails the run — it degrades the recommendation to
469
+ ready-depth refineall.
460
470
  onEnter:
461
471
  - kind: agent.run
462
472
  options:
@@ -475,7 +485,9 @@ states:
475
485
  for feature ${vars.featureId} per sp:spur-dev
476
486
  references/planning-workflow.md § Step 5.6 (Ready preparation): read
477
487
  .spur/run/${vars.__runId}-idea-batch-create-result.json and write
478
- .spur/run/${vars.__runId}-idea-ready.json.
488
+ .spur/run/${vars.__runId}-idea-ready.json. The premises check row passes only
489
+ when each material premise was verified against the current tree and its evidence
490
+ cites at least one verified path:line (handoff-finalize lints it; task 0947).
479
491
  answerFile: .spur/run/${vars.__runId}-ready-prepare-answer.txt
480
492
  expectFile: .spur/run/${vars.__runId}-ready-prepare-answer.txt
481
493
  # Fail-closed shape validation (mirrors the order-sidecar guard). Absence is