@gobing-ai/spur 0.3.67 → 0.3.69

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.
Files changed (79) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/corpus-baseline.json +2 -50
  3. package/config/templates/docs/99_PROJECT_CONSTITUTION.md +21 -16
  4. package/config/workflow-composition-baseline.json +110 -60
  5. package/config/workflows/basic.yaml +1 -1
  6. package/config/workflows/docs-pipeline.yaml +99 -23
  7. package/config/workflows/feature-dev.yaml +1 -1
  8. package/config/workflows/idea-pipeline.yaml +21 -23
  9. package/config/workflows/task-pipeline.yaml +233 -121
  10. package/config/workflows/wayfinder-resolution.yaml +1 -1
  11. package/config/workflows/wrapup-pipeline.yaml +1 -1
  12. package/package.json +9 -9
  13. package/plugins/sp/README.md +6 -7
  14. package/plugins/sp/commands/dev-idea.md +5 -3
  15. package/plugins/sp/commands/dev-plan.md +3 -1
  16. package/plugins/sp/commands/dev-review-session.md +2 -1
  17. package/plugins/sp/hooks/context-post-tool.ts +101 -2
  18. package/plugins/sp/hooks/context-session-start.ts +22 -1
  19. package/plugins/sp/plugin.json +1 -1
  20. package/plugins/sp/scripts/stage-registry-adapter.ts +144 -2
  21. package/plugins/sp/scripts/surface-drift-inventory.ts +2 -15
  22. package/plugins/sp/scripts/task-size-precheck.ts +21 -79
  23. package/plugins/sp/skills/session-review/SKILL.md +16 -0
  24. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +42 -17
  25. package/plugins/sp/skills/spur-dev/references/dev-operations.md +6 -6
  26. package/plugins/sp/skills/spur-dev/references/execution-batch.md +80 -11
  27. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +18 -13
  28. package/spur.js +2062 -609
  29. package/web/_astro/{BoardApp.BEtcJqde.js → BoardApp.BQFbkeqq.js} +15 -15
  30. package/web/_astro/BoardApp.CTkqrhWd.js +1 -0
  31. package/web/_astro/{TaskDetail.ClAbCXom.js → TaskDetail.Dl2Eaj1w.js} +1 -1
  32. package/web/_astro/{arc.CCvf51_y.js → arc.uG14rp8A.js} +1 -1
  33. package/web/_astro/{architectureDiagram-3BPJPVTR.C0cb0J5M.js → architectureDiagram-3BPJPVTR.Dye6uD_x.js} +1 -1
  34. package/web/_astro/{blockDiagram-GPEHLZMM.CIyjqoCE.js → blockDiagram-GPEHLZMM.B9Pkh7Hb.js} +1 -1
  35. package/web/_astro/{c4Diagram-AAUBKEIU.fs14IuFs.js → c4Diagram-AAUBKEIU.C2x7SC_X.js} +1 -1
  36. package/web/_astro/channel.Dsvulp7W.js +1 -0
  37. package/web/_astro/{chunk-2J33WTMH.CaBKv4ZO.js → chunk-2J33WTMH.D2p4-nWk.js} +1 -1
  38. package/web/_astro/{chunk-4BX2VUAB.BOllTPto.js → chunk-4BX2VUAB.S-6jf33o.js} +1 -1
  39. package/web/_astro/{chunk-55IACEB6.ChEof0O4.js → chunk-55IACEB6.DVXj4Fdh.js} +1 -1
  40. package/web/_astro/{chunk-727SXJPM.Co2kdjD8.js → chunk-727SXJPM.Dz689FMN.js} +1 -1
  41. package/web/_astro/{chunk-AQP2D5EJ.SWmfcnog.js → chunk-AQP2D5EJ.KxYj5TnI.js} +1 -1
  42. package/web/_astro/{chunk-FMBD7UC4.rDAFifF3.js → chunk-FMBD7UC4.itTQyHQB.js} +1 -1
  43. package/web/_astro/{chunk-ND2GUHAM.BCnoXKCw.js → chunk-ND2GUHAM.euSrbJf5.js} +1 -1
  44. package/web/_astro/{chunk-QZHKN3VN.RSmy2hDO.js → chunk-QZHKN3VN.OWASJRQy.js} +1 -1
  45. package/web/_astro/{classDiagram-4FO5ZUOK.Be7PEfrX.js → classDiagram-4FO5ZUOK.BLvrlpNO.js} +1 -1
  46. package/web/_astro/{classDiagram-v2-Q7XG4LA2.Be7PEfrX.js → classDiagram-v2-Q7XG4LA2.BLvrlpNO.js} +1 -1
  47. package/web/_astro/{cose-bilkent-S5V4N54A.BkUp2aSK.js → cose-bilkent-S5V4N54A.XBF-rmyD.js} +1 -1
  48. package/web/_astro/{cynefin-OW5HDTMX.BegGGlUV.js → cynefin-OW5HDTMX.DlCx762Z.js} +1 -1
  49. package/web/_astro/{dagre-BM42HDAG.BkUdjsaC.js → dagre-BM42HDAG.D17Rshxv.js} +1 -1
  50. package/web/_astro/{diagram-2AECGRRQ.E9vugt3-.js → diagram-2AECGRRQ.AhBIVJC8.js} +1 -1
  51. package/web/_astro/{diagram-5GNKFQAL.Dj4yeHXB.js → diagram-5GNKFQAL.C9ximjyC.js} +1 -1
  52. package/web/_astro/{diagram-KO2AKTUF.Buaquwli.js → diagram-KO2AKTUF.CZb7Ru_9.js} +1 -1
  53. package/web/_astro/{diagram-LMA3HP47.BV3dgGgm.js → diagram-LMA3HP47.BW7LwqoS.js} +1 -1
  54. package/web/_astro/{diagram-OG6HWLK6.Cnx3s-tc.js → diagram-OG6HWLK6.XC025W0V.js} +1 -1
  55. package/web/_astro/{erDiagram-TEJ5UH35.DKK_abu4.js → erDiagram-TEJ5UH35.CpMXmBDP.js} +1 -1
  56. package/web/_astro/{flowDiagram-I6XJVG4X.BNuu9fbm.js → flowDiagram-I6XJVG4X.D2ednJWg.js} +1 -1
  57. package/web/_astro/{ganttDiagram-6RSMTGT7.b16KUMjy.js → ganttDiagram-6RSMTGT7.BjL9FGKO.js} +1 -1
  58. package/web/_astro/{gitGraphDiagram-PVQCEYII.Kh41lbG5.js → gitGraphDiagram-PVQCEYII.B90g1VGk.js} +1 -1
  59. package/web/_astro/{infoDiagram-5YYISTIA.DEWBXkp-.js → infoDiagram-5YYISTIA.RqgycKtQ.js} +1 -1
  60. package/web/_astro/{ishikawaDiagram-YF4QCWOH.DiAdmcL6.js → ishikawaDiagram-YF4QCWOH.Ctn-zt6a.js} +1 -1
  61. package/web/_astro/{journeyDiagram-JHISSGLW.D1Ki7IRm.js → journeyDiagram-JHISSGLW.DJhT8Ctp.js} +1 -1
  62. package/web/_astro/{kanban-definition-UN3LZRKU.CWUhrQpc.js → kanban-definition-UN3LZRKU.BY1QdejI.js} +1 -1
  63. package/web/_astro/{linear.BaFsgcCe.js → linear.Di7YObSt.js} +1 -1
  64. package/web/_astro/{mermaid.core.CHw_AsGy.js → mermaid.core.CbxtJS3Q.js} +4 -4
  65. package/web/_astro/{mindmap-definition-RKZ34NQL.UIhghgmN.js → mindmap-definition-RKZ34NQL.CxvR4g_J.js} +1 -1
  66. package/web/_astro/{pieDiagram-4H26LBE5.D05l3JUA.js → pieDiagram-4H26LBE5.jNWqnBHH.js} +1 -1
  67. package/web/_astro/{quadrantDiagram-W4KKPZXB.BcWIhIcE.js → quadrantDiagram-W4KKPZXB.BCp12MbA.js} +1 -1
  68. package/web/_astro/{requirementDiagram-4Y6WPE33.B1rYvKGn.js → requirementDiagram-4Y6WPE33.Dxhm4TyR.js} +1 -1
  69. package/web/_astro/{sankeyDiagram-5OEKKPKP.CKylVRC4.js → sankeyDiagram-5OEKKPKP.BtQXp4J9.js} +1 -1
  70. package/web/_astro/{sequenceDiagram-3UESZ5HK.Dm3uA_s4.js → sequenceDiagram-3UESZ5HK.BWEM1R_Q.js} +1 -1
  71. package/web/_astro/{stateDiagram-AJRCARHV.Bgca_BLe.js → stateDiagram-AJRCARHV.BG3wUkWB.js} +1 -1
  72. package/web/_astro/{stateDiagram-v2-BHNVJYJU.C1T7YFrG.js → stateDiagram-v2-BHNVJYJU.BLtMeFVP.js} +1 -1
  73. package/web/_astro/{timeline-definition-PNZ67QCA.ZOHJn3Sn.js → timeline-definition-PNZ67QCA.D5fHo0az.js} +1 -1
  74. package/web/_astro/{vennDiagram-CIIHVFJN.DegZitjD.js → vennDiagram-CIIHVFJN.0DcuMluU.js} +1 -1
  75. package/web/_astro/{wardleyDiagram-YWT4CUSO.BDsC115d.js → wardleyDiagram-YWT4CUSO.BZ-dxgHm.js} +1 -1
  76. package/web/_astro/{xychartDiagram-2RQKCTM6.D0MO70ea.js → xychartDiagram-2RQKCTM6.Bg-XWF7z.js} +1 -1
  77. package/web/index.html +1 -1
  78. package/web/_astro/BoardApp.DBEin4N5.js +0 -1
  79. package/web/_astro/channel.BGn_DUCD.js +0 -1
@@ -7,7 +7,7 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "sp",
10
- "version": "0.3.67",
10
+ "version": "0.3.69",
11
11
  "source": "./plugins/sp"
12
12
  }
13
13
  ]
@@ -67,12 +67,6 @@
67
67
  "code": "L4.dogfood-missing",
68
68
  "severity": "warning"
69
69
  },
70
- {
71
- "kind": "feature",
72
- "id": "A6",
73
- "code": "L4.scenario-unverified",
74
- "severity": "warning"
75
- },
76
70
  {
77
71
  "kind": "feature",
78
72
  "id": "B1",
@@ -1653,50 +1647,8 @@
1653
1647
  },
1654
1648
  {
1655
1649
  "kind": "task",
1656
- "id": "0703",
1657
- "code": "L4.gate-language",
1658
- "severity": "warning"
1659
- },
1660
- {
1661
- "kind": "task",
1662
- "id": "0704",
1663
- "code": "L4.prerequisite-not-done",
1664
- "severity": "warning"
1665
- },
1666
- {
1667
- "kind": "task",
1668
- "id": "0706",
1669
- "code": "L4.gate-language",
1670
- "severity": "warning"
1671
- },
1672
- {
1673
- "kind": "task",
1674
- "id": "0707",
1675
- "code": "L4.prerequisite-not-done",
1676
- "severity": "warning"
1677
- },
1678
- {
1679
- "kind": "task",
1680
- "id": "0708",
1681
- "code": "L4.prerequisite-not-done",
1682
- "severity": "warning"
1683
- },
1684
- {
1685
- "kind": "task",
1686
- "id": "0709",
1687
- "code": "L4.prerequisite-not-done",
1688
- "severity": "warning"
1689
- },
1690
- {
1691
- "kind": "task",
1692
- "id": "0710",
1693
- "code": "L4.prerequisite-not-done",
1694
- "severity": "warning"
1695
- },
1696
- {
1697
- "kind": "task",
1698
- "id": "0712",
1699
- "code": "L4.prerequisite-not-done",
1650
+ "id": "0719",
1651
+ "code": "L4.stale-line-anchor",
1700
1652
  "severity": "warning"
1701
1653
  }
1702
1654
  ]
@@ -61,10 +61,10 @@ Tools are bound by **role**; roles are permanent, bindings evolve. This table is
61
61
  project-variable section besides Lessons — update the binding when the toolchain migrates.
62
62
 
63
63
  | Role | Current binding | Notes |
64
- |------|-----------------|-------|
65
- | Spec lifecycle — tasks | _(project tool — e.g. `spur task` or a task CLI)_ | Task files are tool-owned; edit through the tool, never the Write tool |
66
- | Spec lifecycle — features | _(project tool — e.g. `spur feature` or a feature CLI)_ | Same tool-owned rule |
67
- | Delivery harness | _(project harness — e.g. `spur`)_ | Quality gates are self-hosted through it where possible |
64
+ | ------ | ----------------- | ------- |
65
+ | Spec lifecycle — tasks | *(project tool — e.g. `spur task` or a task CLI)* | Task files are tool-owned; edit through the tool, never the Write tool |
66
+ | Spec lifecycle — features | *(project tool — e.g. `spur feature` or a feature CLI)* | Same tool-owned rule |
67
+ | Delivery harness | *(project harness — e.g. `spur`)* | Quality gates are self-hosted through it where possible |
68
68
  | Agent-facing wrappers | per-project plugin dir (e.g. `plugins/sp/`) | **Fat Skills, thin others:** skills are the SSOT for agent-facing behavior and may be arbitrarily rich; slash commands and subagents are thin wrappers of skills (every agent supports skills; command/subagent support varies) |
69
69
 
70
70
  ## 4. Common file layout
@@ -75,7 +75,7 @@ Each project's `AGENTS.md` embeds an instantiated copy of this table (§4.4). A
75
75
  **one** doc; other docs link to it, never restate it.
76
76
 
77
77
  | Doc | Owns the question | Authority | Read / edit when |
78
- |-----|-------------------|-----------|------------------|
78
+ | ----- | ------------------- | ----------- | ------------------ |
79
79
  | `docs/00_ADR.md` | **WHY** — which cross-cutting decision was made, and the one-line reason | **Authoritative** (wins all content) | Read before any structural change; add a dated entry before diverging from a decision |
80
80
  | `docs/01_PRD.md` | **WHAT** — product vision, users, scope (in / out / deferred) | **Authoritative on scope** | Read before adding a command/feature; edit when scope changes |
81
81
  | `docs/02_ROADMAP.md` | **WHEN** — phases, current vs deferred, sequencing | Derived | Read to place work in a phase; edit when phase status changes |
@@ -97,7 +97,7 @@ Each project's `AGENTS.md` embeds an instantiated copy of this table (§4.4). A
97
97
  ### 4.2 Working layers (outside the authority chain)
98
98
 
99
99
  | Location | Purpose | Rules |
100
- |----------|---------|-------|
100
+ | ---------- | --------- | ------- |
101
101
  | `docs/plans/YYYY-MM-DD-<topic>.md` | Dated working documents: research, triage, design discussions, decision records-in-progress | They **record**, they do not **govern**. Once concluded, immutable except dated correction sections. Decisions they reach must be promoted into `00`–`05` to take effect |
102
102
  | `docs/tasks/` | Task files | Tool-owned (§3). Never edited with raw file writes |
103
103
  | other `docs/` folders | Optional scratch (analysis, refactor notes, ...) | Nothing in the authority chain may depend on them |
@@ -190,7 +190,7 @@ it. Each trigger below has a stable ID (referenced by doc frontmatter `sync:` li
190
190
  names the docs that must be touched **in the same commit / same change**:
191
191
 
192
192
  | ID | When this happens | Touch (same change) |
193
- |----|-------------------|---------------------|
193
+ | ---- | ------------------- | --------------------- |
194
194
  | T1 | New cross-cutting decision, or reversal of one | `00` **first** (dated entry), then `03` mechanism, `01` if scope shifts |
195
195
  | T2 | A code change would contradict an existing ADR | **Stop.** Add the superseding/amending ADR entry first — never silently diverge |
196
196
  | T3 | Command, flag, config key, env var, schema, or DTO added/changed | `04` + the `AGENTS.md` surface block |
@@ -361,6 +361,11 @@ with raw file writes.
361
361
  5. Surfaces that are decided-but-unbuilt are flagged as planned with their ADR pointer, and
362
362
  marked "do not invoke as if they exist".
363
363
  6. Re-synced whenever this file changes the map or process (§4.4).
364
+ 7. Deterministic size ceiling: repo-root `AGENTS.md` and `config/templates/AGENTS.md` stay at or
365
+ below **20480 UTF-8 bytes** (20 KiB), enforced by
366
+ `apps/cli/tests/agents-md-portable-alignment.test.ts` (task 0705). This byte gate guards the
367
+ platform load limit and is separate from rule 4's approximate instruction budget. Over
368
+ ceiling: cut or move content per rules 2–3, or compact via `sp:doc-evolve`.
364
369
 
365
370
  ### 6.8 This file (`99`)
366
371
 
@@ -420,35 +425,35 @@ if it recurs, a new rule in §6.
420
425
 
421
426
  ### Lessons for `docs/00_ADR.md`
422
427
 
423
- _(empty — add lessons as the project evolves)_
428
+ *(empty — add lessons as the project evolves)*
424
429
 
425
430
  ### Lessons for `docs/01_PRD.md`
426
431
 
427
- _(empty — add lessons as the project evolves)_
432
+ *(empty — add lessons as the project evolves)*
428
433
 
429
434
  ### Lessons for `docs/02_ROADMAP.md`
430
435
 
431
- _(empty — add lessons as the project evolves)_
436
+ *(empty — add lessons as the project evolves)*
432
437
 
433
438
  ### Lessons for `docs/03_ARCHITECTURE.md`
434
439
 
435
- _(empty — add lessons as the project evolves)_
440
+ *(empty — add lessons as the project evolves)*
436
441
 
437
442
  ### Lessons for `docs/04_DESIGN.md`
438
443
 
439
- _(empty — add lessons as the project evolves)_
444
+ *(empty — add lessons as the project evolves)*
440
445
 
441
446
  ### Lessons for `docs/05_FEATURES.md`
442
447
 
443
- _(empty — add lessons as the project evolves)_
448
+ *(empty — add lessons as the project evolves)*
444
449
 
445
450
  ### Lessons for `AGENTS.md`
446
451
 
447
- _(empty — add lessons as the project evolves)_
452
+ *(empty — add lessons as the project evolves)*
448
453
 
449
454
  ### Lessons for this file (`99`)
450
455
 
451
- _(empty — add lessons as the project evolves)_
456
+ *(empty — add lessons as the project evolves)*
452
457
 
453
458
  ## 9. Bootstrapping a new project
454
459
 
@@ -470,4 +475,4 @@ Checklist to instantiate this structure in a fresh repo:
470
475
  gate, conventions. Symlink `CLAUDE.md` (and equivalents) to it.
471
476
  9. Wire the §3 tools (spec lifecycle, harness) per their own docs.
472
477
  10. First-session rule for any agent: read `AGENTS.md` → this file → `00`/`01` before touching
473
- anything.
478
+ anything.
@@ -15,10 +15,10 @@
15
15
  "boundary": "docs-evolution",
16
16
  "disposition": "keep",
17
17
  "callers": ["sp:spur-dev", "/sp:dev-run"],
18
- "terminalStates": ["done", "failed", "cancelled"],
19
18
  "artifacts": ["docs-precheck", "docs-verdict"],
20
19
  "failurePolicy": "fail-closed",
21
- "modelQueries": ["draft"],
20
+ "terminalStates": ["done", "failed", "cancelled"],
21
+ "modelQueries": ["draft", "verify"],
22
22
  "actions": {
23
23
  "precheck:onEnter:0": {
24
24
  "kind": "command.gate",
@@ -66,34 +66,63 @@
66
66
  },
67
67
  "done:onEnter:0": {
68
68
  "kind": "shell",
69
- "invocation": "mkdir -p .spur/run && printf '%s\\n' \"{\\\"wbs\\\":\\\"$wbs\\\",\\\"verdict\\\":\\\"PASS\\\",\\\"source\\\":\\\"docs-pipeline\\\",\\\"requirements\\\":[{\\\"id\\\":\\\"docs-deliverable\\\",\\\"status\\\":\\\"MET\\\",\\\"evidence\\\":\\\"docs-pipeline record step\\\"}],\\\"acceptanceCriteria\\\":[],\\\"checks\\\":[{\\\"name\\\":\\\"docs-only\\\",\\\"status\\\":\\\"pass\\\",\\\"evidence\\\":\\\"docs-pipeline\\\"}]}\" > \".spur/run/$wbs-verdict.json\"\n",
69
+ "invocation": "$spurBin task update $wbs done --no-lifecycle",
70
70
  "stateEffect": "read",
71
71
  "evidenceEffect": "write"
72
72
  },
73
73
  "done:onEnter:1": {
74
- "kind": "run.artifact",
74
+ "kind": "note",
75
75
  "stateEffect": "read",
76
76
  "evidenceEffect": "write"
77
77
  },
78
- "done:onEnter:2": {
78
+ "verify:onEnter:0": {
79
79
  "kind": "shell",
80
- "invocation": "$spurBin task update $wbs done --no-lifecycle",
80
+ "invocation": "$spurBin task path $wbs --json 2>/dev/null | jq -r \".path // .filePath // empty\" > \".spur/run/$wbs-docs-taskpath.txt\" || true; exit 0",
81
81
  "stateEffect": "write",
82
82
  "evidenceEffect": "none"
83
83
  },
84
- "done:onEnter:3": {
85
- "kind": "note",
86
- "stateEffect": "read",
84
+ "verify:onEnter:1": {
85
+ "kind": "file.read.into-var"
86
+ },
87
+ "verify:onEnter:2": {
88
+ "kind": "proof.fingerprint",
89
+ "invocation": "/sp:dev-verify ${vars.wbs} --auto --fix none --focus all"
90
+ },
91
+ "verify:onEnter:3": {
92
+ "kind": "agent.run",
93
+ "invocation": "/sp:dev-verify ${vars.wbs} --auto --fix none --focus all",
94
+ "stateEffect": "write",
95
+ "evidenceEffect": "none"
96
+ },
97
+ "verify:onEnter:4": {
98
+ "kind": "shell",
99
+ "invocation": "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt",
100
+ "stateEffect": "write",
101
+ "evidenceEffect": "none"
102
+ },
103
+ "verify:onEnter:5": {
104
+ "kind": "shell",
105
+ "invocation": "V=\".spur/run/$wbs-verdict.json\"; if [ -f \"$V\" ] && [ -n \"$proofDigest\" ]; then\n jq --arg d \"$proofDigest\" '. + {proof: {digest: $d, capturePoint: \"docs-verify-entry\"}}' \"$V\" > \"$V.tmp\" && mv \"$V.tmp\" \"$V\";\nfi; exit 0",
106
+ "stateEffect": "write",
87
107
  "evidenceEffect": "none"
108
+ },
109
+ "verify:onEnter:6": {
110
+ "kind": "run.artifact",
111
+ "stateEffect": "read",
112
+ "evidenceEffect": "write"
113
+ },
114
+ "verify:onEnter:7": {
115
+ "kind": "proof.fingerprint",
116
+ "invocation": "/sp:dev-verify ${vars.wbs} --auto --fix none --focus all"
88
117
  }
89
- }
118
+ },
119
+ "digest": "sha256:2794f4f926ecfcd69c0265214f9fcd69ab84cdd3ed53409a8af77a700fd635cc"
90
120
  },
91
121
  "idea-pipeline": {
92
122
  "definition": "config/workflows/idea-pipeline.yaml",
93
123
  "boundary": "idea-decomposition",
94
124
  "disposition": "keep",
95
125
  "callers": ["sp:spur-dev", "/sp:dev-idea"],
96
- "terminalStates": ["handoff", "cancelled", "failed"],
97
126
  "artifacts": [
98
127
  "idea-eval-report",
99
128
  "idea-needs-design",
@@ -103,6 +132,7 @@
103
132
  "idea-handoff"
104
133
  ],
105
134
  "failurePolicy": "fail-closed",
135
+ "terminalStates": ["handoff", "cancelled", "failed"],
106
136
  "modelQueries": ["discovery", "feature-create", "ac-generate", "system-design", "decompose"],
107
137
  "actions": {
108
138
  "start:onEnter:0": {
@@ -111,8 +141,13 @@
111
141
  "evidenceEffect": "none"
112
142
  },
113
143
  "start:onEnter:1": {
144
+ "kind": "doctor.probe",
145
+ "stateEffect": "read",
146
+ "evidenceEffect": "write"
147
+ },
148
+ "start:onEnter:2": {
114
149
  "kind": "shell",
115
- "invocation": "mkdir -p .spur/run && DOCTOR_FILE=\".spur/run/$__runId-idea-precheck-doctor.status\" && set +e && $spurBin agent doctor $agent; doctor_rc=$?; set -e && if [ \"$doctor_rc\" -eq 0 ] && test -n \"$idea\"; then\n printf 'PASS\\n' > \"$DOCTOR_FILE\";\nelse\n printf 'FAIL\\n' > \"$DOCTOR_FILE\";\nfi && exit 0",
150
+ "invocation": "test -n \"$idea\" || printf 'FAIL\\n' > \".spur/run/$__runId-idea-precheck-doctor.status\"",
116
151
  "stateEffect": "read",
117
152
  "evidenceEffect": "write",
118
153
  "disposition": "GLUE"
@@ -258,45 +293,41 @@
258
293
  "stateEffect": "write",
259
294
  "evidenceEffect": "write"
260
295
  }
261
- }
296
+ },
297
+ "digest": "sha256:acc878217ffc7e31d31600b59d5b240588a079638d2eb0caff8c7a78524220b9"
262
298
  },
263
299
  "task-pipeline": {
264
300
  "definition": "config/workflows/task-pipeline.yaml",
265
301
  "boundary": "task-execution",
266
302
  "disposition": "canonical",
267
303
  "callers": ["sp:spur-dev", "sp:super-planner"],
268
- "terminalStates": ["done", "failed", "cancelled"],
269
304
  "artifacts": ["verify-answer", "verify-verdict", "testing-section", "review-section"],
270
305
  "failurePolicy": "fail-closed",
306
+ "terminalStates": ["done", "failed", "cancelled"],
271
307
  "modelQueries": ["implement", "test-fix", "review", "verify"],
272
308
  "actions": {
273
309
  "precheck:onEnter:0": {
274
- "kind": "doctor.probe",
275
- "stateEffect": "read",
276
- "evidenceEffect": "write"
277
- },
278
- "precheck:onEnter:1": {
279
310
  "kind": "shell",
280
311
  "invocation": "DIRTY=$(git status --porcelain -- . ':(exclude)docs/tasks*' ':(exclude)docs/features' 2>/dev/null); if [ -n \"$DIRTY\" ]; then\n echo \"precheck: WARNING - working tree has uncommitted non-corpus changes; commit or stash before starting a new task:\";\n echo \"$DIRTY\";\nfi; CORPUS_DIRTY=$(git status --porcelain -- ':(glob)docs/tasks*/**' 2>/dev/null); if [ -n \"$CORPUS_DIRTY\" ]; then\n echo \"precheck: NOTE - task corpus has uncommitted changes; review before staging with this task:\";\n echo \"$CORPUS_DIRTY\";\nfi; exit 0",
281
312
  "stateEffect": "read",
282
313
  "evidenceEffect": "none",
283
314
  "disposition": "GLUE"
284
315
  },
285
- "precheck:onEnter:2": {
316
+ "precheck:onEnter:1": {
286
317
  "kind": "note",
287
318
  "stateEffect": "read",
288
319
  "evidenceEffect": "none"
289
320
  },
290
- "precheck:onEnter:3": {
321
+ "precheck:onEnter:2": {
291
322
  "kind": "shell",
292
- "invocation": "if [ \"$profile\" = auto ]; then\n FID=$($spurBin task show $wbs --json 2>/dev/null |\n jq -r '.feature_id // .frontmatter.feature_id // empty' 2>/dev/null);\n if [ -n \"$FID\" ]; then\n $spurBin feature sync \"$FID\" --force --json 2>/dev/null ||\n $spurBin feature update \"$FID\" active 2>/dev/null || true;\n fi;\nfi; exit 0",
323
+ "invocation": "if [ \"$profile\" = auto ]; then\n FID=$($spurBin task show $wbs --json 2>/dev/null |\n jq -r '.feature_id // .frontmatter.feature_id // empty' 2>/dev/null);\n if [ -n \"$FID\" ]; then\n if ! $spurBin feature sync \"$FID\" --force 2>/dev/null; then\n if ! $spurBin feature update \"$FID\" active 2>/dev/null; then\n echo \"precheck: FAIL - feature reactivation $FID failed;\" >&2;\n echo \"precheck: feature sync + feature update both errored\" >&2;\n exit 1;\n fi;\n fi;\n fi;\nfi; exit 0",
293
324
  "stateEffect": "write",
294
325
  "evidenceEffect": "none",
295
326
  "disposition": "GLUE"
296
327
  },
297
- "precheck:onEnter:4": {
328
+ "precheck:onEnter:3": {
298
329
  "kind": "shell",
299
- "invocation": "SIZE_FILE=\".spur/run/$wbs-precheck-size.status\" && mkdir -p .spur/run && if [ -f plugins/sp/scripts/task-size-precheck.ts ]; then bun plugins/sp/scripts/task-size-precheck.ts \"$wbs\" --spur-bin \"$spurBin\" --max-reqs \"$maxImplementReqs\" --max-plan-items \"$maxImplementPlanItems\" --executor \"$implementAgent\"; else\n echo \"task-size-precheck skipped — plugins/sp/scripts/task-size-precheck.ts not present in project.\" >&2 &&\n echo \"PASS\" > \"$SIZE_FILE\";\nfi && exit 0",
330
+ "invocation": "SIZE_FILE=\".spur/run/$wbs-precheck-size.status\" && mkdir -p .spur/run && if [ -f plugins/sp/scripts/task-size-precheck.ts ]; then bun plugins/sp/scripts/task-size-precheck.ts \"$wbs\" --spur-bin \"$spurBin\" --max-reqs \"$maxImplementReqs\" --max-plan-items \"$maxImplementPlanItems\"; else\n echo \"task-size-precheck failed closed checker script\" >&2 &&\n echo \"plugins/sp/scripts/task-size-precheck.ts absent.\" >&2 &&\n echo \"FAIL\" > \"$SIZE_FILE\";\nfi && exit 0",
300
331
  "stateEffect": "read",
301
332
  "evidenceEffect": "write",
302
333
  "disposition": "EXT"
@@ -322,14 +353,33 @@
322
353
  },
323
354
  "test:onEnter:0": {
324
355
  "kind": "shell",
325
- "invocation": "mkdir -p .spur/run && STATUS_FILE=\".spur/run/$wbs-test-gate.status\" && LOG_FILE=\".spur/run/$wbs-test-gate.log\" && ATTEMPT_FILE=\".spur/run/$wbs-test-fix-attempt\" && echo 0 > \"$ATTEMPT_FILE\" && : > \"$LOG_FILE\" && gate_attempt=1; while [ \"$gate_attempt\" -le 5 ]; do\n ATTEMPT_LOG=\"$LOG_FILE.attempt-$gate_attempt\";\n sh -c \"$qualityGateCmd\" > \"$ATTEMPT_LOG\" 2>&1; gate_rc=$?;\n gate_locked=0;\n grep -q 'SQLiteError: database is locked' \"$ATTEMPT_LOG\" && gate_locked=1;\n cat \"$ATTEMPT_LOG\" >> \"$LOG_FILE\";\n rm -f \"$ATTEMPT_LOG\";\n if [ \"$gate_rc\" -eq 0 ] || [ \"$gate_locked\" -ne 1 ] || [ \"$gate_attempt\" -ge 5 ]; then break; fi;\n printf 'quality gate: database is locked; retrying (%s/5) in 10s\\n' \"$gate_attempt\" | tee -a \"$LOG_FILE\";\n sleep 10;\n gate_attempt=$((gate_attempt + 1));\ndone && cat \"$LOG_FILE\" && FINDINGS_FILE=\".spur/run/$wbs-test-gate.findings\" && set +e; grep -oE '[A-Za-z0-9_./-]+\\.[A-Za-z]+:[0-9]+' \"$LOG_FILE\" | sort -u | head -20 | tr '\\n' ' ' > \"$FINDINGS_FILE\"; set -e && if [ \"$gate_rc\" -eq 0 ]; then\n printf 'PASS\\n' > \"$STATUS_FILE\";\nelse\n printf 'FAIL\\n' > \"$STATUS_FILE\";\nfi && exit 0",
356
+ "invocation": "$spurBin task path $wbs --json 2>/dev/null | jq -r \".path // .filePath // empty\" > \".spur/run/$wbs-taskpath.txt\" || true; sed -n \"s/^priority:[[:space:]]*//p\" \"$(cat \".spur/run/$wbs-taskpath.txt\" 2>/dev/null)\" 2>/dev/null | head -1 | tr -d \"[:space:]\" | tr \"[:lower:]\" \"[:upper:]\" > \".spur/run/$wbs-priority.txt\"; exit 0",
326
357
  "stateEffect": "write",
327
358
  "evidenceEffect": "write",
328
359
  "disposition": "POLICY"
329
360
  },
361
+ "test:onEnter:1": {
362
+ "kind": "file.read.into-var",
363
+ "stateEffect": "read",
364
+ "evidenceEffect": "none"
365
+ },
366
+ "test:onEnter:2": {
367
+ "kind": "file.read.into-var",
368
+ "stateEffect": "read",
369
+ "evidenceEffect": "none"
370
+ },
371
+ "test:onEnter:3": {
372
+ "kind": "proof.fingerprint",
373
+ "stateEffect": "write",
374
+ "evidenceEffect": "write"
375
+ },
376
+ "test:onEnter:4": {
377
+ "kind": "shell",
378
+ "invocation": "mkdir -p .spur/run && STATUS_FILE=\".spur/run/$wbs-test-gate.status\" && LOG_FILE=\".spur/run/$wbs-test-gate.log\" && ATTEMPT_FILE=\".spur/run/$wbs-test-fix-attempt\" && echo 0 > \"$ATTEMPT_FILE\" && : > \"$LOG_FILE\" && gate_attempt=1; while [ \"$gate_attempt\" -le 5 ]; do\n ATTEMPT_LOG=\"$LOG_FILE.attempt-$gate_attempt\";\n sh -c \"$qualityGateCmd\" > \"$ATTEMPT_LOG\" 2>&1; gate_rc=$?;\n gate_locked=0;\n grep -q 'SQLiteError: database is locked' \"$ATTEMPT_LOG\" && gate_locked=1;\n cat \"$ATTEMPT_LOG\" >> \"$LOG_FILE\";\n rm -f \"$ATTEMPT_LOG\";\n if [ \"$gate_rc\" -eq 0 ] || [ \"$gate_locked\" -ne 1 ] || [ \"$gate_attempt\" -ge 5 ]; then break; fi;\n printf 'quality gate: database is locked; retrying (%s/5) in 10s\\n' \"$gate_attempt\" | tee -a \"$LOG_FILE\";\n sleep 10;\n gate_attempt=$((gate_attempt + 1));\ndone && cat \"$LOG_FILE\" && FINDINGS_FILE=\".spur/run/$wbs-test-gate.findings\" && set +e; grep -oE '[A-Za-z0-9_./-]+\\.[A-Za-z]+:[0-9]+' \"$LOG_FILE\" | sort -u | head -20 | tr '\\n' ' ' > \"$FINDINGS_FILE\"; set -e && if [ \"$gate_rc\" -eq 0 ]; then\n printf 'PASS\\n' > \"$STATUS_FILE\";\nelse\n printf 'FAIL\\n' > \"$STATUS_FILE\";\nfi && printf 'proof-digest: %s\\n' \"$proofDigest\" >> \"$LOG_FILE\" && exit 0"
379
+ },
330
380
  "test-fix:onEnter:0": {
331
381
  "kind": "shell",
332
- "invocation": "mkdir -p .spur/run && ATTEMPT_FILE=\".spur/run/$wbs-test-fix-attempt\" && n=$(cat \"$ATTEMPT_FILE\" 2>/dev/null || echo 0) && printf '%s\\n' \"$((n + 1))\" > \"$ATTEMPT_FILE\"",
382
+ "invocation": "mkdir -p .spur/run && ATTEMPT_FILE=\".spur/run/$wbs-test-fix-attempt\" && n=$(cat \"$ATTEMPT_FILE\" 2>/dev/null || echo 0) && printf '%s\\n' \"$((n + 1))\" > \"$ATTEMPT_FILE\" && if [ -f \".spur/run/$wbs-verdict.json\" ]; then\n { echo '--- verify verdict (remediation input, task 0703 R4) ---';\n cat \".spur/run/$wbs-verdict.json\";\n } >> \".spur/run/$wbs-test-gate.log\";\nfi; exit 0",
333
383
  "stateEffect": "write",
334
384
  "evidenceEffect": "write"
335
385
  },
@@ -345,12 +395,17 @@
345
395
  "evidenceEffect": "none"
346
396
  },
347
397
  "test-recheck:onEnter:0": {
348
- "kind": "shell",
349
- "invocation": "mkdir -p .spur/run && STATUS_FILE=\".spur/run/$wbs-test-gate.status\" && LOG_FILE=\".spur/run/$wbs-test-gate.log\" && FINDINGS_FILE=\".spur/run/$wbs-test-gate.findings\" && : > \"$LOG_FILE\" && probe_rc=0; if [ -n \"$gateProbeCmd\" ]; then\n sh -c \"$gateProbeCmd\" > \"$LOG_FILE.probe\" 2>&1; probe_rc=$?;\n cat \"$LOG_FILE.probe\" >> \"$LOG_FILE\";\n rm -f \"$LOG_FILE.probe\";\nfi; if [ \"$probe_rc\" -ne 0 ]; then\n gate_rc=$probe_rc;\nelse\n gate_attempt=1;\n while [ \"$gate_attempt\" -le 5 ]; do\n ATTEMPT_LOG=\"$LOG_FILE.attempt-$gate_attempt\";\n sh -c \"$qualityGateCmd\" > \"$ATTEMPT_LOG\" 2>&1; gate_rc=$?;\n gate_locked=0;\n grep -q 'SQLiteError: database is locked' \"$ATTEMPT_LOG\" && gate_locked=1;\n cat \"$ATTEMPT_LOG\" >> \"$LOG_FILE\";\n rm -f \"$ATTEMPT_LOG\";\n if [ \"$gate_rc\" -eq 0 ] || [ \"$gate_locked\" -ne 1 ] || [ \"$gate_attempt\" -ge 5 ]; then break; fi;\n printf 'quality gate: database is locked; retrying (%s/5) in 10s\\n' \"$gate_attempt\" | tee -a \"$LOG_FILE\";\n sleep 10;\n gate_attempt=$((gate_attempt + 1));\n done;\nfi && cat \"$LOG_FILE\" && set +e; grep -oE '[A-Za-z0-9_./-]+\\.[A-Za-z]+:[0-9]+' \"$LOG_FILE\" | sort -u | head -20 | tr '\\n' ' ' > \"$FINDINGS_FILE\"; set -e && if [ \"$gate_rc\" -eq 0 ]; then\n printf 'PASS\\n' > \"$STATUS_FILE\";\nelse\n printf 'FAIL\\n' > \"$STATUS_FILE\";\nfi && exit 0",
398
+ "kind": "proof.fingerprint",
350
399
  "stateEffect": "write",
351
400
  "evidenceEffect": "write",
352
401
  "disposition": "POLICY"
353
402
  },
403
+ "test-recheck:onEnter:1": {
404
+ "kind": "shell",
405
+ "invocation": "mkdir -p .spur/run && STATUS_FILE=\".spur/run/$wbs-test-gate.status\" && LOG_FILE=\".spur/run/$wbs-test-gate.log\" && FINDINGS_FILE=\".spur/run/$wbs-test-gate.findings\" && : > \"$LOG_FILE\" && probe_rc=0; if [ -n \"$gateProbeCmd\" ]; then\n sh -c \"$gateProbeCmd\" > \"$LOG_FILE.probe\" 2>&1; probe_rc=$?;\n cat \"$LOG_FILE.probe\" >> \"$LOG_FILE\";\n rm -f \"$LOG_FILE.probe\";\nfi; if [ \"$probe_rc\" -ne 0 ]; then\n gate_rc=$probe_rc;\nelse\n gate_attempt=1;\n while [ \"$gate_attempt\" -le 5 ]; do\n ATTEMPT_LOG=\"$LOG_FILE.attempt-$gate_attempt\";\n sh -c \"$qualityGateCmd\" > \"$ATTEMPT_LOG\" 2>&1; gate_rc=$?;\n gate_locked=0;\n grep -q 'SQLiteError: database is locked' \"$ATTEMPT_LOG\" && gate_locked=1;\n cat \"$ATTEMPT_LOG\" >> \"$LOG_FILE\";\n rm -f \"$ATTEMPT_LOG\";\n if [ \"$gate_rc\" -eq 0 ] || [ \"$gate_locked\" -ne 1 ] || [ \"$gate_attempt\" -ge 5 ]; then break; fi;\n printf 'quality gate: database is locked; retrying (%s/5) in 10s\\n' \"$gate_attempt\" | tee -a \"$LOG_FILE\";\n sleep 10;\n gate_attempt=$((gate_attempt + 1));\n done;\nfi && cat \"$LOG_FILE\" && set +e; grep -oE '[A-Za-z0-9_./-]+\\.[A-Za-z]+:[0-9]+' \"$LOG_FILE\" | sort -u | head -20 | tr '\\n' ' ' > \"$FINDINGS_FILE\"; set -e && if [ \"$gate_rc\" -eq 0 ]; then\n printf 'PASS\\n' > \"$STATUS_FILE\";\nelse\n printf 'FAIL\\n' > \"$STATUS_FILE\";\nfi && printf 'proof-digest: %s\\n' \"$proofDigest\" >> \"$LOG_FILE\" && exit 0",
406
+ "stateEffect": "write",
407
+ "evidenceEffect": "write"
408
+ },
354
409
  "review:onEnter:0": {
355
410
  "kind": "agent.run",
356
411
  "invocation": "/sp:dev-review ${vars.wbs} --auto",
@@ -363,38 +418,27 @@
363
418
  "evidenceEffect": "none"
364
419
  },
365
420
  "verify:onEnter:0": {
366
- "kind": "agent.run",
367
- "invocation": "/sp:dev-verify ${vars.wbs} --auto --fix all --focus all",
421
+ "kind": "proof.fingerprint",
368
422
  "stateEffect": "may-write",
369
423
  "evidenceEffect": "write"
370
424
  },
371
425
  "verify:onEnter:1": {
372
- "kind": "shell",
373
- "invocation": "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt",
426
+ "kind": "agent.run",
427
+ "invocation": "/sp:dev-verify ${vars.wbs} --auto --fix none --focus all",
374
428
  "stateEffect": "read",
375
429
  "evidenceEffect": "write"
376
430
  },
377
431
  "verify:onEnter:2": {
378
432
  "kind": "shell",
379
- "invocation": "$spurBin task path $wbs --json 2>/dev/null | jq -r \".path // empty\" > \".spur/run/$wbs-taskpath.txt\" || true; exit 0",
433
+ "invocation": "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt",
380
434
  "stateEffect": "read",
381
435
  "evidenceEffect": "write"
382
436
  },
383
437
  "verify:onEnter:3": {
384
- "kind": "file.read.into-var",
385
- "stateEffect": "read",
386
- "evidenceEffect": "none"
387
- },
388
- "verify:onEnter:4": {
389
- "kind": "proof.fingerprint",
390
- "stateEffect": "read",
391
- "evidenceEffect": "none"
392
- },
393
- "verify:onEnter:5": {
394
438
  "kind": "shell",
395
- "invocation": "V=\".spur/run/$wbs-verdict.json\"; if [ -f \"$V\" ] && [ -n \"$proofDigest\" ]; then jq --arg d \"$proofDigest\" \".checks += [{\\\"name\\\":\\\"proof-input-digest\\\",\\\"status\\\":\\\"pass\\\",\\\"evidence\\\":\\$d}]\" \"$V\" > \"$V.tmp\" && mv \"$V.tmp\" \"$V\"; fi; exit 0",
439
+ "invocation": "V=\".spur/run/$wbs-verdict.json\"; if [ -f \"$V\" ] && [ -n \"$proofDigest\" ]; then\n jq --arg d \"$proofDigest\" --arg g \"$(cat .spur/run/$wbs-test-gate.status 2>/dev/null || echo UNKNOWN)\"\n '. + {proof: {digest: $d, capturePoint: \"quality-gate-entry\", stages: {\n qualityGate: {status: $g, digest: $d},\n review: {status: \"completed\", digest: $d},\n verification: {status: .verdict, digest: $d}}}}\n | .checks += [{name: \"proof-input-digest\", status: \"pass\", evidence: $d}]'\n \"$V\" > \"$V.tmp\" && mv \"$V.tmp\" \"$V\";\nfi; exit 0",
396
440
  "stateEffect": "read",
397
- "evidenceEffect": "write"
441
+ "evidenceEffect": "none"
398
442
  },
399
443
  "record:onEnter:0": {
400
444
  "kind": "proof.fingerprint",
@@ -434,20 +478,21 @@
434
478
  },
435
479
  "done:onEnter:3": {
436
480
  "kind": "shell",
437
- "invocation": "mkdir -p .spur/memory/sessions && echo \"checkpoint: task-pipeline done wbs=$wbs ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)\" > .spur/memory/sessions/$wbs-checkpoint.md",
481
+ "invocation": "mkdir -p .spur/memory/sessions; CP_TS=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"; CP_COMMIT=\"$(git rev-parse HEAD 2>/dev/null || echo unknown)\"; CP_DIGEST=\"$(cut -d= -f2 .spur/run/$wbs-proofdigest.txt 2>/dev/null || echo '')\"; CP_RUN=\"$SPUR_RUN_ID\"; [ -z \"$CP_RUN\" ] && CP_RUN=\"$RUN_ID\"; printf '%s\\n' '---' 'schema_version: 1' \"session_id: $(date -u +%Y-%m-%d)-$wbs\" 'workflow: task-pipeline' \"run_id: $CP_RUN\" \"task_wbs: $wbs\" 'feature_id: \"\"' 'phase: done' 'status: done' 'last_gate: record' \"source_commit: $CP_COMMIT\" \"digest: $CP_DIGEST\" \"generated_at: $CP_TS\" \"updated_at: $CP_TS\" \"next_action: none - task $wbs complete (terminal; advisory only)\" 'artifacts:' ' - .spur/run/$wbs-verdict.json' ' - .spur/run/$wbs-test-gate.log' '---' '' '## Session Notes' '' \"Terminal checkpoint for task $wbs (task-pipeline done).\" 'Advisory only; the task file is authoritative.' > .spur/memory/sessions/$wbs-checkpoint.md; exit 0",
438
482
  "stateEffect": "write",
439
483
  "evidenceEffect": "write"
440
484
  }
441
- }
485
+ },
486
+ "digest": "sha256:4098c91f865e9879987bb6049be911f021fe6a26843eced1085f631f33f1e47e"
442
487
  },
443
488
  "wrapup-pipeline": {
444
489
  "definition": "config/workflows/wrapup-pipeline.yaml",
445
490
  "boundary": "task-wrapup",
446
491
  "disposition": "keep",
447
492
  "callers": ["sp:spur-dev", "/sp:dev-wrap", "/sp:dev-wrapall"],
448
- "terminalStates": ["done", "skipped"],
449
493
  "artifacts": ["wrapup-learnings", "wrapup-metrics"],
450
494
  "failurePolicy": "fail-closed",
495
+ "terminalStates": ["done", "skipped"],
451
496
  "modelQueries": ["doc-sync"],
452
497
  "actions": {
453
498
  "start:onEnter:0": {
@@ -503,14 +548,14 @@
503
548
  "stateEffect": "write",
504
549
  "evidenceEffect": "write"
505
550
  }
506
- }
551
+ },
552
+ "digest": "sha256:390621dd339709682065e8954f2d1b49a195111c8372ec83e094fe7e2e35927f"
507
553
  },
508
554
  "pr-review": {
509
555
  "definition": "config/workflows/pr-review.yaml",
510
556
  "boundary": "pr-review",
511
557
  "disposition": "keep",
512
558
  "callers": ["sp:spur-dev", "/sp:dev-pr-review"],
513
- "terminalStates": ["done", "pending", "failed"],
514
559
  "artifacts": [
515
560
  "pr-context",
516
561
  "pr-hygiene",
@@ -522,6 +567,7 @@
522
567
  "pr-status"
523
568
  ],
524
569
  "failurePolicy": "fail-closed",
570
+ "terminalStates": ["done", "pending", "failed"],
525
571
  "modelQueries": [],
526
572
  "actions": {
527
573
  "preflight:onEnter:0": {
@@ -577,16 +623,17 @@
577
623
  "evidenceEffect": "write",
578
624
  "disposition": "EXT"
579
625
  }
580
- }
626
+ },
627
+ "digest": "sha256:eb3f51877647f25907ed6b660b79e4d22b3c7462ceccacc4fc251eb31bac06f0"
581
628
  },
582
629
  "basic": {
583
630
  "definition": "config/workflows/basic.yaml",
584
631
  "boundary": "generic-execution",
585
632
  "disposition": "keep",
586
- "artifacts": ["fix-attempt-counter", "gate-status"],
587
633
  "callers": ["spur workflow run"],
588
- "terminalStates": ["done", "failed"],
634
+ "artifacts": ["fix-attempt-counter", "gate-status"],
589
635
  "failurePolicy": "fail-closed",
636
+ "terminalStates": ["done", "failed"],
590
637
  "modelQueries": ["fix"],
591
638
  "actions": {
592
639
  "implement:onEnter:0": {
@@ -621,16 +668,17 @@
621
668
  "stateEffect": "read",
622
669
  "evidenceEffect": "none"
623
670
  }
624
- }
671
+ },
672
+ "digest": "sha256:fb8ab828b9527f225368d20b08e3fc7ca4b92e6e22642a57868da193d5ebef2c"
625
673
  },
626
674
  "feature-dev": {
627
675
  "definition": "config/workflows/feature-dev.yaml",
628
676
  "boundary": "feature-umbrella",
629
677
  "disposition": "keep",
630
- "artifacts": ["feature-checkpoint"],
631
678
  "callers": ["/sp:dev-runall --feature"],
632
- "terminalStates": ["done", "failed"],
679
+ "artifacts": ["feature-checkpoint"],
633
680
  "failurePolicy": "fail-closed",
681
+ "terminalStates": ["done", "failed"],
634
682
  "modelQueries": ["brainstorm", "plan", "execute-tasks-auto", "execute-tasks"],
635
683
  "actions": {
636
684
  "precheck:onEnter:0": {
@@ -686,16 +734,17 @@
686
734
  "evidenceEffect": "write",
687
735
  "disposition": "GLUE"
688
736
  }
689
- }
737
+ },
738
+ "digest": "sha256:e1fa6b86cb7bcad0f927cf73336996ee8ce0088b6685cebba8c8849e26029529"
690
739
  },
691
740
  "wayfinder-resolution": {
692
741
  "definition": "config/workflows/wayfinder-resolution.yaml",
693
742
  "boundary": "wayfinder-resolution",
694
743
  "disposition": "keep",
695
- "artifacts": ["wayfinder-report", "resolution-status"],
696
744
  "callers": ["spur workflow run"],
697
- "terminalStates": ["done", "failed", "cancelled"],
745
+ "artifacts": ["wayfinder-report", "resolution-status"],
698
746
  "failurePolicy": "fail-closed",
747
+ "terminalStates": ["done", "failed", "cancelled"],
699
748
  "modelQueries": ["investigate", "verify"],
700
749
  "actions": {
701
750
  "precheck:onEnter:0": {
@@ -774,7 +823,8 @@
774
823
  "stateEffect": "read",
775
824
  "evidenceEffect": "none"
776
825
  }
777
- }
826
+ },
827
+ "digest": "sha256:ef75f70a09b67ea5905ac68aba7c3eec2b805530312ca3173fa4b8ee7275059e"
778
828
  }
779
829
  }
780
830
  }
@@ -24,7 +24,7 @@ failureStates:
24
24
  vars:
25
25
  # `task` is reserved by the engine runtime — use taskLabel for the free-form label.
26
26
  taskLabel: "task"
27
- agent: "omp"
27
+ agent: "auto"
28
28
  stepTimeoutMs: "1800000"
29
29
  # Override per project: `--vars '{"qualityGateCmd":"bun run lint && bun run test"}'`
30
30
  qualityGateCmd: "bun run check"