@gobing-ai/spur 0.3.72 → 0.3.74

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.example.yaml +48 -27
  3. package/config/pipeline-budgets.json +9 -5
  4. package/config/plugin-scripts.json +4 -0
  5. package/config/proportional-route-table.ts +155 -0
  6. package/config/rules/strict/runtime-boundaries.yaml +1 -1
  7. package/config/rules/structure/protected-files.yaml +3 -0
  8. package/config/task-pipeline-proportional-migration-plan.md +79 -0
  9. package/config/templates/AGENTS.md +5 -0
  10. package/config/templates/docs/99_PROJECT_CONSTITUTION.md +2 -0
  11. package/config/workflows/basic.yaml +5 -2
  12. package/config/workflows/docs-pipeline.yaml +101 -54
  13. package/config/workflows/feature-dev.yaml +57 -27
  14. package/config/workflows/feature-lifecycle.yaml +1 -0
  15. package/config/workflows/history-anatomy.yaml +8 -4
  16. package/config/workflows/idea-pipeline.yaml +66 -33
  17. package/config/workflows/pr-review.yaml +31 -8
  18. package/config/workflows/task-lifecycle.yaml +28 -15
  19. package/config/workflows/task-pipeline.yaml +929 -844
  20. package/config/workflows/wayfinder-resolution.yaml +124 -90
  21. package/config/workflows/wrapup-pipeline.yaml +290 -107
  22. package/package.json +9 -9
  23. package/plugins/sp/plugin.json +1 -1
  24. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +2 -4
  25. package/plugins/sp/scripts/daily-summary/daily-summary.ts +2 -4
  26. package/plugins/sp/scripts/history-anatomy-cache.mjs +7 -1
  27. package/plugins/sp/scripts/history-anatomy-cache.ts +11 -2
  28. package/plugins/sp/scripts/inline-pipeline-parity-check.ts +185 -0
  29. package/plugins/sp/scripts/pr-reviewing.mjs +5 -1
  30. package/plugins/sp/scripts/pr-reviewing.ts +7 -1
  31. package/plugins/sp/scripts/task-evidence-precheck.ts +1 -1
  32. package/plugins/sp/scripts/transition-shim-check.ts +6 -6
  33. package/plugins/sp/scripts/verify-answer-lint.ts +4 -0
  34. package/plugins/sp/skills/pr-reviewing/SKILL.md +4 -1
  35. package/plugins/sp/skills/spur-cli/references/self.md +17 -3
  36. package/plugins/sp/skills/spur-cli/references/tasks.md +1 -1
  37. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +23 -0
  38. package/plugins/sp/skills/spur-cli/references/workflows/workflow-fit-and-tuning.md +5 -5
  39. package/plugins/sp/skills/spur-cli/references/workflows.md +4 -4
  40. package/plugins/sp/skills/spur-dev/SKILL.md +17 -0
  41. package/plugins/sp/skills/spur-dev/references/execution-batch.md +3 -3
  42. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +1 -2
  43. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +20 -0
  44. package/plugins/sp/skills/wayfinder/SKILL.md +1 -1
  45. package/schemas/state-machine-workflow.schema.json +3 -1
  46. package/schemas/transition-flow-workflow.schema.json +3 -1
  47. package/spur.js +12639 -10106
  48. package/web/_astro/{BoardApp.BYCNkMOn.js → BoardApp.C60RJZRj.js} +78 -77
  49. package/web/_astro/BoardApp.ymfj1EHA.js +1 -0
  50. package/web/_astro/{TaskDetail.CgUreSP2.js → TaskDetail.Guk8VuNu.js} +1 -1
  51. package/web/_astro/{arc.BySSh34M.js → arc.CAZtlWJM.js} +1 -1
  52. package/web/_astro/{architectureDiagram-3BPJPVTR.DM46TS_h.js → architectureDiagram-3BPJPVTR.9-XbF_Tz.js} +1 -1
  53. package/web/_astro/{blockDiagram-GPEHLZMM.tZhvNUHA.js → blockDiagram-GPEHLZMM.DC4WLx3L.js} +1 -1
  54. package/web/_astro/{c4Diagram-AAUBKEIU.PT4Or4Nf.js → c4Diagram-AAUBKEIU.JgjUQMgG.js} +1 -1
  55. package/web/_astro/channel.Bxxe2Byc.js +1 -0
  56. package/web/_astro/{chunk-2J33WTMH.J9r0_Bbe.js → chunk-2J33WTMH.D_JFiXa-.js} +1 -1
  57. package/web/_astro/{chunk-4BX2VUAB.hzyeIvhR.js → chunk-4BX2VUAB.Bk_RxoeT.js} +1 -1
  58. package/web/_astro/{chunk-55IACEB6.B0rO7qVh.js → chunk-55IACEB6.a_Rj2VxL.js} +1 -1
  59. package/web/_astro/{chunk-727SXJPM.wE_Uk5D4.js → chunk-727SXJPM.C2NoS1U6.js} +1 -1
  60. package/web/_astro/{chunk-AQP2D5EJ.DqEEjQw7.js → chunk-AQP2D5EJ.D1Xn6CNa.js} +1 -1
  61. package/web/_astro/{chunk-FMBD7UC4.CDoD9sBX.js → chunk-FMBD7UC4.BhJrSBsX.js} +1 -1
  62. package/web/_astro/{chunk-ND2GUHAM.CtX5nF9P.js → chunk-ND2GUHAM.ByVGduYQ.js} +1 -1
  63. package/web/_astro/{chunk-QZHKN3VN.CK_EwfaT.js → chunk-QZHKN3VN.B47Paunq.js} +1 -1
  64. package/web/_astro/{classDiagram-4FO5ZUOK.DLt5a8Lh.js → classDiagram-4FO5ZUOK.BERMSD5C.js} +1 -1
  65. package/web/_astro/{classDiagram-v2-Q7XG4LA2.DLt5a8Lh.js → classDiagram-v2-Q7XG4LA2.BERMSD5C.js} +1 -1
  66. package/web/_astro/{cose-bilkent-S5V4N54A.CMCWP49h.js → cose-bilkent-S5V4N54A.O_rHGlhU.js} +1 -1
  67. package/web/_astro/{cynefin-OW5HDTMX.HyXw_vdS.js → cynefin-OW5HDTMX.qCW2GdNp.js} +1 -1
  68. package/web/_astro/{dagre-BM42HDAG.BTuAzh01.js → dagre-BM42HDAG.C5Y4lH_u.js} +1 -1
  69. package/web/_astro/{diagram-2AECGRRQ.D9dr9wfT.js → diagram-2AECGRRQ.DxZmRXxF.js} +1 -1
  70. package/web/_astro/{diagram-5GNKFQAL.C4Rot0hj.js → diagram-5GNKFQAL.qSxZeYSK.js} +1 -1
  71. package/web/_astro/{diagram-KO2AKTUF.B_TK5uWC.js → diagram-KO2AKTUF.-7vl3bXs.js} +1 -1
  72. package/web/_astro/{diagram-LMA3HP47.JkXKK7CO.js → diagram-LMA3HP47.BHVV-UH3.js} +1 -1
  73. package/web/_astro/{diagram-OG6HWLK6.BzMN8Bd6.js → diagram-OG6HWLK6.DHAuW9sK.js} +1 -1
  74. package/web/_astro/{erDiagram-TEJ5UH35.DVZaWGUd.js → erDiagram-TEJ5UH35.DMRLQwPN.js} +1 -1
  75. package/web/_astro/{flowDiagram-I6XJVG4X.rjEiWUfR.js → flowDiagram-I6XJVG4X.B3EpPp_8.js} +1 -1
  76. package/web/_astro/{ganttDiagram-6RSMTGT7.C_EgAarK.js → ganttDiagram-6RSMTGT7.BgUrExXM.js} +1 -1
  77. package/web/_astro/{gitGraphDiagram-PVQCEYII.B-QQSDsK.js → gitGraphDiagram-PVQCEYII.CU-9yVN4.js} +1 -1
  78. package/web/_astro/{index.B5MTfe7k.css → index.BhvM3djt.css} +1 -1
  79. package/web/_astro/{infoDiagram-5YYISTIA.DlWesz7T.js → infoDiagram-5YYISTIA.CvVTCRLe.js} +1 -1
  80. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BUMZOawi.js → ishikawaDiagram-YF4QCWOH.BUzOfKPf.js} +1 -1
  81. package/web/_astro/{journeyDiagram-JHISSGLW.CWfkxfjY.js → journeyDiagram-JHISSGLW.BBTb7ziz.js} +1 -1
  82. package/web/_astro/{kanban-definition-UN3LZRKU.B-YpMwXf.js → kanban-definition-UN3LZRKU.CTQQr70i.js} +1 -1
  83. package/web/_astro/{linear.D7uqzENp.js → linear.CLKlJPiS.js} +1 -1
  84. package/web/_astro/{mermaid.core.CxrNppBD.js → mermaid.core.BA4wFhLP.js} +4 -4
  85. package/web/_astro/{mindmap-definition-RKZ34NQL.B4Qe7cM2.js → mindmap-definition-RKZ34NQL.t1vG2l5e.js} +1 -1
  86. package/web/_astro/{pieDiagram-4H26LBE5.Ds-5j2ro.js → pieDiagram-4H26LBE5.C8zJhyTu.js} +1 -1
  87. package/web/_astro/{quadrantDiagram-W4KKPZXB.tBd38uNC.js → quadrantDiagram-W4KKPZXB.DqYYvb7T.js} +1 -1
  88. package/web/_astro/{requirementDiagram-4Y6WPE33.sFENkWl3.js → requirementDiagram-4Y6WPE33.lzfDZ9nI.js} +1 -1
  89. package/web/_astro/{sankeyDiagram-5OEKKPKP.BeB-Hk7C.js → sankeyDiagram-5OEKKPKP.lm6N5ORM.js} +1 -1
  90. package/web/_astro/{sequenceDiagram-3UESZ5HK.DnTeaSpx.js → sequenceDiagram-3UESZ5HK.E6_IV4Dj.js} +1 -1
  91. package/web/_astro/{stateDiagram-AJRCARHV.B-8Jt5EJ.js → stateDiagram-AJRCARHV.Bnv6Ok2p.js} +1 -1
  92. package/web/_astro/{stateDiagram-v2-BHNVJYJU.Br7xoqMW.js → stateDiagram-v2-BHNVJYJU.mJHH_Ng_.js} +1 -1
  93. package/web/_astro/{timeline-definition-PNZ67QCA.C-3WdOyi.js → timeline-definition-PNZ67QCA.BhRgqSLa.js} +1 -1
  94. package/web/_astro/{vennDiagram-CIIHVFJN.DCIs7Lc6.js → vennDiagram-CIIHVFJN.pjb5DMC9.js} +1 -1
  95. package/web/_astro/{wardleyDiagram-YWT4CUSO.rGAL-bbz.js → wardleyDiagram-YWT4CUSO.CW20KUng.js} +1 -1
  96. package/web/_astro/{xychartDiagram-2RQKCTM6.hkfQKiRl.js → xychartDiagram-2RQKCTM6.vX9_yuMl.js} +1 -1
  97. package/web/index.html +2 -2
  98. package/config/corpus-baseline.json +0 -1637
  99. package/config/workflow-composition-baseline.json +0 -576
  100. package/web/_astro/BoardApp.E12MFjOS.js +0 -1
  101. package/web/_astro/channel.5cYKr5cs.js +0 -1
@@ -2,15 +2,22 @@
2
2
  # implementation pipeline (no task-pipeline / /sp:dev-run recursion).
3
3
  #
4
4
  # Reliability (aligned with task-pipeline / ADR-043):
5
- # - Soft precheck (task check + show) → failed via transitions (status file, always exit 0)
6
- # - collect fail-closed on non-empty input bundle
7
- # - investigate→verify enforces Testing content floor (0300 R2) before independent verify
8
- # - verify writes machine-readable PASS|PARTIAL|FAIL with expectFile
5
+ # - Soft precheck (task check + show) → failed via transitions (status file, always exit 0);
6
+ # the show capture doubles as the investigate input bundle (0769: the separate collect
7
+ # state re-ran the same CLI reads with no write in between — deleted)
8
+ # - investigate→verify passes only on a non-empty answer capture (fail-closed both ways)
9
+ # - verify is an independent fresh-session observe-only reviewer over the standard verdict
10
+ # contract (`spur task verdict --from-answer` + proof digest bracket + verify-verdict
11
+ # artifact) — 0769 retires the ad-hoc PASS-word file and the >5-line/>60-word padding
12
+ # metrics; evidence citations must still be truthful (grep -n anchors)
9
13
  # - HITL approve routing is exhaustive (yes/no/cancel)
10
- # - record → done is fail-closed on check + actual status=done
14
+ # - record captures `task record` `task update done --no-lifecycle` into a status file;
15
+ # record → done is fail-closed on the captured result + persisted status readback — an
16
+ # exit 0 never converts a denied record into success (0769)
11
17
  # - Free-form agent inputs are intentional: no pure-slash research surface yet
12
18
 
13
19
  "$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
20
+ version: "1"
14
21
  kind: state-machine
15
22
  name: wayfinder-resolution
16
23
  description: "Reusable resolution pipeline for research/specification tasks without invoking the code implementation pipeline"
@@ -33,46 +40,42 @@ vars:
33
40
  resolutionMode: "research"
34
41
  evidencePolicy: "spur-cli-first"
35
42
  __hitlAnswer: ""
43
+ # R8 (0366): injected by WorkflowAppService.run(); run-scopes every capture.
44
+ __runId: ""
45
+ # Resolved per-run by the verify state's taskpath shell step; folded into the proof
46
+ # digest via taskFile (docs/tasks* is excluded from the digest's git-tree half).
47
+ taskSpecPath: ""
48
+ # Proof-state bracket (docs-pipeline precedent): canonical capture at verify entry,
49
+ # live re-capture after the verifier; the verify → record guard compares them.
50
+ proofDigest: ""
51
+ proofDigestNow: ""
36
52
 
37
53
  states:
38
54
  - id: precheck
39
55
  description: >
40
- Soft precheck: task check + show, status files, always exit 0 so failures
41
- route to `failed` via transitions (not a raw lifecycle abort).
56
+ Soft precheck: task check + show, status file, always exit 0 so failures
57
+ route to `failed` via transitions (not a raw lifecycle abort). The `task show`
58
+ capture is reused as the investigate input bundle — no separate collect state
59
+ (0769: same reads, no intervening write, no re-run).
42
60
  onEnter:
43
61
  - kind: shell
44
62
  options:
45
63
  command: >-
46
- mkdir -p .spur/run/wayfinder &&
64
+ mkdir -p .spur/run &&
47
65
  set +e &&
48
66
  $spurBin task check $wbs; check_rc=$?;
49
- $spurBin task show $wbs --json > .spur/run/wayfinder/$wbs-show.json; show_rc=$?;
67
+ $spurBin task show $wbs --json > .spur/run/$__runId-wayfinder-input.json; show_rc=$?;
50
68
  set -e &&
51
69
  if [ "$check_rc" -eq 0 ] && [ "$show_rc" -eq 0 ]; then
52
- printf 'PASS\n' > .spur/run/wayfinder/$wbs-precheck.status;
70
+ printf 'PASS\n' > .spur/run/$__runId-wayfinder-precheck.status;
53
71
  else
54
- printf 'FAIL\n' > .spur/run/wayfinder/$wbs-precheck.status;
72
+ printf 'FAIL\n' > .spur/run/$__runId-wayfinder-precheck.status;
55
73
  fi &&
56
74
  exit 0
57
75
  - kind: note
58
76
  options:
59
77
  message: "Wayfinder resolution started for task ${vars.wbs} (mode=${vars.resolutionMode}, evidence=${vars.evidencePolicy}); no code implementation pipeline is permitted."
60
78
 
61
- - id: collect
62
- description: "Create a deterministic local input bundle before delegation."
63
- onEnter:
64
- - kind: shell
65
- options:
66
- command: "mkdir -p .spur/run/wayfinder && $spurBin task show $wbs --json > .spur/run/wayfinder/$wbs-input.json"
67
- # `wayfinder-resolution.yaml` uses the project→bundled resolver (tasks 0648/0650):
68
- # a bare name falls back to the bundled tree; an explicit project path wins.
69
- - kind: shell
70
- options:
71
- command: "$spurBin workflow validate wayfinder-resolution.yaml > .spur/run/wayfinder/$wbs-workflow-check.txt"
72
- - kind: shell
73
- options:
74
- command: "$spurBin task check $wbs > .spur/run/wayfinder/$wbs-precheck.txt"
75
-
76
79
  - id: investigate
77
80
  description: "Resolve the task's research/specification requirements and author evidence-backed sections through Spur CLI."
78
81
  onEnter:
@@ -85,7 +88,7 @@ states:
85
88
  mode: text
86
89
  input: >-
87
90
  Resolve task ${vars.wbs} in resolution mode ${vars.resolutionMode} using the prepared
88
- local bundle `.spur/run/wayfinder/${vars.wbs}-input.json` and only local shell/file
91
+ local bundle `.spur/run/${vars.__runId}-wayfinder-input.json` and only local shell/file
89
92
  reads plus the `spur` CLI; do not use network search or MCP tools. Do not
90
93
  invoke task-pipeline.yaml, /sp:dev-run, /sp:dev-runall, or code implementation.
91
94
  Read the task file, map its existing Requirements and Acceptance Criteria to the
@@ -93,24 +96,46 @@ states:
93
96
  sections through `spur task update --section --from-file`. Preserve the research
94
97
  boundary. Finish with a short summary and stop. Evidence policy: ${vars.evidencePolicy}.
95
98
 
96
- Evidence-anchor and content contract (mandatory — 0300 R1/R2): when the task's evidence
97
- lives in a shared evidence file (e.g. `.spur/run/wayfinder-O/implementation-evidence.md`),
98
- the `## <wbs>` section you author MUST (a) be substantive — more than 5 lines AND more
99
- than 60 words, covering the task's own requirements, not a generic 2–3 sentence
100
- placeholder; and (b) be anchored truthfully after writing the section, resolve its
101
- real start line with `grep -n "^## <wbs> " <evidence-file>` and use that exact line
102
- number in every Solution/Testing `file:line` citation. NEVER copy a line number from
103
- another ticket's example (e.g. `:5` from an earlier WBS); each WBS anchors to its own
104
- section. Before finishing, re-read each cited line and confirm it names the
105
- requirement's subject (0299 R1 line-anchor rule).
99
+ Evidence-anchor contract (mandatory — 0299 R1 line-anchor rule): when the task's
100
+ evidence lives in a shared evidence file, anchor every Solution/Testing `file:line`
101
+ citation truthfully resolve the section's real start line with
102
+ `grep -n "^## <wbs> " <evidence-file>` and cite that exact line. NEVER copy a line
103
+ number from another ticket's example; each WBS anchors to its own section. Before
104
+ finishing, re-read each cited line and confirm it names the requirement's subject.
105
+ answerFile: .spur/run/${vars.__runId}-wayfinder-answer.md
106
+ expectFile: .spur/run/${vars.__runId}-wayfinder-answer.md
106
107
  timeoutMs: ${vars.stepTimeoutMs}
107
108
 
108
109
  - id: verify
109
- description: "Perform an independent evidence and traceability check for the resolved research task."
110
+ description: >
111
+ Independent, observe-only measured verification (0769): a fresh-session reviewer runs
112
+ /sp:dev-verify --fix none, the standard `spur task verdict` contract derives ONE verdict,
113
+ and a proof-input digest bracket fails closed on verifier-time mutation. Retires the
114
+ ad-hoc resolution-verdict PASS-word file. The verifier never repairs and never edits
115
+ task sections.
110
116
  onEnter:
111
117
  - kind: shell
112
118
  options:
113
- command: "rm -f .spur/run/wayfinder/$wbs-resolution-verdict.txt"
119
+ command: "mkdir -p .spur/run && rm -f .spur/run/$__runId-wayfinder-verify-answer.txt .spur/run/$wbs-verdict.json"
120
+ # Fail-closed task-path lookup (0760 R1 pattern): the resolved path folds into the
121
+ # proof digest via taskFile; a silent miss would degrade the proof to tree-only.
122
+ - kind: shell
123
+ options:
124
+ command: >-
125
+ set -e;
126
+ task_path="$($spurBin task path $wbs --json | jq -r '.path // .filePath // empty')";
127
+ if [ -z "$task_path" ]; then echo "wayfinder-resolution: task path did not resolve for wbs $wbs" >&2; exit 1; fi;
128
+ printf '%s' "$task_path" > ".spur/run/$__runId-wayfinder-taskpath.txt"
129
+ - kind: file.read.into-var
130
+ options:
131
+ path: .spur/run/${vars.__runId}-wayfinder-taskpath.txt
132
+ var: taskSpecPath
133
+ - kind: proof.fingerprint
134
+ options:
135
+ var: proofDigest
136
+ taskFile: ${vars.taskSpecPath}
137
+ input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
138
+ timeoutMs: ${vars.stepTimeoutMs}
114
139
  - kind: agent.run
115
140
  options:
116
141
  agent: ${vars.agent}
@@ -118,15 +143,33 @@ states:
118
143
  # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
119
144
  role: reviewer
120
145
  mode: text
121
- input: >-
122
- Verify resolved task ${vars.wbs} using only local reads and `spur` CLI. Check its
123
- requirements, acceptance scenarios, Solution, Testing, and Review. Confirm workflow
124
- orchestration uses `spur workflow` and execution uses `spur` CLI by default. Run
125
- `spur task check ${vars.wbs}` and update Testing/Review via the CLI only if needed.
126
- Do not implement plugin code. Write the final verdict word (exactly PASS, PARTIAL,
127
- or FAIL, nothing else) to `.spur/run/wayfinder/${vars.wbs}-resolution-verdict.txt`,
128
- then finish with the same verdict and stop.
129
- expectFile: .spur/run/wayfinder/${vars.wbs}-resolution-verdict.txt
146
+ # Observe-only + fresh session (ADR-071 / 0710 R2 precedent): the verifier
147
+ # certifies, it never repairs and never inherits the investigate session.
148
+ freshSession: true
149
+ input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
150
+ answerFile: .spur/run/${vars.__runId}-wayfinder-verify-answer.txt
151
+ expectFile: .spur/run/${vars.__runId}-wayfinder-verify-answer.txt
152
+ timeoutMs: ${vars.stepTimeoutMs}
153
+ - kind: shell
154
+ options:
155
+ command: "$spurBin task verdict $wbs --from-answer .spur/run/$__runId-wayfinder-verify-answer.txt"
156
+ - kind: shell
157
+ options:
158
+ command: >-
159
+ V=".spur/run/$wbs-verdict.json";
160
+ if [ -f "$V" ] && [ -n "$proofDigest" ]; then
161
+ jq --arg d "$proofDigest" --arg r "$__runId" '. + {proof: {digest: $d, capturePoint: "wayfinder-verify-entry", runId: $r}}' "$V" > "$V.tmp" && mv "$V.tmp" "$V";
162
+ fi;
163
+ exit 0
164
+ - kind: run.artifact
165
+ options:
166
+ path: .spur/run/${vars.wbs}-verdict.json
167
+ artifactKind: verify-verdict
168
+ - kind: proof.fingerprint
169
+ options:
170
+ var: proofDigestNow
171
+ taskFile: ${vars.taskSpecPath}
172
+ input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
130
173
  timeoutMs: ${vars.stepTimeoutMs}
131
174
 
132
175
  - id: approve
@@ -138,22 +181,24 @@ states:
138
181
  prompt: "Approve research resolution for task ${vars.wbs}?"
139
182
 
140
183
  - id: record
141
- description: "Record the resolution through the canonical task CLI and transition only after checks pass."
184
+ description: >
185
+ Record the resolution AFTER measured verification (0769). The `task record` verb
186
+ backfills Solution from the diff and moves the task to testing; `task update done
187
+ --no-lifecycle` then completes it (this pipeline's own verify already produced the
188
+ standard verdict evidence). Both results are captured to a run-scoped status file and
189
+ the persisted status is read back — a denied record or a task that never reached done
190
+ routes to `failed` via the guards below and is never converted to success by exit 0.
142
191
  onEnter:
143
- # Both steps are soft (`; exit 0`) BY DESIGN, not laxity: the real gate is the
144
- # `record → done` guard below, which re-runs `spur task check` AND asserts the
145
- # status actually reached done. Hard-failing here aborted the run inside the
146
- # state, so the declared `record → failed` edge was unreachable and a blocked
147
- # lifecycle transition surfaced as a bare "Command exited with 1" instead of
148
- # the terminal `failed` this workflow documents.
149
192
  - kind: shell
150
193
  options:
151
- command: "$spurBin task check $wbs ; exit 0"
152
- - kind: shell
153
- options:
154
- # PASS-only completion (preserve-list P4): lifecycle guards stay on; a forced
155
- # done without verdict evidence is the 0280 regression this replaces (see 0292).
156
- command: "$spurBin task update $wbs done ; exit 0"
194
+ command: >-
195
+ if $spurBin task record $wbs --solution-from-diff --transition testing &&
196
+ $spurBin task update $wbs done --no-lifecycle; then
197
+ printf 'PASS\n' > ".spur/run/$__runId-wayfinder-final.status";
198
+ else
199
+ printf 'FAIL\n' > ".spur/run/$__runId-wayfinder-final.status";
200
+ fi;
201
+ $spurBin task show $wbs --json | jq -r '.status // empty' > ".spur/run/$__runId-wayfinder-status.txt"
157
202
 
158
203
  - id: done
159
204
  description: "Research task resolved and ready to feed the implementation backlog."
@@ -170,52 +215,43 @@ states:
170
215
 
171
216
  transitions:
172
217
  - from: precheck
173
- to: collect
174
- description: "Precheck PASS — collect deterministic local inputs."
218
+ to: investigate
219
+ description: "Precheck PASS — resolve the research task (input bundle captured at precheck)."
175
220
  guard:
176
221
  kind: shell
177
222
  options:
178
- command: 'test "$(cat .spur/run/wayfinder/$wbs-precheck.status 2>/dev/null)" = PASS'
223
+ command: 'test "$(cat .spur/run/$__runId-wayfinder-precheck.status 2>/dev/null)" = PASS'
179
224
  - from: precheck
180
225
  to: failed
181
226
  description: "Precheck FAIL — stop before delegation."
182
227
  guard:
183
228
  kind: always
184
- - from: collect
185
- to: investigate
186
- description: "Input bundle collected — resolve the research task."
187
- guard:
188
- kind: shell
189
- options:
190
- command: "test -s .spur/run/wayfinder/$wbs-input.json && test -s .spur/run/wayfinder/$wbs-precheck.txt"
191
- - from: collect
192
- to: failed
193
- description: "Input collection failed — stop before delegation."
194
- guard:
195
- kind: shell
196
- options:
197
- command: "! test -s .spur/run/wayfinder/$wbs-input.json || ! test -s .spur/run/wayfinder/$wbs-precheck.txt"
198
229
  - from: investigate
199
230
  to: verify
200
- description: "Research resolution authored — verify evidence and traceability. Guard enforces the evidence content floor (0300 R2): the task's Testing section must be non-placeholder (>5 lines, >60 words) before independent verification may begin."
231
+ description: "Research resolution authored — verify evidence and traceability. Guard enforces a non-empty answer capture (fail-closed both ways)."
201
232
  guard:
202
233
  kind: shell
203
234
  options:
204
- command: 'test "$($spurBin task show $wbs --json | jq -r ".content" | awk "/^### Testing/{f=1;next} /^### /{f=0} f" | wc -l)" -gt 5 && test "$($spurBin task show $wbs --json | jq -r ".content" | awk "/^### Testing/{f=1;next} /^### /{f=0} f" | wc -w)" -gt 60'
235
+ command: 'test -s .spur/run/$__runId-wayfinder-answer.md'
205
236
  - from: investigate
206
237
  to: failed
207
- description: "Evidence content floor not met (0300 R2) — investigate authored a placeholder Testing section; stop before verification rather than certify hollow evidence."
238
+ description: "Empty answer capture — investigate produced nothing to verify; stop rather than certify hollow evidence."
208
239
  guard:
209
240
  kind: shell
210
241
  options:
211
- command: 'test "$($spurBin task show $wbs --json | jq -r ".content" | awk "/^### Testing/{f=1;next} /^### /{f=0} f" | wc -l)" -le 5 || test "$($spurBin task show $wbs --json | jq -r ".content" | awk "/^### Testing/{f=1;next} /^### /{f=0} f" | wc -w)" -le 60'
242
+ command: '! test -s .spur/run/$__runId-wayfinder-answer.md'
212
243
  - from: verify
213
244
  to: record
214
- description: "Auto profile — record only on a machine-readable PASS verdict (fail-closed to the approve gate otherwise)."
245
+ description: "Auto profile — record only on a measured PASS verdict with the proof bracket intact (fail-closed to the approve gate otherwise)."
215
246
  guard:
216
247
  kind: shell
217
248
  options:
218
- command: 'test "$approval" = auto && grep -qx PASS .spur/run/wayfinder/$wbs-resolution-verdict.txt'
249
+ command: >-
250
+ test "$approval" = auto &&
251
+ test -n "$proofDigest" &&
252
+ test "$proofDigestNow" = "$proofDigest" &&
253
+ test -f ".spur/run/$wbs-verdict.json" &&
254
+ test "$(jq -r '.verdict // empty' .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS
219
255
  - from: verify
220
256
  to: approve
221
257
  description: "Verification completed — require explicit review approval."
@@ -244,15 +280,13 @@ transitions:
244
280
  command: 'test "$__hitlAnswer" = no'
245
281
  - from: record
246
282
  to: done
247
- description: "Task check passed and the task status is actually done (the lifecycle transition succeeded)."
283
+ description: "Captured record result PASS and the persisted status readback is actually done."
248
284
  guard:
249
285
  kind: shell
250
286
  options:
251
- command: '$spurBin task check $wbs && test "$($spurBin task show $wbs --json | jq -r .status)" = done'
287
+ command: 'test "$(cat .spur/run/$__runId-wayfinder-final.status 2>/dev/null)" = PASS && test "$(cat .spur/run/$__runId-wayfinder-status.txt 2>/dev/null)" = done'
252
288
  - from: record
253
289
  to: failed
254
- description: "Recording/check failed or the task never reached done — stop without claiming completion."
290
+ description: "Recording failed, was denied, or the task never reached done — stop without claiming completion."
255
291
  guard:
256
- kind: shell
257
- options:
258
- command: '! $spurBin task check $wbs || test "$($spurBin task show $wbs --json | jq -r .status)" != done'
292
+ kind: always