@gobing-ai/spur 0.3.91 → 0.3.93
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/pipeline-budgets.json +2 -9
- package/config/plugin-scripts.json +27 -1
- package/config/templates/AGENTS.md +4 -0
- package/config/templates/docs/02_ROADMAP.md +2 -0
- package/config/templates/docs/03_ARCHITECTURE.md +3 -1
- package/config/templates/docs/04_DESIGN.md +2 -0
- package/config/templates/docs/99_PROJECT_CONSTITUTION.md +10 -2
- package/config/workflow-candidates.json +72 -1
- package/config/workflows/feature-lifecycle.yaml +14 -5
- package/config/workflows/feature-verification.yaml +36 -27
- package/config/workflows/history-anatomy.yaml +16 -25
- package/config/workflows/idea-pipeline.yaml +76 -23
- package/config/workflows/pr-review.yaml +8 -0
- package/config/workflows/task-pipeline.yaml +362 -40
- package/config/workflows/wayfinder-resolution.yaml +5 -0
- package/config/workflows/wrapup-pipeline.yaml +102 -19
- package/package.json +9 -9
- package/plugins/sp/README.md +7 -2
- package/plugins/sp/agents/super-planner.md +14 -5
- package/plugins/sp/commands/dev-dogfood.md +4 -4
- package/plugins/sp/commands/dev-fixall.md +8 -5
- package/plugins/sp/commands/dev-run.md +8 -2
- package/plugins/sp/commands/dev-runall.md +14 -8
- package/plugins/sp/commands/dev-verify.md +9 -0
- package/plugins/sp/commands/dev-verifyall.md +5 -0
- package/plugins/sp/lib/idea-handoff.generated.mjs +306 -301
- package/plugins/sp/lib/inline-run.generated.d.mts +18 -0
- package/plugins/sp/lib/inline-run.generated.mjs +1468 -0
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/environment-lens.md +1 -1
- package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +136 -0
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +196 -2
- package/plugins/sp/scripts/feature-verification-steps.mjs +174 -0
- package/plugins/sp/scripts/feature-verification-steps.ts +275 -0
- package/plugins/sp/scripts/history-anatomy-cache.mjs +104 -4
- package/plugins/sp/scripts/history-anatomy-cache.ts +137 -13
- package/plugins/sp/scripts/inline-pipeline-parity-check.ts +2 -1
- package/plugins/sp/scripts/inline-run-setup.mjs +421 -0
- package/plugins/sp/scripts/inline-run-setup.ts +325 -78
- package/plugins/sp/scripts/quality-gate.mjs +248 -6
- package/plugins/sp/scripts/quality-gate.ts +410 -9
- package/plugins/sp/scripts/record-feature-sync.mjs +63 -0
- package/plugins/sp/scripts/record-feature-sync.ts +84 -0
- package/plugins/sp/scripts/residual-scan.mjs +484 -0
- package/plugins/sp/scripts/residual-scan.ts +640 -0
- package/plugins/sp/scripts/task-diffstat.mjs +156 -0
- package/plugins/sp/scripts/task-diffstat.ts +229 -0
- package/plugins/sp/scripts/task-evidence-precheck.ts +8 -3
- package/plugins/sp/scripts/task-size-precheck.ts +8 -3
- package/plugins/sp/scripts/wrapup-drift-probe.mjs +181 -0
- package/plugins/sp/scripts/wrapup-drift-probe.ts +258 -0
- package/plugins/sp/scripts/wrapup-steps.mjs +60 -1
- package/plugins/sp/scripts/wrapup-steps.ts +89 -4
- package/plugins/sp/skills/brainstorm/SKILL.md +2 -0
- package/plugins/sp/skills/brainstorm/references/workflows.md +17 -2
- package/plugins/sp/skills/branch-workflow/SKILL.md +1 -0
- package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +2 -0
- package/plugins/sp/skills/code-implementation/SKILL.md +17 -0
- package/plugins/sp/skills/code-verification/SKILL.md +21 -0
- package/plugins/sp/skills/code-verification/references/secu-review.md +3 -2
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +1 -0
- package/plugins/sp/skills/dogfood-testing/SKILL.md +5 -3
- package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +63 -26
- package/plugins/sp/skills/dogfood-testing/references/report-template.md +33 -10
- package/plugins/sp/skills/history-anatomy/references/modes.md +5 -3
- package/plugins/sp/skills/next-feature/references/ranking-rubric.md +1 -1
- package/plugins/sp/skills/next-router/references/routing-table.md +7 -0
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
- package/plugins/sp/skills/session-review/SKILL.md +12 -2
- package/plugins/sp/skills/spur-check/SKILL.md +112 -0
- package/plugins/sp/skills/spur-cli/references/features.md +1 -1
- package/plugins/sp/skills/spur-cli/references/projects.md +3 -1
- package/plugins/sp/skills/spur-cli/references/workflows.md +39 -19
- package/plugins/sp/skills/spur-dev/SKILL.md +13 -5
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +18 -3
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +2 -2
- package/plugins/sp/skills/spur-dev/references/document-authoring.md +85 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +286 -58
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +1 -1
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +27 -4
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +3 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +61 -16
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +10 -5
- package/plugins/sp/skills/spur-dev/templates/design.md +31 -0
- package/plugins/sp/skills/spur-dev/templates/plan.md +32 -0
- package/plugins/sp/skills/spur-doctor/SKILL.md +60 -14
- package/schemas/state-machine-workflow.schema.json +4 -0
- package/spur.js +22501 -19644
- package/web/_astro/BoardApp.CerSBgis.js +192 -0
- package/web/_astro/BoardApp.eoTz0pZs.js +1 -0
- package/web/_astro/{TaskDetail.CXGltuT_.js → TaskDetail.DCqiC-OZ.js} +1 -1
- package/web/_astro/arc.CPwg6Rw0.js +1 -0
- package/web/_astro/{architectureDiagram-3BPJPVTR.DJ8DHkWE.js → architectureDiagram-3BPJPVTR.DM_vp_hO.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.D8DHK3Jl.js → blockDiagram-GPEHLZMM.DXVIiv0p.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BugQbX9u.js → c4Diagram-AAUBKEIU.BbF_zCxW.js} +1 -1
- package/web/_astro/channel.MYZLKNwy.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.Mv26KlVn.js → chunk-2J33WTMH.CAgQHpPC.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.CD51JoT_.js → chunk-4BX2VUAB.BN-5tpw4.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.D_PFaIEe.js → chunk-55IACEB6.CnPkEEr0.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DemMW1ao.js → chunk-727SXJPM.BQzQeMVm.js} +4 -4
- package/web/_astro/{chunk-AQP2D5EJ.Iu2V5-ex.js → chunk-AQP2D5EJ.B6xNyDnL.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.MsNgSP-E.js → chunk-FMBD7UC4.C7f9Ih78.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.DfbRaAlm.js → chunk-ND2GUHAM.CNV1dFXT.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BbJAQ4h-.js → chunk-QZHKN3VN.Cudn2TkJ.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.CPurtiC2.js → classDiagram-4FO5ZUOK.D1NwP50q.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.CPurtiC2.js → classDiagram-v2-Q7XG4LA2.D1NwP50q.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CKKdx1bM.js → cose-bilkent-S5V4N54A.B1wSL-Xb.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.CoKMTg-R.js → cynefin-OW5HDTMX.BmK52w8G.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.D4h4_k56.js → dagre-BM42HDAG.Bfy5CTDT.js} +2 -2
- package/web/_astro/diagram-2AECGRRQ.DhNnvUvX.js +43 -0
- package/web/_astro/diagram-5GNKFQAL.lTX5KwnS.js +10 -0
- package/web/_astro/{diagram-KO2AKTUF.BFoCkiCr.js → diagram-KO2AKTUF.CW_vMJ4z.js} +3 -3
- package/web/_astro/{diagram-LMA3HP47.exHn9OVx.js → diagram-LMA3HP47.B_8ZGF67.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.CeqO34nN.js → diagram-OG6HWLK6.BppnHsdS.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.D_v7HqxR.js → erDiagram-TEJ5UH35.BEuHXcjJ.js} +5 -5
- package/web/_astro/{flowDiagram-I6XJVG4X.EUmrpbwh.js → flowDiagram-I6XJVG4X.CH-UlnGr.js} +4 -4
- package/web/_astro/{ganttDiagram-6RSMTGT7.BOCF5lII.js → ganttDiagram-6RSMTGT7.BO81S85v.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.Di7otYZD.js → gitGraphDiagram-PVQCEYII.XnPxPPZN.js} +1 -1
- package/web/_astro/index.Hjbr15fG.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.TcBkCAJk.js → infoDiagram-5YYISTIA.JyjYRu_T.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.D-2y4M0c.js → ishikawaDiagram-YF4QCWOH.BBRBF-Fo.js} +5 -5
- package/web/_astro/{journeyDiagram-JHISSGLW.DPbJI_n2.js → journeyDiagram-JHISSGLW.C_iymSyp.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.EFxhQ9Fj.js → kanban-definition-UN3LZRKU.DdfW-Oqt.js} +7 -7
- package/web/_astro/{linear.DSAsQLzs.js → linear.C2_IkbZT.js} +1 -1
- package/web/_astro/mermaid.core.GAOYeSR0.js +303 -0
- package/web/_astro/{mindmap-definition-RKZ34NQL.CJY1N_7V.js → mindmap-definition-RKZ34NQL.DAZIxQSK.js} +2 -2
- package/web/_astro/{pieDiagram-4H26LBE5.567ZNoL2.js → pieDiagram-4H26LBE5.CN8sIhKM.js} +3 -3
- package/web/_astro/{quadrantDiagram-W4KKPZXB.mqfz9-MY.js → quadrantDiagram-W4KKPZXB.3dGcX5GP.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.Bv1Gv9In.js → requirementDiagram-4Y6WPE33.BV2y4dd6.js} +3 -3
- package/web/_astro/{sankeyDiagram-5OEKKPKP.B6Gs4X4r.js → sankeyDiagram-5OEKKPKP.Cqo15Tvo.js} +4 -4
- package/web/_astro/{sequenceDiagram-3UESZ5HK.BhYj4v-m.js → sequenceDiagram-3UESZ5HK.CROCPMJB.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.BPbBnkpw.js → stateDiagram-AJRCARHV.RfXZrkFE.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.C4squMNK.js → stateDiagram-v2-BHNVJYJU.CPXmbBs9.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.C_SwIHgl.js → timeline-definition-PNZ67QCA.DdgKTiO8.js} +3 -3
- package/web/_astro/{vennDiagram-CIIHVFJN.Bz4NZGpQ.js → vennDiagram-CIIHVFJN.CPNVSHF1.js} +5 -5
- package/web/_astro/{wardleyDiagram-YWT4CUSO.CozMVZ3i.js → wardleyDiagram-YWT4CUSO.CQhA0Jyr.js} +3 -3
- package/web/_astro/{xychartDiagram-2RQKCTM6.BwMGBwjB.js → xychartDiagram-2RQKCTM6.n61BWyy4.js} +1 -1
- package/web/index.html +2 -2
- package/config/workflows/decision-routing-example.yaml +0 -134
- package/web/_astro/BoardApp.BEDWpzsr.js +0 -188
- package/web/_astro/BoardApp.DQG2xfEz.js +0 -1
- package/web/_astro/arc.C0rrflm_.js +0 -1
- package/web/_astro/channel.SRrg1P-w.js +0 -1
- package/web/_astro/diagram-2AECGRRQ.DJ0h9zgw.js +0 -43
- package/web/_astro/diagram-5GNKFQAL.DvPk1jYd.js +0 -10
- package/web/_astro/index.Bx6GY4RH.css +0 -1
- package/web/_astro/mermaid.core.kAZjgJHG.js +0 -301
|
@@ -6,13 +6,18 @@
|
|
|
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[→test-fix↔test-recheck] → review → approve(HITL)
|
|
9
|
+
# Shape: precheck → implement[→escalate] → test[→test-fix↔test-recheck] → review → approve(HITL)
|
|
10
10
|
# → verify → record → done
|
|
11
11
|
# (precheck failure short-circuits to `failed`; approve routes to `failed` on
|
|
12
12
|
# operator rejection or `cancelled` on operator cancel — R1, bug-750).
|
|
13
13
|
# `test` is the project quality gate (shell + bounded /sp:dev-fixall), not
|
|
14
14
|
# /sp:dev-unit (coverage gap-fill; router C3/C5).
|
|
15
15
|
#
|
|
16
|
+
# F96 residual sweep (0950): precheck captures the resume-safe base commit; verify
|
|
17
|
+
# scans and folds residuals between the verdict and the proof bind (blocking leftovers
|
|
18
|
+
# downgrade PASS → PARTIAL and take the existing remediation edge); done settles
|
|
19
|
+
# deferrals; failed renders the recovery report. No new state, edge, or model query.
|
|
20
|
+
#
|
|
16
21
|
# Vars (passed as a JSON object via `--vars`):
|
|
17
22
|
# wbs — task WBS (required)
|
|
18
23
|
# profile — "auto" skips HITL approve (R4)
|
|
@@ -21,6 +26,7 @@
|
|
|
21
26
|
# implementTimeoutMs — implement agent.run budget (ms)
|
|
22
27
|
# qualityGateCmd — project gate (default: bun run spur-check)
|
|
23
28
|
# qualityGateMaxFixAttempts — max /sp:dev-fixall hops after a red gate (default: 2)
|
|
29
|
+
# maxEscalations — max operator-question pauses per implement chain (default: 2)
|
|
24
30
|
#
|
|
25
31
|
# Seeded by `spur init`. agent.run inputs are pure slash commands (ADR-043).
|
|
26
32
|
|
|
@@ -90,6 +96,10 @@ vars:
|
|
|
90
96
|
# Answer captured by the approve gate's hitl.confirm (R1): "yes" | "no" | "cancel".
|
|
91
97
|
# Empty by default; only meaningful once the approve state has been entered.
|
|
92
98
|
__hitlAnswer: ""
|
|
99
|
+
# Operator answer captured by the escalate hop's hitl.input (0933). Empty by
|
|
100
|
+
# default; set by `spur workflow continue --answer-text` after the pause and read
|
|
101
|
+
# by the escalate→implement / escalate→failed guards. Non-empty = answered.
|
|
102
|
+
__hitlInput: ""
|
|
93
103
|
# Proof-state bracket (task 0612, ADR-071; restructured by task 0703). `proofDigest` is the
|
|
94
104
|
# canonical capture taken at quality-gate ENTRY — immediately before the evidence-producing
|
|
95
105
|
# final chain (quality → review → verify) — and re-captured at `test-recheck` when bounded
|
|
@@ -134,6 +144,14 @@ vars:
|
|
|
134
144
|
# Max /sp:dev-fixall attempts after a red quality-gate probe/recheck (bounded; no thrash).
|
|
135
145
|
# Attempt counter: .spur/run/<wbs>-test-fix-attempt. Default 2 = two fixall hops before failed.
|
|
136
146
|
qualityGateMaxFixAttempts: "2"
|
|
147
|
+
# Max operator-question pauses (0933) before the implement chain routes to failed.
|
|
148
|
+
# Escalation counter: .spur/run/<wbs>-escalation-count. Default 2 = two answered
|
|
149
|
+
# questions; a third pause routes to failed with a report note.
|
|
150
|
+
maxEscalations: "2"
|
|
151
|
+
# Runtime-written, 0933: the escalate hop's file.read.into-var fills this from
|
|
152
|
+
# .spur/run/<wbs>-question.md; the hitl.input prompt below references it. Declared
|
|
153
|
+
# here (empty) so the static var-reference validator sees the template source.
|
|
154
|
+
escalationQuestion: ""
|
|
137
155
|
# Post-implement auto-format. Overridable like qualityGateCmd so a non-Bun seeded
|
|
138
156
|
# project can point it at its own formatter; invoked best-effort (a missing or
|
|
139
157
|
# failing formatter must never abort a run — the quality gate is the real gate).
|
|
@@ -156,6 +174,12 @@ vars:
|
|
|
156
174
|
# (default) = on; set to "off" to bypass:
|
|
157
175
|
# `--vars '{"implementScopeGuard":"off"}'`.
|
|
158
176
|
implementScopeGuard: ""
|
|
177
|
+
# 0931 R5: parallel batches defer the per-task feature sync so a task branch never
|
|
178
|
+
# touches feature files or docs/features/INDEX.md. When "true", the record step's
|
|
179
|
+
# post-record shell appends a deferral note and skips the sync; the parallel batch
|
|
180
|
+
# orchestrator runs the sync + `spur feature refresh` once per touched feature on the
|
|
181
|
+
# base ref after integration. Sequential/inline keep the default "false" (unchanged).
|
|
182
|
+
deferFeatureSync: "false"
|
|
159
183
|
|
|
160
184
|
states:
|
|
161
185
|
- id: precheck
|
|
@@ -189,6 +213,12 @@ states:
|
|
|
189
213
|
options:
|
|
190
214
|
command: >-
|
|
191
215
|
mkdir -p .spur/run; S=plugins/sp/scripts/task-evidence-precheck.ts; [ -f "$S" ] || S="$(superskill script path sp task-evidence-precheck.ts 2>/dev/null)"; if [ -f "$S" ]; then bun "$S" "$wbs" --spur-bin "$spurBin"; else echo "task-evidence-precheck failed closed — checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'." >&2; echo "FAIL" > ".spur/run/$wbs-precheck-evidence.status"; fi; exit 0
|
|
216
|
+
# (e) F96 R1 (0950): capture the run's base commit once — a resumed or re-entered run
|
|
217
|
+
# keeps its original base so residual scans stay anchored to the same diff.
|
|
218
|
+
- kind: shell
|
|
219
|
+
options:
|
|
220
|
+
command: >-
|
|
221
|
+
mkdir -p .spur/run; [ -f ".spur/run/$wbs-base.sha" ] || git rev-parse HEAD > ".spur/run/$wbs-base.sha"; exit 0
|
|
192
222
|
# (e) route-reason lookup and routes log; proportional-routing tests locate it
|
|
193
223
|
# (0759 R1/R5 run-scoped artifact; 0804 R8 run-id safety — one line, no in-scalar `#`).
|
|
194
224
|
- kind: shell
|
|
@@ -222,6 +252,20 @@ states:
|
|
|
222
252
|
that command DRIVES this pipeline, so calling it here recurses.
|
|
223
253
|
--mode implement is the single-step implement entry.
|
|
224
254
|
onEnter:
|
|
255
|
+
# 0933 R27 (guard-lines compression): the transcript append lives HERE, on
|
|
256
|
+
# (re-)entry, not in the escalate→implement guard. On first entry there is no
|
|
257
|
+
# pending question (no-op); on a resume entry the guard already confirmed a
|
|
258
|
+
# non-empty $__hitlInput and a fresh question file, so this shell records the
|
|
259
|
+
# Q/A pair (## Q<n>/## A<n>, R3) and consumes the question file before the
|
|
260
|
+
# agent.run re-dispatches — which also disarms the implement→escalate edge.
|
|
261
|
+
- kind: shell
|
|
262
|
+
options:
|
|
263
|
+
command: >-
|
|
264
|
+
test -n "$__hitlInput" -a -s .spur/run/$wbs-question.md || exit 0;
|
|
265
|
+
qn="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)";
|
|
266
|
+
printf '## Q%s\n%s\n\n## A%s\n%s\n' "$qn" "$(cat .spur/run/$wbs-question.md 2>/dev/null)" "$qn" "$__hitlInput" >> .spur/run/$wbs-escalation.md;
|
|
267
|
+
rm -f .spur/run/$wbs-question.md;
|
|
268
|
+
exit 0
|
|
225
269
|
- kind: agent.run
|
|
226
270
|
options:
|
|
227
271
|
agent: ${vars.implementAgent}
|
|
@@ -232,13 +276,23 @@ states:
|
|
|
232
276
|
# resumes the implement session instead of re-reading the task cold.
|
|
233
277
|
session: reuse
|
|
234
278
|
# lives in /sp:dev-run --mode implement → sp:code-implementation, not YAML prose.
|
|
235
|
-
|
|
279
|
+
# 0933 R28: --escalation-file names the Q/A transcript the implement
|
|
280
|
+
# agent appends to when pausing and reads back on re-dispatch; absent
|
|
281
|
+
# on a first attempt means "no prior escalations".
|
|
282
|
+
input: /sp:dev-run --mode implement ${vars.wbs} --auto --escalation-file .spur/run/${vars.wbs}-escalation.md
|
|
236
283
|
timeoutMs: ${vars.implementTimeoutMs}
|
|
237
284
|
# R3 (task 0424): empty-implement no-op guard — the agent.run action
|
|
238
285
|
# fails the step when exit 0 produced zero non-corpus file changes, so
|
|
239
286
|
# a silent no-op routes the run to `failed` here instead of drifting
|
|
240
287
|
# into test/review and being caught a full pass later.
|
|
241
288
|
requireDiff: true
|
|
289
|
+
# 0933 R26: escalation contract — the agent.run option names the QUESTION
|
|
290
|
+
# file (the pause signal, deleted pre-dispatch for freshness); a paused
|
|
291
|
+
# attempt (agent wrote its question there and exited 0) succeeds with
|
|
292
|
+
# data.escalated=true and skips requireDiff for THAT attempt only. The
|
|
293
|
+
# Q/A transcript (.spur/run/<wbs>-escalation.md) is separate: it reaches
|
|
294
|
+
# the agent via --escalation-file in the input below.
|
|
295
|
+
escalationFile: .spur/run/${vars.wbs}-question.md
|
|
242
296
|
# 0706 R6: this stage mutates the working tree unattended under the
|
|
243
297
|
# auto profile, so it declares minimum execution-capability
|
|
244
298
|
# requirements. Dispatch fails closed (before spawn) when the
|
|
@@ -273,6 +327,39 @@ states:
|
|
|
273
327
|
options:
|
|
274
328
|
command: "$formatCmd ; exit 0"
|
|
275
329
|
|
|
330
|
+
# ── escalate hop (operator-question pause, 0933) ──────────────────────────
|
|
331
|
+
# The implement agent paused on an operator question: it wrote
|
|
332
|
+
# .spur/run/<wbs>-question.md and exited 0 (agent.run reported
|
|
333
|
+
# data.escalated=true, skipping requireDiff for that attempt). This hop bounds
|
|
334
|
+
# the asks (counter), surfaces the question verbatim through the HITL responder
|
|
335
|
+
# (the run pauses here), and — after `spur workflow continue --answer-text <a>`
|
|
336
|
+
# delivers __hitlInput — resumes implement with the Q/A transcript
|
|
337
|
+
# (.spur/run/<wbs>-escalation.md) named in the implement input via
|
|
338
|
+
# --escalation-file. The transcript append + question-file consumption happen in
|
|
339
|
+
# the escalate→implement guard so a stale question can never re-trigger the hop
|
|
340
|
+
# after the answered attempt.
|
|
341
|
+
- id: escalate
|
|
342
|
+
description: >-
|
|
343
|
+
Operator-question pause (0933): the implement agent asked a question
|
|
344
|
+
headlessly; surface it to the operator and resume implement with the answer.
|
|
345
|
+
onEnter:
|
|
346
|
+
# Bounded asks: increment the per-task escalation counter before pausing.
|
|
347
|
+
- kind: shell
|
|
348
|
+
options:
|
|
349
|
+
command: >-
|
|
350
|
+
mkdir -p .spur/run; n="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)"; echo $((n + 1)) > .spur/run/$wbs-escalation-count; exit 0
|
|
351
|
+
# The agent's question, verbatim, becomes the pause prompt.
|
|
352
|
+
- kind: file.read.into-var
|
|
353
|
+
options:
|
|
354
|
+
file: .spur/run/${vars.wbs}-question.md
|
|
355
|
+
var: escalationQuestion
|
|
356
|
+
# Pause for the operator (responder pause:true stops the run after this
|
|
357
|
+
# onEnter; `spur workflow continue --answer-text <answer>` writes
|
|
358
|
+
# __hitlInput and re-evaluates the escalate guards).
|
|
359
|
+
- kind: hitl.input
|
|
360
|
+
options:
|
|
361
|
+
prompt: "${vars.escalationQuestion}"
|
|
362
|
+
|
|
276
363
|
# ── test hop (quality gate + bounded auto-fix) ─────────────────────────────
|
|
277
364
|
# NOT /sp:dev-unit. That command (sp:code-testing) *extends/generates* tests toward
|
|
278
365
|
# a coverage target; it is not the project quality gate. Coverage gap-fill remains
|
|
@@ -358,6 +445,14 @@ states:
|
|
|
358
445
|
options:
|
|
359
446
|
command: >-
|
|
360
447
|
mkdir -p .spur/run; A=".spur/run/$wbs-test-fix-attempt"; n=$(cat "$A" 2>/dev/null || echo 0); printf '%s\n' "$((n + 1))" > "$A"; [ ! -f ".spur/run/$wbs-verdict.json" ] || { echo '--- verify verdict (remediation input, task 0703 R4) ---'; cat ".spur/run/$wbs-verdict.json"; } >> ".spur/run/$wbs-test-gate.log"; exit 0
|
|
448
|
+
# (d) F96 R3 (0950): hand the residual list to the remediation loop — dev-fixall
|
|
449
|
+
# treats residual items as fix targets and may defer P3/markers to
|
|
450
|
+
# residual-deferrals.json (see dev-fixall.md). Fold already merged the anchors
|
|
451
|
+
# into <wbs>-test-gate.findings; this carries the structured artifact too.
|
|
452
|
+
- kind: shell
|
|
453
|
+
options:
|
|
454
|
+
command: >-
|
|
455
|
+
[ ! -f ".spur/run/$wbs-residuals.json" ] || { echo '--- residual artifact (F96 fix targets; deferrals go to residual-deferrals.json, P3/markers only) ---'; cat ".spur/run/$wbs-residuals.json"; } >> ".spur/run/$wbs-test-gate.log"; exit 0
|
|
361
456
|
# R3 (0482): project the extracted gate anchors into a var so the dispatch input
|
|
362
457
|
# can NAME the failing file:line, not merely point at a log. A vars template cannot
|
|
363
458
|
# run a shell, so the read is an action, not an inline `$(cat ...)` substitution.
|
|
@@ -391,8 +486,8 @@ states:
|
|
|
391
486
|
- id: test-recheck
|
|
392
487
|
description: >
|
|
393
488
|
Soft recheck after fixall with bounded SQLite-lock retry. Writes PASS|FAIL (always exit 0). Transitions
|
|
394
|
-
branch to
|
|
395
|
-
or the pipeline `failed` state (
|
|
489
|
+
branch to `triage` (PASS — the 0943 lane router), `test-fail-triage` (FAIL — the 0943
|
|
490
|
+
failure-class router), or the pipeline `failed` state (corrupt status) — never a
|
|
396
491
|
raw lifecycle abort that skips the terminal `failed` state.
|
|
397
492
|
onEnter:
|
|
398
493
|
# R4 (0703, ADR-071): bounded remediation mutated the tree by design, so the fresh evidence
|
|
@@ -415,6 +510,99 @@ states:
|
|
|
415
510
|
command: >-
|
|
416
511
|
mkdir -p .spur/run; if [ -f plugins/sp/scripts/quality-gate.ts ]; then bun plugins/sp/scripts/quality-gate.ts recheck; elif Q="$(superskill script path sp quality-gate.mjs 2>/dev/null)" && [ -f "$Q" ]; then node "$Q" recheck; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
|
|
417
512
|
|
|
513
|
+
- id: triage
|
|
514
|
+
description: >-
|
|
515
|
+
Deterministic lane router between a green gate and the review/verify fork (0943 R1).
|
|
516
|
+
Writes the diffstat evidence file, honors a caller-set `mode` (never overridden), pins
|
|
517
|
+
the safety lane on sensitive paths or >400 changed lines without a model call (R2c),
|
|
518
|
+
otherwise consults `decide task-triage` (low → fast lane; anything else stays empty →
|
|
519
|
+
standard review path), and appends the triage route reason to
|
|
520
|
+
.spur/memory/task-pipeline-routes.log (R5). The `decide` action itself runs
|
|
521
|
+
unconditionally (the engine has no onEnter conditionals); its result is consulted only
|
|
522
|
+
when neither a caller mode nor the deterministic guard resolved the lane. The resolved
|
|
523
|
+
lane lands in the `mode` var for the triage → verify/review guards.
|
|
524
|
+
onEnter:
|
|
525
|
+
# (a) diffstat producer: task-diffstat.ts owns git reading and sensitive-path
|
|
526
|
+
# classification; shell only resolves it and fails closed (writes sensitive:true,
|
|
527
|
+
# which the pre-guard below maps to the safety lane).
|
|
528
|
+
- kind: shell
|
|
529
|
+
options:
|
|
530
|
+
command: >-
|
|
531
|
+
mkdir -p .spur/run; if [ -f plugins/sp/scripts/task-diffstat.ts ]; then bun plugins/sp/scripts/task-diffstat.ts --spur-bin "$spurBin"; elif D="$(superskill script path sp task-diffstat.mjs 2>/dev/null)" && [ -f "$D" ]; then node "$D"; else echo "task-diffstat failed closed — task-diffstat script not found — run 'superskill install sp'" >&2; printf '{"files":0,"insertions":0,"deletions":0,"paths":[],"sensitive":true}\n' > ".spur/run/$wbs-diffstat.json"; fi; exit 0
|
|
532
|
+
# (b)+(c) lane pre-guard BEFORE decide: a caller-set mode is projected verbatim (R2b);
|
|
533
|
+
# a sensitive path or >400 changed lines pins safety (R2c) and the decide result below
|
|
534
|
+
# is never consulted. A missing/malformed diffstat row (producer crashed or never ran,
|
|
535
|
+
# disk error) pins safety HERE: an empty mode file would let the low decide row project
|
|
536
|
+
# the fast lane downstream, so the "never to fast" fail-safe is enforced at the guard,
|
|
537
|
+
# not by the projection (the full-suite gate run exposed this fail-open path).
|
|
538
|
+
- kind: shell
|
|
539
|
+
options:
|
|
540
|
+
command: >-
|
|
541
|
+
mkdir -p .spur/run; if [ -n "$mode" ]; then printf '%s\n' "$mode" > ".spur/run/$wbs-mode.txt"; exit 0; fi; DF=".spur/run/$wbs-diffstat.json"; if ! jq -e 'type == "object"' "$DF" >/dev/null 2>&1; then printf 'safety\n' > ".spur/run/$wbs-mode.txt"; exit 0; fi; jq -r 'if .sensitive == true or ((.insertions // 0) + (.deletions // 0)) > 400 then "safety" else empty end' "$DF" 2>/dev/null > ".spur/run/$wbs-mode.txt"; exit 0
|
|
542
|
+
# (d) lane decision — degrades to the standard default whenever workflow.decideDecisionMaker
|
|
543
|
+
# is off (R4), so with the flag off this state is pure shell: no model call is made.
|
|
544
|
+
- kind: decide
|
|
545
|
+
options:
|
|
546
|
+
id: task-triage
|
|
547
|
+
method: choice
|
|
548
|
+
question: >-
|
|
549
|
+
The quality gate is green. Which verification lane does this diff deserve —
|
|
550
|
+
low (small, contained diff — fast lane), standard, or high caution?
|
|
551
|
+
choices: [low, standard, high]
|
|
552
|
+
default: standard
|
|
553
|
+
evidence:
|
|
554
|
+
- .spur/run/${vars.wbs}-diffstat.json
|
|
555
|
+
- ${vars.taskSpecPath}
|
|
556
|
+
resultFile: .spur/run/${vars.wbs}-triage.decision
|
|
557
|
+
# (d) project the decision: low → fast lane; anything else (standard/high, degraded
|
|
558
|
+
# default, missing row) leaves the mode empty → standard review path. A non-empty mode
|
|
559
|
+
# file (caller-set or deterministic-high) is never overridden.
|
|
560
|
+
- kind: shell
|
|
561
|
+
options:
|
|
562
|
+
command: >-
|
|
563
|
+
MF=".spur/run/$wbs-mode.txt"; [ -s "$MF" ] && exit 0; jq -r 'if .value == "low" then "fast" else empty end' ".spur/run/$wbs-triage.decision" 2>/dev/null > "$MF"; exit 0
|
|
564
|
+
# R5: append the triage route reason in the shared routes-log format.
|
|
565
|
+
- kind: shell
|
|
566
|
+
options:
|
|
567
|
+
command: >-
|
|
568
|
+
m="$(cat ".spur/run/$wbs-mode.txt")"; RUN_ID="$__runId"; [ -n "$RUN_ID" ] || RUN_ID="pipeline-$wbs"; mkdir -p .spur/memory; printf '%s %s %s\n' "$RUN_ID" "$wbs" "$(jq -rn --arg m "$m" --arg c "$mode" 'if $c != "" then ($c + ":caller-set") else {"fast":"fast:triage low lane","safety":"safety:triage deterministic-high","":"safety:triage standard lane"}[$m] // "safety:triage unrecognized mode" end')" >> .spur/memory/task-pipeline-routes.log
|
|
569
|
+
# (d) the resolved lane becomes the `mode` var for the triage → verify/review guards.
|
|
570
|
+
- kind: file.read.into-var
|
|
571
|
+
options:
|
|
572
|
+
path: .spur/run/${vars.wbs}-mode.txt
|
|
573
|
+
var: mode
|
|
574
|
+
|
|
575
|
+
- id: test-fail-triage
|
|
576
|
+
description: >-
|
|
577
|
+
Deterministic failure-class router on a red gate (0943 R3). The engine has no onEnter
|
|
578
|
+
conditionals, so the FAIL branch from `test`/`test-recheck` lands here as its own
|
|
579
|
+
deterministic state (the sanctioned alternative), while the green branch goes to
|
|
580
|
+
`triage`. `decide failure-class` reads the bounded gate findings and routes: retryable
|
|
581
|
+
→ test-recheck (the attempt is counted on entry, so qualityGateMaxFixAttempts still
|
|
582
|
+
bounds the loop), fix → test-fix (the repair hop, as before), stop → failed with
|
|
583
|
+
terminalReason failed-check. A missing/corrupt decision fails closed to failed-check.
|
|
584
|
+
onEnter:
|
|
585
|
+
- kind: decide
|
|
586
|
+
options:
|
|
587
|
+
id: failure-class
|
|
588
|
+
method: choice
|
|
589
|
+
question: >-
|
|
590
|
+
The quality gate failed. Is the failure retryable (transient or environmental
|
|
591
|
+
— just re-run the gate), fixable by the repair agent, or should the run stop
|
|
592
|
+
here?
|
|
593
|
+
choices: [retryable, fix, stop]
|
|
594
|
+
default: fix
|
|
595
|
+
evidence:
|
|
596
|
+
- .spur/run/${vars.wbs}-test-gate.findings
|
|
597
|
+
resultFile: .spur/run/${vars.wbs}-failure-class.decision
|
|
598
|
+
# A retryable classification still counts an attempt so the existing
|
|
599
|
+
# qualityGateMaxFixAttempts cap bounds the recheck loop (0943 R3; the cap edge reads
|
|
600
|
+
# the same counter the fixall path uses).
|
|
601
|
+
- kind: shell
|
|
602
|
+
options:
|
|
603
|
+
command: >-
|
|
604
|
+
A=".spur/run/$wbs-test-fix-attempt"; [ "$(jq -r '.value // ""' ".spur/run/$wbs-failure-class.decision" 2>/dev/null)" = retryable ] && { n="$(cat "$A" 2>/dev/null || echo 0)"; printf '%s\n' "$((n + 1))" > "$A"; }; exit 0
|
|
605
|
+
|
|
418
606
|
- id: review
|
|
419
607
|
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`.
|
|
420
608
|
onEnter:
|
|
@@ -530,6 +718,16 @@ states:
|
|
|
530
718
|
- kind: shell
|
|
531
719
|
options:
|
|
532
720
|
command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
|
|
721
|
+
# (d) F96 R2 (0950): residual-scan.ts owns the sweep; shell only resolves it.
|
|
722
|
+
# ONE hard action (scan+fold): a scanner crash fails verify closed — the
|
|
723
|
+
# verify→failed catch-all routes a missing/malformed verdict. Runs AFTER
|
|
724
|
+
# `task verdict` and BEFORE the jq bind so a blocking residual turns PASS
|
|
725
|
+
# into PARTIAL (fold rewrites the verdict artifact) and takes the existing
|
|
726
|
+
# verify→test-fix edge while attempts remain.
|
|
727
|
+
- kind: shell
|
|
728
|
+
options:
|
|
729
|
+
command: >-
|
|
730
|
+
S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ ! -f "$S" ]; then echo "residual-scan failed closed — scanner not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'" >&2; exit 1; fi; case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" scan "$wbs" --spur-bin "$spurBin" && "$RUNNER" "$S" fold "$wbs" --spur-bin "$spurBin"
|
|
533
731
|
# (e) one jq mutation binds the verdict to the proof digest (0703 R3; runId 0730 §B.2 /
|
|
534
732
|
# 0757 R4; definitionDigest 0759 R5; honest review stamp 0785 R4; soft action + hard guard).
|
|
535
733
|
- kind: shell
|
|
@@ -584,10 +782,16 @@ states:
|
|
|
584
782
|
# (d) feature-sync-bounded.ts owns the sync; shell adds the orphan note and fallbacks
|
|
585
783
|
# (0411 retry-suppression; 0328 / ADR-0322). Best-effort `exit 0` — feature status sync is a
|
|
586
784
|
# follow-up, not a completion gate; `record → done` runs `spur task check`.
|
|
785
|
+
# 0931 R5: with deferFeatureSync "true" (parallel mode) the deferral note lands in the
|
|
786
|
+
# task report and the sync is skipped entirely, so task branches never touch feature
|
|
787
|
+
# corpus files; the batch orchestrator performs the deferred sync on the base ref.
|
|
788
|
+
# The sync itself is owned by record-feature-sync.ts (ADR-115: the guard plus the old
|
|
789
|
+
# inline chain cannot share one shell); resolution follows the standard in-repo-first,
|
|
790
|
+
# superskill-staged fallback used by every pipeline checker.
|
|
587
791
|
- kind: shell
|
|
588
792
|
options:
|
|
589
793
|
command: >-
|
|
590
|
-
|
|
794
|
+
S=plugins/sp/scripts/record-feature-sync.ts; [ -f "$S" ] || S="$(superskill script path sp record-feature-sync.mjs 2>/dev/null)"; [ "$deferFeatureSync" = "true" ] && echo "feature sync deferred to batch integration" >> ".spur/run/$wbs-report.txt" || if [ -f "$S" ]; then bun "$S" --spur-bin "$spurBin"; else echo "feature sync skipped — record-feature-sync not found in plugins/sp/scripts/ nor staged" >> ".spur/run/$wbs-report.txt"; fi; exit 0
|
|
591
795
|
|
|
592
796
|
- id: done
|
|
593
797
|
description: >
|
|
@@ -595,6 +799,13 @@ states:
|
|
|
595
799
|
guard runs `spur task check` before certifying; a genuinely non-compliant
|
|
596
800
|
task routes to `failed` instead of a silent bad `done`.
|
|
597
801
|
onEnter:
|
|
802
|
+
# (d) F96 R4 (0950): residual-scan.ts owns the settle; shell only resolves it.
|
|
803
|
+
# Soft best-effort (exit 0) — runs after certification and must never change
|
|
804
|
+
# the outcome; failure prints the re-run command.
|
|
805
|
+
- kind: shell
|
|
806
|
+
options:
|
|
807
|
+
command: >-
|
|
808
|
+
S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ -f "$S" ]; then case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" settle "$wbs" --spur-bin "$spurBin" || echo "residual-settle failed — re-run: residual-scan settle $wbs" >&2; else echo "residual-scan not staged — settle skipped — re-run: residual-scan settle $wbs" >&2; fi; exit 0
|
|
598
809
|
# (c) command.gate owns the done transition with classified transient retry.
|
|
599
810
|
- kind: command.gate
|
|
600
811
|
options:
|
|
@@ -620,7 +831,28 @@ states:
|
|
|
620
831
|
- id: failed
|
|
621
832
|
description: >
|
|
622
833
|
Terminal — precheck, quality-gate exhaustion, verify non-PASS, record check
|
|
623
|
-
failure, or operator rejection; reported, not advanced.
|
|
834
|
+
failure, or operator rejection; reported, not advanced. Also receives an
|
|
835
|
+
escalation-bound pause or an operator give-up (0933).
|
|
836
|
+
onEnter:
|
|
837
|
+
# 0933 R30 (guard-lines compression): the escalation-bound report note lives
|
|
838
|
+
# here as a conditional — no-op unless the run reached failed with a pending
|
|
839
|
+
# question at (or above) the ask bound (bound pause or final give-up). The
|
|
840
|
+
# unanswered question itself is appended to the task report (report.txt, R2).
|
|
841
|
+
- kind: shell
|
|
842
|
+
options:
|
|
843
|
+
command: >-
|
|
844
|
+
n="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)";
|
|
845
|
+
test "$n" -ge "$maxEscalations" -a -s .spur/run/$wbs-question.md || exit 0;
|
|
846
|
+
printf '\n## Escalation bound reached\n\nThe implement step asked an operator question %s times (bound %s) and ended without a resumable answer. Unanswered question:\n\n' "$n" "$maxEscalations" >> .spur/run/$wbs-report.txt;
|
|
847
|
+
cat .spur/run/$wbs-question.md >> .spur/run/$wbs-report.txt;
|
|
848
|
+
exit 0
|
|
849
|
+
# (d) F96 R5 (0950): residual-scan.ts owns the report; shell only resolves it.
|
|
850
|
+
# Soft (exit 0): a run that exhausts its fix budget on residuals leaves the
|
|
851
|
+
# report + recovery line while the task stays `wip`.
|
|
852
|
+
- kind: shell
|
|
853
|
+
options:
|
|
854
|
+
command: >-
|
|
855
|
+
S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ -f "$S" ]; then case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" report "$wbs" --spur-bin "$spurBin" || echo "residual-report failed — re-run: residual-scan report $wbs" >&2; else echo "residual-scan not staged — report skipped — re-run: residual-scan report $wbs" >&2; fi; exit 0
|
|
624
856
|
|
|
625
857
|
- id: cancelled
|
|
626
858
|
description: Terminal — pipeline cancelled by operator at the approval gate (R1).
|
|
@@ -640,43 +872,85 @@ transitions:
|
|
|
640
872
|
test "$size_status" = PASS && test "$evidence_status" = PASS && $spurBin task check $wbs
|
|
641
873
|
- from: precheck
|
|
642
874
|
to: failed
|
|
875
|
+
terminalReason: failed-check
|
|
643
876
|
description: Size and/or task check failed — stop before implement.
|
|
644
877
|
guard:
|
|
645
878
|
kind: always
|
|
646
879
|
|
|
880
|
+
# ── implement routing: escalation first (0933 R26/R30), then the linear body ──
|
|
881
|
+
# Declaration order matters: the escalation bound is checked FIRST — a paused
|
|
882
|
+
# attempt that already exhausted its maxEscalations asks routes to failed (with a
|
|
883
|
+
# report note appended in the same guard) instead of asking forever; then the
|
|
884
|
+
# question-presence hop; then the normal always edge. The bound guard requires a
|
|
885
|
+
# fresh question file so a COMPLETED implement after max asks still routes to test.
|
|
886
|
+
- from: implement
|
|
887
|
+
to: failed
|
|
888
|
+
terminalReason: retry-exhausted
|
|
889
|
+
description: Escalation bound exhausted — the agent paused again after maxEscalations operator answers.
|
|
890
|
+
# 0933 R30 (guard-lines compression): thin predicate; the report note is written
|
|
891
|
+
# by the failed state's onEnter when it observes a bound-exhausted pause.
|
|
892
|
+
guard:
|
|
893
|
+
kind: shell
|
|
894
|
+
options:
|
|
895
|
+
command: >-
|
|
896
|
+
n="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)";
|
|
897
|
+
test "$n" -ge "$maxEscalations" -a -s .spur/run/$wbs-question.md
|
|
898
|
+
- from: implement
|
|
899
|
+
to: escalate
|
|
900
|
+
description: Implement agent paused on an operator question (non-empty question file) — pause for an answer.
|
|
901
|
+
guard:
|
|
902
|
+
kind: shell
|
|
903
|
+
options:
|
|
904
|
+
command: 'test -s .spur/run/$wbs-question.md'
|
|
647
905
|
# ── linear body ──
|
|
648
906
|
- from: implement
|
|
649
907
|
to: test
|
|
650
908
|
description: Implementation done — quality-gate probe.
|
|
651
909
|
guard:
|
|
652
910
|
kind: always
|
|
653
|
-
#
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
911
|
+
# escalate branching (0933 R27): an answered pause resumes implement — the transcript
|
|
912
|
+
# append and question consumption happen in implement's onEnter (guards stay thin
|
|
913
|
+
# under ADR-115 guard-lines caps); an empty answer is an operator give-up → failed
|
|
914
|
+
# (question + transcript preserved as evidence).
|
|
915
|
+
- from: escalate
|
|
916
|
+
to: implement
|
|
917
|
+
description: Operator answered — re-enter implement, which records the Q/A transcript and consumes the question.
|
|
657
918
|
guard:
|
|
658
919
|
kind: shell
|
|
659
920
|
options:
|
|
660
|
-
command:
|
|
661
|
-
|
|
662
|
-
|
|
921
|
+
command: 'test -n "$__hitlInput"'
|
|
922
|
+
- from: escalate
|
|
923
|
+
to: failed
|
|
924
|
+
terminalReason: cancelled
|
|
925
|
+
description: Empty operator answer — give-up routes to failed (question + transcript preserved as evidence).
|
|
926
|
+
guard:
|
|
927
|
+
kind: shell
|
|
928
|
+
options:
|
|
929
|
+
command: 'test -z "$__hitlInput"'
|
|
930
|
+
# Soft probe branching (declaration order: PASS → triage, FAIL → test-fail-triage, defense).
|
|
931
|
+
# 0943 R1/R3: the four former gate-PASS edges (test/test-recheck → verify/review, split on
|
|
932
|
+
# `$mode`) are replaced by the deterministic `triage` lane producer; a red gate lands in
|
|
933
|
+
# `test-fail-triage` where `decide failure-class` routes the failure instead of a static fixall.
|
|
663
934
|
- from: test
|
|
664
|
-
to:
|
|
665
|
-
description: Quality gate
|
|
935
|
+
to: triage
|
|
936
|
+
description: Quality gate green — route the lane deterministically (triage, 0943 R1).
|
|
666
937
|
guard:
|
|
667
938
|
kind: shell
|
|
668
939
|
options:
|
|
669
940
|
command: >-
|
|
670
941
|
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
671
|
-
test "$gate_status" = PASS
|
|
942
|
+
test "$gate_status" = PASS
|
|
672
943
|
- from: test
|
|
673
|
-
to: test-
|
|
674
|
-
description: Quality gate red —
|
|
944
|
+
to: test-fail-triage
|
|
945
|
+
description: Quality gate red — classify the failure before the repair hop (0943 R3).
|
|
675
946
|
guard:
|
|
676
947
|
kind: shell
|
|
677
948
|
options:
|
|
678
949
|
command: 'test "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)" = FAIL'
|
|
679
|
-
#
|
|
950
|
+
# 0943 review P3#2: the former `test → test-fix` FAIL edge is removed — it was dead (the
|
|
951
|
+
# identical guard on test → test-fail-triage fires first) and a silent spec-bypass trap:
|
|
952
|
+
# restoring it would skip failure-class on every red gate. The always-defense below keeps
|
|
953
|
+
# pre-0943 corrupt-status behavior (fixall then recheck).
|
|
680
954
|
- from: test
|
|
681
955
|
to: test-fix
|
|
682
956
|
description: Probe status missing/corrupt — attempt fixall then recheck.
|
|
@@ -687,51 +961,95 @@ transitions:
|
|
|
687
961
|
description: Fixall finished — soft recheck the same quality gate.
|
|
688
962
|
guard:
|
|
689
963
|
kind: always
|
|
690
|
-
# Recheck branching (PASS
|
|
964
|
+
# Recheck branching (PASS → triage; red → test-fail-triage; defense). The two former
|
|
965
|
+
# static FAIL edges (under-max → test-fix, exhausted → failed retry-exhausted) moved into
|
|
966
|
+
# test-fail-triage's decision routing (0943 R3).
|
|
691
967
|
- from: test-recheck
|
|
692
|
-
to:
|
|
693
|
-
description: Quality gate green after fixall
|
|
968
|
+
to: triage
|
|
969
|
+
description: Quality gate green after fixall — route the lane deterministically (triage, 0943 R1).
|
|
694
970
|
guard:
|
|
695
971
|
kind: shell
|
|
696
972
|
options:
|
|
697
973
|
command: >-
|
|
698
974
|
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
699
|
-
test "$gate_status" = PASS
|
|
975
|
+
test "$gate_status" = PASS
|
|
700
976
|
- from: test-recheck
|
|
701
|
-
to:
|
|
702
|
-
description:
|
|
977
|
+
to: test-fail-triage
|
|
978
|
+
description: Still red after fixall — classify the failure (0943 R3).
|
|
703
979
|
guard:
|
|
704
980
|
kind: shell
|
|
705
981
|
options:
|
|
706
982
|
command: >-
|
|
707
983
|
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
708
|
-
test "$gate_status" =
|
|
984
|
+
test "$gate_status" = FAIL
|
|
985
|
+
# Defense: corrupt recheck status — failed, not review.
|
|
709
986
|
- from: test-recheck
|
|
710
|
-
to:
|
|
711
|
-
|
|
712
|
-
|
|
987
|
+
to: failed
|
|
988
|
+
terminalReason: failed-check
|
|
989
|
+
description: Recheck status missing/corrupt — stop at failed.
|
|
990
|
+
guard:
|
|
991
|
+
kind: always
|
|
992
|
+
# ── triage routing (0943 R1/R2): the lane producer replaced the four gate-PASS edges.
|
|
993
|
+
# mode=fast → verify; anything else (standard/high, deterministic-high, degraded default,
|
|
994
|
+
# caller-set non-fast) → review. Together the two guards are exhaustive, so triage never hangs.
|
|
995
|
+
- from: triage
|
|
996
|
+
to: verify
|
|
997
|
+
description: Triage resolved the fast lane (caller-set fast or task-triage low) — skip review.
|
|
998
|
+
guard:
|
|
999
|
+
kind: shell
|
|
1000
|
+
options:
|
|
1001
|
+
command: 'test "$mode" = fast'
|
|
1002
|
+
- from: triage
|
|
1003
|
+
to: review
|
|
1004
|
+
description: Triage resolved a review lane (standard/high, deterministic-high, or caller-set) — review.
|
|
1005
|
+
guard:
|
|
1006
|
+
kind: shell
|
|
1007
|
+
options:
|
|
1008
|
+
command: 'test "$mode" != fast'
|
|
1009
|
+
# ── failure-class routing (0943 R3): stop first (never mislabeled by the cap), then the
|
|
1010
|
+
# attempt cap (bounds BOTH lanes — retryable counted on entry, fix as before), then the
|
|
1011
|
+
# decision lanes, then the fail-closed defense. Declaration order matters.
|
|
1012
|
+
- from: test-fail-triage
|
|
1013
|
+
to: failed
|
|
1014
|
+
terminalReason: failed-check
|
|
1015
|
+
description: Failure class stop — the run terminates at failed, never bypassed.
|
|
713
1016
|
guard:
|
|
714
1017
|
kind: shell
|
|
715
1018
|
options:
|
|
716
1019
|
command: >-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
test "$gate_status" = FAIL && test "$fix_attempts" -lt "$qualityGateMaxFixAttempts"
|
|
720
|
-
- from: test-recheck
|
|
1020
|
+
jq -e '.value == "stop"' ".spur/run/$wbs-failure-class.decision" >/dev/null 2>&1
|
|
1021
|
+
- from: test-fail-triage
|
|
721
1022
|
to: failed
|
|
722
|
-
|
|
723
|
-
|
|
1023
|
+
terminalReason: retry-exhausted
|
|
1024
|
+
description: Attempt cap reached — qualityGateMaxFixAttempts bounds the retryable recheck and fix lanes alike.
|
|
1025
|
+
# (warn) 5 commands: named fix attempts (legibility, 0874).
|
|
724
1026
|
guard:
|
|
725
1027
|
kind: shell
|
|
726
1028
|
options:
|
|
727
1029
|
command: >-
|
|
728
|
-
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
729
1030
|
fix_attempts="$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)";
|
|
730
|
-
test "$
|
|
731
|
-
|
|
732
|
-
|
|
1031
|
+
test "$fix_attempts" -ge "$qualityGateMaxFixAttempts"
|
|
1032
|
+
- from: test-fail-triage
|
|
1033
|
+
to: test-recheck
|
|
1034
|
+
description: Failure class retryable and under the cap — re-run the gate without fixall; the attempt was counted on entry.
|
|
1035
|
+
guard:
|
|
1036
|
+
kind: shell
|
|
1037
|
+
options:
|
|
1038
|
+
command: >-
|
|
1039
|
+
jq -e '.value == "retryable"' ".spur/run/$wbs-failure-class.decision" >/dev/null 2>&1
|
|
1040
|
+
- from: test-fail-triage
|
|
1041
|
+
to: test-fix
|
|
1042
|
+
description: Failure class fix and under the cap — the bounded repair hop, as before.
|
|
1043
|
+
guard:
|
|
1044
|
+
kind: shell
|
|
1045
|
+
options:
|
|
1046
|
+
command: >-
|
|
1047
|
+
jq -e '.value == "fix"' ".spur/run/$wbs-failure-class.decision" >/dev/null 2>&1
|
|
1048
|
+
# Defense: missing/corrupt failure-class decision — fail closed instead of silently repairing.
|
|
1049
|
+
- from: test-fail-triage
|
|
733
1050
|
to: failed
|
|
734
|
-
|
|
1051
|
+
terminalReason: failed-check
|
|
1052
|
+
description: Failure-class decision missing/corrupt — stop at failed.
|
|
735
1053
|
guard:
|
|
736
1054
|
kind: always
|
|
737
1055
|
# ── review → approve, OR skip the HITL gate entirely when profile=auto (R4) ──
|
|
@@ -766,6 +1084,7 @@ transitions:
|
|
|
766
1084
|
command: 'test "$__hitlAnswer" = yes'
|
|
767
1085
|
- from: approve
|
|
768
1086
|
to: failed
|
|
1087
|
+
terminalReason: cancelled
|
|
769
1088
|
description: Operator rejected at the approval gate — report and stop.
|
|
770
1089
|
guard:
|
|
771
1090
|
kind: shell
|
|
@@ -773,6 +1092,7 @@ transitions:
|
|
|
773
1092
|
command: 'test "$__hitlAnswer" = no'
|
|
774
1093
|
- from: approve
|
|
775
1094
|
to: cancelled
|
|
1095
|
+
terminalReason: cancelled
|
|
776
1096
|
description: Operator cancelled at the approval gate.
|
|
777
1097
|
guard:
|
|
778
1098
|
kind: shell
|
|
@@ -821,6 +1141,7 @@ transitions:
|
|
|
821
1141
|
test "$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)" -lt "$qualityGateMaxFixAttempts"
|
|
822
1142
|
- from: verify
|
|
823
1143
|
to: failed
|
|
1144
|
+
terminalReason: retry-exhausted
|
|
824
1145
|
description: >-
|
|
825
1146
|
Non-PASS with the fix budget exhausted, or a PASS/missing/malformed verdict whose proof
|
|
826
1147
|
block is absent or mismatched (task 0703 R5) — block before done; defense catch-all so the
|
|
@@ -850,6 +1171,7 @@ transitions:
|
|
|
850
1171
|
test "$verdict" = PASS && test "$proof_digest" = "$proofDigest"
|
|
851
1172
|
- from: record
|
|
852
1173
|
to: failed
|
|
1174
|
+
terminalReason: failed-check
|
|
853
1175
|
description: Task check failed or proof evidence missing/malformed/mismatched — block before done.
|
|
854
1176
|
guard:
|
|
855
1177
|
kind: always
|