@gobing-ai/spur 0.3.30 → 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/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 +1210 -677
- 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
|
@@ -28,6 +28,14 @@
|
|
|
28
28
|
# spurBin — PATH-independent spur invocation (overridden by CLI at run start)
|
|
29
29
|
# agent — agent for agent.run steps (default: omp)
|
|
30
30
|
#
|
|
31
|
+
# Reliability (aligned with task-pipeline / ADR-043):
|
|
32
|
+
# - Soft agent doctor at start → failed via transitions (not raw lifecycle abort)
|
|
33
|
+
# - expectFile on feature-create / ac-generate / decompose artifacts (no silent no-ops)
|
|
34
|
+
# - Caped AC and batch-create retry loops with fail-closed escalation
|
|
35
|
+
# - HITL taste gates (idea-eval, design-approval) exhaustive yes/no/cancel
|
|
36
|
+
# - Free-form skill pointers remain only where no pure slash surface exists yet
|
|
37
|
+
# (discovery/sys-architecture/decompose internals — residual until dedicated commands)
|
|
38
|
+
#
|
|
31
39
|
# Seeded by `spur init`; adapt the agent.run inputs to your project's command set.
|
|
32
40
|
|
|
33
41
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
@@ -43,6 +51,9 @@ terminalStates:
|
|
|
43
51
|
- handoff
|
|
44
52
|
- cancelled
|
|
45
53
|
- failed
|
|
54
|
+
failureStates:
|
|
55
|
+
- failed
|
|
56
|
+
- cancelled
|
|
46
57
|
vars:
|
|
47
58
|
idea: ""
|
|
48
59
|
profile: "standard"
|
|
@@ -55,44 +66,55 @@ vars:
|
|
|
55
66
|
# R8 (0366): injected by WorkflowAppService.run(); stamps discovery artifact provenance.
|
|
56
67
|
__runId: ""
|
|
57
68
|
agent: "omp"
|
|
58
|
-
stepTimeoutMs: "
|
|
69
|
+
stepTimeoutMs: "1800000"
|
|
59
70
|
|
|
60
71
|
states:
|
|
61
72
|
- id: start
|
|
62
73
|
description: >
|
|
63
74
|
Pipeline start. The idea text arrives as vars.idea. The pipeline stops at
|
|
64
|
-
handoff — no task execution.
|
|
75
|
+
handoff — no task execution. Soft agent doctor (status file) so doctor red
|
|
76
|
+
routes to `failed` via transitions instead of a raw lifecycle abort.
|
|
65
77
|
onEnter:
|
|
66
78
|
- kind: note
|
|
67
79
|
options:
|
|
68
80
|
message: "Idea pipeline start for idea: ${vars.idea}"
|
|
69
81
|
- kind: shell
|
|
70
82
|
options:
|
|
71
|
-
command:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
83
|
+
command: >-
|
|
84
|
+
mkdir -p .spur/run &&
|
|
85
|
+
DOCTOR_FILE=".spur/run/$__runId-idea-precheck-doctor.status" &&
|
|
86
|
+
set +e &&
|
|
87
|
+
$spurBin agent doctor $agent; doctor_rc=$?;
|
|
88
|
+
set -e &&
|
|
89
|
+
if [ "$doctor_rc" -eq 0 ] && test -n "$idea"; then
|
|
90
|
+
printf 'PASS\n' > "$DOCTOR_FILE";
|
|
91
|
+
else
|
|
92
|
+
printf 'FAIL\n' > "$DOCTOR_FILE";
|
|
93
|
+
fi &&
|
|
94
|
+
exit 0
|
|
75
95
|
|
|
76
96
|
- id: discovery
|
|
77
97
|
description: >
|
|
78
98
|
Dispatch sp:brainstorm to explore the idea, generate approaches with trade-offs,
|
|
79
99
|
and record a design summary. The brainstorm ALWAYS records a design summary
|
|
80
100
|
("nothing is too simple" pattern). The brainstorm also emits a needs_design
|
|
81
|
-
boolean signal written to .spur/run
|
|
101
|
+
boolean signal written to .spur/run/${vars.__runId}-idea-needs-design.json — this determines
|
|
82
102
|
whether the system-design state runs. As its terminal artifact for the idea path,
|
|
83
|
-
brainstorm also emits the idea-evaluation report to .spur/run
|
|
103
|
+
brainstorm also emits the idea-evaluation report to .spur/run/${vars.__runId}-idea-eval-report.md
|
|
84
104
|
(template: plugins/sp/skills/spur-dev/references/idea-evaluation.md).
|
|
105
|
+
expectFile fails a silent no-op discovery (no eval report).
|
|
85
106
|
onEnter:
|
|
86
107
|
- kind: agent.run
|
|
87
108
|
options:
|
|
88
109
|
agent: ${vars.agent}
|
|
89
|
-
input: "Run sp:brainstorm for the idea: ${vars.idea}. The skill owns the approach-generation, design summary, and `needs_design` signal criteria; emit .spur/run
|
|
110
|
+
input: "Run sp:brainstorm for the idea: ${vars.idea}. The skill owns the approach-generation, design summary, and `needs_design` signal criteria; emit .spur/run/${vars.__runId}-idea-needs-design.json ({\"needs_design\": true|false}) and the design summary per the skill's `Design Approval Gate` and `The needs_design signal` sections. Also emit the idea-evaluation report to .spur/run/${vars.__runId}-idea-eval-report.md per plugins/sp/skills/spur-dev/references/idea-evaluation.md (urgency/necessity 0–5, premises, pros/cons, alternatives, enhanced idea, recommendation). At the END of the report, append a provenance footer block of the exact form: `---\\nrun_id: ${vars.__runId}\\ngenerated_at: <RFC3339 timestamp>\\n---` (omit the footer only if run_id is empty)."
|
|
111
|
+
expectFile: .spur/run/${vars.__runId}-idea-eval-report.md
|
|
90
112
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
91
113
|
|
|
92
114
|
- id: idea-eval
|
|
93
115
|
description: >
|
|
94
116
|
HITL taste gate. Discovery has produced the idea-evaluation report
|
|
95
|
-
(.spur/run
|
|
117
|
+
(.spur/run/${vars.__runId}-idea-eval-report.md) with urgency/necessity scores, premises,
|
|
96
118
|
pros/cons, and a recommendation. The operator reviews and approves or
|
|
97
119
|
rejects. This gate is NOT auto-clicked by --auto (taste gate, like
|
|
98
120
|
design-approval). Only routes around when vars.idea_approved=true
|
|
@@ -101,24 +123,24 @@ states:
|
|
|
101
123
|
onEnter:
|
|
102
124
|
- kind: hitl.confirm
|
|
103
125
|
options:
|
|
104
|
-
prompt: "Review the idea evaluation report (.spur/run
|
|
126
|
+
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.)"
|
|
105
127
|
|
|
106
128
|
- id: feature-create
|
|
107
129
|
description: >
|
|
108
130
|
Create a feature via spur feature create, or select an existing feature id.
|
|
109
|
-
The agent writes the feature id to .spur/run
|
|
110
|
-
states to read. Prefer the enhanced idea from .spur/run
|
|
131
|
+
The agent writes the feature id to .spur/run/${vars.__runId}-idea-feature-id.txt for subsequent
|
|
132
|
+
states to read. Prefer the enhanced idea from .spur/run/${vars.__runId}-idea-eval-report.md as
|
|
111
133
|
context; do not overwrite vars.idea.
|
|
112
134
|
onEnter:
|
|
113
135
|
- kind: agent.run
|
|
114
136
|
options:
|
|
115
137
|
agent: ${vars.agent}
|
|
116
|
-
input: "Create a feature for the idea: ${vars.idea}. Read .spur/run
|
|
117
|
-
expectFile: .spur/run
|
|
138
|
+
input: "Create a feature for the idea: ${vars.idea}. Read .spur/run/${vars.__runId}-idea-eval-report.md if present for the enhanced idea and scores. Use 'spur feature create \"<name>\" --json' to create it. Write the feature id to .spur/run/${vars.__runId}-idea-feature-id.txt. If an existing feature is appropriate, use its id instead."
|
|
139
|
+
expectFile: .spur/run/${vars.__runId}-idea-feature-id.txt
|
|
118
140
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
119
141
|
- kind: file.read.into-var
|
|
120
142
|
options:
|
|
121
|
-
path: .spur/run
|
|
143
|
+
path: .spur/run/${vars.__runId}-idea-feature-id.txt
|
|
122
144
|
var: featureId
|
|
123
145
|
|
|
124
146
|
- id: ac-generate
|
|
@@ -128,29 +150,47 @@ states:
|
|
|
128
150
|
--from-file`. The agent authors R-numbered Gherkin scenarios tied to the
|
|
129
151
|
design summary into a captured file; the shell step verifies the file is
|
|
130
152
|
non-empty, writes it through the CLI, and writes a completion sentinel
|
|
131
|
-
(.spur/run
|
|
132
|
-
guards (`spur feature check
|
|
153
|
+
(.spur/run/${vars.__runId}-idea-ac-done.txt). AC quality checking lives in the transition
|
|
154
|
+
guards (`spur feature check`), NOT in this action chain — a failing
|
|
133
155
|
check must route through the capped retry loop, not fail the run (the engine's
|
|
134
156
|
default onError policy is `fail`, so an in-action check failure would kill the
|
|
135
157
|
run before the retry edges are ever evaluated).
|
|
136
158
|
onEnter:
|
|
137
159
|
- kind: shell
|
|
138
160
|
options:
|
|
139
|
-
command: 'mkdir -p .spur/run && count=$(cat .spur/run
|
|
161
|
+
command: 'mkdir -p .spur/run && count=$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0); echo $((count + 1)) > .spur/run/$__runId-idea-ac-retry-count; rm -f .spur/run/$__runId-idea-ac-content.md .spur/run/$__runId-idea-ac-done.txt'
|
|
140
162
|
- kind: agent.run
|
|
141
163
|
options:
|
|
142
164
|
agent: ${vars.agent}
|
|
143
165
|
input: "Generate acceptance criteria for feature ${vars.featureId}. Read the feature file and author R-numbered BDD Gherkin scenarios per ac-style-guide.md. Output only the complete Acceptance Criteria section body, including the gherkin code fence, with no surrounding commentary and no section heading."
|
|
144
|
-
answerFile: .spur/run
|
|
145
|
-
expectFile: .spur/run
|
|
166
|
+
answerFile: .spur/run/${vars.__runId}-idea-ac-content.md
|
|
167
|
+
expectFile: .spur/run/${vars.__runId}-idea-ac-content.md
|
|
146
168
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
169
|
+
# Empty capture is a RETRYABLE outcome, not a run abort. `answerFile` always
|
|
170
|
+
# creates the file (so `expectFile` above cannot catch an empty answer), and the
|
|
171
|
+
# old `test -s … && …` chain exited 1 on empty content — killing the run under
|
|
172
|
+
# the default `fail` policy before the capped retry edges were ever evaluated,
|
|
173
|
+
# contradicting this state's own contract. Empty now falls through with exit 0
|
|
174
|
+
# so `spur feature check` in the guards routes it back here (cap: 3). A failing
|
|
175
|
+
# CLI *write* still exits non-zero and aborts — that one is not retryable.
|
|
147
176
|
- kind: shell
|
|
148
177
|
options:
|
|
149
|
-
command:
|
|
178
|
+
command: >-
|
|
179
|
+
if test -s .spur/run/$__runId-idea-ac-content.md; then
|
|
180
|
+
$spurBin feature update $featureId --section "Acceptance Criteria" --from-file .spur/run/$__runId-idea-ac-content.md && date -u +%Y-%m-%dT%H:%M:%SZ > .spur/run/$__runId-idea-ac-done.txt;
|
|
181
|
+
else
|
|
182
|
+
exit 0;
|
|
183
|
+
fi
|
|
150
184
|
|
|
151
185
|
- id: feature-check
|
|
152
186
|
description: >
|
|
153
|
-
HITL gate: runs spur feature check <id
|
|
187
|
+
HITL gate: runs spur feature check <id>. Deliberately NOT --strict: before
|
|
188
|
+
decompose/batch-create a feature has scenarios but zero linked tasks, which
|
|
189
|
+
emits L4.orphan-scenarios at severity `warning`; --strict would elevate that
|
|
190
|
+
to a failure, making the success edges unreachable and looping ac-generate
|
|
191
|
+
into `failed`. Malformed AC still blocks via the error-severity L3 BDD
|
|
192
|
+
checks. Strict coverage belongs at the shippable gate, not here. The check
|
|
193
|
+
is objective
|
|
154
194
|
(schema/AC validation) and auto-routable — under profile=auto the transition
|
|
155
195
|
guards route directly from ac-generate to the appropriate next state, so this
|
|
156
196
|
state is only entered in interactive mode. On failure, the retry cap routes
|
|
@@ -180,8 +220,17 @@ states:
|
|
|
180
220
|
rejects it. This gate is NOT auto-clicked by --auto (Auto-Decision Principle
|
|
181
221
|
#5: taste-decision -> surface to human). Only routes around when
|
|
182
222
|
vars.design_approved=true (explicit prior approval).
|
|
223
|
+
|
|
224
|
+
R7 (0433): a headless `no` persisted by DefaultHitlResponder would loop
|
|
225
|
+
design-approval -> system-design -> design-approval, burning unbounded
|
|
226
|
+
agent passes. The onEnter shell increments a reject counter; the `no`
|
|
227
|
+
edge to system-design is capped at 1 revise, after which the run
|
|
228
|
+
terminates as `failed` naming this gate.
|
|
183
229
|
pause: true
|
|
184
230
|
onEnter:
|
|
231
|
+
- kind: shell
|
|
232
|
+
options:
|
|
233
|
+
command: 'mkdir -p .spur/run && count=$(cat .spur/run/$__runId-idea-design-reject-count 2>/dev/null || echo 0); echo $((count + 1)) > .spur/run/$__runId-idea-design-reject-count'
|
|
185
234
|
- kind: hitl.confirm
|
|
186
235
|
options:
|
|
187
236
|
prompt: "Review the system design for feature ${vars.featureId}. Approve to proceed to decomposition?"
|
|
@@ -190,15 +239,16 @@ states:
|
|
|
190
239
|
description: >
|
|
191
240
|
Dispatch sp:spec-decomposition with the brainstorm artifact, feature AC, and
|
|
192
241
|
design doc as input. The agent produces a task-batch JSON file at
|
|
193
|
-
.spur/run
|
|
242
|
+
.spur/run/${vars.__runId}-idea-task-batch.json, validated against task-batch.schema.json.
|
|
194
243
|
onEnter:
|
|
195
244
|
- kind: shell
|
|
196
245
|
options:
|
|
197
|
-
command: 'mkdir -p .spur/run && count=$(cat .spur/run
|
|
246
|
+
command: 'mkdir -p .spur/run && count=$(cat .spur/run/$__runId-idea-decompose-retry-count 2>/dev/null || echo 0); echo $((count + 1)) > .spur/run/$__runId-idea-decompose-retry-count; rm -f .spur/run/$__runId-idea-task-batch.json .spur/run/$__runId-idea-batch-create.done .spur/run/$__runId-idea-batch-create.failed'
|
|
198
247
|
- kind: agent.run
|
|
199
248
|
options:
|
|
200
249
|
agent: ${vars.agent}
|
|
201
|
-
input: "Run sp:spec-decomposition for feature ${vars.featureId}. Read the brainstorm artifact, feature AC, and design doc. Produce a task-batch JSON array at .spur/run
|
|
250
|
+
input: "Run sp:spec-decomposition for feature ${vars.featureId}. Read the brainstorm artifact, feature AC, and design doc. Produce a task-batch JSON array at .spur/run/${vars.__runId}-idea-task-batch.json, validated against apps/cli/schemas/task-batch.schema.json. Schema-permitted fields per entry: `name`, `background`, `requirements`, `feature_id`, `parent_wbs`, `priority`, `tags`, `template` — schema validation rejects anything else. Acceptance Criteria, Design, and Plan sections are filled in by the per-task refine step after batch-create, NOT at decompose time. Validate locally against the schema before emitting."
|
|
251
|
+
expectFile: .spur/run/${vars.__runId}-idea-task-batch.json
|
|
202
252
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
203
253
|
|
|
204
254
|
- id: batch-create
|
|
@@ -223,7 +273,7 @@ states:
|
|
|
223
273
|
onEnter:
|
|
224
274
|
- kind: shell
|
|
225
275
|
options:
|
|
226
|
-
command: 'if test -f .spur/run
|
|
276
|
+
command: 'if test -f .spur/run/$__runId-idea-batch-create.done; then exit 0; fi; rm -f .spur/run/$__runId-idea-batch-create.failed; if $spurBin task batch-create --file .spur/run/$__runId-idea-task-batch.json; then date -u +%Y-%m-%dT%H:%M:%SZ > .spur/run/$__runId-idea-batch-create.done; else date -u +%Y-%m-%dT%H:%M:%SZ > .spur/run/$__runId-idea-batch-create.failed; fi'
|
|
227
277
|
|
|
228
278
|
- id: handoff
|
|
229
279
|
description: >
|
|
@@ -237,7 +287,7 @@ states:
|
|
|
237
287
|
# Checkpoint write: record session state for resume (Phase 4, task 0171 R3)
|
|
238
288
|
- kind: shell
|
|
239
289
|
options:
|
|
240
|
-
command: 'mkdir -p .spur/memory/sessions && echo "checkpoint: idea-pipeline handoff feature=$
|
|
290
|
+
command: 'mkdir -p .spur/memory/sessions && echo "checkpoint: idea-pipeline handoff feature=$featureId ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)" > .spur/memory/sessions/idea-checkpoint.md'
|
|
241
291
|
|
|
242
292
|
- id: cancelled
|
|
243
293
|
description: Terminal — pipeline cancelled by operator or error.
|
|
@@ -252,7 +302,14 @@ transitions:
|
|
|
252
302
|
# ── start -> discovery ──
|
|
253
303
|
- from: start
|
|
254
304
|
to: discovery
|
|
255
|
-
description:
|
|
305
|
+
description: Agent doctor PASS — begin discovery.
|
|
306
|
+
guard:
|
|
307
|
+
kind: shell
|
|
308
|
+
options:
|
|
309
|
+
command: 'test "$(cat .spur/run/$__runId-idea-precheck-doctor.status 2>/dev/null)" = PASS'
|
|
310
|
+
- from: start
|
|
311
|
+
to: failed
|
|
312
|
+
description: Agent doctor FAIL — stop before discovery.
|
|
256
313
|
guard:
|
|
257
314
|
kind: always
|
|
258
315
|
|
|
@@ -266,7 +323,7 @@ transitions:
|
|
|
266
323
|
guard:
|
|
267
324
|
kind: shell
|
|
268
325
|
options:
|
|
269
|
-
command: 'test "$
|
|
326
|
+
command: 'test "$profile" = auto && test "$idea_approved" = true'
|
|
270
327
|
- from: discovery
|
|
271
328
|
to: idea-eval
|
|
272
329
|
description: Discovery complete — gate on idea evaluation taste decision.
|
|
@@ -281,21 +338,21 @@ transitions:
|
|
|
281
338
|
guard:
|
|
282
339
|
kind: shell
|
|
283
340
|
options:
|
|
284
|
-
command: 'test "$
|
|
341
|
+
command: 'test "$profile" = auto && test "$idea_approved" = true'
|
|
285
342
|
- from: idea-eval
|
|
286
343
|
to: feature-create
|
|
287
344
|
description: Idea evaluation approved — create or select a feature.
|
|
288
345
|
guard:
|
|
289
346
|
kind: shell
|
|
290
347
|
options:
|
|
291
|
-
command: 'test "$
|
|
348
|
+
command: 'test "$__hitlAnswer" = yes'
|
|
292
349
|
- from: idea-eval
|
|
293
350
|
to: cancelled
|
|
294
351
|
description: Idea evaluation rejected or cancelled — no feature created.
|
|
295
352
|
guard:
|
|
296
353
|
kind: shell
|
|
297
354
|
options:
|
|
298
|
-
command: 'test "$
|
|
355
|
+
command: 'test "$__hitlAnswer" = no || test "$__hitlAnswer" = cancel'
|
|
299
356
|
|
|
300
357
|
# ── feature-create -> ac-generate ──
|
|
301
358
|
- from: feature-create
|
|
@@ -317,7 +374,7 @@ transitions:
|
|
|
317
374
|
guard:
|
|
318
375
|
kind: shell
|
|
319
376
|
options:
|
|
320
|
-
command: 'test "$
|
|
377
|
+
command: 'test "$profile" = auto && $spurBin feature check $featureId && test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" != false'
|
|
321
378
|
# Auto-skip 2: pass + skip-design route → decompose
|
|
322
379
|
- from: ac-generate
|
|
323
380
|
to: decompose
|
|
@@ -325,7 +382,7 @@ transitions:
|
|
|
325
382
|
guard:
|
|
326
383
|
kind: shell
|
|
327
384
|
options:
|
|
328
|
-
command: 'test "$
|
|
385
|
+
command: 'test "$profile" = auto && $spurBin feature check $featureId && (test "$design" = skip || (test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false))'
|
|
329
386
|
# Auto-skip 3: check failed, retry < 3 → loop back to ac-generate (self-loop)
|
|
330
387
|
- from: ac-generate
|
|
331
388
|
to: ac-generate
|
|
@@ -333,7 +390,7 @@ transitions:
|
|
|
333
390
|
guard:
|
|
334
391
|
kind: shell
|
|
335
392
|
options:
|
|
336
|
-
command: 'test "$
|
|
393
|
+
command: 'test "$profile" = auto && ! $spurBin feature check $featureId && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -lt 3'
|
|
337
394
|
# Auto-skip 4: check failed, retry cap reached → escalate to failed
|
|
338
395
|
- from: ac-generate
|
|
339
396
|
to: failed
|
|
@@ -341,7 +398,7 @@ transitions:
|
|
|
341
398
|
guard:
|
|
342
399
|
kind: shell
|
|
343
400
|
options:
|
|
344
|
-
command: 'test "$
|
|
401
|
+
command: 'test "$profile" = auto && ! $spurBin feature check $featureId && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -ge 3'
|
|
345
402
|
# Interactive fallback: enter feature-check HITL gate
|
|
346
403
|
- from: ac-generate
|
|
347
404
|
to: feature-check
|
|
@@ -357,35 +414,35 @@ transitions:
|
|
|
357
414
|
guard:
|
|
358
415
|
kind: shell
|
|
359
416
|
options:
|
|
360
|
-
command: 'test "$
|
|
417
|
+
command: 'test "$__hitlAnswer" = yes && $spurBin feature check $featureId && test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" != false'
|
|
361
418
|
- from: feature-check
|
|
362
419
|
to: decompose
|
|
363
420
|
description: Feature check passed, skip-design route — go directly to decompose.
|
|
364
421
|
guard:
|
|
365
422
|
kind: shell
|
|
366
423
|
options:
|
|
367
|
-
command: 'test "$
|
|
424
|
+
command: 'test "$__hitlAnswer" = yes && $spurBin feature check $featureId && (test "$design" = skip || (test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false))'
|
|
368
425
|
- from: feature-check
|
|
369
426
|
to: ac-generate
|
|
370
427
|
description: "Feature check failed — revise AC (retry cap: 3)."
|
|
371
428
|
guard:
|
|
372
429
|
kind: shell
|
|
373
430
|
options:
|
|
374
|
-
command: '(test "$
|
|
431
|
+
command: '(test "$__hitlAnswer" = no || ! $spurBin feature check $featureId) && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -lt 3'
|
|
375
432
|
- from: feature-check
|
|
376
433
|
to: failed
|
|
377
434
|
description: Feature check failed after 3 retries — escalate to failed.
|
|
378
435
|
guard:
|
|
379
436
|
kind: shell
|
|
380
437
|
options:
|
|
381
|
-
command: '(test "$
|
|
438
|
+
command: '(test "$__hitlAnswer" = no || ! $spurBin feature check $featureId) && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -ge 3'
|
|
382
439
|
- from: feature-check
|
|
383
440
|
to: cancelled
|
|
384
441
|
description: Operator cancelled the feature-check gate.
|
|
385
442
|
guard:
|
|
386
443
|
kind: shell
|
|
387
444
|
options:
|
|
388
|
-
command: 'test "$
|
|
445
|
+
command: 'test "$__hitlAnswer" = cancel'
|
|
389
446
|
|
|
390
447
|
# ── system-design: -> design-approval (normal) OR -> decompose (auto + prior approval) ──
|
|
391
448
|
# Declaration order: auto-skip guard tried FIRST (like task-pipeline's review->verify pattern).
|
|
@@ -395,7 +452,7 @@ transitions:
|
|
|
395
452
|
guard:
|
|
396
453
|
kind: shell
|
|
397
454
|
options:
|
|
398
|
-
command: 'test "$
|
|
455
|
+
command: 'test "$profile" = auto && test "$design_approved" = true'
|
|
399
456
|
- from: system-design
|
|
400
457
|
to: design-approval
|
|
401
458
|
description: System design done — gate on design approval.
|
|
@@ -409,21 +466,28 @@ transitions:
|
|
|
409
466
|
guard:
|
|
410
467
|
kind: shell
|
|
411
468
|
options:
|
|
412
|
-
command: 'test "$
|
|
469
|
+
command: 'test "$__hitlAnswer" = yes'
|
|
413
470
|
- from: design-approval
|
|
414
471
|
to: system-design
|
|
415
|
-
description: Design rejected
|
|
472
|
+
description: "Design rejected - revise system design (cap: 1 revise)."
|
|
473
|
+
guard:
|
|
474
|
+
kind: shell
|
|
475
|
+
options:
|
|
476
|
+
command: 'test "$__hitlAnswer" = no && test "$(cat .spur/run/$__runId-idea-design-reject-count 2>/dev/null || echo 0)" -le 1'
|
|
477
|
+
- from: design-approval
|
|
478
|
+
to: failed
|
|
479
|
+
description: "Design rejected after 1 revise - design-approval gate exhausted (R7 0433)."
|
|
416
480
|
guard:
|
|
417
481
|
kind: shell
|
|
418
482
|
options:
|
|
419
|
-
command: 'test "$
|
|
483
|
+
command: 'test "$__hitlAnswer" = no && test "$(cat .spur/run/$__runId-idea-design-reject-count 2>/dev/null || echo 0)" -gt 1'
|
|
420
484
|
- from: design-approval
|
|
421
485
|
to: cancelled
|
|
422
486
|
description: Operator cancelled design approval.
|
|
423
487
|
guard:
|
|
424
488
|
kind: shell
|
|
425
489
|
options:
|
|
426
|
-
command: 'test "$
|
|
490
|
+
command: 'test "$__hitlAnswer" = cancel'
|
|
427
491
|
|
|
428
492
|
# ── decompose: auto-skip (profile=auto) OR enter batch-create HITL gate (interactive) ──
|
|
429
493
|
- from: decompose
|
|
@@ -432,7 +496,7 @@ transitions:
|
|
|
432
496
|
guard:
|
|
433
497
|
kind: shell
|
|
434
498
|
options:
|
|
435
|
-
command: 'test "$
|
|
499
|
+
command: 'test "$profile" = auto'
|
|
436
500
|
# Interactive fallback: enter batch-create HITL gate
|
|
437
501
|
- from: decompose
|
|
438
502
|
to: batch-create
|
|
@@ -446,21 +510,21 @@ transitions:
|
|
|
446
510
|
guard:
|
|
447
511
|
kind: shell
|
|
448
512
|
options:
|
|
449
|
-
command: 'test "$
|
|
513
|
+
command: 'test "$__hitlAnswer" = yes'
|
|
450
514
|
- from: batch-create
|
|
451
515
|
to: decompose
|
|
452
516
|
description: Operator requested decomposition revisions.
|
|
453
517
|
guard:
|
|
454
518
|
kind: shell
|
|
455
519
|
options:
|
|
456
|
-
command: 'test "$
|
|
520
|
+
command: 'test "$__hitlAnswer" = no'
|
|
457
521
|
- from: batch-create
|
|
458
522
|
to: cancelled
|
|
459
523
|
description: Operator cancelled batch creation.
|
|
460
524
|
guard:
|
|
461
525
|
kind: shell
|
|
462
526
|
options:
|
|
463
|
-
command: 'test "$
|
|
527
|
+
command: 'test "$__hitlAnswer" = cancel'
|
|
464
528
|
|
|
465
529
|
# ── batch-create-run: success -> handoff, failure -> decompose (retry cap: 3), failure+cap -> failed ──
|
|
466
530
|
- from: batch-create-run
|
|
@@ -469,18 +533,18 @@ transitions:
|
|
|
469
533
|
guard:
|
|
470
534
|
kind: shell
|
|
471
535
|
options:
|
|
472
|
-
command: 'test -f .spur/run
|
|
536
|
+
command: 'test -f .spur/run/$__runId-idea-batch-create.done'
|
|
473
537
|
- from: batch-create-run
|
|
474
538
|
to: decompose
|
|
475
539
|
description: "Batch-create failed — revise decomposition (retry cap: 3)."
|
|
476
540
|
guard:
|
|
477
541
|
kind: shell
|
|
478
542
|
options:
|
|
479
|
-
command: 'test -f .spur/run
|
|
543
|
+
command: 'test -f .spur/run/$__runId-idea-batch-create.failed && test "$(cat .spur/run/$__runId-idea-decompose-retry-count 2>/dev/null || echo 0)" -lt 3'
|
|
480
544
|
- from: batch-create-run
|
|
481
545
|
to: failed
|
|
482
546
|
description: Batch-create failed after 3 retries — escalate to failed.
|
|
483
547
|
guard:
|
|
484
548
|
kind: shell
|
|
485
549
|
options:
|
|
486
|
-
command: 'test -f .spur/run
|
|
550
|
+
command: 'test -f .spur/run/$__runId-idea-batch-create.failed && test "$(cat .spur/run/$__runId-idea-decompose-retry-count 2>/dev/null || echo 0)" -ge 3'
|