@gobing-ai/spur 0.3.85 → 0.3.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/config/pipeline-budgets.json +0 -25
- package/config/plugin-scripts.json +4 -5
- package/config/rules/boundary/env-var-hygiene.yaml +41 -0
- package/config/templates/feature/default.md +2 -0
- package/config/templates/task/brainstorm.md +2 -2
- package/config/templates/task/feature-impl.md +2 -2
- package/config/templates/task/issue.md +2 -2
- package/config/templates/task/meta.md +2 -2
- package/config/templates/task/review.md +2 -2
- package/config/templates/task/standard.md +2 -2
- package/config/transition-shims.json +1 -1
- package/config/workflow-candidates.json +19 -0
- package/config/workflows/feature-lifecycle.yaml +10 -2
- package/config/workflows/feature-verification.yaml +71 -0
- package/config/workflows/idea-pipeline.yaml +87 -39
- package/config/workflows/task-pipeline.yaml +43 -12
- package/config/workflows/wrapup-pipeline.yaml +70 -7
- package/package.json +9 -9
- package/plugins/sp/README.md +7 -7
- package/plugins/sp/commands/dev-idea.md +9 -2
- package/plugins/sp/commands/dev-refactor.md +33 -0
- package/plugins/sp/hooks/agent-hint.ts +5 -4
- package/plugins/sp/hooks/careful-guard.ts +3 -1
- package/plugins/sp/hooks/context-post-tool.ts +2 -1
- package/plugins/sp/hooks/context-session-start.ts +4 -3
- package/plugins/sp/hooks/context-session-stop.ts +2 -1
- package/plugins/sp/hooks/pi/guard-extension.ts +4 -3
- package/plugins/sp/hooks/task-write-guard.ts +4 -3
- package/plugins/sp/lib/idea-handoff.generated.mjs +260 -260
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +1 -1
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +13 -4
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +6 -4
- package/plugins/sp/scripts/feature-sync-bounded.mjs +10 -2
- package/plugins/sp/scripts/feature-sync-bounded.ts +2 -1
- package/plugins/sp/scripts/idea-coverage-check.ts +168 -0
- package/plugins/sp/scripts/idea-handoff.mjs +6 -1
- package/plugins/sp/scripts/idea-handoff.ts +4 -1
- package/plugins/sp/scripts/inline-pipeline-parity-check.ts +115 -4
- package/plugins/sp/scripts/inline-run-setup.ts +195 -2
- package/plugins/sp/scripts/pr-reviewing.mjs +8 -1
- package/plugins/sp/scripts/pr-reviewing.ts +2 -1
- package/plugins/sp/scripts/quality-gate.mjs +8 -1
- package/plugins/sp/scripts/quality-gate.ts +2 -1
- package/plugins/sp/scripts/surface-drift-inventory.ts +1 -4
- package/plugins/sp/scripts/task-evidence-precheck.ts +2 -1
- package/plugins/sp/scripts/task-size-precheck.ts +6 -4
- package/plugins/sp/scripts/verify-answer-lint.ts +2 -1
- package/plugins/sp/scripts/workflow-step-profile.mjs +10 -2
- package/plugins/sp/scripts/workflow-step-profile.ts +2 -1
- package/plugins/sp/scripts/wrapup-steps.mjs +8 -1
- package/plugins/sp/scripts/wrapup-steps.ts +2 -1
- package/plugins/sp/skills/brainstorm/SKILL.md +4 -0
- package/plugins/sp/skills/code-refactoring/SKILL.md +155 -0
- package/plugins/sp/skills/code-refactoring/references/finding-schema.md +74 -0
- package/plugins/sp/skills/code-refactoring/references/fix-ladder.md +52 -0
- package/plugins/sp/skills/code-refactoring/references/focus-detection.md +44 -0
- package/plugins/sp/skills/code-refactoring/references/refactor-finding.schema.json +95 -0
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +23 -16
- package/plugins/sp/skills/spur-cli/references/features/acceptance-criteria.md +4 -2
- package/plugins/sp/skills/spur-cli/references/features.md +6 -1
- package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +2 -2
- package/plugins/sp/skills/spur-cli/references/workflows/operations.md +3 -3
- package/plugins/sp/skills/spur-cli/references/workflows/workflow-fit-and-tuning.md +1 -1
- package/plugins/sp/skills/spur-cli/references/workflows.md +8 -7
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +24 -0
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +4 -5
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +18 -2
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +1 -1
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +22 -3
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +2 -2
- package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +11 -1
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +91 -1
- package/plugins/sp/skills/taste-refactoring-api/SKILL.md +44 -1
- package/plugins/sp/skills/taste-refactoring-api/references/protocol-modes.md +31 -0
- package/plugins/sp/skills/taste-refactoring-architect/SKILL.md +43 -0
- package/plugins/sp/skills/taste-refactoring-tests/SKILL.md +42 -0
- package/plugins/sp/skills/taste-refactoring-ui/SKILL.md +43 -0
- package/schemas/state-machine-workflow.schema.json +5 -0
- package/schemas/task-batch.schema.json +2 -2
- package/schemas/transition-flow-workflow.schema.json +5 -0
- package/spur.js +21106 -20669
- package/web/_astro/BoardApp.CJiqp5pS.js +1 -0
- package/web/_astro/{BoardApp.yW425dRZ.js → BoardApp.yBBcFXWP.js} +4 -4
- package/web/_astro/{TaskDetail.CGwJAinW.js → TaskDetail.DqFJbRFc.js} +1 -1
- package/web/_astro/{arc.B-qNXzSO.js → arc.DL-BpHoi.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.Bdg-xiji.js → architectureDiagram-3BPJPVTR.9IdQYyDq.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.DFArg3Kp.js → blockDiagram-GPEHLZMM.BKsFCqTl.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BkOLcjyx.js → c4Diagram-AAUBKEIU.DhwI0dh1.js} +1 -1
- package/web/_astro/channel.CX5453qQ.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.DN3c20V4.js → chunk-2J33WTMH.B3QVmQ9S.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.B64K0Ttd.js → chunk-4BX2VUAB.DBSuqs9F.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.C-AJvNwa.js → chunk-55IACEB6.BSYTWAYD.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DMkr46uS.js → chunk-727SXJPM.cWVuxXfS.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.4_WGbI64.js → chunk-AQP2D5EJ.DpU_Ob3d.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.cbFW_lVE.js → chunk-FMBD7UC4.BykFkyji.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CDW_-2O1.js → chunk-ND2GUHAM.DwgHlMdY.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BoYOt_yg.js → chunk-QZHKN3VN.CusXUGWM.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.BNT6XpHQ.js → classDiagram-4FO5ZUOK.fx0ObzkN.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.BNT6XpHQ.js → classDiagram-v2-Q7XG4LA2.fx0ObzkN.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CI1DQxR3.js → cose-bilkent-S5V4N54A.Z4HgOlsd.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.A8ARH61p.js → cynefin-OW5HDTMX.B5dIZHJu.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.u28ZmqwR.js → dagre-BM42HDAG.DT70Q_Yw.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.Dx8JcrGc.js → diagram-2AECGRRQ.DqHA3XBF.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.BXJUG9GY.js → diagram-5GNKFQAL.BmCem957.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.BtlMuWqW.js → diagram-KO2AKTUF.sn0-hrE0.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.C4T7qaAy.js → diagram-LMA3HP47.BSHe9tVc.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.D5HECE10.js → diagram-OG6HWLK6.DHIc-86k.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.B_hMR3yw.js → erDiagram-TEJ5UH35.Bxayrs7v.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.BAmpcYl3.js → flowDiagram-I6XJVG4X.BkzoE_5I.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DV1bSWK-.js → ganttDiagram-6RSMTGT7.okT6CvTo.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.DxYKkKrJ.js → gitGraphDiagram-PVQCEYII.CJuYbhC7.js} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.BAWY2xMb.js → infoDiagram-5YYISTIA.RqLy7nBo.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.CZssRn6V.js → ishikawaDiagram-YF4QCWOH.BwIcoagw.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.C--muARd.js → journeyDiagram-JHISSGLW.UB1VbWtH.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.D_QCK4et.js → kanban-definition-UN3LZRKU.AaxMKpTk.js} +1 -1
- package/web/_astro/{linear.DzrmTtZ0.js → linear.Nv_xOUjP.js} +1 -1
- package/web/_astro/{mermaid.core.Da03W3iu.js → mermaid.core.Bc4LqQgX.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.6cy-8hR_.js → mindmap-definition-RKZ34NQL.oKUvU_qi.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.C5rS1pdU.js → pieDiagram-4H26LBE5.DQk0oo03.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.w56GZZ6Q.js → quadrantDiagram-W4KKPZXB.BdDjESDa.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.CipX3Pwu.js → requirementDiagram-4Y6WPE33.C2u9hUeH.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.C0VVzgJm.js → sankeyDiagram-5OEKKPKP.CDEoiJST.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.BX2dUUbF.js → sequenceDiagram-3UESZ5HK.D_hT_GAT.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.ypCdgODQ.js → stateDiagram-AJRCARHV.DI8RYG0b.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.In0baEtg.js → stateDiagram-v2-BHNVJYJU.Bkxz4DnP.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.CJN4Vkvl.js → timeline-definition-PNZ67QCA.DSY-kH3-.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.Cf8KkIPY.js → vennDiagram-CIIHVFJN.CpaDtuGr.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.DCZBo9xw.js → wardleyDiagram-YWT4CUSO.DujQWvo8.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.Cm4v_MiJ.js → xychartDiagram-2RQKCTM6.DcM5Y4b9.js} +1 -1
- package/web/index.html +1 -1
- package/config/workflows/basic.yaml +0 -146
- package/config/workflows/docs-pipeline.yaml +0 -350
- package/config/workflows/feature-dev.yaml +0 -288
- package/plugins/sp/scripts/feature-dev-precheck.mjs +0 -146
- package/plugins/sp/scripts/feature-dev-precheck.ts +0 -238
- package/web/_astro/BoardApp.CHenHFia.js +0 -1
- package/web/_astro/channel.CbDHK5UQ.js +0 -1
|
@@ -97,7 +97,10 @@ states:
|
|
|
97
97
|
- kind: shell
|
|
98
98
|
options:
|
|
99
99
|
command: >-
|
|
100
|
-
|
|
100
|
+
mkdir -p .spur/run &&
|
|
101
|
+
printf '%s\n' "$idea" > ".spur/run/$__runId-idea-input.md" &&
|
|
102
|
+
awk 'NF' ".spur/run/$__runId-idea-input.md" | grep -q . ||
|
|
103
|
+
printf 'FAIL\n' > ".spur/run/$__runId-idea-precheck-doctor.status"
|
|
101
104
|
|
|
102
105
|
- id: discovery
|
|
103
106
|
description: >
|
|
@@ -109,12 +112,14 @@ states:
|
|
|
109
112
|
brainstorm also emits the idea-evaluation report to .spur/run/${vars.__runId}-idea-eval-report.md
|
|
110
113
|
(template: the `sp:spur-dev` skill's `idea-evaluation` reference — named by skill, not by
|
|
111
114
|
repo path, because `spur init` never scaffolds `plugins/sp/` into a seeded project).
|
|
115
|
+
The operator's verbatim idea argument is persisted at .spur/run/${vars.__runId}-idea-input.md
|
|
116
|
+
(written by start; the authoritative ask every model-bearing stage reads).
|
|
112
117
|
expectFile fails a silent no-op discovery (no eval report).
|
|
113
118
|
onEnter:
|
|
114
119
|
- kind: agent.run
|
|
115
120
|
options:
|
|
116
121
|
agent: ${vars.planningAgent}
|
|
117
|
-
input: "
|
|
122
|
+
input: "The operator's ask of record is .spur/run/${vars.__runId}-idea-input.md — idea persisted verbatim at start; authoritative, read it first (${vars.idea} is a convenience echo). Run sp:brainstorm. The skill owns the approach-generation, design summary, and `needs_design` signal criteria; emit .spur/run/${vars.__runId}-idea-needs-design.json ({\"needs_design\": true|false}) plus the design summary per its `Design Approval Gate` / `The needs_design signal` sections. Also emit the idea-evaluation report to .spur/run/${vars.__runId}-idea-eval-report.md per the `sp:spur-dev` skill's `idea-evaluation` reference (urgency/necessity 0–5, premises, pros/cons, alternatives, enhanced idea, recommendation, plus mandatory `## Requirement inventory`: numbered I<n> items quoting/paraphrasing idea-input lines; `[unclear: ...]` marks ambiguity, `[deferred: <reason>]` marks out-of-scope). End with this exact footer: `---\\nrun_id: ${vars.__runId}\\ngenerated_at: <RFC3339>\\n---` (omit if run_id is empty)."
|
|
118
123
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
119
124
|
role: planner
|
|
120
125
|
expectFile: .spur/run/${vars.__runId}-idea-eval-report.md
|
|
@@ -143,12 +148,14 @@ states:
|
|
|
143
148
|
checklists never enter Goal. Shell actions then persist both sections through
|
|
144
149
|
`spur feature update --section Goal|Scope --from-file ...`; a missing/empty artifact
|
|
145
150
|
stops the state. Prefer the enhanced idea from .spur/run/${vars.__runId}-idea-eval-report.md as
|
|
146
|
-
context; do not overwrite vars.idea.
|
|
151
|
+
context; do not overwrite vars.idea. The operator's verbatim ask of record is
|
|
152
|
+
.spur/run/${vars.__runId}-idea-input.md (persisted at start; authoritative over any
|
|
153
|
+
paraphrase).
|
|
147
154
|
onEnter:
|
|
148
155
|
- kind: agent.run
|
|
149
156
|
options:
|
|
150
157
|
agent: ${vars.planningAgent}
|
|
151
|
-
input: 'Create a feature for the idea
|
|
158
|
+
input: 'Create a feature for the idea. The operator''s ask of record is .spur/run/${vars.__runId}-idea-input.md — the idea argument persisted verbatim at start; treat it as the authoritative ask. Read .spur/run/${vars.__runId}-idea-eval-report.md if present for the enhanced idea and scores. Use ''spur feature create "<name>" --json'' to create it; with --json the feature id is returned under the .ref.id envelope (n), not a top-level .id — read it from there. Write the feature id to .spur/run/${vars.__runId}-idea-feature-id.txt. If an existing feature is appropriate, use its id instead. Also write two body-only intent artifacts: .spur/run/${vars.__runId}-idea-goal.md with concise Goal intent only (a short statement of what the feature achieves; never task breakdowns, checklists, or how-to steps), and .spur/run/${vars.__runId}-idea-scope.md with explicit in-scope and out-of-scope boundary bullets.'
|
|
152
159
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
153
160
|
role: planner
|
|
154
161
|
expectFile: .spur/run/${vars.__runId}-idea-feature-id.txt
|
|
@@ -182,6 +189,9 @@ states:
|
|
|
182
189
|
check records FAIL and routes through the capped retry loop via guards that consume the
|
|
183
190
|
recorded result — it never fails the run (the engine's default onError policy is `fail`,
|
|
184
191
|
so an in-action check failure would kill the run before the retry edges are evaluated).
|
|
192
|
+
Requirement coverage is MEASURED alongside it by the soft idea-coverage-check shell
|
|
193
|
+
(0887 R4): the recorded coverage status conjuncts into the profile=auto ac-generate
|
|
194
|
+
guards below so uncovered inventory items route through the same capped retry loop.
|
|
185
195
|
onEnter:
|
|
186
196
|
- kind: shell
|
|
187
197
|
options:
|
|
@@ -189,7 +199,7 @@ states:
|
|
|
189
199
|
- kind: agent.run
|
|
190
200
|
options:
|
|
191
201
|
agent: ${vars.planningAgent}
|
|
192
|
-
input: "Generate acceptance criteria for feature ${vars.featureId}. Read the feature file and author R-numbered BDD Gherkin scenarios per ac-style-guide.md.
|
|
202
|
+
input: "Generate acceptance criteria for feature ${vars.featureId}. The operator's ask of record is .spur/run/${vars.__runId}-idea-input.md — idea persisted verbatim at start; authoritative. Read the feature file and author R-numbered BDD Gherkin scenarios per ac-style-guide.md. Tie every scenario to the `## Requirement inventory` of .spur/run/${vars.__runId}-idea-eval-report.md: under each `Scenario:` heading add a comment `# covers: I1, I3` listing covered ids — every non-`[deferred: ...]` item needs at least one covering scenario. Two `spur task check` rules bind AC text: (1) AC bullets copy scenario titles verbatim — the title is the byte-identical identity key of its bullet; (2) gate-language words (HITL, approval/approved, merged/merge event, content-gate, GATED, capstone standalone) are forbidden in titles, bodies, and enum values (L4.gate-language) — rephrase around them. Output only the Acceptance Criteria section body (gherkin fence included), no commentary, no heading."
|
|
193
203
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
194
204
|
role: planner
|
|
195
205
|
answerFile: .spur/run/${vars.__runId}-idea-ac-content.md
|
|
@@ -221,6 +231,24 @@ states:
|
|
|
221
231
|
resultFile: .spur/run/${vars.__runId}-idea-ac-check.status
|
|
222
232
|
softFail: true
|
|
223
233
|
timeoutMs: 120000
|
|
234
|
+
# 0887 R4: requirement-inventory ↔ AC coverage, measured once at the same author/revise
|
|
235
|
+
# boundary. Soft shell (exit 0 always): the checker writes the PASS/FAIL status itself and
|
|
236
|
+
# the guards below consume the recorded result — never re-run the checker (0769 pattern).
|
|
237
|
+
# Repo-checkout path first, then the superskill-staged twin (handoff-finalize resolution
|
|
238
|
+
# shape); neither present fails closed to FAIL so readiness degrades visibly instead of
|
|
239
|
+
# silently skipping coverage.
|
|
240
|
+
- kind: shell
|
|
241
|
+
options:
|
|
242
|
+
command: >-
|
|
243
|
+
mkdir -p .spur/run &&
|
|
244
|
+
S=plugins/sp/scripts/idea-coverage-check.ts &&
|
|
245
|
+
if [ ! -f "$S" ]; then S="$(superskill script path sp idea-coverage-check.ts 2>/dev/null)"; fi &&
|
|
246
|
+
if [ -n "$S" ] && [ -f "$S" ]; then
|
|
247
|
+
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";
|
|
248
|
+
else
|
|
249
|
+
printf 'FAIL run=%s checker not found — run superskill install sp\n' "$__runId" | tee ".spur/run/$__runId-idea-coverage.reason" >&2;
|
|
250
|
+
printf 'FAIL\n' > ".spur/run/$__runId-idea-coverage.status";
|
|
251
|
+
fi
|
|
224
252
|
|
|
225
253
|
- id: feature-check
|
|
226
254
|
description: >
|
|
@@ -235,11 +263,14 @@ states:
|
|
|
235
263
|
the transition guards route directly from ac-generate to the appropriate next
|
|
236
264
|
state, so this state is only entered in interactive mode. On failure, the retry
|
|
237
265
|
cap routes back to ac-generate (≤3 retries) or escalates to failed.
|
|
266
|
+
Requirement coverage (.spur/run/${vars.__runId}-idea-coverage.status, 0887 R4) is part of
|
|
267
|
+
the recorded results this gate surfaces: a FAIL there means some inventory items have no
|
|
268
|
+
covering scenario — answer no to route back to ac-generate for revision if needed.
|
|
238
269
|
pause: true
|
|
239
270
|
onEnter:
|
|
240
271
|
- kind: hitl.confirm
|
|
241
272
|
options:
|
|
242
|
-
prompt: "Feature check for ${vars.featureId}. Review the AC and confirm to proceed? (Failures route back to ac-generate for revision, capped at 3 retries.)"
|
|
273
|
+
prompt: "Feature check for ${vars.featureId}. Review the AC and confirm to proceed? Requirement coverage status: $(cat .spur/run/${vars.__runId}-idea-coverage.status 2>/dev/null || echo unknown) — reason: $(cat .spur/run/${vars.__runId}-idea-coverage.reason 2>/dev/null || echo n/a) (.spur/run/${vars.__runId}-idea-coverage.status[.reason]). (Failures route back to ac-generate for revision, capped at 3 retries.)"
|
|
243
274
|
|
|
244
275
|
- id: system-design
|
|
245
276
|
description: >
|
|
@@ -264,7 +295,7 @@ states:
|
|
|
264
295
|
- kind: agent.run
|
|
265
296
|
options:
|
|
266
297
|
agent: ${vars.planningAgent}
|
|
267
|
-
input: 'Run sp:sys-architecture for feature ${vars.featureId}. Read the brainstorm artifact, feature AC, and .spur/run/${vars.__runId}-idea-design-review.md. Produce ADR entries, architecture updates, and design satellites (docs/design/<slug>.md)
|
|
298
|
+
input: 'The operator''s ask of record is .spur/run/${vars.__runId}-idea-input.md (idea persisted verbatim at start; authoritative). Run sp:sys-architecture for feature ${vars.featureId}. Read the brainstorm artifact, feature AC, and .spur/run/${vars.__runId}-idea-design-review.md. Produce ADR entries, architecture updates, and design satellites (docs/design/<slug>.md) per the constitution edit rules; never write task or feature corpus files directly. Design-review contract (fixed headings `## Proposed design`, `## Operator feedback`, `## Reconciliation`): first pass — write the proposed summary under `## Proposed design`, leave `## Operator feedback` empty; retry after operator feedback — revise the design/ADR artifacts, document changes under `## Reconciliation`, and when feedback invalidates an Acceptance Criteria scenario write the revised AC section body to a file, persist via `$spurBin feature update "$featureId" --section "Acceptance Criteria" --from-file <file>`.'
|
|
268
299
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
269
300
|
role: planner
|
|
270
301
|
expectFile: .spur/run/${vars.__runId}-idea-design-review.md
|
|
@@ -331,7 +362,7 @@ states:
|
|
|
331
362
|
- kind: agent.run
|
|
332
363
|
options:
|
|
333
364
|
agent: ${vars.planningAgent}
|
|
334
|
-
input: "Run sp:spec-decomposition for feature ${vars.featureId} per skill references/decomposition.md § Idea-pipeline emission: sizing first, then the batch JSON at .spur/run/${vars.__runId}-idea-task-batch.json and the private task-order sidecar at .spur/run/${vars.__runId}-idea-task-order.json."
|
|
365
|
+
input: "The operator's ask of record is .spur/run/${vars.__runId}-idea-input.md (the idea argument persisted verbatim at start; authoritative). Run sp:spec-decomposition for feature ${vars.featureId} per skill references/decomposition.md § Idea-pipeline emission: sizing first, then the batch JSON at .spur/run/${vars.__runId}-idea-task-batch.json and the private task-order sidecar at .spur/run/${vars.__runId}-idea-task-order.json."
|
|
335
366
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
336
367
|
role: planner
|
|
337
368
|
expectFile: .spur/run/${vars.__runId}-idea-task-batch.json
|
|
@@ -422,7 +453,9 @@ states:
|
|
|
422
453
|
# project's own computePlanningDigest), so the bounded prompt pins the skill
|
|
423
454
|
# reference instead of a command; artifacts are gated by answerFile/expectFile.
|
|
424
455
|
input: >-
|
|
425
|
-
|
|
456
|
+
The operator's ask of record is .spur/run/${vars.__runId}-idea-input.md (the idea
|
|
457
|
+
argument persisted verbatim at start; authoritative). Run the ready-prepare stage
|
|
458
|
+
for feature ${vars.featureId} per sp:spur-dev
|
|
426
459
|
references/planning-workflow.md § Step 5.6 (Ready preparation): read
|
|
427
460
|
.spur/run/${vars.__runId}-idea-batch-create-result.json and write
|
|
428
461
|
.spur/run/${vars.__runId}-idea-ready.json.
|
|
@@ -559,51 +592,60 @@ transitions:
|
|
|
559
592
|
|
|
560
593
|
# ── ac-generate: auto-skip (profile=auto) OR enter feature-check HITL gate (interactive) ──
|
|
561
594
|
# Declaration order: auto-skip guards tried FIRST (same pattern as task-pipeline review→verify
|
|
562
|
-
# and design-gen→handoff). Under profile=auto, the recorded `idea-ac-check` result
|
|
563
|
-
#
|
|
564
|
-
#
|
|
565
|
-
#
|
|
595
|
+
# and design-gen→handoff). Under profile=auto, the recorded `idea-ac-check` result and the
|
|
596
|
+
# recorded requirement-coverage status (0887 R4) route directly to the appropriate next
|
|
597
|
+
# state — guards never re-run the CLI or the checker (task 0769). Under interactive, the
|
|
598
|
+
# always fallback enters the feature-check state whose onEnter hitl.confirm pauses for
|
|
599
|
+
# operator confirmation (coverage is surfaced in that prompt; the operator's answer governs).
|
|
566
600
|
#
|
|
567
|
-
# Auto-skip 1: pass + design route → system-design (design=auto + needs_design != false)
|
|
601
|
+
# Auto-skip 1: pass + coverage + design route → system-design (design=auto + needs_design != false)
|
|
568
602
|
- from: ac-generate
|
|
569
603
|
to: system-design
|
|
570
|
-
description: "profile=auto, check passed, design route — run system design."
|
|
571
|
-
# (warn) 4
|
|
572
|
-
#
|
|
604
|
+
description: "profile=auto, check passed, requirements covered, design route — run system design."
|
|
605
|
+
# (warn) 4 commands: one persistent multi-assignment line captures both statuses; `test -a` folds the
|
|
606
|
+
# profile/ac and design/needs pairs (same operand semantics); guards never re-run the CLI (0769).
|
|
573
607
|
guard:
|
|
574
608
|
kind: shell
|
|
575
609
|
options:
|
|
576
|
-
command:
|
|
577
|
-
|
|
610
|
+
command: >-
|
|
611
|
+
ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" cov_status="$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)";
|
|
612
|
+
test "$profile" = auto -a "$ac_status" = PASS && test "$cov_status" = PASS && test "$design" = auto -a "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" != false
|
|
613
|
+
# Auto-skip 2: pass + coverage + skip-design route → decompose
|
|
578
614
|
- from: ac-generate
|
|
579
615
|
to: decompose
|
|
580
|
-
description: "profile=auto, check passed, skip-design route — go directly to decompose."
|
|
581
|
-
# (warn)
|
|
582
|
-
# pair
|
|
616
|
+
description: "profile=auto, check passed, requirements covered, skip-design route — go directly to decompose."
|
|
617
|
+
# (warn) 4 test segments: profile + inlined ac/coverage reads + the OR'd design=skip/(design=auto AND
|
|
618
|
+
# needs_design=false) pair folded into one `test` (`-a` binds tighter than `-o`), keeping one captured
|
|
619
|
+
# signal file authoritative for both routes (0769).
|
|
583
620
|
guard:
|
|
584
621
|
kind: shell
|
|
585
622
|
options:
|
|
586
|
-
command: 'test "$profile" = auto && test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS && (test "$design" = skip
|
|
587
|
-
# Auto-skip 3: check failed, retry < 3 → loop back to ac-generate (self-loop)
|
|
623
|
+
command: 'test "$profile" = auto && test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS && test "$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)" = PASS && test "$design" = skip -o "$design" = auto -a "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false'
|
|
624
|
+
# Auto-skip 3: check or coverage failed, retry < 3 → loop back to ac-generate (self-loop)
|
|
588
625
|
- from: ac-generate
|
|
589
626
|
to: ac-generate
|
|
590
|
-
description: "profile=auto, check failed, retry cap not reached — re-run ac-generate."
|
|
591
|
-
# (warn)
|
|
592
|
-
#
|
|
627
|
+
description: "profile=auto, check or coverage failed, retry cap not reached — re-run ac-generate."
|
|
628
|
+
# (warn) 5 commands: one persistent multi-assignment line captures both statuses and the retry count
|
|
629
|
+
# (with its 0 fallback); the failed-check pair stays verbatim and the profile gate folds into the retry
|
|
630
|
+
# test via `test -a`; the retry loop is the smallest honest formulation of cap<3 routing (0769).
|
|
593
631
|
guard:
|
|
594
632
|
kind: shell
|
|
595
633
|
options:
|
|
596
|
-
command:
|
|
597
|
-
|
|
634
|
+
command: >-
|
|
635
|
+
ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" cov_status="$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)" retry="$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)";
|
|
636
|
+
{ test "$ac_status" != PASS || test "$cov_status" != PASS; } && test "$profile" = auto -a "$retry" -lt 3
|
|
637
|
+
# Auto-skip 4: check or coverage failed, retry cap reached → escalate to failed
|
|
598
638
|
- from: ac-generate
|
|
599
639
|
to: failed
|
|
600
|
-
description: "profile=auto, check failed after 3 retries — escalate to failed."
|
|
601
|
-
# (warn)
|
|
602
|
-
#
|
|
640
|
+
description: "profile=auto, check or coverage failed after 3 retries — escalate to failed."
|
|
641
|
+
# (warn) 5 commands: mirror of the retry guard with cap>=3; keeping escalation and retry as one
|
|
642
|
+
# test-chain pair makes the cap boundary auditable in the diff (0769).
|
|
603
643
|
guard:
|
|
604
644
|
kind: shell
|
|
605
645
|
options:
|
|
606
|
-
command:
|
|
646
|
+
command: >-
|
|
647
|
+
ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" cov_status="$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)" retry="$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)";
|
|
648
|
+
{ test "$ac_status" != PASS || test "$cov_status" != PASS; } && test "$profile" = auto -a "$retry" -ge 3
|
|
607
649
|
# Interactive fallback: enter feature-check HITL gate
|
|
608
650
|
- from: ac-generate
|
|
609
651
|
to: feature-check
|
|
@@ -616,12 +658,14 @@ transitions:
|
|
|
616
658
|
- from: feature-check
|
|
617
659
|
to: system-design
|
|
618
660
|
description: Feature check passed, design route — run system design.
|
|
619
|
-
# (warn) 4
|
|
661
|
+
# (warn) 5 commands (named status capture + 4 conditions): HITL answer + captured status + design route; same shape as the
|
|
620
662
|
# ac-generate auto-skips, reading the same captured signal files (0769).
|
|
621
663
|
guard:
|
|
622
664
|
kind: shell
|
|
623
665
|
options:
|
|
624
|
-
command:
|
|
666
|
+
command: >-
|
|
667
|
+
ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)";
|
|
668
|
+
test "$__hitlAnswer" = yes && test "$ac_status" = PASS && test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" != false
|
|
625
669
|
- from: feature-check
|
|
626
670
|
to: decompose
|
|
627
671
|
description: Feature check passed, skip-design route — go directly to decompose.
|
|
@@ -634,20 +678,24 @@ transitions:
|
|
|
634
678
|
- from: feature-check
|
|
635
679
|
to: ac-generate
|
|
636
680
|
description: "Feature check failed — revise AC (retry cap: 3)."
|
|
637
|
-
# (warn) 4
|
|
681
|
+
# (warn) 5 commands (named status capture + 4 conditions): HITL reject/failed-status OR-pair + captured retry count; the
|
|
638
682
|
# interactive retry mirror of the ac-generate cap<3 guard (0769).
|
|
639
683
|
guard:
|
|
640
684
|
kind: shell
|
|
641
685
|
options:
|
|
642
|
-
command:
|
|
686
|
+
command: >-
|
|
687
|
+
ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)";
|
|
688
|
+
(test "$__hitlAnswer" = no || test "$ac_status" != PASS) && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -lt 3
|
|
643
689
|
- from: feature-check
|
|
644
690
|
to: failed
|
|
645
691
|
description: Feature check failed after 3 retries — escalate to failed.
|
|
646
|
-
# (warn) 4
|
|
692
|
+
# (warn) 5 commands (named status capture + 4 conditions): mirror of the revise guard with cap>=3 (0769).
|
|
647
693
|
guard:
|
|
648
694
|
kind: shell
|
|
649
695
|
options:
|
|
650
|
-
command:
|
|
696
|
+
command: >-
|
|
697
|
+
ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)";
|
|
698
|
+
(test "$__hitlAnswer" = no || test "$ac_status" != PASS) && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -ge 3
|
|
651
699
|
- from: feature-check
|
|
652
700
|
to: cancelled
|
|
653
701
|
description: Operator cancelled the feature-check gate.
|
|
@@ -603,10 +603,14 @@ transitions:
|
|
|
603
603
|
- from: precheck
|
|
604
604
|
to: implement
|
|
605
605
|
description: Deterministic size, evidence, and task checks are green — begin implementation.
|
|
606
|
+
# (warn) 5 commands: named size/evidence status reads + task check (legibility, 0874).
|
|
606
607
|
guard:
|
|
607
608
|
kind: shell
|
|
608
609
|
options:
|
|
609
|
-
command:
|
|
610
|
+
command: >-
|
|
611
|
+
size_status="$(cat .spur/run/$wbs-precheck-size.status 2>/dev/null)";
|
|
612
|
+
evidence_status="$(cat .spur/run/$wbs-precheck-evidence.status 2>/dev/null)";
|
|
613
|
+
test "$size_status" = PASS && test "$evidence_status" = PASS && $spurBin task check $wbs
|
|
610
614
|
- from: precheck
|
|
611
615
|
to: failed
|
|
612
616
|
description: Size and/or task check failed — stop before implement.
|
|
@@ -626,14 +630,18 @@ transitions:
|
|
|
626
630
|
guard:
|
|
627
631
|
kind: shell
|
|
628
632
|
options:
|
|
629
|
-
command:
|
|
633
|
+
command: >-
|
|
634
|
+
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
635
|
+
test "$gate_status" = PASS && test "$mode" = fast
|
|
630
636
|
- from: test
|
|
631
637
|
to: review
|
|
632
638
|
description: Quality gate already green and safety mode — proceed to review.
|
|
633
639
|
guard:
|
|
634
640
|
kind: shell
|
|
635
641
|
options:
|
|
636
|
-
command:
|
|
642
|
+
command: >-
|
|
643
|
+
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
644
|
+
test "$gate_status" = PASS && test "$mode" != fast
|
|
637
645
|
- from: test
|
|
638
646
|
to: test-fix
|
|
639
647
|
description: Quality gate red — start bounded fixall loop.
|
|
@@ -659,28 +667,40 @@ transitions:
|
|
|
659
667
|
guard:
|
|
660
668
|
kind: shell
|
|
661
669
|
options:
|
|
662
|
-
command:
|
|
670
|
+
command: >-
|
|
671
|
+
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
672
|
+
test "$gate_status" = PASS && test "$mode" = fast
|
|
663
673
|
- from: test-recheck
|
|
664
674
|
to: review
|
|
665
675
|
description: Quality gate green after fixall and safety mode — proceed to review.
|
|
666
676
|
guard:
|
|
667
677
|
kind: shell
|
|
668
678
|
options:
|
|
669
|
-
command:
|
|
679
|
+
command: >-
|
|
680
|
+
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
681
|
+
test "$gate_status" = PASS && test "$mode" != fast
|
|
670
682
|
- from: test-recheck
|
|
671
683
|
to: test-fix
|
|
672
684
|
description: Still red and under qualityGateMaxFixAttempts — another fixall hop.
|
|
685
|
+
# (warn) 5 commands: named gate status + fix attempts (legibility, 0874).
|
|
673
686
|
guard:
|
|
674
687
|
kind: shell
|
|
675
688
|
options:
|
|
676
|
-
command:
|
|
689
|
+
command: >-
|
|
690
|
+
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
691
|
+
fix_attempts="$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)";
|
|
692
|
+
test "$gate_status" = FAIL && test "$fix_attempts" -lt "$qualityGateMaxFixAttempts"
|
|
677
693
|
- from: test-recheck
|
|
678
694
|
to: failed
|
|
679
695
|
description: Still red after max fixall attempts — stop at failed (not silent abort).
|
|
696
|
+
# (warn) 5 commands: named gate status + fix attempts (legibility, 0874).
|
|
680
697
|
guard:
|
|
681
698
|
kind: shell
|
|
682
699
|
options:
|
|
683
|
-
command:
|
|
700
|
+
command: >-
|
|
701
|
+
gate_status="$(cat .spur/run/$wbs-test-gate.status 2>/dev/null)";
|
|
702
|
+
fix_attempts="$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)";
|
|
703
|
+
test "$gate_status" = FAIL && test "$fix_attempts" -ge "$qualityGateMaxFixAttempts"
|
|
684
704
|
# Defense: corrupt recheck status — failed, not review.
|
|
685
705
|
- from: test-recheck
|
|
686
706
|
to: failed
|
|
@@ -748,7 +768,16 @@ transitions:
|
|
|
748
768
|
kind: shell
|
|
749
769
|
options:
|
|
750
770
|
command: >-
|
|
751
|
-
jq -e --arg d "$proofDigest" --arg r "$__runId" --arg dd "$__definitionDigest" '
|
|
771
|
+
jq -e --arg d "$proofDigest" --arg r "$__runId" --arg dd "$__definitionDigest" '
|
|
772
|
+
.verdict == "PASS"
|
|
773
|
+
and (.proof.digest // "") == $d
|
|
774
|
+
and (.proof.stages.qualityGate.digest // "") == $d
|
|
775
|
+
and (.proof.stages.review.digest // "") == $d
|
|
776
|
+
and (.proof.stages.review.status // "") == "completed"
|
|
777
|
+
and (.proof.stages.verification.digest // "") == $d
|
|
778
|
+
and (.proof.runId // "") == $r
|
|
779
|
+
and (.proof.definitionDigest // "") == $dd
|
|
780
|
+
' ".spur/run/$wbs-verdict.json" >/dev/null 2>&1
|
|
752
781
|
- from: verify
|
|
753
782
|
to: test-fix
|
|
754
783
|
description: >-
|
|
@@ -760,8 +789,8 @@ transitions:
|
|
|
760
789
|
kind: shell
|
|
761
790
|
options:
|
|
762
791
|
command: >-
|
|
763
|
-
|
|
764
|
-
test -n "$
|
|
792
|
+
verdict="$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)";
|
|
793
|
+
test -n "$verdict" && test "$verdict" != PASS &&
|
|
765
794
|
test "$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)" -lt "$qualityGateMaxFixAttempts"
|
|
766
795
|
- from: verify
|
|
767
796
|
to: failed
|
|
@@ -778,6 +807,7 @@ transitions:
|
|
|
778
807
|
- from: record
|
|
779
808
|
to: done
|
|
780
809
|
description: Task check passed and the verdict proof block still names the captured digest — certify done.
|
|
810
|
+
# (warn) 5 commands: named verdict + proof digest reads after the task check (legibility, 0874).
|
|
781
811
|
guard:
|
|
782
812
|
kind: shell
|
|
783
813
|
options:
|
|
@@ -788,8 +818,9 @@ transitions:
|
|
|
788
818
|
# one shell line.
|
|
789
819
|
command: >-
|
|
790
820
|
$spurBin task check $wbs --as done &&
|
|
791
|
-
|
|
792
|
-
|
|
821
|
+
verdict="$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" &&
|
|
822
|
+
proof_digest="$(jq -r '.proof.digest // ""' .spur/run/$wbs-verdict.json 2>/dev/null)" &&
|
|
823
|
+
test "$verdict" = PASS && test "$proof_digest" = "$proofDigest"
|
|
793
824
|
- from: record
|
|
794
825
|
to: failed
|
|
795
826
|
description: Task check failed or proof evidence missing/malformed/mismatched — block before done.
|
|
@@ -13,10 +13,12 @@
|
|
|
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 -> metrics-record
|
|
16
|
+
# Shape: start -> task-resolve -> doc-sync -> learnings-append -> metrics-record
|
|
17
17
|
# -> feature-transition (conditional: if vars.feature set)
|
|
18
18
|
# -> branch-cleanup (conditional: if vars.merge=true)
|
|
19
19
|
# -> done
|
|
20
|
+
# doc-sync routes a contract violation to `repair` (cheap, no
|
|
21
|
+
# re-dispatch — ADR-118 pilot) and an executor failure to `failed`;
|
|
20
22
|
# task-resolve with a VALIDATED empty list short-circuits to `skipped`;
|
|
21
23
|
# invalid wrap input, an unresolved/non-completed task, a failed metrics
|
|
22
24
|
# capture, a failed required sync, or a failed feature gate routes to
|
|
@@ -72,7 +74,7 @@
|
|
|
72
74
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
73
75
|
kind: state-machine
|
|
74
76
|
name: wrapup-pipeline
|
|
75
|
-
version: "
|
|
77
|
+
version: "4"
|
|
76
78
|
description: "Post-execution wrap-up: doc-sync (doc drift + learning capture), metrics, feature-transition, branch-cleanup"
|
|
77
79
|
iterationBound: 10
|
|
78
80
|
initialState: start
|
|
@@ -168,13 +170,16 @@ states:
|
|
|
168
170
|
learnings (task 0607 R2: two adjacent agent.run hops merged, count 2 -> 1;
|
|
169
171
|
no operator-decision pause or verdict boundary sits between them). No dedicated
|
|
170
172
|
slash command yet — free-form skill pointer until a /sp:doc-evolve command
|
|
171
|
-
exists (ADR-043 residual).
|
|
172
|
-
a
|
|
173
|
-
|
|
173
|
+
exists (ADR-043 residual). This is the expensive stage; a contract violation
|
|
174
|
+
(a clean exit that missed its declared answerFile/expectFile post-condition)
|
|
175
|
+
routes to the cheap `repair` edge instead of a full re-dispatch (ADR-118
|
|
176
|
+
pilot, 0871) — `onError: continue` lets the transition guards read the
|
|
177
|
+
agent's result instead of halting the run.
|
|
174
178
|
onEnter:
|
|
175
179
|
# (warn) free-form prompt: no /sp:doc-evolve command surface yet (ADR-043
|
|
176
180
|
# residual, 0607 R2 one-query merge); capture is bounded by expectFile.
|
|
177
181
|
- kind: agent.run
|
|
182
|
+
onError: continue
|
|
178
183
|
options:
|
|
179
184
|
agent: ${vars.agent}
|
|
180
185
|
input: >-
|
|
@@ -192,6 +197,13 @@ states:
|
|
|
192
197
|
answerFile: .spur/run/${vars.__runId}-wrapup-learnings.md
|
|
193
198
|
expectFile: .spur/run/${vars.__runId}-wrapup-learnings.md
|
|
194
199
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
200
|
+
|
|
201
|
+
- id: learnings-append
|
|
202
|
+
description: >
|
|
203
|
+
Best-effort soft append of the captured learnings to .spur/memory/learnings.md
|
|
204
|
+
(0607 R2): an empty capture skips without aborting wrap-up. Runs only after
|
|
205
|
+
doc-sync's contract held; a contract violation never reaches this state.
|
|
206
|
+
onEnter:
|
|
195
207
|
# (warn) learnings append is intentionally soft (empty capture skips
|
|
196
208
|
# without aborting wrap-up, 0607 R2).
|
|
197
209
|
- kind: shell
|
|
@@ -207,6 +219,21 @@ states:
|
|
|
207
219
|
fi &&
|
|
208
220
|
exit 0
|
|
209
221
|
|
|
222
|
+
- id: repair
|
|
223
|
+
description: >
|
|
224
|
+
Contract-violation repair (ADR-118 pilot, 0871): doc-sync's agent.run missed
|
|
225
|
+
its declared post-condition after a clean exit, so wrap-up does NOT re-dispatch
|
|
226
|
+
the expensive agent on this attempt. The miss is recorded to a run-scoped
|
|
227
|
+
repair status and wrap-up proceeds to metrics-record — the run log and action
|
|
228
|
+
trace already name the violated contract and the observed value.
|
|
229
|
+
onEnter:
|
|
230
|
+
- kind: shell
|
|
231
|
+
options:
|
|
232
|
+
command: >-
|
|
233
|
+
mkdir -p .spur/run &&
|
|
234
|
+
printf 'contract-violation: doc-sync learnings capture missed its declared contract — repair skipped re-dispatch (ADR-118 pilot)\n' > ".spur/run/$__runId-wrapup-repair.status" &&
|
|
235
|
+
exit 0
|
|
236
|
+
|
|
210
237
|
- id: metrics-record
|
|
211
238
|
description: >
|
|
212
239
|
Append one JSONL row per task to .spur/memory/wrapup-metrics.jsonl deterministically.
|
|
@@ -354,10 +381,46 @@ transitions:
|
|
|
354
381
|
guard:
|
|
355
382
|
kind: always
|
|
356
383
|
|
|
357
|
-
# ──
|
|
384
|
+
# ── doc-sync: contract-first routing (ADR-118 pilot, 0871) ──
|
|
385
|
+
# Declaration order matters: the contract-violation edge is tried first, then
|
|
386
|
+
# success (action-ok), then the executor-failure defense (always) — a failed
|
|
387
|
+
# agent.run reaches these guards because doc-sync's agent.run declares
|
|
388
|
+
# onError: continue.
|
|
358
389
|
- from: doc-sync
|
|
390
|
+
to: repair
|
|
391
|
+
description: >
|
|
392
|
+
Contract violation (ADR-118): the agent exited 0 but missed its declared
|
|
393
|
+
post-condition. Route to the cheap repair edge — never re-dispatch the
|
|
394
|
+
full agent.run on this attempt.
|
|
395
|
+
trigger: contract-violation
|
|
396
|
+
guard:
|
|
397
|
+
kind: contract-violation
|
|
398
|
+
- from: doc-sync
|
|
399
|
+
to: learnings-append
|
|
400
|
+
description: Doc drift repair + learning capture succeeded — append learnings.
|
|
401
|
+
guard:
|
|
402
|
+
kind: action-ok
|
|
403
|
+
- from: doc-sync
|
|
404
|
+
to: failed
|
|
405
|
+
description: >
|
|
406
|
+
Executor failure (non-zero exit, signal, or dispatch error) — keep the
|
|
407
|
+
existing fail semantics; a contract violation never falls through here
|
|
408
|
+
because the contract-violation edge is declared first.
|
|
409
|
+
trigger: executor-failure
|
|
410
|
+
guard:
|
|
411
|
+
kind: always
|
|
412
|
+
|
|
413
|
+
# ── linear body: learnings-append -> metrics-record ──
|
|
414
|
+
- from: learnings-append
|
|
415
|
+
to: metrics-record
|
|
416
|
+
description: Learning capture appended (or soft-skipped) — record metrics.
|
|
417
|
+
guard:
|
|
418
|
+
kind: always
|
|
419
|
+
|
|
420
|
+
# ── repair: cheap path, no re-dispatch -> metrics-record ──
|
|
421
|
+
- from: repair
|
|
359
422
|
to: metrics-record
|
|
360
|
-
description:
|
|
423
|
+
description: Contract-violation repair recorded — proceed to metrics without re-dispatch.
|
|
361
424
|
guard:
|
|
362
425
|
kind: always
|
|
363
426
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.87",
|
|
4
4
|
"description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spur",
|
|
@@ -53,14 +53,14 @@
|
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@commander-js/extra-typings": "^14.0.0",
|
|
56
|
-
"@gobing-ai/ts-db": "^0.4.
|
|
57
|
-
"@gobing-ai/ts-ai-runner": "^0.4.
|
|
58
|
-
"@gobing-ai/ts-dual-workflow-engine": "^0.4.
|
|
59
|
-
"@gobing-ai/ts-infra": "^0.4.
|
|
60
|
-
"@gobing-ai/ts-llm-jsonl-importer": "^0.4.
|
|
61
|
-
"@gobing-ai/ts-rule-engine": "^0.4.
|
|
62
|
-
"@gobing-ai/ts-runtime": "^0.4.
|
|
63
|
-
"@gobing-ai/ts-utils": "^0.4.
|
|
56
|
+
"@gobing-ai/ts-db": "^0.4.67",
|
|
57
|
+
"@gobing-ai/ts-ai-runner": "^0.4.67",
|
|
58
|
+
"@gobing-ai/ts-dual-workflow-engine": "^0.4.67",
|
|
59
|
+
"@gobing-ai/ts-infra": "^0.4.67",
|
|
60
|
+
"@gobing-ai/ts-llm-jsonl-importer": "^0.4.67",
|
|
61
|
+
"@gobing-ai/ts-rule-engine": "^0.4.67",
|
|
62
|
+
"@gobing-ai/ts-runtime": "^0.4.67",
|
|
63
|
+
"@gobing-ai/ts-utils": "^0.4.67",
|
|
64
64
|
"@types/bun": "1.3.14",
|
|
65
65
|
"@types/figlet": "^1.7.0",
|
|
66
66
|
"@types/node-notifier": "8.0.5",
|