@gobing-ai/spur 0.3.29 → 0.3.31
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/templates/AGENTS.md +3 -8
- package/config/templates/docs/04_DESIGN.md +8 -5
- package/config/templates/docs/99_PROJECT_CONSTITUTION.md +4 -2
- 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 +214 -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 +1306 -764
- 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,39 @@ 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
|
+
qualityGateCmd: "bun run autofix && bun run spur-check"
|
|
80
|
+
# Max /sp:dev-fixall attempts after a red quality-gate probe/recheck (bounded; no thrash).
|
|
81
|
+
# Attempt counter: .spur/run/<wbs>-test-fix-attempt. Default 2 = two fixall hops before failed.
|
|
82
|
+
qualityGateMaxFixAttempts: "2"
|
|
83
|
+
# Post-implement auto-format. Overridable like qualityGateCmd so a non-Bun seeded
|
|
84
|
+
# project can point it at its own formatter; invoked best-effort (a missing or
|
|
85
|
+
# failing formatter must never abort a run — the quality gate is the real gate).
|
|
86
|
+
formatCmd: "bun run format"
|
|
70
87
|
|
|
71
88
|
states:
|
|
72
89
|
- id: precheck
|
|
73
90
|
description: >
|
|
74
|
-
Pre-flight
|
|
75
|
-
`spur task check <wbs
|
|
91
|
+
Pre-flight: soft agent doctor + transition guards for doctor PASS and
|
|
92
|
+
`spur task check <wbs>`. Failures route to the `failed` terminal state
|
|
93
|
+
(not a raw lifecycle abort mid-enter).
|
|
76
94
|
onEnter:
|
|
95
|
+
# Soft doctor — write status and always exit 0 so transitions can branch to
|
|
96
|
+
# `failed` cleanly (same pattern as the quality-gate soft probe).
|
|
77
97
|
- kind: shell
|
|
78
98
|
options:
|
|
79
|
-
command:
|
|
99
|
+
command: >-
|
|
100
|
+
mkdir -p .spur/run &&
|
|
101
|
+
DOCTOR_FILE=".spur/run/$wbs-precheck-doctor.status" &&
|
|
102
|
+
if $spurBin agent doctor $agent; then
|
|
103
|
+
echo PASS > "$DOCTOR_FILE";
|
|
104
|
+
else
|
|
105
|
+
echo FAIL > "$DOCTOR_FILE";
|
|
106
|
+
fi &&
|
|
107
|
+
exit 0
|
|
80
108
|
- kind: note
|
|
81
109
|
options:
|
|
82
110
|
# R4 task_run_links linkage (kind=pipeline) is written by a WorkflowService
|
|
@@ -101,40 +129,103 @@ states:
|
|
|
101
129
|
- kind: agent.run
|
|
102
130
|
options:
|
|
103
131
|
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).
|
|
132
|
+
# Pure slash command only (ADR-043). Anti-recursion / implement discipline
|
|
133
|
+
# lives in /sp:dev-run --mode implement → sp:code-implementation, not YAML prose.
|
|
134
|
+
input: /sp:dev-run --mode implement ${vars.wbs} --auto
|
|
109
135
|
timeoutMs: ${vars.implementTimeoutMs}
|
|
136
|
+
# R3 (task 0424): empty-implement no-op guard — the agent.run action
|
|
137
|
+
# fails the step when exit 0 produced zero non-corpus file changes, so
|
|
138
|
+
# a silent no-op routes the run to `failed` here instead of drifting
|
|
139
|
+
# into test/review and being caught a full pass later.
|
|
140
|
+
requireDiff: true
|
|
110
141
|
- kind: shell
|
|
111
142
|
options:
|
|
112
|
-
command: "$
|
|
143
|
+
command: "$spurBin task update $wbs wip --no-lifecycle"
|
|
113
144
|
# Post-implement cleanup: auto-format any unformatted output the agent produced.
|
|
114
145
|
# The agent may leave files that don't pass `biome check`, which then fails
|
|
115
146
|
# `bun run lint` downstream. Running format here is cheap (< 1 s) and prevents
|
|
116
147
|
# the test stage from tripping on a purely mechanical formatting defect (dogfood
|
|
117
148
|
# bug-733 — omp left agent-run.test.ts unformatted, causing a spurious lint gate
|
|
118
149
|
# failure that the ## Testing section mis-attributed to "pre-existing gaps").
|
|
150
|
+
# Best-effort: `; exit 0` (not `&&`) so a missing/failing formatter in a seeded
|
|
151
|
+
# non-Bun project cannot abort a run mid-implement. Formatting is a convenience;
|
|
152
|
+
# `${vars.qualityGateCmd}` at `test` is the gate that actually decides.
|
|
119
153
|
- kind: shell
|
|
120
154
|
options:
|
|
121
|
-
command:
|
|
155
|
+
command: '$formatCmd ; exit 0'
|
|
122
156
|
|
|
157
|
+
# ── test hop (quality gate + bounded auto-fix) ─────────────────────────────
|
|
158
|
+
# NOT /sp:dev-unit. That command (sp:code-testing) *extends/generates* tests toward
|
|
159
|
+
# a coverage target; it is not the project quality gate. Coverage gap-fill remains
|
|
160
|
+
# available via router C3/C5 (`/sp:dev-unit`) or inside implement — not this hop.
|
|
161
|
+
#
|
|
162
|
+
# Shape (engine has no per-action "run next only if previous failed" without
|
|
163
|
+
# `onError`, and Spur's action schema does not expose `onError`):
|
|
164
|
+
# test — soft probe: qualityGateCmd → PASS|FAIL status; always exit 0
|
|
165
|
+
# (green path: one gate run → review; no fixall/recheck tax)
|
|
166
|
+
# test-fix — increment attempt + pure slash /sp:dev-fixall (≤ max attempts)
|
|
167
|
+
# test-recheck — soft recheck → review | test-fix | failed (never silent lifecycle abort)
|
|
123
168
|
- id: test
|
|
124
|
-
description:
|
|
169
|
+
description: >
|
|
170
|
+
Soft quality-gate probe (single full gate on the green path). Runs
|
|
171
|
+
`${vars.qualityGateCmd}`, records PASS|FAIL under
|
|
172
|
+
`.spur/run/<wbs>-test-gate.status`, resets the fix attempt counter, always exit 0.
|
|
125
173
|
onEnter:
|
|
174
|
+
- kind: shell
|
|
175
|
+
options:
|
|
176
|
+
command: >-
|
|
177
|
+
mkdir -p .spur/run &&
|
|
178
|
+
STATUS_FILE=".spur/run/$wbs-test-gate.status" &&
|
|
179
|
+
ATTEMPT_FILE=".spur/run/$wbs-test-fix-attempt" &&
|
|
180
|
+
echo 0 > "$ATTEMPT_FILE" &&
|
|
181
|
+
set +e &&
|
|
182
|
+
( $qualityGateCmd ); gate_rc=$?; set -e &&
|
|
183
|
+
if [ "$gate_rc" -eq 0 ]; then
|
|
184
|
+
printf 'PASS\n' > "$STATUS_FILE";
|
|
185
|
+
else
|
|
186
|
+
printf 'FAIL\n' > "$STATUS_FILE";
|
|
187
|
+
fi &&
|
|
188
|
+
exit 0
|
|
189
|
+
|
|
190
|
+
- id: test-fix
|
|
191
|
+
description: >
|
|
192
|
+
Bounded auto-fix hop when the quality gate is red. Increments
|
|
193
|
+
`.spur/run/<wbs>-test-fix-attempt`, then pure slash (ADR-043)
|
|
194
|
+
`/sp:dev-fixall` against `${vars.qualityGateCmd}`.
|
|
195
|
+
onEnter:
|
|
196
|
+
- kind: shell
|
|
197
|
+
options:
|
|
198
|
+
command: >-
|
|
199
|
+
mkdir -p .spur/run &&
|
|
200
|
+
ATTEMPT_FILE=".spur/run/$wbs-test-fix-attempt" &&
|
|
201
|
+
n=$(cat "$ATTEMPT_FILE" 2>/dev/null || echo 0) &&
|
|
202
|
+
printf '%s\n' "$((n + 1))" > "$ATTEMPT_FILE"
|
|
126
203
|
- kind: agent.run
|
|
127
204
|
options:
|
|
128
205
|
agent: ${vars.agent}
|
|
129
|
-
input: /sp:dev-
|
|
206
|
+
input: /sp:dev-fixall "${vars.qualityGateCmd}"
|
|
130
207
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
208
|
+
|
|
209
|
+
- id: test-recheck
|
|
210
|
+
description: >
|
|
211
|
+
Soft recheck after fixall. Writes PASS|FAIL (always exit 0). Transitions
|
|
212
|
+
branch to review (PASS), another test-fix (FAIL and under max attempts),
|
|
213
|
+
or the pipeline `failed` state (FAIL and attempts exhausted) — never a
|
|
214
|
+
raw lifecycle abort that skips the terminal `failed` state.
|
|
215
|
+
onEnter:
|
|
135
216
|
- kind: shell
|
|
136
217
|
options:
|
|
137
|
-
command:
|
|
218
|
+
command: >-
|
|
219
|
+
mkdir -p .spur/run &&
|
|
220
|
+
STATUS_FILE=".spur/run/$wbs-test-gate.status" &&
|
|
221
|
+
set +e &&
|
|
222
|
+
( $qualityGateCmd ); gate_rc=$?; set -e &&
|
|
223
|
+
if [ "$gate_rc" -eq 0 ]; then
|
|
224
|
+
printf 'PASS\n' > "$STATUS_FILE";
|
|
225
|
+
else
|
|
226
|
+
printf 'FAIL\n' > "$STATUS_FILE";
|
|
227
|
+
fi &&
|
|
228
|
+
exit 0
|
|
138
229
|
|
|
139
230
|
- id: review
|
|
140
231
|
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 +266,7 @@ states:
|
|
|
175
266
|
answerFile: .spur/run/${vars.wbs}-verify-answer.txt
|
|
176
267
|
- kind: shell
|
|
177
268
|
options:
|
|
178
|
-
command: "$
|
|
269
|
+
command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
|
|
179
270
|
|
|
180
271
|
- id: record
|
|
181
272
|
description: >
|
|
@@ -188,10 +279,28 @@ states:
|
|
|
188
279
|
onEnter:
|
|
189
280
|
- kind: shell
|
|
190
281
|
options:
|
|
191
|
-
command: "$
|
|
282
|
+
command: "$spurBin task record $wbs --solution-from-diff --transition testing"
|
|
283
|
+
# Best-effort, and portable across layouts. `feature-sync-bounded.ts` is a
|
|
284
|
+
# Spur-monorepo path — `spur init` never scaffolds `plugins/sp/`, so a seeded
|
|
285
|
+
# project must fall back to the plain `spur feature sync` verb rather than
|
|
286
|
+
# abort a run that already produced a PASS verdict. Trailing `exit 0` keeps the
|
|
287
|
+
# whole step advisory for the same reason (feature status sync is a follow-up,
|
|
288
|
+
# not a completion gate — `record → done` runs `spur task check`).
|
|
192
289
|
- kind: shell
|
|
193
290
|
options:
|
|
194
|
-
command:
|
|
291
|
+
command: >-
|
|
292
|
+
FID=$($spurBin task show $wbs --json 2>/dev/null |
|
|
293
|
+
jq -r ".feature_id // .frontmatter.feature_id // empty" 2>/dev/null);
|
|
294
|
+
if [ -n "$FID" ]; then
|
|
295
|
+
if [ -f plugins/sp/scripts/feature-sync-bounded.ts ]; then
|
|
296
|
+
bun plugins/sp/scripts/feature-sync-bounded.ts "$FID" --spur-bin "$spurBin" --json;
|
|
297
|
+
else
|
|
298
|
+
$spurBin feature sync "$FID" --json;
|
|
299
|
+
fi;
|
|
300
|
+
else
|
|
301
|
+
echo "Orphan task $wbs — no feature_id linked; proposal: consider linking to a parent feature." >> ".spur/run/$wbs-report.txt";
|
|
302
|
+
fi;
|
|
303
|
+
exit 0
|
|
195
304
|
|
|
196
305
|
- id: done
|
|
197
306
|
description: >
|
|
@@ -201,47 +310,96 @@ states:
|
|
|
201
310
|
onEnter:
|
|
202
311
|
- kind: shell
|
|
203
312
|
options:
|
|
204
|
-
command: "$
|
|
313
|
+
command: "$spurBin task update $wbs done --no-lifecycle"
|
|
205
314
|
- kind: note
|
|
206
315
|
options:
|
|
207
316
|
message: "Pipeline complete for task ${vars.wbs} (done gate cleared)."
|
|
208
317
|
# Checkpoint write: record session state for resume (Phase 4, task 0171 R3)
|
|
209
318
|
- kind: shell
|
|
210
319
|
options:
|
|
211
|
-
command: 'mkdir -p .spur/memory/sessions && echo "checkpoint: task-pipeline done wbs=$
|
|
320
|
+
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
321
|
|
|
213
322
|
- id: failed
|
|
214
|
-
description:
|
|
323
|
+
description: >
|
|
324
|
+
Terminal — precheck, quality-gate exhaustion, verify non-PASS, record check
|
|
325
|
+
failure, or operator rejection; reported, not advanced.
|
|
215
326
|
|
|
216
327
|
- id: cancelled
|
|
217
328
|
description: Terminal — pipeline cancelled by operator at the approval gate (R1).
|
|
218
329
|
|
|
219
330
|
transitions:
|
|
220
|
-
# ── precheck:
|
|
331
|
+
# ── precheck: doctor PASS + task check → implement; else → failed ──
|
|
221
332
|
- from: precheck
|
|
222
333
|
to: implement
|
|
223
|
-
description:
|
|
334
|
+
description: Agent doctor PASS and task check green — begin implementation.
|
|
224
335
|
guard:
|
|
225
336
|
kind: shell
|
|
226
337
|
options:
|
|
227
|
-
command: "$
|
|
338
|
+
command: 'test "$(cat .spur/run/$wbs-precheck-doctor.status 2>/dev/null)" = PASS && $spurBin task check $wbs'
|
|
228
339
|
- from: precheck
|
|
229
340
|
to: failed
|
|
230
|
-
description:
|
|
341
|
+
description: Doctor FAIL and/or task check failed — stop before implement.
|
|
231
342
|
guard:
|
|
232
|
-
kind:
|
|
233
|
-
options:
|
|
234
|
-
command: '! ${vars.spurBin} task check ${vars.wbs}'
|
|
343
|
+
kind: always
|
|
235
344
|
|
|
236
345
|
# ── linear body ──
|
|
237
346
|
- from: implement
|
|
238
347
|
to: test
|
|
239
|
-
description: Implementation done —
|
|
348
|
+
description: Implementation done — quality-gate probe.
|
|
240
349
|
guard:
|
|
241
350
|
kind: always
|
|
351
|
+
# Soft probe branching (declaration order: PASS first, then FAIL, then defense).
|
|
242
352
|
- from: test
|
|
243
353
|
to: review
|
|
244
|
-
description:
|
|
354
|
+
description: Quality gate already green — one gate run only; skip fixall/recheck.
|
|
355
|
+
guard:
|
|
356
|
+
kind: shell
|
|
357
|
+
options:
|
|
358
|
+
command: 'test "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)" = PASS'
|
|
359
|
+
- from: test
|
|
360
|
+
to: test-fix
|
|
361
|
+
description: Quality gate red — start bounded fixall loop.
|
|
362
|
+
guard:
|
|
363
|
+
kind: shell
|
|
364
|
+
options:
|
|
365
|
+
command: 'test "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)" = FAIL'
|
|
366
|
+
# Defense: missing/corrupt status — treat as FAIL path, not silent PASS.
|
|
367
|
+
- from: test
|
|
368
|
+
to: test-fix
|
|
369
|
+
description: Probe status missing/corrupt — attempt fixall then recheck.
|
|
370
|
+
guard:
|
|
371
|
+
kind: always
|
|
372
|
+
- from: test-fix
|
|
373
|
+
to: test-recheck
|
|
374
|
+
description: Fixall finished — soft recheck the same quality gate.
|
|
375
|
+
guard:
|
|
376
|
+
kind: always
|
|
377
|
+
# Recheck branching (PASS first; under-max FAIL → fixall again; exhausted → failed).
|
|
378
|
+
- from: test-recheck
|
|
379
|
+
to: review
|
|
380
|
+
description: Quality gate green after fixall — proceed to review.
|
|
381
|
+
guard:
|
|
382
|
+
kind: shell
|
|
383
|
+
options:
|
|
384
|
+
command: 'test "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)" = PASS'
|
|
385
|
+
- from: test-recheck
|
|
386
|
+
to: test-fix
|
|
387
|
+
description: Still red and under qualityGateMaxFixAttempts — another fixall hop.
|
|
388
|
+
guard:
|
|
389
|
+
kind: shell
|
|
390
|
+
options:
|
|
391
|
+
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"'
|
|
392
|
+
- from: test-recheck
|
|
393
|
+
to: failed
|
|
394
|
+
description: Still red after max fixall attempts — stop at failed (not silent abort).
|
|
395
|
+
guard:
|
|
396
|
+
kind: shell
|
|
397
|
+
options:
|
|
398
|
+
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"'
|
|
399
|
+
# Defense: corrupt recheck status — failed, not review.
|
|
400
|
+
- from: test-recheck
|
|
401
|
+
to: failed
|
|
402
|
+
description: Recheck status missing/corrupt — stop at failed.
|
|
245
403
|
guard:
|
|
246
404
|
kind: always
|
|
247
405
|
# ── review → approve, OR skip the HITL gate entirely when profile=auto (R4) ──
|
|
@@ -255,7 +413,7 @@ transitions:
|
|
|
255
413
|
guard:
|
|
256
414
|
kind: shell
|
|
257
415
|
options:
|
|
258
|
-
command: 'test "$
|
|
416
|
+
command: 'test "$profile" = auto'
|
|
259
417
|
- from: review
|
|
260
418
|
to: approve
|
|
261
419
|
description: Review done — gate on human approval.
|
|
@@ -273,21 +431,21 @@ transitions:
|
|
|
273
431
|
guard:
|
|
274
432
|
kind: shell
|
|
275
433
|
options:
|
|
276
|
-
command: 'test "$
|
|
434
|
+
command: 'test "$__hitlAnswer" = yes'
|
|
277
435
|
- from: approve
|
|
278
436
|
to: failed
|
|
279
437
|
description: Operator rejected at the approval gate — report and stop.
|
|
280
438
|
guard:
|
|
281
439
|
kind: shell
|
|
282
440
|
options:
|
|
283
|
-
command: 'test "$
|
|
441
|
+
command: 'test "$__hitlAnswer" = no'
|
|
284
442
|
- from: approve
|
|
285
443
|
to: cancelled
|
|
286
444
|
description: Operator cancelled at the approval gate.
|
|
287
445
|
guard:
|
|
288
446
|
kind: shell
|
|
289
447
|
options:
|
|
290
|
-
command: 'test "$
|
|
448
|
+
command: 'test "$__hitlAnswer" = cancel'
|
|
291
449
|
|
|
292
450
|
# ── completion gate (the YAML-native replacement for rd3's default-on --postflight-verify) ──
|
|
293
451
|
# The verify step emits .spur/run/<wbs>-verdict.json. Only `verdict: PASS` clears
|
|
@@ -299,14 +457,14 @@ transitions:
|
|
|
299
457
|
guard:
|
|
300
458
|
kind: shell
|
|
301
459
|
options:
|
|
302
|
-
command: 'test "$(jq -r .verdict .spur/run/$
|
|
460
|
+
command: 'test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS'
|
|
303
461
|
- from: verify
|
|
304
462
|
to: failed
|
|
305
463
|
description: Verification verdict is not PASS (PARTIAL/FAIL/missing) — block before done.
|
|
306
464
|
guard:
|
|
307
465
|
kind: shell
|
|
308
466
|
options:
|
|
309
|
-
command: 'test "$(jq -r .verdict .spur/run/$
|
|
467
|
+
command: 'test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" != PASS'
|
|
310
468
|
# ── done gate: record → done/failed gated on `spur task check` (ADR-026 amendment 2026-06-23) ──
|
|
311
469
|
# The record step guarantees every done-required section ([Solution, Testing, Review])
|
|
312
470
|
# has real content (each owned by its pipeline step). This guard is defense-in-depth —
|
|
@@ -318,11 +476,11 @@ transitions:
|
|
|
318
476
|
guard:
|
|
319
477
|
kind: shell
|
|
320
478
|
options:
|
|
321
|
-
command: "$
|
|
479
|
+
command: "$spurBin task check $wbs"
|
|
322
480
|
- from: record
|
|
323
481
|
to: failed
|
|
324
482
|
description: Task check failed — block before done; investigate missing sections.
|
|
325
483
|
guard:
|
|
326
484
|
kind: shell
|
|
327
485
|
options:
|
|
328
|
-
command: '! $
|
|
486
|
+
command: '! $spurBin task check $wbs'
|