@gobing-ai/spur 0.3.84 → 0.3.86
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/.claude-plugin/marketplace.json +1 -1
- package/config/config.global.yaml +11 -6
- package/config/pipeline-budgets.json +0 -25
- package/config/plugin-scripts.json +0 -5
- package/config/rules/boundary/env-var-hygiene.yaml +41 -0
- package/config/transition-shims.json +1 -1
- package/config/workflow-candidates.json +41 -0
- package/config/workflows/feature-lifecycle.yaml +4 -2
- package/config/workflows/feature-verification.yaml +70 -0
- package/config/workflows/idea-pipeline.yaml +25 -13
- package/config/workflows/task-pipeline.yaml +43 -12
- package/config/workflows/wrapup-pipeline.yaml +71 -8
- package/package.json +9 -9
- package/plugins/sp/README.md +0 -3
- package/plugins/sp/agents/super-planner.md +2 -1
- package/plugins/sp/hooks/agent-hint.ts +5 -4
- package/plugins/sp/hooks/careful-guard.ts +3 -1
- package/plugins/sp/hooks/context-post-tool.ts +2 -1
- package/plugins/sp/hooks/context-session-start.ts +4 -3
- package/plugins/sp/hooks/context-session-stop.ts +2 -1
- package/plugins/sp/hooks/pi/guard-extension.ts +4 -3
- package/plugins/sp/hooks/task-write-guard.ts +4 -3
- package/plugins/sp/lib/idea-handoff.generated.mjs +260 -260
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +13 -4
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +6 -4
- package/plugins/sp/scripts/feature-sync-bounded.mjs +10 -2
- package/plugins/sp/scripts/feature-sync-bounded.ts +2 -1
- package/plugins/sp/scripts/idea-handoff.mjs +6 -1
- package/plugins/sp/scripts/idea-handoff.ts +4 -1
- package/plugins/sp/scripts/inline-pipeline-parity-check.ts +1 -1
- package/plugins/sp/scripts/inline-run-setup.ts +185 -2
- package/plugins/sp/scripts/pr-reviewing.mjs +8 -1
- package/plugins/sp/scripts/pr-reviewing.ts +2 -1
- package/plugins/sp/scripts/quality-gate.mjs +8 -1
- package/plugins/sp/scripts/quality-gate.ts +2 -1
- package/plugins/sp/scripts/surface-drift-inventory.ts +2 -5
- package/plugins/sp/scripts/task-evidence-precheck.ts +2 -1
- package/plugins/sp/scripts/task-size-precheck.ts +6 -4
- package/plugins/sp/scripts/verify-answer-lint.ts +2 -1
- package/plugins/sp/scripts/workflow-step-profile.mjs +10 -2
- package/plugins/sp/scripts/workflow-step-profile.ts +2 -1
- package/plugins/sp/scripts/wrapup-steps.mjs +8 -1
- package/plugins/sp/scripts/wrapup-steps.ts +2 -1
- package/plugins/sp/skills/spur-cli/references/workflows.md +8 -7
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +4 -5
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +1 -1
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +2 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +59 -1
- package/schemas/state-machine-workflow.schema.json +5 -0
- package/schemas/transition-flow-workflow.schema.json +5 -0
- package/spur.js +21393 -20831
- package/web/_astro/BoardApp.CJiqp5pS.js +1 -0
- package/web/_astro/{BoardApp.D4mBUGLT.js → BoardApp.yBBcFXWP.js} +60 -60
- package/web/_astro/{TaskDetail.DhCWaOPR.js → TaskDetail.DqFJbRFc.js} +1 -1
- package/web/_astro/{arc.D3X0nfq-.js → arc.DL-BpHoi.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.BQDoiGme.js → architectureDiagram-3BPJPVTR.9IdQYyDq.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.BjHekBbM.js → blockDiagram-GPEHLZMM.BKsFCqTl.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BvHt171l.js → c4Diagram-AAUBKEIU.DhwI0dh1.js} +1 -1
- package/web/_astro/channel.CX5453qQ.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.CwxGXlDR.js → chunk-2J33WTMH.B3QVmQ9S.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.Dia1YtwU.js → chunk-4BX2VUAB.DBSuqs9F.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.Oz9epCXa.js → chunk-55IACEB6.BSYTWAYD.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DKFYJjYJ.js → chunk-727SXJPM.cWVuxXfS.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.AD7w5oVz.js → chunk-AQP2D5EJ.DpU_Ob3d.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.D0OqTj52.js → chunk-FMBD7UC4.BykFkyji.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CU5ppR7j.js → chunk-ND2GUHAM.DwgHlMdY.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.Bu1rFztw.js → chunk-QZHKN3VN.CusXUGWM.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.C0Pgm5yE.js → classDiagram-4FO5ZUOK.fx0ObzkN.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.C0Pgm5yE.js → classDiagram-v2-Q7XG4LA2.fx0ObzkN.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.C0ecLb1e.js → cose-bilkent-S5V4N54A.Z4HgOlsd.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.CpStVmhO.js → cynefin-OW5HDTMX.B5dIZHJu.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.BPWN3W9f.js → dagre-BM42HDAG.DT70Q_Yw.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.DnXbEot4.js → diagram-2AECGRRQ.DqHA3XBF.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.BYJsgUiI.js → diagram-5GNKFQAL.BmCem957.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.CU4Bqprx.js → diagram-KO2AKTUF.sn0-hrE0.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.BQLOANIu.js → diagram-LMA3HP47.BSHe9tVc.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.Cn1UVhqj.js → diagram-OG6HWLK6.DHIc-86k.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.C8FdZyvA.js → erDiagram-TEJ5UH35.Bxayrs7v.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.QSZCR8Uo.js → flowDiagram-I6XJVG4X.BkzoE_5I.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.O1Py31MY.js → ganttDiagram-6RSMTGT7.okT6CvTo.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.DoeJRBfY.js → gitGraphDiagram-PVQCEYII.CJuYbhC7.js} +1 -1
- package/web/_astro/{index.TPF1FerP.css → index.CcU5weKX.css} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.9npLJecW.js → infoDiagram-5YYISTIA.RqLy7nBo.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.DXanvOr3.js → ishikawaDiagram-YF4QCWOH.BwIcoagw.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.DxbVjxAv.js → journeyDiagram-JHISSGLW.UB1VbWtH.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.BDk6_iq0.js → kanban-definition-UN3LZRKU.AaxMKpTk.js} +1 -1
- package/web/_astro/{linear.C9cCDjT3.js → linear.Nv_xOUjP.js} +1 -1
- package/web/_astro/{mermaid.core.CpHRe5nH.js → mermaid.core.Bc4LqQgX.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.D-6C85bn.js → mindmap-definition-RKZ34NQL.oKUvU_qi.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.B3Oxodty.js → pieDiagram-4H26LBE5.DQk0oo03.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.QZ_9Hshu.js → quadrantDiagram-W4KKPZXB.BdDjESDa.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.BimvuK53.js → requirementDiagram-4Y6WPE33.C2u9hUeH.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.D5Kkpx2C.js → sankeyDiagram-5OEKKPKP.CDEoiJST.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.B4YR6fAE.js → sequenceDiagram-3UESZ5HK.D_hT_GAT.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.Bt2wkZok.js → stateDiagram-AJRCARHV.DI8RYG0b.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.YZ4X7dfQ.js → stateDiagram-v2-BHNVJYJU.Bkxz4DnP.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.DmiTBL8w.js → timeline-definition-PNZ67QCA.DSY-kH3-.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.KNJV40mf.js → vennDiagram-CIIHVFJN.CpaDtuGr.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.BVAaKgWH.js → wardleyDiagram-YWT4CUSO.DujQWvo8.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.D5Jx7zB2.js → xychartDiagram-2RQKCTM6.DcM5Y4b9.js} +1 -1
- package/web/index.html +2 -2
- package/config/workflows/basic.yaml +0 -146
- package/config/workflows/docs-pipeline.yaml +0 -350
- package/config/workflows/feature-dev.yaml +0 -288
- package/plugins/sp/scripts/feature-dev-precheck.mjs +0 -146
- package/plugins/sp/scripts/feature-dev-precheck.ts +0 -238
- package/web/_astro/BoardApp.DFPYpI5O.js +0 -1
- package/web/_astro/channel.BlQwxyoI.js +0 -1
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
# Docs-only task pipeline — one run per documentation/design-doc deliverable.
|
|
2
|
-
#
|
|
3
|
-
# Sibling of task-pipeline.yaml for tasks whose output is a document, not product
|
|
4
|
-
# code. Keeps docs deliverables out of the full quality gate and routes them
|
|
5
|
-
# through an explicit docs-review HITL gate.
|
|
6
|
-
#
|
|
7
|
-
# Reliability (aligned with task-pipeline / ADR-043):
|
|
8
|
-
# - Soft precheck (task check + status file) so red precheck → failed via transitions
|
|
9
|
-
# - draft agent.run is a pure slash command (docs discipline lives in
|
|
10
|
-
# /sp:dev-run --mode implement + sp:code-implementation, not YAML prose)
|
|
11
|
-
# - requireDiff fails silent no-op drafts
|
|
12
|
-
# - HITL answer routing is exhaustive (yes/no/cancel)
|
|
13
|
-
# - verify measures the deliverable read-only (answer file + `spur task verdict` + proof
|
|
14
|
-
# digest bracket); recording happens only AFTER measured PASS (0769 ordering:
|
|
15
|
-
# precheck → draft → docs-review → verify → record → done) and `record → done` is
|
|
16
|
-
# fail-closed on the captured record result + re-asserted verdict — never on a stub
|
|
17
|
-
|
|
18
|
-
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
19
|
-
version: "2"
|
|
20
|
-
kind: state-machine
|
|
21
|
-
name: docs-pipeline
|
|
22
|
-
description: "Docs-only execution pipeline (precheck -> draft -> docs-review -> verify -> record -> done)"
|
|
23
|
-
iterationBound: 12
|
|
24
|
-
initialState: precheck
|
|
25
|
-
terminalStates:
|
|
26
|
-
- done
|
|
27
|
-
- failed
|
|
28
|
-
- cancelled
|
|
29
|
-
failureStates:
|
|
30
|
-
- failed
|
|
31
|
-
- cancelled
|
|
32
|
-
vars:
|
|
33
|
-
wbs: "0000"
|
|
34
|
-
profile: "standard"
|
|
35
|
-
spurBin: "spur"
|
|
36
|
-
agent: "auto"
|
|
37
|
-
stepTimeoutMs: "1800000"
|
|
38
|
-
# Proof-state bracket (task 0704, mirroring task-pipeline 0612/0703). `proofDigest` is the
|
|
39
|
-
# canonical capture at verify entry; `proofDigestNow` is the live re-capture compared against
|
|
40
|
-
# it by the `verify → record` guard so verifier-time mutation fails closed (R4/R5).
|
|
41
|
-
proofDigest: ""
|
|
42
|
-
proofDigestNow: ""
|
|
43
|
-
# `taskSpecPath` carries the task file path because `docs/tasks*` is excluded from the digest's
|
|
44
|
-
# git-tree half (task 0704 R4); resolved per-run by the verify state's taskpath shell step.
|
|
45
|
-
taskSpecPath: ""
|
|
46
|
-
# 0785 R2: linked feature spec path, resolved at verify entry. Empty (orphan task) means the
|
|
47
|
-
# feature spec is legitimately omitted from the digest inputs (empty-string compatibility);
|
|
48
|
-
# a declared feature whose path fails to resolve fails closed.
|
|
49
|
-
featureSpecPath: ""
|
|
50
|
-
__hitlAnswer: ""
|
|
51
|
-
# R8 (0366): injected by WorkflowAppService.run(); run-scopes every temporary capture.
|
|
52
|
-
__runId: ""
|
|
53
|
-
|
|
54
|
-
states:
|
|
55
|
-
- id: precheck
|
|
56
|
-
description: >
|
|
57
|
-
Soft precheck: task check + agent doctor, each owned by a deterministic `command.gate`
|
|
58
|
-
(D5-J, ADR-069). Both gates run `softFail: true`, so a red probe records FAIL and lets
|
|
59
|
-
the transitions route to `failed` instead of aborting the run — the shipped action
|
|
60
|
-
schema exposes no `onError`, so soft mode is what preserves that routing.
|
|
61
|
-
The canonical `.spur/run/$__runId-docs-precheck.status` is the AND of the two gate files.
|
|
62
|
-
(0769: temporary captures are run-scoped — `.spur/run/<runId>-docs-*` — so concurrent
|
|
63
|
-
runs on one task never share or clobber a capture.)
|
|
64
|
-
onEnter:
|
|
65
|
-
- kind: command.gate
|
|
66
|
-
options:
|
|
67
|
-
id: docs-precheck-task
|
|
68
|
-
executable: "${vars.spurBin}"
|
|
69
|
-
args: ["task", "check", "${vars.wbs}"]
|
|
70
|
-
resultFile: .spur/run/${vars.__runId}-docs-precheck-task.status
|
|
71
|
-
softFail: true
|
|
72
|
-
timeoutMs: 120000
|
|
73
|
-
- kind: command.gate
|
|
74
|
-
options:
|
|
75
|
-
id: docs-precheck-agent
|
|
76
|
-
executable: "${vars.spurBin}"
|
|
77
|
-
args: ["agent", "doctor", "${vars.agent}"]
|
|
78
|
-
resultFile: .spur/run/${vars.__runId}-docs-precheck-agent.status
|
|
79
|
-
softFail: true
|
|
80
|
-
timeoutMs: 120000
|
|
81
|
-
- kind: shell
|
|
82
|
-
options:
|
|
83
|
-
command: >-
|
|
84
|
-
if test "$(cat .spur/run/$__runId-docs-precheck-task.status 2>/dev/null)" = PASS &&
|
|
85
|
-
test "$(cat .spur/run/$__runId-docs-precheck-agent.status 2>/dev/null)" = PASS;
|
|
86
|
-
then printf 'PASS\n' > ".spur/run/$__runId-docs-precheck.status";
|
|
87
|
-
else printf 'FAIL\n' > ".spur/run/$__runId-docs-precheck.status"; fi
|
|
88
|
-
- kind: note
|
|
89
|
-
options:
|
|
90
|
-
message: "Docs pipeline start for task ${vars.wbs}."
|
|
91
|
-
|
|
92
|
-
- id: draft
|
|
93
|
-
description: >
|
|
94
|
-
Author or update the documentation deliverable for task ${vars.wbs}. Pure slash
|
|
95
|
-
implement hop (ADR-043). Docs-only scope is owned by the implement competency when
|
|
96
|
-
the task template/background is documentation — not by YAML essays.
|
|
97
|
-
onEnter:
|
|
98
|
-
- kind: agent.run
|
|
99
|
-
options:
|
|
100
|
-
agent: ${vars.agent}
|
|
101
|
-
# Pure slash only (ADR-043). Do not bolt docs-only prose onto the input line.
|
|
102
|
-
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
103
|
-
role: coder
|
|
104
|
-
input: /sp:dev-run --mode implement ${vars.wbs} --auto
|
|
105
|
-
timeoutMs: ${vars.stepTimeoutMs}
|
|
106
|
-
# Fail a silent no-op draft (same empty-implement class as task-pipeline R3).
|
|
107
|
-
requireDiff: true
|
|
108
|
-
- kind: shell
|
|
109
|
-
options:
|
|
110
|
-
command: "$spurBin task update $wbs wip --no-lifecycle"
|
|
111
|
-
|
|
112
|
-
- id: docs-review
|
|
113
|
-
description: >
|
|
114
|
-
Human documentation review gate. Under profile=auto this state is skipped; in
|
|
115
|
-
interactive mode it pauses for explicit approval before recording completion.
|
|
116
|
-
pause: true
|
|
117
|
-
onEnter:
|
|
118
|
-
- kind: hitl.confirm
|
|
119
|
-
options:
|
|
120
|
-
prompt: "Approve docs-only deliverable for task ${vars.wbs}?"
|
|
121
|
-
|
|
122
|
-
- id: verify
|
|
123
|
-
description: >
|
|
124
|
-
Read-only measured verification (task 0704, R2/R4/R7): dispatch /sp:dev-verify --fix none
|
|
125
|
-
with an answer file, derive the ONE standard verdict via `spur task verdict`, register the
|
|
126
|
-
standard verify-verdict artifact, and bracket the verifier with proof-input digest capture/compare so any
|
|
127
|
-
task-spec or document mutation during certification fails closed (R4). No docs assurance
|
|
128
|
-
subclass — PASS semantics are identical to task-pipeline (R7). 0769: verification now
|
|
129
|
-
PRECEDES recording; the `verify → record` guard compares the proof bracket, and the
|
|
130
|
-
verdict artifact keeps its `.spur/run/<wbs>-verdict.json` compatibility path with
|
|
131
|
-
runId + definitionDigest stamped through the existing proof/run-artifact contract.
|
|
132
|
-
onEnter:
|
|
133
|
-
# 0769: clear any stale current-run answer before the fresh-session verifier writes it.
|
|
134
|
-
- kind: shell
|
|
135
|
-
options:
|
|
136
|
-
command: "mkdir -p .spur/run && rm -f .spur/run/$__runId-docs-verify-answer.txt"
|
|
137
|
-
# R4 (0703 R6 precedent): resolve the task-spec path BEFORE capture. `docs/tasks*` is
|
|
138
|
-
# excluded from the digest's git-tree half, so the spec is folded in via `taskFile`.
|
|
139
|
-
- kind: shell
|
|
140
|
-
options:
|
|
141
|
-
# (e) 0825: 6 lines — fail-closed lookup feeds the verdict/digest file names
|
|
142
|
-
# (0760 R1); a silent miss would degrade the proof to tree-only.
|
|
143
|
-
command: >-
|
|
144
|
-
set -e;
|
|
145
|
-
task_path="$($spurBin task path $wbs --json | jq -r '.path // .filePath // empty')";
|
|
146
|
-
if [ -z "$task_path" ]; then echo "docs-pipeline: task path did not resolve for wbs $wbs" >&2; exit 1; fi;
|
|
147
|
-
printf '%s' "$task_path" > ".spur/run/$__runId-docs-taskpath.txt"
|
|
148
|
-
- kind: file.read.into-var
|
|
149
|
-
options:
|
|
150
|
-
path: .spur/run/${vars.__runId}-docs-taskpath.txt
|
|
151
|
-
var: taskSpecPath
|
|
152
|
-
# 0785 R2: resolve the linked feature spec path so the digest covers it too. An orphan task
|
|
153
|
-
# (no feature_id) resolves to empty — legitimately omitted via empty-string compatibility;
|
|
154
|
-
# a declared feature whose spec path does not resolve fails closed instead of silently
|
|
155
|
-
# folding a stale spec into the proof.
|
|
156
|
-
- kind: shell
|
|
157
|
-
options:
|
|
158
|
-
# (e) 0825: 9 lines — per-check rc capture (task show/feature show/jq) keeps an
|
|
159
|
-
# orphan task and a broken linked feature distinguishable (0785 R2 contract).
|
|
160
|
-
command: >-
|
|
161
|
-
set -e;
|
|
162
|
-
FID="$($spurBin task show $wbs --json 2>/dev/null | jq -r '.feature_id // .frontmatter.feature_id // empty' 2>/dev/null)";
|
|
163
|
-
FPATH_OUT="";
|
|
164
|
-
if [ -n "$FID" ]; then
|
|
165
|
-
FPATH_OUT="$($spurBin feature show "$FID" --json | jq -r '.filePath // .path // empty')";
|
|
166
|
-
if [ -z "$FPATH_OUT" ]; then echo "docs-pipeline: feature $FID linked to task $wbs but its spec path did not resolve" >&2; exit 1; fi;
|
|
167
|
-
fi;
|
|
168
|
-
printf '%s' "$FPATH_OUT" > ".spur/run/$__runId-docs-featurepath.txt"
|
|
169
|
-
- kind: file.read.into-var
|
|
170
|
-
options:
|
|
171
|
-
path: .spur/run/${vars.__runId}-docs-featurepath.txt
|
|
172
|
-
var: featureSpecPath
|
|
173
|
-
# R4: canonical capture BEFORE the verifier runs. Same fingerprint input as the
|
|
174
|
-
# re-capture below so the bracket compares like for like.
|
|
175
|
-
- kind: proof.fingerprint
|
|
176
|
-
options:
|
|
177
|
-
var: proofDigest
|
|
178
|
-
taskFile: ${vars.taskSpecPath}
|
|
179
|
-
featureFile: ${vars.featureSpecPath}
|
|
180
|
-
input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
|
|
181
|
-
timeoutMs: ${vars.stepTimeoutMs}
|
|
182
|
-
- kind: agent.run
|
|
183
|
-
options:
|
|
184
|
-
agent: ${vars.agent}
|
|
185
|
-
# Observe-only (ADR-071 precedent): the verifier certifies, it never repairs.
|
|
186
|
-
# 0710 R2: verify runs in a fresh session — never inherits the implement hop's session.
|
|
187
|
-
freshSession: true
|
|
188
|
-
input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
|
|
189
|
-
role: reviewer
|
|
190
|
-
timeoutMs: ${vars.stepTimeoutMs}
|
|
191
|
-
answerFile: .spur/run/${vars.__runId}-docs-verify-answer.txt
|
|
192
|
-
expectFile: .spur/run/${vars.__runId}-docs-verify-answer.txt
|
|
193
|
-
- kind: shell
|
|
194
|
-
options:
|
|
195
|
-
command: "$spurBin task verdict $wbs --from-answer .spur/run/$__runId-docs-verify-answer.txt"
|
|
196
|
-
# R7: stamp the proof block + run identity into the standard verdict artifact, then register
|
|
197
|
-
# it. Soft action + hard guard: a missing/malformed stamp fails the `verify -> record`
|
|
198
|
-
# guard below, not this step.
|
|
199
|
-
- kind: shell
|
|
200
|
-
options:
|
|
201
|
-
# (e) 0825: 6 lines — stamp shell freezes the docs proof digest for the closing
|
|
202
|
-
# guard; the record→done guard compares against this stamp.
|
|
203
|
-
command: >-
|
|
204
|
-
V=".spur/run/$wbs-verdict.json";
|
|
205
|
-
if [ -f "$V" ] && [ -n "$proofDigest" ]; then
|
|
206
|
-
jq --arg d "$proofDigest" --arg r "$__runId" '. + {proof: {digest: $d, capturePoint: "docs-verify-entry", runId: $r}}' "$V" > "$V.tmp" && mv "$V.tmp" "$V";
|
|
207
|
-
fi;
|
|
208
|
-
exit 0
|
|
209
|
-
- kind: run.artifact
|
|
210
|
-
options:
|
|
211
|
-
path: .spur/run/${vars.wbs}-verdict.json
|
|
212
|
-
artifactKind: verify-verdict
|
|
213
|
-
# R4: re-capture AFTER the verifier. No `expect` here — an action-level abort would
|
|
214
|
-
# bypass the `failed` state; the `verify -> done` guard compares instead (R5).
|
|
215
|
-
- kind: proof.fingerprint
|
|
216
|
-
options:
|
|
217
|
-
var: proofDigestNow
|
|
218
|
-
taskFile: ${vars.taskSpecPath}
|
|
219
|
-
featureFile: ${vars.featureSpecPath}
|
|
220
|
-
input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
|
|
221
|
-
timeoutMs: ${vars.stepTimeoutMs}
|
|
222
|
-
|
|
223
|
-
- id: record
|
|
224
|
-
description: >
|
|
225
|
-
Record the docs-only outcome AFTER measured verification (task 0769 ordering:
|
|
226
|
-
draft/approval → verify → record → done — the pre-verification record could write
|
|
227
|
-
UNKNOWN/old Testing evidence). The verdict is already derived and proof-bracketed in
|
|
228
|
-
`verify`; `verify → record` only opens on measured PASS with an intact bracket. The
|
|
229
|
-
task record verb backfills Solution from the diff and moves the task to testing; its
|
|
230
|
-
result is captured to a run-scoped status file so a record denial reaches `failed`
|
|
231
|
-
(record → failed) and is never converted to success by an exit 0.
|
|
232
|
-
onEnter:
|
|
233
|
-
- kind: shell
|
|
234
|
-
options:
|
|
235
|
-
command: >-
|
|
236
|
-
if $spurBin task record $wbs --solution-from-diff --transition testing; then
|
|
237
|
-
printf 'PASS\n' > ".spur/run/$__runId-docs-record.status";
|
|
238
|
-
else
|
|
239
|
-
printf 'FAIL\n' > ".spur/run/$__runId-docs-record.status";
|
|
240
|
-
fi
|
|
241
|
-
|
|
242
|
-
- id: done
|
|
243
|
-
description: Terminal — docs deliverable measured, reviewed, and recorded.
|
|
244
|
-
onEnter:
|
|
245
|
-
# R1 (0704): no synthetic verdict writer. The verdict artifact is produced by measured
|
|
246
|
-
# verification in `verify` and registered there; done only performs the guarded
|
|
247
|
-
# transition. Override path remains: --force-done --reason.
|
|
248
|
-
- kind: shell
|
|
249
|
-
options:
|
|
250
|
-
command: "$spurBin task update $wbs done --no-lifecycle"
|
|
251
|
-
- kind: note
|
|
252
|
-
options:
|
|
253
|
-
message: "Docs pipeline complete for task ${vars.wbs}."
|
|
254
|
-
- id: failed
|
|
255
|
-
description: Terminal — docs pipeline failed or was rejected.
|
|
256
|
-
|
|
257
|
-
- id: cancelled
|
|
258
|
-
description: Terminal — docs pipeline cancelled by operator.
|
|
259
|
-
|
|
260
|
-
transitions:
|
|
261
|
-
- from: precheck
|
|
262
|
-
to: draft
|
|
263
|
-
description: Precheck PASS — begin docs draft.
|
|
264
|
-
guard:
|
|
265
|
-
kind: shell
|
|
266
|
-
options:
|
|
267
|
-
command: 'test "$(cat .spur/run/$__runId-docs-precheck.status 2>/dev/null)" = PASS'
|
|
268
|
-
- from: precheck
|
|
269
|
-
to: failed
|
|
270
|
-
description: Precheck FAIL — stop before draft.
|
|
271
|
-
guard:
|
|
272
|
-
kind: always
|
|
273
|
-
|
|
274
|
-
- from: draft
|
|
275
|
-
to: verify
|
|
276
|
-
description: "profile=auto — skip the docs-review HITL gate; verify measures BEFORE record (0769: a pre-verification record could write UNKNOWN/old Testing evidence)."
|
|
277
|
-
guard:
|
|
278
|
-
kind: shell
|
|
279
|
-
options:
|
|
280
|
-
command: 'test "$profile" = auto'
|
|
281
|
-
- from: draft
|
|
282
|
-
to: docs-review
|
|
283
|
-
description: Interactive — enter docs-review.
|
|
284
|
-
guard:
|
|
285
|
-
kind: always
|
|
286
|
-
|
|
287
|
-
- from: docs-review
|
|
288
|
-
to: verify
|
|
289
|
-
description: "Docs approved — measure the deliverable (0769: verification precedes recording)."
|
|
290
|
-
guard:
|
|
291
|
-
kind: shell
|
|
292
|
-
options:
|
|
293
|
-
command: 'test "$__hitlAnswer" = yes'
|
|
294
|
-
- from: docs-review
|
|
295
|
-
to: failed
|
|
296
|
-
description: Docs rejected — stop for revision.
|
|
297
|
-
guard:
|
|
298
|
-
kind: shell
|
|
299
|
-
options:
|
|
300
|
-
command: 'test "$__hitlAnswer" = no'
|
|
301
|
-
- from: docs-review
|
|
302
|
-
to: cancelled
|
|
303
|
-
description: Operator cancelled docs review.
|
|
304
|
-
guard:
|
|
305
|
-
kind: shell
|
|
306
|
-
options:
|
|
307
|
-
command: 'test "$__hitlAnswer" = cancel'
|
|
308
|
-
|
|
309
|
-
- from: verify
|
|
310
|
-
to: record
|
|
311
|
-
description: Measured PASS with the proof bracket intact (R4/R5) — record only verified
|
|
312
|
-
outcomes (0769). Structural task-check gates remain at precheck, record (wip→testing),
|
|
313
|
-
and done (verdict-artifact guard, R3).
|
|
314
|
-
guard:
|
|
315
|
-
kind: shell
|
|
316
|
-
options:
|
|
317
|
-
# (e) 0825: 8-line operand ladder condensed to one jq select — same file, same
|
|
318
|
-
# digest-locked PASS semantics (0769 R4/R5); empty/malformed still fail closed.
|
|
319
|
-
command: >-
|
|
320
|
-
test -n "$proofDigest" &&
|
|
321
|
-
test -n "$proofDigestNow" &&
|
|
322
|
-
test "$proofDigestNow" = "$proofDigest" &&
|
|
323
|
-
test "$(jq -r --arg d "$proofDigest" 'select(.proof.digest == $d) | .verdict // empty' ".spur/run/$wbs-verdict.json" 2>/dev/null)" = PASS
|
|
324
|
-
- from: verify
|
|
325
|
-
to: failed
|
|
326
|
-
description: Non-PASS verdict, missing/malformed answer, or digest mismatch (R5) — the run
|
|
327
|
-
reaches failed and nothing is recorded.
|
|
328
|
-
guard:
|
|
329
|
-
kind: always
|
|
330
|
-
|
|
331
|
-
- from: record
|
|
332
|
-
to: done
|
|
333
|
-
description: Recorded from a verified outcome; the persisted verdict/bracket is re-asserted
|
|
334
|
-
so a failed `task record` (captured FAIL) never converts to done (0769).
|
|
335
|
-
guard:
|
|
336
|
-
kind: shell
|
|
337
|
-
options:
|
|
338
|
-
# (e) 0825: 5-line guard — captured record PASS + digest-locked persisted verdict
|
|
339
|
-
# must both hold before done; a failed `task record` never converts to success.
|
|
340
|
-
command: >-
|
|
341
|
-
test "$(cat .spur/run/$__runId-docs-record.status 2>/dev/null)" = PASS &&
|
|
342
|
-
test -f ".spur/run/$wbs-verdict.json" &&
|
|
343
|
-
test "$(jq -r '.verdict // empty' .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS &&
|
|
344
|
-
test -n "$proofDigest" &&
|
|
345
|
-
test "$(jq -r '.proof.digest // empty' .spur/run/$wbs-verdict.json 2>/dev/null)" = "$proofDigest"
|
|
346
|
-
- from: record
|
|
347
|
-
to: failed
|
|
348
|
-
description: "Task record denied or errored (captured status not PASS) — the record denial reaches failed; the done guard above never converts it to success."
|
|
349
|
-
guard:
|
|
350
|
-
kind: always
|
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
# Feature development loop — existing-feature reuse: precheck → execute-tasks →
|
|
2
|
-
# feature-verify → integration-review → done.
|
|
3
|
-
#
|
|
4
|
-
# 0782 (feature D6): the caller supplies a featureId whose AC are already accepted and whose
|
|
5
|
-
# task roster already exists. This definition REUSES them — the brainstorm/plan states and
|
|
6
|
-
# their edges are deleted, so no model hop ever re-plans or re-decomposes an existing feature
|
|
7
|
-
# (explicit planning stays at /sp:dev-plan and /sp:dev-idea, outside this consumer).
|
|
8
|
-
#
|
|
9
|
-
# Reliability (aligned with task-pipeline / ADR-043):
|
|
10
|
-
# - Soft precheck (feature identity + roster structural contract) → failed via transitions,
|
|
11
|
-
# never a raw lifecycle abort. The doctor probe is gone: the precheck now performs the
|
|
12
|
-
# essential feature/roster validation itself; task execution owns executor availability.
|
|
13
|
-
# - Every agent.run input is a pure slash command (no free-form pipeline essays)
|
|
14
|
-
# - featureId must be supplied by the caller (workflow vars are not agent-mutated)
|
|
15
|
-
# - feature-verify runs `feature check --as done --json` EXACTLY ONCE (0782 R3): the shell
|
|
16
|
-
# captures the exit code and JSON result, writes the decision to a .status sibling, and
|
|
17
|
-
# the guards only read that status — no sibling guard re-runs the check.
|
|
18
|
-
# - A nonempty all-terminal roster routes straight to feature-verify with zero execution
|
|
19
|
-
# model calls (0782 R2).
|
|
20
|
-
|
|
21
|
-
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
22
|
-
kind: state-machine
|
|
23
|
-
name: feature-dev
|
|
24
|
-
version: "3"
|
|
25
|
-
description: >
|
|
26
|
-
Existing-feature execution loop: precheck → execute-tasks → feature-verify → done.
|
|
27
|
-
Drives a WHOLE feature whose accepted AC and task roster already exist — the caller
|
|
28
|
-
supplies featureId, this loop reuses the roster and runs it to verified completion.
|
|
29
|
-
For planning a NEW feature use /sp:dev-plan / /sp:dev-idea; for one deliverable use
|
|
30
|
-
task-pipeline.yaml directly.
|
|
31
|
-
|
|
32
|
-
The engine has no native for-each over a dynamic task list, so execution DELEGATES the
|
|
33
|
-
fan-out: the precheck resolves the linked roster via `spur feature show` + `spur task
|
|
34
|
-
list --feature` (captured once under .spur/run/<runId>-feature-dev-{feature,roster}.json),
|
|
35
|
-
validates the essential structural contract (identity, roster shape, duplicate/mismatched
|
|
36
|
-
identities, refinement-blocking statuses), and freezes the sorted todo WBS list into
|
|
37
|
-
.spur/run/<runId>-feature-dev-tasks.txt. The execute-tasks step reads that frozen list
|
|
38
|
-
into a var (file.read.into-var) and dispatches ONE pure-slash /sp:dev-runall --tasks run
|
|
39
|
-
with it — the child never re-enumerates membership (0782 R2).
|
|
40
|
-
|
|
41
|
-
Shape: precheck → execute-tasks[-auto](delegated frozen batch) → feature-verify →
|
|
42
|
-
integration-review → done
|
|
43
|
-
(precheck failure, a non-PASS completion check, or a blocking review short-circuits
|
|
44
|
-
to `failed`; a nonempty all-terminal roster skips execution entirely).
|
|
45
|
-
|
|
46
|
-
Vars (passed as a JSON object via `--vars`):
|
|
47
|
-
featureId — the existing feature ID this loop drives (required), e.g. `--vars '{"featureId":"B3"}'`
|
|
48
|
-
agent — agent the agent.run steps invoke; override `--vars '{"agent":"claude"}'`
|
|
49
|
-
profile — `auto` selects execute-tasks-auto (`/sp:dev-runall --tasks … --auto`); otherwise
|
|
50
|
-
interactive execute-tasks (no --auto, per-task HITL remains)
|
|
51
|
-
featureTaskIds — frozen todo WBS list projected from the roster file at run time; declared
|
|
52
|
-
empty so template resolution cannot throw before the read lands (0782 design)
|
|
53
|
-
spurBin — PATH-independent spur invocation (CLI overrides at run start; literal fallback)
|
|
54
|
-
stepTimeoutMs — agent.run budget (ms) for the runall dispatch
|
|
55
|
-
|
|
56
|
-
Reliability (ADR-043): every agent.run input is a pure slash command. featureId must be
|
|
57
|
-
supplied by the caller (workflow vars cannot be mutated by the agent). profile is wired
|
|
58
|
-
via two execute hops (templates cannot branch a single input string).
|
|
59
|
-
iterationBound: 20
|
|
60
|
-
initialState: precheck
|
|
61
|
-
terminalStates:
|
|
62
|
-
- done
|
|
63
|
-
- failed
|
|
64
|
-
failureStates:
|
|
65
|
-
- failed
|
|
66
|
-
vars:
|
|
67
|
-
featureId: ""
|
|
68
|
-
agent: "auto"
|
|
69
|
-
profile: "standard"
|
|
70
|
-
featureTaskIds: ""
|
|
71
|
-
spurBin: "spur"
|
|
72
|
-
stepTimeoutMs: "1800000"
|
|
73
|
-
# Integration review (D5-P, feature R11). Advisory by default: a pending, timed-out, or
|
|
74
|
-
# quota-unavailable review must never block a locally-verified feature. Set
|
|
75
|
-
# requireCleanReview=true to opt into a hard gate for a branch that must ship clean.
|
|
76
|
-
baseBranch: ""
|
|
77
|
-
requireCleanReview: "false"
|
|
78
|
-
# Injected by WorkflowAppService.run(); scopes .spur/run artifacts per run (0425 R4).
|
|
79
|
-
__runId: ""
|
|
80
|
-
|
|
81
|
-
states:
|
|
82
|
-
- id: precheck
|
|
83
|
-
description: >
|
|
84
|
-
Soft precheck (0782 R1): resolve the supplied feature and its linked task roster via
|
|
85
|
-
existing CLI reads, then validate the essential structural contract — non-empty
|
|
86
|
-
featureId/runId, a feature-show JSON whose identity matches, a nonempty array roster
|
|
87
|
-
with unique non-empty WBS identities and known statuses, no backlog/wip/testing/blocked
|
|
88
|
-
member (planning/refine/resume handoff), and at least one linked task. Rejects fail
|
|
89
|
-
closed with an actionable handoff BEFORE any model dispatch; nothing is auto-created
|
|
90
|
-
or re-planned. Always exit 0 so failures route to `failed` via transitions.
|
|
91
|
-
onEnter:
|
|
92
|
-
- kind: shell
|
|
93
|
-
options:
|
|
94
|
-
# (d) 0825: the 12-command identity/roster program moved into
|
|
95
|
-
# plugins/sp/scripts/feature-dev-precheck.ts (§1.1 owner); same messages,
|
|
96
|
-
# artifacts and soft-fail exit-0 contract, wrapper fails closed.
|
|
97
|
-
command: >-
|
|
98
|
-
mkdir -p .spur/run; if [ -f plugins/sp/scripts/feature-dev-precheck.ts ]; then bun plugins/sp/scripts/feature-dev-precheck.ts; elif W="$(superskill script path sp feature-dev-precheck.mjs 2>/dev/null)" && [ -f "$W" ]; then node "$W"; else echo "feature-dev precheck failed closed — feature-dev-precheck script not found — run 'superskill install sp'" >&2; printf 'FAIL\n' > ".spur/run/$__runId-feature-dev-precheck.status"; fi; exit 0
|
|
99
|
-
- kind: note
|
|
100
|
-
options:
|
|
101
|
-
message: "Feature-dev start for existing feature ${vars.featureId} (0782 reuse path): roster resolved under .spur/run/${vars.__runId}-feature-dev-roster.json; frozen todo list at .spur/run/${vars.__runId}-feature-dev-tasks.txt."
|
|
102
|
-
|
|
103
|
-
# Two pure-slash execute hops so vars.profile actually controls --auto (ADR-043).
|
|
104
|
-
# Engine templates cannot branch a single input string on profile; declaration-order
|
|
105
|
-
# transitions pick the correct hop (auto first, then interactive fallback). Each hop first
|
|
106
|
-
# reads the FROZEN todo list produced by precheck into featureTaskIds, then dispatches the
|
|
107
|
-
# explicit list — the runall child never re-enumerates membership (0782 R2).
|
|
108
|
-
- id: execute-tasks-auto
|
|
109
|
-
description: >
|
|
110
|
-
profile=auto — dispatch the frozen todo WBS list via pure slash
|
|
111
|
-
/sp:dev-runall --tasks <list> --auto (skips per-task HITL inside task-pipeline).
|
|
112
|
-
onEnter:
|
|
113
|
-
- kind: file.read.into-var
|
|
114
|
-
options:
|
|
115
|
-
path: .spur/run/${vars.__runId}-feature-dev-tasks.txt
|
|
116
|
-
var: featureTaskIds
|
|
117
|
-
trim: true
|
|
118
|
-
- kind: agent.run
|
|
119
|
-
options:
|
|
120
|
-
agent: ${vars.agent}
|
|
121
|
-
input: /sp:dev-runall --tasks ${vars.featureTaskIds} --auto
|
|
122
|
-
answerFile: .spur/run/${vars.__runId}-feature-dev-runall-answer.txt
|
|
123
|
-
expectFile: .spur/run/${vars.__runId}-feature-dev-runall-answer.txt
|
|
124
|
-
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
125
|
-
role: planner
|
|
126
|
-
timeoutMs: ${vars.stepTimeoutMs}
|
|
127
|
-
|
|
128
|
-
- id: execute-tasks
|
|
129
|
-
description: >
|
|
130
|
-
Interactive — dispatch the frozen todo WBS list via pure slash
|
|
131
|
-
/sp:dev-runall --tasks <list> without --auto (per-task HITL approve gates remain
|
|
132
|
-
available).
|
|
133
|
-
onEnter:
|
|
134
|
-
- kind: file.read.into-var
|
|
135
|
-
options:
|
|
136
|
-
path: .spur/run/${vars.__runId}-feature-dev-tasks.txt
|
|
137
|
-
var: featureTaskIds
|
|
138
|
-
trim: true
|
|
139
|
-
- kind: agent.run
|
|
140
|
-
options:
|
|
141
|
-
agent: ${vars.agent}
|
|
142
|
-
input: /sp:dev-runall --tasks ${vars.featureTaskIds}
|
|
143
|
-
answerFile: .spur/run/${vars.__runId}-feature-dev-runall-answer.txt
|
|
144
|
-
expectFile: .spur/run/${vars.__runId}-feature-dev-runall-answer.txt
|
|
145
|
-
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
146
|
-
role: planner
|
|
147
|
-
timeoutMs: ${vars.stepTimeoutMs}
|
|
148
|
-
|
|
149
|
-
- id: feature-verify
|
|
150
|
-
description: >
|
|
151
|
-
Certify the feature is complete (0782 R3): run `spur feature check --as done --json`
|
|
152
|
-
EXACTLY ONCE, capture the exit code and JSON result at
|
|
153
|
-
.spur/run/<runId>-feature-dev-verify.json, and decide PASS/FAIL into the .status
|
|
154
|
-
sibling. PASS requires exit 0, a nonempty result array, and every returned scope
|
|
155
|
-
pass === true. The guards below only read the captured status — no sibling guard
|
|
156
|
-
re-runs the check. No --strict elevation, no whole-corpus scan.
|
|
157
|
-
onEnter:
|
|
158
|
-
- kind: shell
|
|
159
|
-
options:
|
|
160
|
-
# (e) 0825: 9 lines — `feature check --as done` runs EXACTLY ONCE per run (0782 R3)
|
|
161
|
-
# and owns the status write the guards read; split would re-run the check.
|
|
162
|
-
command: >-
|
|
163
|
-
mkdir -p .spur/run; rm -f ".spur/run/$__runId-feature-dev-verify.status"; $spurBin feature check "$featureId" --as done --json > ".spur/run/$__runId-feature-dev-verify.json" 2>&1 && jq -e 'type == "array" and length > 0 and all(.[]; .pass == true)' ".spur/run/$__runId-feature-dev-verify.json" > /dev/null 2>&1 && R=PASS || R=FAIL; printf '%s\n' "$R" > ".spur/run/$__runId-feature-dev-verify.status.tmp" && mv -f ".spur/run/$__runId-feature-dev-verify.status.tmp" ".spur/run/$__runId-feature-dev-verify.status"
|
|
164
|
-
- kind: note
|
|
165
|
-
options:
|
|
166
|
-
message: "Feature verification for ${vars.featureId}: decision at .spur/run/${vars.__runId}-feature-dev-verify.status (evidence at .spur/run/${vars.__runId}-feature-dev-verify.json) — exactly one `feature check --as done --json` invocation per run (0782 R3)."
|
|
167
|
-
|
|
168
|
-
- id: integration-review
|
|
169
|
-
description: >
|
|
170
|
-
Advisory integration review (D5-P, feature R11), upgraded by 0770 to a
|
|
171
|
-
truthful collect: ONE Codex review request per HEAD, then exactly ONE
|
|
172
|
-
`pr-reviewing.ts collect --head <captured-head>` against that same HEAD —
|
|
173
|
-
no wait loop, no polling. The request verdict (`REQUESTED` /
|
|
174
|
-
`ALREADY_REQUESTED` / `ALREADY_REVIEWED`) describes request state only;
|
|
175
|
-
it is NEVER clean evidence. The ONLY clean evidence is the collected
|
|
176
|
-
status (CLEAN / FINDINGS / PENDING) persisted run-scoped at
|
|
177
|
-
.spur/run/<runId>-integration-review-collect.status. A missing head SHA,
|
|
178
|
-
an invalid collect result, or head drift records collect FAIL.
|
|
179
|
-
|
|
180
|
-
D8 decision D1 (0753 R3): invoking `pr-reviewing.ts request` directly —
|
|
181
|
-
the same per-HEAD dedupe-or-request logic `config/workflows/pr-review.yaml`
|
|
182
|
-
uses internally. Request FAIL records FAIL in
|
|
183
|
-
.spur/run/<runId>-integration-review.status, loudly (no softFail).
|
|
184
|
-
`requireCleanReview=true` turns a non-clean COLLECTED verdict (including
|
|
185
|
-
collect FAIL) into the blocking edge declared first below.
|
|
186
|
-
onEnter:
|
|
187
|
-
# (e) 0825: one request action + one collect action (same verdicts, same files,
|
|
188
|
-
# collect gated on the captured head SHA as before) to hold the §1.2 budgets.
|
|
189
|
-
- kind: shell
|
|
190
|
-
options:
|
|
191
|
-
command: >-
|
|
192
|
-
mkdir -p .spur/run; bun "$(superskill script path sp pr-reviewing.ts)" request --base "$baseBranch" --json --status-file ".spur/run/$__runId-integration-review-pr-request.status" > ".spur/run/$__runId-integration-review.json" 2>&1 && printf 'PASS\n' > ".spur/run/$__runId-integration-review.status" || printf 'FAIL\n' > ".spur/run/$__runId-integration-review.status"; exit 0
|
|
193
|
-
- kind: shell
|
|
194
|
-
options:
|
|
195
|
-
# (e) 0825: 8 lines — collect stays head-locked to the request record and records
|
|
196
|
-
# its verdict status file; the rc/status echo is the audible soft-fail contract.
|
|
197
|
-
command: >-
|
|
198
|
-
if H=$(jq -er '.head // empty | select(. != "")' ".spur/run/$__runId-integration-review.json" 2>/dev/null); then bun "$(superskill script path sp pr-reviewing.ts)" collect --head "$H" --json --status-file ".spur/run/$__runId-integration-review-collect.status" > ".spur/run/$__runId-integration-review-collect.json" 2>&1; rc=$?; echo "integration-review: collect rc=$rc status=$(cat ".spur/run/$__runId-integration-review-collect.status" 2>/dev/null || echo missing) — verdict captured to .spur/run/$__runId-integration-review-collect.json" >&2; else echo "integration-review: request result carried no head SHA — collect not run, recorded FAIL" >&2; printf 'FAIL\n' > ".spur/run/$__runId-integration-review-collect.status"; fi; exit 0
|
|
199
|
-
- kind: note
|
|
200
|
-
options:
|
|
201
|
-
message: "Integration review for feature ${vars.featureId}: request verdict at .spur/run/${vars.__runId}-integration-review.status (request state only — REQUESTED/ALREADY_* are NEVER clean evidence); collected verdict at .spur/run/${vars.__runId}-integration-review-collect.status (CLEAN/FINDINGS/PENDING — the only clean evidence). Advisory unless requireCleanReview=true."
|
|
202
|
-
|
|
203
|
-
- id: done
|
|
204
|
-
description: Terminal — the existing feature's roster executed and the feature verified.
|
|
205
|
-
|
|
206
|
-
- id: failed
|
|
207
|
-
description: Terminal — the roster contract was rejected at precheck, a task failed verification, or the feature check did not pass.
|
|
208
|
-
|
|
209
|
-
transitions:
|
|
210
|
-
# ── precheck routing (0782 R1/R2) — declaration order matters: the all-terminal
|
|
211
|
-
# direct-verify edge is tried FIRST so a fully-terminal roster reaches completion
|
|
212
|
-
# verification with zero execution model calls; then the profile hops; then the
|
|
213
|
-
# failure fallback. ──
|
|
214
|
-
- from: precheck
|
|
215
|
-
to: feature-verify
|
|
216
|
-
description: Roster PASS and every linked task is already terminal — verify the feature directly, zero execution model calls.
|
|
217
|
-
guard:
|
|
218
|
-
kind: shell
|
|
219
|
-
options:
|
|
220
|
-
command: 'test "$(cat ".spur/run/$__runId-feature-dev-precheck.status" 2>/dev/null)" = PASS && test -f ".spur/run/$__runId-feature-dev-feature.json" && test ! -s ".spur/run/$__runId-feature-dev-tasks.txt"'
|
|
221
|
-
- from: precheck
|
|
222
|
-
to: execute-tasks-auto
|
|
223
|
-
description: Roster PASS with todo work; profile=auto — batch the frozen list with --auto (no per-task HITL).
|
|
224
|
-
guard:
|
|
225
|
-
kind: shell
|
|
226
|
-
options:
|
|
227
|
-
command: 'test "$(cat ".spur/run/$__runId-feature-dev-precheck.status" 2>/dev/null)" = PASS && test -s ".spur/run/$__runId-feature-dev-tasks.txt" && test "$profile" = auto'
|
|
228
|
-
- from: precheck
|
|
229
|
-
to: execute-tasks
|
|
230
|
-
description: Roster PASS with todo work; interactive — batch the frozen list without --auto.
|
|
231
|
-
guard:
|
|
232
|
-
kind: shell
|
|
233
|
-
options:
|
|
234
|
-
command: 'test "$(cat ".spur/run/$__runId-feature-dev-precheck.status" 2>/dev/null)" = PASS && test -s ".spur/run/$__runId-feature-dev-tasks.txt"'
|
|
235
|
-
- from: precheck
|
|
236
|
-
to: failed
|
|
237
|
-
description: Precheck FAIL (missing identity, malformed/empty roster, duplicate identities, or refinement-blocking statuses) — stop before any model dispatch.
|
|
238
|
-
guard:
|
|
239
|
-
kind: always
|
|
240
|
-
|
|
241
|
-
- from: execute-tasks-auto
|
|
242
|
-
to: feature-verify
|
|
243
|
-
description: Auto batch finished — verify the feature.
|
|
244
|
-
guard:
|
|
245
|
-
kind: always
|
|
246
|
-
- from: execute-tasks
|
|
247
|
-
to: feature-verify
|
|
248
|
-
description: Interactive batch finished — verify the feature.
|
|
249
|
-
guard:
|
|
250
|
-
kind: always
|
|
251
|
-
|
|
252
|
-
# ── feature-verify gate: the captured one-shot check decision certifies review, else
|
|
253
|
-
# fail. Declaration order: the pass guard is tried FIRST. The check itself is NOT
|
|
254
|
-
# re-run here (0782 R3) — the shell decision file is the only evidence. ──
|
|
255
|
-
- from: feature-verify
|
|
256
|
-
to: integration-review
|
|
257
|
-
description: Captured completion check is PASS — spend one integration review on this stable HEAD.
|
|
258
|
-
guard:
|
|
259
|
-
kind: shell
|
|
260
|
-
options:
|
|
261
|
-
command: 'test "$(cat ".spur/run/$__runId-feature-dev-verify.status" 2>/dev/null)" = PASS'
|
|
262
|
-
- from: integration-review
|
|
263
|
-
to: failed
|
|
264
|
-
description: >
|
|
265
|
-
Collected verdict is not CLEAN (FINDINGS / PENDING / collect FAIL or
|
|
266
|
-
missing) and this branch opted into a hard gate (requireCleanReview=true).
|
|
267
|
-
Exactly one collect ran against the captured request HEAD — no wait loop —
|
|
268
|
-
so pending or findings stop the feature here with the actual reason.
|
|
269
|
-
Ordered before the advisory edge so the strict policy wins when both
|
|
270
|
-
would match.
|
|
271
|
-
guard:
|
|
272
|
-
kind: shell
|
|
273
|
-
options:
|
|
274
|
-
command: 'test "$requireCleanReview" = true && test "$(cat .spur/run/$__runId-integration-review-collect.status 2>/dev/null)" != CLEAN'
|
|
275
|
-
- from: integration-review
|
|
276
|
-
to: done
|
|
277
|
-
description: >
|
|
278
|
-
Collected CLEAN, or advisory mode (requireCleanReview != true) — the
|
|
279
|
-
feature is complete. A non-clean advisory collect never blocks a
|
|
280
|
-
locally-verified feature (feature R11); the note above preserves the
|
|
281
|
-
collected non-clean state in the run record instead of hiding it.
|
|
282
|
-
guard:
|
|
283
|
-
kind: always
|
|
284
|
-
- from: feature-verify
|
|
285
|
-
to: failed
|
|
286
|
-
description: Completion check missing, malformed, or non-PASS (or its evidence failed to persist) — block BEFORE integration review; no review is requested (0782 R3).
|
|
287
|
-
guard:
|
|
288
|
-
kind: always
|