@gobing-ai/spur 0.4.0 → 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/decisions/gates.yaml +36 -0
- package/config/decisions/history-anatomy.yaml +35 -0
- package/config/decisions/idea-pipeline.yaml +38 -0
- package/config/plugin-scripts.json +15 -0
- package/config/rules/docs/sourced-api-claims.yaml +60 -0
- package/config/rules/recommended-pre-check.yaml +8 -3
- 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 +216 -57
- package/config/workflows/wrapup-pipeline.yaml +106 -13
- package/package.json +9 -9
- package/plugins/sp/README.md +11 -1
- package/plugins/sp/agents/super-planner.md +11 -0
- package/plugins/sp/agents/super-reviewer.md +14 -0
- package/plugins/sp/bunfig.toml +8 -0
- package/plugins/sp/commands/dev-brainstorm.md +29 -16
- 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 +3 -1
- package/plugins/sp/commands/dev-run.md +12 -2
- package/plugins/sp/commands/dev-runall.md +18 -10
- package/plugins/sp/hooks/context-session-start.ts +1 -1
- package/plugins/sp/lib/idea-handoff.generated.mjs +41 -5
- package/plugins/sp/lib/inline-run-app.ts +28 -0
- package/plugins/sp/lib/inline-run.generated.d.mts +5 -0
- package/plugins/sp/lib/inline-run.generated.mjs +333 -45
- 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 +121 -6
- 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/inline-run-dispatch.mjs +130 -0
- package/plugins/sp/scripts/inline-run-dispatch.ts +135 -0
- package/plugins/sp/scripts/inline-run-setup.mjs +551 -80
- package/plugins/sp/scripts/inline-run-setup.ts +52 -78
- 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 +86 -31
- package/plugins/sp/scripts/residual-scan.ts +28 -30
- package/plugins/sp/scripts/run-summary.mjs +421 -14
- package/plugins/sp/scripts/run-summary.ts +41 -177
- package/plugins/sp/scripts/session-timeline.mjs +109 -12
- package/plugins/sp/scripts/session-timeline.ts +71 -19
- 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 +3 -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 +1 -1
- package/plugins/sp/skills/session-review/SKILL.md +38 -7
- 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 +5 -2
- package/plugins/sp/skills/spur-cli/references/agent.md +20 -15
- package/plugins/sp/skills/spur-cli/references/decision.md +7 -6
- package/plugins/sp/skills/spur-cli/references/message.md +7 -7
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +19 -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 +1 -1
- 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 +37 -16
- 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 -1020
- package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +130 -0
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +6 -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 +35 -5
- package/plugins/sp/skills/spur-dev/references/glossary.md +2 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +343 -163
- package/plugins/sp/skills/spur-dev/references/structured-trace-emission.md +178 -0
- package/plugins/sp/skills/wayfinder/SKILL.md +10 -14
- package/schemas/state-machine-workflow.schema.json +23 -0
- package/spur.js +20728 -16630
- package/web/_astro/{BoardApp.VeoxxLBy.js → BoardApp.D66k_s_T.js} +1 -1
- package/web/_astro/{BoardApp.Bzr4OXrW.js → BoardApp.D6sjAJr_.js} +173 -173
- package/web/_astro/{TaskDetail.LAyR_Pvn.js → TaskDetail.BynLnMNc.js} +1 -1
- package/web/_astro/{arc.f4e0OYLg.js → arc._BUadrdH.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.SSIvxi-Z.js → architectureDiagram-3BPJPVTR.Dh7xS1Pp.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.DSXIHOFf.js → blockDiagram-GPEHLZMM.DFDVpfXm.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.DG9Ubu85.js → c4Diagram-AAUBKEIU.V7_3_glh.js} +1 -1
- package/web/_astro/channel.DZVfto-r.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.C7QU88Qh.js → chunk-2J33WTMH.De1yx7Jz.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.26Z94xBj.js → chunk-4BX2VUAB.BDhHFuxx.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.DYRiBkqw.js → chunk-55IACEB6.DDLkWnmC.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.D5Vfv5pe.js → chunk-727SXJPM.CwfiLnA7.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.DXHV47bN.js → chunk-AQP2D5EJ.CtGDmUnM.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.D1suAfOs.js → chunk-FMBD7UC4.BOLjpw73.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.D6BmdHEY.js → chunk-ND2GUHAM.BDhQls6O.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.rnPU-Ak-.js → chunk-QZHKN3VN.76qBynDF.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.CvEfXIo1.js → classDiagram-4FO5ZUOK.N0mpPHT0.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.CvEfXIo1.js → classDiagram-v2-Q7XG4LA2.N0mpPHT0.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.DkMisLSm.js → cose-bilkent-S5V4N54A.CKknFfjB.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.C77Q-pF6.js → cynefin-OW5HDTMX.Cw3ZWBAh.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.YaV8ce27.js → dagre-BM42HDAG.D3yIKCRD.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.CUyGEKge.js → diagram-2AECGRRQ.D51dO83Z.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.CRgd8dgj.js → diagram-5GNKFQAL.Bb-FViDj.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.Bmzys9hq.js → diagram-KO2AKTUF.D3mN8S6x.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.BvmJY4Lw.js → diagram-LMA3HP47.dMMyPcbJ.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.0hEhD30d.js → diagram-OG6HWLK6.AzbvzY4C.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.Bjt8lrnm.js → erDiagram-TEJ5UH35.BR5I4OZb.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.CJZTjRDV.js → flowDiagram-I6XJVG4X.DFqvhGkn.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7._VqoVafc.js → ganttDiagram-6RSMTGT7.ByJbhH6J.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.CEDb7tVo.js → gitGraphDiagram-PVQCEYII.CInHjQR3.js} +1 -1
- package/web/_astro/index.COh_kBxN.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.CgwifPpK.js → infoDiagram-5YYISTIA.Cm0dGVjJ.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.B99wx2J1.js → ishikawaDiagram-YF4QCWOH.C3nOP6Sj.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.2hRwJbEo.js → journeyDiagram-JHISSGLW.4IvLa2MW.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.BahJkKNC.js → kanban-definition-UN3LZRKU.DS87Cl-k.js} +1 -1
- package/web/_astro/{linear.DguUUe6V.js → linear.MzmRrNER.js} +1 -1
- package/web/_astro/{mermaid.core.CvgfmqVr.js → mermaid.core.fK-WNswS.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.B3qEA3x9.js → mindmap-definition-RKZ34NQL.BqipOHhY.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.FlWA-_ru.js → pieDiagram-4H26LBE5.0nBiPqFG.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.9bVn35X7.js → quadrantDiagram-W4KKPZXB.Szj7Zpx5.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.ChykIhct.js → requirementDiagram-4Y6WPE33.D4UR6TWo.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.Z2Y3hkYb.js → sankeyDiagram-5OEKKPKP.DAE7BdOs.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.J7JsHWDt.js → sequenceDiagram-3UESZ5HK.BP9ZVq25.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.DAPbiCSS.js → stateDiagram-AJRCARHV.BQW7mIxk.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.D2jvSi0q.js → stateDiagram-v2-BHNVJYJU.PbK4nDih.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.psW2ci29.js → timeline-definition-PNZ67QCA.Ci_GvUpo.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DlILYVmg.js → vennDiagram-CIIHVFJN.DNw1Y5qx.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.xNWwLJnn.js → wardleyDiagram-YWT4CUSO.CwlkaaNe.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.EU_BuH7V.js → xychartDiagram-2RQKCTM6.MI6ZuiH_.js} +1 -1
- package/web/index.html +2 -2
- package/web/_astro/channel.CUFdtWhm.js +0 -1
- package/web/_astro/index.Dg_3bOaJ.css +0 -1
|
@@ -63,7 +63,14 @@ name: task-pipeline
|
|
|
63
63
|
# UNREACHABLE: a non-PASS verify could only end the run failed. `test-fix` also gained the
|
|
64
64
|
# review-lane evidence projection (see its onEnter) so the repair hop is not fed an empty findings
|
|
65
65
|
# list when the failing hop was `review-fail-triage` rather than the quality gate.
|
|
66
|
-
|
|
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"
|
|
67
74
|
description: "Standard task pipeline: precheck → implement → quality-gate (test/fix/recheck) → review → approve → verify → record → done"
|
|
68
75
|
# Task entity lifecycle (owned by task-lifecycle.yaml):
|
|
69
76
|
# normal: backlog → todo → wip → testing → done
|
|
@@ -116,11 +123,15 @@ vars:
|
|
|
116
123
|
# run unbounded — if a hop still hits this wall, STOP and record it.
|
|
117
124
|
stepTimeoutMs: "1800000"
|
|
118
125
|
# Timeout for the `implement` step specifically (R2a). Implementation is the
|
|
119
|
-
# heaviest agent.run step (full read/write/test-probe loop)
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
|
|
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"
|
|
124
135
|
# Answer captured by the approve gate's hitl.confirm (R1): "yes" | "no" | "cancel".
|
|
125
136
|
# Empty by default; only meaningful once the approve state has been entered.
|
|
126
137
|
__hitlAnswer: ""
|
|
@@ -128,13 +139,16 @@ vars:
|
|
|
128
139
|
# default; set by `spur workflow continue --answer-text` after the pause and read
|
|
129
140
|
# by the escalate→implement / escalate→failed guards. Non-empty = answered.
|
|
130
141
|
__hitlInput: ""
|
|
131
|
-
# Proof-state bracket (task 0612, ADR-071; restructured by task 0703
|
|
132
|
-
# canonical capture taken at quality-gate ENTRY — immediately before the
|
|
133
|
-
# final chain (quality → review → verify) — and re-captured at `test-recheck`
|
|
134
|
-
# remediation mutated the tree, so every evidence stage names one fresh digest
|
|
135
|
-
# `proofDigestNow` is the live re-capture compared against `proofDigest` at
|
|
136
|
-
#
|
|
137
|
-
#
|
|
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.
|
|
138
152
|
# `taskSpecPath` carries the task file path because `docs/tasks*` is excluded from the digest's
|
|
139
153
|
# git-tree half — spec content is folded in explicitly or a task-file edit would go undetected.
|
|
140
154
|
# The fingerprint scopes task content to the proof-input sections only (Background, Requirements,
|
|
@@ -155,6 +169,11 @@ vars:
|
|
|
155
169
|
# with the same package-manager surface (this monorepo is Bun-only):
|
|
156
170
|
# `--vars '{"qualityGateCmd":"bun run lint && bun run test"}'`. Soft probe, hard recheck,
|
|
157
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.
|
|
158
177
|
# TRUSTED CONFIG ONLY — this string is executed via `sh -c` (see test/test-recheck). Never
|
|
159
178
|
# interpolate untrusted operator/LLM input into qualityGateCmd (task 0436 SECUA residual).
|
|
160
179
|
# NO `format` PREFIX: `implement` already ran `$formatCmd` on its way out, and `test`
|
|
@@ -204,6 +223,14 @@ vars:
|
|
|
204
223
|
# (default) = on; set to "off" to bypass:
|
|
205
224
|
# `--vars '{"implementScopeGuard":"off"}'`.
|
|
206
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"
|
|
207
234
|
# 0931 R5: parallel batches defer the per-task feature sync so a task branch never
|
|
208
235
|
# touches feature files or docs/features/INDEX.md. When "true", the record step's
|
|
209
236
|
# post-record shell appends a deferral note and skips the sync; the parallel batch
|
|
@@ -213,6 +240,10 @@ vars:
|
|
|
213
240
|
|
|
214
241
|
states:
|
|
215
242
|
- id: precheck
|
|
243
|
+
display:
|
|
244
|
+
phase: implement
|
|
245
|
+
phaseTitle: Implement
|
|
246
|
+
title: Check task readiness
|
|
216
247
|
description: >
|
|
217
248
|
Fast deterministic task readiness and size checks. Failures route to the
|
|
218
249
|
`failed` terminal state (not a raw lifecycle abort mid-enter).
|
|
@@ -256,6 +287,10 @@ states:
|
|
|
256
287
|
reviewer: "${vars.agent}"
|
|
257
288
|
|
|
258
289
|
- id: implement
|
|
290
|
+
display:
|
|
291
|
+
phase: implement
|
|
292
|
+
phaseTitle: Implement
|
|
293
|
+
title: Implement
|
|
259
294
|
description: >
|
|
260
295
|
Run agent-driven implementation via /sp:dev-run --mode implement, THEN move the
|
|
261
296
|
task to `wip` via the normal verb. The lifecycle transition fires AFTER the
|
|
@@ -287,6 +322,10 @@ states:
|
|
|
287
322
|
options:
|
|
288
323
|
agent: ${vars.implementAgent}
|
|
289
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.
|
|
290
329
|
# Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
|
|
291
330
|
role: coder
|
|
292
331
|
# B7 R3/R6 (0894): coder stages reuse the role session — the test-fix hop
|
|
@@ -350,6 +389,17 @@ states:
|
|
|
350
389
|
- kind: shell
|
|
351
390
|
options:
|
|
352
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"
|
|
353
403
|
|
|
354
404
|
# ── escalate hop (operator-question pause, 0933) ──────────────────────────
|
|
355
405
|
# The implement agent paused on an operator question: it wrote
|
|
@@ -363,6 +413,11 @@ states:
|
|
|
363
413
|
# the escalate→implement guard so a stale question can never re-trigger the hop
|
|
364
414
|
# after the answered attempt.
|
|
365
415
|
- id: escalate
|
|
416
|
+
display:
|
|
417
|
+
phase: implement
|
|
418
|
+
phaseTitle: Implement
|
|
419
|
+
title: Ask operator
|
|
420
|
+
show: on-entry
|
|
366
421
|
description: >-
|
|
367
422
|
Operator-question pause (0933): the implement agent asked a question
|
|
368
423
|
headlessly; surface it to the operator and resume implement with the answer.
|
|
@@ -396,6 +451,10 @@ states:
|
|
|
396
451
|
# test-fix — increment attempt + pure slash /sp:dev-fixall (≤ max attempts)
|
|
397
452
|
# test-recheck — soft recheck → review | test-fix | failed (never silent lifecycle abort)
|
|
398
453
|
- id: test
|
|
454
|
+
display:
|
|
455
|
+
phase: test
|
|
456
|
+
phaseTitle: Test
|
|
457
|
+
title: Run quality gate
|
|
399
458
|
description: >
|
|
400
459
|
Proof-chain entry + soft quality-gate probe (single logical gate on the green path; bounded retries only
|
|
401
460
|
for SQLite lock contention). Capture of the canonical proof-input digest happens HERE — before any
|
|
@@ -440,6 +499,12 @@ states:
|
|
|
440
499
|
# R2 (0703, ADR-071): THE canonical proof capture. Placement is load-bearing: immediately before
|
|
441
500
|
# the final evidence chain, after every implement mutation (including the post-implement format).
|
|
442
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
|
|
443
508
|
- kind: proof.fingerprint
|
|
444
509
|
options:
|
|
445
510
|
var: proofDigest
|
|
@@ -449,9 +514,14 @@ states:
|
|
|
449
514
|
- kind: shell
|
|
450
515
|
options:
|
|
451
516
|
command: >-
|
|
452
|
-
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
|
|
453
518
|
|
|
454
519
|
- id: test-fix
|
|
520
|
+
display:
|
|
521
|
+
phase: test
|
|
522
|
+
phaseTitle: Test
|
|
523
|
+
title: Fix failures
|
|
524
|
+
show: on-entry
|
|
455
525
|
description: >
|
|
456
526
|
Bounded auto-fix hop when the quality gate is red OR final verification returned a
|
|
457
527
|
repairable non-PASS (task 0703 R4: remediation never happens inside verify — it loops
|
|
@@ -515,6 +585,11 @@ states:
|
|
|
515
585
|
processSpawn: available
|
|
516
586
|
|
|
517
587
|
- id: test-recheck
|
|
588
|
+
display:
|
|
589
|
+
phase: test
|
|
590
|
+
phaseTitle: Test
|
|
591
|
+
title: Re-run quality gate
|
|
592
|
+
show: on-entry
|
|
518
593
|
description: >
|
|
519
594
|
Soft recheck after fixall with bounded SQLite-lock retry. Writes PASS|FAIL (always exit 0). Transitions
|
|
520
595
|
branch to `triage` (PASS — the 0943 lane router), `test-fail-triage` (FAIL — the 0943
|
|
@@ -524,6 +599,12 @@ states:
|
|
|
524
599
|
# R4 (0703, ADR-071): bounded remediation mutated the tree by design, so the fresh evidence
|
|
525
600
|
# chain (recheck gate → review → verify) must start from a NEWLY captured digest. Capture-only;
|
|
526
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
|
|
527
608
|
- kind: proof.fingerprint
|
|
528
609
|
options:
|
|
529
610
|
var: proofDigest
|
|
@@ -539,9 +620,13 @@ states:
|
|
|
539
620
|
- kind: shell
|
|
540
621
|
options:
|
|
541
622
|
command: >-
|
|
542
|
-
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
|
|
543
624
|
|
|
544
625
|
- id: triage
|
|
626
|
+
display:
|
|
627
|
+
phase: review
|
|
628
|
+
phaseTitle: Review
|
|
629
|
+
title: Choose review depth
|
|
545
630
|
description: >-
|
|
546
631
|
Deterministic lane router between a green gate and the review/verify fork (0943 R1).
|
|
547
632
|
Writes the diffstat evidence file, honors a caller-set `mode` (never overridden), pins
|
|
@@ -570,17 +655,18 @@ states:
|
|
|
570
655
|
options:
|
|
571
656
|
command: >-
|
|
572
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
|
|
573
|
-
# (d) lane decision — degrades to the standard default whenever
|
|
658
|
+
# (d) lane decision — degrades to the standard default whenever workflows.decideDecisionMaker
|
|
574
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).
|
|
575
664
|
- kind: decide
|
|
576
665
|
options:
|
|
577
666
|
id: task-triage
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
low (small, contained diff — fast lane), standard, or high caution?
|
|
582
|
-
choices: [low, standard, high]
|
|
583
|
-
default: standard
|
|
667
|
+
decision: task-triage
|
|
668
|
+
params:
|
|
669
|
+
wbs: ${vars.wbs}
|
|
584
670
|
evidence:
|
|
585
671
|
- .spur/run/${vars.wbs}-diffstat.json
|
|
586
672
|
- ${vars.taskSpecPath}
|
|
@@ -601,6 +687,11 @@ states:
|
|
|
601
687
|
var: mode
|
|
602
688
|
|
|
603
689
|
- id: test-fail-triage
|
|
690
|
+
display:
|
|
691
|
+
phase: test
|
|
692
|
+
phaseTitle: Test
|
|
693
|
+
title: Triage test failure
|
|
694
|
+
show: on-entry
|
|
604
695
|
description: >-
|
|
605
696
|
Deterministic failure-class router on a red gate (0943 R3). The engine has no onEnter
|
|
606
697
|
conditionals, so the FAIL branch from `test`/`test-recheck` lands here as its own
|
|
@@ -611,22 +702,44 @@ states:
|
|
|
611
702
|
missing/corrupt decision fails closed to failed-check. (0976 R2 collapsed the former
|
|
612
703
|
`retryable` lane: the declared default made it unreachable on the inline path.)
|
|
613
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.
|
|
614
709
|
- kind: decide
|
|
615
710
|
options:
|
|
616
711
|
id: failure-class
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
the run stop here?
|
|
621
|
-
choices: [fix, stop]
|
|
622
|
-
default: fix
|
|
712
|
+
decision: failure-class
|
|
713
|
+
params:
|
|
714
|
+
wbs: ${vars.wbs}
|
|
623
715
|
evidence:
|
|
624
716
|
- .spur/run/${vars.wbs}-test-gate.findings
|
|
625
717
|
resultFile: .spur/run/${vars.wbs}-failure-class.decision
|
|
626
718
|
|
|
627
719
|
- id: review
|
|
628
|
-
|
|
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.
|
|
629
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}
|
|
630
743
|
- kind: agent.run
|
|
631
744
|
options:
|
|
632
745
|
# 0710 R2: review always runs on a fresh session — no implementation-session
|
|
@@ -672,29 +785,42 @@ states:
|
|
|
672
785
|
# (`.spur/run/<wbs>-test-fix-attempt` against `qualityGateMaxFixAttempts`), and the fix
|
|
673
786
|
# re-enters quality → review → verify on a freshly captured digest. The `decide` action
|
|
674
787
|
# itself always runs (the engine has no onEnter conditionals); with
|
|
675
|
-
# `
|
|
788
|
+
# `workflows.decideDecisionMaker` off it degrades to its declared default.
|
|
676
789
|
- id: review-fail-triage
|
|
790
|
+
display:
|
|
791
|
+
phase: review
|
|
792
|
+
phaseTitle: Review
|
|
793
|
+
title: Triage review findings
|
|
794
|
+
show: on-entry
|
|
677
795
|
description: >-
|
|
678
796
|
Deterministic router for a review that did NOT certify PASS (session finding after 1088).
|
|
679
797
|
`decide review-failure-class` reads the reviewer's answer and the task spec and routes:
|
|
680
798
|
fix → the shared test-fix hop, stop → failed with terminalReason failed-check. A
|
|
681
|
-
missing/corrupt decision fails closed to failed-check.
|
|
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.
|
|
682
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.
|
|
683
807
|
- kind: decide
|
|
684
808
|
options:
|
|
685
809
|
id: review-failure-class
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
repair agent, or should the run stop here for the operator?
|
|
690
|
-
choices: [fix, stop]
|
|
691
|
-
default: fix
|
|
810
|
+
decision: review-failure-class
|
|
811
|
+
params:
|
|
812
|
+
wbs: ${vars.wbs}
|
|
692
813
|
evidence:
|
|
693
814
|
- .spur/run/${vars.__runId}-review-answer.txt
|
|
694
815
|
- ${vars.taskSpecPath}
|
|
695
816
|
resultFile: .spur/run/${vars.wbs}-review-failure-class.decision
|
|
696
817
|
|
|
697
818
|
- id: approve
|
|
819
|
+
display:
|
|
820
|
+
phase: review
|
|
821
|
+
phaseTitle: Review
|
|
822
|
+
title: Operator approval
|
|
823
|
+
show: on-entry
|
|
698
824
|
description: >
|
|
699
825
|
Human-in-the-loop approval gate. Under `profile=auto` this state is never entered
|
|
700
826
|
(review routes around it straight to verify). In interactive mode this state pauses
|
|
@@ -710,9 +836,18 @@ states:
|
|
|
710
836
|
mode: never
|
|
711
837
|
|
|
712
838
|
- id: verify
|
|
839
|
+
display:
|
|
840
|
+
phase: verify
|
|
841
|
+
phaseTitle: "Verify & record"
|
|
842
|
+
title: Verify requirements and AC
|
|
713
843
|
description: >
|
|
714
844
|
Observe-only functional verification (BDD + traceability) via /sp:dev-verify --fix none
|
|
715
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`).
|
|
716
851
|
A live digest compare BEFORE the agent refuses to certify a state that drifted after the
|
|
717
852
|
quality/review evidence was produced (R2). The agent's
|
|
718
853
|
captured answer is written to `.spur/run/<wbs>-verify-answer.txt` and MUST follow
|
|
@@ -763,15 +898,17 @@ states:
|
|
|
763
898
|
options:
|
|
764
899
|
command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
|
|
765
900
|
# Session finding after 1088: the verifier's confidence level becomes a `confidence` check
|
|
766
|
-
# row
|
|
767
|
-
#
|
|
768
|
-
#
|
|
769
|
-
#
|
|
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.
|
|
770
907
|
- kind: shell
|
|
771
908
|
options:
|
|
772
909
|
command: >-
|
|
773
910
|
V=".spur/run/$wbs-verdict.json"; [ -f "$V" ] || exit 0;
|
|
774
|
-
jq --arg ack "$ackLowConfidence" '. + {checks: ((.checks // []) | map(select(.name != "confidence"))) + [{name: "confidence", status: (if (.confidence // "LOW") == "
|
|
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";
|
|
775
912
|
printf 'confidence: %s (ack=%s)\n' "$(jq -r '.confidence // "LOW (absent)"' "$V")" "$ackLowConfidence" >> ".spur/run/$wbs-test-gate.log";
|
|
776
913
|
exit 0
|
|
777
914
|
# (e) one jq mutation binds the verdict to the proof digest (0703 R3; runId 0730 §B.2 /
|
|
@@ -782,6 +919,10 @@ states:
|
|
|
782
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
|
|
783
920
|
|
|
784
921
|
- id: record
|
|
922
|
+
display:
|
|
923
|
+
phase: verify
|
|
924
|
+
phaseTitle: "Verify & record"
|
|
925
|
+
title: Record evidence
|
|
785
926
|
description: >
|
|
786
927
|
Record pipeline results into the task file via `spur task record` —
|
|
787
928
|
Testing/Review from the verdict, Solution backfilled from git diff as a
|
|
@@ -941,7 +1082,11 @@ transitions:
|
|
|
941
1082
|
guard:
|
|
942
1083
|
kind: shell
|
|
943
1084
|
options:
|
|
944
|
-
|
|
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'
|
|
945
1090
|
- from: precheck
|
|
946
1091
|
to: failed
|
|
947
1092
|
terminalReason: failed-check
|
|
@@ -1009,9 +1154,11 @@ transitions:
|
|
|
1009
1154
|
guard:
|
|
1010
1155
|
kind: shell
|
|
1011
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.
|
|
1012
1159
|
command: >-
|
|
1013
1160
|
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
1014
|
-
test "$gate_status" = PASS
|
|
1161
|
+
test "$gate_status" = PASS || { test "$gate_status" = DEFERRED && test "$deferQualityGate" = "true"; }
|
|
1015
1162
|
- from: test
|
|
1016
1163
|
to: test-fail-triage
|
|
1017
1164
|
description: Quality gate red — classify the failure before the repair hop (0943 R3).
|
|
@@ -1042,9 +1189,10 @@ transitions:
|
|
|
1042
1189
|
guard:
|
|
1043
1190
|
kind: shell
|
|
1044
1191
|
options:
|
|
1192
|
+
# 1111 R2: same var-gated acceptance of the deferred token as `test → triage`.
|
|
1045
1193
|
command: >-
|
|
1046
1194
|
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
1047
|
-
test "$gate_status" = PASS
|
|
1195
|
+
test "$gate_status" = PASS || { test "$gate_status" = DEFERRED && test "$deferQualityGate" = "true"; }
|
|
1048
1196
|
- from: test-recheck
|
|
1049
1197
|
to: test-fail-triage
|
|
1050
1198
|
description: Still red after fixall — classify the failure (0943 R3).
|
|
@@ -1155,33 +1303,44 @@ transitions:
|
|
|
1155
1303
|
kind: always
|
|
1156
1304
|
# ── review routing: FAIL → bounded remediation; PASS → approve or the auto-skip (R4) ──
|
|
1157
1305
|
# Declaration order matters and is FAIL-CLOSED: the two PASS edges each demand the reviewer's
|
|
1158
|
-
# own `Verdict: PASS` line
|
|
1159
|
-
#
|
|
1160
|
-
#
|
|
1161
|
-
#
|
|
1162
|
-
#
|
|
1163
|
-
#
|
|
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.
|
|
1164
1317
|
- from: review
|
|
1165
1318
|
to: verify
|
|
1166
|
-
description: profile=auto
|
|
1319
|
+
description: profile=auto, the review certified PASS, and no open P1-P3 review finding — skip the human approval gate.
|
|
1167
1320
|
guard:
|
|
1168
1321
|
kind: shell
|
|
1169
1322
|
options:
|
|
1170
1323
|
command: >-
|
|
1171
1324
|
test "$profile" = auto &&
|
|
1172
|
-
grep -qiE '^[[:space:]]*\**Verdict:\** *PASS' ".spur/run/$__runId-review-answer.txt"
|
|
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
|
|
1173
1328
|
- from: review
|
|
1174
1329
|
to: approve
|
|
1175
|
-
description: Review certified PASS — gate on human approval before verification.
|
|
1330
|
+
description: Review certified PASS with no open P1-P3 review finding — gate on human approval before verification.
|
|
1176
1331
|
guard:
|
|
1177
1332
|
kind: shell
|
|
1178
1333
|
options:
|
|
1179
|
-
command:
|
|
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
|
|
1180
1338
|
- from: review
|
|
1181
1339
|
to: review-fail-triage
|
|
1182
1340
|
description: >-
|
|
1183
|
-
No PASS
|
|
1184
|
-
|
|
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.
|
|
1185
1344
|
guard:
|
|
1186
1345
|
kind: always
|
|
1187
1346
|
|