@gobing-ai/spur 0.3.94 → 0.3.95
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/README.md +42 -0
- package/board/index.d.ts +38 -0
- package/config/plugin-scripts.json +5 -0
- package/config/workflows/feature-verification.yaml +7 -4
- package/config/workflows/idea-pipeline.yaml +10 -4
- package/config/workflows/task-pipeline.yaml +54 -26
- package/config/workflows/wrapup-pipeline.yaml +92 -17
- package/package.json +15 -11
- package/plugins/sp/commands/dev-verify.md +7 -4
- package/plugins/sp/commands/dev-verifyall.md +4 -3
- package/plugins/sp/commands/dev-wrap.md +1 -1
- package/plugins/sp/hooks/context-post-tool.ts +2 -2
- package/plugins/sp/hooks/context-session-start.ts +2 -1
- package/plugins/sp/hooks/context-session-stop.ts +22 -14
- package/plugins/sp/hooks/pi/guard-extension.ts +109 -150
- package/plugins/sp/lib/idea-handoff.generated.mjs +2 -2
- package/plugins/sp/lib/inline-run.generated.d.mts +2 -2
- package/plugins/sp/lib/inline-run.generated.mjs +10 -10
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +3 -3
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +3 -3
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +2 -0
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +1 -0
- package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +9 -7
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +8 -7
- package/plugins/sp/scripts/feature-sync-bounded.mjs +5 -2
- package/plugins/sp/scripts/feature-sync-bounded.ts +3 -1
- package/plugins/sp/scripts/feature-verification-steps.ts +6 -6
- package/plugins/sp/scripts/history-anatomy-cache.mjs +3 -3
- package/plugins/sp/scripts/history-anatomy-cache.ts +4 -4
- package/plugins/sp/scripts/inline-run-setup.mjs +23 -13
- package/plugins/sp/scripts/inline-run-setup.ts +60 -27
- package/plugins/sp/scripts/pr-reviewing.mjs +2 -0
- package/plugins/sp/scripts/pr-reviewing.ts +1 -0
- package/plugins/sp/scripts/quality-gate.mjs +4 -2
- package/plugins/sp/scripts/quality-gate.ts +8 -2
- package/plugins/sp/scripts/residual-scan.mjs +3 -3
- package/plugins/sp/scripts/residual-scan.ts +3 -3
- package/plugins/sp/scripts/script-contract-check.ts +175 -46
- package/plugins/sp/scripts/script-root.mjs +125 -0
- package/plugins/sp/scripts/script-root.ts +195 -0
- package/plugins/sp/scripts/stage-registry-adapter.ts +1 -1
- package/plugins/sp/scripts/task-evidence-precheck.ts +4 -2
- package/plugins/sp/scripts/task-size-precheck.ts +3 -1
- package/plugins/sp/scripts/validate-commands.ts +12 -12
- package/plugins/sp/scripts/validate-flag-contracts.ts +42 -30
- package/plugins/sp/scripts/verify-answer-lint.ts +3 -1
- package/plugins/sp/scripts/workflow-step-profile.mjs +5 -2
- package/plugins/sp/scripts/workflow-step-profile.ts +3 -1
- package/plugins/sp/scripts/wrapup-drift-probe.mjs +5 -2
- package/plugins/sp/scripts/wrapup-drift-probe.ts +4 -2
- package/plugins/sp/scripts/wrapup-steps.mjs +32 -8
- package/plugins/sp/scripts/wrapup-steps.ts +56 -10
- package/plugins/sp/skills/code-verification/SKILL.md +12 -7
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +11 -0
- package/plugins/sp/skills/functional-review/SKILL.md +1 -1
- package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +9 -1
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +30 -10
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +6 -3
- package/plugins/sp/tsconfig.json +8 -0
- package/spur.js +5194 -4457
- package/web/_astro/{BoardApp.FTEs3-N8.js → BoardApp.BxJuwD7I.js} +150 -153
- package/web/_astro/BoardApp.Cpxntzad.js +1 -0
- package/web/_astro/TaskDetail.C5bW4WGV.js +1 -0
- package/web/_astro/_commonjsHelpers.CqkleIqs.js +1 -0
- package/web/_astro/{arc.uuAf51IT.js → arc.CyjRvNMY.js} +1 -1
- package/web/_astro/architectureDiagram-3BPJPVTR.B4lWRzJA.js +36 -0
- package/web/_astro/{blockDiagram-GPEHLZMM.D1mGCq3p.js → blockDiagram-GPEHLZMM.Be38USQ2.js} +1 -1
- package/web/_astro/board-facade-react-dom-client.B2U5wMvk.js +1 -0
- package/web/_astro/board-facade-react-dom.Cd2MuMhF.js +1 -0
- package/web/_astro/board-facade-react-jsx-dev-runtime.B_L3JzfC.js +1 -0
- package/web/_astro/board-facade-react-jsx-runtime.BY2yfHRi.js +1 -0
- package/web/_astro/board-facade-react-router-dom.Dy5pjzOw.js +1 -0
- package/web/_astro/board-facade-react-router.DjjqU27_.js +1 -0
- package/web/_astro/board-facade-react.Dgf4GRyj.js +1 -0
- package/web/_astro/{c4Diagram-AAUBKEIU.CMsolcde.js → c4Diagram-AAUBKEIU.DT9Fj5Qx.js} +1 -1
- package/web/_astro/channel.CI6N_tCg.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.CrGA3fik.js → chunk-2J33WTMH.SeSBWLg5.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.DsLVVla0.js → chunk-4BX2VUAB.DoO4VE14.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.Dxc59Tfi.js → chunk-55IACEB6.DrmTFA53.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.CaEVE2Wy.js → chunk-727SXJPM.Bi-TUb_V.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.BiJ4HXeI.js → chunk-AQP2D5EJ.B-xp8Uhi.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.Mxf1fru5.js → chunk-FMBD7UC4.DGWrDnUU.js} +1 -1
- package/web/_astro/chunk-JMJ3UQ3L.BQJEJHu4.js +34 -0
- package/web/_astro/{chunk-ND2GUHAM.pyOWQixH.js → chunk-ND2GUHAM._BagvPDy.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BmEsg4vr.js → chunk-QZHKN3VN.VOboYWQ0.js} +1 -1
- package/web/_astro/chunk-YNUBSHFH.CxeAygfi.js +7 -0
- package/web/_astro/{classDiagram-4FO5ZUOK.BHhhMFTO.js → classDiagram-4FO5ZUOK.D_apfHS7.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.BHhhMFTO.js → classDiagram-v2-Q7XG4LA2.D_apfHS7.js} +1 -1
- package/web/_astro/client.BhluLQqe.js +1 -0
- package/web/_astro/client.DBpSRLnx.js +9 -0
- package/web/_astro/cose-bilkent-S5V4N54A.DNLU_L-x.js +1 -0
- package/web/_astro/{cynefin-OW5HDTMX.C2j1_lKL.js → cynefin-OW5HDTMX.D8borhV-.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.hZ2NCTdT.js → dagre-BM42HDAG.Uc0lvjcV.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.Bfw5_EzK.js → diagram-2AECGRRQ.DDIxtDBo.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.Bt1V_Tmk.js → diagram-5GNKFQAL.DVoDnD3H.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.DEk-YFwp.js → diagram-KO2AKTUF.CRubTJ-0.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.CDjndtQm.js → diagram-LMA3HP47.m9SeYcXQ.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.cFnUHScG.js → diagram-OG6HWLK6.C6s2ZjV5.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DlhYp7NV.js → erDiagram-TEJ5UH35.nSzr5KTj.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.DNTpsxfx.js → flowDiagram-I6XJVG4X.DrZcys16.js} +1 -1
- package/web/_astro/ganttDiagram-6RSMTGT7.Do4M1b-K.js +292 -0
- package/web/_astro/{gitGraphDiagram-PVQCEYII.DkEqNI0P.js → gitGraphDiagram-PVQCEYII.BWc9oJ4l.js} +1 -1
- package/web/_astro/index.5dn-Zm-2.js +1 -0
- package/web/_astro/index.C-IqPpW2.js +1 -0
- package/web/_astro/index.CENnIEqT.css +1 -0
- package/web/_astro/index.Cyc_GA4f.js +1 -0
- package/web/_astro/index.tZfqwSut.js +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.CrjioCTG.js → infoDiagram-5YYISTIA.BIdOctFk.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.BcK0CN8n.js → ishikawaDiagram-YF4QCWOH.CV5SuG2t.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.p0CbBDX1.js → journeyDiagram-JHISSGLW.CxE-rEJ-.js} +1 -1
- package/web/_astro/jsx-runtime.DWOiEOII.js +1 -0
- package/web/_astro/{kanban-definition-UN3LZRKU.puHIFt6J.js → kanban-definition-UN3LZRKU.BPRdKWs_.js} +1 -1
- package/web/_astro/{linear.Bb-3a1d7.js → linear.zRsuuDTE.js} +1 -1
- package/web/_astro/{mermaid.core.CJDgXOJs.js → mermaid.core.jAJTcMKc.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.BoAZEI9t.js → mindmap-definition-RKZ34NQL.BffJxfCr.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.CJNSdqY7.js → pieDiagram-4H26LBE5.CacwWaE3.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.DtTy7_0Z.js → quadrantDiagram-W4KKPZXB.hXELD06-.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.BNYV98Xg.js → requirementDiagram-4Y6WPE33.DdEbPcqT.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.DRq9DGHp.js → sankeyDiagram-5OEKKPKP.DgaDocKv.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.B7KdBFCm.js → sequenceDiagram-3UESZ5HK.B0KScnAu.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.CD62ZJ2H.js → stateDiagram-AJRCARHV.CV9M_WNc.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.CeVk1TAj.js → stateDiagram-v2-BHNVJYJU.BOAo74Et.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.C_ZPA5tT.js → timeline-definition-PNZ67QCA.CqqepUMe.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.CrThO_FQ.js → vennDiagram-CIIHVFJN.DDqe4dOG.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.DSZCA5nl.js → wardleyDiagram-YWT4CUSO.B3R9OPdO.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.KI7baTuk.js → xychartDiagram-2RQKCTM6.B3SvgXpQ.js} +1 -1
- package/web/board-runtime.json +69 -0
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.C02hAHPO.js +0 -1
- package/web/_astro/TaskDetail.C-GdsS-t.js +0 -1
- package/web/_astro/architectureDiagram-3BPJPVTR.CGe629A1.js +0 -36
- package/web/_astro/channel.fsgl7o5j.js +0 -1
- package/web/_astro/client.yhYJvxCU.js +0 -9
- package/web/_astro/cose-bilkent-S5V4N54A.2fH4YOlp.js +0 -1
- package/web/_astro/ganttDiagram-6RSMTGT7.DC_p36PI.js +0 -292
- package/web/_astro/index.De90oHcH.js +0 -1
- package/web/_astro/index.Hjbr15fG.css +0 -1
package/README.md
CHANGED
|
@@ -59,6 +59,21 @@ If `~/.local/bin` isn't already on your `PATH`, add it (e.g. `export PATH="$HOME
|
|
|
59
59
|
in your shell profile). Supported targets: `darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`.
|
|
60
60
|
Windows: use the Bun path under WSL.
|
|
61
61
|
|
|
62
|
+
**Verification.** The installer downloads to a temp file, checks it against the release's
|
|
63
|
+
`SHA256SUMS`, and only then atomically replaces `spur`. A failed download, a checksum mismatch, or a
|
|
64
|
+
missing `SHA256SUMS` leaves an existing install untouched and exits non-zero. `SPUR_RELEASE_URL`
|
|
65
|
+
overrides the download base URL (a mirror, or a `file://` directory in tests).
|
|
66
|
+
|
|
67
|
+
The checksum is a **code-execution** boundary, not just an integrity check: having verified the
|
|
68
|
+
download, the installer *runs* it (`spur init`), so a release whose `SHA256SUMS` cannot be verified
|
|
69
|
+
is a release you cannot safely install. `SPUR_SKIP_VERIFY=1` is the single explicit bypass and
|
|
70
|
+
prints a warning — keep it for local or air-gapped installs, and pipe the script into `sh` only from
|
|
71
|
+
a source you trust.
|
|
72
|
+
|
|
73
|
+
**Releasing standalone binaries.** Run `bun run build:binaries` in `apps/cli`, then upload **all**
|
|
74
|
+
of `dist/cli/spur-*` **and** `dist/cli/SHA256SUMS` to the GitHub Release for the tag. A release
|
|
75
|
+
without `SHA256SUMS` makes the installer fail by default.
|
|
76
|
+
|
|
62
77
|
### Package layout (what ships)
|
|
63
78
|
|
|
64
79
|
The published tarball is a self-contained Bun bundle plus static assets:
|
|
@@ -98,6 +113,33 @@ spur status
|
|
|
98
113
|
|
|
99
114
|
Every command supports `--json` for machine-readable output.
|
|
100
115
|
|
|
116
|
+
### Extending the Spur Board
|
|
117
|
+
|
|
118
|
+
A project can add its own Board modules — a compiled React tool or an embedded URL app — without
|
|
119
|
+
editing this package. An installed Board reads them from a fresh project's `.spur/config.yaml`:
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
bootstrap:
|
|
123
|
+
modules:
|
|
124
|
+
- id: team-board
|
|
125
|
+
name: Team board
|
|
126
|
+
icon: "🧭"
|
|
127
|
+
type: react
|
|
128
|
+
directory: board/team-board/dist
|
|
129
|
+
entry: index.js
|
|
130
|
+
styles: [index.css]
|
|
131
|
+
- id: docs
|
|
132
|
+
name: Documentation
|
|
133
|
+
icon: "📚"
|
|
134
|
+
type: iframe
|
|
135
|
+
url: https://docs.example.test/
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`spur init` seeds `modules: []` (built-ins only); change selection with a config edit, then restart
|
|
139
|
+
`spur serve` and reload. The full authoring contract — the declaration union, the
|
|
140
|
+
`@gobing-ai/spur/board` type export, the Vite library setup and the frame/trust limits — is in the
|
|
141
|
+
[downstream Board modules design](https://github.com/gobing-ai/spur/blob/main/docs/design/downstream-board-modules.md).
|
|
142
|
+
|
|
101
143
|
## Documentation
|
|
102
144
|
|
|
103
145
|
Full docs, architecture, and the complete command surface live in the
|
package/board/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Generated by scripts/commands/emit-board-types.ts from
|
|
2
|
+
// apps/web/src/modules/contribution.ts — edit the authoring source, then regenerate.
|
|
3
|
+
import type { ComponentType } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Public authoring contract for a native (compiled React) Board module contribution
|
|
6
|
+
* (A8 / task 0988 R1).
|
|
7
|
+
*
|
|
8
|
+
* This file is the ONE authoring source for the declaration-only `@gobing-ai/spur/board`
|
|
9
|
+
* package export: `scripts/commands/emit-board-types.ts` emits `apps/cli/board/index.d.ts`
|
|
10
|
+
* from it, so the published ABI cannot drift from the Board's own types. Keep it
|
|
11
|
+
* type-only — no React *value* import may reach the CLI or plugin artifacts (the CLI
|
|
12
|
+
* ships no React; the contributor supplies compatible React types through its own
|
|
13
|
+
* devDependencies).
|
|
14
|
+
*
|
|
15
|
+
* Module metadata (id/name/icon/route) is deliberately absent: it is project
|
|
16
|
+
* configuration (one selection authority), while this shape carries only what the
|
|
17
|
+
* renderer needs to mount a contribution.
|
|
18
|
+
*/
|
|
19
|
+
export interface BoardModuleContribution {
|
|
20
|
+
/** Contribution protocol version this Board accepts. */
|
|
21
|
+
readonly apiVersion: 1;
|
|
22
|
+
/**
|
|
23
|
+
* Workspace component. Rendered inside the Board's React tree with the Board's own
|
|
24
|
+
* React instance — it must not call `createRoot`, and no private Board context is
|
|
25
|
+
* exported to it.
|
|
26
|
+
*/
|
|
27
|
+
readonly component: ComponentType;
|
|
28
|
+
/** Optional companion the Board's right panel renders while this module is active. */
|
|
29
|
+
readonly rightPanelComponent?: ComponentType;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The named export a native Board module entry must publish.
|
|
33
|
+
*
|
|
34
|
+
* Declared rather than implemented: `@gobing-ai/spur/board` is a declaration-only export,
|
|
35
|
+
* not a runtime SDK (consumers import its types; their compiled ESM entry exports this
|
|
36
|
+
* name for the renderer).
|
|
37
|
+
*/
|
|
38
|
+
export declare const webModule: BoardModuleContribution;
|
|
@@ -50,13 +50,16 @@ states:
|
|
|
50
50
|
digest, run identity) and the coarse status file, always exit 0 so the
|
|
51
51
|
transition guard routes missing/corrupt/FAIL to `failed`.
|
|
52
52
|
onEnter:
|
|
53
|
+
# 0960 R2: run-start script-resolution identity — record which tree this run
|
|
54
|
+
# resolved (source-repo vs installed) before the verification step runs. Never aborts.
|
|
53
55
|
- kind: shell
|
|
54
56
|
options:
|
|
55
57
|
command: >-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
S=plugins/sp/scripts/script-root.ts; [ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp script-root.mjs 2>/dev/null)"; RUNNER=bun; case "$S" in *.mjs) RUNNER=node ;; esac; [ -f "$S" ] && "$RUNNER" "$S" --run-id "$__runId" --spur-bin "$spurBin" || echo "script-root failed closed — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; exit 0
|
|
59
|
+
- kind: shell
|
|
60
|
+
options:
|
|
61
|
+
command: >-
|
|
62
|
+
mkdir -p .spur/run; S=plugins/sp/scripts/feature-verification-steps.ts; [ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp feature-verification-steps.mjs 2>/dev/null)"; RUNNER=bun; case "$S" in *.mjs) RUNNER=node ;; esac; [ -f "$S" ] && "$RUNNER" "$S" verify --feature-id "$featureId" --run-id "$__runId" --spur-bin "$spurBin" || printf 'FAIL feature-verification failed closed — script not found — run superskill install sp --marketplace gobing-ai/spur\n' > ".spur/run/$__runId-feature-verification.status"; exit 0
|
|
60
63
|
|
|
61
64
|
- id: done
|
|
62
65
|
description: Terminal — repo-wide checks passed and the receipt is bound.
|
|
@@ -84,6 +84,12 @@ states:
|
|
|
84
84
|
handoff — no task execution. Soft agent doctor (status file) so doctor red
|
|
85
85
|
routes to `failed` via transitions instead of a raw lifecycle abort.
|
|
86
86
|
onEnter:
|
|
87
|
+
# 0960 R2: run-start script-resolution identity — record which tree this run
|
|
88
|
+
# resolved (source-repo vs installed) before any step executes. Never aborts.
|
|
89
|
+
- kind: shell
|
|
90
|
+
options:
|
|
91
|
+
command: >-
|
|
92
|
+
S=plugins/sp/scripts/script-root.ts; [ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp script-root.mjs 2>/dev/null)"; RUNNER=bun; case "$S" in *.mjs) RUNNER=node ;; esac; [ -f "$S" ] && "$RUNNER" "$S" --run-id "$__runId" --spur-bin "$spurBin" || echo "script-root failed closed — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; exit 0
|
|
87
93
|
- kind: note
|
|
88
94
|
options:
|
|
89
95
|
message: "Idea pipeline start for idea: ${vars.idea}"
|
|
@@ -254,12 +260,12 @@ states:
|
|
|
254
260
|
options:
|
|
255
261
|
command: >-
|
|
256
262
|
mkdir -p .spur/run &&
|
|
257
|
-
S=plugins/sp/scripts/idea-coverage-check.ts
|
|
258
|
-
|
|
263
|
+
S=plugins/sp/scripts/idea-coverage-check.ts;
|
|
264
|
+
[ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp idea-coverage-check.ts 2>/dev/null)";
|
|
259
265
|
if [ -n "$S" ] && [ -f "$S" ]; then
|
|
260
266
|
bun "$S" --run-id "$__runId" --report ".spur/run/$__runId-idea-eval-report.md" --ac ".spur/run/$__runId-idea-ac-content.md" || printf 'FAIL run=%s checker exited nonzero (bun missing or checker crash)\n' "$__runId" > ".spur/run/$__runId-idea-coverage.reason";
|
|
261
267
|
else
|
|
262
|
-
printf 'FAIL run=%s checker not found — run superskill install sp\n' "$__runId" | tee ".spur/run/$__runId-idea-coverage.reason" >&2;
|
|
268
|
+
printf 'FAIL run=%s checker not found — run superskill install sp --marketplace gobing-ai/spur\n' "$__runId" | tee ".spur/run/$__runId-idea-coverage.reason" >&2;
|
|
263
269
|
printf 'FAIL\n' > ".spur/run/$__runId-idea-coverage.status";
|
|
264
270
|
fi
|
|
265
271
|
# 0945 R2: derive the route facts ONCE at this boundary (0769 pattern) — guards read these
|
|
@@ -558,7 +564,7 @@ states:
|
|
|
558
564
|
elif H="$(superskill script path sp idea-handoff.mjs 2>/dev/null)" && [ -f "$H" ]; then
|
|
559
565
|
node "$H";
|
|
560
566
|
else
|
|
561
|
-
echo "idea handoff failed closed — idea-handoff script not found — run 'superskill install sp'" >&2;
|
|
567
|
+
echo "idea handoff failed closed — idea-handoff script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
|
|
562
568
|
exit 1;
|
|
563
569
|
fi
|
|
564
570
|
- id: handoff
|
|
@@ -13,9 +13,10 @@
|
|
|
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
|
|
17
|
-
# scans and folds residuals
|
|
18
|
-
#
|
|
16
|
+
# F96 residual sweep (0950, reordered 0983): precheck captures the resume-safe base
|
|
17
|
+
# commit; record scans and folds residuals AFTER `task record` flips the verdict-proven
|
|
18
|
+
# boxes (a post-record blocking leftover downgrades PASS → PARTIAL, fails the record →
|
|
19
|
+
# done guard closed, and re-records Testing before the failed edge); done settles
|
|
19
20
|
# deferrals; failed renders the recovery report. No new state, edge, or model query.
|
|
20
21
|
#
|
|
21
22
|
# Vars (passed as a JSON object via `--vars`):
|
|
@@ -187,6 +188,12 @@ states:
|
|
|
187
188
|
Fast deterministic task readiness and size checks. Failures route to the
|
|
188
189
|
`failed` terminal state (not a raw lifecycle abort mid-enter).
|
|
189
190
|
onEnter:
|
|
191
|
+
# 0960 R2: run-start script-resolution identity — record which tree this run
|
|
192
|
+
# resolved (source-repo vs installed) before any step executes. Never aborts.
|
|
193
|
+
- kind: shell
|
|
194
|
+
options:
|
|
195
|
+
command: >-
|
|
196
|
+
S=plugins/sp/scripts/script-root.ts; [ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp script-root.mjs 2>/dev/null)"; RUNNER=bun; case "$S" in *.mjs) RUNNER=node ;; esac; [ -f "$S" ] && "$RUNNER" "$S" --run-id "$__runId" --spur-bin "$spurBin" || echo "script-root failed closed — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; exit 0
|
|
190
197
|
# (e) git-status hygiene advisory; never fails the run (0487 R6 / 0511 R1).
|
|
191
198
|
- kind: shell
|
|
192
199
|
options:
|
|
@@ -207,12 +214,12 @@ states:
|
|
|
207
214
|
- kind: shell
|
|
208
215
|
options:
|
|
209
216
|
command: >-
|
|
210
|
-
mkdir -p .spur/run; S=plugins/sp/scripts/task-size-precheck.ts; [ -f "$S" ] || S="$(superskill script path sp task-size-precheck.ts 2>/dev/null)"; if [ -f "$S" ]; then bun "$S" "$wbs" --spur-bin "$spurBin" --max-reqs "$maxImplementReqs" --max-plan-items "$maxImplementPlanItems"; else echo "task-size-precheck failed closed — checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'." >&2; echo "FAIL" > ".spur/run/$wbs-precheck-size.status"; fi; exit 0
|
|
217
|
+
mkdir -p .spur/run; S=plugins/sp/scripts/task-size-precheck.ts; [ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp task-size-precheck.ts 2>/dev/null)"; if [ -f "$S" ]; then bun "$S" "$wbs" --spur-bin "$spurBin" --max-reqs "$maxImplementReqs" --max-plan-items "$maxImplementPlanItems"; else echo "task-size-precheck failed closed — checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp --marketplace gobing-ai/spur'." >&2; echo "FAIL" > ".spur/run/$wbs-precheck-size.status"; fi; exit 0
|
|
211
218
|
# (d) task-evidence-precheck.ts owns the check; shell only resolves it and fails closed (0726 R2).
|
|
212
219
|
- kind: shell
|
|
213
220
|
options:
|
|
214
221
|
command: >-
|
|
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
|
|
222
|
+
mkdir -p .spur/run; S=plugins/sp/scripts/task-evidence-precheck.ts; [ -f config/plugin-scripts.json -a -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 --marketplace gobing-ai/spur'." >&2; echo "FAIL" > ".spur/run/$wbs-precheck-evidence.status"; fi; exit 0
|
|
216
223
|
# (e) F96 R1 (0950): capture the run's base commit once — a resumed or re-entered run
|
|
217
224
|
# keeps its original base so residual scans stay anchored to the same diff.
|
|
218
225
|
- kind: shell
|
|
@@ -432,7 +439,7 @@ states:
|
|
|
432
439
|
- kind: shell
|
|
433
440
|
options:
|
|
434
441
|
command: >-
|
|
435
|
-
mkdir -p .spur/run; if [ -f plugins/sp/scripts/quality-gate.ts ]; then bun plugins/sp/scripts/quality-gate.ts run; elif Q="$(superskill script path sp quality-gate.mjs 2>/dev/null)" && [ -f "$Q" ]; then node "$Q" run; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
|
|
442
|
+
mkdir -p .spur/run; if [ -f config/plugin-scripts.json -a -f plugins/sp/scripts/quality-gate.ts ]; then bun plugins/sp/scripts/quality-gate.ts run; elif Q="$(superskill script path sp quality-gate.mjs 2>/dev/null)" && [ -f "$Q" ]; then node "$Q" run; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
|
|
436
443
|
|
|
437
444
|
- id: test-fix
|
|
438
445
|
description: >
|
|
@@ -515,7 +522,7 @@ states:
|
|
|
515
522
|
- kind: shell
|
|
516
523
|
options:
|
|
517
524
|
command: >-
|
|
518
|
-
mkdir -p .spur/run; if [ -f plugins/sp/scripts/quality-gate.ts ]; then bun plugins/sp/scripts/quality-gate.ts recheck; elif Q="$(superskill script path sp quality-gate.mjs 2>/dev/null)" && [ -f "$Q" ]; then node "$Q" recheck; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
|
|
525
|
+
mkdir -p .spur/run; if [ -f config/plugin-scripts.json -a -f plugins/sp/scripts/quality-gate.ts ]; then bun plugins/sp/scripts/quality-gate.ts recheck; elif Q="$(superskill script path sp quality-gate.mjs 2>/dev/null)" && [ -f "$Q" ]; then node "$Q" recheck; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
|
|
519
526
|
|
|
520
527
|
- id: triage
|
|
521
528
|
description: >-
|
|
@@ -535,7 +542,7 @@ states:
|
|
|
535
542
|
- kind: shell
|
|
536
543
|
options:
|
|
537
544
|
command: >-
|
|
538
|
-
mkdir -p .spur/run; if [ -f plugins/sp/scripts/task-diffstat.ts ]; then bun plugins/sp/scripts/task-diffstat.ts --spur-bin "$spurBin"; elif D="$(superskill script path sp task-diffstat.mjs 2>/dev/null)" && [ -f "$D" ]; then node "$D"; else echo "task-diffstat failed closed — task-diffstat script not found — run 'superskill install sp'" >&2; printf '{"files":0,"insertions":0,"deletions":0,"paths":[],"sensitive":true}\n' > ".spur/run/$wbs-diffstat.json"; fi; exit 0
|
|
545
|
+
mkdir -p .spur/run; if [ -f config/plugin-scripts.json -a -f plugins/sp/scripts/task-diffstat.ts ]; then bun plugins/sp/scripts/task-diffstat.ts --spur-bin "$spurBin"; elif D="$(superskill script path sp task-diffstat.mjs 2>/dev/null)" && [ -f "$D" ]; then node "$D"; else echo "task-diffstat failed closed — task-diffstat script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; printf '{"files":0,"insertions":0,"deletions":0,"paths":[],"sensitive":true}\n' > ".spur/run/$wbs-diffstat.json"; fi; exit 0
|
|
539
546
|
# (b)+(c) lane pre-guard BEFORE decide: a caller-set mode is projected verbatim (R2b);
|
|
540
547
|
# a sensitive path or >400 changed lines pins safety (R2c) and the decide result below
|
|
541
548
|
# is never consulted. A missing/malformed diffstat row (producer crashed or never ran,
|
|
@@ -706,10 +713,10 @@ states:
|
|
|
706
713
|
options:
|
|
707
714
|
command: >-
|
|
708
715
|
LINT_SCRIPT="plugins/sp/scripts/verify-answer-lint.ts";
|
|
709
|
-
[ -f "$LINT_SCRIPT" ] ||
|
|
716
|
+
[ -f config/plugin-scripts.json -a -f "$LINT_SCRIPT" ] ||
|
|
710
717
|
LINT_SCRIPT="$(superskill script path sp verify-answer-lint.ts 2>/dev/null)";
|
|
711
718
|
if [ -z "$LINT_SCRIPT" ] || [ ! -f "$LINT_SCRIPT" ]; then
|
|
712
|
-
echo "verify-answer-lint: checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'" >&2;
|
|
719
|
+
echo "verify-answer-lint: checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
|
|
713
720
|
exit 1;
|
|
714
721
|
fi;
|
|
715
722
|
bun "$LINT_SCRIPT" "$wbs"
|
|
@@ -718,16 +725,6 @@ states:
|
|
|
718
725
|
- kind: shell
|
|
719
726
|
options:
|
|
720
727
|
command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
|
|
721
|
-
# (d) F96 R2 (0950): residual-scan.ts owns the sweep; shell only resolves it.
|
|
722
|
-
# ONE hard action (scan+fold): a scanner crash fails verify closed — the
|
|
723
|
-
# verify→failed catch-all routes a missing/malformed verdict. Runs AFTER
|
|
724
|
-
# `task verdict` and BEFORE the jq bind so a blocking residual turns PASS
|
|
725
|
-
# into PARTIAL (fold rewrites the verdict artifact) and takes the existing
|
|
726
|
-
# verify→test-fix edge while attempts remain.
|
|
727
|
-
- kind: shell
|
|
728
|
-
options:
|
|
729
|
-
command: >-
|
|
730
|
-
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"
|
|
731
728
|
# (e) one jq mutation binds the verdict to the proof digest (0703 R3; runId 0730 §B.2 /
|
|
732
729
|
# 0757 R4; definitionDigest 0759 R5; honest review stamp 0785 R4; soft action + hard guard).
|
|
733
730
|
- kind: shell
|
|
@@ -745,7 +742,11 @@ states:
|
|
|
745
742
|
evidence (0785 R4) — before any task record or status mutation. Post-record step
|
|
746
743
|
conditionally syncs feature status via the bounded `feature-sync-bounded` wrapper
|
|
747
744
|
(task 0411 retry-suppression) if `feature_id` is present, or appends an orphan
|
|
748
|
-
link proposal to the run report if absent (task 0328 / ADR-0322).
|
|
745
|
+
link proposal to the run report if absent (task 0328 / ADR-0322). The post-record
|
|
746
|
+
residual sweep (0983) re-scans the task file after the verdict-proven box flips and
|
|
747
|
+
folds blocking leftovers into the verdict before `record → done`; a downgrade
|
|
748
|
+
re-records Testing from the final artifact so a failed task never keeps a stale
|
|
749
|
+
PASS narrative.
|
|
749
750
|
onEnter:
|
|
750
751
|
# 0785 R3: BOUND verify-verdict registration — FIRST action, before any task record or
|
|
751
752
|
# status mutation, replacing the redundant proof.fingerprint compare (the action itself
|
|
@@ -771,7 +772,11 @@ states:
|
|
|
771
772
|
options:
|
|
772
773
|
id: task-record-transition
|
|
773
774
|
executable: "${vars.spurBin}"
|
|
774
|
-
|
|
775
|
+
# 0980: --no-lifecycle mirrors the wip/done hops — the pipeline run is
|
|
776
|
+
# already the lifecycle record, so a record-stage transition must not
|
|
777
|
+
# spawn a nested task-lifecycle run that outlives the pipeline as a
|
|
778
|
+
# `running` orphan. The target-aware check gate still runs (inline).
|
|
779
|
+
args: ["task", "record", "${vars.wbs}", "--solution-from-diff", "--transition", "testing", "--no-lifecycle"]
|
|
775
780
|
retry:
|
|
776
781
|
maxAttempts: 2
|
|
777
782
|
delayMs: 2000
|
|
@@ -791,7 +796,30 @@ states:
|
|
|
791
796
|
- kind: shell
|
|
792
797
|
options:
|
|
793
798
|
command: >-
|
|
794
|
-
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
|
|
799
|
+
S=plugins/sp/scripts/record-feature-sync.ts; [ -f config/plugin-scripts.json -a -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
|
|
800
|
+
# (d) F96 (0983): residual-scan.ts owns the sweep; shell only resolves it. The
|
|
801
|
+
# scan moved here from verify: it must read the task file AFTER `task record`
|
|
802
|
+
# flipped the verdict-proven Requirement/AC boxes (0692), or a proven-but-unticked
|
|
803
|
+
# box folds every good run to PARTIAL and the done guard is unreachable (0967).
|
|
804
|
+
# Classification unchanged: any box still unchecked post-record (unproven R/AC,
|
|
805
|
+
# unfinished Plan) stays blocking and fails the record → done guard closed.
|
|
806
|
+
# ONE hard action (scan+fold): a scanner crash fails record closed.
|
|
807
|
+
- kind: shell
|
|
808
|
+
options:
|
|
809
|
+
command: >-
|
|
810
|
+
S=plugins/sp/scripts/residual-scan.ts; [ -f config/plugin-scripts.json -a -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 --marketplace gobing-ai/spur'" >&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"
|
|
811
|
+
# (e) F96 R5 (0983): a sweep downgrade must reach the task record — re-record from
|
|
812
|
+
# the FINAL (post-fold) artifact so Testing carries the downgraded verdict; a failed
|
|
813
|
+
# task must not retain a stale PASS Testing narrative. Soft (exit 0): the downgrade
|
|
814
|
+
# itself already fails the record → done guard; a re-record failure prints its
|
|
815
|
+
# re-run command and the failed state renders the recovery report.
|
|
816
|
+
# 0980: --no-lifecycle for the same orphan reason as the main record command —
|
|
817
|
+
# inert today (the task is already at testing, so this is a same-status no-op),
|
|
818
|
+
# but it keeps the no-nested-lifecycle invariant if the flow shifts.
|
|
819
|
+
- kind: shell
|
|
820
|
+
options:
|
|
821
|
+
command: >-
|
|
822
|
+
verdict="$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)"; if [ -n "$verdict" ] && [ "$verdict" != PASS ]; then $spurBin task record $wbs --solution-from-diff --transition testing --no-lifecycle || echo "post-downgrade re-record failed — re-run: $spurBin task record $wbs" >&2; fi; exit 0
|
|
795
823
|
|
|
796
824
|
- id: done
|
|
797
825
|
description: >
|
|
@@ -805,7 +833,7 @@ states:
|
|
|
805
833
|
- kind: shell
|
|
806
834
|
options:
|
|
807
835
|
command: >-
|
|
808
|
-
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
|
|
836
|
+
S=plugins/sp/scripts/residual-scan.ts; [ -f config/plugin-scripts.json -a -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
|
|
809
837
|
# (c) command.gate owns the done transition with classified transient retry.
|
|
810
838
|
- kind: command.gate
|
|
811
839
|
options:
|
|
@@ -852,7 +880,7 @@ states:
|
|
|
852
880
|
- kind: shell
|
|
853
881
|
options:
|
|
854
882
|
command: >-
|
|
855
|
-
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
|
|
883
|
+
S=plugins/sp/scripts/residual-scan.ts; [ -f config/plugin-scripts.json -a -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
|
|
856
884
|
|
|
857
885
|
- id: cancelled
|
|
858
886
|
description: Terminal — pipeline cancelled by operator at the approval gate (R1).
|
|
@@ -1163,6 +1191,6 @@ transitions:
|
|
|
1163
1191
|
- from: record
|
|
1164
1192
|
to: failed
|
|
1165
1193
|
terminalReason: failed-check
|
|
1166
|
-
description: Task check failed or proof evidence missing/malformed/mismatched — block before done.
|
|
1194
|
+
description: Task check failed, a post-record residual downgrade, or proof evidence missing/malformed/mismatched — block before done.
|
|
1167
1195
|
guard:
|
|
1168
1196
|
kind: always
|
|
@@ -13,13 +13,18 @@
|
|
|
13
13
|
# pauses,
|
|
14
14
|
# even under --auto (Iron Law #6: irreversible action -> surface to human).
|
|
15
15
|
#
|
|
16
|
-
# Shape: start -> task-resolve -> doc-sync -> learnings-
|
|
16
|
+
# Shape: start -> task-resolve -> doc-sync -> learnings-validate -> learnings-append
|
|
17
|
+
# -> metrics-record
|
|
17
18
|
# -> feature-transition (conditional: if vars.feature set)
|
|
18
19
|
# -> feature-verify (post-transition feature check gate, 0915 F1)
|
|
19
20
|
# -> branch-cleanup (conditional: if vars.merge=true)
|
|
20
21
|
# -> done
|
|
21
22
|
# doc-sync routes a contract violation to `repair` (cheap, no
|
|
22
23
|
# re-dispatch — ADR-118 pilot) and an executor failure to `failed`;
|
|
24
|
+
# learnings-validate (0986) rejects a nonempty narration-only capture to
|
|
25
|
+
# the same `repair` edge with a distinct invalid-learnings-shape status —
|
|
26
|
+
# expectFile proves existence, never shape — while empty/missing captures
|
|
27
|
+
# keep the soft skip by passing through to learnings-append;
|
|
23
28
|
# task-resolve with a VALIDATED empty list short-circuits to `skipped`;
|
|
24
29
|
# invalid wrap input, an unresolved/non-completed task, a failed metrics
|
|
25
30
|
# capture, a failed required sync, or a failed feature gate routes to
|
|
@@ -75,7 +80,7 @@
|
|
|
75
80
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
76
81
|
kind: state-machine
|
|
77
82
|
name: wrapup-pipeline
|
|
78
|
-
version: "
|
|
83
|
+
version: "6"
|
|
79
84
|
description: "Post-execution wrap-up: doc-sync (doc drift + learning capture), metrics, feature-transition, branch-cleanup"
|
|
80
85
|
iterationBound: 10
|
|
81
86
|
initialState: start
|
|
@@ -108,6 +113,12 @@ states:
|
|
|
108
113
|
Pipeline start. Task statuses are NOT mutated by wrap-up — wrap-up consumes
|
|
109
114
|
completed tasks and produces learning/metrics/doc artifacts only.
|
|
110
115
|
onEnter:
|
|
116
|
+
# 0960 R2: run-start script-resolution identity — record which tree this run
|
|
117
|
+
# resolved (source-repo vs installed) before any step executes. Never aborts.
|
|
118
|
+
- kind: shell
|
|
119
|
+
options:
|
|
120
|
+
command: >-
|
|
121
|
+
S=plugins/sp/scripts/script-root.ts; [ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp script-root.mjs 2>/dev/null)"; RUNNER=bun; case "$S" in *.mjs) RUNNER=node ;; esac; [ -f "$S" ] && "$RUNNER" "$S" --run-id "$__runId" --spur-bin "$spurBin" || echo "script-root failed closed — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; exit 0
|
|
111
122
|
- kind: note
|
|
112
123
|
options:
|
|
113
124
|
message: "Wrap-up pipeline start for tasks: ${vars.tasks}. Task statuses are NOT mutated."
|
|
@@ -143,12 +154,12 @@ states:
|
|
|
143
154
|
options:
|
|
144
155
|
command: >-
|
|
145
156
|
mkdir -p .spur/run &&
|
|
146
|
-
if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
|
|
157
|
+
if [ -f config/plugin-scripts.json -a -f plugins/sp/scripts/wrapup-steps.ts ]; then
|
|
147
158
|
bun plugins/sp/scripts/wrapup-steps.ts resolve;
|
|
148
159
|
elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
|
|
149
160
|
node "$W" resolve;
|
|
150
161
|
else
|
|
151
|
-
echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
|
|
162
|
+
echo "wrapup-steps failed closed — script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
|
|
152
163
|
printf 'FAIL\n' > ".spur/run/$__runId-wrapup-resolve.status";
|
|
153
164
|
fi
|
|
154
165
|
# (0944 R1-R3) deterministic drift probe — runs ONLY when the caller left mode
|
|
@@ -163,7 +174,7 @@ states:
|
|
|
163
174
|
command: >-
|
|
164
175
|
if [ -n "$mode" ]; then
|
|
165
176
|
printf '%s\n' "$mode" > ".spur/run/$__runId-mode.txt";
|
|
166
|
-
elif [ -f plugins/sp/scripts/wrapup-drift-probe.ts ]; then
|
|
177
|
+
elif [ -f config/plugin-scripts.json -a -f plugins/sp/scripts/wrapup-drift-probe.ts ]; then
|
|
167
178
|
bun plugins/sp/scripts/wrapup-drift-probe.ts;
|
|
168
179
|
elif W="$(superskill script path sp wrapup-drift-probe.mjs 2>/dev/null)" && [ -f "$W" ]; then
|
|
169
180
|
node "$W";
|
|
@@ -190,12 +201,12 @@ states:
|
|
|
190
201
|
options:
|
|
191
202
|
command: >-
|
|
192
203
|
mkdir -p .spur/run .spur/memory &&
|
|
193
|
-
if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
|
|
204
|
+
if [ -f config/plugin-scripts.json -a -f plugins/sp/scripts/wrapup-steps.ts ]; then
|
|
194
205
|
bun plugins/sp/scripts/wrapup-steps.ts route-reason;
|
|
195
206
|
elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
|
|
196
207
|
node "$W" route-reason;
|
|
197
208
|
else
|
|
198
|
-
echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
|
|
209
|
+
echo "wrapup-steps failed closed — script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
|
|
199
210
|
printf 'FAIL\n' > ".spur/run/$__runId-wrapup-resolve.status";
|
|
200
211
|
fi
|
|
201
212
|
|
|
@@ -234,6 +245,34 @@ states:
|
|
|
234
245
|
expectFile: .spur/run/${vars.__runId}-wrapup-learnings.md
|
|
235
246
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
236
247
|
|
|
248
|
+
- id: learnings-validate
|
|
249
|
+
description: >
|
|
250
|
+
Structural shape gate between doc-sync and the append (0986): expectFile
|
|
251
|
+
asserts the capture EXISTS and nothing about its shape, so a
|
|
252
|
+
stream-of-thought capture could be appended verbatim to the tracked
|
|
253
|
+
memory file. This state classifies a NONEMPTY capture — a date, a
|
|
254
|
+
four-digit task WBS, and at least one markdown bullet — and writes PASS
|
|
255
|
+
or invalid-learnings-shape to a run-scoped status. An empty or missing
|
|
256
|
+
capture keeps the existing soft skip (PASS) so learnings-append still
|
|
257
|
+
performs its no-op; an unclassifiable status fails loud instead of
|
|
258
|
+
appending it. Structural check only — the doc-sync prompt owns prose
|
|
259
|
+
quality; no new engine-level content contract.
|
|
260
|
+
onEnter:
|
|
261
|
+
# (warn) structural check only; the doc-sync prompt owns prose quality (0986 Design).
|
|
262
|
+
# The WBS predicate excludes digit/dash neighbours so a date's year cannot satisfy it.
|
|
263
|
+
- kind: shell
|
|
264
|
+
options:
|
|
265
|
+
command: >-
|
|
266
|
+
mkdir -p .spur/run &&
|
|
267
|
+
S=".spur/run/$__runId-wrapup-learnings.status" &&
|
|
268
|
+
F=".spur/run/$__runId-wrapup-learnings.md" &&
|
|
269
|
+
if [ ! -s "$F" ] || awk '/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/{d=1} /(^|[^0-9-])[0-9][0-9][0-9][0-9]([^0-9-]|$)/{w=1} /^[[:space:]]*[-*] /{b=1} END{exit !(d+w+b==3)}' "$F"; then
|
|
270
|
+
printf 'PASS\n' > "$S";
|
|
271
|
+
else
|
|
272
|
+
printf 'invalid-learnings-shape\n' > "$S";
|
|
273
|
+
fi &&
|
|
274
|
+
exit 0
|
|
275
|
+
|
|
237
276
|
- id: learnings-append
|
|
238
277
|
description: >
|
|
239
278
|
Best-effort soft append of the captured learnings to .spur/memory/learnings.md
|
|
@@ -259,15 +298,22 @@ states:
|
|
|
259
298
|
description: >
|
|
260
299
|
Contract-violation repair (ADR-118 pilot, 0871): doc-sync's agent.run missed
|
|
261
300
|
its declared post-condition after a clean exit, so wrap-up does NOT re-dispatch
|
|
262
|
-
the expensive agent on this attempt.
|
|
263
|
-
|
|
264
|
-
|
|
301
|
+
the expensive agent on this attempt. Also the destination for a nonempty
|
|
302
|
+
capture that fails learnings-validate's shape gate (0986). The miss is
|
|
303
|
+
recorded to a run-scoped repair status — text distinguishing a narration-only
|
|
304
|
+
shape failure from the missing-file contract violation — and wrap-up proceeds
|
|
305
|
+
to metrics-record; the run log and action trace already name the violated
|
|
306
|
+
contract and the observed value.
|
|
265
307
|
onEnter:
|
|
266
308
|
- kind: shell
|
|
267
309
|
options:
|
|
268
310
|
command: >-
|
|
269
311
|
mkdir -p .spur/run &&
|
|
270
|
-
|
|
312
|
+
R=".spur/run/$__runId-wrapup-repair.status" &&
|
|
313
|
+
V="$(cat .spur/run/$__runId-wrapup-learnings.status 2>/dev/null)" &&
|
|
314
|
+
if [ "$V" = invalid-learnings-shape ]; then printf 'invalid-learnings-shape: narration-only learnings capture — append skipped, repair recorded (0986)\n' > "$R";
|
|
315
|
+
else printf 'contract-violation: doc-sync learnings capture missed its declared contract — repair skipped re-dispatch (ADR-118 pilot)\n' > "$R";
|
|
316
|
+
fi &&
|
|
271
317
|
exit 0
|
|
272
318
|
|
|
273
319
|
- id: metrics-record
|
|
@@ -288,12 +334,12 @@ states:
|
|
|
288
334
|
options:
|
|
289
335
|
command: >-
|
|
290
336
|
mkdir -p .spur/run &&
|
|
291
|
-
if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
|
|
337
|
+
if [ -f config/plugin-scripts.json -a -f plugins/sp/scripts/wrapup-steps.ts ]; then
|
|
292
338
|
bun plugins/sp/scripts/wrapup-steps.ts metrics;
|
|
293
339
|
elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
|
|
294
340
|
node "$W" metrics;
|
|
295
341
|
else
|
|
296
|
-
echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
|
|
342
|
+
echo "wrapup-steps failed closed — script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
|
|
297
343
|
printf 'FAIL\n' > ".spur/run/$__runId-wrapup-metrics.status";
|
|
298
344
|
fi
|
|
299
345
|
|
|
@@ -322,12 +368,12 @@ states:
|
|
|
322
368
|
options:
|
|
323
369
|
command: >-
|
|
324
370
|
mkdir -p .spur/run &&
|
|
325
|
-
if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
|
|
371
|
+
if [ -f config/plugin-scripts.json -a -f plugins/sp/scripts/wrapup-steps.ts ]; then
|
|
326
372
|
bun plugins/sp/scripts/wrapup-steps.ts feature-transition;
|
|
327
373
|
elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
|
|
328
374
|
node "$W" feature-transition;
|
|
329
375
|
else
|
|
330
|
-
echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
|
|
376
|
+
echo "wrapup-steps failed closed — script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
|
|
331
377
|
printf 'FAIL\n' > ".spur/run/$__runId-wrapup-sync.status";
|
|
332
378
|
fi
|
|
333
379
|
|
|
@@ -460,8 +506,8 @@ transitions:
|
|
|
460
506
|
guard:
|
|
461
507
|
kind: contract-violation
|
|
462
508
|
- from: doc-sync
|
|
463
|
-
to: learnings-
|
|
464
|
-
description: Doc drift repair + learning capture succeeded —
|
|
509
|
+
to: learnings-validate
|
|
510
|
+
description: Doc drift repair + learning capture succeeded — validate the capture's shape before appending.
|
|
465
511
|
guard:
|
|
466
512
|
kind: action-ok
|
|
467
513
|
- from: doc-sync
|
|
@@ -475,6 +521,35 @@ transitions:
|
|
|
475
521
|
guard:
|
|
476
522
|
kind: always
|
|
477
523
|
|
|
524
|
+
# ── learnings-validate: shape gate (0986) — invalid-shape to repair, PASS to append ──
|
|
525
|
+
# Declaration order matters: the discriminating invalid-shape edge is tried
|
|
526
|
+
# first, then PASS; an unreadable status fails loud rather than appending an
|
|
527
|
+
# unclassified capture.
|
|
528
|
+
- from: learnings-validate
|
|
529
|
+
to: repair
|
|
530
|
+
description: >
|
|
531
|
+
Nonempty capture failed the structural shape gate (no date/WBS/bullet) —
|
|
532
|
+
route to the cheap repair edge and never append narration (0986 R2).
|
|
533
|
+
guard:
|
|
534
|
+
kind: shell
|
|
535
|
+
options:
|
|
536
|
+
command: 'test "$(cat .spur/run/$__runId-wrapup-learnings.status 2>/dev/null)" = invalid-learnings-shape'
|
|
537
|
+
- from: learnings-validate
|
|
538
|
+
to: learnings-append
|
|
539
|
+
description: Capture is shape-valid (or empty/missing, keeping the soft skip) — append.
|
|
540
|
+
guard:
|
|
541
|
+
kind: shell
|
|
542
|
+
options:
|
|
543
|
+
command: 'test "$(cat .spur/run/$__runId-wrapup-learnings.status 2>/dev/null)" = PASS'
|
|
544
|
+
- from: learnings-validate
|
|
545
|
+
to: failed
|
|
546
|
+
terminalReason: failed-check
|
|
547
|
+
description: >
|
|
548
|
+
Validation status missing or unreadable — fail loud instead of appending
|
|
549
|
+
a capture whose shape was never classified.
|
|
550
|
+
guard:
|
|
551
|
+
kind: always
|
|
552
|
+
|
|
478
553
|
# ── linear body: learnings-append -> metrics-record ──
|
|
479
554
|
- from: learnings-append
|
|
480
555
|
to: metrics-record
|