@gobing-ai/spur 0.3.94 → 0.3.96

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 (198) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +42 -0
  3. package/board/index.d.ts +38 -0
  4. package/config/plugin-scripts.json +3 -52
  5. package/config/rules/boundary/sp-script-placement.yaml +19 -0
  6. package/config/rules/strict/runtime-boundaries.yaml +5 -0
  7. package/config/rules/structure/test-location.yaml +2 -0
  8. package/config/rules/typescript/no-syscall-emulation-in-boundary-mock.yaml +1 -1
  9. package/config/rules/typescript/output-boundaries.yaml +15 -2
  10. package/config/script-placement-baseline.json +51 -0
  11. package/config/workflows/feature-verification.yaml +7 -4
  12. package/config/workflows/history-anatomy.yaml +23 -11
  13. package/config/workflows/idea-pipeline.yaml +87 -86
  14. package/config/workflows/pr-review.yaml +18 -9
  15. package/config/workflows/task-pipeline.yaml +84 -109
  16. package/config/workflows/wrapup-pipeline.yaml +173 -46
  17. package/package.json +15 -11
  18. package/plugins/sp/README.md +8 -10
  19. package/plugins/sp/agents/super-reviewer.md +43 -18
  20. package/plugins/sp/commands/dev-fixgha.md +83 -0
  21. package/plugins/sp/commands/dev-gitmsg.md +8 -6
  22. package/plugins/sp/commands/dev-gtd.md +2 -2
  23. package/plugins/sp/commands/dev-idea.md +22 -12
  24. package/plugins/sp/commands/dev-plan.md +8 -9
  25. package/plugins/sp/commands/dev-review.md +22 -13
  26. package/plugins/sp/commands/dev-verify.md +7 -4
  27. package/plugins/sp/commands/dev-verifyall.md +5 -4
  28. package/plugins/sp/commands/dev-wrap.md +1 -1
  29. package/plugins/sp/commands/spur-init.md +2 -2
  30. package/plugins/sp/hooks/context-post-tool.ts +2 -2
  31. package/plugins/sp/hooks/context-session-start.ts +2 -1
  32. package/plugins/sp/hooks/context-session-stop.ts +22 -14
  33. package/plugins/sp/hooks/pi/guard-extension.ts +109 -150
  34. package/plugins/sp/lib/history-anatomy.generated.d.mts +112 -0
  35. package/plugins/sp/lib/history-anatomy.generated.mjs +686 -0
  36. package/plugins/sp/lib/idea-handoff.generated.mjs +6 -5
  37. package/plugins/sp/lib/inline-run.generated.d.mts +13 -2
  38. package/plugins/sp/lib/inline-run.generated.mjs +33 -16
  39. package/plugins/sp/lib/quality-gate.generated.d.mts +104 -0
  40. package/plugins/sp/lib/quality-gate.generated.mjs +438 -0
  41. package/plugins/sp/lib/residual-scan.generated.d.mts +62 -0
  42. package/plugins/sp/lib/residual-scan.generated.mjs +210 -0
  43. package/plugins/sp/lib/spur-bin.ts +36 -0
  44. package/plugins/sp/lib/step-profile.generated.d.mts +71 -0
  45. package/plugins/sp/lib/step-profile.generated.mjs +174 -0
  46. package/plugins/sp/plugin.json +1 -1
  47. package/plugins/sp/references/roles.md +1 -1
  48. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +3 -3
  49. package/plugins/sp/scripts/daily-summary/daily-summary.ts +3 -3
  50. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +2 -0
  51. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +1 -0
  52. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +9 -7
  53. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +8 -7
  54. package/plugins/sp/scripts/feature-verification-steps.ts +6 -6
  55. package/plugins/sp/scripts/history-anatomy-cache.mjs +23 -22
  56. package/plugins/sp/scripts/history-anatomy-cache.ts +23 -928
  57. package/plugins/sp/scripts/inline-run-setup.mjs +90 -315
  58. package/plugins/sp/scripts/inline-run-setup.ts +109 -639
  59. package/plugins/sp/scripts/pr-reviewing.mjs +2 -0
  60. package/plugins/sp/scripts/pr-reviewing.ts +1 -0
  61. package/plugins/sp/scripts/quality-gate.mjs +38 -21
  62. package/plugins/sp/scripts/quality-gate.ts +20 -660
  63. package/plugins/sp/scripts/residual-scan.mjs +138 -159
  64. package/plugins/sp/scripts/residual-scan.ts +102 -499
  65. package/plugins/sp/scripts/script-root.mjs +129 -0
  66. package/plugins/sp/scripts/script-root.ts +199 -0
  67. package/plugins/sp/scripts/workflow-step-profile.mjs +27 -16
  68. package/plugins/sp/scripts/workflow-step-profile.ts +22 -314
  69. package/plugins/sp/scripts/wrapup-drift-probe.mjs +12 -3
  70. package/plugins/sp/scripts/wrapup-drift-probe.ts +6 -3
  71. package/plugins/sp/scripts/wrapup-steps.mjs +42 -40
  72. package/plugins/sp/scripts/wrapup-steps.ts +64 -46
  73. package/plugins/sp/skills/code-improvement/SKILL.md +5 -4
  74. package/plugins/sp/skills/code-verification/SKILL.md +46 -16
  75. package/plugins/sp/skills/code-verification/references/verdict-schema.md +13 -2
  76. package/plugins/sp/skills/functional-review/SKILL.md +8 -5
  77. package/plugins/sp/skills/functional-review/references/verdict-schema.md +1 -1
  78. package/plugins/sp/skills/history-anatomy/references/modes.md +2 -1
  79. package/plugins/sp/skills/next-feature/references/handoff-routing.md +1 -1
  80. package/plugins/sp/skills/next-router/references/routing-table.md +2 -2
  81. package/plugins/sp/skills/spur-cli/SKILL.md +3 -3
  82. package/plugins/sp/skills/spur-cli/references/agent.md +10 -10
  83. package/plugins/sp/skills/spur-cli/references/features.md +17 -6
  84. package/plugins/sp/skills/spur-cli/references/init.md +17 -16
  85. package/plugins/sp/skills/spur-cli/references/self.md +3 -2
  86. package/plugins/sp/skills/spur-cli/references/serve.md +10 -10
  87. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +28 -5
  88. package/plugins/sp/skills/spur-cli/references/tasks.md +14 -8
  89. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +4 -3
  90. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +11 -9
  91. package/plugins/sp/skills/spur-dev/references/decision-brief.md +1 -1
  92. package/plugins/sp/skills/spur-dev/references/dev-operations.md +86 -70
  93. package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +3 -3
  94. package/plugins/sp/skills/spur-dev/references/execution-batch.md +107 -44
  95. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +5 -9
  96. package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +3 -3
  97. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +31 -21
  98. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +19 -19
  99. package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +4 -3
  100. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +35 -6
  101. package/plugins/sp/skills/spur-doctor/SKILL.md +1 -1
  102. package/plugins/sp/skills/sys-architecture/SKILL.md +3 -2
  103. package/plugins/sp/tsconfig.json +8 -0
  104. package/spur.js +6638 -4775
  105. package/web/_astro/BoardApp.BIjMatT1.js +1 -0
  106. package/web/_astro/{BoardApp.FTEs3-N8.js → BoardApp.GvjIe9Z6.js} +150 -153
  107. package/web/_astro/TaskDetail.BZM3EAFx.js +1 -0
  108. package/web/_astro/_commonjsHelpers.CqkleIqs.js +1 -0
  109. package/web/_astro/{arc.uuAf51IT.js → arc.HkRiZnoI.js} +1 -1
  110. package/web/_astro/architectureDiagram-3BPJPVTR.BDdK-tgZ.js +36 -0
  111. package/web/_astro/{blockDiagram-GPEHLZMM.D1mGCq3p.js → blockDiagram-GPEHLZMM.CZ9kOBxx.js} +1 -1
  112. package/web/_astro/board-facade-react-dom-client.B2U5wMvk.js +1 -0
  113. package/web/_astro/board-facade-react-dom.Cd2MuMhF.js +1 -0
  114. package/web/_astro/board-facade-react-jsx-dev-runtime.B_L3JzfC.js +1 -0
  115. package/web/_astro/board-facade-react-jsx-runtime.BY2yfHRi.js +1 -0
  116. package/web/_astro/board-facade-react-router-dom.Dy5pjzOw.js +1 -0
  117. package/web/_astro/board-facade-react-router.DjjqU27_.js +1 -0
  118. package/web/_astro/board-facade-react.Dgf4GRyj.js +1 -0
  119. package/web/_astro/{c4Diagram-AAUBKEIU.CMsolcde.js → c4Diagram-AAUBKEIU.DXK9qeRD.js} +1 -1
  120. package/web/_astro/channel.DlhX2MEt.js +1 -0
  121. package/web/_astro/{chunk-2J33WTMH.CrGA3fik.js → chunk-2J33WTMH.BTD2WeX5.js} +1 -1
  122. package/web/_astro/{chunk-4BX2VUAB.DsLVVla0.js → chunk-4BX2VUAB.Ci6Qbcvk.js} +1 -1
  123. package/web/_astro/{chunk-55IACEB6.Dxc59Tfi.js → chunk-55IACEB6.yl3zsj7p.js} +1 -1
  124. package/web/_astro/{chunk-727SXJPM.CaEVE2Wy.js → chunk-727SXJPM.ClXZsfyR.js} +1 -1
  125. package/web/_astro/{chunk-AQP2D5EJ.BiJ4HXeI.js → chunk-AQP2D5EJ.BmKWZBcP.js} +1 -1
  126. package/web/_astro/{chunk-FMBD7UC4.Mxf1fru5.js → chunk-FMBD7UC4.By30fcb7.js} +1 -1
  127. package/web/_astro/chunk-JMJ3UQ3L.BQJEJHu4.js +34 -0
  128. package/web/_astro/{chunk-ND2GUHAM.pyOWQixH.js → chunk-ND2GUHAM.24NmrD-k.js} +1 -1
  129. package/web/_astro/{chunk-QZHKN3VN.BmEsg4vr.js → chunk-QZHKN3VN.BN4sKdcS.js} +1 -1
  130. package/web/_astro/chunk-YNUBSHFH.CxeAygfi.js +7 -0
  131. package/web/_astro/{classDiagram-4FO5ZUOK.BHhhMFTO.js → classDiagram-4FO5ZUOK.CJpoMPb5.js} +1 -1
  132. package/web/_astro/{classDiagram-v2-Q7XG4LA2.BHhhMFTO.js → classDiagram-v2-Q7XG4LA2.CJpoMPb5.js} +1 -1
  133. package/web/_astro/client.BhluLQqe.js +1 -0
  134. package/web/_astro/client.DBpSRLnx.js +9 -0
  135. package/web/_astro/cose-bilkent-S5V4N54A.BraxQ2Nt.js +1 -0
  136. package/web/_astro/{cynefin-OW5HDTMX.C2j1_lKL.js → cynefin-OW5HDTMX.gzoU73oL.js} +1 -1
  137. package/web/_astro/{dagre-BM42HDAG.hZ2NCTdT.js → dagre-BM42HDAG.wyDfWySU.js} +1 -1
  138. package/web/_astro/{diagram-2AECGRRQ.Bfw5_EzK.js → diagram-2AECGRRQ.h2_EbMxV.js} +1 -1
  139. package/web/_astro/{diagram-5GNKFQAL.Bt1V_Tmk.js → diagram-5GNKFQAL.Db6dcs89.js} +1 -1
  140. package/web/_astro/{diagram-KO2AKTUF.DEk-YFwp.js → diagram-KO2AKTUF.NVwzxu_U.js} +1 -1
  141. package/web/_astro/{diagram-LMA3HP47.CDjndtQm.js → diagram-LMA3HP47.B-eNgDQk.js} +1 -1
  142. package/web/_astro/{diagram-OG6HWLK6.cFnUHScG.js → diagram-OG6HWLK6.Bsa8ZRbJ.js} +1 -1
  143. package/web/_astro/{erDiagram-TEJ5UH35.DlhYp7NV.js → erDiagram-TEJ5UH35.BospRE5Q.js} +1 -1
  144. package/web/_astro/{flowDiagram-I6XJVG4X.DNTpsxfx.js → flowDiagram-I6XJVG4X.DMzvHwAA.js} +1 -1
  145. package/web/_astro/ganttDiagram-6RSMTGT7.Dmdxgd-M.js +292 -0
  146. package/web/_astro/{gitGraphDiagram-PVQCEYII.DkEqNI0P.js → gitGraphDiagram-PVQCEYII.CaqdO0rL.js} +1 -1
  147. package/web/_astro/index.5dn-Zm-2.js +1 -0
  148. package/web/_astro/index.C-IqPpW2.js +1 -0
  149. package/web/_astro/index.Cyc_GA4f.js +1 -0
  150. package/web/_astro/index.EoZlzLK-.css +1 -0
  151. package/web/_astro/index.tZfqwSut.js +1 -0
  152. package/web/_astro/{infoDiagram-5YYISTIA.CrjioCTG.js → infoDiagram-5YYISTIA.DDVD9Wn7.js} +1 -1
  153. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BcK0CN8n.js → ishikawaDiagram-YF4QCWOH.EKyCUFsL.js} +1 -1
  154. package/web/_astro/{journeyDiagram-JHISSGLW.p0CbBDX1.js → journeyDiagram-JHISSGLW.By2-RkYB.js} +1 -1
  155. package/web/_astro/jsx-runtime.DWOiEOII.js +1 -0
  156. package/web/_astro/{kanban-definition-UN3LZRKU.puHIFt6J.js → kanban-definition-UN3LZRKU.ar-WmlyR.js} +1 -1
  157. package/web/_astro/{linear.Bb-3a1d7.js → linear.BnzMBgo_.js} +1 -1
  158. package/web/_astro/{mermaid.core.CJDgXOJs.js → mermaid.core.DSqeFu2Y.js} +4 -4
  159. package/web/_astro/{mindmap-definition-RKZ34NQL.BoAZEI9t.js → mindmap-definition-RKZ34NQL.1XcF8Wh2.js} +1 -1
  160. package/web/_astro/{pieDiagram-4H26LBE5.CJNSdqY7.js → pieDiagram-4H26LBE5.DnItHOdK.js} +1 -1
  161. package/web/_astro/{quadrantDiagram-W4KKPZXB.DtTy7_0Z.js → quadrantDiagram-W4KKPZXB.BQQyrnBt.js} +1 -1
  162. package/web/_astro/{requirementDiagram-4Y6WPE33.BNYV98Xg.js → requirementDiagram-4Y6WPE33.Dmzxun82.js} +1 -1
  163. package/web/_astro/{sankeyDiagram-5OEKKPKP.DRq9DGHp.js → sankeyDiagram-5OEKKPKP.BBIeRKYB.js} +1 -1
  164. package/web/_astro/{sequenceDiagram-3UESZ5HK.B7KdBFCm.js → sequenceDiagram-3UESZ5HK.CUNVdBBf.js} +1 -1
  165. package/web/_astro/{stateDiagram-AJRCARHV.CD62ZJ2H.js → stateDiagram-AJRCARHV.DlFf2sJm.js} +1 -1
  166. package/web/_astro/{stateDiagram-v2-BHNVJYJU.CeVk1TAj.js → stateDiagram-v2-BHNVJYJU.DXR7I1H5.js} +1 -1
  167. package/web/_astro/{timeline-definition-PNZ67QCA.C_ZPA5tT.js → timeline-definition-PNZ67QCA.BcO-GyX2.js} +1 -1
  168. package/web/_astro/{vennDiagram-CIIHVFJN.CrThO_FQ.js → vennDiagram-CIIHVFJN.ChCECmmW.js} +1 -1
  169. package/web/_astro/{wardleyDiagram-YWT4CUSO.DSZCA5nl.js → wardleyDiagram-YWT4CUSO.CRaT12mD.js} +1 -1
  170. package/web/_astro/{xychartDiagram-2RQKCTM6.KI7baTuk.js → xychartDiagram-2RQKCTM6.B3lsHVpj.js} +1 -1
  171. package/web/board-runtime.json +69 -0
  172. package/web/index.html +2 -2
  173. package/plugins/sp/lib/artifact-digest.generated.d.mts +0 -7
  174. package/plugins/sp/lib/artifact-digest.generated.mjs +0 -48
  175. package/plugins/sp/scripts/feature-sync-bounded.mjs +0 -298
  176. package/plugins/sp/scripts/feature-sync-bounded.ts +0 -479
  177. package/plugins/sp/scripts/idea-coverage-check.ts +0 -168
  178. package/plugins/sp/scripts/inline-pipeline-parity-check.ts +0 -298
  179. package/plugins/sp/scripts/record-feature-sync.mjs +0 -63
  180. package/plugins/sp/scripts/record-feature-sync.ts +0 -84
  181. package/plugins/sp/scripts/script-contract-check.ts +0 -377
  182. package/plugins/sp/scripts/stage-registry-adapter.ts +0 -1533
  183. package/plugins/sp/scripts/surface-drift-inventory.ts +0 -989
  184. package/plugins/sp/scripts/task-evidence-precheck.ts +0 -187
  185. package/plugins/sp/scripts/task-size-precheck.ts +0 -210
  186. package/plugins/sp/scripts/transition-shim-check.ts +0 -238
  187. package/plugins/sp/scripts/validate-commands.ts +0 -689
  188. package/plugins/sp/scripts/validate-flag-contracts.ts +0 -878
  189. package/plugins/sp/scripts/verify-answer-lint.ts +0 -547
  190. package/web/_astro/BoardApp.C02hAHPO.js +0 -1
  191. package/web/_astro/TaskDetail.C-GdsS-t.js +0 -1
  192. package/web/_astro/architectureDiagram-3BPJPVTR.CGe629A1.js +0 -36
  193. package/web/_astro/channel.fsgl7o5j.js +0 -1
  194. package/web/_astro/client.yhYJvxCU.js +0 -9
  195. package/web/_astro/cose-bilkent-S5V4N54A.2fH4YOlp.js +0 -1
  196. package/web/_astro/ganttDiagram-6RSMTGT7.DC_p36PI.js +0 -292
  197. package/web/_astro/index.De90oHcH.js +0 -1
  198. package/web/_astro/index.Hjbr15fG.css +0 -1
@@ -13,17 +13,28 @@
13
13
  # pauses,
14
14
  # even under --auto (Iron Law #6: irreversible action -> surface to human).
15
15
  #
16
- # Shape: start -> task-resolve -> doc-sync -> learnings-append -> metrics-record
16
+ # Shape: start -> task-resolve -> doc-sync -> learnings-validate -> learnings-append
17
+ # -> doc-tripwire (1037: repo-wide tripwire over the still-uncommitted wrap
18
+ # diff; repair also enters it; the task-resolve fast path does not)
19
+ # -> metrics-record
17
20
  # -> feature-transition (conditional: if vars.feature set)
18
21
  # -> feature-verify (post-transition feature check gate, 0915 F1)
19
22
  # -> branch-cleanup (conditional: if vars.merge=true)
20
23
  # -> done
21
24
  # doc-sync routes a contract violation to `repair` (cheap, no
22
25
  # re-dispatch — ADR-118 pilot) and an executor failure to `failed`;
26
+ # learnings-validate (0986) rejects a nonempty narration-only capture to
27
+ # the same `repair` edge with a distinct invalid-learnings-shape status —
28
+ # expectFile proves existence, never shape — while empty/missing captures
29
+ # keep the soft skip by passing through to learnings-append;
30
+ # learnings-append and repair converge on doc-tripwire (1037), which runs
31
+ # docTripwireCmd — the repo-wide tripwires over the still-uncommitted wrap
32
+ # diff — before metrics-record; the task-resolve fast path never enters it;
23
33
  # task-resolve with a VALIDATED empty list short-circuits to `skipped`;
24
34
  # invalid wrap input, an unresolved/non-completed task, a failed metrics
25
- # capture, a failed required sync, or a failed feature gate routes to
26
- # `failed` (0770) instead of being absorbed by an always-defensive skip.
35
+ # capture, a failed required sync, a failed repo-wide tripwire (1037), or
36
+ # a failed feature gate routes to `failed` (0770) instead of being
37
+ # absorbed by an always-defensive skip.
27
38
  #
28
39
  # Vars (passed as a JSON object via `--vars`):
29
40
  # tasks — JSON array of WBS strings, passed as a JSON-encoded STRING value
@@ -75,7 +86,7 @@
75
86
  "$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
76
87
  kind: state-machine
77
88
  name: wrapup-pipeline
78
- version: "5"
89
+ version: "7"
79
90
  description: "Post-execution wrap-up: doc-sync (doc drift + learning capture), metrics, feature-transition, branch-cleanup"
80
91
  iterationBound: 10
81
92
  initialState: start
@@ -100,6 +111,13 @@ vars:
100
111
  # TRUSTED CONFIG ONLY — this string is executed via `sh -c` (same surface as
101
112
  # task-pipeline's qualityGateCmd). Never interpolate untrusted input into it.
102
113
  featureGateCmd: '$spurBin feature check "$feature"'
114
+ # Repo-wide tripwire over the wrap diff (1037): runs `bun run test-repo-wide`
115
+ # only when package.json declares the script, so other projects no-op. Callers
116
+ # can override it with --vars; an empty string disables the check (the hop
117
+ # still writes PASS).
118
+ # TRUSTED CONFIG ONLY — this string is executed via `sh -c` (same surface as
119
+ # featureGateCmd). Never interpolate untrusted input into it.
120
+ docTripwireCmd: 'if jq -e ''.scripts["test-repo-wide"]'' package.json >/dev/null 2>&1; then bun run test-repo-wide; fi'
103
121
  __hitlAnswer: ""
104
122
 
105
123
  states:
@@ -108,6 +126,12 @@ states:
108
126
  Pipeline start. Task statuses are NOT mutated by wrap-up — wrap-up consumes
109
127
  completed tasks and produces learning/metrics/doc artifacts only.
110
128
  onEnter:
129
+ # 0960 R2: run-start script-resolution identity — record which tree this run
130
+ # resolved (source-repo vs installed) before any step executes. Never aborts.
131
+ - kind: shell
132
+ options:
133
+ command: >-
134
+ S=plugins/sp/scripts/script-root.ts; [ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp script-root.mjs 2>/dev/null)"; RUNNER=bun; case "$S" in *.mjs) RUNNER=node ;; esac; [ -f "$S" ] && "$RUNNER" "$S" --run-id "$__runId" --spur-bin "$spurBin" || echo "script-root failed closed — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; exit 0
111
135
  - kind: note
112
136
  options:
113
137
  message: "Wrap-up pipeline start for tasks: ${vars.tasks}. Task statuses are NOT mutated."
@@ -143,12 +167,10 @@ states:
143
167
  options:
144
168
  command: >-
145
169
  mkdir -p .spur/run &&
146
- if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
147
- bun plugins/sp/scripts/wrapup-steps.ts resolve;
148
- elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
149
- node "$W" resolve;
170
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/wrapup-steps.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/wrapup-steps.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then
171
+ "$RUNNER" "$S" resolve;
150
172
  else
151
- echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
173
+ echo "wrapup-steps failed closed — script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
152
174
  printf 'FAIL\n' > ".spur/run/$__runId-wrapup-resolve.status";
153
175
  fi
154
176
  # (0944 R1-R3) deterministic drift probe — runs ONLY when the caller left mode
@@ -163,13 +185,14 @@ states:
163
185
  command: >-
164
186
  if [ -n "$mode" ]; then
165
187
  printf '%s\n' "$mode" > ".spur/run/$__runId-mode.txt";
166
- elif [ -f plugins/sp/scripts/wrapup-drift-probe.ts ]; then
167
- bun plugins/sp/scripts/wrapup-drift-probe.ts;
168
- elif W="$(superskill script path sp wrapup-drift-probe.mjs 2>/dev/null)" && [ -f "$W" ]; then
169
- node "$W";
170
188
  else
171
- printf '{"clean":false,"reasons":["probe script not found"],"paths":[]}' > ".spur/run/$__runId-drift-probe.json";
172
- printf '\n' > ".spur/run/$__runId-mode.txt";
189
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/wrapup-drift-probe.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/wrapup-drift-probe.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)";
190
+ if [ -f "$S" ]; then
191
+ "$RUNNER" "$S";
192
+ else
193
+ printf '{"clean":false,"reasons":["probe script not found"],"paths":[]}' > ".spur/run/$__runId-drift-probe.json";
194
+ printf '\n' > ".spur/run/$__runId-mode.txt";
195
+ fi;
173
196
  fi
174
197
  - kind: file.read.into-var
175
198
  options:
@@ -190,12 +213,10 @@ states:
190
213
  options:
191
214
  command: >-
192
215
  mkdir -p .spur/run .spur/memory &&
193
- if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
194
- bun plugins/sp/scripts/wrapup-steps.ts route-reason;
195
- elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
196
- node "$W" route-reason;
216
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/wrapup-steps.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/wrapup-steps.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then
217
+ "$RUNNER" "$S" route-reason;
197
218
  else
198
- echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
219
+ echo "wrapup-steps failed closed — script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
199
220
  printf 'FAIL\n' > ".spur/run/$__runId-wrapup-resolve.status";
200
221
  fi
201
222
 
@@ -234,6 +255,34 @@ states:
234
255
  expectFile: .spur/run/${vars.__runId}-wrapup-learnings.md
235
256
  timeoutMs: ${vars.stepTimeoutMs}
236
257
 
258
+ - id: learnings-validate
259
+ description: >
260
+ Structural shape gate between doc-sync and the append (0986): expectFile
261
+ asserts the capture EXISTS and nothing about its shape, so a
262
+ stream-of-thought capture could be appended verbatim to the tracked
263
+ memory file. This state classifies a NONEMPTY capture — a date, a
264
+ four-digit task WBS, and at least one markdown bullet — and writes PASS
265
+ or invalid-learnings-shape to a run-scoped status. An empty or missing
266
+ capture keeps the existing soft skip (PASS) so learnings-append still
267
+ performs its no-op; an unclassifiable status fails loud instead of
268
+ appending it. Structural check only — the doc-sync prompt owns prose
269
+ quality; no new engine-level content contract.
270
+ onEnter:
271
+ # (warn) structural check only; the doc-sync prompt owns prose quality (0986 Design).
272
+ # The WBS predicate excludes digit/dash neighbours so a date's year cannot satisfy it.
273
+ - kind: shell
274
+ options:
275
+ command: >-
276
+ mkdir -p .spur/run &&
277
+ S=".spur/run/$__runId-wrapup-learnings.status" &&
278
+ F=".spur/run/$__runId-wrapup-learnings.md" &&
279
+ if [ ! -s "$F" ] || awk '/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/{d=1} /(^|[^0-9-])[0-9][0-9][0-9][0-9]([^0-9-]|$)/{w=1} /^[[:space:]]*[-*] /{b=1} END{exit !(d+w+b==3)}' "$F"; then
280
+ printf 'PASS\n' > "$S";
281
+ else
282
+ printf 'invalid-learnings-shape\n' > "$S";
283
+ fi &&
284
+ exit 0
285
+
237
286
  - id: learnings-append
238
287
  description: >
239
288
  Best-effort soft append of the captured learnings to .spur/memory/learnings.md
@@ -259,17 +308,45 @@ states:
259
308
  description: >
260
309
  Contract-violation repair (ADR-118 pilot, 0871): doc-sync's agent.run missed
261
310
  its declared post-condition after a clean exit, so wrap-up does NOT re-dispatch
262
- the expensive agent on this attempt. The miss is recorded to a run-scoped
263
- repair status and wrap-up proceeds to metrics-record — the run log and action
264
- trace already name the violated contract and the observed value.
311
+ the expensive agent on this attempt. Also the destination for a nonempty
312
+ capture that fails learnings-validate's shape gate (0986). The miss is
313
+ recorded to a run-scoped repair status — text distinguishing a narration-only
314
+ shape failure from the missing-file contract violation — and wrap-up proceeds
315
+ through the doc-tripwire hop (1037) to metrics-record; the run log and
316
+ action trace already name the violated contract and the observed value.
265
317
  onEnter:
266
318
  - kind: shell
267
319
  options:
268
320
  command: >-
269
321
  mkdir -p .spur/run &&
270
- printf 'contract-violation: doc-sync learnings capture missed its declared contract — repair skipped re-dispatch (ADR-118 pilot)\n' > ".spur/run/$__runId-wrapup-repair.status" &&
322
+ R=".spur/run/$__runId-wrapup-repair.status" &&
323
+ V="$(cat .spur/run/$__runId-wrapup-learnings.status 2>/dev/null)" &&
324
+ if [ "$V" = invalid-learnings-shape ]; then printf 'invalid-learnings-shape: narration-only learnings capture — append skipped, repair recorded (0986)\n' > "$R";
325
+ else printf 'contract-violation: doc-sync learnings capture missed its declared contract — repair skipped re-dispatch (ADR-118 pilot)\n' > "$R";
326
+ fi &&
271
327
  exit 0
272
328
 
329
+ - id: doc-tripwire
330
+ description: >
331
+ Repo-wide tripwire over the wrap diff (1037): the doc-sync edits are still
332
+ uncommitted when wrap-up reaches a terminal success, and the repo-wide
333
+ tripwires (repo-wide-tests/) execute only inside spur-check-feature — once
334
+ a wrap edit is committed on a clean tree, the working-diff tests (e.g.
335
+ adr-supersession (e)) can no longer see it. Entered from learnings-append
336
+ and repair, before metrics or feature state mutate, it runs the trusted
337
+ `docTripwireCmd` and records PASS or FAIL to a run-scoped status file; the
338
+ action always exits 0 so status truth lives in the file (0783 R4). Only a
339
+ verified run writes PASS; an empty docTripwireCmd disables the check and
340
+ still writes PASS. The no-doc-sync fast path (task-resolve →
341
+ metrics-record) never enters this state.
342
+ onEnter:
343
+ - kind: shell
344
+ options:
345
+ command: >-
346
+ sh -c "$docTripwireCmd" &&
347
+ printf 'PASS\n' > ".spur/run/$__runId-wrapup-doc-tripwire.status" ||
348
+ printf 'FAIL\n' > ".spur/run/$__runId-wrapup-doc-tripwire.status"
349
+
273
350
  - id: metrics-record
274
351
  description: >
275
352
  Append one JSONL row per task to .spur/memory/wrapup-metrics.jsonl deterministically.
@@ -288,18 +365,17 @@ states:
288
365
  options:
289
366
  command: >-
290
367
  mkdir -p .spur/run &&
291
- if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
292
- bun plugins/sp/scripts/wrapup-steps.ts metrics;
293
- elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
294
- node "$W" metrics;
368
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/wrapup-steps.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/wrapup-steps.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then
369
+ "$RUNNER" "$S" metrics;
295
370
  else
296
- echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
371
+ echo "wrapup-steps failed closed — script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
297
372
  printf 'FAIL\n' > ".spur/run/$__runId-wrapup-metrics.status";
298
373
  fi
299
374
 
300
375
  - id: feature-transition
301
376
  description: >
302
- If vars.feature is set, sync feature status via bounded feature-sync-bounded
377
+ If vars.feature is set, sync feature status via `spur feature sync` (repeated-BLOCKED
378
+ suppression is built into the sync service, so no wrapper script is needed)
303
379
  (0411). The shell terminates `exit 0` so artifacts already landed are never
304
380
  discarded, but the outcome is truthful (0770 + 0783 R4): sync succeeds only
305
381
  with a valid proposal matching vars.feature, no gateBlocked/requiresConfirm
@@ -322,12 +398,10 @@ states:
322
398
  options:
323
399
  command: >-
324
400
  mkdir -p .spur/run &&
325
- if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
326
- bun plugins/sp/scripts/wrapup-steps.ts feature-transition;
327
- elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
328
- node "$W" feature-transition;
401
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/wrapup-steps.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/wrapup-steps.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then
402
+ "$RUNNER" "$S" feature-transition;
329
403
  else
330
- echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
404
+ echo "wrapup-steps failed closed — script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
331
405
  printf 'FAIL\n' > ".spur/run/$__runId-wrapup-sync.status";
332
406
  fi
333
407
 
@@ -387,9 +461,10 @@ states:
387
461
  - id: failed
388
462
  description: >
389
463
  Terminal — wrap-up failed (0770): invalid wrap input, an unresolved or
390
- non-completed task, a failed metrics capture, a failed required sync, or
391
- a failed feature gate. Already-written artifacts (learnings, metrics
392
- rows, route reason) are preserved; nothing is rolled back.
464
+ non-completed task, a failed metrics capture, a failed required sync, a
465
+ failed repo-wide tripwire (1037), or a failed feature gate.
466
+ Already-written artifacts (learnings, metrics rows, route reason) are
467
+ preserved; nothing is rolled back.
393
468
 
394
469
  transitions:
395
470
  # ── start -> task-resolve ──
@@ -460,8 +535,8 @@ transitions:
460
535
  guard:
461
536
  kind: contract-violation
462
537
  - from: doc-sync
463
- to: learnings-append
464
- description: Doc drift repair + learning capture succeeded — append learnings.
538
+ to: learnings-validate
539
+ description: Doc drift repair + learning capture succeeded — validate the capture's shape before appending.
465
540
  guard:
466
541
  kind: action-ok
467
542
  - from: doc-sync
@@ -475,20 +550,72 @@ transitions:
475
550
  guard:
476
551
  kind: always
477
552
 
478
- # ── linear body: learnings-append -> metrics-record ──
553
+ # ── learnings-validate: shape gate (0986) — invalid-shape to repair, PASS to append ──
554
+ # Declaration order matters: the discriminating invalid-shape edge is tried
555
+ # first, then PASS; an unreadable status fails loud rather than appending an
556
+ # unclassified capture.
557
+ - from: learnings-validate
558
+ to: repair
559
+ description: >
560
+ Nonempty capture failed the structural shape gate (no date/WBS/bullet) —
561
+ route to the cheap repair edge and never append narration (0986 R2).
562
+ guard:
563
+ kind: shell
564
+ options:
565
+ command: 'test "$(cat .spur/run/$__runId-wrapup-learnings.status 2>/dev/null)" = invalid-learnings-shape'
566
+ - from: learnings-validate
567
+ to: learnings-append
568
+ description: Capture is shape-valid (or empty/missing, keeping the soft skip) — append.
569
+ guard:
570
+ kind: shell
571
+ options:
572
+ command: 'test "$(cat .spur/run/$__runId-wrapup-learnings.status 2>/dev/null)" = PASS'
573
+ - from: learnings-validate
574
+ to: failed
575
+ terminalReason: failed-check
576
+ description: >
577
+ Validation status missing or unreadable — fail loud instead of appending
578
+ a capture whose shape was never classified.
579
+ guard:
580
+ kind: always
581
+
582
+ # ── doc-sync exits converge on the doc-tripwire hop (1037) before metrics ──
479
583
  - from: learnings-append
480
- to: metrics-record
481
- description: Learning capture appended (or soft-skipped) — record metrics.
584
+ to: doc-tripwire
585
+ description: Learning capture appended (or soft-skipped) — run the repo-wide tripwire over the wrap diff.
482
586
  guard:
483
587
  kind: always
484
588
 
485
- # ── repair: cheap path, no re-dispatch -> metrics-record ──
486
589
  - from: repair
487
- to: metrics-record
488
- description: Contract-violation repair recorded — proceed to metrics without re-dispatch.
590
+ to: doc-tripwire
591
+ description: Contract-violation repair recorded — run the tripwire before metrics without re-dispatch.
489
592
  guard:
490
593
  kind: always
491
594
 
595
+ # ── doc-tripwire: repo-wide tripwire gate (1037) ──
596
+ # Declaration order matters: the FAIL edge is tried first so a failed tripwire
597
+ # can never be absorbed by the PASS edge; a missing status matches neither
598
+ # edge and follows the engine's no-match behavior for status-file states.
599
+ - from: doc-tripwire
600
+ to: failed
601
+ terminalReason: failed-check
602
+ description: >
603
+ Repo-wide tripwire FAILED on the still-uncommitted wrap diff (1037): an
604
+ edit the doc-sync stage made (e.g. an in-place historical ADR change)
605
+ violates a working-diff test. Learnings and docs already on disk stay
606
+ put; nothing is rolled back.
607
+ guard:
608
+ kind: shell
609
+ options:
610
+ command: 'test "$(cat .spur/run/$__runId-wrapup-doc-tripwire.status 2>/dev/null)" = FAIL'
611
+ - from: doc-tripwire
612
+ to: metrics-record
613
+ description: Repo-wide tripwire PASS (or the check disabled by an empty docTripwireCmd) — record metrics.
614
+ guard:
615
+ kind: shell
616
+ options:
617
+ command: 'test "$(cat .spur/run/$__runId-wrapup-doc-tripwire.status 2>/dev/null)" = PASS'
618
+
492
619
  # ── metrics-record: fail edge, then conditional routing (feature → merge → done) ──
493
620
  # Declaration order matters: the FAIL edge is tried first (0770), then
494
621
  # feature-transition (if feature is set), then branch-cleanup (if merge=true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/spur",
3
- "version": "0.3.94",
3
+ "version": "0.3.96",
4
4
  "description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
5
5
  "keywords": [
6
6
  "spur",
@@ -24,12 +24,16 @@
24
24
  "spur": "spur.js"
25
25
  },
26
26
  "exports": {
27
- "./schemas/*": "./schemas/*"
27
+ "./schemas/*": "./schemas/*",
28
+ "./board": {
29
+ "types": "./board/index.d.ts"
30
+ }
28
31
  },
29
32
  "files": [
30
33
  "spur.js",
31
34
  "config",
32
35
  "schemas",
36
+ "board",
33
37
  "web",
34
38
  "README.md",
35
39
  "plugins/",
@@ -45,7 +49,7 @@
45
49
  "dev": "bun run src/index.ts",
46
50
  "build": "bun run ../../scripts/spur-dev.ts build-cli",
47
51
  "build:binaries": "bun run ../../scripts/spur-dev.ts build-binaries",
48
- "build:bundle": "bun run ../../scripts/spur-dev.ts bundle-web && bun build src/index.ts --target=bun --outfile spur.js && bun run ../../scripts/spur-dev.ts bundle-config config && bun run ../../scripts/spur-dev.ts bundle-plugins",
52
+ "build:bundle": "bun run ../../scripts/spur-dev.ts bundle-web && bun run ../../scripts/spur-dev.ts emit-board-types && bun build src/index.ts --target=bun --outfile spur.js && bun run ../../scripts/spur-dev.ts bundle-config config && bun run ../../scripts/spur-dev.ts bundle-plugins",
49
53
  "test": "bun test tests --coverage --coverage-dir=../../.coverage --pass-with-no-tests",
50
54
  "typecheck": "tsc --noEmit",
51
55
  "prepack": "bun run build:bundle",
@@ -53,14 +57,14 @@
53
57
  },
54
58
  "devDependencies": {
55
59
  "@commander-js/extra-typings": "^14.0.0",
56
- "@gobing-ai/ts-db": "^0.5.9",
57
- "@gobing-ai/ts-ai-runner": "^0.5.9",
58
- "@gobing-ai/ts-dual-workflow-engine": "^0.5.9",
59
- "@gobing-ai/ts-infra": "^0.5.9",
60
- "@gobing-ai/ts-llm-jsonl-importer": "^0.5.9",
61
- "@gobing-ai/ts-rule-engine": "^0.5.9",
62
- "@gobing-ai/ts-runtime": "^0.5.9",
63
- "@gobing-ai/ts-utils": "^0.5.9",
60
+ "@gobing-ai/ts-db": "^0.5.11",
61
+ "@gobing-ai/ts-ai-runner": "^0.5.11",
62
+ "@gobing-ai/ts-dual-workflow-engine": "^0.5.11",
63
+ "@gobing-ai/ts-infra": "^0.5.11",
64
+ "@gobing-ai/ts-llm-jsonl-importer": "^0.5.11",
65
+ "@gobing-ai/ts-rule-engine": "^0.5.11",
66
+ "@gobing-ai/ts-runtime": "^0.5.11",
67
+ "@gobing-ai/ts-utils": "^0.5.11",
64
68
  "@types/bun": "1.3.14",
65
69
  "@types/figlet": "^1.7.0",
66
70
  "@types/node-notifier": "8.0.5",
@@ -133,11 +133,12 @@ list this README is checked against.
133
133
  | `dev-find-conflict` | Authority-aware semantic audit across source, task, feature, and project authority files — detect conflicts, resolve claim-specific authority, and route confirmed repairs through owner surfaces |
134
134
  | `dev-find-next` | Prompt-first feature frontier prioritizer — ranks the open feature frontier by derived importance/urgency with per-candidate evidence; gates unactionable features; emits tree defects as proposals only |
135
135
  | `dev-fixall` | Fix all lint, type, and test errors systematically across the working tree |
136
+ | `dev-fixgha` | Find and fix failing GitHub Actions runs — gh fetch → diagnose → root-cause fix → commit → push → re-verify until green; optional context/filter argument |
136
137
  | `dev-simplify` | Simplify recently-changed code for clarity without changing behavior — incremental, test-after-each, revert on regression |
137
138
  | `dev-refactor` | Lens-routed refactoring with a preservation contract — taste lenses (api/architect/tests/ui) classify findings on the shared schema; cutting/breaking changes pause for operator approval; forwards to sp:code-refactoring |
138
139
  | `dev-arch` | Survey a codebase (or module tree) for shallow modules and deepening opportunities — emit a ranked MARKDOWN candidate report that feeds the planning half; never auto-refactors |
139
140
  | `dev-reverse` | Reverse-engineer a codebase — analyze unfamiliar repos, generate HLD/architecture docs, audit quality/security, and produce onboarding documentation |
140
- | `dev-gitmsg` | Generate conventional commit message(s) from the current change set via one bounded diff capture, optionally commit |
141
+ | `dev-gitmsg` | Generate conventional commit message(s) from the current change set via one bounded gather call, optionally commit |
141
142
  | `dev-gtd` | Get things done — quality gate (auto-fix) → conventional commit → push → gh verify in one flow; optional act CI simulation via `--act` |
142
143
  | `dev-changelog` | Generate changelog from git commits |
143
144
 
@@ -269,9 +270,9 @@ plugins/sp/
269
270
  │ # + careful-guard.{ts,test.ts} + context-hooks.test.ts + token-estimate.test.ts
270
271
  │ # + shared policy modules: agent-hint.ts, destructive-policy.{ts,test.ts}, task-file-policy.{ts,test.ts}
271
272
  │ # + pi/guard-extension.{ts,test.ts} (plugin.json `extensions.pi` entry point)
272
- ├── scripts/ # Executable helpers, split from prompts (ADR-031) — validate-commands.ts (thin-wrapper validator), batch-preflight.ts + scripts/<skill>/
273
+ ├── scripts/ # Executable helpers, split from prompts (ADR-031) — batch-preflight.ts + scripts/<skill>/
273
274
  │ # (daily-summary: {daily-summary, logger}.ts; dogfood-testing: {detect-pipeline-driving, validate-report}.ts)
274
- ├── tests/ # Plugin tests — command-contract.test.ts + skill-structure.test.ts + batch-preflight.test.ts + per-skill suites
275
+ ├── tests/ # Plugin tests — skill-structure.test.ts + batch-preflight.test.ts + per-skill suites (command-contract moved to scripts/commands/)
275
276
  ├── evals/ # Skill behavioral eval harness (scenarios + judge + run-eval runner)
276
277
  ├── plugin.json # Marketplace entry
277
278
  └── README.md # This file
@@ -399,7 +400,7 @@ hand-editable source for the operator command surface. Per-platform adapters are
399
400
  output** owned by `superskill` (`superskill install sp`) and never committed here. Plugin `sp` ships
400
401
  no per-platform artifacts — only the platform-independent thin wrappers.
401
402
 
402
- **Thin-wrapper contract** is enforced by `scripts/validate-commands.ts`:
403
+ **Thin-wrapper contract** is enforced by `scripts/commands/validate-commands.ts`:
403
404
 
404
405
  ```bash
405
406
  bun run validate-commands # validate all 39 commands
@@ -415,7 +416,7 @@ gate (a) is strengthened: the ordered three-heading set `## Argument Flags` →
415
416
  `## Implementation` is required, and gate (e) checks the `argument-hint` is syntax-only (no
416
417
  Markdown links), the `## Argument Flags` table has exactly `Flag | Description | Default` columns,
417
418
  the command carries exactly one glossary reference, and canonical hint tokens have bidirectional
418
- parity with table rows. The same gates are tested in `tests/command-contract.test.ts` and
419
+ parity with table rows. The same gates are tested in `scripts/commands/command-contract.test.ts` and
419
420
  `tests/command-flag-parity.test.ts`. See
420
421
  `docs/design/dev-command-argument-contract.md` for the full contract.
421
422
 
@@ -506,15 +507,12 @@ hold `SKILL.md` and prompt-side companions only.
506
507
  | `hooks/context-*.ts` | Runtime for the three registered context hooks (session-start, post-tool, session-stop) — token-cost estimation + ledger append for `sp:indexed-context` |
507
508
  | `hooks/careful-guard.ts` | Opt-in destructive-command guard (unwired — see Hooks above) |
508
509
  | `scripts/batch-preflight.ts` | Pure TABLE A STOP evaluation for `super-planner` — skip doomed pipeline launches without spawning a Skill subprocess; recovery hints map stuck statuses to a single `/sp:dev-*` hop |
509
- | `scripts/workflow-step-profile.ts` | Read-only step profile from `spur workflow trace` — per node and action-kind durations, idle gaps, session mode and `cacheHit` coverage, plus the ADR-115 cache-window flags `sp:spur-doctor` turns into workflow-optimization proposals |
510
+ | `scripts/workflow-step-profile.ts` | Thin glue over the generated lib bundle (`lib/step-profile.generated.mjs` from `packages/app/src/workflow/step-profile.ts`) — read-only step profile from `spur workflow trace`: per node and action-kind durations, idle gaps, session mode and `cacheHit` coverage, plus the ADR-115 cache-window flags `sp:spur-doctor` turns into workflow-optimization proposals |
510
511
  | `scripts/dogfood-testing/detect-pipeline-driving.ts` | Word-boundary detector for pipeline-driving testees (leading-space invariant) |
511
512
  | `scripts/dogfood-testing/validate-report.ts` | Pure `validateReport(md)` — footer-mandatory + 7-check finalize-or-abort contract with stable error codes |
512
513
  | `scripts/daily-summary/{daily-summary,logger}.ts` | ccusage + git-history orchestration helpers for `sp:daily-summary` |
513
- | `scripts/feature-sync-bounded.ts` | Bounded retry-suppression wrapper for `spur feature sync` during batch/wrap-up runs — suppresses identical L4-blocked repeats |
514
- | `scripts/stage-registry-adapter.ts` | dev-next golden-path adapter over the canonical stage registry — TABLE A/B/C resolution bridge for the status-aware facade |
515
- | `scripts/task-size-precheck.ts` | Pipeline size precheck guard (R2) — evaluates R-item/Plan-count limits to PASS/FAIL |
516
514
  | `scripts/task-diffstat.ts` | 0943 triage-lane diffstat producer — numstat + untracked scan vs the run base; writes `<wbs>-diffstat.json` with the sensitive-path flag; fails safe (sensitive) |
517
- | `scripts/validate-flag-contracts.ts` | Mechanical consistency gate — compares flag claims across command files, flag-glossary, cross-cutting, dev-operations, and ADR; reports disagreements |
515
+ | `scripts/commands/validate-flag-contracts.ts` | Mechanical consistency gate — compares flag claims across command files, flag-glossary, cross-cutting, dev-operations, and ADR; reports disagreements |
518
516
  | `*.test.ts` | Unit suites — in `hooks/` for guards, in `tests/<skill>/` per ADR-031 pairing |
519
517
 
520
518
  **Design principle:** Scripts are **deterministic enforcement**. Unlike skills (which are advisory
@@ -26,7 +26,8 @@ skills: [sp:code-verification, sp:functional-review, sp:code-improvement]
26
26
 
27
27
  The **review specialist** for the sp plugin. Runs the multi-dimensional review defined by
28
28
  `/sp:dev-review` — functional traceability, SECUA quality, and architectural depth — either
29
- standalone (a source path or a task WBS) or as the pipeline's Phase 7 review step.
29
+ standalone (a task, a task set, a source path, or a path list) or as the pipeline's Phase 7
30
+ review step.
30
31
 
31
32
  ## Role
32
33
 
@@ -44,8 +45,8 @@ write `## Review`. This coordinator is the single `## Review` writer in coordina
44
45
  fallback only and never overwrites authored Review.
45
46
 
46
47
  Your job: establish scope, dispatch each requested dimension to its skill, collect findings, merge
47
- them into a ranked report, and write the report to the task's `## Review` section (pipeline mode) or
48
- emit it as advisory output (standalone mode).
48
+ them into a ranked report, and write the report to the task's `## Review` section (per task target)
49
+ or emit it as advisory output (path target).
49
50
 
50
51
  ## When to use
51
52
 
@@ -57,9 +58,13 @@ emit it as advisory output (standalone mode).
57
58
 
58
59
  ### Direct-Entry (standalone)
59
60
 
60
- Invoked by the operator or `/sp:dev-review <wbs|path>`. You run the full multi-dimensional review
61
- and emit the ranked findings. Advisory by default — the operator decides what to act on. Only
62
- when invoked under the pipeline (or with `--next`) do blocker/major findings block a gate.
61
+ Invoked by the operator or `/sp:dev-review` — usually as the coordinator definition the
62
+ invoking session acts under (`/sp:dev-review` runs its review inline; it does not dispatch this
63
+ agent). The target kind decides the output contract: **WBS target → the merged report is written
64
+ to the task's `## Review` section** (via `spur task update <wbs> --section Review --from-file`);
65
+ **path target → advisory output only** (no task mutation). With multiple targets the contract
66
+ applies per target — see [Multi-target coordination](#multi-target-coordination-task-1023) below.
67
+ Only when invoked under the pipeline do blocker/major findings block a gate.
63
68
 
64
69
  ### Pipeline Phase 7
65
70
 
@@ -68,12 +73,29 @@ Invoked by `task-pipeline.yaml`'s `review` step. The pipeline hands you the task
68
73
  return a PASS/PARTIAL/FAIL verdict to the pipeline's `approve(HITL)` gate. `blocker`/`major`
69
74
  findings block the gate; `minor`/`advisory` are recorded but do not block.
70
75
 
76
+ ### Multi-target coordination (task 1023)
77
+
78
+ - **Task targets (`--tasks <selector>` / `--feature <id>[,<id>]`).** The set resolves once through
79
+ the batch selector grammar ([execution-batch.md § Step 1](../skills/spur-dev/references/execution-batch.md#step-1--selector-resolution-r1))
80
+ and freezes. Fan out one WBS-mode review per task and write each task's **own** merged
81
+ `## Review` — never merge two tasks into one Review. Tasks in `backlog`/`todo`/`blocked` are
82
+ reported **NOT-STARTED** and skipped (§ 3a outcome vocabulary); a per-task failure does not stop
83
+ the remaining tasks. End the run with a combined summary table (WBS, verdict, P1/P2 counts).
84
+ - **Path targets (`--scope <path>[,<path>]`).** Paths must exist, are normalized, and
85
+ nested/duplicate paths are merged. Run one path-scope sub-review (Step 3p) per surviving path —
86
+ each eligible for native-subagent dispatch per
87
+ [dispatch-surface.md](../skills/parallel-execution/references/dispatch-surface.md) — then merge
88
+ the fragments, run **one** cross-path architecture pass (`sp:code-improvement` over the
89
+ inter-path imports), and emit **one** advisory report. No task mutation.
90
+ - **`--triage` with multiple targets** buckets findings across all targets once; identical
91
+ `file:line` findings are deduped before bucketing.
92
+
71
93
  ## Skill invocation
72
94
 
73
95
  | Platform | Invocation |
74
96
  | ---------- | ----------- |
75
- | Claude Code | Spawned by `/sp:dev-review` → `Skill(skill="sp:code-verification"/"sp:functional-review"/"sp:code-improvement", args="...")` dispatch |
76
- | Other platforms | Invoke the three skills' review modes directly; this agent is the dispatcher |
97
+ | Claude Code | The review coordinator dispatches `Skill(skill="sp:code-verification"/"sp:functional-review"/"sp:code-improvement", args="...")` — under `/sp:dev-review` the coordinator is the invoking session (this agent is not dispatched); when this agent is dispatched directly, it dispatches the same skills |
98
+ | Other platforms | The coordinator invokes the three skills' review modes directly — this agent when dispatched, the invoking session under `/sp:dev-review` |
77
99
 
78
100
  ## Dispatch surface
79
101
 
@@ -94,13 +116,17 @@ HITL gate unless `--auto` was passed.
94
116
 
95
117
  ### Always
96
118
 
97
- - [ ] Establish scope first: WBS mode (task diff) or path mode (source glob). Derive the diff
98
- scope the same way `sp:code-verification` Step 3 does.
119
+ - [ ] Establish scope first per target kind: task targets (task diff → `sp:code-verification`
120
+ Step 3, one review per task) or path targets (tracked files under the path →
121
+ `sp:code-verification` Step 3p, one sub-review per path). Defer to that recipe — no
122
+ restated copy.
99
123
  - [ ] Dispatch each requested dimension to its owning skill — do not inline the review logic.
100
124
  - [ ] Merge findings into a single ranked report, emitting native priority cells
101
125
  (`P1 (blocker)` > `P2 (major)` > `P3 (minor)` > `P4 (advisory)` — see Output Format).
102
- - [ ] In pipeline mode, write the merged report to the task's `## Review` section via
103
- `spur task update <wbs> --section Review --from-file`; in standalone mode, emit as output.
126
+ - [ ] With a WBS target (standalone or pipeline), write the merged report to that task's
127
+ `## Review` section via `spur task update <wbs> --section Review --from-file` — per task
128
+ under a task set, then the combined summary table; with a path target, emit as advisory
129
+ output (one merged report for a path list, including the cross-path architecture pass).
104
130
  - [ ] Cite `file:line` evidence for every finding — no vague "implemented correctly."
105
131
  - [ ] Apply the honesty gate: no PASS verdict without fresh, pasted verification evidence.
106
132
 
@@ -139,10 +165,11 @@ fails it. One explicit mapping, no transcription step anywhere downstream:
139
165
  Severity words stay visible in the same cell — the mapping adds the machine-readable label, it does
140
166
  not replace the semantics.
141
167
 
142
- **Section-relative headings.** In pipeline mode the report body is written *into* the task's
143
- `### Review` section, so every heading inside it MUST be `####` or deeper. A `##`/`###` heading in
144
- the body becomes a new top-level task section and corrupts the document. In standalone mode
145
- (emitted as output, not written to a task) the same body may be rendered one level shallower.
168
+ **Section-relative headings.** In WBS mode (standalone or pipeline) the report body is written
169
+ *into* the task's `### Review` section, so every heading inside it MUST be `####` or deeper. A
170
+ `##`/`###` heading in the body becomes a new top-level task section and corrupts the document. With
171
+ a path target (emitted as output, not written to a task) the same body may be rendered one level
172
+ shallower.
146
173
 
147
174
  ```markdown
148
175
  #### Review Report — <wbs|path>
@@ -180,8 +207,6 @@ rejected by the checker, and so they should be:
180
207
  | 1 | P4 (advisory) | — | No P1–P3 findings: 6 changed files reviewed across all six dimensions; R1–R3 traceable to tests | `packages/app/src/workflow/proof-input-fingerprint.ts:102-160` |
181
208
  ```
182
209
 
183
- With `--json`, emit the same shape as a JSON object for machine consumption.
184
-
185
210
  ## Out of scope
186
211
 
187
212
  - Implementing fixes (that's `sp:code-implementation` / `sp:super-coder`).