@gobing-ai/spur 0.3.86 → 0.3.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/config/config.example.yaml +9 -0
- package/config/plugin-scripts.json +4 -0
- package/config/rules/strict/runtime-boundaries.yaml +1 -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/workflow-candidates.json +13 -35
- package/config/workflows/feature-lifecycle.yaml +6 -0
- package/config/workflows/feature-verification.yaml +6 -5
- package/config/workflows/idea-pipeline.yaml +89 -36
- package/config/workflows/task-pipeline.yaml +25 -0
- package/package.json +9 -9
- package/plugins/sp/README.md +9 -6
- package/plugins/sp/commands/dev-idea.md +9 -2
- package/plugins/sp/commands/dev-refactor.md +33 -0
- package/plugins/sp/commands/dev-refine.md +25 -7
- package/plugins/sp/commands/dev-refineall.md +9 -6
- package/plugins/sp/lib/idea-handoff.generated.mjs +160 -152
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +1 -1
- package/plugins/sp/scripts/idea-coverage-check.ts +168 -0
- package/plugins/sp/scripts/inline-pipeline-parity-check.ts +114 -3
- package/plugins/sp/scripts/inline-run-setup.ts +28 -18
- 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/agent.md +92 -9
- 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-dev/SKILL.md +33 -33
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +24 -0
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +99 -26
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +27 -5
- package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +11 -1
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +33 -1
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +10 -6
- 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/spur-config.schema.json +14 -2
- package/schemas/task-batch.schema.json +2 -2
- package/spur.js +2012 -487
- package/web/_astro/{BoardApp.yBBcFXWP.js → BoardApp.CDUcHlTJ.js} +67 -67
- package/web/_astro/BoardApp.CaCGU_uX.js +1 -0
- package/web/_astro/{TaskDetail.DqFJbRFc.js → TaskDetail.DwTmbQp5.js} +1 -1
- package/web/_astro/{arc.DL-BpHoi.js → arc.BzF71EFI.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.9IdQYyDq.js → architectureDiagram-3BPJPVTR.jvdDahWM.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.BKsFCqTl.js → blockDiagram-GPEHLZMM.zSg4AmFD.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.DhwI0dh1.js → c4Diagram-AAUBKEIU.BkUIUQWH.js} +1 -1
- package/web/_astro/channel.SSVY0JPQ.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.B3QVmQ9S.js → chunk-2J33WTMH.DvfQ_f50.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.DBSuqs9F.js → chunk-4BX2VUAB.DuI4gQqX.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.BSYTWAYD.js → chunk-55IACEB6.D3BWBOpF.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.cWVuxXfS.js → chunk-727SXJPM.3QSi0a9M.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.DpU_Ob3d.js → chunk-AQP2D5EJ.xazCQrAF.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.BykFkyji.js → chunk-FMBD7UC4.B2g6u4rA.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.DwgHlMdY.js → chunk-ND2GUHAM.wWwWs99t.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.CusXUGWM.js → chunk-QZHKN3VN.BD5g3qa9.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.fx0ObzkN.js → classDiagram-4FO5ZUOK.C7CzCdsX.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.fx0ObzkN.js → classDiagram-v2-Q7XG4LA2.C7CzCdsX.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.Z4HgOlsd.js → cose-bilkent-S5V4N54A.Xyiau0gw.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.B5dIZHJu.js → cynefin-OW5HDTMX.BeC5MWas.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.DT70Q_Yw.js → dagre-BM42HDAG.yZbMN9vc.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.DqHA3XBF.js → diagram-2AECGRRQ.Cmo2zQM-.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.BmCem957.js → diagram-5GNKFQAL.D033eSVi.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.sn0-hrE0.js → diagram-KO2AKTUF.CR6k3Y3G.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.BSHe9tVc.js → diagram-LMA3HP47.x7mwu8jz.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.DHIc-86k.js → diagram-OG6HWLK6.D8aTTvUr.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.Bxayrs7v.js → erDiagram-TEJ5UH35.BoBqcKXQ.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.BkzoE_5I.js → flowDiagram-I6XJVG4X.D3mTQdrU.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.okT6CvTo.js → ganttDiagram-6RSMTGT7.H-cqgIh-.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.CJuYbhC7.js → gitGraphDiagram-PVQCEYII.B6s9zbfC.js} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.RqLy7nBo.js → infoDiagram-5YYISTIA.BzgCoV6P.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.BwIcoagw.js → ishikawaDiagram-YF4QCWOH.BZzVhy1-.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.UB1VbWtH.js → journeyDiagram-JHISSGLW.BV3195Py.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.AaxMKpTk.js → kanban-definition-UN3LZRKU.BjRd2DWz.js} +1 -1
- package/web/_astro/{linear.Nv_xOUjP.js → linear.BILTgS5N.js} +1 -1
- package/web/_astro/{mermaid.core.Bc4LqQgX.js → mermaid.core.DBy_WKeW.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.oKUvU_qi.js → mindmap-definition-RKZ34NQL.BiEjaI4-.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.DQk0oo03.js → pieDiagram-4H26LBE5.i_8V5pIn.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.BdDjESDa.js → quadrantDiagram-W4KKPZXB.BWaW3MHn.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.C2u9hUeH.js → requirementDiagram-4Y6WPE33.CzddBbtg.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.CDEoiJST.js → sankeyDiagram-5OEKKPKP.X2ww0e-D.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.D_hT_GAT.js → sequenceDiagram-3UESZ5HK.DSA4kTcc.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.DI8RYG0b.js → stateDiagram-AJRCARHV.D0DtFSpR.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.Bkxz4DnP.js → stateDiagram-v2-BHNVJYJU.BfQq0zQv.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.DSY-kH3-.js → timeline-definition-PNZ67QCA.Dmlrgi1m.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.CpaDtuGr.js → vennDiagram-CIIHVFJN.D5mpl00Z.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.DujQWvo8.js → wardleyDiagram-YWT4CUSO.Df4BdzO4.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.DcM5Y4b9.js → xychartDiagram-2RQKCTM6.DiTRreKN.js} +1 -1
- package/web/index.html +1 -1
- package/web/_astro/BoardApp.CJiqp5pS.js +0 -1
- package/web/_astro/channel.CX5453qQ.js +0 -1
|
@@ -133,9 +133,18 @@ agent:
|
|
|
133
133
|
# A disabled profile stays visible to `spur agent doctor` but never routes
|
|
134
134
|
# (no role, team, stage, or explicit selection). Flip back to enabled by
|
|
135
135
|
# removing the line or setting disabled: false.
|
|
136
|
+
# Quota refresh is external: schedule `spur agent usage` (cron/launchd) to
|
|
137
|
+
# capture provider usage and record quota-owned availability observations.
|
|
138
|
+
# spur serve never runs it (B6 0892; docs/design/session-pinned-dispatch.md §3.4).
|
|
139
|
+
# A bare `true` is operator-owned (only humans write booleans). Automatic
|
|
140
|
+
# writers (quota/probe checks) emit the ownership object instead; an
|
|
141
|
+
# operator-owned disable is never auto-re-enabled (B6 0890).
|
|
136
142
|
# - name: retired-profile
|
|
137
143
|
# agent: omp
|
|
138
144
|
# disabled: true
|
|
145
|
+
# - name: quota-limited
|
|
146
|
+
# agent: omp
|
|
147
|
+
# disabled: { owner: quota, since: 2026-02-14T09:30:00.000Z, reason: agent.quota.exhausted quota-limited }
|
|
139
148
|
- name: pi-dsv4-flash-volc
|
|
140
149
|
agent: pi
|
|
141
150
|
# tier: standard
|
|
@@ -58,6 +58,7 @@ rules:
|
|
|
58
58
|
- "packages/app/src/services/token-ledger-watcher.ts" # node:fs watch() live watcher
|
|
59
59
|
- "packages/app/src/services/project-registry.ts" # atomic projects.json persistence
|
|
60
60
|
- "packages/app/src/services/slash-commands-service.ts" # synchronous ~/.config/spur/slash_commands.json persistence (mirrors project-registry.ts)
|
|
61
|
+
- "packages/app/src/services/agent-usage-producer.ts" # atomic agent-usage snapshot write (tmp + rename, mirrors project-registry.ts; task 0892 R1)
|
|
61
62
|
- "packages/app/src/services/history-service.ts" # versioned analyze artifact + bounded-errors sidecar + latest.json symlink pointer (task 0474); ts-runtime FileSystem seam has no symlink, so the pointer uses node:fs directly (mirrors project-registry.ts persistence exemption)
|
|
62
63
|
- "packages/app/src/observability/workflow-run-log-sink.ts" # sync FD append for mid-run tail-able all-in-one run log (task 0426 / feature D2); append() is sync from the observability bus
|
|
63
64
|
- "apps/cli/src/commands/workflow.ts" # FD byte-window tail of the mid-run run log for `workflow trace --follow` streaming (task 0428 / feature D2); readSync at offset over the observability sink's FDs
|
|
@@ -23,6 +23,8 @@ updated_at: "{{ CREATED_AT }}"
|
|
|
23
23
|
## Acceptance Criteria
|
|
24
24
|
|
|
25
25
|
```gherkin
|
|
26
|
+
# Keep the Feature: line (feature check L3.ac-bdd-error without it). Each Scenario: title is the
|
|
27
|
+
# identity key tasks reference verbatim ("- [ ] AC1 — <title>"); number R1, R2, …; never rename after tasks link.
|
|
26
28
|
Feature: {{ NAME }}
|
|
27
29
|
|
|
28
30
|
Scenario: Basic acceptance
|
|
@@ -23,11 +23,11 @@ updated_at: "{{ CREATED_AT }}"
|
|
|
23
23
|
|
|
24
24
|
### Requirements
|
|
25
25
|
|
|
26
|
-
<!-- Constraints the eventual direction must satisfy, if known. -->
|
|
26
|
+
<!-- One R-item per line, exactly `- [ ] R1. <text>` (checkbox + `R<n>.`); `spur task check` flags any other form. Constraints the eventual direction must satisfy, if known. -->
|
|
27
27
|
|
|
28
28
|
### Acceptance Criteria
|
|
29
29
|
|
|
30
|
-
<!--
|
|
30
|
+
<!-- Number items AC1, AC2, … (never R<n> — that is the Requirements namespace): `- [ ] AC1 — <feature scenario title without its R-number>` bullets or `Scenario: AC1 — <title>` blocks; add `(req: R<n>)` to bind a task requirement; task-only checks go in prose below, or set `ac_altitude: task-local`. Keep empty if not applicable. -->
|
|
31
31
|
|
|
32
32
|
### Q&A
|
|
33
33
|
|
|
@@ -23,11 +23,11 @@ updated_at: "{{ CREATED_AT }}"
|
|
|
23
23
|
|
|
24
24
|
### Requirements
|
|
25
25
|
|
|
26
|
-
<!-- R-
|
|
26
|
+
<!-- One R-item per line, exactly `- [ ] R1. <text>` (checkbox + `R<n>.`); `spur task check` flags any other form. Derive from the linked feature or refined task scope. -->
|
|
27
27
|
|
|
28
28
|
### Acceptance Criteria
|
|
29
29
|
|
|
30
|
-
<!--
|
|
30
|
+
<!-- Number items AC1, AC2, … (never R<n> — that is the Requirements namespace): `- [ ] AC1 — <feature scenario title without its R-number>` bullets or `Scenario: AC1 — <title>` blocks; add `(req: R<n>)` to bind a task requirement; task-only checks go in prose below, or set `ac_altitude: task-local`. Do not leave placeholder AC here. -->
|
|
31
31
|
|
|
32
32
|
### Q&A
|
|
33
33
|
|
|
@@ -23,11 +23,11 @@ updated_at: "{{ CREATED_AT }}"
|
|
|
23
23
|
|
|
24
24
|
### Requirements
|
|
25
25
|
|
|
26
|
-
<!-- R-
|
|
26
|
+
<!-- One R-item per line, exactly `- [ ] R1. <text>` (checkbox + `R<n>.`); `spur task check` flags any other form. Include repro/expected behavior if it helps traceability. -->
|
|
27
27
|
|
|
28
28
|
### Acceptance Criteria
|
|
29
29
|
|
|
30
|
-
<!--
|
|
30
|
+
<!-- Number items AC1, AC2, … (never R<n> — that is the Requirements namespace): `- [ ] AC1 — <feature scenario title without its R-number>` bullets or `Scenario: AC1 — <title>` blocks; add `(req: R<n>)` to bind a task requirement; task-only checks go in prose below, or set `ac_altitude: task-local`. Use a regression scenario proving the bug is fixed. -->
|
|
31
31
|
|
|
32
32
|
### Q&A
|
|
33
33
|
|
|
@@ -23,11 +23,11 @@ updated_at: "{{ CREATED_AT }}"
|
|
|
23
23
|
|
|
24
24
|
### Requirements
|
|
25
25
|
|
|
26
|
-
<!-- R-
|
|
26
|
+
<!-- One R-item per line, exactly `- [ ] R1. <text>` (checkbox + `R<n>.`); `spur task check` flags any other form. Keep empty if not applicable. -->
|
|
27
27
|
|
|
28
28
|
### Acceptance Criteria
|
|
29
29
|
|
|
30
|
-
<!--
|
|
30
|
+
<!-- Number items AC1, AC2, … (never R<n> — that is the Requirements namespace): `- [ ] AC1 — <feature scenario title without its R-number>` bullets or `Scenario: AC1 — <title>` blocks; add `(req: R<n>)` to bind a task requirement; task-only checks go in prose below, or set `ac_altitude: task-local`. Keep empty if not applicable. -->
|
|
31
31
|
|
|
32
32
|
### Q&A
|
|
33
33
|
|
|
@@ -33,11 +33,11 @@ in the reviewed PR/commit/diff). Fix in priority order (P1 → P2 → …); re-r
|
|
|
33
33
|
|
|
34
34
|
### Requirements
|
|
35
35
|
|
|
36
|
-
<!-- R-
|
|
36
|
+
<!-- One R-item per line, exactly `- [ ] R1. <text>` (checkbox + `R<n>.`); `spur task check` flags any other form. Fill after triage/refinement from the findings. -->
|
|
37
37
|
|
|
38
38
|
### Acceptance Criteria
|
|
39
39
|
|
|
40
|
-
<!--
|
|
40
|
+
<!-- Number items AC1, AC2, … (never R<n> — that is the Requirements namespace): `- [ ] AC1 — <feature scenario title without its R-number>` bullets or `Scenario: AC1 — <title>` blocks; add `(req: R<n>)` to bind a task requirement; task-only checks go in prose below, or set `ac_altitude: task-local`. Keep empty until the review task becomes executable work. -->
|
|
41
41
|
|
|
42
42
|
### Q&A
|
|
43
43
|
|
|
@@ -23,11 +23,11 @@ updated_at: "{{ CREATED_AT }}"
|
|
|
23
23
|
|
|
24
24
|
### Requirements
|
|
25
25
|
|
|
26
|
-
<!-- R-
|
|
26
|
+
<!-- One R-item per line, exactly `- [ ] R1. <text>` (checkbox + `R<n>.`); `spur task check` flags any other form. Keep empty until requirements are known. -->
|
|
27
27
|
|
|
28
28
|
### Acceptance Criteria
|
|
29
29
|
|
|
30
|
-
<!--
|
|
30
|
+
<!-- Number items AC1, AC2, … (never R<n> — that is the Requirements namespace): `- [ ] AC1 — <feature scenario title without its R-number>` bullets or `Scenario: AC1 — <title>` blocks; add `(req: R<n>)` to bind a task requirement; task-only checks go in prose below, or set `ac_altitude: task-local`. Keep empty if this task has no objective AC yet. -->
|
|
31
31
|
|
|
32
32
|
### Q&A
|
|
33
33
|
|
|
@@ -1,41 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"note": "Workflow graph-change promotion candidates (task 0873, feature D62; ADR-076 amendment). A candidate is shadow-run against recorded real-run inputs and is promoted into the canonical definition or deleted by its named deadline — never left as a standing parallel <name>2.yaml. `verdict` is null while pending and is filled by `bun scripts/spur-dev.ts promotion evaluate <id>`; `promotion check` (spur-check-feature) fails any candidate still present past its deadline
|
|
4
|
-
"candidates": [
|
|
3
|
+
"note": "Workflow graph-change promotion candidates (task 0873, feature D62; ADR-076 amendment). A candidate is shadow-run against recorded real-run inputs and is promoted into the canonical definition or deleted by its named deadline — never left as a standing parallel <name>2.yaml. `verdict` is null while pending and is filled by `bun scripts/spur-dev.ts promotion evaluate <id>`; `promotion check` (spur-check-feature) fails any candidate still present past its deadline, any unreferenced parallel definition in config/workflows/, and (0877 R8) any retired definition with real (non-dry) terminal runs lacking a recorded decision in `retirements[]`.",
|
|
4
|
+
"candidates": [],
|
|
5
|
+
"retirements": [
|
|
5
6
|
{
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"agentRunCount": 1
|
|
17
|
-
},
|
|
18
|
-
"verdict": {
|
|
19
|
-
"decision": "delete",
|
|
20
|
-
"evaluatedAt": "2026-09-17T15:33:27.274Z",
|
|
21
|
-
"agentRunCount": {
|
|
22
|
-
"runs": 1,
|
|
23
|
-
"mean": 1,
|
|
24
|
-
"median": 1,
|
|
25
|
-
"min": 1,
|
|
26
|
-
"max": 1
|
|
27
|
-
},
|
|
28
|
-
"agentRunDurationMs": {
|
|
29
|
-
"runs": 1,
|
|
30
|
-
"mean": 505937,
|
|
31
|
-
"median": 505937,
|
|
32
|
-
"min": 505937,
|
|
33
|
-
"max": 505937
|
|
34
|
-
},
|
|
35
|
-
"candidateAgentRunCount": 1,
|
|
36
|
-
"canonicalAgentRunCount": 1,
|
|
37
|
-
"reason": "candidate projects 1 agent.run action(s), not fewer than the canonical wrapup-pipeline count of 1 (1 real run(s), median 1 agent.run action(s)/run, median 505937 ms/run) — ADR-076 rejected a graph adding a model hop"
|
|
38
|
-
}
|
|
7
|
+
"name": "planning-pipeline",
|
|
8
|
+
"recordedBy": "0872 (ADR-072/075 composition-baseline pass 2dc86579a)",
|
|
9
|
+
"date": "2026-08-19",
|
|
10
|
+
"rationale": "Planning pipeline superseded by the task-pipeline planning stages; 3 real terminal runs retained in history."
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "task-pipeline2",
|
|
14
|
+
"recordedBy": "ADR-076 (commit 017ac7a30)",
|
|
15
|
+
"date": "2026-08-20",
|
|
16
|
+
"rationale": "Standing parallel definition deleted with the D5-N fixture promotion bar; 5 real terminal runs retained in history."
|
|
39
17
|
}
|
|
40
18
|
]
|
|
41
19
|
}
|
|
@@ -37,6 +37,12 @@ states:
|
|
|
37
37
|
description: >
|
|
38
38
|
Feature verification work (DD-13). Makes verification derivable —
|
|
39
39
|
listable, event-triggerable, assignable.
|
|
40
|
+
onEnter:
|
|
41
|
+
# Caller wiring (task 0880, ADR-119): entering verification RUNS the
|
|
42
|
+
# feature-scoped pass instead of only passively reading its status file.
|
|
43
|
+
- kind: shell
|
|
44
|
+
options:
|
|
45
|
+
command: '$spurBin workflow run feature-verification.yaml --vars "{\"featureId\":\"$featureId\"}"'
|
|
40
46
|
- id: blocked
|
|
41
47
|
description: Impediment; work suspended.
|
|
42
48
|
- id: done
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
# Owns a lifecycle boundary no per-task graph owns: the repo-wide checks whose
|
|
4
4
|
# invariant spans the repository rather than a single task's diff — corpus
|
|
5
5
|
# consistency, contract baselines, dependency/schema drift, the frozen History
|
|
6
|
-
# surface, and the repo-wide test set. They run once per feature
|
|
7
|
-
#
|
|
8
|
-
# verifying→done guard refuses to complete the
|
|
9
|
-
# PASS (ADR-119 consequence: a feature is not
|
|
6
|
+
# surface, and the repo-wide test set. They run once per feature, deliberately
|
|
7
|
+
# the slow pass; `feature-lifecycle`'s verifying entry invokes this workflow (task
|
|
8
|
+
# 0880 caller wiring), and its verifying→done guard refuses to complete the
|
|
9
|
+
# feature until this pass records PASS (ADR-119 consequence: a feature is not
|
|
10
|
+
# done until it passes).
|
|
10
11
|
#
|
|
11
12
|
# Run: spur workflow run feature-verification.yaml --vars '{"featureId":"D62"}'
|
|
12
13
|
#
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
kind: state-machine
|
|
23
24
|
name: feature-verification
|
|
24
25
|
version: "1"
|
|
25
|
-
description: "Feature-scoped verification pass (ADR-119): runs the repo-wide check set once per feature
|
|
26
|
+
description: "Feature-scoped verification pass (ADR-119): runs the repo-wide check set once per feature and records PASS/FAIL. Invoked by feature-lifecycle's verifying entry."
|
|
26
27
|
iterationBound: 2
|
|
27
28
|
initialState: verify
|
|
28
29
|
terminalStates:
|
|
@@ -94,10 +94,17 @@ states:
|
|
|
94
94
|
agent: "${vars.agent}"
|
|
95
95
|
role: planner
|
|
96
96
|
resolvedAgentVar: planningAgent
|
|
97
|
+
# B7 R1 (0894): also pin the role once — __executor.planner feeds stage
|
|
98
|
+
# dispatch so no later idea stage re-walks the doctor ladder.
|
|
99
|
+
roles:
|
|
100
|
+
planner: "${vars.agent}"
|
|
97
101
|
- kind: shell
|
|
98
102
|
options:
|
|
99
103
|
command: >-
|
|
100
|
-
|
|
104
|
+
mkdir -p .spur/run &&
|
|
105
|
+
printf '%s\n' "$idea" > ".spur/run/$__runId-idea-input.md" &&
|
|
106
|
+
awk 'NF' ".spur/run/$__runId-idea-input.md" | grep -q . ||
|
|
107
|
+
printf 'FAIL\n' > ".spur/run/$__runId-idea-precheck-doctor.status"
|
|
101
108
|
|
|
102
109
|
- id: discovery
|
|
103
110
|
description: >
|
|
@@ -109,14 +116,19 @@ states:
|
|
|
109
116
|
brainstorm also emits the idea-evaluation report to .spur/run/${vars.__runId}-idea-eval-report.md
|
|
110
117
|
(template: the `sp:spur-dev` skill's `idea-evaluation` reference — named by skill, not by
|
|
111
118
|
repo path, because `spur init` never scaffolds `plugins/sp/` into a seeded project).
|
|
119
|
+
The operator's verbatim idea argument is persisted at .spur/run/${vars.__runId}-idea-input.md
|
|
120
|
+
(written by start; the authoritative ask every model-bearing stage reads).
|
|
112
121
|
expectFile fails a silent no-op discovery (no eval report).
|
|
113
122
|
onEnter:
|
|
114
123
|
- kind: agent.run
|
|
115
124
|
options:
|
|
116
125
|
agent: ${vars.planningAgent}
|
|
117
|
-
input: "
|
|
126
|
+
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
127
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
119
128
|
role: planner
|
|
129
|
+
# B7 R6 (0894): planner stages declare fresh — the role default is stated
|
|
130
|
+
# explicitly so the definition is self-documenting.
|
|
131
|
+
session: fresh
|
|
120
132
|
expectFile: .spur/run/${vars.__runId}-idea-eval-report.md
|
|
121
133
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
122
134
|
|
|
@@ -143,14 +155,18 @@ states:
|
|
|
143
155
|
checklists never enter Goal. Shell actions then persist both sections through
|
|
144
156
|
`spur feature update --section Goal|Scope --from-file ...`; a missing/empty artifact
|
|
145
157
|
stops the state. Prefer the enhanced idea from .spur/run/${vars.__runId}-idea-eval-report.md as
|
|
146
|
-
context; do not overwrite vars.idea.
|
|
158
|
+
context; do not overwrite vars.idea. The operator's verbatim ask of record is
|
|
159
|
+
.spur/run/${vars.__runId}-idea-input.md (persisted at start; authoritative over any
|
|
160
|
+
paraphrase).
|
|
147
161
|
onEnter:
|
|
148
162
|
- kind: agent.run
|
|
149
163
|
options:
|
|
150
164
|
agent: ${vars.planningAgent}
|
|
151
|
-
input: 'Create a feature for the idea
|
|
165
|
+
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
166
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
153
167
|
role: planner
|
|
168
|
+
# B7 R6 (0894): declared fresh policy (planner default).
|
|
169
|
+
session: fresh
|
|
154
170
|
expectFile: .spur/run/${vars.__runId}-idea-feature-id.txt
|
|
155
171
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
156
172
|
- kind: file.read.into-var
|
|
@@ -182,6 +198,9 @@ states:
|
|
|
182
198
|
check records FAIL and routes through the capped retry loop via guards that consume the
|
|
183
199
|
recorded result — it never fails the run (the engine's default onError policy is `fail`,
|
|
184
200
|
so an in-action check failure would kill the run before the retry edges are evaluated).
|
|
201
|
+
Requirement coverage is MEASURED alongside it by the soft idea-coverage-check shell
|
|
202
|
+
(0887 R4): the recorded coverage status conjuncts into the profile=auto ac-generate
|
|
203
|
+
guards below so uncovered inventory items route through the same capped retry loop.
|
|
185
204
|
onEnter:
|
|
186
205
|
- kind: shell
|
|
187
206
|
options:
|
|
@@ -189,9 +208,11 @@ states:
|
|
|
189
208
|
- kind: agent.run
|
|
190
209
|
options:
|
|
191
210
|
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.
|
|
211
|
+
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
212
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
194
213
|
role: planner
|
|
214
|
+
# B7 R6 (0894): declared fresh policy (planner default).
|
|
215
|
+
session: fresh
|
|
195
216
|
answerFile: .spur/run/${vars.__runId}-idea-ac-content.md
|
|
196
217
|
expectFile: .spur/run/${vars.__runId}-idea-ac-content.md
|
|
197
218
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
@@ -221,6 +242,24 @@ states:
|
|
|
221
242
|
resultFile: .spur/run/${vars.__runId}-idea-ac-check.status
|
|
222
243
|
softFail: true
|
|
223
244
|
timeoutMs: 120000
|
|
245
|
+
# 0887 R4: requirement-inventory ↔ AC coverage, measured once at the same author/revise
|
|
246
|
+
# boundary. Soft shell (exit 0 always): the checker writes the PASS/FAIL status itself and
|
|
247
|
+
# the guards below consume the recorded result — never re-run the checker (0769 pattern).
|
|
248
|
+
# Repo-checkout path first, then the superskill-staged twin (handoff-finalize resolution
|
|
249
|
+
# shape); neither present fails closed to FAIL so readiness degrades visibly instead of
|
|
250
|
+
# silently skipping coverage.
|
|
251
|
+
- kind: shell
|
|
252
|
+
options:
|
|
253
|
+
command: >-
|
|
254
|
+
mkdir -p .spur/run &&
|
|
255
|
+
S=plugins/sp/scripts/idea-coverage-check.ts &&
|
|
256
|
+
if [ ! -f "$S" ]; then S="$(superskill script path sp idea-coverage-check.ts 2>/dev/null)"; fi &&
|
|
257
|
+
if [ -n "$S" ] && [ -f "$S" ]; then
|
|
258
|
+
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";
|
|
259
|
+
else
|
|
260
|
+
printf 'FAIL run=%s checker not found — run superskill install sp\n' "$__runId" | tee ".spur/run/$__runId-idea-coverage.reason" >&2;
|
|
261
|
+
printf 'FAIL\n' > ".spur/run/$__runId-idea-coverage.status";
|
|
262
|
+
fi
|
|
224
263
|
|
|
225
264
|
- id: feature-check
|
|
226
265
|
description: >
|
|
@@ -235,11 +274,14 @@ states:
|
|
|
235
274
|
the transition guards route directly from ac-generate to the appropriate next
|
|
236
275
|
state, so this state is only entered in interactive mode. On failure, the retry
|
|
237
276
|
cap routes back to ac-generate (≤3 retries) or escalates to failed.
|
|
277
|
+
Requirement coverage (.spur/run/${vars.__runId}-idea-coverage.status, 0887 R4) is part of
|
|
278
|
+
the recorded results this gate surfaces: a FAIL there means some inventory items have no
|
|
279
|
+
covering scenario — answer no to route back to ac-generate for revision if needed.
|
|
238
280
|
pause: true
|
|
239
281
|
onEnter:
|
|
240
282
|
- kind: hitl.confirm
|
|
241
283
|
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.)"
|
|
284
|
+
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
285
|
|
|
244
286
|
- id: system-design
|
|
245
287
|
description: >
|
|
@@ -264,9 +306,11 @@ states:
|
|
|
264
306
|
- kind: agent.run
|
|
265
307
|
options:
|
|
266
308
|
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)
|
|
309
|
+
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
310
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
269
311
|
role: planner
|
|
312
|
+
# B7 R6 (0894): declared fresh policy (planner default).
|
|
313
|
+
session: fresh
|
|
270
314
|
expectFile: .spur/run/${vars.__runId}-idea-design-review.md
|
|
271
315
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
272
316
|
# expectFile proves existence only, and the onEnter skeleton pre-creates the file — so an
|
|
@@ -331,9 +375,11 @@ states:
|
|
|
331
375
|
- kind: agent.run
|
|
332
376
|
options:
|
|
333
377
|
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."
|
|
378
|
+
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
379
|
# Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
|
|
336
380
|
role: planner
|
|
381
|
+
# B7 R6 (0894): declared fresh policy (planner default).
|
|
382
|
+
session: fresh
|
|
337
383
|
expectFile: .spur/run/${vars.__runId}-idea-task-batch.json
|
|
338
384
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
339
385
|
# R1 (0518): the task-order sidecar is the ordering contract for handoff-finalize.
|
|
@@ -417,12 +463,16 @@ states:
|
|
|
417
463
|
agent: ${vars.planningAgent}
|
|
418
464
|
# Declared Layer-1 role (0538 R2), same planner executor as decompose.
|
|
419
465
|
role: planner
|
|
466
|
+
# B7 R6 (0894): declared fresh policy (planner default).
|
|
467
|
+
session: fresh
|
|
420
468
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
421
469
|
# (warn) non-slash pointer: the 0788 checklist is per-checkout (digest via the
|
|
422
470
|
# project's own computePlanningDigest), so the bounded prompt pins the skill
|
|
423
471
|
# reference instead of a command; artifacts are gated by answerFile/expectFile.
|
|
424
472
|
input: >-
|
|
425
|
-
|
|
473
|
+
The operator's ask of record is .spur/run/${vars.__runId}-idea-input.md (the idea
|
|
474
|
+
argument persisted verbatim at start; authoritative). Run the ready-prepare stage
|
|
475
|
+
for feature ${vars.featureId} per sp:spur-dev
|
|
426
476
|
references/planning-workflow.md § Step 5.6 (Ready preparation): read
|
|
427
477
|
.spur/run/${vars.__runId}-idea-batch-create-result.json and write
|
|
428
478
|
.spur/run/${vars.__runId}-idea-ready.json.
|
|
@@ -559,57 +609,60 @@ transitions:
|
|
|
559
609
|
|
|
560
610
|
# ── ac-generate: auto-skip (profile=auto) OR enter feature-check HITL gate (interactive) ──
|
|
561
611
|
# 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
|
-
#
|
|
612
|
+
# and design-gen→handoff). Under profile=auto, the recorded `idea-ac-check` result and the
|
|
613
|
+
# recorded requirement-coverage status (0887 R4) route directly to the appropriate next
|
|
614
|
+
# state — guards never re-run the CLI or the checker (task 0769). Under interactive, the
|
|
615
|
+
# always fallback enters the feature-check state whose onEnter hitl.confirm pauses for
|
|
616
|
+
# operator confirmation (coverage is surfaced in that prompt; the operator's answer governs).
|
|
566
617
|
#
|
|
567
|
-
# Auto-skip 1: pass + design route → system-design (design=auto + needs_design != false)
|
|
618
|
+
# Auto-skip 1: pass + coverage + design route → system-design (design=auto + needs_design != false)
|
|
568
619
|
- from: ac-generate
|
|
569
620
|
to: system-design
|
|
570
|
-
description: "profile=auto, check passed, design route — run system design."
|
|
571
|
-
# (warn)
|
|
572
|
-
#
|
|
621
|
+
description: "profile=auto, check passed, requirements covered, design route — run system design."
|
|
622
|
+
# (warn) 4 commands: one persistent multi-assignment line captures both statuses; `test -a` folds the
|
|
623
|
+
# profile/ac and design/needs pairs (same operand semantics); guards never re-run the CLI (0769).
|
|
573
624
|
guard:
|
|
574
625
|
kind: shell
|
|
575
626
|
options:
|
|
576
627
|
command: >-
|
|
577
|
-
ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)";
|
|
578
|
-
test "$profile" = auto && test "$
|
|
579
|
-
# Auto-skip 2: pass + skip-design route → decompose
|
|
628
|
+
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)";
|
|
629
|
+
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
|
|
630
|
+
# Auto-skip 2: pass + coverage + skip-design route → decompose
|
|
580
631
|
- from: ac-generate
|
|
581
632
|
to: decompose
|
|
582
|
-
description: "profile=auto, check passed, skip-design route — go directly to decompose."
|
|
583
|
-
# (warn)
|
|
584
|
-
# pair
|
|
633
|
+
description: "profile=auto, check passed, requirements covered, skip-design route — go directly to decompose."
|
|
634
|
+
# (warn) 4 test segments: profile + inlined ac/coverage reads + the OR'd design=skip/(design=auto AND
|
|
635
|
+
# needs_design=false) pair folded into one `test` (`-a` binds tighter than `-o`), keeping one captured
|
|
636
|
+
# signal file authoritative for both routes (0769).
|
|
585
637
|
guard:
|
|
586
638
|
kind: shell
|
|
587
639
|
options:
|
|
588
|
-
command: 'test "$profile" = auto && test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS && (test "$design" = skip
|
|
589
|
-
# Auto-skip 3: check failed, retry < 3 → loop back to ac-generate (self-loop)
|
|
640
|
+
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'
|
|
641
|
+
# Auto-skip 3: check or coverage failed, retry < 3 → loop back to ac-generate (self-loop)
|
|
590
642
|
- from: ac-generate
|
|
591
643
|
to: ac-generate
|
|
592
|
-
description: "profile=auto, check failed, retry cap not reached — re-run ac-generate."
|
|
593
|
-
# (warn) 5 commands
|
|
594
|
-
#
|
|
644
|
+
description: "profile=auto, check or coverage failed, retry cap not reached — re-run ac-generate."
|
|
645
|
+
# (warn) 5 commands: one persistent multi-assignment line captures both statuses and the retry count
|
|
646
|
+
# (with its 0 fallback); the failed-check pair stays verbatim and the profile gate folds into the retry
|
|
647
|
+
# test via `test -a`; the retry loop is the smallest honest formulation of cap<3 routing (0769).
|
|
595
648
|
guard:
|
|
596
649
|
kind: shell
|
|
597
650
|
options:
|
|
598
651
|
command: >-
|
|
599
|
-
ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)";
|
|
600
|
-
test "$
|
|
601
|
-
# Auto-skip 4: check failed, retry cap reached → escalate to failed
|
|
652
|
+
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)";
|
|
653
|
+
{ test "$ac_status" != PASS || test "$cov_status" != PASS; } && test "$profile" = auto -a "$retry" -lt 3
|
|
654
|
+
# Auto-skip 4: check or coverage failed, retry cap reached → escalate to failed
|
|
602
655
|
- from: ac-generate
|
|
603
656
|
to: failed
|
|
604
|
-
description: "profile=auto, check failed after 3 retries — escalate to failed."
|
|
605
|
-
# (warn) 5 commands
|
|
606
|
-
#
|
|
657
|
+
description: "profile=auto, check or coverage failed after 3 retries — escalate to failed."
|
|
658
|
+
# (warn) 5 commands: mirror of the retry guard with cap>=3; keeping escalation and retry as one
|
|
659
|
+
# test-chain pair makes the cap boundary auditable in the diff (0769).
|
|
607
660
|
guard:
|
|
608
661
|
kind: shell
|
|
609
662
|
options:
|
|
610
663
|
command: >-
|
|
611
|
-
ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)";
|
|
612
|
-
test "$
|
|
664
|
+
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)";
|
|
665
|
+
{ test "$ac_status" != PASS || test "$cov_status" != PASS; } && test "$profile" = auto -a "$retry" -ge 3
|
|
613
666
|
# Interactive fallback: enter feature-check HITL gate
|
|
614
667
|
- from: ac-generate
|
|
615
668
|
to: feature-check
|
|
@@ -196,6 +196,18 @@ states:
|
|
|
196
196
|
command: >-
|
|
197
197
|
mkdir -p .spur/run .spur/memory; RUN_ID="$__runId"; [ -n "$RUN_ID" ] || RUN_ID="pipeline-$wbs"; case "$RUN_ID" in *'$'*|*'{'*|*'}'*|*vars.*|*/*|*'\'*|*..*) echo "route-reason: refusing unsafe run id: $RUN_ID" >&2; exit 1 ;; esac; REASON_FILE=".spur/run/$RUN_ID-route-reason.txt"; jq -rn --arg m "$mode" '{"fast":"fast:evidence complete+consistent","":"safety:standard verification","unknown":"safety:unknown evidence quality","conflict":"safety:conflicting evidence"}[$m] // "safety:unrecognized evidence (mode=\($m))"' > "$REASON_FILE"; printf '%s %s %s\n' "$RUN_ID" "$wbs" "$(cat "$REASON_FILE")" >> .spur/memory/task-pipeline-routes.log; exit 0
|
|
198
198
|
|
|
199
|
+
# (e) B7 R1 (0894): resolve every declared role ONCE at precheck — pins land
|
|
200
|
+
# in __executor.<role> run vars so stage dispatch performs no doctor call.
|
|
201
|
+
# Soft probe: failures mark the status file and stages degrade to their own
|
|
202
|
+
# resolution; nothing here aborts the run.
|
|
203
|
+
- kind: doctor.probe
|
|
204
|
+
options:
|
|
205
|
+
resultFile: ".spur/run/${vars.__runId}-precheck-roles.status"
|
|
206
|
+
spurBin: "${vars.spurBin}"
|
|
207
|
+
roles:
|
|
208
|
+
coder: "${vars.implementAgent}"
|
|
209
|
+
reviewer: "${vars.agent}"
|
|
210
|
+
|
|
199
211
|
- id: implement
|
|
200
212
|
description: >
|
|
201
213
|
Run agent-driven implementation via /sp:dev-run --mode implement, THEN move the
|
|
@@ -216,6 +228,9 @@ states:
|
|
|
216
228
|
# Pure slash command only (ADR-043). Anti-recursion / implement discipline
|
|
217
229
|
# Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
|
|
218
230
|
role: coder
|
|
231
|
+
# B7 R3/R6 (0894): coder stages reuse the role session — the test-fix hop
|
|
232
|
+
# resumes the implement session instead of re-reading the task cold.
|
|
233
|
+
session: reuse
|
|
219
234
|
# lives in /sp:dev-run --mode implement → sp:code-implementation, not YAML prose.
|
|
220
235
|
input: /sp:dev-run --mode implement ${vars.wbs} --auto
|
|
221
236
|
timeoutMs: ${vars.implementTimeoutMs}
|
|
@@ -356,6 +371,9 @@ states:
|
|
|
356
371
|
# R3 (0482): `--findings` names the failing anchors inline; `--gate-log` remains
|
|
357
372
|
# Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
|
|
358
373
|
role: coder
|
|
374
|
+
# B7 R3/R6 (0894): coder stages reuse the role session — the fix hop
|
|
375
|
+
# continues the implement session it is repairing.
|
|
376
|
+
session: reuse
|
|
359
377
|
# the full-context escape hatch when the digest is not enough.
|
|
360
378
|
input: /sp:dev-fixall "${vars.qualityGateCmd}" --gate-log .spur/run/${vars.wbs}-test-gate.log --findings "${vars.gateFindings}"
|
|
361
379
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
@@ -417,7 +435,11 @@ states:
|
|
|
417
435
|
expectFile: .spur/run/${vars.__runId}-review-answer.txt
|
|
418
436
|
# Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
|
|
419
437
|
role: reviewer
|
|
438
|
+
# B7 R3/R6 (0894): declared fresh policy (reviewer default) — the action
|
|
439
|
+
# result records this as declared, not defaulted. `freshSession: true` is
|
|
440
|
+
# kept as the action-level hard guarantee (0710 R2 structural assertion).
|
|
420
441
|
freshSession: true
|
|
442
|
+
session: fresh
|
|
421
443
|
priority: ${vars.taskPriority}
|
|
422
444
|
compareExecutorWith: implement
|
|
423
445
|
timeoutMs: ${vars.stepTimeoutMs}
|
|
@@ -477,7 +499,10 @@ states:
|
|
|
477
499
|
input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
|
|
478
500
|
# Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
|
|
479
501
|
role: reviewer
|
|
502
|
+
# B7 R3/R6 (0894): declared fresh policy (reviewer default).
|
|
503
|
+
# `freshSession: true` kept as the action-level hard guarantee (0710 R2).
|
|
480
504
|
freshSession: true
|
|
505
|
+
session: fresh
|
|
481
506
|
priority: ${vars.taskPriority}
|
|
482
507
|
compareExecutorWith: implement
|
|
483
508
|
timeoutMs: ${vars.stepTimeoutMs}
|