@gobing-ai/spur 0.3.99 → 0.4.1
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 +17 -0
- package/config/decisions/gates.yaml +36 -0
- package/config/decisions/history-anatomy.yaml +35 -0
- package/config/decisions/idea-pipeline.yaml +38 -0
- package/config/decisions/task-pipeline.yaml +55 -0
- package/config/plugin-scripts.json +25 -0
- package/config/rules/boundary/sp-runtime-path.yaml +2 -0
- package/config/rules/docs/sourced-api-claims.yaml +60 -0
- package/config/rules/quality/coverage-gate.yaml +5 -3
- package/config/rules/recommended-pre-check.yaml +8 -3
- package/config/rules/strict/runtime-boundaries.yaml +11 -0
- package/config/rules/structure/protected-files.yaml +3 -0
- package/config/rules/structure/scratch-evidence-pointer.yaml +35 -0
- package/config/script-placement-baseline.json +2 -2
- package/config/workflows/feature-lifecycle.yaml +9 -2
- package/config/workflows/history-anatomy.yaml +22 -0
- package/config/workflows/idea-pipeline.yaml +75 -0
- package/config/workflows/task-pipeline.yaml +368 -49
- package/config/workflows/wrapup-pipeline.yaml +106 -13
- package/package.json +9 -9
- package/plugins/sp/README.md +25 -2
- package/plugins/sp/agents/super-planner.md +11 -0
- package/plugins/sp/agents/super-reviewer.md +39 -11
- package/plugins/sp/bunfig.toml +8 -0
- package/plugins/sp/commands/dev-brainstorm.md +29 -16
- package/plugins/sp/commands/dev-changelog.md +5 -4
- package/plugins/sp/commands/dev-find-way.md +80 -0
- package/plugins/sp/commands/dev-idea.md +6 -0
- package/plugins/sp/commands/dev-parallel.md +8 -2
- package/plugins/sp/commands/dev-plan.md +6 -0
- package/plugins/sp/commands/dev-review-session.md +14 -7
- package/plugins/sp/commands/dev-run.md +17 -4
- package/plugins/sp/commands/dev-runall.md +21 -10
- package/plugins/sp/hooks/agent-lifecycle.ts +155 -0
- package/plugins/sp/hooks/context-session-start.ts +1 -1
- package/plugins/sp/hooks/fleet-guest-stop.ts +180 -0
- package/plugins/sp/hooks/hooks.json +45 -1
- package/plugins/sp/hooks/pi/guard-extension.ts +21 -0
- package/plugins/sp/lib/history-anatomy.generated.mjs +5 -0
- package/plugins/sp/lib/idea-handoff.generated.mjs +72 -11
- package/plugins/sp/lib/inline-run-app.ts +28 -0
- package/plugins/sp/lib/inline-run.generated.d.mts +6 -0
- package/plugins/sp/lib/inline-run.generated.mjs +364 -46
- package/plugins/sp/lib/plan-projection.generated.d.mts +28 -0
- package/plugins/sp/lib/plan-projection.generated.mjs +255 -0
- package/plugins/sp/lib/quality-gate.generated.d.mts +47 -1
- package/plugins/sp/lib/quality-gate.generated.mjs +30489 -82
- package/plugins/sp/lib/residual-scan.generated.d.mts +19 -0
- package/plugins/sp/lib/residual-scan.generated.mjs +66 -0
- package/plugins/sp/lib/run-summary-core.ts +561 -0
- package/plugins/sp/lib/transcript.ts +275 -0
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +1 -1
- package/plugins/sp/scripts/batch-plan.mjs +335 -0
- package/plugins/sp/scripts/batch-plan.ts +100 -0
- package/plugins/sp/scripts/batch-preflight.mjs +51 -3
- package/plugins/sp/scripts/batch-preflight.ts +72 -1
- package/plugins/sp/scripts/commit-guard.mjs +216 -0
- package/plugins/sp/scripts/commit-guard.ts +249 -0
- package/plugins/sp/scripts/history-anatomy-cache.mjs +5 -0
- package/plugins/sp/scripts/inline-run-dispatch.mjs +130 -0
- package/plugins/sp/scripts/inline-run-dispatch.ts +135 -0
- package/plugins/sp/scripts/inline-run-setup.mjs +563 -91
- package/plugins/sp/scripts/inline-run-setup.ts +65 -97
- package/plugins/sp/scripts/persist-out-check.mjs +90 -41
- package/plugins/sp/scripts/persist-out-check.ts +112 -57
- package/plugins/sp/scripts/quality-gate.mjs +30407 -73
- package/plugins/sp/scripts/quality-gate.ts +21 -5
- package/plugins/sp/scripts/residual-scan.mjs +88 -38
- package/plugins/sp/scripts/residual-scan.ts +35 -38
- package/plugins/sp/scripts/run-summary.mjs +693 -0
- package/plugins/sp/scripts/run-summary.ts +105 -0
- package/plugins/sp/scripts/session-timeline.mjs +331 -0
- package/plugins/sp/scripts/session-timeline.ts +204 -0
- package/plugins/sp/scripts/wrapup-steps.mjs +150 -2
- package/plugins/sp/scripts/wrapup-steps.ts +203 -1
- package/plugins/sp/skills/brainstorm/SKILL.md +9 -47
- package/plugins/sp/skills/branch-workflow/SKILL.md +1 -0
- package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +1 -0
- package/plugins/sp/skills/code-implementation/SKILL.md +48 -1
- package/plugins/sp/skills/code-verification/SKILL.md +8 -4
- package/plugins/sp/skills/code-verification/references/secu-review.md +3 -0
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +68 -0
- package/plugins/sp/skills/fleet-join/SKILL.md +63 -0
- package/plugins/sp/skills/session-review/SKILL.md +77 -24
- package/plugins/sp/skills/source-driven-development/SKILL.md +5 -0
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +5 -3
- package/plugins/sp/skills/spur-cli/SKILL.md +6 -2
- package/plugins/sp/skills/spur-cli/references/agent.md +124 -17
- package/plugins/sp/skills/spur-cli/references/decision.md +98 -0
- package/plugins/sp/skills/spur-cli/references/message.md +7 -7
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +41 -3
- package/plugins/sp/skills/spur-cli/references/tasks.md +10 -7
- package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +7 -0
- package/plugins/sp/skills/spur-cli/references/workflows.md +7 -2
- package/plugins/sp/skills/spur-composer/SKILL.md +28 -2
- package/plugins/sp/skills/spur-dev/SKILL.md +18 -14
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +6 -3
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +49 -14
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +51 -18
- package/plugins/sp/skills/spur-dev/references/execution-batch-continuation.md +68 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +194 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +113 -963
- package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +130 -0
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +20 -0
- package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +471 -0
- package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +379 -0
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +51 -9
- package/plugins/sp/skills/spur-dev/references/glossary.md +2 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +361 -156
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +6 -0
- package/plugins/sp/skills/spur-dev/references/structured-trace-emission.md +178 -0
- package/plugins/sp/skills/wayfinder/SKILL.md +10 -14
- package/schemas/decision-catalog.schema.json +226 -0
- package/schemas/spur-config.schema.json +25 -0
- package/schemas/state-machine-workflow.schema.json +23 -0
- package/spur.js +28165 -19051
- package/web/_astro/{BoardApp.i4eh_fHA.js → BoardApp.D66k_s_T.js} +1 -1
- package/web/_astro/BoardApp.D6sjAJr_.js +324 -0
- package/web/_astro/{TaskDetail.C5Cu8LdB.js → TaskDetail.BynLnMNc.js} +1 -1
- package/web/_astro/{arc.Bu5XpBEz.js → arc._BUadrdH.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.9vHQTvhF.js → architectureDiagram-3BPJPVTR.Dh7xS1Pp.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.Cn2Xl7D6.js → blockDiagram-GPEHLZMM.DFDVpfXm.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.7o0P_QDo.js → c4Diagram-AAUBKEIU.V7_3_glh.js} +1 -1
- package/web/_astro/channel.DZVfto-r.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.C3zZFsNt.js → chunk-2J33WTMH.De1yx7Jz.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.CNy_M7fO.js → chunk-4BX2VUAB.BDhHFuxx.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.2TiPnLBL.js → chunk-55IACEB6.DDLkWnmC.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.5CGSyKAp.js → chunk-727SXJPM.CwfiLnA7.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.w-ZIgfsK.js → chunk-AQP2D5EJ.CtGDmUnM.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.BkcEyhKa.js → chunk-FMBD7UC4.BOLjpw73.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.mxKKbBG4.js → chunk-ND2GUHAM.BDhQls6O.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.cyA0z9aT.js → chunk-QZHKN3VN.76qBynDF.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.CqtUzwhX.js → classDiagram-4FO5ZUOK.N0mpPHT0.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.CqtUzwhX.js → classDiagram-v2-Q7XG4LA2.N0mpPHT0.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.BExPTopI.js → cose-bilkent-S5V4N54A.CKknFfjB.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.Bq2i10Cn.js → cynefin-OW5HDTMX.Cw3ZWBAh.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.By_HsOuv.js → dagre-BM42HDAG.D3yIKCRD.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.BtU0b7hz.js → diagram-2AECGRRQ.D51dO83Z.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.D00ztMdT.js → diagram-5GNKFQAL.Bb-FViDj.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.DMVJWaUN.js → diagram-KO2AKTUF.D3mN8S6x.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.Cxqrjg5-.js → diagram-LMA3HP47.dMMyPcbJ.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.2lz_1B5h.js → diagram-OG6HWLK6.AzbvzY4C.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.BVQEuJ3T.js → erDiagram-TEJ5UH35.BR5I4OZb.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.Qlyo90ky.js → flowDiagram-I6XJVG4X.DFqvhGkn.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DRwb8HHZ.js → ganttDiagram-6RSMTGT7.ByJbhH6J.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.YfoPthfS.js → gitGraphDiagram-PVQCEYII.CInHjQR3.js} +1 -1
- package/web/_astro/index.COh_kBxN.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.DvFREck1.js → infoDiagram-5YYISTIA.Cm0dGVjJ.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.BzCj9Q0-.js → ishikawaDiagram-YF4QCWOH.C3nOP6Sj.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.BDMT_AFb.js → journeyDiagram-JHISSGLW.4IvLa2MW.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.D6Fh3gj9.js → kanban-definition-UN3LZRKU.DS87Cl-k.js} +1 -1
- package/web/_astro/{linear.Dxw00fGQ.js → linear.MzmRrNER.js} +1 -1
- package/web/_astro/{mermaid.core.CsoxUWa0.js → mermaid.core.fK-WNswS.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.CN8oeHLu.js → mindmap-definition-RKZ34NQL.BqipOHhY.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.C7ADqQ_7.js → pieDiagram-4H26LBE5.0nBiPqFG.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.Cw9lKyHP.js → quadrantDiagram-W4KKPZXB.Szj7Zpx5.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.B1ni-z4q.js → requirementDiagram-4Y6WPE33.D4UR6TWo.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.BhexdjVr.js → sankeyDiagram-5OEKKPKP.DAE7BdOs.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.C3Rm7dpQ.js → sequenceDiagram-3UESZ5HK.BP9ZVq25.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.CkuMt27u.js → stateDiagram-AJRCARHV.BQW7mIxk.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.Dc_aazUA.js → stateDiagram-v2-BHNVJYJU.PbK4nDih.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.ja7sUFhH.js → timeline-definition-PNZ67QCA.Ci_GvUpo.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.BxIshX_K.js → vennDiagram-CIIHVFJN.DNw1Y5qx.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.DfHlC0sh.js → wardleyDiagram-YWT4CUSO.CwlkaaNe.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.DSnhHwCh.js → xychartDiagram-2RQKCTM6.MI6ZuiH_.js} +1 -1
- package/web/board-runtime.json +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.BVp-LYi6.js +0 -322
- package/web/_astro/channel.6IFIKBhu.js +0 -1
- package/web/_astro/index.CbNz17Sx.css +0 -1
|
@@ -19,6 +19,21 @@
|
|
|
19
19
|
# done guard closed, and re-records Testing before the failed edge); done settles
|
|
20
20
|
# deferrals; failed renders the recovery report. No new state, edge, or model query.
|
|
21
21
|
#
|
|
22
|
+
# Confidence gate (session finding after 1088, task 1068 follow-up): the verify answer has
|
|
23
|
+
# carried a `Confidence: HIGH|MEDIUM|LOW` line since 1068, and nothing read it — a PASS at
|
|
24
|
+
# LOW confidence certified exactly like HIGH. The verify stamp now records a `confidence`
|
|
25
|
+
# check row, and BOTH completion guards (verify → record, record → done) refuse a LOW (or
|
|
26
|
+
# absent) level unless the run was launched with `--vars '{"ackLowConfidence":"true"}'`.
|
|
27
|
+
# The acknowledgement is an operator decision, not a model one: it is the only way to
|
|
28
|
+
# certify a verdict the verifier itself would not stand behind.
|
|
29
|
+
#
|
|
30
|
+
# Review-failure routing (session finding after 1088): `review` had no outgoing edge for a
|
|
31
|
+
# FAIL verdict, so a failing review could only be remediated by driving the graph by hand
|
|
32
|
+
# (re-entering `test` and hand-emitting rows). The review stage now derives
|
|
33
|
+
# `.spur/run/<wbs>-review.status` from its own answer file (fail-closed to FAIL), and a FAIL
|
|
34
|
+
# routes through `review-fail-triage` — the review-side twin of `test-fail-triage` (0943) —
|
|
35
|
+
# into the SAME bounded fix budget, so remediation stays on-graph and bounded.
|
|
36
|
+
#
|
|
22
37
|
# Vars (passed as a JSON object via `--vars`):
|
|
23
38
|
# wbs — task WBS (required)
|
|
24
39
|
# profile — "auto" skips HITL approve (R4)
|
|
@@ -36,7 +51,26 @@ kind: state-machine
|
|
|
36
51
|
name: task-pipeline
|
|
37
52
|
# 0772 R2: explicit identity tag. Set only after the proof failure-path tests
|
|
38
53
|
# passed; the engine treats unversioned external definitions as supported.
|
|
39
|
-
|
|
54
|
+
# v4 (session finding after 1088): the completion gate reads the verifier's confidence level and
|
|
55
|
+
# the graph routes a non-PASS review into bounded remediation — both are contract changes, so the
|
|
56
|
+
# identity moves with them.
|
|
57
|
+
# v5 (task 1077's inline run, 2026-10-06): the verify verdict action is explicitly `onError:
|
|
58
|
+
# continue`. `task verdict` exits non-zero on any non-PASS verdict BY DESIGN (1003 R2) — that is
|
|
59
|
+
# data for the verify guards, not a state failure. Under the engine's default 'fail' policy
|
|
60
|
+
# (`resolveOnErrorPolicy: action ?? workflowDefault ?? runOption ?? 'fail'`) the state sequence
|
|
61
|
+
# halted on that exit code and `lifecycle.fail('verify')` finalized the run before any transition
|
|
62
|
+
# guard was evaluated, which made the declared `verify → test-fix` "repairable non-PASS" lane
|
|
63
|
+
# UNREACHABLE: a non-PASS verify could only end the run failed. `test-fix` also gained the
|
|
64
|
+
# review-lane evidence projection (see its onEnter) so the repair hop is not fed an empty findings
|
|
65
|
+
# list when the failing hop was `review-fail-triage` rather than the quality gate.
|
|
66
|
+
# v6 (task 1134 run, 2026-10-09): the `confidence` check row now encodes the SAME policy as the two
|
|
67
|
+
# completion guards instead of a stricter one of its own. It warned for every level below HIGH, so a
|
|
68
|
+
# MEDIUM certification was admitted by both guards but recomputed as PARTIAL by the CLI done gate —
|
|
69
|
+
# the artifact was self-inconsistent and `done` was refused with no named level to act on. The row
|
|
70
|
+
# now warns only for an unacknowledged LOW (or absent) level, which is exactly what the guards
|
|
71
|
+
# refuse; `packages/app/tests/workflow/task-pipeline-proof-chain.test.ts` pins the agreement for
|
|
72
|
+
# HIGH/MEDIUM/LOW/absent × ack.
|
|
73
|
+
version: "6"
|
|
40
74
|
description: "Standard task pipeline: precheck → implement → quality-gate (test/fix/recheck) → review → approve → verify → record → done"
|
|
41
75
|
# Task entity lifecycle (owned by task-lifecycle.yaml):
|
|
42
76
|
# normal: backlog → todo → wip → testing → done
|
|
@@ -89,11 +123,15 @@ vars:
|
|
|
89
123
|
# run unbounded — if a hop still hits this wall, STOP and record it.
|
|
90
124
|
stepTimeoutMs: "1800000"
|
|
91
125
|
# Timeout for the `implement` step specifically (R2a). Implementation is the
|
|
92
|
-
# heaviest agent.run step (full read/write/test-probe loop)
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
|
|
126
|
+
# heaviest agent.run step (full read/write/test-probe loop); the old 600s default
|
|
127
|
+
# failed five consecutive dogfood runs (bugs 742/744/746/748). Default is 45 min
|
|
128
|
+
# (task 1108): it governs subprocess surfaces (`spur workflow run`, parallel,
|
|
129
|
+
# headless); inline hosts receive it only when their dispatch tool accepts a
|
|
130
|
+
# timeout (inline-pipeline-driver.md § Timeout boundary). 45 min is a reasoned
|
|
131
|
+
# default, not a proven bound — in P1 one implement still hit 45 min and resumed
|
|
132
|
+
# (docs/reports/i31/1107-runall-p1-pilot.md § Timeout attribution).
|
|
133
|
+
# Override per run: `--vars '{"implementTimeoutMs":"3600000"}'`.
|
|
134
|
+
implementTimeoutMs: "2700000"
|
|
97
135
|
# Answer captured by the approve gate's hitl.confirm (R1): "yes" | "no" | "cancel".
|
|
98
136
|
# Empty by default; only meaningful once the approve state has been entered.
|
|
99
137
|
__hitlAnswer: ""
|
|
@@ -101,13 +139,16 @@ vars:
|
|
|
101
139
|
# default; set by `spur workflow continue --answer-text` after the pause and read
|
|
102
140
|
# by the escalate→implement / escalate→failed guards. Non-empty = answered.
|
|
103
141
|
__hitlInput: ""
|
|
104
|
-
# Proof-state bracket (task 0612, ADR-071; restructured by task 0703
|
|
105
|
-
# canonical capture taken at quality-gate ENTRY — immediately before the
|
|
106
|
-
# final chain (quality → review → verify) — and re-captured at `test-recheck`
|
|
107
|
-
# remediation mutated the tree, so every evidence stage names one fresh digest
|
|
108
|
-
# `proofDigestNow` is the live re-capture compared against `proofDigest` at
|
|
109
|
-
#
|
|
110
|
-
#
|
|
142
|
+
# Proof-state bracket (task 0612, ADR-071; restructured by task 0703; review joins by task 1135).
|
|
143
|
+
# `proofDigest` is the canonical capture taken at quality-gate ENTRY — immediately before the
|
|
144
|
+
# evidence-producing final chain (quality → review → verify) — and re-captured at `test-recheck`
|
|
145
|
+
# when bounded remediation mutated the tree, so every evidence stage names one fresh digest
|
|
146
|
+
# (R2/R4). `proofDigestNow` is the live re-capture compared against `proofDigest` at review,
|
|
147
|
+
# verify and record entry; a mismatch means a proof input changed after evidence was established,
|
|
148
|
+
# so the run routes to `failed` instead of spending a review dispatch or crossing the completion
|
|
149
|
+
# boundary (R5). Task 1135 adds the review-entry compare and the gate-entry tree snapshot
|
|
150
|
+
# (`.spur/run/<run-id>-gate-paths.txt`, same exclusions as the git-tree half) so a mismatch also
|
|
151
|
+
# names the drifted paths.
|
|
111
152
|
# `taskSpecPath` carries the task file path because `docs/tasks*` is excluded from the digest's
|
|
112
153
|
# git-tree half — spec content is folded in explicitly or a task-file edit would go undetected.
|
|
113
154
|
# The fingerprint scopes task content to the proof-input sections only (Background, Requirements,
|
|
@@ -128,6 +169,11 @@ vars:
|
|
|
128
169
|
# with the same package-manager surface (this monorepo is Bun-only):
|
|
129
170
|
# `--vars '{"qualityGateCmd":"bun run lint && bun run test"}'`. Soft probe, hard recheck,
|
|
130
171
|
# and the fixall slash input all use this same var so the command stays single-sourced.
|
|
172
|
+
# INVARIANT (ADR-124, clarified 2026-10-07 by task 1111 R5): only the FULL tier writes PASS.
|
|
173
|
+
# Under the opt-in `deferQualityGate` policy the per-task token is DEFERRED (light tier) and
|
|
174
|
+
# the "review runs only after a green full gate" invariant moves to BATCH scope — nothing is
|
|
175
|
+
# reported PASS without the integrated full gate on the base ref. Default "false" = per-task
|
|
176
|
+
# full gate, unchanged.
|
|
131
177
|
# TRUSTED CONFIG ONLY — this string is executed via `sh -c` (see test/test-recheck). Never
|
|
132
178
|
# interpolate untrusted operator/LLM input into qualityGateCmd (task 0436 SECUA residual).
|
|
133
179
|
# NO `format` PREFIX: `implement` already ran `$formatCmd` on its way out, and `test`
|
|
@@ -149,6 +195,14 @@ vars:
|
|
|
149
195
|
# Escalation counter: .spur/run/<wbs>-escalation-count. Default 2 = two answered
|
|
150
196
|
# questions; a third pause routes to failed with a report note.
|
|
151
197
|
maxEscalations: "2"
|
|
198
|
+
# Operator acknowledgement of a LOW-confidence certification (session finding after 1088).
|
|
199
|
+
# The verify answer's `Confidence:` line is captured into the verdict artifact; a LOW (or
|
|
200
|
+
# absent) level fails the completion guards unless this is "true", because a PASS the
|
|
201
|
+
# verifier would not stand behind is an operator risk decision, not a mechanical one.
|
|
202
|
+
# Set per run: `--vars '{"ackLowConfidence":"true"}'` (and export it on the inline path).
|
|
203
|
+
# Deliberately NOT settable from the task file or the verifier's own answer: the point is
|
|
204
|
+
# that a second party, not the producer, accepts the residual uncertainty.
|
|
205
|
+
ackLowConfidence: ""
|
|
152
206
|
# Runtime-written, 0933: the escalate hop's file.read.into-var fills this from
|
|
153
207
|
# .spur/run/<wbs>-question.md; the hitl.input prompt below references it. Declared
|
|
154
208
|
# here (empty) so the static var-reference validator sees the template source.
|
|
@@ -169,6 +223,14 @@ vars:
|
|
|
169
223
|
# (default) = on; set to "off" to bypass:
|
|
170
224
|
# `--vars '{"implementScopeGuard":"off"}'`.
|
|
171
225
|
implementScopeGuard: ""
|
|
226
|
+
# 1111 R1: opt-in parallel-batch gate policy. When "true", `test` / `test-recheck` run the
|
|
227
|
+
# LIGHT tier for per-task early feedback and write `DEFERRED` (light PASS) or `FAIL` to
|
|
228
|
+
# `.spur/run/<wbs>-test-gate.status` — never `PASS`, because that token means the full
|
|
229
|
+
# project gate ran green on this tree. The batch orchestrator owes ONE integrated full gate
|
|
230
|
+
# on the base ref over the merged slices (1111 R3). Default "false" = unchanged behavior,
|
|
231
|
+
# and a stray `DEFERRED` file fails the guards. Sequential/inline runs never set it:
|
|
232
|
+
# `--defer-gate` requires `--mode parallel`.
|
|
233
|
+
deferQualityGate: "false"
|
|
172
234
|
# 0931 R5: parallel batches defer the per-task feature sync so a task branch never
|
|
173
235
|
# touches feature files or docs/features/INDEX.md. When "true", the record step's
|
|
174
236
|
# post-record shell appends a deferral note and skips the sync; the parallel batch
|
|
@@ -178,6 +240,10 @@ vars:
|
|
|
178
240
|
|
|
179
241
|
states:
|
|
180
242
|
- id: precheck
|
|
243
|
+
display:
|
|
244
|
+
phase: implement
|
|
245
|
+
phaseTitle: Implement
|
|
246
|
+
title: Check task readiness
|
|
181
247
|
description: >
|
|
182
248
|
Fast deterministic task readiness and size checks. Failures route to the
|
|
183
249
|
`failed` terminal state (not a raw lifecycle abort mid-enter).
|
|
@@ -221,6 +287,10 @@ states:
|
|
|
221
287
|
reviewer: "${vars.agent}"
|
|
222
288
|
|
|
223
289
|
- id: implement
|
|
290
|
+
display:
|
|
291
|
+
phase: implement
|
|
292
|
+
phaseTitle: Implement
|
|
293
|
+
title: Implement
|
|
224
294
|
description: >
|
|
225
295
|
Run agent-driven implementation via /sp:dev-run --mode implement, THEN move the
|
|
226
296
|
task to `wip` via the normal verb. The lifecycle transition fires AFTER the
|
|
@@ -252,6 +322,10 @@ states:
|
|
|
252
322
|
options:
|
|
253
323
|
agent: ${vars.implementAgent}
|
|
254
324
|
# Pure slash command only (ADR-043). Anti-recursion / implement discipline
|
|
325
|
+
# The worker's brief is OWNED BY the skill, not restated here (task 1110 R3):
|
|
326
|
+
# see `plugins/sp/skills/code-implementation/SKILL.md` (targeted-probe scope
|
|
327
|
+
# § Implement scope, dependency-aware § Changed-path targeted checks, Solution
|
|
328
|
+
# anchor form in § Red Flags). The YAML only names the entry command.
|
|
255
329
|
# Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
|
|
256
330
|
role: coder
|
|
257
331
|
# B7 R3/R6 (0894): coder stages reuse the role session — the test-fix hop
|
|
@@ -315,6 +389,17 @@ states:
|
|
|
315
389
|
- kind: shell
|
|
316
390
|
options:
|
|
317
391
|
command: "$formatCmd ; exit 0"
|
|
392
|
+
# 1109 R3: qualify this task's unique basename anchors to repo-relative paths.
|
|
393
|
+
# Placement is load-bearing: it runs AFTER implement's mutations (and the format
|
|
394
|
+
# above) but BEFORE the `test` stage's `proof.fingerprint` capture, so a rewrite in
|
|
395
|
+
# a digest section cannot invalidate the proof. `--wbs` scopes the pass to this
|
|
396
|
+
# task's resolved file — the unscoped form rewrites ~119 unrelated task files.
|
|
397
|
+
# Non-fatal (`; exit 0`): the done gate still reports anything left, and this step
|
|
398
|
+
# deliberately does NOT address line drift or `L4.anchor-subject-mismatch`
|
|
399
|
+
# (those need the implementer to re-anchor). Scope contract: task 1109 R5.
|
|
400
|
+
- kind: shell
|
|
401
|
+
options:
|
|
402
|
+
command: "$spurBin task migrate-anchors --wbs $wbs --json ; exit 0"
|
|
318
403
|
|
|
319
404
|
# ── escalate hop (operator-question pause, 0933) ──────────────────────────
|
|
320
405
|
# The implement agent paused on an operator question: it wrote
|
|
@@ -328,6 +413,11 @@ states:
|
|
|
328
413
|
# the escalate→implement guard so a stale question can never re-trigger the hop
|
|
329
414
|
# after the answered attempt.
|
|
330
415
|
- id: escalate
|
|
416
|
+
display:
|
|
417
|
+
phase: implement
|
|
418
|
+
phaseTitle: Implement
|
|
419
|
+
title: Ask operator
|
|
420
|
+
show: on-entry
|
|
331
421
|
description: >-
|
|
332
422
|
Operator-question pause (0933): the implement agent asked a question
|
|
333
423
|
headlessly; surface it to the operator and resume implement with the answer.
|
|
@@ -361,6 +451,10 @@ states:
|
|
|
361
451
|
# test-fix — increment attempt + pure slash /sp:dev-fixall (≤ max attempts)
|
|
362
452
|
# test-recheck — soft recheck → review | test-fix | failed (never silent lifecycle abort)
|
|
363
453
|
- id: test
|
|
454
|
+
display:
|
|
455
|
+
phase: test
|
|
456
|
+
phaseTitle: Test
|
|
457
|
+
title: Run quality gate
|
|
364
458
|
description: >
|
|
365
459
|
Proof-chain entry + soft quality-gate probe (single logical gate on the green path; bounded retries only
|
|
366
460
|
for SQLite lock contention). Capture of the canonical proof-input digest happens HERE — before any
|
|
@@ -405,6 +499,12 @@ states:
|
|
|
405
499
|
# R2 (0703, ADR-071): THE canonical proof capture. Placement is load-bearing: immediately before
|
|
406
500
|
# the final evidence chain, after every implement mutation (including the post-implement format).
|
|
407
501
|
# Capture-only here; `record` compares. A remediation pass re-captures at `test-recheck` (R4).
|
|
502
|
+
# 1135 R5: snapshot the non-corpus tree state FIRST, so a later proof mismatch names the
|
|
503
|
+
# drifted paths (not only the D1/D2 pair). Same exclusions as the digest's git-tree half.
|
|
504
|
+
- kind: shell
|
|
505
|
+
options:
|
|
506
|
+
command: >-
|
|
507
|
+
mkdir -p .spur/run; { git status --porcelain=v1 -uall -- . ':(exclude)docs/tasks*' ':(exclude)docs/features*'; git diff --name-only HEAD -- . ':(exclude)docs/tasks*' ':(exclude)docs/features*'; } > ".spur/run/$__runId-gate-paths.txt" 2>/dev/null; exit 0
|
|
408
508
|
- kind: proof.fingerprint
|
|
409
509
|
options:
|
|
410
510
|
var: proofDigest
|
|
@@ -414,9 +514,14 @@ states:
|
|
|
414
514
|
- kind: shell
|
|
415
515
|
options:
|
|
416
516
|
command: >-
|
|
417
|
-
eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/quality-gate.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/quality-gate.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then "$RUNNER" "$S"
|
|
517
|
+
eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/quality-gate.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/quality-gate.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; M=run; [ "$deferQualityGate" = "true" ] && M=deferred; if [ -f "$S" ]; then "$RUNNER" "$S" "$M"; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
|
|
418
518
|
|
|
419
519
|
- id: test-fix
|
|
520
|
+
display:
|
|
521
|
+
phase: test
|
|
522
|
+
phaseTitle: Test
|
|
523
|
+
title: Fix failures
|
|
524
|
+
show: on-entry
|
|
420
525
|
description: >
|
|
421
526
|
Bounded auto-fix hop when the quality gate is red OR final verification returned a
|
|
422
527
|
repairable non-PASS (task 0703 R4: remediation never happens inside verify — it loops
|
|
@@ -438,6 +543,17 @@ states:
|
|
|
438
543
|
options:
|
|
439
544
|
command: >-
|
|
440
545
|
printf '%s\n' "$(( $(cat ".spur/run/$wbs-test-fix-attempt" 2>/dev/null || echo 0) + 1 ))" > ".spur/run/$wbs-test-fix-attempt"; [ -f ".spur/run/$wbs-verdict.json" ] && echo '--- verify verdict (remediation input, task 0703 R4) ---' >> ".spur/run/$wbs-test-gate.log" && cat ".spur/run/$wbs-verdict.json" >> ".spur/run/$wbs-test-gate.log"; [ -f ".spur/run/$wbs-residuals.json" ] && echo '--- residual artifact (F96 fix targets; deferrals go to residual-deferrals.json, P3/markers only) ---' >> ".spur/run/$wbs-test-gate.log" && cat ".spur/run/$wbs-residuals.json" >> ".spur/run/$wbs-test-gate.log"; exit 0
|
|
546
|
+
# Review-lane input (v5, task 1077 run): `review-fail-triage` routes a non-PASS review
|
|
547
|
+
# into this same bounded repair hop, but it stages no review evidence — the fixer then
|
|
548
|
+
# received a GREEN gate log and an empty findings list, so the review finding it exists
|
|
549
|
+
# to repair was invisible to it. Project the reviewer's answer into the same log the
|
|
550
|
+
# other lanes use, and only on the review lane (the decision file exists only after
|
|
551
|
+
# `review-fail-triage`). Own action, not an append to the one above: ADR-115's 800-char
|
|
552
|
+
# shell cap is already 602 chars there.
|
|
553
|
+
- kind: shell
|
|
554
|
+
options:
|
|
555
|
+
command: >-
|
|
556
|
+
[ -f ".spur/run/$wbs-review-failure-class.decision" ] && [ -f ".spur/run/$__runId-review-answer.txt" ] && echo '--- review verdict (remediation input, review lane) ---' >> ".spur/run/$wbs-test-gate.log" && cat ".spur/run/$__runId-review-answer.txt" >> ".spur/run/$wbs-test-gate.log"; exit 0
|
|
441
557
|
# R3 (0482): project the extracted gate anchors into a var so the dispatch input
|
|
442
558
|
# can NAME the failing file:line, not merely point at a log. A vars template cannot
|
|
443
559
|
# run a shell, so the read is an action, not an inline `$(cat ...)` substitution.
|
|
@@ -469,6 +585,11 @@ states:
|
|
|
469
585
|
processSpawn: available
|
|
470
586
|
|
|
471
587
|
- id: test-recheck
|
|
588
|
+
display:
|
|
589
|
+
phase: test
|
|
590
|
+
phaseTitle: Test
|
|
591
|
+
title: Re-run quality gate
|
|
592
|
+
show: on-entry
|
|
472
593
|
description: >
|
|
473
594
|
Soft recheck after fixall with bounded SQLite-lock retry. Writes PASS|FAIL (always exit 0). Transitions
|
|
474
595
|
branch to `triage` (PASS — the 0943 lane router), `test-fail-triage` (FAIL — the 0943
|
|
@@ -478,6 +599,12 @@ states:
|
|
|
478
599
|
# R4 (0703, ADR-071): bounded remediation mutated the tree by design, so the fresh evidence
|
|
479
600
|
# chain (recheck gate → review → verify) must start from a NEWLY captured digest. Capture-only;
|
|
480
601
|
# the guards and `record` compare against this value.
|
|
602
|
+
# 1135 R5: re-snapshot the tree state after the remediation, so the refresh does not compare
|
|
603
|
+
# against a pre-remediation snapshot (a legitimate test-fix edit must not read as drift).
|
|
604
|
+
- kind: shell
|
|
605
|
+
options:
|
|
606
|
+
command: >-
|
|
607
|
+
mkdir -p .spur/run; { git status --porcelain=v1 -uall -- . ':(exclude)docs/tasks*' ':(exclude)docs/features*'; git diff --name-only HEAD -- . ':(exclude)docs/tasks*' ':(exclude)docs/features*'; } > ".spur/run/$__runId-gate-paths.txt" 2>/dev/null; exit 0
|
|
481
608
|
- kind: proof.fingerprint
|
|
482
609
|
options:
|
|
483
610
|
var: proofDigest
|
|
@@ -493,9 +620,13 @@ states:
|
|
|
493
620
|
- kind: shell
|
|
494
621
|
options:
|
|
495
622
|
command: >-
|
|
496
|
-
eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/quality-gate.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/quality-gate.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then "$RUNNER" "$S"
|
|
623
|
+
eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/quality-gate.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/quality-gate.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; M=recheck; [ "$deferQualityGate" = "true" ] && M=deferred; if [ -f "$S" ]; then "$RUNNER" "$S" "$M"; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
|
|
497
624
|
|
|
498
625
|
- id: triage
|
|
626
|
+
display:
|
|
627
|
+
phase: review
|
|
628
|
+
phaseTitle: Review
|
|
629
|
+
title: Choose review depth
|
|
499
630
|
description: >-
|
|
500
631
|
Deterministic lane router between a green gate and the review/verify fork (0943 R1).
|
|
501
632
|
Writes the diffstat evidence file, honors a caller-set `mode` (never overridden), pins
|
|
@@ -524,17 +655,18 @@ states:
|
|
|
524
655
|
options:
|
|
525
656
|
command: >-
|
|
526
657
|
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
|
|
527
|
-
# (d) lane decision — degrades to the standard default whenever
|
|
658
|
+
# (d) lane decision — degrades to the standard default whenever workflows.decideDecisionMaker
|
|
528
659
|
# is off (R4), so with the flag off this state is pure shell: no model call is made.
|
|
660
|
+
# 1114: the inline decide moved to the bundled catalog (`config/decisions/task-pipeline.yaml`
|
|
661
|
+
# → `task-triage`), whose R0 samples measured this exact prompt before the migration.
|
|
662
|
+
# Routing contract is unchanged: same evidence, same resultFile, same guards, same
|
|
663
|
+
# `standard` fallback when the switch is off (field-identical to this form's default).
|
|
529
664
|
- kind: decide
|
|
530
665
|
options:
|
|
531
666
|
id: task-triage
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
low (small, contained diff — fast lane), standard, or high caution?
|
|
536
|
-
choices: [low, standard, high]
|
|
537
|
-
default: standard
|
|
667
|
+
decision: task-triage
|
|
668
|
+
params:
|
|
669
|
+
wbs: ${vars.wbs}
|
|
538
670
|
evidence:
|
|
539
671
|
- .spur/run/${vars.wbs}-diffstat.json
|
|
540
672
|
- ${vars.taskSpecPath}
|
|
@@ -555,6 +687,11 @@ states:
|
|
|
555
687
|
var: mode
|
|
556
688
|
|
|
557
689
|
- id: test-fail-triage
|
|
690
|
+
display:
|
|
691
|
+
phase: test
|
|
692
|
+
phaseTitle: Test
|
|
693
|
+
title: Triage test failure
|
|
694
|
+
show: on-entry
|
|
558
695
|
description: >-
|
|
559
696
|
Deterministic failure-class router on a red gate (0943 R3). The engine has no onEnter
|
|
560
697
|
conditionals, so the FAIL branch from `test`/`test-recheck` lands here as its own
|
|
@@ -565,22 +702,44 @@ states:
|
|
|
565
702
|
missing/corrupt decision fails closed to failed-check. (0976 R2 collapsed the former
|
|
566
703
|
`retryable` lane: the declared default made it unreachable on the inline path.)
|
|
567
704
|
onEnter:
|
|
705
|
+
# 1115: catalog-reference decide (task 1094 form) — question/choices/fallback live in
|
|
706
|
+
# the bundled catalog (`config/decisions/task-pipeline.yaml` → `failure-class`), whose
|
|
707
|
+
# R0 samples measured this exact prompt before the migration. Routing contract is
|
|
708
|
+
# unchanged: same resultFile, same guards, same `fix` fallback when the switch is off.
|
|
568
709
|
- kind: decide
|
|
569
710
|
options:
|
|
570
711
|
id: failure-class
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
the run stop here?
|
|
575
|
-
choices: [fix, stop]
|
|
576
|
-
default: fix
|
|
712
|
+
decision: failure-class
|
|
713
|
+
params:
|
|
714
|
+
wbs: ${vars.wbs}
|
|
577
715
|
evidence:
|
|
578
716
|
- .spur/run/${vars.wbs}-test-gate.findings
|
|
579
717
|
resultFile: .spur/run/${vars.wbs}-failure-class.decision
|
|
580
718
|
|
|
581
719
|
- id: review
|
|
582
|
-
|
|
720
|
+
display:
|
|
721
|
+
phase: review
|
|
722
|
+
phaseTitle: Review
|
|
723
|
+
title: Review changes
|
|
724
|
+
description: >-
|
|
725
|
+
Three-dimensional code review via /sp:dev-review (functional requirements traceability +
|
|
726
|
+
SECUA framework (Security, Efficiency, Correctness, Usability, Architecture) +
|
|
727
|
+
architecture depth), findings written to `## Review`. Cost at this decision point (1122):
|
|
728
|
+
open P1-P3 review findings block `done` — the PASS edges below also run the review-gate
|
|
729
|
+
residual check, and a PASS carrying an open P1-P3 row routes to review-fail-triage
|
|
730
|
+
before verify. Fixing a finding invalidates the certified digest and re-runs
|
|
731
|
+
quality → review → verify on a fresh digest; only P4 rows and DEFER-ed P3 rows are wrap
|
|
732
|
+
residuals.
|
|
583
733
|
onEnter:
|
|
734
|
+
# 1135 R4: review joins the proof bracket. A pre-review compare refuses to spend a review
|
|
735
|
+
# dispatch on a state that has drifted from the certified digest; the mismatch routes
|
|
736
|
+
# through the existing tripwire to `failed` (no new re-certify path).
|
|
737
|
+
- kind: proof.fingerprint
|
|
738
|
+
options:
|
|
739
|
+
var: proofDigestNow
|
|
740
|
+
taskFile: ${vars.taskSpecPath}
|
|
741
|
+
featureFile: ${vars.featureSpecPath}
|
|
742
|
+
expect: ${vars.proofDigest}
|
|
584
743
|
- kind: agent.run
|
|
585
744
|
options:
|
|
586
745
|
# 0710 R2: review always runs on a fresh session — no implementation-session
|
|
@@ -611,11 +770,57 @@ states:
|
|
|
611
770
|
# verify stamp marks review `completed` only when this marker equals the current digest;
|
|
612
771
|
# otherwise `skipped` (an honest downgrade, never a fake completed), and the bound
|
|
613
772
|
# `record` registration refuses a skipped review.
|
|
773
|
+
# Session finding after 1088: the review VERDICT is read straight out of the reviewer's
|
|
774
|
+
# own answer file by the review → * guards below, so this stage needs no extra artifact
|
|
775
|
+
# and no extra action (ADR-115 legibility cap).
|
|
614
776
|
- kind: shell
|
|
615
777
|
options:
|
|
616
778
|
command: 'mkdir -p .spur/run; printf "%s" "$proofDigest" > ".spur/run/$__runId-review-proof.digest"; exit 0'
|
|
617
779
|
|
|
780
|
+
# ── review-fail-triage (session finding after 1088) ────────────────────────
|
|
781
|
+
# A review that reports FAIL used to have no outgoing edge: the graph could not see the
|
|
782
|
+
# verdict and nothing consumed it, so remediating a failing review meant driving the
|
|
783
|
+
# states by hand. This state is the review-side twin of `test-fail-triage` (0943 R3):
|
|
784
|
+
# the deterministic classifier routes the failure into the SAME bounded fix budget
|
|
785
|
+
# (`.spur/run/<wbs>-test-fix-attempt` against `qualityGateMaxFixAttempts`), and the fix
|
|
786
|
+
# re-enters quality → review → verify on a freshly captured digest. The `decide` action
|
|
787
|
+
# itself always runs (the engine has no onEnter conditionals); with
|
|
788
|
+
# `workflows.decideDecisionMaker` off it degrades to its declared default.
|
|
789
|
+
- id: review-fail-triage
|
|
790
|
+
display:
|
|
791
|
+
phase: review
|
|
792
|
+
phaseTitle: Review
|
|
793
|
+
title: Triage review findings
|
|
794
|
+
show: on-entry
|
|
795
|
+
description: >-
|
|
796
|
+
Deterministic router for a review that did NOT certify PASS (session finding after 1088).
|
|
797
|
+
`decide review-failure-class` reads the reviewer's answer and the task spec and routes:
|
|
798
|
+
fix → the shared test-fix hop, stop → failed with terminalReason failed-check. A
|
|
799
|
+
missing/corrupt decision fails closed to failed-check. Cost either way (1122): open
|
|
800
|
+
P1-P3 review findings block `done`; the fix lane re-enters quality → review → verify on a
|
|
801
|
+
fresh digest; only P4 rows and DEFER-ed P3 rows are wrap residuals.
|
|
802
|
+
onEnter:
|
|
803
|
+
# 1116: the inline decide moved to the bundled catalog (`config/decisions/task-pipeline.yaml`
|
|
804
|
+
# → `review-failure-class`), whose R0 samples measured this exact prompt before the
|
|
805
|
+
# migration. Routing contract is unchanged: same evidence, same resultFile, same guards,
|
|
806
|
+
# same `fix` fallback when the switch is off.
|
|
807
|
+
- kind: decide
|
|
808
|
+
options:
|
|
809
|
+
id: review-failure-class
|
|
810
|
+
decision: review-failure-class
|
|
811
|
+
params:
|
|
812
|
+
wbs: ${vars.wbs}
|
|
813
|
+
evidence:
|
|
814
|
+
- .spur/run/${vars.__runId}-review-answer.txt
|
|
815
|
+
- ${vars.taskSpecPath}
|
|
816
|
+
resultFile: .spur/run/${vars.wbs}-review-failure-class.decision
|
|
817
|
+
|
|
618
818
|
- id: approve
|
|
819
|
+
display:
|
|
820
|
+
phase: review
|
|
821
|
+
phaseTitle: Review
|
|
822
|
+
title: Operator approval
|
|
823
|
+
show: on-entry
|
|
619
824
|
description: >
|
|
620
825
|
Human-in-the-loop approval gate. Under `profile=auto` this state is never entered
|
|
621
826
|
(review routes around it straight to verify). In interactive mode this state pauses
|
|
@@ -631,9 +836,18 @@ states:
|
|
|
631
836
|
mode: never
|
|
632
837
|
|
|
633
838
|
- id: verify
|
|
839
|
+
display:
|
|
840
|
+
phase: verify
|
|
841
|
+
phaseTitle: "Verify & record"
|
|
842
|
+
title: Verify requirements and AC
|
|
634
843
|
description: >
|
|
635
844
|
Observe-only functional verification (BDD + traceability) via /sp:dev-verify --fix none
|
|
636
845
|
(task 0703 R1, ADR-071): the verifier certifies the state, it never repairs its own subject.
|
|
846
|
+
The answer-shape contract this stage enforces is OWNED BY the skill, not restated here
|
|
847
|
+
(task 1110 R3): see `plugins/sp/skills/code-verification/SKILL.md` § Answer-File Schema
|
|
848
|
+
Contract (`:340-375`), with the row-id/evidence vocabularies in
|
|
849
|
+
`plugins/sp/skills/code-verification/references/verdict-schema.md`. The YAML only names
|
|
850
|
+
the lint that consumes it (`task verdict --from-answer`).
|
|
637
851
|
A live digest compare BEFORE the agent refuses to certify a state that drifted after the
|
|
638
852
|
quality/review evidence was produced (R2). The agent's
|
|
639
853
|
captured answer is written to `.spur/run/<wbs>-verify-answer.txt` and MUST follow
|
|
@@ -675,8 +889,28 @@ states:
|
|
|
675
889
|
# (d) `spur task verdict` owns the answer lint (task 1003 R2) — the shell below
|
|
676
890
|
# fails closed when the verifier's answer is malformed, before any verdict artifact.
|
|
677
891
|
- kind: shell
|
|
892
|
+
# `task verdict` exits 1 on a non-PASS verdict by design (1003 R2). The `continue`
|
|
893
|
+
# policy keeps that exit code as recorded evidence (the action row is still `failed`)
|
|
894
|
+
# while letting the state finish its remaining actions and reach the guards below;
|
|
895
|
+
# without it the default 'fail' policy halts the run here and `verify → test-fix`
|
|
896
|
+
# (the declared bounded remediation lane) can never fire (v5, task 1077 run).
|
|
897
|
+
onError: continue
|
|
678
898
|
options:
|
|
679
899
|
command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
|
|
900
|
+
# Session finding after 1088: the verifier's confidence level becomes a `confidence` check
|
|
901
|
+
# row and a gate-log line, so the level the completion guards enforce is visible in the
|
|
902
|
+
# artifact and the log — not only in the answer file. v6 (task 1134 run): the row warns for
|
|
903
|
+
# an unacknowledged LOW/absent level ONLY, matching the guards' ack rule; warning for
|
|
904
|
+
# MEDIUM too made an admitted certification aggregate to PARTIAL (self-inconsistent artifact,
|
|
905
|
+
# done refused). This is its own action because the proof-binding stamp below must stay the
|
|
906
|
+
# state's LAST action AND under the ADR-115 800-char shell cap.
|
|
907
|
+
- kind: shell
|
|
908
|
+
options:
|
|
909
|
+
command: >-
|
|
910
|
+
V=".spur/run/$wbs-verdict.json"; [ -f "$V" ] || exit 0;
|
|
911
|
+
jq --arg ack "$ackLowConfidence" '. + {checks: (((.checks // []) | map(select(.name != "confidence"))) + [{name: "confidence", status: (if ((.confidence // "LOW") != "LOW" or $ack == "true") then "pass" else "warn" end), evidence: ((.confidence // "LOW (absent from artifact)") + (if $ack == "true" then " (operator-acknowledged)" else "" end))}])}' "$V" > "$V.tmp" && mv "$V.tmp" "$V";
|
|
912
|
+
printf 'confidence: %s (ack=%s)\n' "$(jq -r '.confidence // "LOW (absent)"' "$V")" "$ackLowConfidence" >> ".spur/run/$wbs-test-gate.log";
|
|
913
|
+
exit 0
|
|
680
914
|
# (e) one jq mutation binds the verdict to the proof digest (0703 R3; runId 0730 §B.2 /
|
|
681
915
|
# 0757 R4; definitionDigest 0759 R5; honest review stamp 0785 R4; soft action + hard guard).
|
|
682
916
|
- kind: shell
|
|
@@ -685,6 +919,10 @@ states:
|
|
|
685
919
|
V=".spur/run/$wbs-verdict.json"; [ -f "$V" ] && [ -n "$proofDigest" ] || exit 0; jq --arg d "$proofDigest" --arg r "$__runId" --arg dd "$__definitionDigest" --arg rp "$(cat .spur/run/$__runId-review-proof.digest 2>/dev/null)" --arg g "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null || echo UNKNOWN)" '. + {proof: {digest: $d, runId: $r, definitionDigest: $dd, capturePoint: "quality-gate-entry", stages: {qualityGate: {status: $g, digest: $d}, review: {status: (if $rp == $d then "completed" else "skipped" end), digest: $d}, verification: {status: .verdict, digest: $d}}}} | .checks += [{name: "proof-input-digest", status: "pass", evidence: $d}]' "$V" > "$V.tmp" && mv "$V.tmp" "$V"; exit 0
|
|
686
920
|
|
|
687
921
|
- id: record
|
|
922
|
+
display:
|
|
923
|
+
phase: verify
|
|
924
|
+
phaseTitle: "Verify & record"
|
|
925
|
+
title: Record evidence
|
|
688
926
|
description: >
|
|
689
927
|
Record pipeline results into the task file via `spur task record` —
|
|
690
928
|
Testing/Review from the verdict, Solution backfilled from git diff as a
|
|
@@ -844,7 +1082,11 @@ transitions:
|
|
|
844
1082
|
guard:
|
|
845
1083
|
kind: shell
|
|
846
1084
|
options:
|
|
847
|
-
|
|
1085
|
+
# 1132 R4 (auto-fix-first): repair mechanically first, then judge fail-closed. The
|
|
1086
|
+
# `--fix` output is captured to a run artifact so the batch report can carry the
|
|
1087
|
+
# task-level repairs under `autoRepairs` (feature-level repairs come from the
|
|
1088
|
+
# `feature check --fix` preflight); only `--precheck` decides this transition.
|
|
1089
|
+
command: '$spurBin task check $wbs --fix --json > ".spur/run/$wbs-auto-repairs.json" 2>/dev/null ; $spurBin task check $wbs --precheck'
|
|
848
1090
|
- from: precheck
|
|
849
1091
|
to: failed
|
|
850
1092
|
terminalReason: failed-check
|
|
@@ -912,9 +1154,11 @@ transitions:
|
|
|
912
1154
|
guard:
|
|
913
1155
|
kind: shell
|
|
914
1156
|
options:
|
|
1157
|
+
# 1111 R2: `DEFERRED` is accepted ONLY when the opt-in var is "true" — with the
|
|
1158
|
+
# default "false" a stray DEFERRED file fails the guard exactly like a corrupt one.
|
|
915
1159
|
command: >-
|
|
916
1160
|
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
917
|
-
test "$gate_status" = PASS
|
|
1161
|
+
test "$gate_status" = PASS || { test "$gate_status" = DEFERRED && test "$deferQualityGate" = "true"; }
|
|
918
1162
|
- from: test
|
|
919
1163
|
to: test-fail-triage
|
|
920
1164
|
description: Quality gate red — classify the failure before the repair hop (0943 R3).
|
|
@@ -945,9 +1189,10 @@ transitions:
|
|
|
945
1189
|
guard:
|
|
946
1190
|
kind: shell
|
|
947
1191
|
options:
|
|
1192
|
+
# 1111 R2: same var-gated acceptance of the deferred token as `test → triage`.
|
|
948
1193
|
command: >-
|
|
949
1194
|
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
950
|
-
test "$gate_status" = PASS
|
|
1195
|
+
test "$gate_status" = PASS || { test "$gate_status" = DEFERRED && test "$deferQualityGate" = "true"; }
|
|
951
1196
|
- from: test-recheck
|
|
952
1197
|
to: test-fail-triage
|
|
953
1198
|
description: Still red after fixall — classify the failure (0943 R3).
|
|
@@ -1018,21 +1263,84 @@ transitions:
|
|
|
1018
1263
|
description: Failure-class decision missing/corrupt — stop at failed.
|
|
1019
1264
|
guard:
|
|
1020
1265
|
kind: always
|
|
1021
|
-
# ── review
|
|
1022
|
-
#
|
|
1023
|
-
#
|
|
1024
|
-
#
|
|
1025
|
-
|
|
1266
|
+
# ── review-failure routing (session finding after 1088): the review-side twin of the
|
|
1267
|
+
# failure-class router above — stop first, then the shared attempt cap, then the fix lane,
|
|
1268
|
+
# then the fail-closed defense. The counter is the SAME one the quality-gate loop uses, so a
|
|
1269
|
+
# review FAIL cannot buy extra attempts and the iteration bound stays finite.
|
|
1270
|
+
- from: review-fail-triage
|
|
1271
|
+
to: failed
|
|
1272
|
+
terminalReason: failed-check
|
|
1273
|
+
description: Review failure class stop — the run terminates at failed, never bypassed.
|
|
1274
|
+
guard:
|
|
1275
|
+
kind: shell
|
|
1276
|
+
options:
|
|
1277
|
+
command: >-
|
|
1278
|
+
jq -e '.value == "stop"' ".spur/run/$wbs-review-failure-class.decision" >/dev/null 2>&1
|
|
1279
|
+
- from: review-fail-triage
|
|
1280
|
+
to: failed
|
|
1281
|
+
terminalReason: retry-exhausted
|
|
1282
|
+
description: Attempt cap reached — qualityGateMaxFixAttempts bounds the review repair lane.
|
|
1283
|
+
guard:
|
|
1284
|
+
kind: shell
|
|
1285
|
+
options:
|
|
1286
|
+
command: >-
|
|
1287
|
+
fix_attempts="$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)";
|
|
1288
|
+
test "$fix_attempts" -ge "$qualityGateMaxFixAttempts"
|
|
1289
|
+
- from: review-fail-triage
|
|
1290
|
+
to: test-fix
|
|
1291
|
+
description: Review failure class fix and under the cap — the shared bounded repair hop.
|
|
1292
|
+
guard:
|
|
1293
|
+
kind: shell
|
|
1294
|
+
options:
|
|
1295
|
+
command: >-
|
|
1296
|
+
jq -e '.value == "fix"' ".spur/run/$wbs-review-failure-class.decision" >/dev/null 2>&1
|
|
1297
|
+
# Defense: missing/corrupt review-failure decision — fail closed instead of silently repairing.
|
|
1298
|
+
- from: review-fail-triage
|
|
1299
|
+
to: failed
|
|
1300
|
+
terminalReason: failed-check
|
|
1301
|
+
description: Review-failure decision missing/corrupt — stop at failed.
|
|
1302
|
+
guard:
|
|
1303
|
+
kind: always
|
|
1304
|
+
# ── review routing: FAIL → bounded remediation; PASS → approve or the auto-skip (R4) ──
|
|
1305
|
+
# Declaration order matters and is FAIL-CLOSED: the two PASS edges each demand the reviewer's
|
|
1306
|
+
# own `Verdict: PASS` line AND a passing review-gate residual check (1122 R3) — the SAME
|
|
1307
|
+
# parse/classify/deferrals the record sweep enforces, resolved through the same source-repo /
|
|
1308
|
+
# installed scanner pair as the record step; a missing scanner fails closed into the catch-all.
|
|
1309
|
+
# EVERYTHING ELSE — FAIL, a missing or unparseable answer, or a PASS carrying an open P1-P3
|
|
1310
|
+
# review finding (record would terminally fail it after a full verify + record) — enters
|
|
1311
|
+
# `review-fail-triage` and its bounded repair hop BEFORE verify spends the cycle, then
|
|
1312
|
+
# re-enters quality → review → verify on a fresh digest. Before 1088 a FAIL review had no
|
|
1313
|
+
# outgoing edge at all; before 1122 a PASS-with-findings cost a full re-certification cycle per
|
|
1314
|
+
# attempt (knowledge-kit 0210/0213). The reviewer writes `Verdict: PASS|FAIL` in its answer;
|
|
1315
|
+
# both plain and bold forms are accepted. Under `profile=auto` the approve gate is skipped, so
|
|
1316
|
+
# the PASS+auto edge is tried first and the interactive PASS edge second.
|
|
1026
1317
|
- from: review
|
|
1027
1318
|
to: verify
|
|
1028
|
-
description: profile=auto — skip the human approval gate
|
|
1319
|
+
description: profile=auto, the review certified PASS, and no open P1-P3 review finding — skip the human approval gate.
|
|
1029
1320
|
guard:
|
|
1030
1321
|
kind: shell
|
|
1031
1322
|
options:
|
|
1032
|
-
command:
|
|
1323
|
+
command: >-
|
|
1324
|
+
test "$profile" = auto &&
|
|
1325
|
+
grep -qiE '^[[:space:]]*\**Verdict:\** *PASS' ".spur/run/$__runId-review-answer.txt" &&
|
|
1326
|
+
eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/residual-scan.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/residual-scan.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)" &&
|
|
1327
|
+
[ -f "$S" ] && "$RUNNER" "$S" review-gate "$wbs" --spur-bin "$spurBin" >&2
|
|
1033
1328
|
- from: review
|
|
1034
1329
|
to: approve
|
|
1035
|
-
description: Review
|
|
1330
|
+
description: Review certified PASS with no open P1-P3 review finding — gate on human approval before verification.
|
|
1331
|
+
guard:
|
|
1332
|
+
kind: shell
|
|
1333
|
+
options:
|
|
1334
|
+
command: >-
|
|
1335
|
+
grep -qiE '^[[:space:]]*\**Verdict:\** *PASS' ".spur/run/$__runId-review-answer.txt" &&
|
|
1336
|
+
eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/residual-scan.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/residual-scan.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)" &&
|
|
1337
|
+
[ -f "$S" ] && "$RUNNER" "$S" review-gate "$wbs" --spur-bin "$spurBin" >&2
|
|
1338
|
+
- from: review
|
|
1339
|
+
to: review-fail-triage
|
|
1340
|
+
description: >-
|
|
1341
|
+
No certified PASS without an open P1-P3 finding (FAIL, PARTIAL, missing, unparseable, or
|
|
1342
|
+
a PASS whose review-gate check found an open P1-P3 row — fail closed) — classify the
|
|
1343
|
+
failure and route it into the bounded repair hop instead of dead-ending the run.
|
|
1036
1344
|
guard:
|
|
1037
1345
|
kind: always
|
|
1038
1346
|
|
|
@@ -1069,19 +1377,23 @@ transitions:
|
|
|
1069
1377
|
# The verify step emits .spur/run/<wbs>-verdict.json with a required proof block (task 0703 R3/R5).
|
|
1070
1378
|
# Only `verdict: PASS` PLUS a proof block whose digest — top level and every named stage — equals
|
|
1071
1379
|
# the captured `proofDigest` clears the gate to `record`; any non-PASS, a missing file, malformed
|
|
1072
|
-
# JSON, or missing/mismatched proof evidence does not.
|
|
1380
|
+
# JSON, or missing/mismatched proof evidence does not. The verifier's confidence level is part of
|
|
1381
|
+
# that certification (session finding after 1088): a PASS the verifier itself marked LOW — or left
|
|
1382
|
+
# unstated — clears the gate only when the operator accepted it with
|
|
1383
|
+
# `--vars '{"ackLowConfidence":"true"}'`. Declaration order: PASS+proof guard FIRST,
|
|
1073
1384
|
# then the bounded remediation route (R4), then the always catch-all so a PASS verdict with a
|
|
1074
1385
|
# missing/malformed proof block still terminates at `failed` instead of hanging the state.
|
|
1075
1386
|
- from: verify
|
|
1076
1387
|
to: record
|
|
1077
|
-
description: Verification verdict is PASS
|
|
1388
|
+
description: Verification verdict is PASS, its proof block names the captured digest on every stage, and any LOW confidence was operator-acknowledged — record results and proceed to done.
|
|
1078
1389
|
guard:
|
|
1079
1390
|
# (one jq -e predicate) PASS verdict; proof, quality-gate, review and verification digests
|
|
1080
|
-
# equal to proofDigest; review completed; matching run id and definition digest (0703 R5, 0785 R4)
|
|
1391
|
+
# equal to proofDigest; review completed; matching run id and definition digest (0703 R5, 0785 R4);
|
|
1392
|
+
# confidence HIGH/MEDIUM, or LOW/absent with the operator's ack (session finding after 1088).
|
|
1081
1393
|
kind: shell
|
|
1082
1394
|
options:
|
|
1083
1395
|
command: >-
|
|
1084
|
-
jq -e --arg d "$proofDigest" --arg r "$__runId" --arg dd "$__definitionDigest" '
|
|
1396
|
+
jq -e --arg d "$proofDigest" --arg r "$__runId" --arg dd "$__definitionDigest" --arg ack "$ackLowConfidence" '
|
|
1085
1397
|
.verdict == "PASS"
|
|
1086
1398
|
and (.proof.digest // "") == $d
|
|
1087
1399
|
and (.proof.stages.qualityGate.digest // "") == $d
|
|
@@ -1090,6 +1402,7 @@ transitions:
|
|
|
1090
1402
|
and (.proof.stages.verification.digest // "") == $d
|
|
1091
1403
|
and (.proof.runId // "") == $r
|
|
1092
1404
|
and (.proof.definitionDigest // "") == $dd
|
|
1405
|
+
and ((.confidence // "LOW") != "LOW" or $ack == "true")
|
|
1093
1406
|
' ".spur/run/$wbs-verdict.json" >/dev/null 2>&1
|
|
1094
1407
|
- from: verify
|
|
1095
1408
|
to: test-fix
|
|
@@ -1117,11 +1430,12 @@ transitions:
|
|
|
1117
1430
|
# ── done gate: record → done/failed gated on `spur task check` (ADR-026 amendment 2026-06-23)
|
|
1118
1431
|
# PLUS the proof-block re-assertion (task 0703 R5): the verdict artifact must still be PASS and
|
|
1119
1432
|
# still name the captured digest — a forged or mutated completion artifact fails closed here.
|
|
1433
|
+
# PLUS the confidence re-assertion (session finding after 1088): the same ack rule as verify →
|
|
1434
|
+
# record, re-read from the artifact so a mutation between the two boundaries cannot slip through.
|
|
1120
1435
|
# Declaration order: pass guard first.
|
|
1121
1436
|
- from: record
|
|
1122
1437
|
to: done
|
|
1123
|
-
description: Task check passed
|
|
1124
|
-
# (warn) 5 commands: named verdict + proof digest reads after the task check (legibility, 0874).
|
|
1438
|
+
description: Task check passed, the verdict proof block still names the captured digest, and any LOW confidence was acknowledged — certify done.
|
|
1125
1439
|
guard:
|
|
1126
1440
|
kind: shell
|
|
1127
1441
|
options:
|
|
@@ -1130,11 +1444,16 @@ transitions:
|
|
|
1130
1444
|
# the CLI's own target-aware `--no-lifecycle` backstop (F92 R3). No `#`
|
|
1131
1445
|
# comments inside the folded scalar: `>-` joins same-indent lines into
|
|
1132
1446
|
# one shell line.
|
|
1447
|
+
# Two logical commands, deliberately (ADR-115): the `task check` projection plus
|
|
1448
|
+
# ONE jq predicate re-asserting the whole completion contract — PASS verdict, the
|
|
1449
|
+
# captured proof digest, and the confidence rule (session finding after 1088).
|
|
1133
1450
|
command: >-
|
|
1134
1451
|
$spurBin task check $wbs --as done &&
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1452
|
+
jq -e --arg p "$proofDigest" --arg ack "$ackLowConfidence" '
|
|
1453
|
+
.verdict == "PASS"
|
|
1454
|
+
and ((.proof.digest // "") == $p)
|
|
1455
|
+
and ((.confidence // "LOW") != "LOW" or $ack == "true")
|
|
1456
|
+
' ".spur/run/$wbs-verdict.json" >/dev/null 2>&1
|
|
1138
1457
|
- from: record
|
|
1139
1458
|
to: failed
|
|
1140
1459
|
terminalReason: failed-check
|