@gobing-ai/spur 0.3.55 → 0.3.58

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 (91) hide show
  1. package/.claude-plugin/marketplace.json +2 -3
  2. package/config/corpus-baseline.json +2748 -68
  3. package/config/rules/strict/runtime-boundaries.yaml +3 -0
  4. package/config/rules/surface/check-cli-surface.yaml +1 -0
  5. package/config/workflow-composition-baseline.json +242 -23
  6. package/config/workflows/wrapup-pipeline.yaml +31 -1
  7. package/package.json +9 -9
  8. package/plugins/README.md +1 -1
  9. package/plugins/sp/README.md +1 -1
  10. package/plugins/sp/agents/expert-spur.md +4 -1
  11. package/plugins/sp/commands/dev-feature-change.md +2 -2
  12. package/plugins/sp/commands/dev-idea.md +7 -19
  13. package/plugins/sp/plugin.json +1 -1
  14. package/plugins/sp/scripts/task-size-precheck.ts +11 -6
  15. package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +4 -4
  16. package/plugins/sp/skills/dogfood-testing/references/report-template.md +4 -2
  17. package/plugins/sp/skills/issue-finding/SKILL.md +23 -11
  18. package/plugins/sp/skills/spur-cli/SKILL.md +23 -15
  19. package/plugins/sp/skills/spur-cli/references/agent.md +5 -0
  20. package/plugins/sp/skills/spur-cli/references/builder.md +49 -0
  21. package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +2 -2
  22. package/plugins/sp/skills/spur-cli/references/features/roadmap-priority.md +1 -1
  23. package/plugins/sp/skills/spur-cli/references/features/verbs.md +1 -1
  24. package/plugins/sp/skills/spur-cli/references/features.md +11 -3
  25. package/plugins/sp/skills/spur-cli/references/message.md +5 -0
  26. package/plugins/sp/skills/spur-cli/references/rules.md +5 -0
  27. package/plugins/sp/skills/spur-cli/references/self.md +101 -0
  28. package/plugins/sp/skills/spur-cli/references/tasks.md +6 -1
  29. package/plugins/sp/skills/spur-cli/references/team.md +5 -0
  30. package/plugins/sp/skills/spur-cli/references/workflows.md +40 -0
  31. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +1 -1
  32. package/plugins/sp/skills/spur-dev/references/dev-operations.md +9 -8
  33. package/plugins/sp/skills/spur-dev/references/execution-batch.md +19 -0
  34. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +1 -1
  35. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +27 -5
  36. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +1 -1
  37. package/spur.js +5060 -553
  38. package/web/_astro/BoardApp.CrusGeQ4.js +1 -0
  39. package/web/_astro/BoardApp.P8SRAD5Q.js +179 -0
  40. package/web/_astro/{TaskDetail.DN_RxS-2.js → TaskDetail.DHjEt5vl.js} +1 -1
  41. package/web/_astro/{arc.CldTHRg-.js → arc.XgRC1Ij_.js} +1 -1
  42. package/web/_astro/{architectureDiagram-3BPJPVTR.DQ4T9oeU.js → architectureDiagram-3BPJPVTR.DOZWrfHc.js} +1 -1
  43. package/web/_astro/{blockDiagram-GPEHLZMM.CGDaXH8J.js → blockDiagram-GPEHLZMM.ClQnCGf_.js} +1 -1
  44. package/web/_astro/{c4Diagram-AAUBKEIU.Cqsc2iub.js → c4Diagram-AAUBKEIU.CKCtUD0Y.js} +1 -1
  45. package/web/_astro/channel.CmK546kO.js +1 -0
  46. package/web/_astro/{chunk-2J33WTMH.CQSKsRmq.js → chunk-2J33WTMH.c7J8OHq5.js} +1 -1
  47. package/web/_astro/{chunk-4BX2VUAB.Pv1HCtp8.js → chunk-4BX2VUAB.C-A1Dv27.js} +1 -1
  48. package/web/_astro/{chunk-55IACEB6.-9MseOIk.js → chunk-55IACEB6.C4kGGALB.js} +1 -1
  49. package/web/_astro/{chunk-727SXJPM.M3OI1DF7.js → chunk-727SXJPM.Bith2NHt.js} +1 -1
  50. package/web/_astro/{chunk-AQP2D5EJ.NfHka5Ca.js → chunk-AQP2D5EJ.qeSXhsVY.js} +1 -1
  51. package/web/_astro/{chunk-FMBD7UC4.B2suYe3s.js → chunk-FMBD7UC4.DdQQnTAy.js} +1 -1
  52. package/web/_astro/{chunk-ND2GUHAM.BfJ7aucP.js → chunk-ND2GUHAM.BZYQVeZd.js} +1 -1
  53. package/web/_astro/{chunk-QZHKN3VN._582hZVc.js → chunk-QZHKN3VN.BiUWwHaV.js} +1 -1
  54. package/web/_astro/{classDiagram-4FO5ZUOK._tttU_jk.js → classDiagram-4FO5ZUOK.OGRhcldh.js} +1 -1
  55. package/web/_astro/{classDiagram-v2-Q7XG4LA2._tttU_jk.js → classDiagram-v2-Q7XG4LA2.OGRhcldh.js} +1 -1
  56. package/web/_astro/{cose-bilkent-S5V4N54A.C4rVATLQ.js → cose-bilkent-S5V4N54A.DxYklM_j.js} +1 -1
  57. package/web/_astro/{dagre-BM42HDAG.8BLRi7f9.js → dagre-BM42HDAG.BSb2dEbo.js} +1 -1
  58. package/web/_astro/{diagram-2AECGRRQ.D6lwUZos.js → diagram-2AECGRRQ.mOrItPK2.js} +1 -1
  59. package/web/_astro/{diagram-5GNKFQAL.Cl_rMiVT.js → diagram-5GNKFQAL.C99r7J3C.js} +1 -1
  60. package/web/_astro/{diagram-KO2AKTUF.DhMExHLp.js → diagram-KO2AKTUF.BKbnisJO.js} +1 -1
  61. package/web/_astro/{diagram-LMA3HP47.3OAxzH_o.js → diagram-LMA3HP47.D8FJGo4V.js} +1 -1
  62. package/web/_astro/{diagram-OG6HWLK6.Uh9RLucG.js → diagram-OG6HWLK6.DVBs7n4Q.js} +1 -1
  63. package/web/_astro/{erDiagram-TEJ5UH35.izzElG0c.js → erDiagram-TEJ5UH35.CddMTl4l.js} +1 -1
  64. package/web/_astro/{flowDiagram-I6XJVG4X.BlGwp5qM.js → flowDiagram-I6XJVG4X.B7WclnjQ.js} +1 -1
  65. package/web/_astro/{ganttDiagram-6RSMTGT7.je7Vf8dN.js → ganttDiagram-6RSMTGT7.CRh7ggvz.js} +1 -1
  66. package/web/_astro/{gitGraphDiagram-PVQCEYII.DNk0Ycop.js → gitGraphDiagram-PVQCEYII.du-L7V8A.js} +1 -1
  67. package/web/_astro/index.B4x8fe52.css +1 -0
  68. package/web/_astro/{infoDiagram-5YYISTIA.K2HhGyWH.js → infoDiagram-5YYISTIA.CClGl9Px.js} +1 -1
  69. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BbbOW4IN.js → ishikawaDiagram-YF4QCWOH.BuTETIPz.js} +1 -1
  70. package/web/_astro/{journeyDiagram-JHISSGLW.B1UaZKqN.js → journeyDiagram-JHISSGLW.Cyg1zCiE.js} +1 -1
  71. package/web/_astro/{kanban-definition-UN3LZRKU.9tsw5QFd.js → kanban-definition-UN3LZRKU.aH8eDXwX.js} +1 -1
  72. package/web/_astro/{linear.I9dvtu-j.js → linear.paE_RY_i.js} +1 -1
  73. package/web/_astro/{mermaid.core.5bKJsMgf.js → mermaid.core.BhdKkI85.js} +4 -4
  74. package/web/_astro/{mindmap-definition-RKZ34NQL.BC5MqSn6.js → mindmap-definition-RKZ34NQL.aZNfv8Nx.js} +1 -1
  75. package/web/_astro/{pieDiagram-4H26LBE5.B8GIMyxD.js → pieDiagram-4H26LBE5.5psni0hC.js} +1 -1
  76. package/web/_astro/{quadrantDiagram-W4KKPZXB.K_aZSM_u.js → quadrantDiagram-W4KKPZXB.DcGPGrFd.js} +1 -1
  77. package/web/_astro/{requirementDiagram-4Y6WPE33.B_V5kzfT.js → requirementDiagram-4Y6WPE33.BwPD2lzi.js} +1 -1
  78. package/web/_astro/{sankeyDiagram-5OEKKPKP.DyV2quLS.js → sankeyDiagram-5OEKKPKP.B3jGVk0l.js} +1 -1
  79. package/web/_astro/{sequenceDiagram-3UESZ5HK.BlKvPnBv.js → sequenceDiagram-3UESZ5HK.BdWsx3LW.js} +1 -1
  80. package/web/_astro/{stateDiagram-AJRCARHV.C1lYUMdS.js → stateDiagram-AJRCARHV.DRpG4ClZ.js} +1 -1
  81. package/web/_astro/{stateDiagram-v2-BHNVJYJU.DJWjr3QV.js → stateDiagram-v2-BHNVJYJU.Su0ML9Wo.js} +1 -1
  82. package/web/_astro/{timeline-definition-PNZ67QCA.CYYiXVlv.js → timeline-definition-PNZ67QCA.Cg_Uv8A5.js} +1 -1
  83. package/web/_astro/{vennDiagram-CIIHVFJN.zYjQKa_S.js → vennDiagram-CIIHVFJN.DVouKT4b.js} +1 -1
  84. package/web/_astro/{wardley-L42UT6IY.BGrWTY3D.js → wardley-L42UT6IY.CexIVQli.js} +1 -1
  85. package/web/_astro/{wardleyDiagram-YWT4CUSO.CkXxtcI1.js → wardleyDiagram-YWT4CUSO.ChSAzcvx.js} +1 -1
  86. package/web/_astro/{xychartDiagram-2RQKCTM6.BhKH3KG3.js → xychartDiagram-2RQKCTM6.CN-Yp50J.js} +1 -1
  87. package/web/index.html +2 -2
  88. package/web/_astro/BoardApp.DCLSB3Zs.js +0 -179
  89. package/web/_astro/BoardApp.Dx5gzAhb.js +0 -1
  90. package/web/_astro/channel.CrBJYpxo.js +0 -1
  91. package/web/_astro/index.V6Q7nhed.css +0 -1
@@ -199,10 +199,45 @@ spur workflow run ./workflows/approval.yaml --steer # interactive
199
199
  - **`--steer`** is synchronous and in-process: it cannot combine with `--json` or `--async` (exit `2`).
200
200
  It accepts steering commands on stdin at declared action boundaries for interactive control.
201
201
 
202
+ ## Composition measures and the advisory (0615)
203
+
204
+ `workflow validate` (valid path only) also reports a **warn-only composition advisory** covering the
205
+ two detectable measures from ADR-069. It answers "does this workflow lean on ad-hoc shell or raw
206
+ agent prompts where a first-class surface would own it better?" — nothing more.
207
+
208
+ **The two triggers:**
209
+
210
+ - **Shell measure** — a `shell` action (state hooks `onEnter`/`onExit`; guards are exempt) flags when
211
+ its `command` has **≥6** non-comment units (split on newline and `;`, blank/`#` units skipped).
212
+ - **agent.run measure** — an `agent.run` action flags when its `input` is a **non-slash** prompt;
213
+ raw prompt length only sets the reported severity (<200 low / ≤1000 medium / >1000 high).
214
+
215
+ **How to run it:** it is not a separate command — `spur workflow validate <file> --json` returns
216
+ `composition: {findings[], suppressed}` on the valid path; human mode prints the advisory to stderr
217
+ with exit 0. Actions with a recorded disposition in
218
+ `config/workflow-composition-baseline.json` (resolved by walking up from the workflow file) are
219
+ counted in `suppressed`, not `findings`.
220
+
221
+ **How to read it, and the fix path per defect class:**
222
+
223
+ - **Shell finding** → pick one of the five recorded owner options from
224
+ `docs/design/workflow-shell-ownership.md`: (a) public `spur` verb (consent-gated),
225
+ (b) application service, (c) least-privilege built-in action kind, (d) workflow-relative external
226
+ extension, (e) deliberately-stays-shell exception (record the reason in the baseline).
227
+ - **agent.run finding** → move the operation behind a centralized agent skill or slash command and
228
+ make the action's `input` reference it (ADR-043 preference).
229
+
230
+ **Advisory-only posture (binding):** findings never justify blocking a run, failing a gate, or
231
+ editing a pipeline that is currently executing. The advisory never changes `validate`'s exit status,
232
+ never blocks `workflow run`, and is not part of `spur-check` / `spur-check-new`. Treat a finding as
233
+ a to-be-enhanced note for the workflow's owner — surface it in your report, apply the fix only when
234
+ the operator accepts it, and never hot-edit a running workflow's shell in place.
235
+
202
236
  ## Command surface
203
237
 
204
238
  ```
205
239
  spur workflow validate <file> [--no-schema] [--json]
240
+ spur workflow show <file>
206
241
  spur workflow run <file> [--run-id <id>] [--vars <json>] [--dry-run] [--async] [--no-plan] [--quiet/--silent/--verbose] [--detail <level>] [--trace-file] [--no-log] [--steer] [--json]
207
242
  spur workflow continue [run-id] [--yes] [--answer <yes|no|cancel>] [--json]
208
243
  spur workflow cancel <run-id> [--json]
@@ -359,3 +394,8 @@ directly on the command line.
359
394
 
360
395
  **Template type**: technique
361
396
  **Purpose**: Operate `spur workflow` across its full lifecycle — choose the execution mode, author, validate, run, and refine dual-mode workflows
397
+
398
+ > **Shared option declarations (0618):** options shared across command modules resolve from
399
+ > `apps/cli/src/commands/shared-options.ts` (`SHARED_OPTIONS`). Never re-declare a shared flag
400
+ > inline in a command module — see SKILL.md "Shared option registry" and
401
+ > `docs/04_DESIGN.md` §1.0.1.
@@ -193,7 +193,7 @@ During decomposition, each core scenario maps to ≥1 task:
193
193
  | R3 — Login with email and password | 0043, 0044 | Auth service + UI |
194
194
 
195
195
  The mapping is recorded in the task's `## Background` or in the feature's `## Notes`.
196
- `spur feature check` warns on unmapped core scenarios after `spur feature refresh`
196
+ `spur feature check` warns on unmapped core scenarios after `spur feature refresh --feature <id>`
197
197
  regenerates the `## Tasks` block.
198
198
 
199
199
  ## Decision-trace → AC-scenario mapping
@@ -412,14 +412,15 @@ is the procedure. The backing is a combination of git CLI, `spur` CLI, and agent
412
412
  - **Behavior:** 0. **Start at the anchors, never at a discovery run.** If `--findings <anchors>` is given, that space-separated `file:line` list IS the failing set — open those locations first, in order, and fix them; do not run the gate to find out what broke. If only `--gate-log <path>` is given, read that log first and identify the failing findings (lint/test errors with their `file:line` anchors) before running the loop — the captured log is the authoritative source. Either way the first action of this hop is a read, not a gate run (R3, task 0482).
413
413
  1. Run `bun run format` (add `-- <path>` if `--scope` is given) to settle formatter-only diffs first — `bun run lint` asserts `--error-on-warnings` + typecheck but does **not** rewrite formatting, so a formatter-only change (e.g. a multi-line import reflow) can pass `lint` locally yet still be unformatted. Formatting before linting removes that class of false-green.
414
414
  2. Run `bun run lint` (add `-- <path>` if `--scope` is given). Collect all errors.
415
- 3. If lint is clean, skip to step 5.
416
- 4. **Lint fix loop:** for each error, diagnose the root cause and apply the smallest fix. **Use targeted probes to verify each fix** (`bunx tsc --noEmit` on the affected package, `bun run lint -- <file>`) — do NOT re-run the full gate after every batch. Loop until lint is green.
417
- 5. Run `bun run test`. Collect all failures.
418
- 6. If tests are green, done.
419
- 7. **Test fix loop:** for each failure, diagnose (test bug vs implementation bug), apply the fix, re-run the **failing test only** (`bun test <file> --test-name-pattern "<test>"`). Do NOT re-run the full suite per fix — it is the dominant loop cost (task 0436 R2).
420
- 8. **Confirming run (at most once).** After all fixes, run `bun run format && bun run lint && bun run test` **at most once** to confirm. If it passes, the hop is done.
421
- 9. **Pipeline-awareness (R4, task 0483).** When `/sp:dev-fixall` is invoked from the pipeline's `test-fix` hop, `test-recheck` runs the full `${vars.qualityGateCmd}` gate immediately after this hop returns — that is the **deciding** run that writes PASS to `.spur/run/<wbs>-test-gate.status`. Do NOT re-run the full gate beyond the single confirming run in step 8; the deciding run belongs to `test-recheck`. If your confirming run already passed, return immediately — a second or third gate run inside this hop is pure redundancy (0482 ran the gate 3× plus a standalone `bun run test`; all four were followed by `test-recheck` running it a 5th time). If your confirming run failed and you fixed more, re-run the full gate once more within `--max-retry` budget, then return — let `test-recheck` judge.
422
- 10. Report: list what was fixed (file + one-line summary per fix). If any error could not be resolved, report it explicitlydo not suppress.
415
+ 3. **Surface-change sweep (before any fix).** If the failing set is a **surface/parity** change — CLI noun/verb/flag surface, reference-file structure, or a renamed/moved symbol — do one upfront `rg` sweep across ALL test dirs + docs for stale references to the changed symbols (e.g. `rg -l "<old-noun>|<old-file>.md|Tier C" apps/*/tests plugins/sp/tests plugins/sp/skills docs`), and fix every pinned test/docs file in that sweep. A surface change is pinned in **multiple independent test files** (each with its own hardcoded noun→reference map); discovering them one-by-one via full-suite probes is the dominant waste — each wave costs a suite run and a fresh edit loop (task 0436 R2 lesson). One sweep produces the complete edit set upfront.
416
+ 4. If lint is clean, skip to step 6.
417
+ 5. **Lint fix loop:** for each error, diagnose the root cause and apply the smallest fix. **Use targeted probes to verify each fix** (`bunx tsc --noEmit` on the affected package, `bun run lint -- <file>`) — do NOT re-run the full gate after every batch. Loop until lint is green.
418
+ 6. Run `bun run test`. Collect all failures.
419
+ 7. If tests are green, done.
420
+ 8. **Test fix loop:** for each failure, diagnose (test bug vs implementation bug), apply the fix, re-run the **failing test only** (`bun test <file> --test-name-pattern "<test>"`). Do NOT re-run the full suite per fix it is the dominant loop cost (task 0436 R2).
421
+ 9. **Confirming run (at most once).** After all fixes, run `bun run format && bun run lint && bun run test` **at most once** to confirm. If it passes, the hop is done.
422
+ 10. **Pipeline-awareness (R4, task 0483).** When `/sp:dev-fixall` is invoked from the pipeline's `test-fix` hop, `test-recheck` runs the full `${vars.qualityGateCmd}` gate immediately after this hop returns — that is the **deciding** run that writes PASS to `.spur/run/<wbs>-test-gate.status`. Do NOT re-run the full gate beyond the single confirming run in step 9; the deciding run belongs to `test-recheck`. If your confirming run already passed, return immediately — a second or third gate run inside this hop is pure redundancy (0482 ran the gate 3× plus a standalone `bun run test`; all four were followed by `test-recheck` running it a 5th time). If your confirming run failed and you fixed more, re-run the full gate once more within `--max-retry` budget, then return let `test-recheck` judge.
423
+ 11. Report: list what was fixed (file + one-line summary per fix). If any error could not be resolved, report it explicitly — do not suppress.
423
424
  - **Invariants:** Never bypass with `--no-verify`, `--force`, or new `biome-ignore`/`eslint-disable` suppressions. Never skip or `.skip` a test to make the suite green. Fix the root cause, not the symptom. Never claim green on `bun run lint` alone — a formatter-only diff passes `lint` but fails the formatter; run `bun run format` (or assert it produces no diff) before declaring the gate clean. **Never re-run the full gate more than once per confirming pass** (R4) — use targeted probes during the fix loops and let the pipeline's `test-recheck` state be the deciding run.
424
425
  - **MANDATORY Exit Condition.** The ONLY way to complete successfully:
425
426
  1. Run validation command: `eval "$VALIDATION_CMD"`
@@ -734,6 +734,25 @@ command doc so it does not read as a bug.
734
734
  `sp:super-planner` surfaces blockers/HITL only at the **batch boundary** (between task runs), not
735
735
  from inside a pipeline step.
736
736
 
737
+ ## Gate preflight (dogfood 2026-08-21, feature A3)
738
+
739
+ The A3 batch burned multiple full `spur-check-new` runs (~2 min each) that failed only at the tail
740
+ gates. The cheap rule gates fail fast when run first — the full-gate run is dominated by the ~65 s
741
+ test suite, so a gate run that dies at `test-post-check` or `corpus-check` wasted most of its wall
742
+ time. Before launching a full `spur-check-new`:
743
+
744
+ 1. **Run the two rule gates first** — `bun run test-pre-check` (43 rules: `no-console-output`,
745
+ `no-direct-process-spawn`, `cli-*`, `require-corresponding-test`) and `bun run test-post-check`
746
+ (`every-export-has-tsdoc`, `coverage-gate`). They catch boundary/TSDoc violations in seconds.
747
+ 2. **Promoted code must satisfy the boundary rules `scripts/` never enforced.** A command module
748
+ moving from `scripts/` into `apps/cli/src` must route output through the `CommandOutput` seam (no
749
+ `console.*`), spawn processes via `NodeProcessExecutor` (no `Bun.spawnSync`), get a
750
+ `runtime-boundaries` fs-io exemption for sync reads (mirrors `task.ts`), and a non-command helper
751
+ must not live in `apps/cli/src/commands/` (the noun scan treats every file there as a noun).
752
+ 3. **Doc/TSDoc edits shift `file:line` anchors** cited by other tasks — `corpus-check` surfaces them
753
+ as `L4.anchor-subject-mismatch`. Repoint the shifted citations (via `spur task update --section`)
754
+ in the same commit, and reconcile new/stale baseline entries before the gate run.
755
+
737
756
  ## AC traceability
738
757
 
739
758
  | AC | Where satisfied |
@@ -351,7 +351,7 @@ After a completed task, decide next action:
351
351
  - **More tasks in the feature?** Pick the next one, run again.
352
352
  - **Feature complete?** Run `spur feature update <id> verifying` to mark it for
353
353
  acceptance verification.
354
- - **All done?** Run `spur task refresh` + `spur feature refresh` to regenerate the kanban
354
+ - **All done?** Run `spur task refresh` + `spur feature refresh --all` to regenerate the kanban
355
355
  and index.
356
356
 
357
357
  ## Skipping HITL
@@ -124,12 +124,34 @@ Transition guards are not advisory. Execute the declared guard exactly, in order
124
124
  resolved variables and artifacts. `--no-lifecycle` remains bookkeeping only; the YAML's task checks,
125
125
  verdict gate, record step, and done guard all remain authoritative.
126
126
 
127
- ## Batch use
127
+ ## Record & done sequencing (dogfood 2026-08-21, feature A3)
128
128
 
129
- Sequential `/sp:dev-runall` with omit/`inline` runs this driver once per ready WBS, with a fresh run
130
- id and the same frozen/topologically ordered batch plan. Batch inspection, halt/keep-going policy,
131
- and reporting remain in `execution-batch.md`. Parallel mode cannot share one host session safely and
132
- therefore keeps the existing isolated subprocess/worktree path (trigger 4).
129
+ Order matters for the `testing done` hop. The A3 batch hit the same clobbering spiral on two
130
+ tasks (0617, 0619) because the sections were hand-written **before** the verdict artifact existed:
131
+
132
+ 1. **Write the verdict artifact first.** `spur task record --solution-from-diff --transition testing`
133
+ reads `.spur/run/<wbs>-verdict.json` (default). With no artifact it emits a **UNKNOWN** verdict and
134
+ **overwrites** a hand-authored `## Testing` with an auto-generated "No requirements recorded" table,
135
+ plus replaces `## Solution` with a bare auto change-map. Creating the artifact first (PASS, with
136
+ requirement rows keyed by scenario title) makes `task record` the compliant path.
137
+ ```bash
138
+ # verdict artifact first (shape: {wbs, verdict, requirements:[{id,status,evidence}], checks:[], source})
139
+ # then the record hop; then re-write Testing/Solution if record's backfill is thinner than intended.
140
+ spur task update <wbs> wip --no-lifecycle
141
+ spur task record <wbs> --solution-from-diff --transition testing
142
+ ```
143
+ The engine now preserves an already-authored Testing when the verdict is UNKNOWN (task-service
144
+ `record` fallback-only, mirroring the Review 0593 precedent) — but the order above is still the
145
+ contract for the standard pipeline.
146
+ 2. **Done-probe before done.** Run the check projected to `done` (`spur task check <wbs> --as done`
147
+ via the `TaskCheckService` probe pattern) — it surfaces `L3.unchecked-checklist` (flip `- [ ]` → `- [x]`)
148
+ and `L3.required-section-placeholder` before the transition, not after.
149
+ 3. **Solution change-map anchor rule (L4.anchor-subject-mismatch).** A Solution change-map table must
150
+ list **one `file:line` per row**. A ·-joined paragraph makes every anchor's "subject" the other
151
+ anchors and trips the L4 subject check. Paths containing `_` (e.g. `docs/help/cmd_*.md`,
152
+ `spur-cli-matrix.md`) can **never** match their cited line — the snake_case filename token is
153
+ extracted as the subject and cannot appear in the line content — so drop those rows from the table
154
+ (prose still covers them).
133
155
 
134
156
  ## Failure contract
135
157
 
@@ -146,7 +146,7 @@ that is the pre-check's job above). Common shape failures:
146
146
  - WBS collisions (already-allocated range).
147
147
 
148
148
  Loop until the command exits 0 — then the batch is created and each task appears in the
149
- feature's `## Tasks` block on next `spur feature refresh`.
149
+ feature's `## Tasks` block on next `spur feature refresh --feature <id>`.
150
150
 
151
151
  **If you decomposed a parent task into sub-task files** (the children carry `parent_wbs`), the
152
152
  sub-task roster is **auto-generated** — `spur task batch-create` invokes `spur task refresh-roster`