@gobing-ai/spur 0.3.78 → 0.3.81

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 (177) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/config.example.yaml +29 -18
  3. package/config/config.global.yaml +10 -11
  4. package/config/pipeline-budgets.json +34 -2
  5. package/config/plugin-scripts.json +25 -0
  6. package/config/rules/boundary/config-loading-ownership.yaml +0 -3
  7. package/config/rules/boundary/dao-boundary.yaml +4 -17
  8. package/config/rules/boundary/planning-folder-hardcode.yaml +0 -1
  9. package/config/rules/boundary/sp-no-vendor-refs.yaml +3 -2
  10. package/config/rules/boundary/sp-runtime-path.yaml +3 -14
  11. package/config/rules/quality/coverage-gate.yaml +3 -14
  12. package/config/rules/quality/tsdoc-exports.yaml +4 -7
  13. package/config/rules/strict/http-boundaries.yaml +5 -8
  14. package/config/rules/strict/runtime-boundaries.yaml +1 -5
  15. package/config/rules/structure/protected-files.yaml +9 -3
  16. package/config/rules/structure/test-focus-skip.yaml +0 -2
  17. package/config/rules/structure/test-location.yaml +0 -5
  18. package/config/rules/surface/check-cli-surface.yaml +3 -2
  19. package/config/rules/typescript/bun-tooling.yaml +5 -7
  20. package/config/rules/typescript/guarded-happy-dom-register.yaml +0 -2
  21. package/config/rules/typescript/happy-dom-teardown.yaml +0 -2
  22. package/config/rules/typescript/no-biome-suppressions.yaml +0 -2
  23. package/config/rules/typescript/no-debugger.yaml +0 -2
  24. package/config/rules/typescript/no-eslint-suppressions.yaml +0 -4
  25. package/config/rules/typescript/no-leaky-module-mocks.yaml +6 -13
  26. package/config/rules/typescript/no-module-scope-import-calls.yaml +0 -2
  27. package/config/rules/typescript/no-syscall-emulation-in-boundary-mock.yaml +0 -3
  28. package/config/rules/typescript/no-unmocked-module-eval-side-effects.yaml +0 -3
  29. package/config/rules/typescript/output-boundaries.yaml +0 -3
  30. package/config/rules/typescript/prefer-accessible-role-for-button-queries.yaml +0 -3
  31. package/config/rules/ui/ui-import-boundary.yaml +1 -5
  32. package/config/templates/AGENTS.md +26 -23
  33. package/config/templates/docs/00_ADR.md +13 -23
  34. package/config/templates/docs/01_PRD.md +5 -2
  35. package/config/templates/docs/02_ROADMAP.md +9 -13
  36. package/config/templates/docs/03_ARCHITECTURE.md +2 -2
  37. package/config/templates/docs/04_DESIGN.md +12 -31
  38. package/config/templates/docs/05_FEATURES.md +6 -18
  39. package/config/templates/docs/99_PROJECT_CONSTITUTION.md +162 -394
  40. package/config/transition-shims.json +7 -7
  41. package/config/workflows/basic.yaml +4 -0
  42. package/config/workflows/docs-pipeline.yaml +13 -14
  43. package/config/workflows/feature-dev.yaml +20 -65
  44. package/config/workflows/history-anatomy.yaml +22 -1
  45. package/config/workflows/idea-pipeline.yaml +53 -97
  46. package/config/workflows/pr-review.yaml +21 -33
  47. package/config/workflows/task-pipeline.yaml +87 -330
  48. package/config/workflows/wayfinder-resolution.yaml +12 -26
  49. package/config/workflows/wrapup-pipeline.yaml +48 -189
  50. package/package.json +9 -9
  51. package/plugins/sp/README.md +22 -8
  52. package/plugins/sp/agents/expert-spur.md +41 -19
  53. package/plugins/sp/agents/super-reviewer.md +43 -8
  54. package/plugins/sp/lib/idea-handoff.generated.d.mts +17 -0
  55. package/plugins/sp/lib/idea-handoff.generated.mjs +1301 -0
  56. package/plugins/sp/plugin.json +1 -1
  57. package/plugins/sp/scripts/feature-dev-precheck.mjs +146 -0
  58. package/plugins/sp/scripts/feature-dev-precheck.ts +238 -0
  59. package/plugins/sp/scripts/idea-handoff.mjs +27 -0
  60. package/plugins/sp/scripts/idea-handoff.ts +44 -0
  61. package/plugins/sp/scripts/quality-gate.mjs +165 -0
  62. package/plugins/sp/scripts/quality-gate.ts +217 -0
  63. package/plugins/sp/scripts/verify-answer-lint.ts +21 -3
  64. package/plugins/sp/scripts/workflow-step-profile.mjs +319 -0
  65. package/plugins/sp/scripts/workflow-step-profile.ts +456 -0
  66. package/plugins/sp/scripts/wrapup-steps.mjs +350 -0
  67. package/plugins/sp/scripts/wrapup-steps.ts +466 -0
  68. package/plugins/sp/skills/conflict-finding/SKILL.md +6 -0
  69. package/plugins/sp/skills/daily-summary/SKILL.md +1 -1
  70. package/plugins/sp/skills/doc-evolve/SKILL.md +26 -40
  71. package/plugins/sp/skills/doc-evolve/references/operations.md +17 -30
  72. package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
  73. package/plugins/sp/skills/spec-decomposition/references/decomposition.md +29 -0
  74. package/plugins/sp/skills/spur-cli/references/agent.md +56 -14
  75. package/plugins/sp/skills/spur-cli/references/message.md +30 -3
  76. package/plugins/sp/skills/spur-cli/references/projects.md +45 -1
  77. package/plugins/sp/skills/spur-cli/references/self.md +5 -4
  78. package/plugins/sp/skills/spur-cli/references/serve.md +5 -4
  79. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +17 -1
  80. package/plugins/sp/skills/spur-cli/references/tasks.md +32 -2
  81. package/plugins/sp/skills/spur-cli/references/team.md +21 -1
  82. package/plugins/sp/skills/spur-cli/references/workflows/operations.md +6 -3
  83. package/plugins/sp/skills/spur-cli/references/workflows/workflow-fit-and-tuning.md +57 -18
  84. package/plugins/sp/skills/spur-composer/SKILL.md +145 -0
  85. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +14 -0
  86. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +3 -3
  87. package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +12 -0
  88. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +46 -4
  89. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +24 -0
  90. package/plugins/sp/skills/spur-doctor/SKILL.md +138 -0
  91. package/plugins/sp/skills/taste-refactoring-api/README.md +43 -0
  92. package/plugins/sp/skills/taste-refactoring-api/SKILL.md +334 -0
  93. package/plugins/sp/skills/taste-refactoring-api/checklists/daily-api-review.md +71 -0
  94. package/plugins/sp/skills/taste-refactoring-api/examples/refactor-example.md +72 -0
  95. package/plugins/sp/skills/taste-refactoring-api/examples/review-template.md +93 -0
  96. package/plugins/sp/skills/taste-refactoring-api/references/api-refactoring-playbook.md +253 -0
  97. package/plugins/sp/skills/taste-refactoring-api/references/protocol-modes.md +79 -0
  98. package/plugins/sp/skills/taste-refactoring-api/references/research-basis.md +58 -0
  99. package/plugins/sp/skills/taste-refactoring-architect/README.md +26 -0
  100. package/plugins/sp/skills/taste-refactoring-architect/SKILL.md +471 -0
  101. package/plugins/sp/skills/taste-refactoring-architect/checklists/daily-architecture-review.md +48 -0
  102. package/plugins/sp/skills/taste-refactoring-architect/examples/refactor-example.md +55 -0
  103. package/plugins/sp/skills/taste-refactoring-architect/examples/review-template.md +51 -0
  104. package/plugins/sp/skills/taste-refactoring-architect/references/architecture-refactoring-playbook.md +173 -0
  105. package/plugins/sp/skills/taste-refactoring-architect/references/research-basis.md +28 -0
  106. package/plugins/sp/skills/taste-refactoring-tests/README.md +28 -0
  107. package/plugins/sp/skills/taste-refactoring-tests/SKILL.md +482 -0
  108. package/plugins/sp/skills/taste-refactoring-tests/checklists/daily-test-review.md +39 -0
  109. package/plugins/sp/skills/taste-refactoring-tests/examples/refactor-example.md +85 -0
  110. package/plugins/sp/skills/taste-refactoring-tests/examples/review-template.md +59 -0
  111. package/plugins/sp/skills/taste-refactoring-tests/references/research-basis.md +47 -0
  112. package/plugins/sp/skills/taste-refactoring-tests/references/test-refactoring-playbook.md +222 -0
  113. package/plugins/sp/skills/taste-refactoring-ui/README.md +12 -0
  114. package/plugins/sp/skills/taste-refactoring-ui/SKILL.md +290 -0
  115. package/plugins/sp/skills/taste-refactoring-ui/checklists/daily-ui-review.md +72 -0
  116. package/plugins/sp/skills/taste-refactoring-ui/examples/review-template.md +51 -0
  117. package/plugins/sp/skills/taste-refactoring-ui/references/refactoring-ui-playbook.md +170 -0
  118. package/plugins/sp/skills/wayfinder/SKILL.md +2 -2
  119. package/plugins/sp/skills/wayfinder/references/pipeline-resolution.md +30 -0
  120. package/schemas/spur-config.schema.json +49 -0
  121. package/spur.js +46936 -44198
  122. package/web/_astro/{BoardApp.CHQ1lycZ.js → BoardApp.B1U26g3I.js} +97 -95
  123. package/web/_astro/BoardApp.Csgyg-lS.js +1 -0
  124. package/web/_astro/{TaskDetail.GKfQJ60c.js → TaskDetail.DwPqpq7v.js} +1 -1
  125. package/web/_astro/{arc.DWEtA3Tx.js → arc.CweZEjN2.js} +1 -1
  126. package/web/_astro/{architectureDiagram-3BPJPVTR.DB42oWmP.js → architectureDiagram-3BPJPVTR.D89pbDuv.js} +1 -1
  127. package/web/_astro/{blockDiagram-GPEHLZMM.rhv-zNQV.js → blockDiagram-GPEHLZMM.BOuTeEpX.js} +1 -1
  128. package/web/_astro/{c4Diagram-AAUBKEIU.Ci4-4VvY.js → c4Diagram-AAUBKEIU.CASbkWZF.js} +1 -1
  129. package/web/_astro/channel.Cx6sXxhq.js +1 -0
  130. package/web/_astro/{chunk-2J33WTMH.Cc9veUgf.js → chunk-2J33WTMH.BKQYtOvY.js} +1 -1
  131. package/web/_astro/{chunk-4BX2VUAB.Bec9c4eI.js → chunk-4BX2VUAB.9sHLdMtG.js} +1 -1
  132. package/web/_astro/{chunk-55IACEB6.DoV8S1iB.js → chunk-55IACEB6.wOLXWlPs.js} +1 -1
  133. package/web/_astro/{chunk-727SXJPM.DwR-Qlyj.js → chunk-727SXJPM.DovFbwg3.js} +1 -1
  134. package/web/_astro/{chunk-AQP2D5EJ.ND_a81WY.js → chunk-AQP2D5EJ.B1Weod1X.js} +1 -1
  135. package/web/_astro/{chunk-FMBD7UC4.Wv_jwG48.js → chunk-FMBD7UC4.TEMS04st.js} +1 -1
  136. package/web/_astro/{chunk-ND2GUHAM.CXKXCMmp.js → chunk-ND2GUHAM.Cp8VT1wQ.js} +1 -1
  137. package/web/_astro/{chunk-QZHKN3VN.nkaoNYQq.js → chunk-QZHKN3VN.BzATdEcP.js} +1 -1
  138. package/web/_astro/{classDiagram-4FO5ZUOK.cMQcVlQu.js → classDiagram-4FO5ZUOK.C9BOCfAO.js} +1 -1
  139. package/web/_astro/{classDiagram-v2-Q7XG4LA2.cMQcVlQu.js → classDiagram-v2-Q7XG4LA2.C9BOCfAO.js} +1 -1
  140. package/web/_astro/{cose-bilkent-S5V4N54A.OaDJ7Mr2.js → cose-bilkent-S5V4N54A.DUnr4UAw.js} +1 -1
  141. package/web/_astro/{cynefin-OW5HDTMX.Chi8IphF.js → cynefin-OW5HDTMX.rYq5uM3D.js} +1 -1
  142. package/web/_astro/{cytoscape.esm.DzSz-X2X.js → cytoscape.esm.BB4DxJjf.js} +1 -1
  143. package/web/_astro/{dagre-BM42HDAG.CzK2t_Fp.js → dagre-BM42HDAG.CWeNKe3I.js} +1 -1
  144. package/web/_astro/{diagram-2AECGRRQ.DRvxlVS7.js → diagram-2AECGRRQ.DCkfls10.js} +1 -1
  145. package/web/_astro/{diagram-5GNKFQAL.CnYvNdwA.js → diagram-5GNKFQAL.D5U4JCka.js} +1 -1
  146. package/web/_astro/{diagram-KO2AKTUF.CpLpMw5R.js → diagram-KO2AKTUF.BZJgqaqG.js} +1 -1
  147. package/web/_astro/{diagram-LMA3HP47.JTb78qUA.js → diagram-LMA3HP47.DoMeHvPR.js} +1 -1
  148. package/web/_astro/{diagram-OG6HWLK6.Bk-1jDIb.js → diagram-OG6HWLK6.B50qwwWX.js} +1 -1
  149. package/web/_astro/{erDiagram-TEJ5UH35.D8hN9GZq.js → erDiagram-TEJ5UH35.DdGPG6LK.js} +1 -1
  150. package/web/_astro/{flowDiagram-I6XJVG4X.-6zQr6m5.js → flowDiagram-I6XJVG4X.QP2MJ12u.js} +1 -1
  151. package/web/_astro/{ganttDiagram-6RSMTGT7.DboLQ9ca.js → ganttDiagram-6RSMTGT7.BI6LgKSy.js} +1 -1
  152. package/web/_astro/{gitGraphDiagram-PVQCEYII.4tYvJKGR.js → gitGraphDiagram-PVQCEYII.npPZiC2G.js} +1 -1
  153. package/web/_astro/index.DayyIngm.css +1 -0
  154. package/web/_astro/{infoDiagram-5YYISTIA.Bd9rXpsB.js → infoDiagram-5YYISTIA.DCJCBVbp.js} +1 -1
  155. package/web/_astro/{ishikawaDiagram-YF4QCWOH.CvMoaf67.js → ishikawaDiagram-YF4QCWOH.BMLV-3I1.js} +1 -1
  156. package/web/_astro/{journeyDiagram-JHISSGLW.Ccy1CA7y.js → journeyDiagram-JHISSGLW.LE58crde.js} +1 -1
  157. package/web/_astro/{kanban-definition-UN3LZRKU.0MaMqHNS.js → kanban-definition-UN3LZRKU.BPbz8rH9.js} +1 -1
  158. package/web/_astro/{linear.CHXgcIbN.js → linear.DhZaBtYh.js} +1 -1
  159. package/web/_astro/{mermaid.core.Ca-kcelG.js → mermaid.core.BD5-jXum.js} +6 -6
  160. package/web/_astro/{mindmap-definition-RKZ34NQL.BUIDlHa0.js → mindmap-definition-RKZ34NQL.MTJyrQ65.js} +1 -1
  161. package/web/_astro/ordinal.BYWQX77i.js +1 -0
  162. package/web/_astro/{pieDiagram-4H26LBE5.2dX3CU1s.js → pieDiagram-4H26LBE5.BrDhDvIS.js} +1 -1
  163. package/web/_astro/{quadrantDiagram-W4KKPZXB.B3LBlRiv.js → quadrantDiagram-W4KKPZXB.71d73_5N.js} +1 -1
  164. package/web/_astro/{requirementDiagram-4Y6WPE33.X12I2uNx.js → requirementDiagram-4Y6WPE33.Bga6UF-z.js} +1 -1
  165. package/web/_astro/{sankeyDiagram-5OEKKPKP.BXohIHqx.js → sankeyDiagram-5OEKKPKP.BnHs4K82.js} +1 -1
  166. package/web/_astro/{sequenceDiagram-3UESZ5HK.C37ZIUzg.js → sequenceDiagram-3UESZ5HK.DsfY2gnj.js} +1 -1
  167. package/web/_astro/{stateDiagram-AJRCARHV.BRgz317z.js → stateDiagram-AJRCARHV.DvsTSc9a.js} +1 -1
  168. package/web/_astro/{stateDiagram-v2-BHNVJYJU.7VYSXN9-.js → stateDiagram-v2-BHNVJYJU.DxzzmHUR.js} +1 -1
  169. package/web/_astro/{timeline-definition-PNZ67QCA.BVNz_HiN.js → timeline-definition-PNZ67QCA.4ZuQmOTt.js} +1 -1
  170. package/web/_astro/{vennDiagram-CIIHVFJN.CHVDkPX4.js → vennDiagram-CIIHVFJN.Ck5Q86SG.js} +1 -1
  171. package/web/_astro/{wardleyDiagram-YWT4CUSO.EQQ_qT9v.js → wardleyDiagram-YWT4CUSO.BK7k2hXr.js} +1 -1
  172. package/web/_astro/{xychartDiagram-2RQKCTM6.DrAT9WoP.js → xychartDiagram-2RQKCTM6.DfCrgauK.js} +1 -1
  173. package/web/index.html +2 -2
  174. package/web/_astro/BoardApp.DV9kx0wo.js +0 -1
  175. package/web/_astro/channel.BAI6xLeV.js +0 -1
  176. package/web/_astro/index.Dcr_8fiK.css +0 -1
  177. package/web/_astro/ordinal.DBvzRdQf.js +0 -1
@@ -60,18 +60,10 @@ states:
60
60
  onEnter:
61
61
  - kind: shell
62
62
  options:
63
+ # (e) 0825: 8 lines — task check + show capture the investigate input bundle in the
64
+ # same soft probe; show must stay verbatim (it IS the bundle downstream reads).
63
65
  command: >-
64
- mkdir -p .spur/run &&
65
- set +e &&
66
- $spurBin task check $wbs; check_rc=$?;
67
- $spurBin task show $wbs --json > .spur/run/$__runId-wayfinder-input.json; show_rc=$?;
68
- set -e &&
69
- if [ "$check_rc" -eq 0 ] && [ "$show_rc" -eq 0 ]; then
70
- printf 'PASS\n' > .spur/run/$__runId-wayfinder-precheck.status;
71
- else
72
- printf 'FAIL\n' > .spur/run/$__runId-wayfinder-precheck.status;
73
- fi &&
74
- exit 0
66
+ mkdir -p .spur/run; $spurBin task check $wbs; c=$?; $spurBin task show $wbs --json > .spur/run/$__runId-wayfinder-input.json && [ "$c" -eq 0 ] && printf 'PASS\n' > .spur/run/$__runId-wayfinder-precheck.status || printf 'FAIL\n' > .spur/run/$__runId-wayfinder-precheck.status; exit 0
75
67
  - kind: note
76
68
  options:
77
69
  message: "Wayfinder resolution started for task ${vars.wbs} (mode=${vars.resolutionMode}, evidence=${vars.evidencePolicy}); no code implementation pipeline is permitted."
@@ -86,22 +78,10 @@ states:
86
78
  # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
87
79
  role: planner
88
80
  mode: text
81
+ # (e) 0825: bounded reference-reading prompt (260 chars) — the authoring contract
82
+ # lives in the skill reference sp:wayfinder references/pipeline-resolution.md.
89
83
  input: >-
90
- Resolve task ${vars.wbs} in resolution mode ${vars.resolutionMode} using the prepared
91
- local bundle `.spur/run/${vars.__runId}-wayfinder-input.json` and only local shell/file
92
- reads plus the `spur` CLI; do not use network search or MCP tools. Do not
93
- invoke task-pipeline.yaml, /sp:dev-run, /sp:dev-runall, or code implementation.
94
- Read the task file, map its existing Requirements and Acceptance Criteria to the
95
- existing Design/Plan/References, then author concise Solution, Testing, and Review
96
- sections through `spur task update --section --from-file`. Preserve the research
97
- boundary. Finish with a short summary and stop. Evidence policy: ${vars.evidencePolicy}.
98
-
99
- Evidence-anchor contract (mandatory — 0299 R1 line-anchor rule): when the task's
100
- evidence lives in a shared evidence file, anchor every Solution/Testing `file:line`
101
- citation truthfully — resolve the section's real start line with
102
- `grep -n "^## <wbs> " <evidence-file>` and cite that exact line. NEVER copy a line
103
- number from another ticket's example; each WBS anchors to its own section. Before
104
- finishing, re-read each cited line and confirm it names the requirement's subject.
84
+ Resolve wayfinder task ${vars.wbs} per the sp:wayfinder skill (references/pipeline-resolution.md). Mode ${vars.resolutionMode}; evidence policy ${vars.evidencePolicy}; bundle .spur/run/${vars.__runId}-wayfinder-input.json. Finish with a short summary and stop.
105
85
  answerFile: .spur/run/${vars.__runId}-wayfinder-answer.md
106
86
  expectFile: .spur/run/${vars.__runId}-wayfinder-answer.md
107
87
  timeoutMs: ${vars.stepTimeoutMs}
@@ -121,6 +101,8 @@ states:
121
101
  # proof digest via taskFile; a silent miss would degrade the proof to tree-only.
122
102
  - kind: shell
123
103
  options:
104
+ # (e) 0825: 6 lines — fail-closed lookup feeds every downstream artifact name;
105
+ # folding a silent miss into the digest would fake tree coverage.
124
106
  command: >-
125
107
  set -e;
126
108
  task_path="$($spurBin task path $wbs --json | jq -r '.path // .filePath // empty')";
@@ -155,6 +137,8 @@ states:
155
137
  command: "$spurBin task verdict $wbs --from-answer .spur/run/$__runId-wayfinder-verify-answer.txt"
156
138
  - kind: shell
157
139
  options:
140
+ # (e) 0825: 6 lines — stamp shell freezes the proof digest + capture point into the
141
+ # verdict before it is registered; the closing guard compares against this stamp.
158
142
  command: >-
159
143
  V=".spur/run/$wbs-verdict.json";
160
144
  if [ -f "$V" ] && [ -n "$proofDigest" ]; then
@@ -246,6 +230,8 @@ transitions:
246
230
  guard:
247
231
  kind: shell
248
232
  options:
233
+ # (e) 0825: 5-line guard — approval + digest-bracket + verdict PASS must all hold
234
+ # before record; dropping any operand would let a stale proof auto-record.
249
235
  command: >-
250
236
  test "$approval" = auto &&
251
237
  test -n "$proofDigest" &&
@@ -130,91 +130,36 @@ states:
130
130
  - kind: note
131
131
  options:
132
132
  message: "Resolving task list: ${vars.tasks} (proportional mode: ${vars.mode})"
133
- # 0770/0783 truthful input: parse and validate vars.tasks exactly once,
134
- # here and only here. Malformed JSON, a non-array, a non-string entry,
135
- # whitespace or a non-canonical WBS (anything but four digits), a missing
136
- # __runId, an unresolved task, a failed or malformed lookup, or a task
137
- # not at a completed status records FAIL (routed to `failed` by the first
138
- # declared edge) and is never re-interpreted as an empty list by a later
139
- # sibling guard. The normalized, deduplicated list is persisted
140
- # run-scoped; the route writer, metrics, prompts, notes and guards only
141
- # ever read that capture.
133
+ # (d) wrapup-steps.ts resolve owns task capture and status resolution (0824);
134
+ # the wrapper only locates it (monorepo first, registered twin under node) and
135
+ # fails closed, writing FAIL for the failed defense edge — never PASS.
142
136
  - kind: shell
143
137
  options:
144
138
  command: >-
145
139
  mkdir -p .spur/run &&
146
- RUN_ID="$__runId" &&
147
- if [ -z "$RUN_ID" ]; then
148
- echo "task-resolve: __runId is empty — refusing the legacy fixed-path fallback" >&2;
149
- exit 1;
150
- fi &&
151
- REASON_FILE=".spur/run/$RUN_ID-route-reason.txt" &&
152
- STATUS_FILE=".spur/run/$RUN_ID-wrapup-resolve.status" &&
153
- TASKS_FILE=".spur/run/$RUN_ID-wrapup-tasks.json" &&
154
- if ! printf '%s' "$tasks" | jq -e 'type == "array" and all(.[]; type == "string" and test("^[0-9]{4}$"))' > /dev/null 2>&1; then
155
- echo "task-resolve: tasks must be a JSON array of canonical four-digit WBS strings (whitespace is rejected, not trimmed)" >&2;
156
- echo "failed:tasks is not a JSON array of canonical four-digit WBS strings" > "$REASON_FILE";
157
- printf 'FAIL\n' > "$STATUS_FILE";
140
+ if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
141
+ bun plugins/sp/scripts/wrapup-steps.ts resolve;
142
+ elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
143
+ node "$W" resolve;
158
144
  else
159
- printf '%s' "$tasks" | jq -c 'reduce .[] as $w ([]; if any(.[]; . == $w) then . else . + [$w] end)' > "$TASKS_FILE";
160
- RESOLVE_RC=0;
161
- for wbs in $(jq -r '.[]' "$TASKS_FILE"); do
162
- TASK_JSON=$($spurBin task show "$wbs" --json 2>/dev/null || true);
163
- TASK_STATUS=$(printf '%s' "$TASK_JSON" | jq -r '.frontmatter.status // .status // empty' 2>/dev/null || true);
164
- if [ "$TASK_STATUS" != "done" ] && [ "$TASK_STATUS" != "cancelled" ]; then
165
- STATUS_DISPLAY="$TASK_STATUS";
166
- if [ -z "$STATUS_DISPLAY" ]; then STATUS_DISPLAY=unresolved; fi;
167
- echo "task-resolve: task $wbs did not resolve to a completed status (status=$STATUS_DISPLAY)" >&2;
168
- RESOLVE_RC=1;
169
- fi;
170
- done;
171
- if [ "$RESOLVE_RC" -eq 0 ]; then
172
- printf 'PASS\n' > "$STATUS_FILE";
173
- else
174
- echo "failed:unresolved or non-completed task (see $TASKS_FILE)" > "$REASON_FILE";
175
- printf 'FAIL\n' > "$STATUS_FILE";
176
- fi;
177
- fi;
178
- exit 0
179
- # Route reason writer (0758 R3/R4 run-attribution pins intact). Runs AFTER
180
- # validation and reads ONLY the validated run-scoped capture — never raw
181
- # vars.tasks (0783 R2/R5); the fixed-path fallback is gone because
182
- # validation refuses an empty __runId above. A FAIL resolve exits without
183
- # writing: the failed reason written by validation stands, and the skip
184
- # reason can never mask it. A missing/corrupted capture yields N=-1 and
185
- # no skipped claim; the failed defense edge owns the run.
145
+ echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
146
+ printf 'FAIL\n' > ".spur/run/$__runId-wrapup-resolve.status";
147
+ fi
148
+ # (e) route-reason writer: one jq table lookup over the mode var over the
149
+ # validated capture; workflow-local routing glue (0824). Runs AFTER validation
150
+ # and reads ONLY .spur/run/<runId>-wrapup-tasks.json — never raw vars.tasks
151
+ # (0783 R2/R5). A FAIL resolve exits without writing: the failed reason written
152
+ # by validation stands, and the skip reason can never mask it. A missing or
153
+ # corrupted capture fails the jq lookup (no skipped claim can be invented);
154
+ # the failed defense edge owns the run.
186
155
  - kind: shell
187
156
  options:
188
157
  command: >-
189
- mkdir -p .spur/run .spur/memory &&
190
- RUN_ID="$__runId" &&
191
- if [ -z "$RUN_ID" ]; then
192
- echo "task-resolve: __runId is empty — refusing to write a route reason" >&2;
193
- exit 1;
194
- fi &&
195
- REASON_FILE=".spur/run/$RUN_ID-route-reason.txt" &&
196
- STATUS_FILE=".spur/run/$RUN_ID-wrapup-resolve.status" &&
197
- TASKS_FILE=".spur/run/$RUN_ID-wrapup-tasks.json" &&
198
- if [ "$(cat "$STATUS_FILE" 2>/dev/null)" = FAIL ]; then
199
- exit 0;
200
- fi &&
201
- N=$(jq length "$TASKS_FILE" 2>/dev/null || echo -1) &&
202
- if [ "$N" -eq 0 ]; then
203
- echo "skipped:empty task list" > "$REASON_FILE";
204
- elif [ "$mode" = "fast" ]; then
205
- echo "fast:evidence complete+consistent" > "$REASON_FILE";
206
- elif [ -z "$mode" ]; then
207
- echo "safety:missing evidence (mode empty)" > "$REASON_FILE";
208
- elif [ "$mode" = "unknown" ]; then
209
- echo "safety:unknown evidence quality" > "$REASON_FILE";
210
- elif [ "$mode" = "conflict" ]; then
211
- echo "safety:conflicting evidence" > "$REASON_FILE";
212
- else
213
- echo "safety:unrecognized evidence (mode=$mode)" > "$REASON_FILE";
214
- fi &&
215
- printf '%s %s\n' "$RUN_ID" "$(cat "$REASON_FILE")"
216
- >> .spur/memory/wrapup-routes.log &&
217
- exit 0
158
+ mkdir -p .spur/run .spur/memory; RUN_ID="$__runId"; case "$RUN_ID" in '') echo "task-resolve: __runId is empty — refusing to write a route reason" >&2; exit 1 ;; esac;
159
+ REASON_FILE=".spur/run/$RUN_ID-route-reason.txt"; case "$(cat ".spur/run/$RUN_ID-wrapup-resolve.status" 2>/dev/null)" in FAIL) exit 0 ;; esac;
160
+ N=$(jq length ".spur/run/$RUN_ID-wrapup-tasks.json" 2>/dev/null);
161
+ jq -rn --arg m "$mode" --arg n "$N" 'if $n == "0" then "skipped:empty task list" else {"fast":"fast:evidence complete+consistent","":"safety:missing evidence (mode empty)","unknown":"safety:unknown evidence quality","conflict":"safety:conflicting evidence"}[$m] // "safety:unrecognized evidence (mode=\($m))" end' > "$REASON_FILE";
162
+ printf '%s %s\n' "$RUN_ID" "$(cat "$REASON_FILE")" >> .spur/memory/wrapup-routes.log
218
163
 
219
164
  - id: doc-sync
220
165
  description: >
@@ -227,6 +172,8 @@ states:
227
172
  a non-empty capture before the append; append is best-effort soft (empty capture
228
173
  skips without aborting wrap-up).
229
174
  onEnter:
175
+ # (warn) free-form prompt: no /sp:doc-evolve command surface yet (ADR-043
176
+ # residual, 0607 R2 one-query merge); capture is bounded by expectFile.
230
177
  - kind: agent.run
231
178
  options:
232
179
  agent: ${vars.agent}
@@ -245,6 +192,8 @@ states:
245
192
  answerFile: .spur/run/${vars.__runId}-wrapup-learnings.md
246
193
  expectFile: .spur/run/${vars.__runId}-wrapup-learnings.md
247
194
  timeoutMs: ${vars.stepTimeoutMs}
195
+ # (warn) learnings append is intentionally soft (empty capture skips
196
+ # without aborting wrap-up, 0607 R2).
248
197
  - kind: shell
249
198
  options:
250
199
  command: >-
@@ -270,40 +219,20 @@ states:
270
219
  is UNKNOWN telemetry, never proof of completion; previously written valid rows
271
220
  survive a failure.
272
221
  onEnter:
222
+ # (d) wrapup-steps.ts metrics owns the JSONL row append (0824); the wrapper
223
+ # only locates it and fails closed — FAIL, never a silent skip.
273
224
  - kind: shell
274
225
  options:
275
226
  command: >-
276
- mkdir -p .spur/run .spur/memory &&
277
- STATUS_FILE=".spur/run/$__runId-wrapup-metrics.status" &&
278
- TASKS_FILE=".spur/run/$__runId-wrapup-tasks.json" &&
279
- METRICS_RC=0 &&
280
- if ! jq -e 'type == "array" and all(.[]; type == "string" and test("^[0-9]{4}$"))' "$TASKS_FILE" > /dev/null 2>&1; then
281
- echo "metrics-record: run-scoped task capture missing, corrupted or non-canonical — refusing to record metrics" >&2;
282
- printf 'FAIL\n' > "$STATUS_FILE";
227
+ mkdir -p .spur/run &&
228
+ if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
229
+ bun plugins/sp/scripts/wrapup-steps.ts metrics;
230
+ elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
231
+ node "$W" metrics;
283
232
  else
284
- for wbs in $(jq -r '.[]' "$TASKS_FILE"); do
285
- task_json=$($spurBin task show "$wbs" --json 2>/dev/null || true);
286
- if printf '%s' "$task_json" | jq -e '(.frontmatter.status // .status) != null' > /dev/null 2>&1; then
287
- feat=$(printf '%s' "$task_json" | jq -r '.frontmatter.feature_id // .feature_id // ""');
288
- stat=$(printf '%s' "$task_json" | jq -r '.frontmatter.status // .status // "unknown"');
289
- verdict="UNKNOWN";
290
- if [ -f ".spur/run/$wbs-verdict.json" ]; then
291
- v=$(jq -r '.verdict // "UNKNOWN"' ".spur/run/$wbs-verdict.json" 2>/dev/null || true);
292
- if [ -n "$v" ]; then verdict="$v"; fi;
293
- fi;
294
- ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ");
295
- if ! jq -cn --arg wbs "$wbs" --arg feature_id "$feat" --arg status "$stat" --arg verdict "$verdict" --arg timestamp "$ts" '{wbs:$wbs, feature_id:$feature_id, status:$status, verdict:$verdict, timestamp:$timestamp}' >> .spur/memory/wrapup-metrics.jsonl; then
296
- echo "metrics-record: metrics append failed for task $wbs — recording FAIL instead of claiming the row landed" >&2;
297
- METRICS_RC=1;
298
- fi;
299
- else
300
- echo "metrics-record: task $wbs lookup failed or was malformed — recording FAIL instead of silently omitting its metrics row" >&2;
301
- METRICS_RC=1;
302
- fi;
303
- done;
304
- if [ "$METRICS_RC" -eq 0 ]; then printf 'PASS\n' > "$STATUS_FILE"; else printf 'FAIL\n' > "$STATUS_FILE"; fi;
305
- fi;
306
- exit 0
233
+ echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
234
+ printf 'FAIL\n' > ".spur/run/$__runId-wrapup-metrics.status";
235
+ fi
307
236
 
308
237
  - id: feature-transition
309
238
  description: >
@@ -320,94 +249,24 @@ states:
320
249
  (the engine only enters this state when vars.feature is set) and fails
321
250
  loud (dogfood 2026-08-15, feature I3).
322
251
  onEnter:
323
- # The terminating `exit 0` must be reached on every branch — the sync is
324
- # chained with `;`, because `&&` would abort the state, discarding the
325
- # learnings/metrics that already landed. Soft TERMINATION is not soft
326
- # TRUTH: the result is classified per 0783 R4 and only a verified sync
327
- # writes PASS. `feature-sync-bounded.ts` is a Spur-monorepo path (`spur
328
- # init` does not scaffold `plugins/sp/`), so seeded projects fall back to
329
- # the plain `spur feature sync` verb.
330
- # R1 (0625): a feature transition that changed state may have left
331
- # cross-task fallout the per-task fast gates never see. The
332
- # affected-feature gate (featureGateCmd) runs after an applied sync OR a
333
- # non-zero exit that may follow a partial multi-hop transition. It is a
334
- # diagnostic only: a gate PASS can never convert a failed sync into
335
- # success, and a gate FAIL fails the step (0770 failure routing).
336
- # NOTE: do not add
337
- # `#` comments INSIDE the folded shell string — YAML `>-` folds them onto
338
- # the following statement line and comments it out.
252
+ # (d) wrapup-steps.ts feature-transition owns the bounded sync, observation
253
+ # and the gate (0824); the wrapper only locates it and fails closed. The
254
+ # script terminates exit 0 on every path so artifacts that already landed
255
+ # are never discarded; soft TERMINATION is not soft TRUTH — only a verified
256
+ # sync writes PASS (0783 R4). A gate PASS can never convert a failed sync
257
+ # into success, and a gate FAIL fails the step (0770 failure routing).
339
258
  - kind: shell
340
259
  options:
341
260
  command: >-
342
261
  mkdir -p .spur/run &&
343
- if [ -z "$feature" ]; then
344
- echo "feature-transition: vars.feature is empty — refusing no-op feature sync (mis-invocation, not a blocked sync)" >&2;
345
- exit 1;
346
- fi;
347
- SYNC_OUTPUT=$(if [ -f plugins/sp/scripts/feature-sync-bounded.ts ]; then
348
- bun plugins/sp/scripts/feature-sync-bounded.ts "$feature" --spur-bin "$spurBin" --json;
349
- elif SYNC_MJS="$(superskill script path sp feature-sync-bounded.mjs 2>/dev/null)" && [ -f "$SYNC_MJS" ]; then
350
- node "$SYNC_MJS" "$feature" --spur-bin "$spurBin" --json;
351
- else
352
- $spurBin feature sync "$feature" --json;
353
- fi);
354
- SYNC_RC=$?;
355
- printf '%s\n' "$SYNC_OUTPUT";
356
- OBSERVED=$($spurBin feature show "$feature" --json 2>/dev/null | jq -r '.status // .frontmatter.status // empty' 2>/dev/null || true);
357
- if [ -z "$OBSERVED" ]; then OBSERVED=unreadable; fi;
358
- APPLIED=unreadable;
359
- SYNC_OK=0;
360
- REASON="";
361
- if [ "$SYNC_RC" -ne 0 ]; then
362
- REASON="sync exited nonzero (rc=$SYNC_RC)";
363
- elif ! printf '%s' "$SYNC_OUTPUT" | jq -e 'type == "object" and (.proposal | type == "object") and (.proposal.featureId | type == "string") and (.proposal.from | type == "string") and (.proposal.to | type == "string") and (.applied | type == "boolean")' > /dev/null 2>&1; then
364
- REASON="malformed or unreadable sync result";
365
- else
366
- P_FROM=$(printf '%s' "$SYNC_OUTPUT" | jq -r '.proposal.from // ""');
367
- P_TO=$(printf '%s' "$SYNC_OUTPUT" | jq -r '.proposal.to // ""');
368
- APPLIED=$(printf '%s' "$SYNC_OUTPUT" | jq -r '.applied');
369
- if [ "$(printf '%s' "$SYNC_OUTPUT" | jq -r '.proposal.featureId // ""')" != "$feature" ]; then
370
- REASON="sync proposal does not match feature $feature";
371
- elif [ "$(printf '%s' "$SYNC_OUTPUT" | jq -r '.proposal.gateBlocked // false')" = "true" ]; then
372
- REASON="sync proposal is gate-blocked — a blocked sync is not a no-change success";
373
- elif [ "$(printf '%s' "$SYNC_OUTPUT" | jq -r '.proposal.requiresConfirm // false')" = "true" ]; then
374
- REASON="sync proposal requires operator confirmation";
375
- elif [ "$APPLIED" = "true" ] && [ "$OBSERVED" != "$P_TO" ]; then
376
- REASON="applied sync did not land on the proposal target (observed=$OBSERVED, to=$P_TO)";
377
- elif [ "$APPLIED" = "false" ] && { [ "$P_FROM" != "$P_TO" ] || [ "$OBSERVED" != "$P_TO" ]; }; then
378
- REASON="sync applied nothing without a from==to observed no-op (from=$P_FROM, to=$P_TO, observed=$OBSERVED)";
379
- else
380
- SYNC_OK=1;
381
- fi;
382
- fi;
383
- GATE="skipped";
384
- if [ "$APPLIED" = "true" ] || [ "$SYNC_RC" -ne 0 ]; then
385
- echo "feature-transition: sync applied or failed after a possible partial transition for $feature — running feature gate: $featureGateCmd";
386
- if sh -c "$featureGateCmd"; then
387
- GATE="PASS";
388
- echo "feature-transition: feature gate PASS for feature $feature";
389
- else
390
- GATE="FAIL";
391
- echo "feature-transition: feature gate FAIL for feature $feature — inspect findings before reporting the transition complete" >&2;
392
- fi;
393
- else
394
- echo "feature-transition: sync did not apply a transition (rc=$SYNC_RC, applied=$APPLIED) — feature gate skipped";
395
- fi;
396
- SYNC_STATUS="PASS";
397
- if [ "$SYNC_OK" -ne 1 ] || [ "$GATE" = "FAIL" ]; then
398
- SYNC_STATUS="FAIL";
399
- echo "feature-transition: required synchronization failed for $feature — $REASON; gate=$GATE" >&2;
400
- elif [ "$APPLIED" = "false" ]; then
401
- echo "feature-transition: feature sync verified for $feature (from==to observed at $OBSERVED, gate=$GATE) — explicit no-change";
402
- else
403
- echo "feature-transition: feature sync verified for $feature (applied, observed=$OBSERVED, gate=$GATE)";
404
- fi;
405
- if [ "$SYNC_STATUS" = "PASS" ]; then
406
- printf 'PASS\n' > ".spur/run/$__runId-wrapup-sync.status";
262
+ if [ -f plugins/sp/scripts/wrapup-steps.ts ]; then
263
+ bun plugins/sp/scripts/wrapup-steps.ts feature-transition;
264
+ elif W="$(superskill script path sp wrapup-steps.mjs 2>/dev/null)" && [ -f "$W" ]; then
265
+ node "$W" feature-transition;
407
266
  else
267
+ echo "wrapup-steps failed closed — script not found — run 'superskill install sp'" >&2;
408
268
  printf 'FAIL\n' > ".spur/run/$__runId-wrapup-sync.status";
409
- fi;
410
- exit 0
269
+ fi
411
270
 
412
271
  - id: branch-cleanup
413
272
  description: >
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/spur",
3
- "version": "0.3.78",
3
+ "version": "0.3.81",
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",
@@ -53,14 +53,14 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@commander-js/extra-typings": "^14.0.0",
56
- "@gobing-ai/ts-db": "^0.4.60",
57
- "@gobing-ai/ts-ai-runner": "^0.4.60",
58
- "@gobing-ai/ts-dual-workflow-engine": "^0.4.60",
59
- "@gobing-ai/ts-infra": "^0.4.60",
60
- "@gobing-ai/ts-llm-jsonl-importer": "^0.4.60",
61
- "@gobing-ai/ts-rule-engine": "^0.4.60",
62
- "@gobing-ai/ts-runtime": "^0.4.60",
63
- "@gobing-ai/ts-utils": "^0.4.60",
56
+ "@gobing-ai/ts-db": "^0.4.66",
57
+ "@gobing-ai/ts-ai-runner": "^0.4.66",
58
+ "@gobing-ai/ts-dual-workflow-engine": "^0.4.66",
59
+ "@gobing-ai/ts-infra": "^0.4.66",
60
+ "@gobing-ai/ts-llm-jsonl-importer": "^0.4.66",
61
+ "@gobing-ai/ts-rule-engine": "^0.4.66",
62
+ "@gobing-ai/ts-runtime": "^0.4.66",
63
+ "@gobing-ai/ts-utils": "^0.4.66",
64
64
  "@types/bun": "1.3.14",
65
65
  "@types/figlet": "^1.7.0",
66
66
  "@types/node-notifier": "8.0.5",
@@ -171,10 +171,12 @@ Commands above are thin wrappers; the actual logic lives in `skills/`. The spine
171
171
  dispatches five competency skills by function — design (`sp:sys-architecture`), decomposition
172
172
  (`sp:spec-decomposition`), implementation (`sp:code-implementation`), testing (`sp:code-testing`),
173
173
  and verification (`sp:code-verification`) — plus a CLI facade (`sp:spur-cli`, one reference per
174
- `spur` noun) and standalone technique skills (`sp:next-router`, `sp:test-driven-development`, `sp:brainstorm`,
175
- `sp:wayfinder`, `sp:sys-debugging`, `sp:code-review`, `sp:code-simplification`, `sp:code-improvement`,
176
- `sp:parallel-execution`, `sp:branch-workflow`, `sp:doc-evolve`, `sp:dogfood-testing`,
177
- `sp:daily-summary`, `sp:reverse-engineering`, `sp:issue-finding`, `sp:conflict-finding`,
174
+ `spur` noun) and standalone technique skills (`sp:next-router`, `sp:next-feature`,
175
+ `sp:test-driven-development`, `sp:source-driven-development`, `sp:doubt-driven-development`,
176
+ `sp:brainstorm`, `sp:wayfinder`, `sp:sys-debugging`, `sp:code-review`, `sp:pr-reviewing`,
177
+ `sp:functional-review`, `sp:code-simplification`, `sp:code-improvement`, `sp:parallel-execution`,
178
+ `sp:branch-workflow`, `sp:doc-evolve`, `sp:dogfood-testing`, `sp:daily-summary`,
179
+ `sp:reverse-engineering`, `sp:history-anatomy`, `sp:issue-finding`, `sp:conflict-finding`,
178
180
  `sp:indexed-context`, `sp:session-review`, `sp:redesign-web-ui`). See
179
181
  [skills/spur-dev/SKILL.md](skills/spur-dev/SKILL.md)'s Step routing table for which skill owns which
180
182
  pipeline step.
@@ -183,7 +185,7 @@ pipeline step.
183
185
 
184
186
  ```
185
187
  plugins/sp/
186
- ├── skills/ # Domain knowledge + workflow docs (32 skills)
188
+ ├── skills/ # Domain knowledge + workflow docs (34 skills)
187
189
  │ ├── brainstorm/ # Structured ideation workflow
188
190
  │ │ ├── agents/openai.yaml
189
191
  │ │ ├── examples/ideation-example.md
@@ -215,6 +217,7 @@ plugins/sp/
215
217
  │ │ └── references/routing-table.md
216
218
  │ ├── parallel-execution/ # Fan-out decision framework + patterns
217
219
  │ │ └── references/{fan-out-patterns, result-synthesis}.md
220
+ │ ├── pr-reviewing/ # GitHub PR review loop backing /sp:dev-pr-review
218
221
  │ ├── source-driven-development/ # Source-first API/contract verification (SKILL.md only)
219
222
  │ ├── spec-decomposition/ # Feature/spec → task-batch competency
220
223
  │ │ └── references/decomposition.md
@@ -224,6 +227,8 @@ plugins/sp/
224
227
  │ │ ├── features.md + features/{verbs, acceptance-criteria, roadmap-priority}.md
225
228
  │ │ ├── rules.md + rules/{operations, authoring-rules, fine-tuning, validation-and-extension}.md
226
229
  │ │ └── workflows.md + workflows/{operations, authoring-workflows, validation-and-extension}.md
230
+ │ ├── spur-composer/ # Cross-noun selection, composition ladder, rule tuning; applies doctor proposals
231
+ │ ├── spur-doctor/ # Read-only artifact evaluation → proposal table (backs spur-composer)
227
232
  │ ├── spur-dev/ # Thin planning→execution orchestration spine
228
233
  │ │ └── references/ # ac-style-guide, cross-cutting, decision-brief, dev-operations,
229
234
  │ │ execution-batch, execution-workflow, feature-link-helper,
@@ -255,6 +260,8 @@ plugins/sp/
255
260
  ├── agents/ # 4 specialist subagents (expert-spur, super-coder, super-planner, super-reviewer)
256
261
  ├── hooks/ # hooks.json + task-write-guard.{ts,test.ts} + context-{session-start,post-tool,session-stop}.ts
257
262
  │ # + careful-guard.{ts,test.ts} + context-hooks.test.ts + token-estimate.test.ts
263
+ │ # + shared policy modules: agent-hint.ts, destructive-policy.{ts,test.ts}, task-file-policy.{ts,test.ts}
264
+ │ # + pi/guard-extension.{ts,test.ts} (plugin.json `extensions.pi` entry point)
258
265
  ├── scripts/ # Executable helpers, split from prompts (ADR-031) — validate-commands.ts (thin-wrapper validator), batch-preflight.ts + scripts/<skill>/
259
266
  │ # (daily-summary: {daily-summary, logger}.ts; dogfood-testing: {detect-pipeline-driving, validate-report}.ts)
260
267
  ├── tests/ # Plugin tests — command-contract.test.ts + skill-structure.test.ts + batch-preflight.test.ts + per-skill suites
@@ -318,14 +325,20 @@ surface or run one workflow. All skills target the same five core platforms: `cl
318
325
  | `daily-summary` | 1.0.0 | Daily summary report generator — orchestrates ccusage CLI + git history into structured markdown summaries |
319
326
  | `doc-evolve` | 1.0 | Key-document evolution per `docs/99_PROJECT_CONSTITUTION.md` — drift audits, same-commit sync checks, frontmatter-contract verification, machine-appended lessons |
320
327
  | `reverse-engineering` | 1.1 | Codebase analysis / HLD generation / audit — depth-driven reverse engineering with orthogonal mode, focus, and format controls; backs `/sp:dev-reverse` |
321
- | `issue-finding` | 1.1 | Session-log forensics — multi-source discovery, bottleneck ranking, optional topic focus, CLI-gated fix task generation; **legacy path** — superseded by `history-anatomy` for indexed reporting; backs no current command; directly invocable as sp:issue-finding |
328
+ | `issue-finding` | 2.0 | Session-log forensics — multi-source discovery, bottleneck ranking, optional topic focus, CLI-gated fix task generation; **legacy path** — superseded by `history-anatomy` for indexed reporting; backs no current command; directly invocable as sp:issue-finding |
322
329
  | `conflict-finding` | 1.0 | Authority-aware semantic audit — four-pillar (source/task/feature/authority) conflict discovery, claim-specific authority resolution, reproducible evidence, confirmed owner-routed remediation; backs `/sp:dev-find-conflict` |
323
330
  | `next-feature` | 1.0 | Prompt-first feature frontier prioritizer — sync-first precondition, B3 actionability gate (cited, never restated), tiered rubric over measured signals, D1–D4 defect proposals conforming to the restructure map schema; backs `/sp:dev-find-next` |
324
331
  | `pr-reviewing` | 1.0 | GitHub Codex PR review — PR prepare/reuse, `@codex review` request with per-HEAD dedupe, bounded polling, findings normalization, validated fix + re-review; spine SSOT `pr-review.yaml` + `scripts/pr-reviewing.ts`; backs `/sp:dev-pr-review` |
325
332
  | `indexed-context` | 1.0 | Cross-agent project context — anatomy/learnings/pitfalls/buglog/memory in `.spur/context/`; hook-tracked token-ledger; graceful degradation on agents without hooks |
326
333
  | `history-anatomy` | 1.0 | Diagnostic interpretation owner over already-imported history — daily/ad-hoc mode contract, closed finding taxonomy, twelve-section report contract, `enrich`/`validate` rubrics; no workflow launch, no JSONL fallback, no corpus mutation |
327
- | `session-review` | 1.0 | Inline review of the active coding-agent session — compact outcomes, evidence-backed resolved/open issue classification, proposal-only improvements, and next actions; no workflow, import, delegation, or mutation |
334
+ | `session-review` | 1.1 | Inline review of the active coding-agent session — compact outcomes, evidence-backed resolved/open issue classification, proposal-only improvements, and next actions; no workflow, import, delegation, or mutation |
335
+ | `spur-composer` | 1.0 | Cross-noun composition — workflow catalog selection, the ephemeral→project→shared ladder, ADR-115 budgets, trace-driven rule tuning; applies accepted `spur-doctor` proposals through `spur` verbs; never judges its own output and never runs a recurring loop |
336
+ | `spur-doctor` | 1.0 | Cross-noun evaluation — read-only CLI evidence per noun (task/feature/rule/workflow/agent spec), reflection over `history-anatomy` findings through a closed action-class map, and a proposal table; writes nothing; diagnoses artifacts, not runtime environments (`spur agent doctor`'s job) |
328
337
  | `redesign-web-ui` | 1.0 | Existing-UI visual upgrade — audit generic AI fingerprints, apply in-stack polish against `DESIGN.md` / live tokens, verify behavior and viewports; does not migrate frameworks |
338
+ | `taste-refactoring-api` | — | API design and refactoring for REST/HTTP, RPC/gRPC, GraphQL, and event contracts; compatibility, security, and migration review |
339
+ | `taste-refactoring-ui` | — | UI design and refactoring with visual hierarchy, typography, spacing, color, and interaction review |
340
+ | `taste-refactoring-architect` | — | Architecture review, simplification, and refactoring; boundary modeling, dependency reduction, and migration planning |
341
+ | `taste-refactoring-tests` | — | Test suite refactoring for failure sensitivity, regression detection, and assertion strength; eliminates brittle mocks |
329
342
 
330
343
  #### Bounded coexistence and retirement gate — `sp:issue-finding` (HA-S1 0661)
331
344
 
@@ -418,7 +431,7 @@ the pipeline's Phase 7 review step.
418
431
  | ---------------- | ------------ | ----------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------- |
419
432
  | `expert-spur` | expert | `sp:spur-cli` | green | "create tasks", "feature lifecycle", "add a rule", "author a workflow" |
420
433
  | `super-coder` | builder | `sp:sys-architecture` + `sp:code-implementation` + `sp:code-testing` + `sp:sys-debugging` | blue | "implement this", "write the code", "fix this bug", "design the architecture" |
421
- | `super-planner` | orchestrator | `sp:spur-dev` + `sp:dogfood-testing` | green | "run this task end to end", "run all tasks", "run the batch", "runall" |
434
+ | `super-planner` | orchestrator | `sp:spur-dev` + `sp:parallel-execution` + `sp:dogfood-testing` + `sp:next-router` | green | "run this task end to end", "run all tasks", "run the batch", "runall" |
422
435
  | `super-reviewer` | reviewer | `sp:code-verification` + `sp:functional-review` + `sp:code-improvement` | crimson | "review this", "check the code", "SECUA review", "run task 0042 through review" |
423
436
 
424
437
  Each agent has:
@@ -483,6 +496,7 @@ hold `SKILL.md` and prompt-side companions only.
483
496
  | `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` |
484
497
  | `hooks/careful-guard.ts` | Opt-in destructive-command guard (unwired — see Hooks above) |
485
498
  | `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 |
499
+ | `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 |
486
500
  | `scripts/dogfood-testing/detect-pipeline-driving.ts` | Word-boundary detector for pipeline-driving testees (leading-space invariant) |
487
501
  | `scripts/dogfood-testing/validate-report.ts` | Pure `validateReport(md)` — footer-mandatory + 7-check finalize-or-abort contract with stable error codes |
488
502
  | `scripts/daily-summary/{daily-summary,logger}.ts` | ccusage + git-history orchestration helpers for `sp:daily-summary` |