@gobing-ai/spur 0.3.73 → 0.3.75
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 +117 -55
- package/config/workflows/feature-dev.yaml +185 -121
- package/config/workflows/feature-lifecycle.yaml +1 -0
- package/config/workflows/history-anatomy.yaml +8 -4
- package/config/workflows/idea-pipeline.yaml +123 -43
- package/config/workflows/pr-review.yaml +31 -8
- package/config/workflows/task-lifecycle.yaml +1 -0
- package/config/workflows/task-pipeline.yaml +965 -905
- package/config/workflows/wayfinder-resolution.yaml +124 -90
- package/config/workflows/wrapup-pipeline.yaml +304 -107
- package/package.json +1 -1
- package/plugins/sp/agents/expert-spur.md +7 -4
- package/plugins/sp/commands/dev-idea.md +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 +4 -2
- 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/cross-cutting.md +23 -8
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +1 -1
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +3 -3
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +5 -3
- package/plugins/sp/skills/wayfinder/SKILL.md +1 -1
- package/spur.js +2999 -1010
- package/web/_astro/{BoardApp.BYCNkMOn.js → BoardApp.BOW1815F.js} +101 -100
- package/web/_astro/BoardApp.C4zimv1U.js +1 -0
- package/web/_astro/{TaskDetail.CgUreSP2.js → TaskDetail.CX6C7dSJ.js} +1 -1
- package/web/_astro/{arc.BySSh34M.js → arc.CwSvH1ji.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.DM46TS_h.js → architectureDiagram-3BPJPVTR.Dxne1RvP.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.tZhvNUHA.js → blockDiagram-GPEHLZMM.D9Fb14rC.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.PT4Or4Nf.js → c4Diagram-AAUBKEIU.DmvWSFvv.js} +1 -1
- package/web/_astro/channel.CQHdDVp9.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.J9r0_Bbe.js → chunk-2J33WTMH.BCCktIrE.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.hzyeIvhR.js → chunk-4BX2VUAB.BzCk9q27.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.B0rO7qVh.js → chunk-55IACEB6.CZXVgTk4.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.wE_Uk5D4.js → chunk-727SXJPM.CJL8UIpX.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.DqEEjQw7.js → chunk-AQP2D5EJ.Dz8MDEdw.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.CDoD9sBX.js → chunk-FMBD7UC4.CkQeYYUw.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CtX5nF9P.js → chunk-ND2GUHAM.KiC1QgzH.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.CK_EwfaT.js → chunk-QZHKN3VN.AJ08mw2e.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.DLt5a8Lh.js → classDiagram-4FO5ZUOK.DRWRDKzK.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.DLt5a8Lh.js → classDiagram-v2-Q7XG4LA2.DRWRDKzK.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CMCWP49h.js → cose-bilkent-S5V4N54A.CavydfLP.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.HyXw_vdS.js → cynefin-OW5HDTMX.D_7o_a0B.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.BTuAzh01.js → dagre-BM42HDAG.LWk2dKgg.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.D9dr9wfT.js → diagram-2AECGRRQ.82lbq6aB.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.C4Rot0hj.js → diagram-5GNKFQAL.hyNL1pwY.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.B_TK5uWC.js → diagram-KO2AKTUF.BaLqVf-b.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.JkXKK7CO.js → diagram-LMA3HP47.DQJxj0oz.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.BzMN8Bd6.js → diagram-OG6HWLK6.DhlL8cG2.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DVZaWGUd.js → erDiagram-TEJ5UH35.HoTnXwkF.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.rjEiWUfR.js → flowDiagram-I6XJVG4X.DkFKlZIZ.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.C_EgAarK.js → ganttDiagram-6RSMTGT7.9qPfOTDb.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.B-QQSDsK.js → gitGraphDiagram-PVQCEYII.B4G18Dwc.js} +1 -1
- package/web/_astro/index.Dcr_8fiK.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.DlWesz7T.js → infoDiagram-5YYISTIA.e3KJkXAM.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.BUMZOawi.js → ishikawaDiagram-YF4QCWOH.CY3yddhD.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.CWfkxfjY.js → journeyDiagram-JHISSGLW.DaAKIO1t.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.B-YpMwXf.js → kanban-definition-UN3LZRKU.DGkDddtc.js} +1 -1
- package/web/_astro/{linear.D7uqzENp.js → linear.DnDPcpd1.js} +1 -1
- package/web/_astro/{mermaid.core.CxrNppBD.js → mermaid.core.1uBmxa9t.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.B4Qe7cM2.js → mindmap-definition-RKZ34NQL.XFJVayxw.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.Ds-5j2ro.js → pieDiagram-4H26LBE5.BXm2OgHh.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.tBd38uNC.js → quadrantDiagram-W4KKPZXB.DgB2p5fc.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.sFENkWl3.js → requirementDiagram-4Y6WPE33.jBR39bnS.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.BeB-Hk7C.js → sankeyDiagram-5OEKKPKP.N3u9OhE3.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.DnTeaSpx.js → sequenceDiagram-3UESZ5HK.CZhqZXNL.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.B-8Jt5EJ.js → stateDiagram-AJRCARHV.DlNu1VEa.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.Br7xoqMW.js → stateDiagram-v2-BHNVJYJU.BEqi8NQV.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.C-3WdOyi.js → timeline-definition-PNZ67QCA.BPcexclc.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DCIs7Lc6.js → vennDiagram-CIIHVFJN.BZalxKGQ.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.rGAL-bbz.js → wardleyDiagram-YWT4CUSO.BqOljod9.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.hkfQKiRl.js → xychartDiagram-2RQKCTM6.tkO4ppN5.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
- package/web/_astro/index.B5MTfe7k.css +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: "2"
|
|
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,19 @@ 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: ""
|
|
46
|
+
# 0785 R2: linked feature spec path, resolved at verify entry. Empty (orphan task) means the
|
|
47
|
+
# feature spec is legitimately omitted from the digest inputs (empty-string compatibility);
|
|
48
|
+
# a declared feature whose path fails to resolve fails closed.
|
|
49
|
+
featureSpecPath: ""
|
|
43
50
|
__hitlAnswer: ""
|
|
51
|
+
# R8 (0366): injected by WorkflowAppService.run(); run-scopes every temporary capture.
|
|
52
|
+
__runId: ""
|
|
44
53
|
|
|
45
54
|
states:
|
|
46
55
|
- id: precheck
|
|
@@ -49,14 +58,16 @@ states:
|
|
|
49
58
|
(D5-J, ADR-069). Both gates run `softFail: true`, so a red probe records FAIL and lets
|
|
50
59
|
the transitions route to `failed` instead of aborting the run — the shipped action
|
|
51
60
|
schema exposes no `onError`, so soft mode is what preserves that routing.
|
|
52
|
-
The canonical `.spur/run/$
|
|
61
|
+
The canonical `.spur/run/$__runId-docs-precheck.status` is the AND of the two gate files.
|
|
62
|
+
(0769: temporary captures are run-scoped — `.spur/run/<runId>-docs-*` — so concurrent
|
|
63
|
+
runs on one task never share or clobber a capture.)
|
|
53
64
|
onEnter:
|
|
54
65
|
- kind: command.gate
|
|
55
66
|
options:
|
|
56
67
|
id: docs-precheck-task
|
|
57
68
|
executable: "${vars.spurBin}"
|
|
58
69
|
args: ["task", "check", "${vars.wbs}"]
|
|
59
|
-
resultFile: .spur/run/${vars.
|
|
70
|
+
resultFile: .spur/run/${vars.__runId}-docs-precheck-task.status
|
|
60
71
|
softFail: true
|
|
61
72
|
timeoutMs: 120000
|
|
62
73
|
- kind: command.gate
|
|
@@ -64,16 +75,16 @@ states:
|
|
|
64
75
|
id: docs-precheck-agent
|
|
65
76
|
executable: "${vars.spurBin}"
|
|
66
77
|
args: ["agent", "doctor", "${vars.agent}"]
|
|
67
|
-
resultFile: .spur/run/${vars.
|
|
78
|
+
resultFile: .spur/run/${vars.__runId}-docs-precheck-agent.status
|
|
68
79
|
softFail: true
|
|
69
80
|
timeoutMs: 120000
|
|
70
81
|
- kind: shell
|
|
71
82
|
options:
|
|
72
83
|
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/$
|
|
84
|
+
if test "$(cat .spur/run/$__runId-docs-precheck-task.status 2>/dev/null)" = PASS &&
|
|
85
|
+
test "$(cat .spur/run/$__runId-docs-precheck-agent.status 2>/dev/null)" = PASS;
|
|
86
|
+
then printf 'PASS\n' > ".spur/run/$__runId-docs-precheck.status";
|
|
87
|
+
else printf 'FAIL\n' > ".spur/run/$__runId-docs-precheck.status"; fi
|
|
77
88
|
- kind: note
|
|
78
89
|
options:
|
|
79
90
|
message: "Docs pipeline start for task ${vars.wbs}."
|
|
@@ -108,36 +119,21 @@ states:
|
|
|
108
119
|
options:
|
|
109
120
|
prompt: "Approve docs-only deliverable for task ${vars.wbs}?"
|
|
110
121
|
|
|
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
122
|
- id: verify
|
|
134
123
|
description: >
|
|
135
124
|
Read-only measured verification (task 0704, R2/R4/R7): dispatch /sp:dev-verify --fix none
|
|
136
125
|
with an answer file, derive the ONE standard verdict via `spur task verdict`, register the
|
|
137
126
|
standard verify-verdict artifact, and bracket the verifier with proof-input digest capture/compare so any
|
|
138
127
|
task-spec or document mutation during certification fails closed (R4). No docs assurance
|
|
139
|
-
subclass — PASS semantics are identical to task-pipeline (R7).
|
|
128
|
+
subclass — PASS semantics are identical to task-pipeline (R7). 0769: verification now
|
|
129
|
+
PRECEDES recording; the `verify → record` guard compares the proof bracket, and the
|
|
130
|
+
verdict artifact keeps its `.spur/run/<wbs>-verdict.json` compatibility path with
|
|
131
|
+
runId + definitionDigest stamped through the existing proof/run-artifact contract.
|
|
140
132
|
onEnter:
|
|
133
|
+
# 0769: clear any stale current-run answer before the fresh-session verifier writes it.
|
|
134
|
+
- kind: shell
|
|
135
|
+
options:
|
|
136
|
+
command: "mkdir -p .spur/run && rm -f .spur/run/$__runId-docs-verify-answer.txt"
|
|
141
137
|
# R4 (0703 R6 precedent): resolve the task-spec path BEFORE capture. `docs/tasks*` is
|
|
142
138
|
# excluded from the digest's git-tree half, so the spec is folded in via `taskFile`.
|
|
143
139
|
- kind: shell
|
|
@@ -147,22 +143,42 @@ states:
|
|
|
147
143
|
# wbs exits non-zero with a named message. The resolved path folds
|
|
148
144
|
# into the proof digest via `taskFile:` below; a silent miss would
|
|
149
145
|
# degrade the docs-pipeline proof to tree-only (same hazard 0751 R2
|
|
150
|
-
# removed from task-pipeline).
|
|
146
|
+
# removed from task-pipeline). (0769: run-scoped capture path.)
|
|
151
147
|
command: >-
|
|
152
148
|
set -e;
|
|
153
149
|
task_path="$($spurBin task path $wbs --json | jq -r '.path // .filePath // empty')";
|
|
154
150
|
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/$
|
|
151
|
+
printf '%s' "$task_path" > ".spur/run/$__runId-docs-taskpath.txt"
|
|
156
152
|
- kind: file.read.into-var
|
|
157
153
|
options:
|
|
158
|
-
path: .spur/run/${vars.
|
|
154
|
+
path: .spur/run/${vars.__runId}-docs-taskpath.txt
|
|
159
155
|
var: taskSpecPath
|
|
156
|
+
# 0785 R2: resolve the linked feature spec path so the digest covers it too. An orphan task
|
|
157
|
+
# (no feature_id) resolves to empty — legitimately omitted via empty-string compatibility;
|
|
158
|
+
# a declared feature whose spec path does not resolve fails closed instead of silently
|
|
159
|
+
# folding a stale spec into the proof.
|
|
160
|
+
- kind: shell
|
|
161
|
+
options:
|
|
162
|
+
command: >-
|
|
163
|
+
set -e;
|
|
164
|
+
FID="$($spurBin task show $wbs --json 2>/dev/null | jq -r '.feature_id // .frontmatter.feature_id // empty' 2>/dev/null)";
|
|
165
|
+
FPATH_OUT="";
|
|
166
|
+
if [ -n "$FID" ]; then
|
|
167
|
+
FPATH_OUT="$($spurBin feature show "$FID" --json | jq -r '.filePath // .path // empty')";
|
|
168
|
+
if [ -z "$FPATH_OUT" ]; then echo "docs-pipeline: feature $FID linked to task $wbs but its spec path did not resolve" >&2; exit 1; fi;
|
|
169
|
+
fi;
|
|
170
|
+
printf '%s' "$FPATH_OUT" > ".spur/run/$__runId-docs-featurepath.txt"
|
|
171
|
+
- kind: file.read.into-var
|
|
172
|
+
options:
|
|
173
|
+
path: .spur/run/${vars.__runId}-docs-featurepath.txt
|
|
174
|
+
var: featureSpecPath
|
|
160
175
|
# R4: canonical capture BEFORE the verifier runs. Same fingerprint input as the
|
|
161
176
|
# re-capture below so the bracket compares like for like.
|
|
162
177
|
- kind: proof.fingerprint
|
|
163
178
|
options:
|
|
164
179
|
var: proofDigest
|
|
165
180
|
taskFile: ${vars.taskSpecPath}
|
|
181
|
+
featureFile: ${vars.featureSpecPath}
|
|
166
182
|
input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
|
|
167
183
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
168
184
|
- kind: agent.run
|
|
@@ -174,19 +190,19 @@ states:
|
|
|
174
190
|
input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
|
|
175
191
|
role: reviewer
|
|
176
192
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
177
|
-
answerFile: .spur/run/${vars.
|
|
193
|
+
answerFile: .spur/run/${vars.__runId}-docs-verify-answer.txt
|
|
178
194
|
- kind: shell
|
|
179
195
|
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 ->
|
|
196
|
+
command: "$spurBin task verdict $wbs --from-answer .spur/run/$__runId-docs-verify-answer.txt"
|
|
197
|
+
# R7: stamp the proof block + run identity into the standard verdict artifact, then register
|
|
198
|
+
# it. Soft action + hard guard: a missing/malformed stamp fails the `verify -> record`
|
|
183
199
|
# guard below, not this step.
|
|
184
200
|
- kind: shell
|
|
185
201
|
options:
|
|
186
202
|
command: >-
|
|
187
203
|
V=".spur/run/$wbs-verdict.json";
|
|
188
204
|
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";
|
|
205
|
+
jq --arg d "$proofDigest" --arg r "$__runId" '. + {proof: {digest: $d, capturePoint: "docs-verify-entry", runId: $r}}' "$V" > "$V.tmp" && mv "$V.tmp" "$V";
|
|
190
206
|
fi;
|
|
191
207
|
exit 0
|
|
192
208
|
- kind: run.artifact
|
|
@@ -199,9 +215,41 @@ states:
|
|
|
199
215
|
options:
|
|
200
216
|
var: proofDigestNow
|
|
201
217
|
taskFile: ${vars.taskSpecPath}
|
|
218
|
+
featureFile: ${vars.featureSpecPath}
|
|
202
219
|
input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
|
|
203
220
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
204
221
|
|
|
222
|
+
- id: record
|
|
223
|
+
description: >
|
|
224
|
+
Record the docs-only outcome AFTER measured verification (task 0769 ordering:
|
|
225
|
+
draft/approval → verify → record → done — the pre-verification record could write
|
|
226
|
+
UNKNOWN/old Testing evidence). The verdict is already derived and proof-bracketed in
|
|
227
|
+
`verify`; `verify → record` only opens on measured PASS with an intact bracket. The
|
|
228
|
+
task record verb backfills Solution from the diff and moves the task to testing; its
|
|
229
|
+
result is captured to a run-scoped status file so a record denial reaches `failed`
|
|
230
|
+
(record → failed) and is never converted to success by an exit 0.
|
|
231
|
+
onEnter:
|
|
232
|
+
- kind: shell
|
|
233
|
+
options:
|
|
234
|
+
command: >-
|
|
235
|
+
if $spurBin task record $wbs --solution-from-diff --transition testing; then
|
|
236
|
+
printf 'PASS\n' > ".spur/run/$__runId-docs-record.status";
|
|
237
|
+
else
|
|
238
|
+
printf 'FAIL\n' > ".spur/run/$__runId-docs-record.status";
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
- id: done
|
|
242
|
+
description: Terminal — docs deliverable measured, reviewed, and recorded.
|
|
243
|
+
onEnter:
|
|
244
|
+
# R1 (0704): no synthetic verdict writer. The verdict artifact is produced by measured
|
|
245
|
+
# verification in `verify` and registered there; done only performs the guarded
|
|
246
|
+
# transition. Override path remains: --force-done --reason.
|
|
247
|
+
- kind: shell
|
|
248
|
+
options:
|
|
249
|
+
command: "$spurBin task update $wbs done --no-lifecycle"
|
|
250
|
+
- kind: note
|
|
251
|
+
options:
|
|
252
|
+
message: "Docs pipeline complete for task ${vars.wbs}."
|
|
205
253
|
- id: failed
|
|
206
254
|
description: Terminal — docs pipeline failed or was rejected.
|
|
207
255
|
|
|
@@ -223,8 +271,8 @@ transitions:
|
|
|
223
271
|
kind: always
|
|
224
272
|
|
|
225
273
|
- from: draft
|
|
226
|
-
to:
|
|
227
|
-
description: profile=auto — skip the docs-review HITL gate.
|
|
274
|
+
to: verify
|
|
275
|
+
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
276
|
guard:
|
|
229
277
|
kind: shell
|
|
230
278
|
options:
|
|
@@ -236,8 +284,8 @@ transitions:
|
|
|
236
284
|
kind: always
|
|
237
285
|
|
|
238
286
|
- from: docs-review
|
|
239
|
-
to:
|
|
240
|
-
description: Docs approved —
|
|
287
|
+
to: verify
|
|
288
|
+
description: "Docs approved — measure the deliverable (0769: verification precedes recording)."
|
|
241
289
|
guard:
|
|
242
290
|
kind: shell
|
|
243
291
|
options:
|
|
@@ -257,16 +305,11 @@ transitions:
|
|
|
257
305
|
options:
|
|
258
306
|
command: 'test "$__hitlAnswer" = cancel'
|
|
259
307
|
|
|
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
308
|
- from: verify
|
|
268
|
-
to:
|
|
269
|
-
description: Measured PASS with the proof bracket intact (R4/R5)
|
|
309
|
+
to: record
|
|
310
|
+
description: Measured PASS with the proof bracket intact (R4/R5) — record only verified
|
|
311
|
+
outcomes (0769). Structural task-check gates remain at precheck, record (wip→testing),
|
|
312
|
+
and done (verdict-artifact guard, R3).
|
|
270
313
|
guard:
|
|
271
314
|
kind: shell
|
|
272
315
|
options:
|
|
@@ -284,6 +327,25 @@ transitions:
|
|
|
284
327
|
- from: verify
|
|
285
328
|
to: failed
|
|
286
329
|
description: Non-PASS verdict, missing/malformed answer, or digest mismatch (R5) — the run
|
|
287
|
-
reaches failed and
|
|
330
|
+
reaches failed and nothing is recorded.
|
|
331
|
+
guard:
|
|
332
|
+
kind: always
|
|
333
|
+
|
|
334
|
+
- from: record
|
|
335
|
+
to: done
|
|
336
|
+
description: Recorded from a verified outcome; the persisted verdict/bracket is re-asserted
|
|
337
|
+
so a failed `task record` (captured FAIL) never converts to done (0769).
|
|
338
|
+
guard:
|
|
339
|
+
kind: shell
|
|
340
|
+
options:
|
|
341
|
+
command: >-
|
|
342
|
+
test "$(cat .spur/run/$__runId-docs-record.status 2>/dev/null)" = PASS &&
|
|
343
|
+
test -f ".spur/run/$wbs-verdict.json" &&
|
|
344
|
+
test "$(jq -r '.verdict // empty' .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS &&
|
|
345
|
+
test -n "$proofDigest" &&
|
|
346
|
+
test "$(jq -r '.proof.digest // empty' .spur/run/$wbs-verdict.json 2>/dev/null)" = "$proofDigest"
|
|
347
|
+
- from: record
|
|
348
|
+
to: failed
|
|
349
|
+
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
350
|
guard:
|
|
289
351
|
kind: always
|