@gobing-ai/spur 0.3.73 → 0.3.74
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.example.yaml +15 -4
- package/config/pipeline-budgets.json +4 -4
- package/config/rules/strict/runtime-boundaries.yaml +1 -1
- package/config/templates/AGENTS.md +5 -0
- package/config/templates/docs/99_PROJECT_CONSTITUTION.md +2 -0
- package/config/workflows/basic.yaml +5 -2
- package/config/workflows/docs-pipeline.yaml +92 -55
- package/config/workflows/feature-dev.yaml +43 -20
- package/config/workflows/feature-lifecycle.yaml +1 -0
- package/config/workflows/history-anatomy.yaml +8 -4
- package/config/workflows/idea-pipeline.yaml +66 -33
- package/config/workflows/pr-review.yaml +31 -8
- package/config/workflows/task-lifecycle.yaml +1 -0
- package/config/workflows/task-pipeline.yaml +929 -905
- package/config/workflows/wayfinder-resolution.yaml +124 -90
- package/config/workflows/wrapup-pipeline.yaml +208 -83
- package/package.json +1 -1
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/history-anatomy-cache.mjs +7 -1
- package/plugins/sp/scripts/history-anatomy-cache.ts +11 -2
- package/plugins/sp/scripts/pr-reviewing.mjs +5 -1
- package/plugins/sp/scripts/pr-reviewing.ts +7 -1
- package/plugins/sp/scripts/transition-shim-check.ts +6 -6
- package/plugins/sp/skills/pr-reviewing/SKILL.md +4 -1
- package/plugins/sp/skills/spur-cli/references/self.md +17 -3
- package/plugins/sp/skills/spur-cli/references/tasks.md +1 -1
- package/plugins/sp/skills/spur-cli/references/workflows/workflow-fit-and-tuning.md +5 -5
- package/plugins/sp/skills/spur-cli/references/workflows.md +4 -4
- package/plugins/sp/skills/spur-dev/SKILL.md +17 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +3 -3
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +1 -2
- package/plugins/sp/skills/wayfinder/SKILL.md +1 -1
- package/spur.js +1125 -784
- package/web/_astro/{BoardApp.BYCNkMOn.js → BoardApp.C60RJZRj.js} +78 -77
- package/web/_astro/BoardApp.ymfj1EHA.js +1 -0
- package/web/_astro/{TaskDetail.CgUreSP2.js → TaskDetail.Guk8VuNu.js} +1 -1
- package/web/_astro/{arc.BySSh34M.js → arc.CAZtlWJM.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.DM46TS_h.js → architectureDiagram-3BPJPVTR.9-XbF_Tz.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.tZhvNUHA.js → blockDiagram-GPEHLZMM.DC4WLx3L.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.PT4Or4Nf.js → c4Diagram-AAUBKEIU.JgjUQMgG.js} +1 -1
- package/web/_astro/channel.Bxxe2Byc.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.J9r0_Bbe.js → chunk-2J33WTMH.D_JFiXa-.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.hzyeIvhR.js → chunk-4BX2VUAB.Bk_RxoeT.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.B0rO7qVh.js → chunk-55IACEB6.a_Rj2VxL.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.wE_Uk5D4.js → chunk-727SXJPM.C2NoS1U6.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.DqEEjQw7.js → chunk-AQP2D5EJ.D1Xn6CNa.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.CDoD9sBX.js → chunk-FMBD7UC4.BhJrSBsX.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CtX5nF9P.js → chunk-ND2GUHAM.ByVGduYQ.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.CK_EwfaT.js → chunk-QZHKN3VN.B47Paunq.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.DLt5a8Lh.js → classDiagram-4FO5ZUOK.BERMSD5C.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.DLt5a8Lh.js → classDiagram-v2-Q7XG4LA2.BERMSD5C.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CMCWP49h.js → cose-bilkent-S5V4N54A.O_rHGlhU.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.HyXw_vdS.js → cynefin-OW5HDTMX.qCW2GdNp.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.BTuAzh01.js → dagre-BM42HDAG.C5Y4lH_u.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.D9dr9wfT.js → diagram-2AECGRRQ.DxZmRXxF.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.C4Rot0hj.js → diagram-5GNKFQAL.qSxZeYSK.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.B_TK5uWC.js → diagram-KO2AKTUF.-7vl3bXs.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.JkXKK7CO.js → diagram-LMA3HP47.BHVV-UH3.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.BzMN8Bd6.js → diagram-OG6HWLK6.DHAuW9sK.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DVZaWGUd.js → erDiagram-TEJ5UH35.DMRLQwPN.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.rjEiWUfR.js → flowDiagram-I6XJVG4X.B3EpPp_8.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.C_EgAarK.js → ganttDiagram-6RSMTGT7.BgUrExXM.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.B-QQSDsK.js → gitGraphDiagram-PVQCEYII.CU-9yVN4.js} +1 -1
- package/web/_astro/{index.B5MTfe7k.css → index.BhvM3djt.css} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.DlWesz7T.js → infoDiagram-5YYISTIA.CvVTCRLe.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.BUMZOawi.js → ishikawaDiagram-YF4QCWOH.BUzOfKPf.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.CWfkxfjY.js → journeyDiagram-JHISSGLW.BBTb7ziz.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.B-YpMwXf.js → kanban-definition-UN3LZRKU.CTQQr70i.js} +1 -1
- package/web/_astro/{linear.D7uqzENp.js → linear.CLKlJPiS.js} +1 -1
- package/web/_astro/{mermaid.core.CxrNppBD.js → mermaid.core.BA4wFhLP.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.B4Qe7cM2.js → mindmap-definition-RKZ34NQL.t1vG2l5e.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.Ds-5j2ro.js → pieDiagram-4H26LBE5.C8zJhyTu.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.tBd38uNC.js → quadrantDiagram-W4KKPZXB.DqYYvb7T.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.sFENkWl3.js → requirementDiagram-4Y6WPE33.lzfDZ9nI.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.BeB-Hk7C.js → sankeyDiagram-5OEKKPKP.lm6N5ORM.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.DnTeaSpx.js → sequenceDiagram-3UESZ5HK.E6_IV4Dj.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.B-8Jt5EJ.js → stateDiagram-AJRCARHV.Bnv6Ok2p.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.Br7xoqMW.js → stateDiagram-v2-BHNVJYJU.mJHH_Ng_.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.C-3WdOyi.js → timeline-definition-PNZ67QCA.BhRgqSLa.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DCIs7Lc6.js → vennDiagram-CIIHVFJN.pjb5DMC9.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.rGAL-bbz.js → wardleyDiagram-YWT4CUSO.CW20KUng.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.hkfQKiRl.js → xychartDiagram-2RQKCTM6.vX9_yuMl.js} +1 -1
- package/web/index.html +2 -2
- package/config/corpus-baseline.json +0 -1805
- package/config/workflow-composition-baseline.json +0 -615
- package/web/_astro/BoardApp.E12MFjOS.js +0 -1
- package/web/_astro/channel.5cYKr5cs.js +0 -1
|
@@ -130,10 +130,21 @@ agent:
|
|
|
130
130
|
# agent: omp
|
|
131
131
|
# model: minimax/MiniMax-M3
|
|
132
132
|
# tier: cheap
|
|
133
|
-
- name:
|
|
134
|
-
agent:
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
- name: pi-dsv4-flash-volc
|
|
134
|
+
agent: pi
|
|
135
|
+
# tier: standard
|
|
136
|
+
executionCapabilities:
|
|
137
|
+
version: 1
|
|
138
|
+
axes:
|
|
139
|
+
fsRead:
|
|
140
|
+
state: available
|
|
141
|
+
provenance: native-known
|
|
142
|
+
fsWrite:
|
|
143
|
+
state: available
|
|
144
|
+
provenance: native-known
|
|
145
|
+
processSpawn:
|
|
146
|
+
state: available
|
|
147
|
+
provenance: native-known
|
|
137
148
|
# - name: omp-zai
|
|
138
149
|
# agent: omp
|
|
139
150
|
# model: zai/glm-5.2
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedAt": "2026-08-20T00:00:00.000Z",
|
|
4
|
-
"note": "Per-pipeline model-query + wall-clock cost budgets (task 0607 R3). modelQueries anchors the
|
|
4
|
+
"note": "Per-pipeline model-query + wall-clock cost budgets (task 0607 R3). modelQueries anchors the live workflow definitions' query lists — the SSOT, extracted by extractResolvedWorkflowFacts and guarded by composition-baseline.test.ts (0775 retired the snapshot this file previously anchored to). wallClockMs is a gross-regression ceiling anchored to measured real-run data (R5): the gate compares the median-of-sane terminal-run wall-clock against it. A null budget is unenforced until measured — never treated as 0. Raising a numeric budget requires a fresh recorded decision in the same commit (config/pipeline-budgets.json vs git HEAD); the check-pipeline-budgets gate fails a silent raise by name.",
|
|
5
5
|
"budgets": {
|
|
6
6
|
"task-pipeline": {
|
|
7
7
|
"modelQueries": 4,
|
|
@@ -28,18 +28,18 @@
|
|
|
28
28
|
"modelQueries": 2,
|
|
29
29
|
"wallClockMs": null,
|
|
30
30
|
"tokenCostUsd": null,
|
|
31
|
-
"source": "No fixture (0607 option a) and only dry/short runs recorded in history (max 1s, n=4) — wall-clock budget unenforced until a real docs-pipeline run exists. Query budget 2 matches the live
|
|
31
|
+
"source": "No fixture (0607 option a) and only dry/short runs recorded in history (max 1s, n=4) — wall-clock budget unenforced until a real docs-pipeline run exists. Query budget 2 matches the live workflow definition's query list ['draft','verify'] (added by task 0704; 0607 R3 recorded 1, which is stale against the definition). 0754 R6: FIX, not raise — the value was wrong against the definition, the workflow's declared query count did not change.",
|
|
32
32
|
"decision": {
|
|
33
33
|
"date": "2026-09-03",
|
|
34
34
|
"wbs": "0754",
|
|
35
|
-
"note": "align docs-pipeline.modelQueries to the live
|
|
35
|
+
"note": "align docs-pipeline.modelQueries to the live workflow definition's query list ['draft','verify']; not a measured-cost raise — the workflow's declared query count was already 2 (added by 0704); the budget was the stale side, not the workflow. Per D8 Decision 11."
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"pr-review": {
|
|
39
39
|
"modelQueries": 0,
|
|
40
40
|
"wallClockMs": null,
|
|
41
41
|
"tokenCostUsd": null,
|
|
42
|
-
"source": "Zero-query pipeline (
|
|
42
|
+
"source": "Zero-query pipeline (the live definition declares no model queries); query budget trivially 0 — the gate handles an empty list (0607 R3). No real full run recorded; wall-clock unenforced.",
|
|
43
43
|
"decision": null
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -74,5 +74,5 @@ rules:
|
|
|
74
74
|
# Synchronous template & workflow resolvers:
|
|
75
75
|
- "apps/cli/src/commands/task.ts" # sync loadTemplateContent/Bodies callbacks
|
|
76
76
|
- "apps/cli/src/workflow/make-lifecycle-adapter.ts" # sync resolveWorkflowPath lookup
|
|
77
|
-
- "packages/app/src/services/workflow-service.ts" #
|
|
77
|
+
- "packages/app/src/services/workflow-service.ts" # composition advisory source (0775: facts extracted from the live definition inside the synchronous validate path; the baseline snapshot sync read was retired)
|
|
78
78
|
- "apps/cli/src/release-ops.ts" # sync manifest/workspace reads + Bun.write rewrites inside the git release flow (task 0617); mirrors task.ts sync-template exemption
|
|
@@ -74,6 +74,11 @@ All product development work goes through the harness by default.
|
|
|
74
74
|
Use `spur task path <wbs> --json` only when a filesystem consumer needs the absolute path. Both
|
|
75
75
|
commands resolve across configured task folders. Reuse the first `show` response within the run.
|
|
76
76
|
|
|
77
|
+
**Corpus checks (constitution T10/T11):** checker-policy changes require one explicit unsuppressed
|
|
78
|
+
audit, recording/reconciling essential failures without waivers. Ordinary commit prep checks changed
|
|
79
|
+
task/feature documents and their required linked evidence, not the whole corpus. Do not regenerate
|
|
80
|
+
an acceptance baseline or insert audits into routine batch/wrapup loops.
|
|
81
|
+
|
|
77
82
|
**Platform fallback:** Platforms without slash commands and/or subagents still use the harness.
|
|
78
83
|
Install the plugin through Superskill for the target platform, then use skills `sp:spur-dev`,
|
|
79
84
|
`sp:spur-cli`, `sp:code-verification` (and related) plus the `spur` CLI. Do not invent a parallel
|
|
@@ -200,6 +200,8 @@ names the docs that must be touched **in the same commit / same change**:
|
|
|
200
200
|
| T7 | The doc map or process changes | this file → re-sync `AGENTS.md` (§4.4) → propagate to sibling projects |
|
|
201
201
|
| T8 | A multi-wave batch is planned | schedule "doc sync" as an **explicit work item** — same-commit discipline does not survive on memory alone |
|
|
202
202
|
| T9 | A design or feature item is added/changed | the satellite **first** (`docs/design/<slug>.md` or `docs/features/<id>_<slug>.md`), **then** its index row in `04`/`05` — same change (§4.5 rule 5) |
|
|
203
|
+
| T10 | Corpus checker policy changes | Run one explicit unsuppressed audit plus focused rule tests; record/reconcile exposed essential failures without waivers. |
|
|
204
|
+
| T11 | Ordinary task/feature commit prep | Check changed documents and their required linked evidence, not the whole corpus. Never regenerate an acceptance baseline or add routine audit callers. |
|
|
203
205
|
|
|
204
206
|
## 6. Edit principles per file
|
|
205
207
|
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
# Reliability (aligned with task-pipeline / ADR-043):
|
|
7
7
|
# - check is a soft probe (status file + always exit 0) so red gates route to fix
|
|
8
8
|
# via transitions, not a raw lifecycle abort that skips the failed terminal
|
|
9
|
+
# - qualityGateCmd is TRUSTED CONFIG ONLY — executed via `sh -c` so compound
|
|
10
|
+
# commands (`&&`, `||`) preserve their exit status; never interpolated task data
|
|
9
11
|
# - fix is pure slash /sp:dev-fixall against the same qualityGateCmd (single-sourced)
|
|
10
12
|
# - qualityGateMaxFixAttempts bounds the fix loop; exhausted → failed (fail-closed)
|
|
11
13
|
# - Bun package scripts only for gate surface (no alternate package-manager CLIs)
|
|
@@ -13,7 +15,8 @@
|
|
|
13
15
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
14
16
|
name: basic
|
|
15
17
|
kind: state-machine
|
|
16
|
-
description: The canonical implement-check-fix-until-pass loop
|
|
18
|
+
description: The canonical implement-check-fix-until-pass loop (example definition; override qualityGateCmd per project)
|
|
19
|
+
version: "1"
|
|
17
20
|
iterationBound: 8
|
|
18
21
|
initialState: implement
|
|
19
22
|
terminalStates:
|
|
@@ -57,7 +60,7 @@ states:
|
|
|
57
60
|
mkdir -p .spur/run &&
|
|
58
61
|
STATUS_FILE=".spur/run/$__runId-basic-gate.status" &&
|
|
59
62
|
set +e &&
|
|
60
|
-
|
|
63
|
+
sh -c "$qualityGateCmd"; gate_rc=$?; set -e &&
|
|
61
64
|
if [ "$gate_rc" -eq 0 ]; then
|
|
62
65
|
printf 'PASS\n' > "$STATUS_FILE";
|
|
63
66
|
else
|
|
@@ -11,12 +11,15 @@
|
|
|
11
11
|
# - requireDiff fails silent no-op drafts
|
|
12
12
|
# - HITL answer routing is exhaustive (yes/no/cancel)
|
|
13
13
|
# - verify measures the deliverable read-only (answer file + `spur task verdict` + proof
|
|
14
|
-
# digest bracket)
|
|
14
|
+
# digest bracket); recording happens only AFTER measured PASS (0769 ordering:
|
|
15
|
+
# precheck → draft → docs-review → verify → record → done) and `record → done` is
|
|
16
|
+
# fail-closed on the captured record result + re-asserted verdict — never on a stub
|
|
15
17
|
|
|
16
18
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
19
|
+
version: "1"
|
|
17
20
|
kind: state-machine
|
|
18
21
|
name: docs-pipeline
|
|
19
|
-
description: "Docs-only execution pipeline (precheck -> draft -> docs-review ->
|
|
22
|
+
description: "Docs-only execution pipeline (precheck -> draft -> docs-review -> verify -> record -> done)"
|
|
20
23
|
iterationBound: 12
|
|
21
24
|
initialState: precheck
|
|
22
25
|
terminalStates:
|
|
@@ -34,13 +37,15 @@ vars:
|
|
|
34
37
|
stepTimeoutMs: "1800000"
|
|
35
38
|
# Proof-state bracket (task 0704, mirroring task-pipeline 0612/0703). `proofDigest` is the
|
|
36
39
|
# canonical capture at verify entry; `proofDigestNow` is the live re-capture compared against
|
|
37
|
-
# it by the `verify →
|
|
40
|
+
# it by the `verify → record` guard so verifier-time mutation fails closed (R4/R5).
|
|
38
41
|
proofDigest: ""
|
|
39
42
|
proofDigestNow: ""
|
|
40
43
|
# `taskSpecPath` carries the task file path because `docs/tasks*` is excluded from the digest's
|
|
41
44
|
# git-tree half (task 0704 R4); resolved per-run by the verify state's taskpath shell step.
|
|
42
45
|
taskSpecPath: ""
|
|
43
46
|
__hitlAnswer: ""
|
|
47
|
+
# R8 (0366): injected by WorkflowAppService.run(); run-scopes every temporary capture.
|
|
48
|
+
__runId: ""
|
|
44
49
|
|
|
45
50
|
states:
|
|
46
51
|
- id: precheck
|
|
@@ -49,14 +54,16 @@ states:
|
|
|
49
54
|
(D5-J, ADR-069). Both gates run `softFail: true`, so a red probe records FAIL and lets
|
|
50
55
|
the transitions route to `failed` instead of aborting the run — the shipped action
|
|
51
56
|
schema exposes no `onError`, so soft mode is what preserves that routing.
|
|
52
|
-
The canonical `.spur/run/$
|
|
57
|
+
The canonical `.spur/run/$__runId-docs-precheck.status` is the AND of the two gate files.
|
|
58
|
+
(0769: temporary captures are run-scoped — `.spur/run/<runId>-docs-*` — so concurrent
|
|
59
|
+
runs on one task never share or clobber a capture.)
|
|
53
60
|
onEnter:
|
|
54
61
|
- kind: command.gate
|
|
55
62
|
options:
|
|
56
63
|
id: docs-precheck-task
|
|
57
64
|
executable: "${vars.spurBin}"
|
|
58
65
|
args: ["task", "check", "${vars.wbs}"]
|
|
59
|
-
resultFile: .spur/run/${vars.
|
|
66
|
+
resultFile: .spur/run/${vars.__runId}-docs-precheck-task.status
|
|
60
67
|
softFail: true
|
|
61
68
|
timeoutMs: 120000
|
|
62
69
|
- kind: command.gate
|
|
@@ -64,16 +71,16 @@ states:
|
|
|
64
71
|
id: docs-precheck-agent
|
|
65
72
|
executable: "${vars.spurBin}"
|
|
66
73
|
args: ["agent", "doctor", "${vars.agent}"]
|
|
67
|
-
resultFile: .spur/run/${vars.
|
|
74
|
+
resultFile: .spur/run/${vars.__runId}-docs-precheck-agent.status
|
|
68
75
|
softFail: true
|
|
69
76
|
timeoutMs: 120000
|
|
70
77
|
- kind: shell
|
|
71
78
|
options:
|
|
72
79
|
command: >-
|
|
73
|
-
if test "$(cat .spur/run/$
|
|
74
|
-
test "$(cat .spur/run/$
|
|
75
|
-
then printf 'PASS\n' > ".spur/run/$
|
|
76
|
-
else printf 'FAIL\n' > ".spur/run/$
|
|
80
|
+
if test "$(cat .spur/run/$__runId-docs-precheck-task.status 2>/dev/null)" = PASS &&
|
|
81
|
+
test "$(cat .spur/run/$__runId-docs-precheck-agent.status 2>/dev/null)" = PASS;
|
|
82
|
+
then printf 'PASS\n' > ".spur/run/$__runId-docs-precheck.status";
|
|
83
|
+
else printf 'FAIL\n' > ".spur/run/$__runId-docs-precheck.status"; fi
|
|
77
84
|
- kind: note
|
|
78
85
|
options:
|
|
79
86
|
message: "Docs pipeline start for task ${vars.wbs}."
|
|
@@ -108,36 +115,21 @@ states:
|
|
|
108
115
|
options:
|
|
109
116
|
prompt: "Approve docs-only deliverable for task ${vars.wbs}?"
|
|
110
117
|
|
|
111
|
-
- id: record
|
|
112
|
-
description: >
|
|
113
|
-
Record the docs-only outcome into the task file. The task record verb backfills
|
|
114
|
-
Solution from the diff and moves the task to testing; the done gate still runs
|
|
115
|
-
the normal task matrix check before completion.
|
|
116
|
-
onEnter:
|
|
117
|
-
- kind: shell
|
|
118
|
-
options:
|
|
119
|
-
command: "$spurBin task record $wbs --solution-from-diff --transition testing"
|
|
120
|
-
|
|
121
|
-
- id: done
|
|
122
|
-
description: Terminal — docs deliverable measured, reviewed, and recorded.
|
|
123
|
-
onEnter:
|
|
124
|
-
# R1 (0704): no synthetic verdict writer. The verdict artifact is produced by measured
|
|
125
|
-
# verification in `verify` and registered there; done only performs the guarded
|
|
126
|
-
# transition. Override path remains: --force-done --reason.
|
|
127
|
-
- kind: shell
|
|
128
|
-
options:
|
|
129
|
-
command: "$spurBin task update $wbs done --no-lifecycle"
|
|
130
|
-
- kind: note
|
|
131
|
-
options:
|
|
132
|
-
message: "Docs pipeline complete for task ${vars.wbs}."
|
|
133
118
|
- id: verify
|
|
134
119
|
description: >
|
|
135
120
|
Read-only measured verification (task 0704, R2/R4/R7): dispatch /sp:dev-verify --fix none
|
|
136
121
|
with an answer file, derive the ONE standard verdict via `spur task verdict`, register the
|
|
137
122
|
standard verify-verdict artifact, and bracket the verifier with proof-input digest capture/compare so any
|
|
138
123
|
task-spec or document mutation during certification fails closed (R4). No docs assurance
|
|
139
|
-
subclass — PASS semantics are identical to task-pipeline (R7).
|
|
124
|
+
subclass — PASS semantics are identical to task-pipeline (R7). 0769: verification now
|
|
125
|
+
PRECEDES recording; the `verify → record` guard compares the proof bracket, and the
|
|
126
|
+
verdict artifact keeps its `.spur/run/<wbs>-verdict.json` compatibility path with
|
|
127
|
+
runId + definitionDigest stamped through the existing proof/run-artifact contract.
|
|
140
128
|
onEnter:
|
|
129
|
+
# 0769: clear any stale current-run answer before the fresh-session verifier writes it.
|
|
130
|
+
- kind: shell
|
|
131
|
+
options:
|
|
132
|
+
command: "mkdir -p .spur/run && rm -f .spur/run/$__runId-docs-verify-answer.txt"
|
|
141
133
|
# R4 (0703 R6 precedent): resolve the task-spec path BEFORE capture. `docs/tasks*` is
|
|
142
134
|
# excluded from the digest's git-tree half, so the spec is folded in via `taskFile`.
|
|
143
135
|
- kind: shell
|
|
@@ -147,15 +139,15 @@ states:
|
|
|
147
139
|
# wbs exits non-zero with a named message. The resolved path folds
|
|
148
140
|
# into the proof digest via `taskFile:` below; a silent miss would
|
|
149
141
|
# degrade the docs-pipeline proof to tree-only (same hazard 0751 R2
|
|
150
|
-
# removed from task-pipeline).
|
|
142
|
+
# removed from task-pipeline). (0769: run-scoped capture path.)
|
|
151
143
|
command: >-
|
|
152
144
|
set -e;
|
|
153
145
|
task_path="$($spurBin task path $wbs --json | jq -r '.path // .filePath // empty')";
|
|
154
146
|
if [ -z "$task_path" ]; then echo "docs-pipeline: task path did not resolve for wbs $wbs" >&2; exit 1; fi;
|
|
155
|
-
printf '%s' "$task_path" > ".spur/run/$
|
|
147
|
+
printf '%s' "$task_path" > ".spur/run/$__runId-docs-taskpath.txt"
|
|
156
148
|
- kind: file.read.into-var
|
|
157
149
|
options:
|
|
158
|
-
path: .spur/run/${vars.
|
|
150
|
+
path: .spur/run/${vars.__runId}-docs-taskpath.txt
|
|
159
151
|
var: taskSpecPath
|
|
160
152
|
# R4: canonical capture BEFORE the verifier runs. Same fingerprint input as the
|
|
161
153
|
# re-capture below so the bracket compares like for like.
|
|
@@ -174,19 +166,19 @@ states:
|
|
|
174
166
|
input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
|
|
175
167
|
role: reviewer
|
|
176
168
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
177
|
-
answerFile: .spur/run/${vars.
|
|
169
|
+
answerFile: .spur/run/${vars.__runId}-docs-verify-answer.txt
|
|
178
170
|
- kind: shell
|
|
179
171
|
options:
|
|
180
|
-
command: "$spurBin task verdict $wbs --from-answer .spur/run/$
|
|
181
|
-
# R7: stamp the proof block into the standard verdict artifact, then register
|
|
182
|
-
# Soft action + hard guard: a missing/malformed stamp fails the `verify ->
|
|
172
|
+
command: "$spurBin task verdict $wbs --from-answer .spur/run/$__runId-docs-verify-answer.txt"
|
|
173
|
+
# R7: stamp the proof block + run identity into the standard verdict artifact, then register
|
|
174
|
+
# it. Soft action + hard guard: a missing/malformed stamp fails the `verify -> record`
|
|
183
175
|
# guard below, not this step.
|
|
184
176
|
- kind: shell
|
|
185
177
|
options:
|
|
186
178
|
command: >-
|
|
187
179
|
V=".spur/run/$wbs-verdict.json";
|
|
188
180
|
if [ -f "$V" ] && [ -n "$proofDigest" ]; then
|
|
189
|
-
jq --arg d "$proofDigest" '. + {proof: {digest: $d, capturePoint: "docs-verify-entry"}}' "$V" > "$V.tmp" && mv "$V.tmp" "$V";
|
|
181
|
+
jq --arg d "$proofDigest" --arg r "$__runId" '. + {proof: {digest: $d, capturePoint: "docs-verify-entry", runId: $r}}' "$V" > "$V.tmp" && mv "$V.tmp" "$V";
|
|
190
182
|
fi;
|
|
191
183
|
exit 0
|
|
192
184
|
- kind: run.artifact
|
|
@@ -202,6 +194,37 @@ states:
|
|
|
202
194
|
input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
|
|
203
195
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
204
196
|
|
|
197
|
+
- id: record
|
|
198
|
+
description: >
|
|
199
|
+
Record the docs-only outcome AFTER measured verification (task 0769 ordering:
|
|
200
|
+
draft/approval → verify → record → done — the pre-verification record could write
|
|
201
|
+
UNKNOWN/old Testing evidence). The verdict is already derived and proof-bracketed in
|
|
202
|
+
`verify`; `verify → record` only opens on measured PASS with an intact bracket. The
|
|
203
|
+
task record verb backfills Solution from the diff and moves the task to testing; its
|
|
204
|
+
result is captured to a run-scoped status file so a record denial reaches `failed`
|
|
205
|
+
(record → failed) and is never converted to success by an exit 0.
|
|
206
|
+
onEnter:
|
|
207
|
+
- kind: shell
|
|
208
|
+
options:
|
|
209
|
+
command: >-
|
|
210
|
+
if $spurBin task record $wbs --solution-from-diff --transition testing; then
|
|
211
|
+
printf 'PASS\n' > ".spur/run/$__runId-docs-record.status";
|
|
212
|
+
else
|
|
213
|
+
printf 'FAIL\n' > ".spur/run/$__runId-docs-record.status";
|
|
214
|
+
fi
|
|
215
|
+
|
|
216
|
+
- id: done
|
|
217
|
+
description: Terminal — docs deliverable measured, reviewed, and recorded.
|
|
218
|
+
onEnter:
|
|
219
|
+
# R1 (0704): no synthetic verdict writer. The verdict artifact is produced by measured
|
|
220
|
+
# verification in `verify` and registered there; done only performs the guarded
|
|
221
|
+
# transition. Override path remains: --force-done --reason.
|
|
222
|
+
- kind: shell
|
|
223
|
+
options:
|
|
224
|
+
command: "$spurBin task update $wbs done --no-lifecycle"
|
|
225
|
+
- kind: note
|
|
226
|
+
options:
|
|
227
|
+
message: "Docs pipeline complete for task ${vars.wbs}."
|
|
205
228
|
- id: failed
|
|
206
229
|
description: Terminal — docs pipeline failed or was rejected.
|
|
207
230
|
|
|
@@ -223,8 +246,8 @@ transitions:
|
|
|
223
246
|
kind: always
|
|
224
247
|
|
|
225
248
|
- from: draft
|
|
226
|
-
to:
|
|
227
|
-
description: profile=auto — skip the docs-review HITL gate.
|
|
249
|
+
to: verify
|
|
250
|
+
description: "profile=auto — skip the docs-review HITL gate; verify measures BEFORE record (0769: a pre-verification record could write UNKNOWN/old Testing evidence)."
|
|
228
251
|
guard:
|
|
229
252
|
kind: shell
|
|
230
253
|
options:
|
|
@@ -236,8 +259,8 @@ transitions:
|
|
|
236
259
|
kind: always
|
|
237
260
|
|
|
238
261
|
- from: docs-review
|
|
239
|
-
to:
|
|
240
|
-
description: Docs approved —
|
|
262
|
+
to: verify
|
|
263
|
+
description: "Docs approved — measure the deliverable (0769: verification precedes recording)."
|
|
241
264
|
guard:
|
|
242
265
|
kind: shell
|
|
243
266
|
options:
|
|
@@ -257,16 +280,11 @@ transitions:
|
|
|
257
280
|
options:
|
|
258
281
|
command: 'test "$__hitlAnswer" = cancel'
|
|
259
282
|
|
|
260
|
-
- from: record
|
|
261
|
-
to: verify
|
|
262
|
-
description: Recorded — measure the deliverable (R2). Structural task-check gates remain
|
|
263
|
-
at precheck, record (wip→testing), and done (verdict-artifact guard, R3).
|
|
264
|
-
guard:
|
|
265
|
-
kind: always
|
|
266
|
-
|
|
267
283
|
- from: verify
|
|
268
|
-
to:
|
|
269
|
-
description: Measured PASS with the proof bracket intact (R4/R5)
|
|
284
|
+
to: record
|
|
285
|
+
description: Measured PASS with the proof bracket intact (R4/R5) — record only verified
|
|
286
|
+
outcomes (0769). Structural task-check gates remain at precheck, record (wip→testing),
|
|
287
|
+
and done (verdict-artifact guard, R3).
|
|
270
288
|
guard:
|
|
271
289
|
kind: shell
|
|
272
290
|
options:
|
|
@@ -284,6 +302,25 @@ transitions:
|
|
|
284
302
|
- from: verify
|
|
285
303
|
to: failed
|
|
286
304
|
description: Non-PASS verdict, missing/malformed answer, or digest mismatch (R5) — the run
|
|
287
|
-
reaches failed and
|
|
305
|
+
reaches failed and nothing is recorded.
|
|
306
|
+
guard:
|
|
307
|
+
kind: always
|
|
308
|
+
|
|
309
|
+
- from: record
|
|
310
|
+
to: done
|
|
311
|
+
description: Recorded from a verified outcome; the persisted verdict/bracket is re-asserted
|
|
312
|
+
so a failed `task record` (captured FAIL) never converts to done (0769).
|
|
313
|
+
guard:
|
|
314
|
+
kind: shell
|
|
315
|
+
options:
|
|
316
|
+
command: >-
|
|
317
|
+
test "$(cat .spur/run/$__runId-docs-record.status 2>/dev/null)" = PASS &&
|
|
318
|
+
test -f ".spur/run/$wbs-verdict.json" &&
|
|
319
|
+
test "$(jq -r '.verdict // empty' .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS &&
|
|
320
|
+
test -n "$proofDigest" &&
|
|
321
|
+
test "$(jq -r '.proof.digest // empty' .spur/run/$wbs-verdict.json 2>/dev/null)" = "$proofDigest"
|
|
322
|
+
- from: record
|
|
323
|
+
to: failed
|
|
324
|
+
description: "Task record denied or errored (captured status not PASS) — the record denial reaches failed; the done guard above never converts it to success."
|
|
288
325
|
guard:
|
|
289
326
|
kind: always
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
10
10
|
kind: state-machine
|
|
11
11
|
name: feature-dev
|
|
12
|
+
version: "1"
|
|
12
13
|
description: >
|
|
13
14
|
End-to-end FEATURE development loop: precheck → brainstorm → plan (decompose) →
|
|
14
15
|
execute-tasks → feature-verify → done. Drives a whole feature (one description → a
|
|
@@ -143,18 +144,22 @@ states:
|
|
|
143
144
|
|
|
144
145
|
- id: integration-review
|
|
145
146
|
description: >
|
|
146
|
-
Advisory integration review (D5-P, feature R11)
|
|
147
|
-
|
|
147
|
+
Advisory integration review (D5-P, feature R11), upgraded by 0770 to a
|
|
148
|
+
truthful collect: ONE Codex review request per HEAD, then exactly ONE
|
|
149
|
+
`pr-reviewing.ts collect --head <captured-head>` against that same HEAD —
|
|
150
|
+
no wait loop, no polling. The request verdict (`REQUESTED` /
|
|
151
|
+
`ALREADY_REQUESTED` / `ALREADY_REVIEWED`) describes request state only;
|
|
152
|
+
it is NEVER clean evidence. The ONLY clean evidence is the collected
|
|
153
|
+
status (CLEAN / FINDINGS / PENDING) persisted run-scoped at
|
|
154
|
+
.spur/run/<runId>-integration-review-collect.status. A missing head SHA,
|
|
155
|
+
an invalid collect result, or head drift records collect FAIL.
|
|
148
156
|
|
|
149
|
-
D8 decision D1 (0753 R3):
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
all count as PASS (review is initiated for this HEAD); only a request
|
|
156
|
-
error counts as FAIL. `softFail` is gone: a real failure now records FAIL
|
|
157
|
-
loudly. `requireCleanReview=true` still turns that FAIL into a blocking edge.
|
|
157
|
+
D8 decision D1 (0753 R3): invoking `pr-reviewing.ts request` directly —
|
|
158
|
+
the same per-HEAD dedupe-or-request logic `config/workflows/pr-review.yaml`
|
|
159
|
+
uses internally. Request FAIL records FAIL in
|
|
160
|
+
.spur/run/<runId>-integration-review.status, loudly (no softFail).
|
|
161
|
+
`requireCleanReview=true` turns a non-clean COLLECTED verdict (including
|
|
162
|
+
collect FAIL) into the blocking edge declared first below.
|
|
158
163
|
onEnter:
|
|
159
164
|
- kind: shell
|
|
160
165
|
options:
|
|
@@ -162,20 +167,33 @@ states:
|
|
|
162
167
|
mkdir -p .spur/run &&
|
|
163
168
|
STATUS_FILE=".spur/run/$__runId-integration-review.status" &&
|
|
164
169
|
REQUEST_JSON=".spur/run/$__runId-integration-review.json" &&
|
|
170
|
+
COLLECT_JSON=".spur/run/$__runId-integration-review-collect.json" &&
|
|
171
|
+
COLLECT_STATUS=".spur/run/$__runId-integration-review-collect.status" &&
|
|
165
172
|
PR_REQUEST_STATUS=".spur/run/$__runId-integration-review-pr-request.status" &&
|
|
166
173
|
set +e &&
|
|
167
174
|
bun "$(superskill script path sp pr-reviewing.ts)" request --base "$baseBranch" --json
|
|
168
175
|
--status-file "$PR_REQUEST_STATUS" > "$REQUEST_JSON" 2>&1;
|
|
169
|
-
|
|
170
|
-
if [ "$
|
|
176
|
+
request_rc=$?; set -e &&
|
|
177
|
+
if [ "$request_rc" -eq 0 ]; then
|
|
171
178
|
printf 'PASS\n' > "$STATUS_FILE";
|
|
172
179
|
else
|
|
173
180
|
printf 'FAIL\n' > "$STATUS_FILE";
|
|
174
181
|
fi &&
|
|
182
|
+
HEAD_SHA=$(jq -r '.head // empty' "$REQUEST_JSON" 2>/dev/null || true) &&
|
|
183
|
+
if [ -z "$HEAD_SHA" ]; then
|
|
184
|
+
echo "integration-review: request result carried no head SHA — collect not run, recorded FAIL" >&2;
|
|
185
|
+
printf 'FAIL\n' > "$COLLECT_STATUS";
|
|
186
|
+
else
|
|
187
|
+
set +e &&
|
|
188
|
+
bun "$(superskill script path sp pr-reviewing.ts)" collect --head "$HEAD_SHA" --json
|
|
189
|
+
--status-file "$COLLECT_STATUS" > "$COLLECT_JSON" 2>&1;
|
|
190
|
+
collect_rc=$?; set -e &&
|
|
191
|
+
echo "integration-review: collect rc=$collect_rc status=$(cat "$COLLECT_STATUS" 2>/dev/null || echo missing) — verdict captured to $COLLECT_JSON" >&2;
|
|
192
|
+
fi;
|
|
175
193
|
exit 0
|
|
176
194
|
- kind: note
|
|
177
195
|
options:
|
|
178
|
-
message: "Integration review for feature ${vars.featureId}
|
|
196
|
+
message: "Integration review for feature ${vars.featureId}: request verdict at .spur/run/${vars.__runId}-integration-review.status (request state only — REQUESTED/ALREADY_* are NEVER clean evidence); collected verdict at .spur/run/${vars.__runId}-integration-review-collect.status (CLEAN/FINDINGS/PENDING — the only clean evidence). Advisory unless requireCleanReview=true."
|
|
179
197
|
|
|
180
198
|
- id: done
|
|
181
199
|
description: Terminal — feature planned, all tasks executed, and the feature verified.
|
|
@@ -246,18 +264,23 @@ transitions:
|
|
|
246
264
|
- from: integration-review
|
|
247
265
|
to: failed
|
|
248
266
|
description: >
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
267
|
+
Collected verdict is not CLEAN (FINDINGS / PENDING / collect FAIL or
|
|
268
|
+
missing) and this branch opted into a hard gate (requireCleanReview=true).
|
|
269
|
+
Exactly one collect ran against the captured request HEAD — no wait loop —
|
|
270
|
+
so pending or findings stop the feature here with the actual reason.
|
|
271
|
+
Ordered before the advisory edge so the strict policy wins when both
|
|
272
|
+
would match.
|
|
252
273
|
guard:
|
|
253
274
|
kind: shell
|
|
254
275
|
options:
|
|
255
|
-
command: 'test "$requireCleanReview" = true && test "$(cat .spur/run/$__runId-integration-review.status 2>/dev/null)"
|
|
276
|
+
command: 'test "$requireCleanReview" = true && test "$(cat .spur/run/$__runId-integration-review-collect.status 2>/dev/null)" != CLEAN'
|
|
256
277
|
- from: integration-review
|
|
257
278
|
to: done
|
|
258
279
|
description: >
|
|
259
|
-
|
|
260
|
-
non-clean advisory
|
|
280
|
+
Collected CLEAN, or advisory mode (requireCleanReview != true) — the
|
|
281
|
+
feature is complete. A non-clean advisory collect never blocks a
|
|
282
|
+
locally-verified feature (feature R11); the note above preserves the
|
|
283
|
+
collected non-clean state in the run record instead of hiding it.
|
|
261
284
|
guard:
|
|
262
285
|
kind: always
|
|
263
286
|
- from: feature-verify
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
10
10
|
kind: state-machine
|
|
11
11
|
name: feature-lifecycle
|
|
12
|
+
version: "1"
|
|
12
13
|
description: >
|
|
13
14
|
Feature lifecycle FSM (design §2.3, §5.1, DD-13). States are the canonical
|
|
14
15
|
FeatureStatus vocabulary; transitions encode the §2.3 graph including the
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
49
49
|
kind: state-machine
|
|
50
50
|
name: history-anatomy
|
|
51
|
+
version: "1"
|
|
51
52
|
description: "Daily/ad-hoc history-anatomy report: cache branch, deterministic analyze/render, skill enrichment, deterministic structure gate, independent evidence validation, bounded correction, atomic publication"
|
|
52
53
|
iterationBound: 20
|
|
53
54
|
initialState: start
|
|
@@ -153,7 +154,7 @@ states:
|
|
|
153
154
|
--baseline .spur/run/$__runId-history-anatomy-baseline.json --target "$HA_TARGET"
|
|
154
155
|
--mode "$mode" --date "$HA_DATE" --recompute "$recompute" --executor "$agent"
|
|
155
156
|
--skill-dir "$HA_SKILL" --contract "$HA_SKILL/references/report-contract.md"
|
|
156
|
-
--workflow "$workflowFile" --contract-version "$contractVersion" --run-id "$__runId"
|
|
157
|
+
--workflow "$workflowFile" --helper "$HA_HELPER" --contract-version "$contractVersion" --run-id "$__runId"
|
|
157
158
|
--out .spur/run/$__runId-provenance.json
|
|
158
159
|
> .spur/run/$__runId-cache-disposition.txt
|
|
159
160
|
|
|
@@ -208,6 +209,9 @@ states:
|
|
|
208
209
|
description: >
|
|
209
210
|
Independent evidence validation via the skill operation sp:history-anatomy validate.
|
|
210
211
|
Publication is reachable only from a PASS here. Same undeclared-write assertion as enrich (0676 R3).
|
|
212
|
+
The publish guard reads the ANCHORED FINAL LINE (0771): only a validation artifact whose last
|
|
213
|
+
line is exactly `Verdict: PASS` publishes — a leading PASS under a later FAIL or a
|
|
214
|
+
`not Verdict: PASS` line can never satisfy it.
|
|
211
215
|
onEnter:
|
|
212
216
|
- kind: shell
|
|
213
217
|
options:
|
|
@@ -390,18 +394,18 @@ transitions:
|
|
|
390
394
|
|
|
391
395
|
- from: validate
|
|
392
396
|
to: stamp
|
|
393
|
-
description: Independent validation PASS — stamp provenance, then publish atomically.
|
|
397
|
+
description: Independent validation PASS (anchored final line, 0771) — stamp provenance, then publish atomically.
|
|
394
398
|
guard:
|
|
395
399
|
kind: shell
|
|
396
400
|
options:
|
|
397
|
-
command: '
|
|
401
|
+
command: 'tail -n 1 .spur/run/$__runId-validation.txt 2>/dev/null | grep -qx "Verdict: PASS"'
|
|
398
402
|
- from: validate
|
|
399
403
|
to: correct
|
|
400
404
|
description: Validation FAIL under the shared two-pass correction cap.
|
|
401
405
|
guard:
|
|
402
406
|
kind: shell
|
|
403
407
|
options:
|
|
404
|
-
command: '!
|
|
408
|
+
command: '! tail -n 1 .spur/run/$__runId-validation.txt 2>/dev/null | grep -qx "Verdict: PASS" && test "$(cat .spur/run/$__runId-correction-count 2>/dev/null || echo 0)" -lt 2'
|
|
405
409
|
- from: validate
|
|
406
410
|
to: failed
|
|
407
411
|
description: Validation FAIL with the correction cap exhausted — terminate without publishing.
|