@gobing-ai/spur 0.3.30 → 0.3.32
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.
- package/config/rules/strict/runtime-boundaries.yaml +2 -1
- package/config/workflows/basic.yaml +92 -14
- package/config/workflows/docs-pipeline.yaml +71 -25
- package/config/workflows/feature-dev.yaml +104 -35
- package/config/workflows/feature-lifecycle.yaml +10 -2
- package/config/workflows/idea-pipeline.yaml +118 -54
- package/config/workflows/planning-pipeline.yaml +78 -30
- package/config/workflows/task-lifecycle.yaml +10 -2
- package/config/workflows/task-pipeline.yaml +219 -56
- package/config/workflows/wayfinder-resolution.yaml +64 -27
- package/config/workflows/wrapup-pipeline.yaml +79 -39
- package/package.json +9 -9
- package/schemas/state-machine-workflow.schema.json +5 -0
- package/spur.js +1302 -707
- package/web/_astro/BoardApp.CBVEjvSW.js +1 -0
- package/web/_astro/{BoardApp.BwAdAgK9.js → BoardApp.CyyIiK76.js} +74 -74
- package/web/_astro/TaskDetail.BfUuRsfM.js +1 -0
- package/web/_astro/{arc.CO-I_PZe.js → arc.C7fql4LL.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.Si-A1Ncl.js → architectureDiagram-3BPJPVTR.IJPsRX-V.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.CeNy_ta6.js → blockDiagram-GPEHLZMM.B1AUwBxq.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BgN_scEU.js → c4Diagram-AAUBKEIU.BuSJPR3z.js} +1 -1
- package/web/_astro/channel.D3uZSASb.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.C3oDtmdi.js → chunk-2J33WTMH.CaOPTr9l.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.Bv8Fxh4H.js → chunk-4BX2VUAB.DQzxExn8.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.BT-TqtV6.js → chunk-55IACEB6.IIb103c7.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DkGMsI0B.js → chunk-727SXJPM.DOYz1K1b.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.B_-SqGnF.js → chunk-AQP2D5EJ.CFcfW-wt.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.DwR3skMv.js → chunk-FMBD7UC4.C7Hn0jo3.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.BaTQutFl.js → chunk-ND2GUHAM.Ba83VQ1m.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BJMSqqJp.js → chunk-QZHKN3VN.CizNbIIP.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.SaqCNUPF.js → classDiagram-4FO5ZUOK.2NYYPXHq.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.SaqCNUPF.js → classDiagram-v2-Q7XG4LA2.2NYYPXHq.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.BkmjA_E2.js → cose-bilkent-S5V4N54A.DwBqVzml.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.CNUvWhrX.js → dagre-BM42HDAG.DqnYsHWG.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.C68Cg9uE.js → diagram-2AECGRRQ.D8TKhgy-.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.DbHkPLEn.js → diagram-5GNKFQAL.BUD6Prj5.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.Dt0EdErs.js → diagram-KO2AKTUF.Cvg7hmND.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.Bixs6mnm.js → diagram-LMA3HP47.FUG_B9eS.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.B4KBI6KT.js → diagram-OG6HWLK6.XsBZQ0hQ.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.C_4i9Xvx.js → erDiagram-TEJ5UH35.M_LSGgLQ.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.CfGFczAY.js → flowDiagram-I6XJVG4X.DZikZBRa.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.C2AIvtmg.js → ganttDiagram-6RSMTGT7.DTKuEmXY.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.HlXuGqQg.js → gitGraphDiagram-PVQCEYII.Dt-E9XmY.js} +1 -1
- package/web/_astro/index.yAse9IaO.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.BWQJsJ4Z.js → infoDiagram-5YYISTIA.D5snevU1.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.CCHgIHik.js → ishikawaDiagram-YF4QCWOH.DmXdBf9W.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.D9M6YwOJ.js → journeyDiagram-JHISSGLW.HPJSRkkU.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.K20D-a1_.js → kanban-definition-UN3LZRKU.BxCqCnL1.js} +1 -1
- package/web/_astro/{linear.DeP5Qsol.js → linear.BnXQUpS-.js} +1 -1
- package/web/_astro/{mermaid.core.ClzxNMPU.js → mermaid.core.D-ZeOmpg.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.CGn9RUNj.js → mindmap-definition-RKZ34NQL.DxrftiFR.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.CoA92Csb.js → pieDiagram-4H26LBE5.D-ZcWxwg.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.CJ_UPjM1.js → quadrantDiagram-W4KKPZXB.C-dVJ7GW.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.KkEPNNUU.js → requirementDiagram-4Y6WPE33.lalE_R8X.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.CoCWbQgh.js → sankeyDiagram-5OEKKPKP.C4uPynAF.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.DUFpV3EP.js → sequenceDiagram-3UESZ5HK.uBOenkqh.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.CgWX0_9m.js → stateDiagram-AJRCARHV.CQOusSP2.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.BKUXeGSf.js → stateDiagram-v2-BHNVJYJU.Bw0ZdjYb.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.CXayAguY.js → timeline-definition-PNZ67QCA.DbkPA5ce.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DPak_Elh.js → vennDiagram-CIIHVFJN.CIKhzwoA.js} +1 -1
- package/web/_astro/{wardley-L42UT6IY.t3ZlDKd0.js → wardley-L42UT6IY.0P-tqaFs.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.CwPSVASQ.js → wardleyDiagram-YWT4CUSO.DrwTvM_M.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.CJfrQgpF.js → xychartDiagram-2RQKCTM6.BgJsQVms.js} +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.Bk3T0o6s.js +0 -1
- package/web/_astro/TaskDetail.L36slEqE.js +0 -1
- package/web/_astro/channel.CYdGnFHM.js +0 -1
- package/web/_astro/index.D5Wqk2Tw.css +0 -1
|
@@ -6,20 +6,28 @@
|
|
|
6
6
|
# through the normal `spur task update <wbs> <status>` verb so the lifecycle guards
|
|
7
7
|
# (0055) apply identically. Run linkage is written to `task_run_links` (kind=pipeline).
|
|
8
8
|
#
|
|
9
|
-
# Shape: precheck → implement → test → review → approve(HITL)
|
|
9
|
+
# Shape: precheck → implement → test[→test-fix↔test-recheck] → review → approve(HITL)
|
|
10
|
+
# → verify → record → done
|
|
10
11
|
# (precheck failure short-circuits to `failed`; approve routes to `failed` on
|
|
11
12
|
# operator rejection or `cancelled` on operator cancel — R1, bug-750).
|
|
13
|
+
# `test` is the project quality gate (shell + bounded /sp:dev-fixall), not
|
|
14
|
+
# /sp:dev-unit (coverage gap-fill; router C3/C5).
|
|
12
15
|
#
|
|
13
16
|
# Vars (passed as a JSON object via `--vars`):
|
|
14
|
-
# wbs
|
|
15
|
-
# profile
|
|
17
|
+
# wbs — task WBS (required)
|
|
18
|
+
# profile — "auto" skips HITL approve (R4)
|
|
19
|
+
# agent / spurBin — executor + spur binary (CLI overrides spurBin)
|
|
20
|
+
# stepTimeoutMs — agent.run budget for review/verify/test-fix (ms)
|
|
21
|
+
# implementTimeoutMs — implement agent.run budget (ms)
|
|
22
|
+
# qualityGateCmd — project gate (default: bun run autofix && bun run spur-check)
|
|
23
|
+
# qualityGateMaxFixAttempts — max /sp:dev-fixall hops after a red gate (default: 2)
|
|
16
24
|
#
|
|
17
|
-
# Seeded by `spur init
|
|
25
|
+
# Seeded by `spur init`. agent.run inputs are pure slash commands (ADR-043).
|
|
18
26
|
|
|
19
27
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
20
28
|
kind: state-machine
|
|
21
29
|
name: task-pipeline
|
|
22
|
-
description: "Standard task
|
|
30
|
+
description: "Standard task pipeline: precheck → implement → quality-gate (test/fix/recheck) → review → approve → verify → record → done"
|
|
23
31
|
# Task entity lifecycle (owned by task-lifecycle.yaml):
|
|
24
32
|
# normal: backlog → todo → wip → testing → done
|
|
25
33
|
# blocked is bidirectional with todo/wip/testing; done may reopen to wip.
|
|
@@ -35,6 +43,9 @@ terminalStates:
|
|
|
35
43
|
- done
|
|
36
44
|
- failed
|
|
37
45
|
- cancelled
|
|
46
|
+
failureStates:
|
|
47
|
+
- failed
|
|
48
|
+
- cancelled
|
|
38
49
|
vars:
|
|
39
50
|
wbs: "0000"
|
|
40
51
|
profile: "standard"
|
|
@@ -46,17 +57,11 @@ vars:
|
|
|
46
57
|
# `--vars '{"agent":"claude"}'`. Pinned (not left to the AiRunner's <default>
|
|
47
58
|
# selection) so a broken/misconfigured agent on the box can't silently capture the run.
|
|
48
59
|
agent: "omp"
|
|
49
|
-
# Step-level timeout for
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# `.spur/run/*-test-partial.md`), the same failure signature that justified
|
|
55
|
-
# implementTimeoutMs below. Agentic test/review/verify steps read the diff,
|
|
56
|
-
# run the suite, and write a section — that does not fit in 10 min on this
|
|
57
|
-
# corpus. Same honesty rule as implementTimeoutMs: 30 min is headroom, not a
|
|
58
|
-
# licence to run unbounded. If a step still hits this wall, STOP and record it
|
|
59
|
-
# rather than raising again without operator sign-off.
|
|
60
|
+
# Step-level timeout for agentic hops (review / verify / test-fix) in ms.
|
|
61
|
+
# Soft quality-gate shells are unbounded by this var (host shell only).
|
|
62
|
+
# Raised 600s → 1800s (task 0398 R4 / H6 dogfood). Override:
|
|
63
|
+
# `--vars '{"stepTimeoutMs":"120000"}'`. 30 min is headroom, not a licence to
|
|
64
|
+
# run unbounded — if a hop still hits this wall, STOP and record it.
|
|
60
65
|
stepTimeoutMs: "1800000"
|
|
61
66
|
# Timeout for the `implement` step specifically (R2a). Implementation is the
|
|
62
67
|
# heaviest agent.run step (full read/write/test-probe loop) and has timed out
|
|
@@ -67,16 +72,41 @@ vars:
|
|
|
67
72
|
# Answer captured by the approve gate's hitl.confirm (R1): "yes" | "no" | "cancel".
|
|
68
73
|
# Empty by default; only meaningful once the approve state has been entered.
|
|
69
74
|
__hitlAnswer: ""
|
|
75
|
+
# Project quality gate for the `test` hop (probe + fixall + recheck). Override per project
|
|
76
|
+
# with the same package-manager surface (this monorepo is Bun-only):
|
|
77
|
+
# `--vars '{"qualityGateCmd":"bun run lint && bun run test"}'`. Soft probe, hard recheck,
|
|
78
|
+
# and the fixall slash input all use this same var so the command stays single-sourced.
|
|
79
|
+
# TRUSTED CONFIG ONLY — this string is executed via `sh -c` (see test/test-recheck). Never
|
|
80
|
+
# interpolate untrusted operator/LLM input into qualityGateCmd (task 0436 SECUA residual).
|
|
81
|
+
qualityGateCmd: "bun run autofix && bun run spur-check"
|
|
82
|
+
# Max /sp:dev-fixall attempts after a red quality-gate probe/recheck (bounded; no thrash).
|
|
83
|
+
# Attempt counter: .spur/run/<wbs>-test-fix-attempt. Default 2 = two fixall hops before failed.
|
|
84
|
+
qualityGateMaxFixAttempts: "2"
|
|
85
|
+
# Post-implement auto-format. Overridable like qualityGateCmd so a non-Bun seeded
|
|
86
|
+
# project can point it at its own formatter; invoked best-effort (a missing or
|
|
87
|
+
# failing formatter must never abort a run — the quality gate is the real gate).
|
|
88
|
+
formatCmd: "bun run format"
|
|
70
89
|
|
|
71
90
|
states:
|
|
72
91
|
- id: precheck
|
|
73
92
|
description: >
|
|
74
|
-
Pre-flight
|
|
75
|
-
`spur task check <wbs
|
|
93
|
+
Pre-flight: soft agent doctor + transition guards for doctor PASS and
|
|
94
|
+
`spur task check <wbs>`. Failures route to the `failed` terminal state
|
|
95
|
+
(not a raw lifecycle abort mid-enter).
|
|
76
96
|
onEnter:
|
|
97
|
+
# Soft doctor — write status and always exit 0 so transitions can branch to
|
|
98
|
+
# `failed` cleanly (same pattern as the quality-gate soft probe).
|
|
77
99
|
- kind: shell
|
|
78
100
|
options:
|
|
79
|
-
command:
|
|
101
|
+
command: >-
|
|
102
|
+
mkdir -p .spur/run &&
|
|
103
|
+
DOCTOR_FILE=".spur/run/$wbs-precheck-doctor.status" &&
|
|
104
|
+
if $spurBin agent doctor $agent; then
|
|
105
|
+
echo PASS > "$DOCTOR_FILE";
|
|
106
|
+
else
|
|
107
|
+
echo FAIL > "$DOCTOR_FILE";
|
|
108
|
+
fi &&
|
|
109
|
+
exit 0
|
|
80
110
|
- kind: note
|
|
81
111
|
options:
|
|
82
112
|
# R4 task_run_links linkage (kind=pipeline) is written by a WorkflowService
|
|
@@ -101,40 +131,106 @@ states:
|
|
|
101
131
|
- kind: agent.run
|
|
102
132
|
options:
|
|
103
133
|
agent: ${vars.agent}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
`spur workflow run` or `/sp:dev-run` without `--mode implement` —
|
|
108
|
-
this step IS the pipeline (bug-742).
|
|
134
|
+
# Pure slash command only (ADR-043). Anti-recursion / implement discipline
|
|
135
|
+
# lives in /sp:dev-run --mode implement → sp:code-implementation, not YAML prose.
|
|
136
|
+
input: /sp:dev-run --mode implement ${vars.wbs} --auto
|
|
109
137
|
timeoutMs: ${vars.implementTimeoutMs}
|
|
138
|
+
# R3 (task 0424): empty-implement no-op guard — the agent.run action
|
|
139
|
+
# fails the step when exit 0 produced zero non-corpus file changes, so
|
|
140
|
+
# a silent no-op routes the run to `failed` here instead of drifting
|
|
141
|
+
# into test/review and being caught a full pass later.
|
|
142
|
+
requireDiff: true
|
|
110
143
|
- kind: shell
|
|
111
144
|
options:
|
|
112
|
-
command: "$
|
|
145
|
+
command: "$spurBin task update $wbs wip --no-lifecycle"
|
|
113
146
|
# Post-implement cleanup: auto-format any unformatted output the agent produced.
|
|
114
147
|
# The agent may leave files that don't pass `biome check`, which then fails
|
|
115
148
|
# `bun run lint` downstream. Running format here is cheap (< 1 s) and prevents
|
|
116
149
|
# the test stage from tripping on a purely mechanical formatting defect (dogfood
|
|
117
150
|
# bug-733 — omp left agent-run.test.ts unformatted, causing a spurious lint gate
|
|
118
151
|
# failure that the ## Testing section mis-attributed to "pre-existing gaps").
|
|
152
|
+
# Best-effort: `; exit 0` (not `&&`) so a missing/failing formatter in a seeded
|
|
153
|
+
# non-Bun project cannot abort a run mid-implement. Formatting is a convenience;
|
|
154
|
+
# `${vars.qualityGateCmd}` at `test` is the gate that actually decides.
|
|
119
155
|
- kind: shell
|
|
120
156
|
options:
|
|
121
|
-
command:
|
|
157
|
+
command: '$formatCmd ; exit 0'
|
|
122
158
|
|
|
159
|
+
# ── test hop (quality gate + bounded auto-fix) ─────────────────────────────
|
|
160
|
+
# NOT /sp:dev-unit. That command (sp:code-testing) *extends/generates* tests toward
|
|
161
|
+
# a coverage target; it is not the project quality gate. Coverage gap-fill remains
|
|
162
|
+
# available via router C3/C5 (`/sp:dev-unit`) or inside implement — not this hop.
|
|
163
|
+
#
|
|
164
|
+
# Shape (engine has no per-action "run next only if previous failed" without
|
|
165
|
+
# `onError`, and Spur's action schema does not expose `onError`):
|
|
166
|
+
# test — soft probe: qualityGateCmd → PASS|FAIL status; always exit 0
|
|
167
|
+
# (green path: one gate run → review; no fixall/recheck tax)
|
|
168
|
+
# test-fix — increment attempt + pure slash /sp:dev-fixall (≤ max attempts)
|
|
169
|
+
# test-recheck — soft recheck → review | test-fix | failed (never silent lifecycle abort)
|
|
123
170
|
- id: test
|
|
124
|
-
description:
|
|
171
|
+
description: >
|
|
172
|
+
Soft quality-gate probe (single full gate on the green path). Runs
|
|
173
|
+
`${vars.qualityGateCmd}`, records PASS|FAIL under
|
|
174
|
+
`.spur/run/<wbs>-test-gate.status`, resets the fix attempt counter, always exit 0.
|
|
125
175
|
onEnter:
|
|
176
|
+
- kind: shell
|
|
177
|
+
options:
|
|
178
|
+
command: >-
|
|
179
|
+
mkdir -p .spur/run &&
|
|
180
|
+
STATUS_FILE=".spur/run/$wbs-test-gate.status" &&
|
|
181
|
+
ATTEMPT_FILE=".spur/run/$wbs-test-fix-attempt" &&
|
|
182
|
+
echo 0 > "$ATTEMPT_FILE" &&
|
|
183
|
+
set +e &&
|
|
184
|
+
# sh -c re-parses multi-command gates (&&, ;); do NOT use bare `$qualityGateCmd`
|
|
185
|
+
# word-split (breaks on &&). qualityGateCmd is pipeline-owned trusted config only.
|
|
186
|
+
( sh -c "$qualityGateCmd" ); gate_rc=$?; set -e &&
|
|
187
|
+
if [ "$gate_rc" -eq 0 ]; then
|
|
188
|
+
printf 'PASS\n' > "$STATUS_FILE";
|
|
189
|
+
else
|
|
190
|
+
printf 'FAIL\n' > "$STATUS_FILE";
|
|
191
|
+
fi &&
|
|
192
|
+
exit 0
|
|
193
|
+
|
|
194
|
+
- id: test-fix
|
|
195
|
+
description: >
|
|
196
|
+
Bounded auto-fix hop when the quality gate is red. Increments
|
|
197
|
+
`.spur/run/<wbs>-test-fix-attempt`, then pure slash (ADR-043)
|
|
198
|
+
`/sp:dev-fixall` against `${vars.qualityGateCmd}`.
|
|
199
|
+
onEnter:
|
|
200
|
+
- kind: shell
|
|
201
|
+
options:
|
|
202
|
+
command: >-
|
|
203
|
+
mkdir -p .spur/run &&
|
|
204
|
+
ATTEMPT_FILE=".spur/run/$wbs-test-fix-attempt" &&
|
|
205
|
+
n=$(cat "$ATTEMPT_FILE" 2>/dev/null || echo 0) &&
|
|
206
|
+
printf '%s\n' "$((n + 1))" > "$ATTEMPT_FILE"
|
|
126
207
|
- kind: agent.run
|
|
127
208
|
options:
|
|
128
209
|
agent: ${vars.agent}
|
|
129
|
-
input: /sp:dev-
|
|
210
|
+
input: /sp:dev-fixall "${vars.qualityGateCmd}"
|
|
130
211
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
212
|
+
|
|
213
|
+
- id: test-recheck
|
|
214
|
+
description: >
|
|
215
|
+
Soft recheck after fixall. Writes PASS|FAIL (always exit 0). Transitions
|
|
216
|
+
branch to review (PASS), another test-fix (FAIL and under max attempts),
|
|
217
|
+
or the pipeline `failed` state (FAIL and attempts exhausted) — never a
|
|
218
|
+
raw lifecycle abort that skips the terminal `failed` state.
|
|
219
|
+
onEnter:
|
|
135
220
|
- kind: shell
|
|
136
221
|
options:
|
|
137
|
-
command:
|
|
222
|
+
command: >-
|
|
223
|
+
mkdir -p .spur/run &&
|
|
224
|
+
STATUS_FILE=".spur/run/$wbs-test-gate.status" &&
|
|
225
|
+
set +e &&
|
|
226
|
+
# See test probe: sh -c for multi-command; qualityGateCmd is trusted config only.
|
|
227
|
+
( sh -c "$qualityGateCmd" ); gate_rc=$?; set -e &&
|
|
228
|
+
if [ "$gate_rc" -eq 0 ]; then
|
|
229
|
+
printf 'PASS\n' > "$STATUS_FILE";
|
|
230
|
+
else
|
|
231
|
+
printf 'FAIL\n' > "$STATUS_FILE";
|
|
232
|
+
fi &&
|
|
233
|
+
exit 0
|
|
138
234
|
|
|
139
235
|
- id: review
|
|
140
236
|
description: Three-dimensional code review via /sp:dev-review (functional requirements traceability + SECUA framework (Security, Efficiency, Correctness, Usability, Architecture) + architecture depth), findings written to `## Review`.
|
|
@@ -175,7 +271,7 @@ states:
|
|
|
175
271
|
answerFile: .spur/run/${vars.wbs}-verify-answer.txt
|
|
176
272
|
- kind: shell
|
|
177
273
|
options:
|
|
178
|
-
command: "$
|
|
274
|
+
command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
|
|
179
275
|
|
|
180
276
|
- id: record
|
|
181
277
|
description: >
|
|
@@ -188,10 +284,28 @@ states:
|
|
|
188
284
|
onEnter:
|
|
189
285
|
- kind: shell
|
|
190
286
|
options:
|
|
191
|
-
command: "$
|
|
287
|
+
command: "$spurBin task record $wbs --solution-from-diff --transition testing"
|
|
288
|
+
# Best-effort, and portable across layouts. `feature-sync-bounded.ts` is a
|
|
289
|
+
# Spur-monorepo path — `spur init` never scaffolds `plugins/sp/`, so a seeded
|
|
290
|
+
# project must fall back to the plain `spur feature sync` verb rather than
|
|
291
|
+
# abort a run that already produced a PASS verdict. Trailing `exit 0` keeps the
|
|
292
|
+
# whole step advisory for the same reason (feature status sync is a follow-up,
|
|
293
|
+
# not a completion gate — `record → done` runs `spur task check`).
|
|
192
294
|
- kind: shell
|
|
193
295
|
options:
|
|
194
|
-
command:
|
|
296
|
+
command: >-
|
|
297
|
+
FID=$($spurBin task show $wbs --json 2>/dev/null |
|
|
298
|
+
jq -r ".feature_id // .frontmatter.feature_id // empty" 2>/dev/null);
|
|
299
|
+
if [ -n "$FID" ]; then
|
|
300
|
+
if [ -f plugins/sp/scripts/feature-sync-bounded.ts ]; then
|
|
301
|
+
bun plugins/sp/scripts/feature-sync-bounded.ts "$FID" --spur-bin "$spurBin" --json;
|
|
302
|
+
else
|
|
303
|
+
$spurBin feature sync "$FID" --json;
|
|
304
|
+
fi;
|
|
305
|
+
else
|
|
306
|
+
echo "Orphan task $wbs — no feature_id linked; proposal: consider linking to a parent feature." >> ".spur/run/$wbs-report.txt";
|
|
307
|
+
fi;
|
|
308
|
+
exit 0
|
|
195
309
|
|
|
196
310
|
- id: done
|
|
197
311
|
description: >
|
|
@@ -201,47 +315,96 @@ states:
|
|
|
201
315
|
onEnter:
|
|
202
316
|
- kind: shell
|
|
203
317
|
options:
|
|
204
|
-
command: "$
|
|
318
|
+
command: "$spurBin task update $wbs done --no-lifecycle"
|
|
205
319
|
- kind: note
|
|
206
320
|
options:
|
|
207
321
|
message: "Pipeline complete for task ${vars.wbs} (done gate cleared)."
|
|
208
322
|
# Checkpoint write: record session state for resume (Phase 4, task 0171 R3)
|
|
209
323
|
- kind: shell
|
|
210
324
|
options:
|
|
211
|
-
command: 'mkdir -p .spur/memory/sessions && echo "checkpoint: task-pipeline done wbs=$
|
|
325
|
+
command: 'mkdir -p .spur/memory/sessions && echo "checkpoint: task-pipeline done wbs=$wbs ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)" > .spur/memory/sessions/$wbs-checkpoint.md'
|
|
212
326
|
|
|
213
327
|
- id: failed
|
|
214
|
-
description:
|
|
328
|
+
description: >
|
|
329
|
+
Terminal — precheck, quality-gate exhaustion, verify non-PASS, record check
|
|
330
|
+
failure, or operator rejection; reported, not advanced.
|
|
215
331
|
|
|
216
332
|
- id: cancelled
|
|
217
333
|
description: Terminal — pipeline cancelled by operator at the approval gate (R1).
|
|
218
334
|
|
|
219
335
|
transitions:
|
|
220
|
-
# ── precheck:
|
|
336
|
+
# ── precheck: doctor PASS + task check → implement; else → failed ──
|
|
221
337
|
- from: precheck
|
|
222
338
|
to: implement
|
|
223
|
-
description:
|
|
339
|
+
description: Agent doctor PASS and task check green — begin implementation.
|
|
224
340
|
guard:
|
|
225
341
|
kind: shell
|
|
226
342
|
options:
|
|
227
|
-
command: "$
|
|
343
|
+
command: 'test "$(cat .spur/run/$wbs-precheck-doctor.status 2>/dev/null)" = PASS && $spurBin task check $wbs'
|
|
228
344
|
- from: precheck
|
|
229
345
|
to: failed
|
|
230
|
-
description:
|
|
346
|
+
description: Doctor FAIL and/or task check failed — stop before implement.
|
|
231
347
|
guard:
|
|
232
|
-
kind:
|
|
233
|
-
options:
|
|
234
|
-
command: '! ${vars.spurBin} task check ${vars.wbs}'
|
|
348
|
+
kind: always
|
|
235
349
|
|
|
236
350
|
# ── linear body ──
|
|
237
351
|
- from: implement
|
|
238
352
|
to: test
|
|
239
|
-
description: Implementation done —
|
|
353
|
+
description: Implementation done — quality-gate probe.
|
|
240
354
|
guard:
|
|
241
355
|
kind: always
|
|
356
|
+
# Soft probe branching (declaration order: PASS first, then FAIL, then defense).
|
|
242
357
|
- from: test
|
|
243
358
|
to: review
|
|
244
|
-
description:
|
|
359
|
+
description: Quality gate already green — one gate run only; skip fixall/recheck.
|
|
360
|
+
guard:
|
|
361
|
+
kind: shell
|
|
362
|
+
options:
|
|
363
|
+
command: 'test "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)" = PASS'
|
|
364
|
+
- from: test
|
|
365
|
+
to: test-fix
|
|
366
|
+
description: Quality gate red — start bounded fixall loop.
|
|
367
|
+
guard:
|
|
368
|
+
kind: shell
|
|
369
|
+
options:
|
|
370
|
+
command: 'test "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)" = FAIL'
|
|
371
|
+
# Defense: missing/corrupt status — treat as FAIL path, not silent PASS.
|
|
372
|
+
- from: test
|
|
373
|
+
to: test-fix
|
|
374
|
+
description: Probe status missing/corrupt — attempt fixall then recheck.
|
|
375
|
+
guard:
|
|
376
|
+
kind: always
|
|
377
|
+
- from: test-fix
|
|
378
|
+
to: test-recheck
|
|
379
|
+
description: Fixall finished — soft recheck the same quality gate.
|
|
380
|
+
guard:
|
|
381
|
+
kind: always
|
|
382
|
+
# Recheck branching (PASS first; under-max FAIL → fixall again; exhausted → failed).
|
|
383
|
+
- from: test-recheck
|
|
384
|
+
to: review
|
|
385
|
+
description: Quality gate green after fixall — proceed to review.
|
|
386
|
+
guard:
|
|
387
|
+
kind: shell
|
|
388
|
+
options:
|
|
389
|
+
command: 'test "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)" = PASS'
|
|
390
|
+
- from: test-recheck
|
|
391
|
+
to: test-fix
|
|
392
|
+
description: Still red and under qualityGateMaxFixAttempts — another fixall hop.
|
|
393
|
+
guard:
|
|
394
|
+
kind: shell
|
|
395
|
+
options:
|
|
396
|
+
command: 'test "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)" = FAIL && test "$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)" -lt "$qualityGateMaxFixAttempts"'
|
|
397
|
+
- from: test-recheck
|
|
398
|
+
to: failed
|
|
399
|
+
description: Still red after max fixall attempts — stop at failed (not silent abort).
|
|
400
|
+
guard:
|
|
401
|
+
kind: shell
|
|
402
|
+
options:
|
|
403
|
+
command: 'test "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)" = FAIL && test "$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)" -ge "$qualityGateMaxFixAttempts"'
|
|
404
|
+
# Defense: corrupt recheck status — failed, not review.
|
|
405
|
+
- from: test-recheck
|
|
406
|
+
to: failed
|
|
407
|
+
description: Recheck status missing/corrupt — stop at failed.
|
|
245
408
|
guard:
|
|
246
409
|
kind: always
|
|
247
410
|
# ── review → approve, OR skip the HITL gate entirely when profile=auto (R4) ──
|
|
@@ -255,7 +418,7 @@ transitions:
|
|
|
255
418
|
guard:
|
|
256
419
|
kind: shell
|
|
257
420
|
options:
|
|
258
|
-
command: 'test "$
|
|
421
|
+
command: 'test "$profile" = auto'
|
|
259
422
|
- from: review
|
|
260
423
|
to: approve
|
|
261
424
|
description: Review done — gate on human approval.
|
|
@@ -273,21 +436,21 @@ transitions:
|
|
|
273
436
|
guard:
|
|
274
437
|
kind: shell
|
|
275
438
|
options:
|
|
276
|
-
command: 'test "$
|
|
439
|
+
command: 'test "$__hitlAnswer" = yes'
|
|
277
440
|
- from: approve
|
|
278
441
|
to: failed
|
|
279
442
|
description: Operator rejected at the approval gate — report and stop.
|
|
280
443
|
guard:
|
|
281
444
|
kind: shell
|
|
282
445
|
options:
|
|
283
|
-
command: 'test "$
|
|
446
|
+
command: 'test "$__hitlAnswer" = no'
|
|
284
447
|
- from: approve
|
|
285
448
|
to: cancelled
|
|
286
449
|
description: Operator cancelled at the approval gate.
|
|
287
450
|
guard:
|
|
288
451
|
kind: shell
|
|
289
452
|
options:
|
|
290
|
-
command: 'test "$
|
|
453
|
+
command: 'test "$__hitlAnswer" = cancel'
|
|
291
454
|
|
|
292
455
|
# ── completion gate (the YAML-native replacement for rd3's default-on --postflight-verify) ──
|
|
293
456
|
# The verify step emits .spur/run/<wbs>-verdict.json. Only `verdict: PASS` clears
|
|
@@ -299,14 +462,14 @@ transitions:
|
|
|
299
462
|
guard:
|
|
300
463
|
kind: shell
|
|
301
464
|
options:
|
|
302
|
-
command: 'test "$(jq -r .verdict .spur/run/$
|
|
465
|
+
command: 'test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS'
|
|
303
466
|
- from: verify
|
|
304
467
|
to: failed
|
|
305
468
|
description: Verification verdict is not PASS (PARTIAL/FAIL/missing) — block before done.
|
|
306
469
|
guard:
|
|
307
470
|
kind: shell
|
|
308
471
|
options:
|
|
309
|
-
command: 'test "$(jq -r .verdict .spur/run/$
|
|
472
|
+
command: 'test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" != PASS'
|
|
310
473
|
# ── done gate: record → done/failed gated on `spur task check` (ADR-026 amendment 2026-06-23) ──
|
|
311
474
|
# The record step guarantees every done-required section ([Solution, Testing, Review])
|
|
312
475
|
# has real content (each owned by its pipeline step). This guard is defense-in-depth —
|
|
@@ -318,11 +481,11 @@ transitions:
|
|
|
318
481
|
guard:
|
|
319
482
|
kind: shell
|
|
320
483
|
options:
|
|
321
|
-
command: "$
|
|
484
|
+
command: "$spurBin task check $wbs"
|
|
322
485
|
- from: record
|
|
323
486
|
to: failed
|
|
324
487
|
description: Task check failed — block before done; investigate missing sections.
|
|
325
488
|
guard:
|
|
326
489
|
kind: shell
|
|
327
490
|
options:
|
|
328
|
-
command: '! $
|
|
491
|
+
command: '! $spurBin task check $wbs'
|