@gobing-ai/spur 0.3.91 → 0.3.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/config/pipeline-budgets.json +2 -2
- package/config/plugin-scripts.json +17 -1
- package/config/workflows/feature-lifecycle.yaml +14 -5
- package/config/workflows/feature-verification.yaml +35 -27
- package/config/workflows/history-anatomy.yaml +14 -25
- package/config/workflows/idea-pipeline.yaml +9 -5
- package/config/workflows/task-pipeline.yaml +185 -4
- package/config/workflows/wrapup-pipeline.yaml +47 -5
- package/package.json +9 -9
- package/plugins/sp/agents/super-planner.md +14 -5
- package/plugins/sp/commands/dev-dogfood.md +4 -4
- package/plugins/sp/commands/dev-fixall.md +8 -5
- package/plugins/sp/commands/dev-run.md +6 -0
- package/plugins/sp/commands/dev-runall.md +12 -6
- package/plugins/sp/commands/dev-verify.md +9 -0
- package/plugins/sp/commands/dev-verifyall.md +5 -0
- package/plugins/sp/lib/idea-handoff.generated.mjs +301 -300
- package/plugins/sp/lib/inline-run.generated.d.mts +17 -0
- package/plugins/sp/lib/inline-run.generated.mjs +1460 -0
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/environment-lens.md +1 -1
- package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +136 -0
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +196 -2
- package/plugins/sp/scripts/feature-verification-steps.mjs +174 -0
- package/plugins/sp/scripts/feature-verification-steps.ts +275 -0
- package/plugins/sp/scripts/history-anatomy-cache.mjs +104 -4
- package/plugins/sp/scripts/history-anatomy-cache.ts +137 -13
- package/plugins/sp/scripts/inline-pipeline-parity-check.ts +1 -0
- package/plugins/sp/scripts/inline-run-setup.mjs +349 -0
- package/plugins/sp/scripts/inline-run-setup.ts +192 -75
- package/plugins/sp/scripts/record-feature-sync.mjs +63 -0
- package/plugins/sp/scripts/record-feature-sync.ts +84 -0
- package/plugins/sp/scripts/residual-scan.mjs +476 -0
- package/plugins/sp/scripts/residual-scan.ts +614 -0
- package/plugins/sp/scripts/task-evidence-precheck.ts +8 -3
- package/plugins/sp/scripts/task-size-precheck.ts +8 -3
- package/plugins/sp/skills/branch-workflow/SKILL.md +1 -0
- package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +2 -0
- package/plugins/sp/skills/code-implementation/SKILL.md +17 -0
- package/plugins/sp/skills/code-verification/SKILL.md +21 -0
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +1 -0
- package/plugins/sp/skills/dogfood-testing/SKILL.md +5 -3
- package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +63 -26
- package/plugins/sp/skills/dogfood-testing/references/report-template.md +33 -10
- package/plugins/sp/skills/history-anatomy/references/modes.md +5 -3
- package/plugins/sp/skills/next-feature/references/ranking-rubric.md +1 -1
- package/plugins/sp/skills/next-router/references/routing-table.md +7 -0
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
- package/plugins/sp/skills/session-review/SKILL.md +12 -2
- package/plugins/sp/skills/spur-cli/references/features.md +1 -1
- package/plugins/sp/skills/spur-cli/references/projects.md +3 -1
- package/plugins/sp/skills/spur-cli/references/workflows.md +39 -19
- package/plugins/sp/skills/spur-dev/SKILL.md +11 -4
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +4 -1
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +2 -2
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +285 -57
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +1 -1
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +19 -4
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +43 -16
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +5 -0
- package/spur.js +21827 -19615
- package/web/_astro/BoardApp.CerSBgis.js +192 -0
- package/web/_astro/BoardApp.eoTz0pZs.js +1 -0
- package/web/_astro/{TaskDetail.CXGltuT_.js → TaskDetail.DCqiC-OZ.js} +1 -1
- package/web/_astro/arc.CPwg6Rw0.js +1 -0
- package/web/_astro/{architectureDiagram-3BPJPVTR.DJ8DHkWE.js → architectureDiagram-3BPJPVTR.DM_vp_hO.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.D8DHK3Jl.js → blockDiagram-GPEHLZMM.DXVIiv0p.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BugQbX9u.js → c4Diagram-AAUBKEIU.BbF_zCxW.js} +1 -1
- package/web/_astro/channel.MYZLKNwy.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.Mv26KlVn.js → chunk-2J33WTMH.CAgQHpPC.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.CD51JoT_.js → chunk-4BX2VUAB.BN-5tpw4.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.D_PFaIEe.js → chunk-55IACEB6.CnPkEEr0.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DemMW1ao.js → chunk-727SXJPM.BQzQeMVm.js} +4 -4
- package/web/_astro/{chunk-AQP2D5EJ.Iu2V5-ex.js → chunk-AQP2D5EJ.B6xNyDnL.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.MsNgSP-E.js → chunk-FMBD7UC4.C7f9Ih78.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.DfbRaAlm.js → chunk-ND2GUHAM.CNV1dFXT.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BbJAQ4h-.js → chunk-QZHKN3VN.Cudn2TkJ.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.CPurtiC2.js → classDiagram-4FO5ZUOK.D1NwP50q.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.CPurtiC2.js → classDiagram-v2-Q7XG4LA2.D1NwP50q.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CKKdx1bM.js → cose-bilkent-S5V4N54A.B1wSL-Xb.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.CoKMTg-R.js → cynefin-OW5HDTMX.BmK52w8G.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.D4h4_k56.js → dagre-BM42HDAG.Bfy5CTDT.js} +2 -2
- package/web/_astro/diagram-2AECGRRQ.DhNnvUvX.js +43 -0
- package/web/_astro/diagram-5GNKFQAL.lTX5KwnS.js +10 -0
- package/web/_astro/{diagram-KO2AKTUF.BFoCkiCr.js → diagram-KO2AKTUF.CW_vMJ4z.js} +3 -3
- package/web/_astro/{diagram-LMA3HP47.exHn9OVx.js → diagram-LMA3HP47.B_8ZGF67.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.CeqO34nN.js → diagram-OG6HWLK6.BppnHsdS.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.D_v7HqxR.js → erDiagram-TEJ5UH35.BEuHXcjJ.js} +5 -5
- package/web/_astro/{flowDiagram-I6XJVG4X.EUmrpbwh.js → flowDiagram-I6XJVG4X.CH-UlnGr.js} +4 -4
- package/web/_astro/{ganttDiagram-6RSMTGT7.BOCF5lII.js → ganttDiagram-6RSMTGT7.BO81S85v.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.Di7otYZD.js → gitGraphDiagram-PVQCEYII.XnPxPPZN.js} +1 -1
- package/web/_astro/index.Hjbr15fG.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.TcBkCAJk.js → infoDiagram-5YYISTIA.JyjYRu_T.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.D-2y4M0c.js → ishikawaDiagram-YF4QCWOH.BBRBF-Fo.js} +5 -5
- package/web/_astro/{journeyDiagram-JHISSGLW.DPbJI_n2.js → journeyDiagram-JHISSGLW.C_iymSyp.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.EFxhQ9Fj.js → kanban-definition-UN3LZRKU.DdfW-Oqt.js} +7 -7
- package/web/_astro/{linear.DSAsQLzs.js → linear.C2_IkbZT.js} +1 -1
- package/web/_astro/mermaid.core.GAOYeSR0.js +303 -0
- package/web/_astro/{mindmap-definition-RKZ34NQL.CJY1N_7V.js → mindmap-definition-RKZ34NQL.DAZIxQSK.js} +2 -2
- package/web/_astro/{pieDiagram-4H26LBE5.567ZNoL2.js → pieDiagram-4H26LBE5.CN8sIhKM.js} +3 -3
- package/web/_astro/{quadrantDiagram-W4KKPZXB.mqfz9-MY.js → quadrantDiagram-W4KKPZXB.3dGcX5GP.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.Bv1Gv9In.js → requirementDiagram-4Y6WPE33.BV2y4dd6.js} +3 -3
- package/web/_astro/{sankeyDiagram-5OEKKPKP.B6Gs4X4r.js → sankeyDiagram-5OEKKPKP.Cqo15Tvo.js} +4 -4
- package/web/_astro/{sequenceDiagram-3UESZ5HK.BhYj4v-m.js → sequenceDiagram-3UESZ5HK.CROCPMJB.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.BPbBnkpw.js → stateDiagram-AJRCARHV.RfXZrkFE.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.C4squMNK.js → stateDiagram-v2-BHNVJYJU.CPXmbBs9.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.C_SwIHgl.js → timeline-definition-PNZ67QCA.DdgKTiO8.js} +3 -3
- package/web/_astro/{vennDiagram-CIIHVFJN.Bz4NZGpQ.js → vennDiagram-CIIHVFJN.CPNVSHF1.js} +5 -5
- package/web/_astro/{wardleyDiagram-YWT4CUSO.CozMVZ3i.js → wardleyDiagram-YWT4CUSO.CQhA0Jyr.js} +3 -3
- package/web/_astro/{xychartDiagram-2RQKCTM6.BwMGBwjB.js → xychartDiagram-2RQKCTM6.n61BWyy4.js} +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.BEDWpzsr.js +0 -188
- package/web/_astro/BoardApp.DQG2xfEz.js +0 -1
- package/web/_astro/arc.C0rrflm_.js +0 -1
- package/web/_astro/channel.SRrg1P-w.js +0 -1
- package/web/_astro/diagram-2AECGRRQ.DJ0h9zgw.js +0 -43
- package/web/_astro/diagram-5GNKFQAL.DvPk1jYd.js +0 -10
- package/web/_astro/index.Bx6GY4RH.css +0 -1
- package/web/_astro/mermaid.core.kAZjgJHG.js +0 -301
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"decision": null
|
|
37
37
|
},
|
|
38
38
|
"history-anatomy": {
|
|
39
|
-
"modelQueries":
|
|
39
|
+
"modelQueries": 3,
|
|
40
40
|
"wallClockMs": null,
|
|
41
41
|
"tokenCostUsd": null,
|
|
42
|
-
"source": "Coverage entry (0826 R2): the live definition's model-query count (extractResolvedWorkflowFacts, 2026-09-11). No real-run measurement yet: wall-clock and cost are unenforced until measured, never 0.",
|
|
42
|
+
"source": "Coverage entry (0826 R2): the live definition's model-query count (extractResolvedWorkflowFacts, 2026-09-11). No real-run measurement yet: wall-clock and cost are unenforced until measured, never 0. 0920 recount 2026-09-23: 4 -> 3 — the resolve-scope model hop was removed; scope/window validation is deterministic in the history-anatomy-cache paths command.",
|
|
43
43
|
"decision": null
|
|
44
44
|
},
|
|
45
45
|
"wayfinder-resolution": {
|
|
@@ -48,7 +48,13 @@
|
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"rel": "inline-run-setup.ts",
|
|
51
|
-
"contract": "
|
|
51
|
+
"contract": "standard",
|
|
52
|
+
"twin": "inline-run-setup.mjs"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"rel": "feature-verification-steps.ts",
|
|
56
|
+
"contract": "standard",
|
|
57
|
+
"twin": "feature-verification-steps.mjs"
|
|
52
58
|
},
|
|
53
59
|
{
|
|
54
60
|
"rel": "idea-coverage-check.ts",
|
|
@@ -63,11 +69,21 @@
|
|
|
63
69
|
"contract": "standard",
|
|
64
70
|
"twin": "pr-reviewing.mjs"
|
|
65
71
|
},
|
|
72
|
+
{
|
|
73
|
+
"rel": "record-feature-sync.ts",
|
|
74
|
+
"contract": "standard",
|
|
75
|
+
"twin": "record-feature-sync.mjs"
|
|
76
|
+
},
|
|
66
77
|
{
|
|
67
78
|
"rel": "quality-gate.ts",
|
|
68
79
|
"contract": "standard",
|
|
69
80
|
"twin": "quality-gate.mjs"
|
|
70
81
|
},
|
|
82
|
+
{
|
|
83
|
+
"rel": "residual-scan.ts",
|
|
84
|
+
"contract": "standard",
|
|
85
|
+
"twin": "residual-scan.mjs"
|
|
86
|
+
},
|
|
71
87
|
{
|
|
72
88
|
"rel": "script-contract-check.ts",
|
|
73
89
|
"contract": "repo-only"
|
|
@@ -40,9 +40,17 @@ states:
|
|
|
40
40
|
onEnter:
|
|
41
41
|
# Caller wiring (task 0880, ADR-119): entering verification RUNS the
|
|
42
42
|
# feature-scoped pass instead of only passively reading its status file.
|
|
43
|
+
# 0948 R1: pass BOTH vars the inner workflow needs. `--vars` was documented as
|
|
44
|
+
# replace-not-merge and a partial override silently blanked `spurBin`; the engine
|
|
45
|
+
# merges declared defaults today (0948 R2), but the caller stays explicit so the
|
|
46
|
+
# nested run is self-sufficient under either semantic.
|
|
43
47
|
- kind: shell
|
|
44
48
|
options:
|
|
45
|
-
|
|
49
|
+
# Pass featureId and spurBin together. A partial --vars map used to be
|
|
50
|
+
# applied as a replacement, so the inner run lost spurBin and loadModule
|
|
51
|
+
# fell into source mode (0948 R1). The nested JSON is shell-expanded:
|
|
52
|
+
# $spurBin inside the double quotes keeps a multi-word invocation intact.
|
|
53
|
+
command: '$spurBin workflow run feature-verification.yaml --vars "{\"featureId\":\"$featureId\",\"spurBin\":\"$spurBin\"}"'
|
|
46
54
|
- id: blocked
|
|
47
55
|
description: Impediment; work suspended.
|
|
48
56
|
- id: done
|
|
@@ -68,13 +76,14 @@ transitions:
|
|
|
68
76
|
- from: verifying
|
|
69
77
|
to: done
|
|
70
78
|
description: >
|
|
71
|
-
Feature verified — complete.
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
Feature verified — complete. The strict check at the done boundary also
|
|
80
|
+
validates the bound verification receipt (D63 task 0915): current, PASS,
|
|
81
|
+
matching feature identity and verifier contract, digest-chained to the
|
|
82
|
+
checked inputs. Stale/missing/failed evidence denies the hop.
|
|
74
83
|
guard:
|
|
75
84
|
kind: shell
|
|
76
85
|
options:
|
|
77
|
-
command: '
|
|
86
|
+
command: '$spurBin feature check $featureId --strict --as done'
|
|
78
87
|
|
|
79
88
|
# Rework: verifying → active (mandatory History entry)
|
|
80
89
|
- from: verifying
|
|
@@ -1,29 +1,34 @@
|
|
|
1
|
-
# Feature-scoped verification pass (ADR-119, feature D62, task 0872
|
|
1
|
+
# Feature-scoped verification pass (ADR-119, feature D62, task 0872; D63 task
|
|
2
|
+
# 0915 remediation folds the evidence contract into a workflow-owned script).
|
|
2
3
|
#
|
|
3
4
|
# Owns a lifecycle boundary no per-task graph owns: the repo-wide checks whose
|
|
4
|
-
# invariant spans the repository rather than a single task's diff
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# feature until this pass records PASS (ADR-119 consequence: a feature is not
|
|
10
|
-
# done until it passes).
|
|
5
|
+
# invariant spans the repository rather than a single task's diff. They run
|
|
6
|
+
# once per feature, deliberately the slow pass; `feature-lifecycle`'s verifying
|
|
7
|
+
# entry invokes this workflow (task 0880 caller wiring), and its verifying→done
|
|
8
|
+
# guard refuses to complete the feature until this pass records PASS (ADR-119
|
|
9
|
+
# consequence: a feature is not done until it passes).
|
|
11
10
|
#
|
|
12
|
-
# Run: spur workflow run feature-verification.yaml --vars '{"featureId":"
|
|
11
|
+
# Run: spur workflow run feature-verification.yaml --vars '{"featureId":"D63"}'
|
|
13
12
|
#
|
|
14
|
-
# Shape: verify -> done | failed. The
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
13
|
+
# Shape: verify -> done | failed. The onEnter step runs the standard script
|
|
14
|
+
# `feature-verification-steps.ts` (no public CLI verb, D63 task 0915): it
|
|
15
|
+
# resolves this very definition for the verifier identity (name, source path,
|
|
16
|
+
# layer, definition digest), records the RUNNING receipt (run-scoped +
|
|
17
|
+
# feature-latest copies), registers the run-scoped receipt as a run artifact,
|
|
18
|
+
# runs the configured verification command via the safe launch splitter, and
|
|
19
|
+
# completes the receipt PASS/FAIL with the after-pass proof-input digest. A
|
|
20
|
+
# changed tree during the pass records FAIL.
|
|
18
21
|
#
|
|
19
22
|
# Reliability (aligned with task-pipeline / ADR-043): no agent.run nodes; the
|
|
20
|
-
# verification command
|
|
21
|
-
#
|
|
23
|
+
# verification command comes from `vars.verificationCmd` below and is never
|
|
24
|
+
# interpolated through a shell. The always-exit-0 onEnter means missing,
|
|
25
|
+
# corrupt or FAIL evidence routes to `failed` via the guard (fail-closed),
|
|
26
|
+
# never a silent PASS; infrastructure errors exit nonzero and surface.
|
|
22
27
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
23
28
|
kind: state-machine
|
|
24
29
|
name: feature-verification
|
|
25
30
|
version: "1"
|
|
26
|
-
description: "Feature-scoped verification pass (ADR-119): runs the repo-wide check set once per feature and records PASS/FAIL. Invoked by feature-lifecycle's verifying entry."
|
|
31
|
+
description: "Feature-scoped verification pass (ADR-119): runs the repo-wide check set once per feature and records a bound PASS/FAIL evidence receipt. Invoked by feature-lifecycle's verifying entry."
|
|
27
32
|
iterationBound: 2
|
|
28
33
|
initialState: verify
|
|
29
34
|
terminalStates:
|
|
@@ -35,37 +40,40 @@ vars:
|
|
|
35
40
|
featureId: "X"
|
|
36
41
|
spurBin: "spur"
|
|
37
42
|
verificationCmd: "bun run spur-check-feature"
|
|
43
|
+
__runId: ""
|
|
38
44
|
|
|
39
45
|
states:
|
|
40
46
|
- id: verify
|
|
41
47
|
description: >
|
|
42
|
-
Run the repo-wide check set
|
|
48
|
+
Run the repo-wide check set via the standard verification script, which
|
|
49
|
+
records the bound evidence receipt (verifier identity, checked-input
|
|
50
|
+
digest, run identity) and the coarse status file, always exit 0 so the
|
|
51
|
+
transition guard routes missing/corrupt/FAIL to `failed`.
|
|
43
52
|
onEnter:
|
|
44
53
|
- kind: shell
|
|
45
54
|
options:
|
|
46
55
|
command: >-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
exit 0
|
|
56
|
+
bun plugins/sp/scripts/feature-verification-steps.ts verify
|
|
57
|
+
--feature-id "$featureId"
|
|
58
|
+
--run-id "$__runId"
|
|
59
|
+
--spur-bin "$spurBin"
|
|
52
60
|
|
|
53
61
|
- id: done
|
|
54
|
-
description: Terminal — repo-wide checks passed.
|
|
62
|
+
description: Terminal — repo-wide checks passed and the receipt is bound.
|
|
55
63
|
|
|
56
64
|
- id: failed
|
|
57
|
-
description: Terminal — repo-wide checks failed or the
|
|
65
|
+
description: Terminal — repo-wide checks failed or the evidence is missing/corrupt.
|
|
58
66
|
|
|
59
67
|
transitions:
|
|
60
68
|
- from: verify
|
|
61
69
|
to: done
|
|
62
|
-
description: Repo-wide checks passed — the
|
|
70
|
+
description: Repo-wide checks passed — the script completed the receipt with PASS.
|
|
63
71
|
guard:
|
|
64
72
|
kind: shell
|
|
65
73
|
options:
|
|
66
|
-
command: 'test "$(cat .spur/run/$
|
|
74
|
+
command: 'test "$(cat .spur/run/$__runId-feature-verification.status 2>/dev/null)" = PASS'
|
|
67
75
|
- from: verify
|
|
68
76
|
to: failed
|
|
69
|
-
description: Repo-wide checks failed (or the
|
|
77
|
+
description: Repo-wide checks failed (or the evidence is missing/corrupt) — stop at failed.
|
|
70
78
|
guard:
|
|
71
79
|
kind: always
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# would exceed the shell composition threshold and be flagged as an owned-capability candidate.
|
|
12
12
|
#
|
|
13
13
|
# Shape:
|
|
14
|
-
# start -> resolve-
|
|
14
|
+
# start -> resolve-paths -> analyze -> cache-probe
|
|
15
15
|
# (hit -> refresh-provenance -> publish -> published)
|
|
16
16
|
# (miss -> render -> enrich -> structure-gate -> validate -> stamp -> publish)
|
|
17
17
|
# (structure-gate FAIL -> correct (max 2 total) -> structure-gate; exhausted -> failed)
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
#
|
|
29
29
|
# Vars (all must be declared here — the vars: block is the only safe shape; `spur workflow
|
|
30
30
|
# validate` and the skill-structure test enforce it):
|
|
31
|
-
# mode — "daily" (default) | "ad-hoc" (validated
|
|
31
|
+
# mode — "daily" (default) | "ad-hoc" (validated deterministically by the helper `paths` command)
|
|
32
32
|
# date — YYYY-MM-DD for --date (daily); empty for ad-hoc
|
|
33
33
|
# since — inclusive ISO lower bound (ad-hoc; also normalizes daily via the DST-aware rule)
|
|
34
34
|
# until — inclusive ISO upper bound (ad-hoc)
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
# focus — ad-hoc focus string (required in ad-hoc mode, rejected in daily)
|
|
40
40
|
# recompute — "true" forces the full analyze/render/enrich/validate path (cache disposition
|
|
41
41
|
# forced-recompute)
|
|
42
|
-
# output — explicit report output path; default
|
|
42
|
+
# output — explicit report output path; default docs/report/<date>-history-anatomy.md
|
|
43
43
|
# agent — executor for the agent.run stages (enrich/validate)
|
|
44
44
|
# spurBin — PATH-independent spur invocation (overridden by CLI at run start)
|
|
45
45
|
# __runId — run-scoped id for explicit artifact paths (allocated in start)
|
|
@@ -85,28 +85,22 @@ states:
|
|
|
85
85
|
description: >
|
|
86
86
|
Allocate the run-scoped id and root. Every analyze/render path in this workflow writes to
|
|
87
87
|
an explicit unique path under this run id — no stage reads the mutable latest.json pointer.
|
|
88
|
+
The retained identity is `.spur/run/<runId>-history-anatomy-run.id` (0948 R8). The fixed
|
|
89
|
+
`history-anatomy-run.id` name is only a latest pointer and is overwritten by the next run.
|
|
88
90
|
onEnter:
|
|
89
91
|
- kind: shell
|
|
90
92
|
options:
|
|
91
93
|
command: >-
|
|
92
94
|
mkdir -p .spur/run;
|
|
93
95
|
if [ -z "$__runId" ]; then __runId=$(uuidgen | tr 'A-Z' 'a-z' | cut -c1-8); fi;
|
|
94
|
-
echo "$__runId" > .spur/run
|
|
96
|
+
echo "$__runId" > ".spur/run/$__runId-history-anatomy-run.id";
|
|
97
|
+
cp ".spur/run/$__runId-history-anatomy-run.id" .spur/run/history-anatomy-run.id
|
|
98
|
+
# 0948 R8 retention disposition: `history-anatomy-run.id` is a SINGLE fixed-name
|
|
99
|
+
# pointer that is overwritten every run — it does not accumulate, so it needs no
|
|
100
|
+
# reclamation path (unlike the run-record pair and legacy `.log` files, which
|
|
101
|
+
# `spur workflow clean --logs` owns). It is deliberately NOT a run record and is
|
|
102
|
+
# exempt from the catalog record-name sweep (see run-record-catalog.test.ts).
|
|
95
103
|
|
|
96
|
-
- id: resolve-scope
|
|
97
|
-
description: >
|
|
98
|
-
Dispatch the skill's mode validation (0658 references/modes.md): daily is the default and
|
|
99
|
-
rejects focus/since/until/output; ad-hoc requires a non-empty focus plus two ordered
|
|
100
|
-
inclusive bounds and rejects --date/--recompute. Writes the normalized selector artifact.
|
|
101
|
-
onEnter:
|
|
102
|
-
- kind: agent.run
|
|
103
|
-
options:
|
|
104
|
-
agent: ${vars.agent}
|
|
105
|
-
input: "Validate the mode arguments per sp:history-anatomy references/modes.md and write the normalized selector to .spur/run/${vars.__runId}-selector.json. mode=${vars.mode} date=${vars.date} since=${vars.since} until=${vars.until} focus=${vars.focus}. Reject conflicting arguments, naming the offending one; a rejection marks the run failed."
|
|
106
|
-
# Declared Layer-1 role (0538 R2): mode validation is a reviewer-standard judgment.
|
|
107
|
-
role: reviewer
|
|
108
|
-
expectFile: .spur/run/${vars.__runId}-selector.json
|
|
109
|
-
timeoutMs: ${vars.stepTimeoutMs}
|
|
110
104
|
|
|
111
105
|
- id: resolve-paths
|
|
112
106
|
description: >
|
|
@@ -122,6 +116,7 @@ states:
|
|
|
122
116
|
h=$(superskill script path sp history-anatomy-cache.mjs);
|
|
123
117
|
node "$h" paths --helper "$h" --report-dir "$reportDir" --date "$date"
|
|
124
118
|
--output "$output" --mode "$mode" --since "$since" --until "$until"
|
|
119
|
+
--focus "$focus" --recompute "$recompute" --run-id "$__runId"
|
|
125
120
|
--out .spur/run/$__runId-paths.txt
|
|
126
121
|
|
|
127
122
|
- id: analyze
|
|
@@ -338,14 +333,8 @@ states:
|
|
|
338
333
|
|
|
339
334
|
transitions:
|
|
340
335
|
- from: start
|
|
341
|
-
to: resolve-scope
|
|
342
|
-
description: Scope resolved.
|
|
343
|
-
guard:
|
|
344
|
-
kind: always
|
|
345
|
-
|
|
346
|
-
- from: resolve-scope
|
|
347
336
|
to: resolve-paths
|
|
348
|
-
description: Mode
|
|
337
|
+
description: Mode/window grammar validated and paths resolved once (deterministic).
|
|
349
338
|
guard:
|
|
350
339
|
kind: always
|
|
351
340
|
|
|
@@ -461,10 +461,12 @@ states:
|
|
|
461
461
|
plan, ac, decisions, dependencies, premises) so the deterministic task
|
|
462
462
|
check passes, then writes the run-scoped ready evidence sidecar
|
|
463
463
|
(.spur/run/${vars.__runId}-idea-ready.json) with one row per task: wbs,
|
|
464
|
-
status (ready|failed|skipped), planningDigest, and seven check rows
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
464
|
+
status (ready|failed|skipped), planningDigest, and seven check rows,
|
|
465
|
+
with the premises row carrying tree-verified path:line citations
|
|
466
|
+
(0947). Handoff-finalize verifies presence, digest, feature binding and
|
|
467
|
+
checklist evidence before recommending auto runall; missing or failing
|
|
468
|
+
evidence never fails the run — it degrades the recommendation to
|
|
469
|
+
ready-depth refineall.
|
|
468
470
|
onEnter:
|
|
469
471
|
- kind: agent.run
|
|
470
472
|
options:
|
|
@@ -483,7 +485,9 @@ states:
|
|
|
483
485
|
for feature ${vars.featureId} per sp:spur-dev
|
|
484
486
|
references/planning-workflow.md § Step 5.6 (Ready preparation): read
|
|
485
487
|
.spur/run/${vars.__runId}-idea-batch-create-result.json and write
|
|
486
|
-
.spur/run/${vars.__runId}-idea-ready.json.
|
|
488
|
+
.spur/run/${vars.__runId}-idea-ready.json. The premises check row passes only
|
|
489
|
+
when each material premise was verified against the current tree and its evidence
|
|
490
|
+
cites at least one verified path:line (handoff-finalize lints it; task 0947).
|
|
487
491
|
answerFile: .spur/run/${vars.__runId}-ready-prepare-answer.txt
|
|
488
492
|
expectFile: .spur/run/${vars.__runId}-ready-prepare-answer.txt
|
|
489
493
|
# Fail-closed shape validation (mirrors the order-sidecar guard). Absence is
|
|
@@ -6,13 +6,18 @@
|
|
|
6
6
|
# through the normal `spur task update <wbs> <status>` verb so the lifecycle guards
|
|
7
7
|
# (0055) apply identically. Run linkage is written to `task_run_links` (kind=pipeline).
|
|
8
8
|
#
|
|
9
|
-
# Shape: precheck → implement → test[→test-fix↔test-recheck] → review → approve(HITL)
|
|
9
|
+
# Shape: precheck → implement[→escalate] → test[→test-fix↔test-recheck] → review → approve(HITL)
|
|
10
10
|
# → verify → record → done
|
|
11
11
|
# (precheck failure short-circuits to `failed`; approve routes to `failed` on
|
|
12
12
|
# operator rejection or `cancelled` on operator cancel — R1, bug-750).
|
|
13
13
|
# `test` is the project quality gate (shell + bounded /sp:dev-fixall), not
|
|
14
14
|
# /sp:dev-unit (coverage gap-fill; router C3/C5).
|
|
15
15
|
#
|
|
16
|
+
# F96 residual sweep (0950): precheck captures the resume-safe base commit; verify
|
|
17
|
+
# scans and folds residuals between the verdict and the proof bind (blocking leftovers
|
|
18
|
+
# downgrade PASS → PARTIAL and take the existing remediation edge); done settles
|
|
19
|
+
# deferrals; failed renders the recovery report. No new state, edge, or model query.
|
|
20
|
+
#
|
|
16
21
|
# Vars (passed as a JSON object via `--vars`):
|
|
17
22
|
# wbs — task WBS (required)
|
|
18
23
|
# profile — "auto" skips HITL approve (R4)
|
|
@@ -21,6 +26,7 @@
|
|
|
21
26
|
# implementTimeoutMs — implement agent.run budget (ms)
|
|
22
27
|
# qualityGateCmd — project gate (default: bun run spur-check)
|
|
23
28
|
# qualityGateMaxFixAttempts — max /sp:dev-fixall hops after a red gate (default: 2)
|
|
29
|
+
# maxEscalations — max operator-question pauses per implement chain (default: 2)
|
|
24
30
|
#
|
|
25
31
|
# Seeded by `spur init`. agent.run inputs are pure slash commands (ADR-043).
|
|
26
32
|
|
|
@@ -90,6 +96,10 @@ vars:
|
|
|
90
96
|
# Answer captured by the approve gate's hitl.confirm (R1): "yes" | "no" | "cancel".
|
|
91
97
|
# Empty by default; only meaningful once the approve state has been entered.
|
|
92
98
|
__hitlAnswer: ""
|
|
99
|
+
# Operator answer captured by the escalate hop's hitl.input (0933). Empty by
|
|
100
|
+
# default; set by `spur workflow continue --answer-text` after the pause and read
|
|
101
|
+
# by the escalate→implement / escalate→failed guards. Non-empty = answered.
|
|
102
|
+
__hitlInput: ""
|
|
93
103
|
# Proof-state bracket (task 0612, ADR-071; restructured by task 0703). `proofDigest` is the
|
|
94
104
|
# canonical capture taken at quality-gate ENTRY — immediately before the evidence-producing
|
|
95
105
|
# final chain (quality → review → verify) — and re-captured at `test-recheck` when bounded
|
|
@@ -134,6 +144,14 @@ vars:
|
|
|
134
144
|
# Max /sp:dev-fixall attempts after a red quality-gate probe/recheck (bounded; no thrash).
|
|
135
145
|
# Attempt counter: .spur/run/<wbs>-test-fix-attempt. Default 2 = two fixall hops before failed.
|
|
136
146
|
qualityGateMaxFixAttempts: "2"
|
|
147
|
+
# Max operator-question pauses (0933) before the implement chain routes to failed.
|
|
148
|
+
# Escalation counter: .spur/run/<wbs>-escalation-count. Default 2 = two answered
|
|
149
|
+
# questions; a third pause routes to failed with a report note.
|
|
150
|
+
maxEscalations: "2"
|
|
151
|
+
# Runtime-written, 0933: the escalate hop's file.read.into-var fills this from
|
|
152
|
+
# .spur/run/<wbs>-question.md; the hitl.input prompt below references it. Declared
|
|
153
|
+
# here (empty) so the static var-reference validator sees the template source.
|
|
154
|
+
escalationQuestion: ""
|
|
137
155
|
# Post-implement auto-format. Overridable like qualityGateCmd so a non-Bun seeded
|
|
138
156
|
# project can point it at its own formatter; invoked best-effort (a missing or
|
|
139
157
|
# failing formatter must never abort a run — the quality gate is the real gate).
|
|
@@ -156,6 +174,12 @@ vars:
|
|
|
156
174
|
# (default) = on; set to "off" to bypass:
|
|
157
175
|
# `--vars '{"implementScopeGuard":"off"}'`.
|
|
158
176
|
implementScopeGuard: ""
|
|
177
|
+
# 0931 R5: parallel batches defer the per-task feature sync so a task branch never
|
|
178
|
+
# touches feature files or docs/features/INDEX.md. When "true", the record step's
|
|
179
|
+
# post-record shell appends a deferral note and skips the sync; the parallel batch
|
|
180
|
+
# orchestrator runs the sync + `spur feature refresh` once per touched feature on the
|
|
181
|
+
# base ref after integration. Sequential/inline keep the default "false" (unchanged).
|
|
182
|
+
deferFeatureSync: "false"
|
|
159
183
|
|
|
160
184
|
states:
|
|
161
185
|
- id: precheck
|
|
@@ -189,6 +213,12 @@ states:
|
|
|
189
213
|
options:
|
|
190
214
|
command: >-
|
|
191
215
|
mkdir -p .spur/run; S=plugins/sp/scripts/task-evidence-precheck.ts; [ -f "$S" ] || S="$(superskill script path sp task-evidence-precheck.ts 2>/dev/null)"; if [ -f "$S" ]; then bun "$S" "$wbs" --spur-bin "$spurBin"; else echo "task-evidence-precheck failed closed — checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'." >&2; echo "FAIL" > ".spur/run/$wbs-precheck-evidence.status"; fi; exit 0
|
|
216
|
+
# (e) F96 R1 (0950): capture the run's base commit once — a resumed or re-entered run
|
|
217
|
+
# keeps its original base so residual scans stay anchored to the same diff.
|
|
218
|
+
- kind: shell
|
|
219
|
+
options:
|
|
220
|
+
command: >-
|
|
221
|
+
mkdir -p .spur/run; [ -f ".spur/run/$wbs-base.sha" ] || git rev-parse HEAD > ".spur/run/$wbs-base.sha"; exit 0
|
|
192
222
|
# (e) route-reason lookup and routes log; proportional-routing tests locate it
|
|
193
223
|
# (0759 R1/R5 run-scoped artifact; 0804 R8 run-id safety — one line, no in-scalar `#`).
|
|
194
224
|
- kind: shell
|
|
@@ -222,6 +252,20 @@ states:
|
|
|
222
252
|
that command DRIVES this pipeline, so calling it here recurses.
|
|
223
253
|
--mode implement is the single-step implement entry.
|
|
224
254
|
onEnter:
|
|
255
|
+
# 0933 R27 (guard-lines compression): the transcript append lives HERE, on
|
|
256
|
+
# (re-)entry, not in the escalate→implement guard. On first entry there is no
|
|
257
|
+
# pending question (no-op); on a resume entry the guard already confirmed a
|
|
258
|
+
# non-empty $__hitlInput and a fresh question file, so this shell records the
|
|
259
|
+
# Q/A pair (## Q<n>/## A<n>, R3) and consumes the question file before the
|
|
260
|
+
# agent.run re-dispatches — which also disarms the implement→escalate edge.
|
|
261
|
+
- kind: shell
|
|
262
|
+
options:
|
|
263
|
+
command: >-
|
|
264
|
+
test -n "$__hitlInput" -a -s .spur/run/$wbs-question.md || exit 0;
|
|
265
|
+
qn="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)";
|
|
266
|
+
printf '## Q%s\n%s\n\n## A%s\n%s\n' "$qn" "$(cat .spur/run/$wbs-question.md 2>/dev/null)" "$qn" "$__hitlInput" >> .spur/run/$wbs-escalation.md;
|
|
267
|
+
rm -f .spur/run/$wbs-question.md;
|
|
268
|
+
exit 0
|
|
225
269
|
- kind: agent.run
|
|
226
270
|
options:
|
|
227
271
|
agent: ${vars.implementAgent}
|
|
@@ -232,13 +276,23 @@ states:
|
|
|
232
276
|
# resumes the implement session instead of re-reading the task cold.
|
|
233
277
|
session: reuse
|
|
234
278
|
# lives in /sp:dev-run --mode implement → sp:code-implementation, not YAML prose.
|
|
235
|
-
|
|
279
|
+
# 0933 R28: --escalation-file names the Q/A transcript the implement
|
|
280
|
+
# agent appends to when pausing and reads back on re-dispatch; absent
|
|
281
|
+
# on a first attempt means "no prior escalations".
|
|
282
|
+
input: /sp:dev-run --mode implement ${vars.wbs} --auto --escalation-file .spur/run/${vars.wbs}-escalation.md
|
|
236
283
|
timeoutMs: ${vars.implementTimeoutMs}
|
|
237
284
|
# R3 (task 0424): empty-implement no-op guard — the agent.run action
|
|
238
285
|
# fails the step when exit 0 produced zero non-corpus file changes, so
|
|
239
286
|
# a silent no-op routes the run to `failed` here instead of drifting
|
|
240
287
|
# into test/review and being caught a full pass later.
|
|
241
288
|
requireDiff: true
|
|
289
|
+
# 0933 R26: escalation contract — the agent.run option names the QUESTION
|
|
290
|
+
# file (the pause signal, deleted pre-dispatch for freshness); a paused
|
|
291
|
+
# attempt (agent wrote its question there and exited 0) succeeds with
|
|
292
|
+
# data.escalated=true and skips requireDiff for THAT attempt only. The
|
|
293
|
+
# Q/A transcript (.spur/run/<wbs>-escalation.md) is separate: it reaches
|
|
294
|
+
# the agent via --escalation-file in the input below.
|
|
295
|
+
escalationFile: .spur/run/${vars.wbs}-question.md
|
|
242
296
|
# 0706 R6: this stage mutates the working tree unattended under the
|
|
243
297
|
# auto profile, so it declares minimum execution-capability
|
|
244
298
|
# requirements. Dispatch fails closed (before spawn) when the
|
|
@@ -273,6 +327,39 @@ states:
|
|
|
273
327
|
options:
|
|
274
328
|
command: "$formatCmd ; exit 0"
|
|
275
329
|
|
|
330
|
+
# ── escalate hop (operator-question pause, 0933) ──────────────────────────
|
|
331
|
+
# The implement agent paused on an operator question: it wrote
|
|
332
|
+
# .spur/run/<wbs>-question.md and exited 0 (agent.run reported
|
|
333
|
+
# data.escalated=true, skipping requireDiff for that attempt). This hop bounds
|
|
334
|
+
# the asks (counter), surfaces the question verbatim through the HITL responder
|
|
335
|
+
# (the run pauses here), and — after `spur workflow continue --answer-text <a>`
|
|
336
|
+
# delivers __hitlInput — resumes implement with the Q/A transcript
|
|
337
|
+
# (.spur/run/<wbs>-escalation.md) named in the implement input via
|
|
338
|
+
# --escalation-file. The transcript append + question-file consumption happen in
|
|
339
|
+
# the escalate→implement guard so a stale question can never re-trigger the hop
|
|
340
|
+
# after the answered attempt.
|
|
341
|
+
- id: escalate
|
|
342
|
+
description: >-
|
|
343
|
+
Operator-question pause (0933): the implement agent asked a question
|
|
344
|
+
headlessly; surface it to the operator and resume implement with the answer.
|
|
345
|
+
onEnter:
|
|
346
|
+
# Bounded asks: increment the per-task escalation counter before pausing.
|
|
347
|
+
- kind: shell
|
|
348
|
+
options:
|
|
349
|
+
command: >-
|
|
350
|
+
mkdir -p .spur/run; n="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)"; echo $((n + 1)) > .spur/run/$wbs-escalation-count; exit 0
|
|
351
|
+
# The agent's question, verbatim, becomes the pause prompt.
|
|
352
|
+
- kind: file.read.into-var
|
|
353
|
+
options:
|
|
354
|
+
file: .spur/run/${vars.wbs}-question.md
|
|
355
|
+
var: escalationQuestion
|
|
356
|
+
# Pause for the operator (responder pause:true stops the run after this
|
|
357
|
+
# onEnter; `spur workflow continue --answer-text <answer>` writes
|
|
358
|
+
# __hitlInput and re-evaluates the escalate guards).
|
|
359
|
+
- kind: hitl.input
|
|
360
|
+
options:
|
|
361
|
+
prompt: "${vars.escalationQuestion}"
|
|
362
|
+
|
|
276
363
|
# ── test hop (quality gate + bounded auto-fix) ─────────────────────────────
|
|
277
364
|
# NOT /sp:dev-unit. That command (sp:code-testing) *extends/generates* tests toward
|
|
278
365
|
# a coverage target; it is not the project quality gate. Coverage gap-fill remains
|
|
@@ -358,6 +445,14 @@ states:
|
|
|
358
445
|
options:
|
|
359
446
|
command: >-
|
|
360
447
|
mkdir -p .spur/run; A=".spur/run/$wbs-test-fix-attempt"; n=$(cat "$A" 2>/dev/null || echo 0); printf '%s\n' "$((n + 1))" > "$A"; [ ! -f ".spur/run/$wbs-verdict.json" ] || { echo '--- verify verdict (remediation input, task 0703 R4) ---'; cat ".spur/run/$wbs-verdict.json"; } >> ".spur/run/$wbs-test-gate.log"; exit 0
|
|
448
|
+
# (d) F96 R3 (0950): hand the residual list to the remediation loop — dev-fixall
|
|
449
|
+
# treats residual items as fix targets and may defer P3/markers to
|
|
450
|
+
# residual-deferrals.json (see dev-fixall.md). Fold already merged the anchors
|
|
451
|
+
# into <wbs>-test-gate.findings; this carries the structured artifact too.
|
|
452
|
+
- kind: shell
|
|
453
|
+
options:
|
|
454
|
+
command: >-
|
|
455
|
+
[ ! -f ".spur/run/$wbs-residuals.json" ] || { echo '--- residual artifact (F96 fix targets; deferrals go to residual-deferrals.json, P3/markers only) ---'; cat ".spur/run/$wbs-residuals.json"; } >> ".spur/run/$wbs-test-gate.log"; exit 0
|
|
361
456
|
# R3 (0482): project the extracted gate anchors into a var so the dispatch input
|
|
362
457
|
# can NAME the failing file:line, not merely point at a log. A vars template cannot
|
|
363
458
|
# run a shell, so the read is an action, not an inline `$(cat ...)` substitution.
|
|
@@ -530,6 +625,16 @@ states:
|
|
|
530
625
|
- kind: shell
|
|
531
626
|
options:
|
|
532
627
|
command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
|
|
628
|
+
# (d) F96 R2 (0950): residual-scan.ts owns the sweep; shell only resolves it.
|
|
629
|
+
# ONE hard action (scan+fold): a scanner crash fails verify closed — the
|
|
630
|
+
# verify→failed catch-all routes a missing/malformed verdict. Runs AFTER
|
|
631
|
+
# `task verdict` and BEFORE the jq bind so a blocking residual turns PASS
|
|
632
|
+
# into PARTIAL (fold rewrites the verdict artifact) and takes the existing
|
|
633
|
+
# verify→test-fix edge while attempts remain.
|
|
634
|
+
- kind: shell
|
|
635
|
+
options:
|
|
636
|
+
command: >-
|
|
637
|
+
S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ ! -f "$S" ]; then echo "residual-scan failed closed — scanner not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'" >&2; exit 1; fi; case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" scan "$wbs" --spur-bin "$spurBin" && "$RUNNER" "$S" fold "$wbs" --spur-bin "$spurBin"
|
|
533
638
|
# (e) one jq mutation binds the verdict to the proof digest (0703 R3; runId 0730 §B.2 /
|
|
534
639
|
# 0757 R4; definitionDigest 0759 R5; honest review stamp 0785 R4; soft action + hard guard).
|
|
535
640
|
- kind: shell
|
|
@@ -584,10 +689,16 @@ states:
|
|
|
584
689
|
# (d) feature-sync-bounded.ts owns the sync; shell adds the orphan note and fallbacks
|
|
585
690
|
# (0411 retry-suppression; 0328 / ADR-0322). Best-effort `exit 0` — feature status sync is a
|
|
586
691
|
# follow-up, not a completion gate; `record → done` runs `spur task check`.
|
|
692
|
+
# 0931 R5: with deferFeatureSync "true" (parallel mode) the deferral note lands in the
|
|
693
|
+
# task report and the sync is skipped entirely, so task branches never touch feature
|
|
694
|
+
# corpus files; the batch orchestrator performs the deferred sync on the base ref.
|
|
695
|
+
# The sync itself is owned by record-feature-sync.ts (ADR-115: the guard plus the old
|
|
696
|
+
# inline chain cannot share one shell); resolution follows the standard in-repo-first,
|
|
697
|
+
# superskill-staged fallback used by every pipeline checker.
|
|
587
698
|
- kind: shell
|
|
588
699
|
options:
|
|
589
700
|
command: >-
|
|
590
|
-
|
|
701
|
+
S=plugins/sp/scripts/record-feature-sync.ts; [ -f "$S" ] || S="$(superskill script path sp record-feature-sync.mjs 2>/dev/null)"; [ "$deferFeatureSync" = "true" ] && echo "feature sync deferred to batch integration" >> ".spur/run/$wbs-report.txt" || if [ -f "$S" ]; then bun "$S" --spur-bin "$spurBin"; else echo "feature sync skipped — record-feature-sync not found in plugins/sp/scripts/ nor staged" >> ".spur/run/$wbs-report.txt"; fi; exit 0
|
|
591
702
|
|
|
592
703
|
- id: done
|
|
593
704
|
description: >
|
|
@@ -595,6 +706,13 @@ states:
|
|
|
595
706
|
guard runs `spur task check` before certifying; a genuinely non-compliant
|
|
596
707
|
task routes to `failed` instead of a silent bad `done`.
|
|
597
708
|
onEnter:
|
|
709
|
+
# (d) F96 R4 (0950): residual-scan.ts owns the settle; shell only resolves it.
|
|
710
|
+
# Soft best-effort (exit 0) — runs after certification and must never change
|
|
711
|
+
# the outcome; failure prints the re-run command.
|
|
712
|
+
- kind: shell
|
|
713
|
+
options:
|
|
714
|
+
command: >-
|
|
715
|
+
S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ -f "$S" ]; then case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" settle "$wbs" --spur-bin "$spurBin" || echo "residual-settle failed — re-run: residual-scan settle $wbs" >&2; else echo "residual-scan not staged — settle skipped — re-run: residual-scan settle $wbs" >&2; fi; exit 0
|
|
598
716
|
# (c) command.gate owns the done transition with classified transient retry.
|
|
599
717
|
- kind: command.gate
|
|
600
718
|
options:
|
|
@@ -620,7 +738,28 @@ states:
|
|
|
620
738
|
- id: failed
|
|
621
739
|
description: >
|
|
622
740
|
Terminal — precheck, quality-gate exhaustion, verify non-PASS, record check
|
|
623
|
-
failure, or operator rejection; reported, not advanced.
|
|
741
|
+
failure, or operator rejection; reported, not advanced. Also receives an
|
|
742
|
+
escalation-bound pause or an operator give-up (0933).
|
|
743
|
+
onEnter:
|
|
744
|
+
# 0933 R30 (guard-lines compression): the escalation-bound report note lives
|
|
745
|
+
# here as a conditional — no-op unless the run reached failed with a pending
|
|
746
|
+
# question at (or above) the ask bound (bound pause or final give-up). The
|
|
747
|
+
# unanswered question itself is appended to the task report (report.txt, R2).
|
|
748
|
+
- kind: shell
|
|
749
|
+
options:
|
|
750
|
+
command: >-
|
|
751
|
+
n="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)";
|
|
752
|
+
test "$n" -ge "$maxEscalations" -a -s .spur/run/$wbs-question.md || exit 0;
|
|
753
|
+
printf '\n## Escalation bound reached\n\nThe implement step asked an operator question %s times (bound %s) and ended without a resumable answer. Unanswered question:\n\n' "$n" "$maxEscalations" >> .spur/run/$wbs-report.txt;
|
|
754
|
+
cat .spur/run/$wbs-question.md >> .spur/run/$wbs-report.txt;
|
|
755
|
+
exit 0
|
|
756
|
+
# (d) F96 R5 (0950): residual-scan.ts owns the report; shell only resolves it.
|
|
757
|
+
# Soft (exit 0): a run that exhausts its fix budget on residuals leaves the
|
|
758
|
+
# report + recovery line while the task stays `wip`.
|
|
759
|
+
- kind: shell
|
|
760
|
+
options:
|
|
761
|
+
command: >-
|
|
762
|
+
S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ -f "$S" ]; then case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" report "$wbs" --spur-bin "$spurBin" || echo "residual-report failed — re-run: residual-scan report $wbs" >&2; else echo "residual-scan not staged — report skipped — re-run: residual-scan report $wbs" >&2; fi; exit 0
|
|
624
763
|
|
|
625
764
|
- id: cancelled
|
|
626
765
|
description: Terminal — pipeline cancelled by operator at the approval gate (R1).
|
|
@@ -644,12 +783,54 @@ transitions:
|
|
|
644
783
|
guard:
|
|
645
784
|
kind: always
|
|
646
785
|
|
|
786
|
+
# ── implement routing: escalation first (0933 R26/R30), then the linear body ──
|
|
787
|
+
# Declaration order matters: the escalation bound is checked FIRST — a paused
|
|
788
|
+
# attempt that already exhausted its maxEscalations asks routes to failed (with a
|
|
789
|
+
# report note appended in the same guard) instead of asking forever; then the
|
|
790
|
+
# question-presence hop; then the normal always edge. The bound guard requires a
|
|
791
|
+
# fresh question file so a COMPLETED implement after max asks still routes to test.
|
|
792
|
+
- from: implement
|
|
793
|
+
to: failed
|
|
794
|
+
description: Escalation bound exhausted — the agent paused again after maxEscalations operator answers.
|
|
795
|
+
# 0933 R30 (guard-lines compression): thin predicate; the report note is written
|
|
796
|
+
# by the failed state's onEnter when it observes a bound-exhausted pause.
|
|
797
|
+
guard:
|
|
798
|
+
kind: shell
|
|
799
|
+
options:
|
|
800
|
+
command: >-
|
|
801
|
+
n="$(cat .spur/run/$wbs-escalation-count 2>/dev/null || echo 0)";
|
|
802
|
+
test "$n" -ge "$maxEscalations" -a -s .spur/run/$wbs-question.md
|
|
803
|
+
- from: implement
|
|
804
|
+
to: escalate
|
|
805
|
+
description: Implement agent paused on an operator question (non-empty question file) — pause for an answer.
|
|
806
|
+
guard:
|
|
807
|
+
kind: shell
|
|
808
|
+
options:
|
|
809
|
+
command: 'test -s .spur/run/$wbs-question.md'
|
|
647
810
|
# ── linear body ──
|
|
648
811
|
- from: implement
|
|
649
812
|
to: test
|
|
650
813
|
description: Implementation done — quality-gate probe.
|
|
651
814
|
guard:
|
|
652
815
|
kind: always
|
|
816
|
+
# escalate branching (0933 R27): an answered pause resumes implement — the transcript
|
|
817
|
+
# append and question consumption happen in implement's onEnter (guards stay thin
|
|
818
|
+
# under ADR-115 guard-lines caps); an empty answer is an operator give-up → failed
|
|
819
|
+
# (question + transcript preserved as evidence).
|
|
820
|
+
- from: escalate
|
|
821
|
+
to: implement
|
|
822
|
+
description: Operator answered — re-enter implement, which records the Q/A transcript and consumes the question.
|
|
823
|
+
guard:
|
|
824
|
+
kind: shell
|
|
825
|
+
options:
|
|
826
|
+
command: 'test -n "$__hitlInput"'
|
|
827
|
+
- from: escalate
|
|
828
|
+
to: failed
|
|
829
|
+
description: Empty operator answer — give-up routes to failed (question + transcript preserved as evidence).
|
|
830
|
+
guard:
|
|
831
|
+
kind: shell
|
|
832
|
+
options:
|
|
833
|
+
command: 'test -z "$__hitlInput"'
|
|
653
834
|
# Soft probe branching (declaration order: PASS first, then FAIL, then defense).
|
|
654
835
|
- from: test
|
|
655
836
|
to: verify
|