@gobing-ai/spur 0.4.2 → 0.4.4
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/decisions/maker-liveness.yaml +39 -0
- package/config/plugin-scripts.json +0 -4
- package/config/rules/README.md +1 -0
- package/config/rules/docs/sourced-api-claims.yaml +56 -12
- package/config/rules/docs/verdict-confidence.yaml +68 -0
- package/config/rules/quality/coverage-gate.yaml +13 -0
- package/config/rules/recommended-pre-check.yaml +6 -2
- package/config/rules/strict/runtime-boundaries.yaml +10 -0
- package/config/rules/surface/check-cli-surface.yaml +1 -3
- package/config/script-placement-baseline.json +1 -19
- package/config/templates/AGENTS.md +7 -0
- package/config/workflows/feature-lifecycle.yaml +46 -1
- package/config/workflows/feature-verification.yaml +20 -1
- package/config/workflows/task-lifecycle.yaml +50 -0
- package/config/workflows/task-pipeline.yaml +15 -9
- package/package.json +10 -10
- package/plugins/sp/README.md +22 -16
- package/plugins/sp/agents/super-reviewer.md +46 -0
- package/plugins/sp/bunfig.toml +8 -5
- package/plugins/sp/commands/dev-changelog.md +1 -1
- package/plugins/sp/commands/dev-gitmsg.md +6 -2
- package/plugins/sp/commands/dev-handover.md +1 -0
- package/plugins/sp/commands/dev-job-dump.md +2 -1
- package/plugins/sp/commands/dev-refine.md +14 -2
- package/plugins/sp/commands/dev-refineall.md +7 -1
- package/plugins/sp/commands/dev-review.md +1 -0
- package/plugins/sp/hooks/careful-guard.ts +1 -1
- package/plugins/sp/hooks/context-post-tool.ts +7 -427
- package/plugins/sp/hooks/context-session-start.ts +5 -213
- package/plugins/sp/hooks/context-session-stop.ts +5 -191
- package/plugins/sp/hooks/pi/guard-extension.ts +6 -5
- package/plugins/sp/hooks/task-write-guard.ts +1 -1
- package/plugins/sp/{hooks → lib}/agent-hint.ts +1 -1
- package/plugins/sp/lib/context-post-tool.ts +432 -0
- package/plugins/sp/lib/context-session-start.ts +214 -0
- package/plugins/sp/lib/context-session-stop.ts +196 -0
- package/plugins/sp/lib/dogfood-pipeline.ts +265 -0
- package/plugins/sp/lib/dogfood-report.ts +278 -0
- package/plugins/sp/lib/history-anatomy.generated.mjs +18 -18
- package/plugins/sp/lib/idea-handoff.generated.mjs +91 -91
- package/plugins/sp/lib/inline-run-app.ts +40 -0
- package/plugins/sp/lib/inline-run.generated.d.mts +3 -3
- package/plugins/sp/lib/inline-run.generated.mjs +1425 -212
- package/plugins/sp/lib/plan-projection.generated.d.mts +150 -0
- package/plugins/sp/lib/plan-projection.generated.mjs +623 -9
- package/plugins/sp/lib/quality-gate.generated.d.mts +1 -0
- package/plugins/sp/lib/quality-gate.generated.mjs +13809 -13969
- package/plugins/sp/lib/residual-scan.generated.d.mts +20 -1
- package/plugins/sp/lib/residual-scan.generated.mjs +120 -25
- package/plugins/sp/lib/run-summary-core.ts +34 -370
- package/plugins/sp/lib/step-profile.generated.mjs +8 -8
- package/plugins/sp/lib/transcript.ts +37 -228
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/batch-plan.mjs +619 -11
- package/plugins/sp/scripts/batch-preflight.mjs +57 -13
- package/plugins/sp/scripts/batch-preflight.ts +35 -295
- package/plugins/sp/scripts/commit-guard.mjs +6 -6
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +127 -108
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +111 -104
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +13 -12
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +7 -265
- package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +7 -4
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +6 -272
- package/plugins/sp/scripts/feature-verification-steps.mjs +20 -125
- package/plugins/sp/scripts/feature-verification-steps.ts +57 -181
- package/plugins/sp/scripts/history-anatomy-cache.mjs +19 -19
- package/plugins/sp/scripts/idea-handoff.mjs +2 -2
- package/plugins/sp/scripts/inline-run-dispatch.mjs +25 -24
- package/plugins/sp/scripts/inline-run-dispatch.ts +1 -21
- package/plugins/sp/scripts/inline-run-setup.mjs +164 -137
- package/plugins/sp/scripts/inline-run-setup.ts +1 -21
- package/plugins/sp/scripts/persist-out-check.mjs +5 -5
- package/plugins/sp/scripts/pr-reviewing.mjs +13 -13
- package/plugins/sp/scripts/quality-gate.mjs +13730 -13887
- package/plugins/sp/scripts/residual-scan.mjs +129 -31
- package/plugins/sp/scripts/residual-scan.ts +16 -13
- package/plugins/sp/scripts/run-summary.mjs +166 -112
- package/plugins/sp/scripts/run-summary.ts +7 -5
- package/plugins/sp/scripts/script-root.mjs +6 -6
- package/plugins/sp/scripts/session-timeline.mjs +62 -35
- package/plugins/sp/scripts/task-diffstat.mjs +19 -9
- package/plugins/sp/scripts/task-diffstat.ts +8 -39
- package/plugins/sp/scripts/workflow-step-profile.mjs +12 -12
- package/plugins/sp/scripts/wrapup-drift-probe.mjs +9 -9
- package/plugins/sp/scripts/wrapup-steps.mjs +25 -25
- package/plugins/sp/skills/code-implementation/SKILL.md +7 -1
- package/plugins/sp/skills/code-verification/references/secu-review.md +2 -1
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +4 -0
- package/plugins/sp/skills/dogfood-testing/SKILL.md +2 -2
- package/plugins/sp/skills/next-feature/SKILL.md +1 -1
- package/plugins/sp/skills/next-router/SKILL.md +3 -1
- package/plugins/sp/skills/next-router/references/routing-table.md +9 -3
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
- package/plugins/sp/skills/source-driven-development/SKILL.md +7 -4
- package/plugins/sp/skills/spur-cli/references/builder.md +3 -2
- package/plugins/sp/skills/spur-cli/references/decision.md +32 -7
- package/plugins/sp/skills/spur-cli/references/features.md +46 -5
- package/plugins/sp/skills/spur-cli/references/tasks.md +24 -4
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +8 -1
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +37 -11
- package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +1 -1
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +19 -6
- package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +22 -0
- package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +14 -0
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +4 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +49 -12
- package/schemas/section-matrix.schema.json +3 -2
- package/spur.js +66591 -73262
- package/web/_astro/{BoardApp.B3GQZvj8.js → BoardApp.Niubpe6z.js} +1 -1
- package/web/_astro/{BoardApp.BT7L2kSb.js → BoardApp.hF0RAIrg.js} +150 -150
- package/web/_astro/TaskDetail.DJpapt38.js +1 -0
- package/web/_astro/{arc.vaT7tPOB.js → arc.BgKcK0i8.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.DRMmTjkN.js → architectureDiagram-3BPJPVTR.ChP-Ig0V.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.cla0LO_q.js → blockDiagram-GPEHLZMM.BVaCBoeN.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.D4YAIBKn.js → c4Diagram-AAUBKEIU.CHSDpEO5.js} +1 -1
- package/web/_astro/channel.DkpvN2tD.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.BrSJbMRZ.js → chunk-2J33WTMH.MYRcYVRa.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.CuLMgKF5.js → chunk-4BX2VUAB.S5j22Zqa.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.zkvgu54F.js → chunk-55IACEB6.gciRPvmZ.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DxWkACh8.js → chunk-727SXJPM.CdqrSQkX.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.42XrmIlH.js → chunk-AQP2D5EJ.CyokdHT3.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.Bao2wMK9.js → chunk-FMBD7UC4.Bg9KJhjW.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.BhydojD1.js → chunk-ND2GUHAM.1gxxI-vD.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.CmZ82g-H.js → chunk-QZHKN3VN.DDEYtCKU.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.Blr83Gt_.js → classDiagram-4FO5ZUOK.Ch3zi37T.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.Blr83Gt_.js → classDiagram-v2-Q7XG4LA2.Ch3zi37T.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.qmfv0SPn.js → cose-bilkent-S5V4N54A.D2q5AINI.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.BtELhXPR.js → cynefin-OW5HDTMX.BA9kC2YT.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.AWmaAvXo.js → dagre-BM42HDAG.CHO08nRp.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.DdH34KDi.js → diagram-2AECGRRQ.BfFQt0LW.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.BmNPix1k.js → diagram-5GNKFQAL.CHMwMTe4.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.BNQd_Ppo.js → diagram-KO2AKTUF.BJ-7gK-w.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.BAPgDi0e.js → diagram-LMA3HP47.C5xqcc0t.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.DZ4zyLdC.js → diagram-OG6HWLK6.C2pQjfrC.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.Q1TySMmw.js → erDiagram-TEJ5UH35._FoNyxgC.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.BXhFBicG.js → flowDiagram-I6XJVG4X.B_ENkT2I.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.vHSgcuo2.js → ganttDiagram-6RSMTGT7.B3q8h77C.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.Bi1f73C7.js → gitGraphDiagram-PVQCEYII.QWZFDboZ.js} +1 -1
- package/web/_astro/index.BFyW13JJ.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.DPvXZEWm.js → infoDiagram-5YYISTIA.Cs6eEc92.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.Cz829fsV.js → ishikawaDiagram-YF4QCWOH.BU9DJMHA.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.enRnB9Me.js → journeyDiagram-JHISSGLW.D35k6Jpe.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.DnTNk6d2.js → kanban-definition-UN3LZRKU.DBqcAT4m.js} +1 -1
- package/web/_astro/{linear.BzGnBwNL.js → linear.D-LSNK8W.js} +1 -1
- package/web/_astro/{mermaid.core.CSbTpIVz.js → mermaid.core.CSruWVOa.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.DGJDy8zT.js → mindmap-definition-RKZ34NQL.BiFaUsfj.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.HSPdi5_8.js → pieDiagram-4H26LBE5.D1KTKqb9.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.6Gv8mz2Y.js → quadrantDiagram-W4KKPZXB.DBHflsMG.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.CnBCtFwa.js → requirementDiagram-4Y6WPE33.hwX9CNdk.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.5M8VWAu8.js → sankeyDiagram-5OEKKPKP.DkI8mJiE.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.DN41XN-U.js → sequenceDiagram-3UESZ5HK.DMz7jBDx.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.ErOO3W8j.js → stateDiagram-AJRCARHV.B6Ef2xJ1.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.B_ZHICM-.js → stateDiagram-v2-BHNVJYJU.CgoaufB9.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.CWdosr07.js → timeline-definition-PNZ67QCA.B3c8h1t-.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.BHzYjNV5.js → vennDiagram-CIIHVFJN.BdHPAxAb.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.h8x4IwPX.js → wardleyDiagram-YWT4CUSO.BrJXPPAj.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.RTapW2X8.js → xychartDiagram-2RQKCTM6.CMH5yFsV.js} +1 -1
- package/web/index.html +2 -2
- package/web/spur_logo.svg +1 -1
- package/config/proportional-route-table.ts +0 -155
- package/plugins/sp/scripts/daily-summary/logger.ts +0 -28
- package/web/_astro/TaskDetail.Cxov1_N_.js +0 -1
- package/web/_astro/channel.D4nG9YLf.js +0 -1
- package/web/_astro/index.BhSwN8yY.css +0 -1
- /package/plugins/sp/{hooks → lib}/context-owner.ts +0 -0
- /package/plugins/sp/{hooks → lib}/destructive-policy.ts +0 -0
- /package/plugins/sp/{hooks → lib}/task-file-policy.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spur-cli-decision
|
|
3
|
-
description: "spur-cli noun reference: operate `spur decision` as the read/serve surface over the decision catalog - list registered decisions, show one served contract (parameters, criteria vocabulary, effective maker), run a decision to a served outcome (never writes a workflow resultFile), and status the catalog layers. Backed by @gobing-ai/ts-ai-decision 0.5.22 hub; offline by default via the built-in `typesafe` maker. Introduced by task 1093."
|
|
3
|
+
description: "spur-cli noun reference: operate `spur decision` as the read/serve surface over the decision catalog - list registered decisions, show one served contract (parameters, criteria vocabulary, effective maker), run a decision to a served outcome (never writes a workflow resultFile), and status the catalog layers with per-maker readiness marks (registered, configured, recorded, probed). Backed by @gobing-ai/ts-ai-decision 0.5.22 hub; offline by default via the built-in `typesafe` maker. Introduced by task 1093; readiness marks and `--probe` by feature P11."
|
|
4
4
|
see_also:
|
|
5
5
|
- spur-cli
|
|
6
6
|
---
|
|
@@ -25,9 +25,10 @@ Decisions resolve first-wins across three layers:
|
|
|
25
25
|
| `registered` | folders listed in config `decisions.paths` | Operator-added catalogs |
|
|
26
26
|
| `shared` | `decisions/` under the bundled config root | Shipped catalogs (`config/decisions/` in-repo) |
|
|
27
27
|
|
|
28
|
-
The bundled shared catalog ships `task-triage`, `failure-class`,
|
|
29
|
-
`
|
|
30
|
-
|
|
28
|
+
The bundled shared catalog ships `task-triage`, `failure-class`, `review-failure-class`,
|
|
29
|
+
`gate-evidence`, `idea-recommendation`, `needs-design`, `anatomy-validation-verdict` and
|
|
30
|
+
`maker-liveness` (the last served only by `spur decision status --probe`; no workflow references
|
|
31
|
+
it). Duplicate ids across layers keep the higher layer; duplicates inside one file are a load error.
|
|
31
32
|
|
|
32
33
|
**Config keys** (under `decisions:` in the global `~/.config/spur/config.yaml` or project `.spur/config.yaml`):
|
|
33
34
|
`paths` (extra catalog folders forming the `registered` layer), `maker` (default DecisionMaker
|
|
@@ -41,7 +42,7 @@ config error, never a silent fallback (design §3.6).
|
|
|
41
42
|
| `list` | Every visible decision: id, type, layer, catalog file, description | `--layer <layer>`, `--json` |
|
|
42
43
|
| `show <id>` | One served contract: type, parameters, criteria, fallback, minConfidence, effective maker + source | `--json` |
|
|
43
44
|
| `run <id>` | Serve one outcome (closed vocabulary; **never writes a resultFile**) | `--param <pairs...>`, `--evidence <files...>`, `--maker <name>`, `--json` |
|
|
44
|
-
| `status` |
|
|
45
|
+
| `status` | Sectioned readiness report: one status line, errors, aligned `Makers` and `Decisions` tables (registration, configuration source, recorded evidence), `Catalog` block | `--probe`, `--reliability [--since <iso>]`, `--json` |
|
|
45
46
|
|
|
46
47
|
All verbs support `--json` (bare payload) and `--json-envelope` (`{ok, data|error}` envelope,
|
|
47
48
|
ADR-091). Failure output for `--json` commands uses the canonical error envelope only under
|
|
@@ -51,6 +52,25 @@ ADR-091). Failure output for `--json` commands uses the canonical error envelope
|
|
|
51
52
|
(design §3.4 — load errors surface via `status`) except for an invalid `--layer` value (exit 1).
|
|
52
53
|
Error envelopes use `NOT_FOUND` for an unknown id and `VALIDATION_FAILED` for every other caller mistake.
|
|
53
54
|
|
|
55
|
+
## Readiness marks (`status`, feature P11)
|
|
56
|
+
|
|
57
|
+
The default `status` output separates four marks per maker and per decision
|
|
58
|
+
(`docs/design/decision-observability-and-adoption.md` §3.4.1):
|
|
59
|
+
|
|
60
|
+
| Mark | Column | Source |
|
|
61
|
+
| ---- | ------ | ------ |
|
|
62
|
+
| registered | `ST` glyph on the maker row | the maker registry holds the name |
|
|
63
|
+
| configured | `CONFIGURED BY` | `decisions.maker` / `decisions.makers.<id>` |
|
|
64
|
+
| recorded | `RECORDED` / `ACCEPTED` / `LAST SEEN` | the recorded `decision.end` ledger, matched on `(decisionId, maker)` |
|
|
65
|
+
| proven | `PROBE` (only with `--probe`) | one live liveness decision per maker |
|
|
66
|
+
|
|
67
|
+
`RECORDED` with `ACCEPTED 0` is the state that reads as healthy everywhere else: the maker is
|
|
68
|
+
registered and configured but has never once succeeded. `--probe` is the only path that calls a
|
|
69
|
+
maker, is bounded per driver, writes no decision log row and emits no event (`--probe` with
|
|
70
|
+
`--reliability` is refused). Parse the marks with `--json`: `makers[]`
|
|
71
|
+
(`registered`, `configuredBy`, `serves`, `evidence`), `perDecision[].evidence`, and `probes[]`
|
|
72
|
+
under `--probe`.
|
|
73
|
+
|
|
54
74
|
**Exit contract for `run` (design §3.4):** any backend-observed outcome — low confidence, model
|
|
55
75
|
error surfaced as fallback, declined — is still a **successful serve** (exit 0, envelope carries
|
|
56
76
|
`source`/`confidence` so callers can see why). Exit 1 is reserved for caller mistakes caught
|
|
@@ -95,11 +115,16 @@ spur decision run task-triage --param wbs=1093 --json
|
|
|
95
115
|
spur decision run failure-class --param wbs=1093 \
|
|
96
116
|
--evidence .spur/run/<runId>-test-output.txt # redacted evidence -> instructions
|
|
97
117
|
spur decision status --json | jq '.loadErrors' # audit catalog health
|
|
118
|
+
spur decision status # readiness marks: registered / configured / recorded
|
|
119
|
+
spur decision status --probe # prove each effective maker answers now
|
|
120
|
+
spur decision status --json | jq '.makers[] | {name, registered, recorded: .evidence.recorded}'
|
|
98
121
|
```
|
|
99
122
|
|
|
100
123
|
## References
|
|
101
124
|
|
|
102
|
-
- Design: `docs/design/decision-catalog.md` (§2 catalog authoring, §3.4 CLI surface)
|
|
125
|
+
- Design: `docs/design/decision-catalog.md` (§2 catalog authoring, §3.4 CLI surface),
|
|
126
|
+
`docs/design/decision-observability-and-adoption.md` (§3.4 reliability report, §3.4.1 readiness view)
|
|
103
127
|
- Hub: `@gobing-ai/ts-ai-decision` 0.5.22 (`DecisionService`, catalog schema, maker registry)
|
|
104
|
-
- App service: `packages/app/src/decision/decision-service.ts`
|
|
128
|
+
- App service: `packages/app/src/decision/decision-service.ts` (makers, `probeMaker`),
|
|
129
|
+
`packages/app/src/decision/decision-status-readiness.ts` (readiness marks, probe loop)
|
|
105
130
|
- Shipped catalogs: `config/decisions/*.yaml`
|
|
@@ -81,9 +81,45 @@ mode needs its own required args).
|
|
|
81
81
|
spur feature update H2 active
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Valid statuses: `backlog → active → verifying → blocked → done → cancelled
|
|
85
|
-
enforces legal transitions; `verifying` is the gate where AC
|
|
86
|
-
**One active goal** at a time is enforced by `check` (a corpus invariant).
|
|
84
|
+
Valid statuses: `backlog → active → verifying → blocked → done → cancelled`, plus the frozen
|
|
85
|
+
`deprecated`. The lifecycle engine enforces legal transitions; `verifying` is the gate where AC
|
|
86
|
+
traceability must hold (L4). **One active goal** at a time is enforced by `check` (a corpus invariant).
|
|
87
|
+
|
|
88
|
+
**`deprecated` — frozen, not terminal (ADR-136).** The state means *retained and frozen*: the record
|
|
89
|
+
stays readable and countable, but nothing may attach new work to it or advance it. It is entered from
|
|
90
|
+
`backlog`, `active`, `verifying`, `blocked` and `done`, and left only to `active` (un-deprecate,
|
|
91
|
+
mandatory History entry) or `cancelled` (removed) — every other edge out of `deprecated` is undeclared
|
|
92
|
+
and refused by the graph. The freeze, as shipped:
|
|
93
|
+
|
|
94
|
+
- **Task links are refused** — `task create`, `update --feature` and `batch-create` exit non-zero and
|
|
95
|
+
write nothing (no sibling hint; `--no-reopen` is irrelevant for a frozen parent):
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
parent-feature-status: feature <id> is deprecated (frozen); new tasks cannot link to it. Run removal work under its own feature, or un-deprecate: spur feature update <id> active
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- **`L4.feature-deprecated`** — `task check` warns (does not error) for a *live* task under a
|
|
102
|
+
deprecated feature; a terminal task is the correct end state and gets no finding; `--strict`
|
|
103
|
+
elevates the warning as usual:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
Feature "<id>" is deprecated (frozen) — re-parent this live task (`spur task update <wbs> --feature <otherId>`) or cancel it.
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- **`update --section` still lands** (exit `0`), appending a warning to `warnings[]`:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
Feature <id> is deprecated (frozen); change it only as part of removal
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
- **`sync` / `refresh` / `check --fix` never move it** — derivation is sticky and returns the no-op
|
|
116
|
+
proposal `{ from: 'deprecated', to: 'deprecated', reason: 'Feature is deprecated (frozen)' }`.
|
|
117
|
+
|
|
118
|
+
- **`advance` refuses** with exit `1`, naming the un-deprecate command:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
<id> is deprecated; un-deprecate first: spur feature update <id> active
|
|
122
|
+
```
|
|
87
123
|
|
|
88
124
|
**Scalar field set:**
|
|
89
125
|
|
|
@@ -113,7 +149,8 @@ spur feature advance H2 --to verifying
|
|
|
113
149
|
```
|
|
114
150
|
|
|
115
151
|
Walks the legal forward path (`backlog → active → verifying → done`) hop-by-hop until `--to`
|
|
116
|
-
(default `done`). No-op when already at the target
|
|
152
|
+
(default `done`). No-op when already at the target; a `deprecated` feature is refused up front (see
|
|
153
|
+
the freeze block above).
|
|
117
154
|
|
|
118
155
|
## Acceptance criteria conventions
|
|
119
156
|
|
|
@@ -169,7 +206,8 @@ the AC coverage map. Habits that keep it green:
|
|
|
169
206
|
Use feature hierarchy for user-facing capabilities and roadmap themes; keep technical-module mapping
|
|
170
207
|
as prose or notes unless the product surface is developer infrastructure. Priority is a scalar field
|
|
171
208
|
(`spur feature update <id> --field priority --value P1`), while status is lifecycle state
|
|
172
|
-
(`backlog → active → verifying → blocked → done → cancelled`). Do not
|
|
209
|
+
(`backlog → active → verifying → blocked → done → cancelled`, plus the frozen `deprecated`). Do not
|
|
210
|
+
conflate the two.
|
|
173
211
|
|
|
174
212
|
**Structure first:** [features/hierarchy-mece.md](features/hierarchy-mece.md) (MECE roots, when to
|
|
175
213
|
extend vs create). **Then priority:** [features/roadmap-priority.md](features/roadmap-priority.md).
|
|
@@ -216,6 +254,9 @@ spur feature sync H2 --force # re-derive live: bypass replay +
|
|
|
216
254
|
spur feature sync H2 --folder docs/custom-tasks --json # non-default tasks folder
|
|
217
255
|
```
|
|
218
256
|
|
|
257
|
+
- **`deprecated` is sticky:** derivation returns no proposal for it
|
|
258
|
+
(`reason: 'Feature is deprecated (frozen)'`), so neither `sync` nor `check --fix` moves a frozen
|
|
259
|
+
feature — see the freeze block in §Editing a feature.
|
|
219
260
|
- **`[id]`** syncs one feature; **`--all`** syncs every feature with linked tasks. One of the two is
|
|
220
261
|
required - exit `2` if neither is given.
|
|
221
262
|
- **`--dry-run`** reports proposed transitions without applying. **`--force`** applies a *reopen*
|
|
@@ -126,12 +126,32 @@ mutually exclusive.
|
|
|
126
126
|
spur task update 0040 wip
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
Valid statuses
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
Valid statuses are the canonical `TaskStatus` vocabulary — **`TASK_STATUSES` in
|
|
130
|
+
`packages/domain/src/planning/schema.ts` is the only list**, and the lifecycle engine enforces legal
|
|
131
|
+
transitions against the shipped `task-lifecycle` graph (the engine's bundled workflow, resolved per
|
|
132
|
+
project).
|
|
133
|
+
Operator-facing semantics (the freeze, its guards, the exempt write set) live in the design
|
|
134
|
+
satellite [`task-deprecated-status.md`](../../../../../docs/design/task-deprecated-status.md) — read it
|
|
135
|
+
there rather than restating the vocabulary. Two transitions are **guarded by `check`**:
|
|
136
|
+
`wip→testing` runs `spur task check <wbs> --as testing`, and `testing→done` runs
|
|
137
|
+
`spur task check <wbs> --as done` (F92 R3 — target-aware guards) — a failing
|
|
133
138
|
gate blocks the transition (§7.5).
|
|
134
139
|
|
|
140
|
+
**`deprecated` — frozen but retained (ADR-137).** Non-terminal: the record stays readable and
|
|
141
|
+
countable, but nothing new attaches to it and it never advances. Legal edges (from the shipped
|
|
142
|
+
graph): `backlog`, `todo`, `wip`, `testing`, `blocked` and `done` may move to `deprecated`, and it leaves only to `todo`
|
|
143
|
+
(un-deprecate, mandatory `History` entry) or `cancelled` (removed). Any other status write is
|
|
144
|
+
refused by the graph, and the refusal names the un-deprecate command.
|
|
145
|
+
|
|
146
|
+
Two guards carry the freeze past the graph: a **new** dependency edge onto a `deprecated` task is
|
|
147
|
+
refused (ready-set resolver and pipeline preflight), and a live dependent is reported by the
|
|
148
|
+
`L4.task-deprecated` warning. The freeze is prospective — an edge recorded before the deprecation is
|
|
149
|
+
reported, never rewritten.
|
|
150
|
+
|
|
151
|
+
Writes that stay **permitted** on a `deprecated` task (each edits the record rather than declaring
|
|
152
|
+
the work resumable): `spur task record`, `migrate-anchors` and verdict writes, and
|
|
153
|
+
`spur task update <wbs> --section <any>` — the section write lands and returns a freeze warning.
|
|
154
|
+
|
|
135
155
|
**`--no-lifecycle`** suppresses lifecycle workflow *run record* creation (use during pipeline-driven
|
|
136
156
|
transitions so nested lifecycle runs are not orphaned). **It is not a guard bypass** — the
|
|
137
157
|
`wip→testing` / `testing→done` `check` gates still run, evaluated inline when the FSM guard does not.
|
|
@@ -572,7 +572,14 @@ does not earn another full-gate run:
|
|
|
572
572
|
4. Give the test an explicit per-test timeout and a WHY comment (see
|
|
573
573
|
`plugins/sp/tests/inline-run-close-reason.test.ts:100-102`) as soon as EITHER (a) the same test
|
|
574
574
|
load-flakes in two separate runs, OR (b) it times out once **outside the change scope** and then
|
|
575
|
-
passes green alone on three consecutive isolated reruns.
|
|
575
|
+
passes green alone on three consecutive isolated reruns. **Prefer making the test cheap or
|
|
576
|
+
hermetic first** — a test that hashes the live checkout transitively, or writes a probe file into
|
|
577
|
+
it, should build a `mkdtemp` fixture repo instead of buying a bigger budget
|
|
578
|
+
(`packages/app/tests/workflow/actions/proof-fingerprint.test.ts` is the pattern, 2026-10-13).
|
|
579
|
+
Only then hand the remaining repeat flakers an explicit budget: the suite-wide `--timeout` is
|
|
580
|
+
not the lever, and raising it was measured NOT to help (a 60s suite default still failed 7
|
|
581
|
+
spawn-heavy tests under a host shared with two sibling agent suites, while every one passed
|
|
582
|
+
alone in 0.15-0.3s — 2026-10-13). Waiting for a second gate run to license
|
|
576
583
|
the fix cost 21 minutes on 2026-10-08 (task 1128, the 1058 two-tree canary: 5145 ms then 5967 ms
|
|
577
584
|
against bun's 5000 ms default, green 3/3 alone). Never raise the global timeout, skip the test,
|
|
578
585
|
or loop full-gate reruns.
|
|
@@ -79,7 +79,7 @@ each would be scope creep for one-liner procedures.
|
|
|
79
79
|
| 6 | plan | `dev-plan` | `Skill()` | inline driver (`idea-pipeline`) or async workflow | `"<description>" [--feature <id>] [--parent <feature-id>] [--skip-design] [--agent <inline\|auto\|name>] [--auto]` |
|
|
80
80
|
| 7 | docs | _(no thin wrapper)_ | `Skill()` | `sp:doc-evolve` | `"<change description>"` |
|
|
81
81
|
| 8 | changelog | `dev-changelog` | `inline` | git log + conventional-commit grouping | `[<file>] [--since <ref>] [--until <ref>] [--version <ver>]` |
|
|
82
|
-
| 9 | gitmsg | `dev-gitmsg` | `inline` | bounded diff capture → concern grouping → conventional commit | `[--commit] [--squash] [--all] [--scope <path>]`
|
|
82
|
+
| 9 | gitmsg | `dev-gitmsg` | `inline` | bounded diff capture → concern grouping → conventional commit | `[--commit] [--squash] [--all] [--scope <path>] [--check <cmd>]` |
|
|
83
83
|
| 10 | fixall | `dev-fixall` | `inline` | lint + test fix loop | `[<validation-command>] [--max-retry <n>] [--scope <path>] [--gate-log <path>] [--findings <anchors>]` |
|
|
84
84
|
| 11 | handover | `dev-handover` | `inline` | structured doc generation | `"<blocker description>"` |
|
|
85
85
|
| 11a | job-dump | `dev-job-dump` | `Skill()` | `sp:spur-dev` (`job-dump`) | `--file <path>` |
|
|
@@ -250,7 +250,8 @@ check receipt (`receipt.runId === runId`), otherwise `n/a (<reason>)`. Any value
|
|
|
250
250
|
checklist** against target sections (read codebases, ADRs, dependent WBS, dogfood evidence as
|
|
251
251
|
needed). If any item fails, synthesize and rewrite via CLI-gated section updates until all pass
|
|
252
252
|
(or surface a blocked Q&A with a concrete question). Outcome vocabulary: `refined` (wrote) |
|
|
253
|
-
`ready` (checklist already met, no write — optional alias of refined with zero writes) |
|
|
253
|
+
`ready` (checklist already met, no write — optional alias of refined with zero writes) |
|
|
254
|
+
`cancelled` (issue triage found no valid issue — see `premises`) | `failed`.
|
|
254
255
|
Prefer reporting `refined` when any section changed; if checklist already fully met, emit:
|
|
255
256
|
|
|
256
257
|
```
|
|
@@ -295,6 +296,17 @@ check receipt (`receipt.runId === runId`), otherwise `n/a (<reason>)`. Any value
|
|
|
295
296
|
list`, `spur task list --status wip --json`) are recorded in References/Design.
|
|
296
297
|
- **Scope** — the work is not already done, and not owned by another task.
|
|
297
298
|
|
|
299
|
+
**Issue triage.** When the task bundles several issues (findings, defects, R-items with their
|
|
300
|
+
proposed fixes), judge each one separately as `valid` (reproduced or confirmed in the current
|
|
301
|
+
tree), `already-fixed`, `owned-elsewhere` (name the WBS) or `invalid` (premise false). An issue
|
|
302
|
+
that is not `valid` is removed **with everything that exists only for it**: its Background
|
|
303
|
+
paragraph, R-items, Design/Solution notes, Plan steps and ACs. Renumber nothing that other
|
|
304
|
+
tasks or feature scenarios cite; leave a gap instead. Each removal is one correction-record
|
|
305
|
+
line. When **no** issue stays valid, do not rewrite the task. Record the triage in the
|
|
306
|
+
correction block, then `spur task update <wbs> cancelled --json`, and report outcome
|
|
307
|
+
`cancelled`. Cancelling is not demotion; it is valid only within the backlog/todo status scope
|
|
308
|
+
above.
|
|
309
|
+
|
|
298
310
|
Contradictions are corrected in **this** refine (rewrite the claim, or re-point the design at
|
|
299
311
|
ground truth), never deferred to the implementer. `--depth ready` exists so a downstream agent
|
|
300
312
|
does not re-derive the analysis; a frozen design built on a false premise is the worst
|
|
@@ -309,7 +321,10 @@ check receipt (`receipt.runId === runId`), otherwise `n/a (<reason>)`. Any value
|
|
|
309
321
|
1. Run `spur task check <wbs> --as todo --json`. Any error means the task is not ready. Fix it,
|
|
310
322
|
or report `failed`.
|
|
311
323
|
2. Fill metadata that is still unset: `spur task update <wbs> --priority <P0–P3>` and
|
|
312
|
-
`--estimate-hours <n>` (both `--json`). Never overwrite a value the operator set.
|
|
324
|
+
`--estimate-hours <n>` (both `--json`). Never overwrite a value the operator set. The one
|
|
325
|
+
exception is a triage that dropped issues: re-estimate the remaining scope and record
|
|
326
|
+
old → new in the correction block. The CLI cannot rename a task. When a drop leaves the title
|
|
327
|
+
naming removed scope, record that in the correction block as well.
|
|
313
328
|
3. Promote `backlog → todo` idempotently with `spur task update <wbs> todo --json`, the same FSM
|
|
314
329
|
transition `--next` uses. Create-time ready preparation skips its own promotion when the task
|
|
315
330
|
is already `todo`, and next-router stops routing the task back to refine. Without `--next`,
|
|
@@ -341,9 +356,10 @@ check receipt (`receipt.runId === runId`), otherwise `n/a (<reason>)`. Any value
|
|
|
341
356
|
3. Topo-sort by `dependencies[]` (Kahn, WBS-ascending tie-break). Cycle → abort entire batch before any refine. Out-of-set deps: `done` → allow; else → block subtree (same as runall).
|
|
342
357
|
4. For each WBS in order: invoke single-task refine with shared flags **including `--depth`**. Under `--auto` + **`--depth standard`** (default), the per-task **L3 pre-synthesis SKIP gate** still applies. Under **`--depth ready`**, each task runs the implement-ready checklist (no L3-only SKIP). That includes the premises audit, the correction record and ready finalization, so a passing task leaves at `todo`.
|
|
343
358
|
5. Failure policy: **stop-the-batch** (default) or `--keep-going` (skip in-batch dependents of a failed refine; continue independents).
|
|
344
|
-
6. Emit a batch report (markdown or `--json`) that records `depth` once at the header. Under `--depth ready`, each row also carries the corrections count, status before → after, and failed checklist ids.
|
|
345
|
-
|
|
346
|
-
- **
|
|
359
|
+
6. Emit a batch report (markdown or `--json`) that records `depth` once at the header. Under `--depth ready`, each row also carries the corrections count, dropped issues, status before → after, and failed checklist ids.
|
|
360
|
+
7. **Cross-task proposals (`--depth ready` only).** After the per-task pass, list two kinds of proposals in the report: tasks whose remaining issues overlap another set member (same root cause or file set → name the merge target; tasks that only share a step, such as one upstream release, or that fix two layers of one failure → propose ordering or a shared step, not a merge), and tasks with no `feature_id` (name the candidate owning feature with evidence). These are proposals only. Refineall merges, cancels or links a task only when the operator's `--description` names that task and the action (e.g. `cancel 0273 and merge its issues into 0269; link 0260 to G11`). That explicit directive is the confirmation the [feature-link helper](feature-link-helper.md) requires. A merge moves the surviving issues with their fixes into the target through CLI section updates, records the merge in both tasks' correction blocks, then cancels the source. Run directives before the per-task pass, so each target is refined with its merged content.
|
|
361
|
+
- **Per-task outcome vocabulary:** `refined` (synthesis wrote sections) | `SKIP` (already meets the active depth bar under `--auto`) | `cancelled` (no valid issue left, or merged away by directive) | `failed` | `skipped` (dep failed under `--keep-going`) | `not-attempted` (halted) | `blocked` (unmet out-of-set dep).
|
|
362
|
+
- **Batch verdict:** `clean` (all attempted tasks `refined`, `SKIP` or `cancelled`) | `halted` (a failure stopped the batch) | `aborted` (cycle / unknown selector / empty set after filter).
|
|
347
363
|
- **`--next` is not accepted** (dropped by feature H8, 2026-07-31 — see `plugins/sp/commands/dev-refineall.md` for the removal record). Chain execution explicitly: refineall, then `/sp:dev-runall --feature <id>`.
|
|
348
364
|
- **`--auto` recommendation:** Batch refine without `--auto` requires per-task interactive Q&A and does not scale. Default operator path: `/sp:dev-refineall --feature <id> --auto`. For implement handoffs, or to re-audit a feature's filed tasks: `/sp:dev-refineall --feature <id> --auto --depth ready`.
|
|
349
365
|
- **Delegation:** `Skill(skill="sp:spur-dev", args="refineall $ARGUMENTS")` → per task `Skill(skill="sp:spur-dev", args="refine <wbs> $SHARED_FLAGS")` (shared flags include `--depth` when set).
|
|
@@ -375,7 +391,7 @@ check receipt (`receipt.runId === runId`), otherwise `n/a (<reason>)`. Any value
|
|
|
375
391
|
- **Behavior:**
|
|
376
392
|
1. Parse arguments, preserving quoted paths with spaces. Reject a missing/empty path, repeated `--file`, unknown flags, or extra positional arguments with usage. Resolve the absolute path before changing directories. Reject a directory target; create missing parent directories. Respect CLI-gated corpus writes: task/feature documents cannot be dump targets.
|
|
377
393
|
2. Gather the mission, original invocation/options, approved outcome, completed and partial work, blockers, and next actions. Verify repository/worktree paths, branch, HEAD/base, dirty files and relevant commits with Git. Inspect referenced tasks/features/runs through the CLI facade with `--json` in their execution directory. Preserve frozen batch membership, dependency order, run IDs, workflow/checkpoint identity, failure policy, executor state and worktree marker when applicable. Record inspection time and provenance; label unavailable facts `unknown`.
|
|
378
|
-
3. Fill every template section for this job; use `N/A` where inapplicable. Include uncommitted work and ownership, gate commands/results, pending questions, approvals given or still required, discovery maps, evidence paths, and wrap/merge/cleanup success conditions. Keep confirmed lessons and rejected approaches with anchors. Link authoritative specifications instead of copying them; never turn task-specific bypasses into general instructions.
|
|
394
|
+
3. Fill every template section for this job; use `N/A` where inapplicable. Include uncommitted work and ownership, gate commands/results already on record (never run a gate to fill this — write `not run`), pending questions, approvals given or still required, discovery maps, evidence paths, and wrap/merge/cleanup success conditions. Keep confirmed lessons and rejected approaches with anchors. Link authoritative specifications instead of copying them; never turn task-specific bypasses into general instructions.
|
|
379
395
|
4. Redact credentials, tokens and sensitive personal data. Link large logs/artifacts by path and note their durability and availability to the recipient; the Markdown file does not transfer referenced files. Include essential continuation context directly so missing optional scratch notes do not erase the plan.
|
|
380
396
|
5. Construct the complete snapshot before writing or refreshing `--file`. Read it back to verify the mission, execution directory, ordered remaining work and first actions. Report the absolute path and unresolved facts. Dumping only saves context: it does not stop an active executor, execute remaining work, change lifecycle state, commit, merge, or remove a worktree; record any executor still running.
|
|
381
397
|
|
|
@@ -552,6 +568,14 @@ gate commands, pending questions and approval requirements.>
|
|
|
552
568
|
These define their procedure directly in the command file. No `Skill()` delegation — the command
|
|
553
569
|
is the procedure. The backing is a combination of git CLI, `spur` CLI, and agent reasoning.
|
|
554
570
|
|
|
571
|
+
**Gate ownership.** A project quality gate (`bun run gate`, `spur-check`, lint, typecheck, tests,
|
|
572
|
+
rule runs) runs only where an operation's own contract names it: the pipeline `test` hop
|
|
573
|
+
(`run`/`runall`), `fixall`, `gtd`, `fixgha`, `unit`, and the `--check <cmd>` loops. The scribe
|
|
574
|
+
operations — `changelog`, `gitmsg`, `handover`, `job-dump` — produce text or a commit, not code, so
|
|
575
|
+
they run **no gate by default**, and a generic "verify before you finish" rule from `AGENTS.md` or
|
|
576
|
+
host instructions does not add one. An opt-in gate is explicit: `gitmsg --check <cmd>`, or
|
|
577
|
+
`/sp:dev-gtd [--no-push]` for gate → auto-fix → commit. Commit hooks still run as configured.
|
|
578
|
+
|
|
555
579
|
### 8. changelog
|
|
556
580
|
|
|
557
581
|
- **Purpose:** Generate a structured changelog from git commits between two refs.
|
|
@@ -568,12 +592,12 @@ is the procedure. The backing is a combination of git CLI, `spur` CLI, and agent
|
|
|
568
592
|
6. Emit: with `<file>`, insert the section into that file above its newest `## [` release heading (or after its title when none exists) and touch nothing else in the file; without `<file>`, print it to stdout.
|
|
569
593
|
7. Self-check before emitting: every short hash in `<since>..<until>` appears exactly once. Fix any miss or duplicate; do not report a verdict.
|
|
570
594
|
8. Reply in at most three lines: the range, bullet counts per category, and the output target.
|
|
571
|
-
- **Invariants:** Output is derived from `git log` only. No quality gates — no lint/test/`spur-check`/rule runs, citation or manifest lookups, confidence ratings, or edits beyond the one inserted section. The file is left uncommitted.
|
|
595
|
+
- **Invariants:** Output is derived from `git log` only. No quality gates — no `bun run gate`/lint/typecheck/test/`spur-check`/rule runs, citation or manifest lookups, confidence ratings, or edits beyond the one inserted section. The file is left uncommitted.
|
|
572
596
|
|
|
573
597
|
### 9. gitmsg
|
|
574
598
|
|
|
575
599
|
- **Purpose:** Generate conventional commit message(s) for the current change set — one gather call → concern grouping → one message per concern; optionally commit. Git + POSIX shell only; no helper script.
|
|
576
|
-
- **Inputs:** `--scope <path>` (default: the whole change set) — path filter; an explicit `--scope` always wins over change-set auto-discovery. `--all` (default: off) — widen the change set past the index to every change in the tree: unstaged **and untracked** files. Omitted, the change set is the index only, which keeps pre-commit semantics stable. `--commit` (default: off) — commit the change set, one commit per concern. `--squash` (default: off) — collapse every concern into one message and one commit; implies `--commit`.
|
|
600
|
+
- **Inputs:** `--scope <path>` (default: the whole change set) — path filter; an explicit `--scope` always wins over change-set auto-discovery. `--check <cmd>` (default: off) — run `<cmd>` once as a pre-commit gate (step 5a). `--all` (default: off) — widen the change set past the index to every change in the tree: unstaged **and untracked** files. Omitted, the change set is the index only, which keeps pre-commit semantics stable. `--commit` (default: off) — commit the change set, one commit per concern. `--squash` (default: off) — collapse every concern into one message and one commit; implies `--commit`.
|
|
577
601
|
- **Backing:** `inline` — one bounded gather call + concern grouping + conventional commit formatting.
|
|
578
602
|
- **Behavior:**
|
|
579
603
|
|
|
@@ -631,6 +655,8 @@ is the procedure. The backing is a combination of git CLI, `spur` CLI, and agent
|
|
|
631
655
|
|
|
632
656
|
5. **Report.** Print: one context line (branch; `linked worktree` when `--git-dir` ≠ `--git-common-dir` and the superproject line is empty), then each message in a fenced block. No per-file summaries, no restated diff. With neither `--commit` nor `--squash`, add one copy-paste `git commit` line per message and stop.
|
|
633
657
|
|
|
658
|
+
5a. **Gate (`--check <cmd>` only) — one more Bash call.** Without `--check`, run no gate of any kind. With it, run `<cmd>` exactly once, verbatim, after the report: exit 0 → one `check PASS` line and continue; non-zero → print its last 30 lines and commit nothing. Never fix, retry, or widen the command — gate → fix → commit is `/sp:dev-gtd`.
|
|
659
|
+
|
|
634
660
|
6. **Commit (`--commit` / `--squash`) — one more Bash call.** `--squash` implies `--commit`, so both together is just `--squash`. Refuse before touching the index when:
|
|
635
661
|
- `## secret hits` is non-empty → print each `file: line`, commit nothing;
|
|
636
662
|
- `--commit` would split (more than one group) and `## partially staged` is non-empty → splitting would widen those `git add -p` stagings to whole files; print the paths and commit nothing (`--squash` is allowed — it commits the index as staged).
|
|
@@ -649,7 +675,7 @@ is the procedure. The backing is a combination of git CLI, `spur` CLI, and agent
|
|
|
649
675
|
|
|
650
676
|
Hooks stay enabled; a failing hook stops the run with its output — never `--no-verify`.
|
|
651
677
|
|
|
652
|
-
- **Invariants:** Git and POSIX shell only — no helper script, no temp file. At most two Bash calls: gather, then (only when committing) commit. With neither `--commit` nor `--squash`, never runs `git commit` — message only. Neither flag commits across a secret hit, and `--commit` never splits across a partial staging. Without `--all` the change set is the index, so plain `/sp:dev-gitmsg` keeps pre-commit semantics; only `--all` reaches unstaged and untracked files, and only a committing run stages them. The empty-index widen is read-only and always announced — a committing run never widens its own scope. An explicit `--scope <path>` always bounds the change set, with or without `--all`. One bounded, context-free capture per run — never a second, wider read.
|
|
678
|
+
- **Invariants:** Git and POSIX shell only — no helper script, no temp file. At most two Bash calls: gather, then (only when committing) commit — three with `--check`. No quality gate (`bun run gate`, lint, typecheck, tests, `spur-check`) unless `--check` names one. With neither `--commit` nor `--squash`, never runs `git commit` — message only. Neither flag commits across a secret hit, and `--commit` never splits across a partial staging. Without `--all` the change set is the index, so plain `/sp:dev-gitmsg` keeps pre-commit semantics; only `--all` reaches unstaged and untracked files, and only a committing run stages them. The empty-index widen is read-only and always announced — a committing run never widens its own scope. An explicit `--scope <path>` always bounds the change set, with or without `--all`. One bounded, context-free capture per run — never a second, wider read.
|
|
653
679
|
|
|
654
680
|
### 10. fixall
|
|
655
681
|
|
|
@@ -796,4 +822,4 @@ is the procedure. The backing is a combination of git CLI, `spur` CLI, and agent
|
|
|
796
822
|
`## Testing`, `## Review`), verdict files (`.spur/run/<wbs>-verdict.json`), diffs, and docs — by
|
|
797
823
|
**path**, not by pasting their content into the handover body. The handover is a pointer document;
|
|
798
824
|
restating content it can instead link to makes it stale the moment the source changes.
|
|
799
|
-
- **Invariants:** The handover is honest — rejected approaches are recorded so the next agent doesn't retry them. The blocker is specific, not "it doesn't work."
|
|
825
|
+
- **Invariants:** The handover is honest — rejected approaches are recorded so the next agent doesn't retry them. The blocker is specific, not "it doesn't work." No quality gate runs — cite gate results already on record.
|
|
@@ -126,7 +126,7 @@ success exits 0 printing
|
|
|
126
126
|
`{"ok":true,"persisted":<n>,"skipped":[{"id":<run-id>,"reason":"id-exists"|"external-key-conflict"|"record-conflict:<file>"|"record-missing:<file>"|"cited-directory:<name>"|"cited-symlink:<name>"|"cited-non-file:<name>"}],"evidenceSkipped":[{"name":<file>,"reason":"foreign-divergent","newer":"invoking"|"worktree"}]}`
|
|
127
127
|
(`evidenceSkipped` is omitted when empty; the same object is written to `<invoking-tree>/.spur/run/persist-out.json` for `persist-out-check` to read)
|
|
128
128
|
— an `external-key-conflict` skip leaves the target run unchanged **and fails the pass (1049)**: the delegate exits 1 printing `{"ok":false,"error":…}` naming the skipped source run ids, because that (workflow, external key) identity already belongs to a different receiving run — the batch was not persisted, so reconcile the source worktree by hand (it stays the provenance owner of record) before any teardown: auditable reconciliation names the original archived DB snapshot and the skipped source run identities, verifies the archive by file hash and by merged-commit ancestry of the source branch, and treats any residual deletion as explicit operator-authorized cleanup under the strict canonical evidence rules above. Task 1149 R1 grades a terminal duplicate lifecycle row (`task-lifecycle`/`feature-lifecycle`) as `external-key-conflict-bookkeeping` (non-fatal), so guarded transitions driven inside the worktree do not block teardown; the receiving lifecycle row is reconciled automatically during persist-out. An `id-exists` replay repairs missing owned artifacts and task links without duplicating them. A
|
|
129
|
-
`record-conflict:<file>` never overwrites a divergent invoking-tree record and causes the delegate to exit 1, retaining the worktree. A
|
|
129
|
+
`record-conflict:<file>` never overwrites a divergent invoking-tree record and causes the delegate to exit 1, retaining the worktree. Before reconciling one by hand, check **what** the invoking record is: when the run closed `done` inside a linked worktree the owning tree holds that run's **WT-0 landing obligation** (`landing: required branch=… path=… base=…`, see [execution-worktree-landing.md § WT-0](execution-worktree-landing.md#wt-0--markerless-worktree-runs)) — a 3-line record that is *not* a stub of the worktree's stage narrative, so copying the worktree record over it destroys the very obligation a later merge must rewrite. The reconciliation is therefore: discharge the obligation in place (`landing: merged <sha>` or `landing: retained`), and preserve the worktree narrative beside it (e.g. `<runId>.worktree-provenance.md`) rather than in place of it. A
|
|
130
130
|
`record-missing:<file>` skip is a known `task-lifecycle`/`feature-lifecycle` row with no record file
|
|
131
131
|
at all (its inserted DB row still counts in `persisted` — 0984 R5). Any failure
|
|
132
132
|
exits 1 printing `{"ok":false,"error":<message>}` (a worktree DB run id that is not a single safe
|
|
@@ -152,8 +152,8 @@ kickoff** — the driver never re-queries `spur task list` to recompute membersh
|
|
|
152
152
|
| --- | --- | --- |
|
|
153
153
|
| Explicit WBS list | `^[0-9, ]+$` | Split on comma; validate each token is a 4-digit WBS; collect the explicit set. (R1.1) |
|
|
154
154
|
| `feature:<id>` (via `--tasks` or `--feature <id>`) | literal `feature:` prefix or `--feature` flag | `spur task list --feature <id> --json`; collect `wbs` from each row. The `--feature` flag is sugar that becomes `--tasks feature:<id>` at the command layer. (R1.3) |
|
|
155
|
-
| `ready` | literal `ready` | Resolve the union of `spur task list --status todo --json` + `spur task list --status backlog --json`, drop tasks with open children (R1.5, umbrella-parent exclusion below), then keep only tasks whose every `dependencies[]` entry resolves to `status == done` (via `spur task show <dep> --json | jq '{wbs, status, dependencies, feature_id}'` — R5 metadata-only). Report each excluded task with its unmet dependency. (R1.4) |
|
|
156
|
-
| Status pseudo-list | `todo` \| `backlog` \| `wip` \| `blocked` \| `testing` | `spur task list --status <value> --json`; collect `wbs` from each row. (R1.2) |
|
|
155
|
+
| `ready` | literal `ready` | Resolve the union of `spur task list --status todo --json` + `spur task list --status backlog --json`, drop tasks with open children (R1.5, umbrella-parent exclusion below), then keep only tasks whose every `dependencies[]` entry resolves to `status == done` (via `spur task show <dep> --json | jq '{wbs, status, dependencies, feature_id}'` — R5 metadata-only). Report each excluded task with its unmet dependency. A `deprecated` dependency is *not* satisfied (ADR-137: a frozen task never reads as `done`), so it keeps its dependents out of the ready set. (R1.4) |
|
|
156
|
+
| Status pseudo-list | `todo` \| `backlog` \| `wip` \| `blocked` \| `testing` | `spur task list --status <value> --json`; collect `wbs` from each row. (R1.2) `deprecated` is deliberately not a selector value: a frozen task has no pipeline hop to drive, so a batch is never built from that status (ADR-137; `/sp:dev-next` row A10 stops the same way). |
|
|
157
157
|
| *(else)* | no match | Error: "unknown selector `<value>`" — list the valid forms and halt before running anything. |
|
|
158
158
|
|
|
159
159
|
**Dedup:** an explicit list with a repeated WBS (`--tasks 0040,0040`) collapses to a single entry;
|
|
@@ -200,7 +200,9 @@ For each dependency edge to a task **outside** the frozen set, resolve its curre
|
|
|
200
200
|
- status ≠ `done` → mark the dependent **blocked**. Transitively mark its in-set descendants blocked
|
|
201
201
|
too (fixpoint propagation: any task depending on a blocked task is itself blocked). Exclude all
|
|
202
202
|
blocked tasks from execution and record the unmet dependency + the blocked subtree for the report
|
|
203
|
-
(R2.4). Independent (non-blocked) tasks in the set still run.
|
|
203
|
+
(R2.4). Independent (non-blocked) tasks in the set still run. **`deprecated` is not satisfied**
|
|
204
|
+
(ADR-137): a frozen task never reads as `done`, so the dependent blocks and the report names the
|
|
205
|
+
remedy — re-point the edge, or un-deprecate (`spur task update <dep> todo`).
|
|
204
206
|
|
|
205
207
|
### 2.4 Topological sort
|
|
206
208
|
|
|
@@ -277,6 +279,7 @@ node "$(superskill script path sp batch-preflight.mjs)" \
|
|
|
277
279
|
| `action: skip` code **A2** | Do not launch; report `preflight-skip` + unmet deps (mirrors TABLE A2) |
|
|
278
280
|
| `action: skip` code **A7** | Do not launch; report blocked (handover is operator-side) |
|
|
279
281
|
| `action: skip` code **A8**/**A9** | Do not launch; already done / cancelled |
|
|
282
|
+
| `action: skip` code **DEPRECATED** | Do not launch; frozen and retained (ADR-137) — the reason line names the un-deprecate command. A deprecated WBS can reach preflight through an explicit `--tasks` list or a `feature:<id>` selector (`spur task list --feature` reports every linked row, whatever its status); the `ready` and status pseudo-lists exclude it |
|
|
280
283
|
|
|
281
284
|
**Invariants:** Preflight never replaces the pipeline with a loop of `/sp:dev-next`. TABLES A/B/C
|
|
282
285
|
remain SSOT in `next-router/references/routing-table.md`. Step 2.3 already pre-blocks many unmet
|
|
@@ -606,15 +609,25 @@ The cheap rule gates fail fast when run first — the full-gate run is dominated
|
|
|
606
609
|
suite, so a gate run that dies at `test-post-check` or `corpus-check` wastes most of its wall time.
|
|
607
610
|
Before launching a full `spur-check-new`:
|
|
608
611
|
|
|
609
|
-
1. **Run the
|
|
612
|
+
1. **Run the static checks first** — `bun run lint` (biome over the whole tree plus every workspace
|
|
613
|
+
typecheck). They fail in ~20 s and are the two defects that most often kill a full launch: a
|
|
614
|
+
formatting miss in a touched test file, or a generated declaration surface that no longer lists a
|
|
615
|
+
new export. Measured 2026-10-12: two consecutive `spur-check` launches died here and each spent
|
|
616
|
+
its whole wall time before reaching the suite.
|
|
617
|
+
2. **Then the two rule gates** — `bun run test-pre-check` (43 rules: `no-console-output`,
|
|
610
618
|
`no-direct-process-spawn`, `cli-*`, `require-corresponding-test`) and `bun run test-post-check`
|
|
611
619
|
(`every-export-has-tsdoc`, `coverage-gate`). They catch boundary/TSDoc violations in seconds.
|
|
612
|
-
|
|
620
|
+
Two `coverage-gate` facts change how you call post-check: it **fails closed when
|
|
621
|
+
`.coverage/lcov.info` is absent**, which is the normal state of a fresh worktree, so run it after
|
|
622
|
+
the suite has written coverage or expect that one error instead of reading it as a finding; and a
|
|
623
|
+
targeted `bun test <file>` **overwrites** the tracefile, so post-check judges partial data if it
|
|
624
|
+
runs after one (the `coverage-gate` rule's own header documents both facts).
|
|
625
|
+
3. **Promoted code must satisfy the boundary rules `scripts/` never enforced.** A command module
|
|
613
626
|
moving from `scripts/` into `apps/cli/src` must route output through the `CommandOutput` seam (no
|
|
614
627
|
`console.*`), spawn processes via `NodeProcessExecutor` (no `Bun.spawnSync`), get a
|
|
615
628
|
`runtime-boundaries` fs-io exemption for sync reads (mirrors `task.ts`), and a non-command helper
|
|
616
629
|
must not live in `apps/cli/src/commands/` (the noun scan treats every file there as a noun).
|
|
617
|
-
|
|
630
|
+
4. **Doc/TSDoc edits shift `file:line` anchors** cited by other tasks — the per-task gate surfaces
|
|
618
631
|
them as `L4.anchor-subject-mismatch` (0775: the corpus sweep retired; run `spur task check <wbs>`
|
|
619
632
|
on touched tasks). Repoint the shifted citations (via `spur task update --section`)
|
|
620
633
|
|
|
@@ -16,6 +16,28 @@ When the batch completes with **no failed task**, fast-forward-merge the worktre
|
|
|
16
16
|
base ref. The terminal action after the merge differs by mode (ownership rule: *the flag removes
|
|
17
17
|
only what it created*):
|
|
18
18
|
|
|
19
|
+
**Duplicate-WBS sweep before the merge (observed 2026-10-12).** WBS allocation is per-tree — a
|
|
20
|
+
worktree's allocator reads only its own corpus and DB — so two trees cut from the same base both
|
|
21
|
+
allocate the same next number, and the collision surfaces only here (measured: the F42 batch's
|
|
22
|
+
residual task shipped as `1183` while the base ref had already given `1183` to another task, so the
|
|
23
|
+
file had to be re-filed before landing). Run this against the ref you are about to merge INTO:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
TARGET=<base-ref>; BRANCH=sp/<branch>
|
|
27
|
+
for f in $(git diff --diff-filter=A --name-only "$(git merge-base "$TARGET" "$BRANCH")..$BRANCH" -- docs \
|
|
28
|
+
| grep -E '^docs/tasks[0-9]*/'); do
|
|
29
|
+
wbs=$(basename "$f" | cut -c1-4)
|
|
30
|
+
git ls-tree -r --name-only "$TARGET" -- docs | grep -qE "/${wbs}_" && echo "COLLISION $wbs $f"
|
|
31
|
+
done
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
A hit means one file must lose: keep the target's task, re-create the branch's task in the invoking
|
|
35
|
+
tree through `spur task create` (the allocator picks the next free number), and drop the branch's
|
|
36
|
+
file in the merge resolution — never land both, and never renumber by hand. Verified against a
|
|
37
|
+
fixture (flags a duplicate, silent on a free WBS). The pathspec form is load-bearing: `-- docs` plus
|
|
38
|
+
the `^docs/tasks[0-9]*/` filter, because plain `docs/tasks*` matches nothing under `ls-tree` here and
|
|
39
|
+
`:(glob)` magic is rejected by `ls-tree`/`diff` (it works for `git status`).
|
|
40
|
+
|
|
19
41
|
#### Create mode — merge, remove, delete
|
|
20
42
|
|
|
21
43
|
```bash
|
|
@@ -180,6 +180,13 @@ main-repo hooks from inside the "isolated" tree. Scripts are skipped only at thi
|
|
|
180
180
|
a normal clone keeps `prepare`. The worktree still gets a usable dependency tree — the install
|
|
181
181
|
exists so the first `bun test` resolves workspace imports.
|
|
182
182
|
|
|
183
|
+
**Generated trees are still missing after the install.** A gitignored generated tree does not ride the
|
|
184
|
+
worktree, so any suite comparing the canonical source against its generated copy fails until the
|
|
185
|
+
generator runs. In this repo that is `apps/cli/config/` (from `bun run bundle:config`): without it
|
|
186
|
+
`plugins/sp/tests/command-flag-parity.test.ts` fails on the missing generated pipeline YAML under that
|
|
187
|
+
directory (observed 2026-10-12, A91 batch). Run the generator once after a create-mode install, and
|
|
188
|
+
again after a rebase or merge that touches the canonical workflow sources it is built from.
|
|
189
|
+
|
|
183
190
|
#### Reuse mode (`--worktree <name>`)
|
|
184
191
|
|
|
185
192
|
Creation is **skipped entirely**. `$BRANCH` is the resolved worktree's already-checked-out branch; a
|
|
@@ -374,6 +381,13 @@ same call, verifies the WT-3 identity, and never relies on a persistent `cd` or
|
|
|
374
381
|
> concurrent writer happened to leave in the tree — the two incidents this guard exists for are
|
|
375
382
|
> `a94f9f431` and `36f274590` — so a driver stages only through `commit-guard stage`.
|
|
376
383
|
|
|
384
|
+
> **`stage` takes files, never directories.** A directory argument is refused as `(unchanged since
|
|
385
|
+
> base)` and stages *nothing*, so a task whose diff lives in a moved tree must expand the changed
|
|
386
|
+
> paths (`git status --porcelain` plus the filter for the task's own files) instead of passing
|
|
387
|
+
> `plugins/sp/hooks` or `packages/app/tests/hooks`. Symptom observed on 2026-10-12 (A91 batch): the
|
|
388
|
+
> first commit captured only the pre-staged `git mv`/`git rm` renames and needed an amend to carry
|
|
389
|
+
> the rest of the task.
|
|
390
|
+
|
|
377
391
|
The FF-only git merge carries only commits — uncommitted writes in the worktree would be left
|
|
378
392
|
behind by the merge and then destroyed by create mode's `git worktree remove`. WT-3b exists so
|
|
379
393
|
that can never happen.
|
|
@@ -225,8 +225,10 @@ the `feature:<id>` sets, resolved once and frozen.
|
|
|
225
225
|
|
|
226
226
|
**Anchor:** `#flag-check`.
|
|
227
227
|
|
|
228
|
-
Verification command a command iterates against (`dev-simplify`, `dev-refactor`). The command
|
|
228
|
+
Verification command a command iterates against (`dev-simplify`, `dev-refactor`, `dev-gitmsg`). The command
|
|
229
229
|
establishes a baseline with it before the first change and re-runs it after each change.
|
|
230
|
+
`dev-gitmsg` uses it as a one-shot opt-in pre-commit gate: run once, non-zero commits nothing, no
|
|
231
|
+
fix loop. A command without `--check` in its contract runs no gate.
|
|
230
232
|
|
|
231
233
|
### `--focus <dims>` — constrain the operation to specific dimensions
|
|
232
234
|
|
|
@@ -462,7 +464,7 @@ Orthogonal to `--focus` (which _narrows_ domains) and to `--mode` on other comma
|
|
|
462
464
|
| Value (refine family) | Bar | `--auto` SKIP behavior |
|
|
463
465
|
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
464
466
|
| `standard` (default when omitted) | L3 structural completeness (not empty/placeholder; check-clean for target sections) | **SKIP** when no L3 findings on target sections |
|
|
465
|
-
| `ready` | **Implement-ready** freeze: another agent can implement without inventing design (frozen names/APIs or explicit "no new API", anti-patterns, file targets, handoffs, out-of-scope) | **Do not SKIP** on L3-clean alone — audit existing claims, run the ready checklist, rewrite sections until the bar is met, then promote `backlog → todo` |
|
|
467
|
+
| `ready` | **Implement-ready** freeze: another agent can implement without inventing design (frozen names/APIs or explicit "no new API", anti-patterns, file targets, handoffs, out-of-scope) | **Do not SKIP** on L3-clean alone — audit existing claims, drop invalid issues with their fixes (cancel when none stays valid), run the ready checklist, rewrite sections until the bar is met, then promote `backlog → todo` |
|
|
466
468
|
|
|
467
469
|
Default for refine stays `standard` so ordinary `refineall --auto` remains cheap. Use `ready` for
|
|
468
470
|
multi-package / multi-agent handoffs, flaky-pipeline features where a wrong implement is costly, and
|