@specship/specship-win32-arm64 0.25.0 → 0.29.0

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 (305) hide show
  1. package/bin/specship.cmd +31 -1
  2. package/lib/dist/activation/cheatsheet.d.ts +17 -1
  3. package/lib/dist/activation/cheatsheet.d.ts.map +1 -1
  4. package/lib/dist/activation/cheatsheet.js +47 -3
  5. package/lib/dist/activation/cheatsheet.js.map +1 -1
  6. package/lib/dist/activation/hook-output.d.ts +80 -0
  7. package/lib/dist/activation/hook-output.d.ts.map +1 -0
  8. package/lib/dist/activation/hook-output.js +103 -0
  9. package/lib/dist/activation/hook-output.js.map +1 -0
  10. package/lib/dist/activation/search-intercept.d.ts +60 -29
  11. package/lib/dist/activation/search-intercept.d.ts.map +1 -1
  12. package/lib/dist/activation/search-intercept.js +159 -55
  13. package/lib/dist/activation/search-intercept.js.map +1 -1
  14. package/lib/dist/activation/steering.d.ts +8 -10
  15. package/lib/dist/activation/steering.d.ts.map +1 -1
  16. package/lib/dist/activation/steering.js +21 -6
  17. package/lib/dist/activation/steering.js.map +1 -1
  18. package/lib/dist/behaviour/behaviour-surface.d.ts +47 -0
  19. package/lib/dist/behaviour/behaviour-surface.d.ts.map +1 -1
  20. package/lib/dist/behaviour/behaviour-surface.js +108 -2
  21. package/lib/dist/behaviour/behaviour-surface.js.map +1 -1
  22. package/lib/dist/bin/node-version-check.d.ts +22 -7
  23. package/lib/dist/bin/node-version-check.d.ts.map +1 -1
  24. package/lib/dist/bin/node-version-check.js +39 -9
  25. package/lib/dist/bin/node-version-check.js.map +1 -1
  26. package/lib/dist/bin/specship.js +799 -81
  27. package/lib/dist/bin/specship.js.map +1 -1
  28. package/lib/dist/commands/specship/learn.md +22 -0
  29. package/lib/dist/commands/specship/spec.md +19 -1
  30. package/lib/dist/db/sqlite-adapter.d.ts +7 -5
  31. package/lib/dist/db/sqlite-adapter.d.ts.map +1 -1
  32. package/lib/dist/db/sqlite-adapter.js +11 -9
  33. package/lib/dist/db/sqlite-adapter.js.map +1 -1
  34. package/lib/dist/design-md/check.d.ts +51 -0
  35. package/lib/dist/design-md/check.d.ts.map +1 -0
  36. package/lib/dist/design-md/check.js +335 -0
  37. package/lib/dist/design-md/check.js.map +1 -0
  38. package/lib/dist/design-md/css.d.ts +40 -0
  39. package/lib/dist/design-md/css.d.ts.map +1 -0
  40. package/lib/dist/design-md/css.js +224 -0
  41. package/lib/dist/design-md/css.js.map +1 -0
  42. package/lib/dist/design-md/extract.d.ts +84 -0
  43. package/lib/dist/design-md/extract.d.ts.map +1 -0
  44. package/lib/dist/design-md/extract.js +595 -0
  45. package/lib/dist/design-md/extract.js.map +1 -0
  46. package/lib/dist/design-md/maintain.d.ts +45 -0
  47. package/lib/dist/design-md/maintain.d.ts.map +1 -0
  48. package/lib/dist/design-md/maintain.js +127 -0
  49. package/lib/dist/design-md/maintain.js.map +1 -0
  50. package/lib/dist/design-md/render.d.ts +28 -0
  51. package/lib/dist/design-md/render.d.ts.map +1 -0
  52. package/lib/dist/design-md/render.js +178 -0
  53. package/lib/dist/design-md/render.js.map +1 -0
  54. package/lib/dist/design-md/upkeep.d.ts +48 -0
  55. package/lib/dist/design-md/upkeep.d.ts.map +1 -0
  56. package/lib/dist/design-md/upkeep.js +169 -0
  57. package/lib/dist/design-md/upkeep.js.map +1 -0
  58. package/lib/dist/design-md/verify.d.ts +65 -0
  59. package/lib/dist/design-md/verify.d.ts.map +1 -0
  60. package/lib/dist/design-md/verify.js +311 -0
  61. package/lib/dist/design-md/verify.js.map +1 -0
  62. package/lib/dist/enforce/changed-files.d.ts +11 -0
  63. package/lib/dist/enforce/changed-files.d.ts.map +1 -1
  64. package/lib/dist/enforce/changed-files.js +42 -0
  65. package/lib/dist/enforce/changed-files.js.map +1 -1
  66. package/lib/dist/enforce/enforce.d.ts +25 -1
  67. package/lib/dist/enforce/enforce.d.ts.map +1 -1
  68. package/lib/dist/enforce/enforce.js +58 -3
  69. package/lib/dist/enforce/enforce.js.map +1 -1
  70. package/lib/dist/enforce/mutation.d.ts +46 -0
  71. package/lib/dist/enforce/mutation.d.ts.map +1 -0
  72. package/lib/dist/enforce/mutation.js +104 -0
  73. package/lib/dist/enforce/mutation.js.map +1 -0
  74. package/lib/dist/enforce/suppressions.d.ts +33 -0
  75. package/lib/dist/enforce/suppressions.d.ts.map +1 -0
  76. package/lib/dist/enforce/suppressions.js +159 -0
  77. package/lib/dist/enforce/suppressions.js.map +1 -0
  78. package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
  79. package/lib/dist/extraction/specs/markdown-spec-extractor.js +16 -2
  80. package/lib/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
  81. package/lib/dist/graph/spec-coverage.d.ts +57 -1
  82. package/lib/dist/graph/spec-coverage.d.ts.map +1 -1
  83. package/lib/dist/graph/spec-coverage.js +129 -5
  84. package/lib/dist/graph/spec-coverage.js.map +1 -1
  85. package/lib/dist/health/smoke-check.js +2 -2
  86. package/lib/dist/health/smoke-check.js.map +1 -1
  87. package/lib/dist/index.d.ts +8 -3
  88. package/lib/dist/index.d.ts.map +1 -1
  89. package/lib/dist/index.js +65 -9
  90. package/lib/dist/index.js.map +1 -1
  91. package/lib/dist/installer/gemini-commands.d.ts +107 -0
  92. package/lib/dist/installer/gemini-commands.d.ts.map +1 -0
  93. package/lib/dist/installer/gemini-commands.js +271 -0
  94. package/lib/dist/installer/gemini-commands.js.map +1 -0
  95. package/lib/dist/installer/index.d.ts +23 -1
  96. package/lib/dist/installer/index.d.ts.map +1 -1
  97. package/lib/dist/installer/index.js +22 -3
  98. package/lib/dist/installer/index.js.map +1 -1
  99. package/lib/dist/installer/install-defaults.d.ts +19 -0
  100. package/lib/dist/installer/install-defaults.d.ts.map +1 -1
  101. package/lib/dist/installer/install-defaults.js +28 -0
  102. package/lib/dist/installer/install-defaults.js.map +1 -1
  103. package/lib/dist/installer/instructions-template.d.ts +22 -0
  104. package/lib/dist/installer/instructions-template.d.ts.map +1 -1
  105. package/lib/dist/installer/instructions-template.js +37 -1
  106. package/lib/dist/installer/instructions-template.js.map +1 -1
  107. package/lib/dist/installer/targets/claude.d.ts +5 -1
  108. package/lib/dist/installer/targets/claude.d.ts.map +1 -1
  109. package/lib/dist/installer/targets/claude.js +15 -27
  110. package/lib/dist/installer/targets/claude.js.map +1 -1
  111. package/lib/dist/installer/targets/gemini.d.ts +85 -12
  112. package/lib/dist/installer/targets/gemini.d.ts.map +1 -1
  113. package/lib/dist/installer/targets/gemini.js +527 -30
  114. package/lib/dist/installer/targets/gemini.js.map +1 -1
  115. package/lib/dist/installer/targets/shared.d.ts +13 -0
  116. package/lib/dist/installer/targets/shared.d.ts.map +1 -1
  117. package/lib/dist/installer/targets/shared.js +18 -0
  118. package/lib/dist/installer/targets/shared.js.map +1 -1
  119. package/lib/dist/installer/targets/types.d.ts +12 -0
  120. package/lib/dist/installer/targets/types.d.ts.map +1 -1
  121. package/lib/dist/jira/auto-publish.d.ts +71 -4
  122. package/lib/dist/jira/auto-publish.d.ts.map +1 -1
  123. package/lib/dist/jira/auto-publish.js +186 -17
  124. package/lib/dist/jira/auto-publish.js.map +1 -1
  125. package/lib/dist/jira/reconcile.d.ts +24 -1
  126. package/lib/dist/jira/reconcile.d.ts.map +1 -1
  127. package/lib/dist/jira/reconcile.js +46 -2
  128. package/lib/dist/jira/reconcile.js.map +1 -1
  129. package/lib/dist/jira/repo-config.d.ts +9 -0
  130. package/lib/dist/jira/repo-config.d.ts.map +1 -1
  131. package/lib/dist/jira/repo-config.js +11 -0
  132. package/lib/dist/jira/repo-config.js.map +1 -1
  133. package/lib/dist/jira/types.d.ts +7 -0
  134. package/lib/dist/jira/types.d.ts.map +1 -1
  135. package/lib/dist/jira/types.js.map +1 -1
  136. package/lib/dist/knowledge/enforce.d.ts +75 -0
  137. package/lib/dist/knowledge/enforce.d.ts.map +1 -0
  138. package/lib/dist/knowledge/enforce.js +250 -0
  139. package/lib/dist/knowledge/enforce.js.map +1 -0
  140. package/lib/dist/knowledge/facts.d.ts +33 -0
  141. package/lib/dist/knowledge/facts.d.ts.map +1 -0
  142. package/lib/dist/knowledge/facts.js +117 -0
  143. package/lib/dist/knowledge/facts.js.map +1 -0
  144. package/lib/dist/knowledge/proposals.d.ts +88 -0
  145. package/lib/dist/knowledge/proposals.d.ts.map +1 -0
  146. package/lib/dist/knowledge/proposals.js +360 -0
  147. package/lib/dist/knowledge/proposals.js.map +1 -0
  148. package/lib/dist/knowledge/stale.d.ts +64 -0
  149. package/lib/dist/knowledge/stale.d.ts.map +1 -0
  150. package/lib/dist/knowledge/stale.js +174 -0
  151. package/lib/dist/knowledge/stale.js.map +1 -0
  152. package/lib/dist/mcp/gemini-session.d.ts +50 -0
  153. package/lib/dist/mcp/gemini-session.d.ts.map +1 -0
  154. package/lib/dist/mcp/gemini-session.js +159 -0
  155. package/lib/dist/mcp/gemini-session.js.map +1 -0
  156. package/lib/dist/mcp/jira-tools.d.ts.map +1 -1
  157. package/lib/dist/mcp/jira-tools.js +25 -0
  158. package/lib/dist/mcp/jira-tools.js.map +1 -1
  159. package/lib/dist/mcp/model-context.d.ts +22 -9
  160. package/lib/dist/mcp/model-context.d.ts.map +1 -1
  161. package/lib/dist/mcp/model-context.js +35 -13
  162. package/lib/dist/mcp/model-context.js.map +1 -1
  163. package/lib/dist/mcp/proxy.js +1 -1
  164. package/lib/dist/mcp/proxy.js.map +1 -1
  165. package/lib/dist/mcp/server-instructions.d.ts +16 -15
  166. package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
  167. package/lib/dist/mcp/server-instructions.js +67 -1
  168. package/lib/dist/mcp/server-instructions.js.map +1 -1
  169. package/lib/dist/mcp/session.js +1 -1
  170. package/lib/dist/mcp/session.js.map +1 -1
  171. package/lib/dist/mcp/spec-tools.d.ts +9 -1
  172. package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
  173. package/lib/dist/mcp/spec-tools.js +69 -21
  174. package/lib/dist/mcp/spec-tools.js.map +1 -1
  175. package/lib/dist/mcp/tools.d.ts +37 -1
  176. package/lib/dist/mcp/tools.d.ts.map +1 -1
  177. package/lib/dist/mcp/tools.js +120 -9
  178. package/lib/dist/mcp/tools.js.map +1 -1
  179. package/lib/dist/pulse/pulse.d.ts +93 -0
  180. package/lib/dist/pulse/pulse.d.ts.map +1 -0
  181. package/lib/dist/pulse/pulse.js +401 -0
  182. package/lib/dist/pulse/pulse.js.map +1 -0
  183. package/lib/dist/reflect/apply.d.ts.map +1 -1
  184. package/lib/dist/reflect/apply.js +38 -3
  185. package/lib/dist/reflect/apply.js.map +1 -1
  186. package/lib/dist/reflect/auto-sweep.d.ts +26 -0
  187. package/lib/dist/reflect/auto-sweep.d.ts.map +1 -0
  188. package/lib/dist/reflect/auto-sweep.js +90 -0
  189. package/lib/dist/reflect/auto-sweep.js.map +1 -0
  190. package/lib/dist/reflect/cli.d.ts +62 -0
  191. package/lib/dist/reflect/cli.d.ts.map +1 -0
  192. package/lib/dist/reflect/cli.js +163 -0
  193. package/lib/dist/reflect/cli.js.map +1 -0
  194. package/lib/dist/reflect/miner.d.ts.map +1 -1
  195. package/lib/dist/reflect/miner.js +119 -0
  196. package/lib/dist/reflect/miner.js.map +1 -1
  197. package/lib/dist/reflect/sweep.d.ts +1 -0
  198. package/lib/dist/reflect/sweep.d.ts.map +1 -1
  199. package/lib/dist/reflect/sweep.js +62 -13
  200. package/lib/dist/reflect/sweep.js.map +1 -1
  201. package/lib/dist/reflect/targets.d.ts +2 -0
  202. package/lib/dist/reflect/targets.d.ts.map +1 -1
  203. package/lib/dist/reflect/targets.js +33 -0
  204. package/lib/dist/reflect/targets.js.map +1 -1
  205. package/lib/dist/reflect/types.d.ts +19 -2
  206. package/lib/dist/reflect/types.d.ts.map +1 -1
  207. package/lib/dist/resolution/test-title-links.d.ts.map +1 -1
  208. package/lib/dist/resolution/test-title-links.js +3 -14
  209. package/lib/dist/resolution/test-title-links.js.map +1 -1
  210. package/lib/dist/server/routes/claude.js +15 -7
  211. package/lib/dist/server/routes/knowledge.js +118 -0
  212. package/lib/dist/server/server.js +2 -0
  213. package/lib/dist/skills/design-md/SKILL.md +172 -0
  214. package/lib/dist/skills/design-md/references/authored-sections.md +90 -0
  215. package/lib/dist/skills/design-md/references/sources.md +71 -0
  216. package/lib/dist/spec-lint/lint.d.ts +1 -1
  217. package/lib/dist/spec-lint/lint.d.ts.map +1 -1
  218. package/lib/dist/spec-lint/lint.js +63 -2
  219. package/lib/dist/spec-lint/lint.js.map +1 -1
  220. package/lib/dist/spec-quality/criterion-ids.d.ts +13 -0
  221. package/lib/dist/spec-quality/criterion-ids.d.ts.map +1 -0
  222. package/lib/dist/spec-quality/criterion-ids.js +38 -0
  223. package/lib/dist/spec-quality/criterion-ids.js.map +1 -0
  224. package/lib/dist/spec-quality/evidence-kind.d.ts +54 -0
  225. package/lib/dist/spec-quality/evidence-kind.d.ts.map +1 -0
  226. package/lib/dist/spec-quality/evidence-kind.js +183 -0
  227. package/lib/dist/spec-quality/evidence-kind.js.map +1 -0
  228. package/lib/dist/spec-quality/link-persist.d.ts +65 -0
  229. package/lib/dist/spec-quality/link-persist.d.ts.map +1 -0
  230. package/lib/dist/spec-quality/link-persist.js +249 -0
  231. package/lib/dist/spec-quality/link-persist.js.map +1 -0
  232. package/lib/dist/spec-quality/plan-scope.d.ts +38 -0
  233. package/lib/dist/spec-quality/plan-scope.d.ts.map +1 -0
  234. package/lib/dist/spec-quality/plan-scope.js +129 -0
  235. package/lib/dist/spec-quality/plan-scope.js.map +1 -0
  236. package/lib/dist/spec-quality/postcheck.d.ts +91 -0
  237. package/lib/dist/spec-quality/postcheck.d.ts.map +1 -0
  238. package/lib/dist/spec-quality/postcheck.js +421 -0
  239. package/lib/dist/spec-quality/postcheck.js.map +1 -0
  240. package/lib/dist/spec-quality/readiness.d.ts +72 -0
  241. package/lib/dist/spec-quality/readiness.d.ts.map +1 -0
  242. package/lib/dist/spec-quality/readiness.js +226 -0
  243. package/lib/dist/spec-quality/readiness.js.map +1 -0
  244. package/lib/dist/workflows/agents/claude.d.ts +16 -0
  245. package/lib/dist/workflows/agents/claude.d.ts.map +1 -0
  246. package/lib/dist/workflows/agents/claude.js +82 -0
  247. package/lib/dist/workflows/agents/claude.js.map +1 -0
  248. package/lib/dist/workflows/agents/gemini.d.ts +21 -0
  249. package/lib/dist/workflows/agents/gemini.d.ts.map +1 -0
  250. package/lib/dist/workflows/agents/gemini.js +124 -0
  251. package/lib/dist/workflows/agents/gemini.js.map +1 -0
  252. package/lib/dist/workflows/agents/index.d.ts +28 -0
  253. package/lib/dist/workflows/agents/index.d.ts.map +1 -0
  254. package/lib/dist/workflows/agents/index.js +104 -0
  255. package/lib/dist/workflows/agents/index.js.map +1 -0
  256. package/lib/dist/workflows/agents/types.d.ts +55 -0
  257. package/lib/dist/workflows/agents/types.d.ts.map +1 -0
  258. package/lib/dist/workflows/agents/types.js +46 -0
  259. package/lib/dist/workflows/agents/types.js.map +1 -0
  260. package/lib/dist/workflows/batch.d.ts +63 -0
  261. package/lib/dist/workflows/batch.d.ts.map +1 -0
  262. package/lib/dist/workflows/batch.js +151 -0
  263. package/lib/dist/workflows/batch.js.map +1 -0
  264. package/lib/dist/workflows/defaults/claude-design-implement.yaml +37 -9
  265. package/lib/dist/workflows/defaults/spec-author.yaml +11 -9
  266. package/lib/dist/workflows/defaults/spec-implement-mixed.yaml +21 -436
  267. package/lib/dist/workflows/defaults/spec-implement.yaml +481 -46
  268. package/lib/dist/workflows/discovery.d.ts +13 -0
  269. package/lib/dist/workflows/discovery.d.ts.map +1 -1
  270. package/lib/dist/workflows/discovery.js +79 -17
  271. package/lib/dist/workflows/discovery.js.map +1 -1
  272. package/lib/dist/workflows/executor.d.ts +18 -0
  273. package/lib/dist/workflows/executor.d.ts.map +1 -1
  274. package/lib/dist/workflows/executor.js +130 -33
  275. package/lib/dist/workflows/executor.js.map +1 -1
  276. package/lib/dist/workflows/gc.d.ts +50 -0
  277. package/lib/dist/workflows/gc.d.ts.map +1 -0
  278. package/lib/dist/workflows/gc.js +120 -0
  279. package/lib/dist/workflows/gc.js.map +1 -0
  280. package/lib/dist/workflows/merge-queue.d.ts +64 -0
  281. package/lib/dist/workflows/merge-queue.d.ts.map +1 -0
  282. package/lib/dist/workflows/merge-queue.js +162 -0
  283. package/lib/dist/workflows/merge-queue.js.map +1 -0
  284. package/lib/dist/workflows/runners/approval.d.ts +1 -1
  285. package/lib/dist/workflows/runners/approval.d.ts.map +1 -1
  286. package/lib/dist/workflows/runners/approval.js +11 -2
  287. package/lib/dist/workflows/runners/approval.js.map +1 -1
  288. package/lib/dist/workflows/runners/bash.d.ts +15 -0
  289. package/lib/dist/workflows/runners/bash.d.ts.map +1 -1
  290. package/lib/dist/workflows/runners/bash.js +50 -1
  291. package/lib/dist/workflows/runners/bash.js.map +1 -1
  292. package/lib/dist/workflows/runners/prompt.d.ts +16 -41
  293. package/lib/dist/workflows/runners/prompt.d.ts.map +1 -1
  294. package/lib/dist/workflows/runners/prompt.js +55 -120
  295. package/lib/dist/workflows/runners/prompt.js.map +1 -1
  296. package/lib/dist/workflows/runners/types.d.ts +12 -0
  297. package/lib/dist/workflows/runners/types.d.ts.map +1 -1
  298. package/lib/dist/workflows/schemas/workflow.d.ts +17 -0
  299. package/lib/dist/workflows/schemas/workflow.d.ts.map +1 -1
  300. package/lib/dist/workflows/schemas/workflow.js +27 -0
  301. package/lib/dist/workflows/schemas/workflow.js.map +1 -1
  302. package/lib/node_modules/.package-lock.json +1 -1
  303. package/lib/package.json +2 -2
  304. package/package.json +5 -3
  305. package/node.exe +0 -4
@@ -14,8 +14,25 @@ inputs:
14
14
  systemPromptAppend: |
15
15
  You are implementing a specific requirement. Before editing code, call
16
16
  specship_spec($INPUT.SPEC_ID) to see the spec body and any code it
17
- already links to. After editing, call specship_link_assert with the
18
- spec_id and the symbol you implemented BEFORE reporting done.
17
+ already links to. After editing, record each symbol you implemented as a
18
+ `path:Symbol` bullet under the requirement's `implementations:` block in
19
+ its spec file — links in the spec file survive any reindex.
20
+
21
+ Design-backed specs (REQ-DESIGNMD-006): if the spec file's frontmatter
22
+ carries a `design:` key, read that design.md before ANY UI edit and build
23
+ from it — every color, size, spacing, radius, shadow, font and duration
24
+ verbatim from its Generated reference, every state under Components &
25
+ states, every breakpoint under Responsive behaviour. Never round or
26
+ substitute a "close" value; reuse a project token only when its value is
27
+ exactly equal. Anything design.md doesn't state is a question, not a guess.
28
+ Keep it current (REQ-DESIGNMD-007): when your change alters the UI — a new
29
+ or changed component, state, layout, token or copy — update that design.md
30
+ in the same change: revise the authored sections that describe what moved,
31
+ add a dated Change log line naming $INPUT.SPEC_ID, and when the design
32
+ source itself changed run `specship design extract <sources> --update
33
+ <design.md>`. Then run `specship design check <design.md>`. The postcheck
34
+ fails a UI change whose design.md has no new Change log entry, and fails a
35
+ design.md that no longer passes the check.
19
36
 
20
37
  JIRA-backed specs (REQ-JIRAPUB-004): if the spec file's frontmatter
21
38
  carries a `jira_issue:` key, EVERY git commit message you write for this
@@ -41,9 +58,30 @@ nodes:
41
58
  (b) which code areas / symbols are most relevant, and (c) whether
42
59
  any code currently claims to implement it (look at linked_code).
43
60
 
61
+ - id: readiness
62
+ kind: bash
63
+ depends_on: [fetch_spec]
64
+ output_type: readiness_report
65
+ timeout: 120000
66
+ bash: |
67
+ # REQ-PIPETRUST-004 — implement must not start on a spec that is not
68
+ # ready (lint errors, no criteria, a criterion still [needs review]).
69
+ # Also records the run's base commit so postcheck can diff against it.
70
+ git rev-parse HEAD > "$(git rev-parse --git-dir)/specship-run-base" 2>/dev/null || true
71
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
72
+ elif command -v specship >/dev/null 2>&1; then SS=specship
73
+ elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
74
+ else SS=""
75
+ fi
76
+ if [ -z "$SS" ]; then
77
+ echo "READY=unavailable — specship CLI not found; the readiness gate did NOT run"
78
+ exit 1
79
+ fi
80
+ $SS ready $INPUT.SPEC_ID --path .
81
+
44
82
  - id: plan
45
83
  kind: prompt
46
- depends_on: [fetch_spec]
84
+ depends_on: [fetch_spec, readiness]
47
85
  output_type: plan
48
86
  allowed_tools:
49
87
  - mcp__specship__specship_explore
@@ -55,6 +93,17 @@ nodes:
55
93
 
56
94
  $fetch_spec.output
57
95
 
96
+ Readiness + evidence plan (every acceptance criterion needs a test of
97
+ the stated kind, written as a NAMED function passed to it() with the
98
+ criterion id in its title):
99
+ $readiness.output
100
+
101
+ Domain facts that `specship_spec` returns with the requirement are
102
+ constraints, not background: honour each external fact's verified
103
+ version, and treat every `## Enforced` rule (`<glob>` must not match
104
+ `/<regex>/`) as a hard constraint — `specship knowledge check` fails the
105
+ run on a violation (REQ-KNOW-005).
106
+
58
107
  The plan should list:
59
108
  - Files to create or modify (with project-relative paths)
60
109
  - Specific functions/methods/classes to add or change
@@ -63,23 +112,93 @@ nodes:
63
112
 
64
113
  Keep it tight (≤500 words). Do NOT edit code in this step.
65
114
 
115
+ - id: plan_scope
116
+ kind: bash
117
+ depends_on: [plan]
118
+ output_type: plan_scope
119
+ bash: |
120
+ # REQ-THRU-003 — opt-in auto-approval of a small, in-scope plan. Prints
121
+ # AUTO_APPROVE=yes only when specship.config.json opts in, the plan
122
+ # names only the requirement's implementation files (plus tests, its
123
+ # spec and CHANGELOG.md), and the requirement has few criteria.
124
+ PLAN=$plan.output
125
+ F="$(mktemp)"
126
+ printf '%s\n' "$PLAN" > "$F"
127
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" plan-scope $INPUT.SPEC_ID --plan-file "$F" --path .
128
+ elif command -v specship >/dev/null 2>&1; then specship plan-scope $INPUT.SPEC_ID --plan-file "$F" --path . || echo "AUTO_APPROVE=no"
129
+ else echo "AUTO_APPROVE=no"; echo "- specship CLI not found"
130
+ fi
131
+ rm -f "$F"
132
+
66
133
  - id: approve_plan
67
134
  kind: approval
68
- depends_on: [plan]
135
+ depends_on: [plan, plan_scope]
136
+ auto_approve:
137
+ from: plan_scope
138
+ marker: AUTO_APPROVE=yes
69
139
  message: |
70
140
  Plan ready for $INPUT.SPEC_ID. Review the plan output and approve
71
141
  to proceed with implementation, or reject with feedback to revise.
72
142
  capture_response: true
73
143
  on_reject:
144
+ # The reviewer's rejection reason is appended to this prompt
145
+ # automatically; the revision replaces $plan.output downstream.
74
146
  prompt: |
75
- The plan was rejected with this feedback. Revise:
147
+ The plan was rejected (feedback follows). Revise the plan to
148
+ address it and output the full revised plan.
76
149
 
77
- $approve_plan.output
150
+ Current plan:
151
+ $plan.output
152
+ revises: plan
78
153
  max_attempts: 3
79
154
 
155
+ - id: quality_baseline
156
+ kind: bash
157
+ depends_on: [approve_plan]
158
+ output_type: quality_report
159
+ timeout: 600000
160
+ bash: |
161
+ # REQ-AUTHG-008.A1 — run the project's quality command BEFORE implement
162
+ # edits anything, so the gate can tell errors this change introduced
163
+ # from errors the worktree already had (a sub-package with no built
164
+ # parent, known lint debt). The baseline lives under the worktree's git
165
+ # dir, so it never shows up in the diff. It is written ONLY when the
166
+ # pre-change command fails: a clean baseline means any later failure is
167
+ # the change's, so the gate keeps its full strictness (A5 fallback).
168
+ qnorm() { sed -E 's/\([0-9]+,[0-9]+\)//g; s/:[0-9]+:[0-9]+/:/g; s/:[0-9]+:/:/g' | sed -E '/^[[:space:]]*$/d' | sort -u; }
169
+ BASELINE="$(git rev-parse --git-dir 2>/dev/null)/specship-quality-baseline.txt"
170
+ rm -f "$BASELINE"
171
+ QUALITY_CMD=""
172
+ if [ -f package.json ]; then
173
+ if [ ! -d node_modules ]; then
174
+ npm ci --no-audit --no-fund >/dev/null 2>&1 || npm install --no-audit --no-fund >/dev/null 2>&1 || true
175
+ fi
176
+ if node -e 'const s=(require("./package.json").scripts)||{};process.exit(s.lint?0:1)' 2>/dev/null; then
177
+ QUALITY_CMD="npm run lint --if-present"
178
+ elif [ -f tsconfig.json ]; then
179
+ QUALITY_CMD="npx --no-install tsc --noEmit"
180
+ fi
181
+ elif [ -f Cargo.toml ]; then
182
+ if command -v cargo >/dev/null 2>&1; then QUALITY_CMD="cargo clippy --no-deps"; fi
183
+ elif [ -f pyproject.toml ] || [ -f requirements.txt ]; then
184
+ if command -v ruff >/dev/null 2>&1; then QUALITY_CMD="ruff check ."; fi
185
+ fi
186
+ if [ -z "$QUALITY_CMD" ]; then
187
+ echo "QUALITY_BASELINE=skipped"
188
+ exit 0
189
+ fi
190
+ if OUT=$($QUALITY_CMD 2>&1); then
191
+ echo "QUALITY_BASELINE=clean"
192
+ else
193
+ printf '%s\n' "$OUT" | qnorm > "$BASELINE"
194
+ echo "QUALITY_BASELINE=recorded"
195
+ echo "QUALITY_BASELINE_LINES=$(wc -l < "$BASELINE" | tr -d ' ')"
196
+ fi
197
+ exit 0
198
+
80
199
  - id: implement
81
200
  kind: prompt
82
- depends_on: [approve_plan]
201
+ depends_on: [approve_plan, quality_baseline]
83
202
  output_type: diff
84
203
  allowed_tools:
85
204
  - Read
@@ -92,12 +211,23 @@ nodes:
92
211
  prompt: |
93
212
  Implement the approved plan. Follow it closely.
94
213
 
214
+ Domain facts that `specship_spec` returns with the requirement are
215
+ constraints, not background: honour each external fact's verified
216
+ version, and treat every `## Enforced` rule (`<glob>` must not match
217
+ `/<regex>/`) as a hard constraint — `specship knowledge check` fails the
218
+ run on a violation (REQ-KNOW-005).
219
+
95
220
  Plan:
96
221
  $plan.output
97
222
 
98
223
  Approval feedback (if any):
99
224
  $approve_plan.output
100
225
 
226
+ Readiness + evidence plan (every acceptance criterion needs a test of
227
+ the stated kind, written as a NAMED function passed to it() with the
228
+ criterion id in its title):
229
+ $readiness.output
230
+
101
231
  When done, output a short diff summary (which files changed and why).
102
232
 
103
233
  - id: quality_gate
@@ -135,8 +265,26 @@ nodes:
135
265
  exit 0
136
266
  fi
137
267
  echo "QUALITY_CMD=$QUALITY_CMD"
268
+ qnorm() { sed -E 's/\([0-9]+,[0-9]+\)//g; s/:[0-9]+:[0-9]+/:/g; s/:[0-9]+:/:/g' | sed -E '/^[[:space:]]*$/d' | sort -u; }
269
+ BASELINE="$(git rev-parse --git-dir 2>/dev/null)/specship-quality-baseline.txt"
138
270
  if OUT=$($QUALITY_CMD 2>&1); then
139
271
  echo "QUALITY_GATE=passed"
272
+ elif [ -f "$BASELINE" ]; then
273
+ # REQ-AUTHG-008.A2/A3 — judge only error lines absent from the
274
+ # pre-change baseline; report pre-existing ones, never hide them.
275
+ NEW=$(printf '%s\n' "$OUT" | qnorm | comm -13 "$BASELINE" - | grep -iE 'error' || true)
276
+ PRE=$(printf '%s\n' "$OUT" | qnorm | comm -12 "$BASELINE" - | grep -ciE 'error' || true)
277
+ if [ -z "$NEW" ]; then
278
+ echo "QUALITY_GATE=passed"
279
+ echo "QUALITY_PREEXISTING=$PRE"
280
+ echo "Pre-existing errors (already failing before implement; not caused by this change), sample:"
281
+ printf '%s\n' "$OUT" | grep -iE 'error' | head -n 5
282
+ else
283
+ echo "QUALITY_GATE=failed"
284
+ echo "QUALITY_PREEXISTING=$PRE"
285
+ echo "New errors introduced by this change:"
286
+ printf '%s\n' "$NEW" | tail -n 80
287
+ fi
140
288
  else
141
289
  echo "QUALITY_GATE=failed"
142
290
  printf '%s\n' "$OUT" | tail -n 80
@@ -194,14 +342,142 @@ nodes:
194
342
  echo "QUALITY_RESULT=clean"
195
343
  exit 0
196
344
  fi
197
- echo "QUALITY_RESULT=failed"
198
- printf '%s\n' "$OUT" | tail -n 80
345
+ qnorm() { sed -E 's/\([0-9]+,[0-9]+\)//g; s/:[0-9]+:[0-9]+/:/g; s/:[0-9]+:/:/g' | sed -E '/^[[:space:]]*$/d' | sort -u; }
346
+ BASELINE="$(git rev-parse --git-dir 2>/dev/null)/specship-quality-baseline.txt"
347
+ if [ -f "$BASELINE" ]; then
348
+ # REQ-AUTHG-008.A2/A3 — only errors absent from the baseline halt.
349
+ NEW=$(printf '%s\n' "$OUT" | qnorm | comm -13 "$BASELINE" - | grep -iE 'error' || true)
350
+ if [ -z "$NEW" ]; then
351
+ echo "QUALITY_RESULT=clean"
352
+ echo "QUALITY_PREEXISTING=$(printf '%s\n' "$OUT" | qnorm | comm -12 "$BASELINE" - | grep -ciE 'error' || true)"
353
+ exit 0
354
+ fi
355
+ echo "QUALITY_RESULT=failed"
356
+ printf '%s\n' "$NEW" | tail -n 80
357
+ else
358
+ echo "QUALITY_RESULT=failed"
359
+ printf '%s\n' "$OUT" | tail -n 80
360
+ fi
199
361
  echo "HALT_CAUSE=lint/typecheck still fails after the fix attempt — the change is not reviewable yet"
200
362
  exit 1
201
363
 
202
- - id: diff
364
+ - id: postcheck
203
365
  kind: bash
204
366
  depends_on: [quality_recheck]
367
+ output_type: postcheck_report
368
+ timeout: 600000
369
+ bash: |
370
+ # REQ-PIPETRUST-005 — check the agent's work mechanically: verifies
371
+ # bullets are real named test symbols covering every criterion, a src
372
+ # change has a CHANGELOG entry, and project-configured checks pass
373
+ # (their fix commands run first). Exit 0 always: the POSTCHECK marker
374
+ # routes the fix step; postcheck_recheck is what halts.
375
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
376
+ elif command -v specship >/dev/null 2>&1; then SS=specship
377
+ elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
378
+ else SS=""
379
+ fi
380
+ if [ -z "$SS" ]; then
381
+ echo "POSTCHECK=failed"
382
+ echo "specship CLI not found — postcheck did NOT run"
383
+ exit 0
384
+ fi
385
+ $SS postcheck $INPUT.SPEC_ID --path . --fix || true
386
+
387
+ - id: fix_postcheck
388
+ kind: prompt
389
+ depends_on: [postcheck]
390
+ output_type: postcheck_fix
391
+ allowed_tools:
392
+ - Read
393
+ - Edit
394
+ - Write
395
+ - Bash
396
+ - mcp__specship__specship_spec
397
+ prompt: |
398
+ Mechanical post-implement check for $INPUT.SPEC_ID:
399
+
400
+ $postcheck.output
401
+
402
+ Route on the POSTCHECK marker — do not re-judge:
403
+
404
+ - POSTCHECK=passed → change NOTHING. Output exactly
405
+ `FIX_POSTCHECK=not-needed` and stop.
406
+ - POSTCHECK=failed → fix every ✗ finding:
407
+ - [verifies] — every acceptance criterion needs a test written as a
408
+ NAMED function passed to it(), with the criterion id in the it()
409
+ title, listed under the requirement's `verifies:` block in its spec
410
+ file as `path:FunctionName` (never an it() title string).
411
+ - [changelog] — add a plain-sentence, user-facing entry under
412
+ `## [Unreleased]` in CHANGELOG.md (no internal paths or symbols).
413
+ - [command] — make the named check pass by fixing the cause.
414
+ A bash step re-runs postcheck after you; any finding left halts the run.
415
+
416
+ Output `FIX_POSTCHECK=fixed` or `FIX_POSTCHECK=still-failing` followed
417
+ by what remains.
418
+
419
+ - id: postcheck_recheck
420
+ kind: bash
421
+ depends_on: [fix_postcheck]
422
+ output_type: postcheck_result
423
+ timeout: 600000
424
+ bash: |
425
+ # REQ-PIPETRUST-005.A5 — the authoritative half: re-run and halt while
426
+ # anything still fails, so an unlinked or undocumented change never
427
+ # reaches verify or the human gate.
428
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
429
+ elif command -v specship >/dev/null 2>&1; then SS=specship
430
+ elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
431
+ else SS=""
432
+ fi
433
+ if [ -z "$SS" ]; then
434
+ echo "POSTCHECK_RESULT=failed"
435
+ echo "HALT_CAUSE=specship CLI not found — postcheck did NOT run"
436
+ exit 1
437
+ fi
438
+ if OUT=$($SS postcheck $INPUT.SPEC_ID --path . 2>&1); then
439
+ echo "POSTCHECK_RESULT=clean"
440
+ printf '%s\n' "$OUT"
441
+ exit 0
442
+ fi
443
+ echo "POSTCHECK_RESULT=failed"
444
+ printf '%s\n' "$OUT"
445
+ echo "HALT_CAUSE=postcheck still fails after the fix attempt — the change is not reviewable yet"
446
+ exit 1
447
+
448
+ - id: suppression_gate
449
+ kind: bash
450
+ depends_on: [postcheck_recheck]
451
+ output_type: suppression_report
452
+ bash: |
453
+ # REQ-QGATE-004.A3 — deterministic scan for lint/type suppression
454
+ # comments the change introduces (noqa, eslint-disable, @ts-ignore, …).
455
+ # The fix_quality prompt forbids silencing rules; this node enforces it
456
+ # in code. SUPPRESSION_GATE is the marker contract: a scan that could
457
+ # not run is `skipped`, never `clean`.
458
+ # REQ-PIPETRUST-006.A4 — prefer the CLI running this workflow over any
459
+ # (possibly older) `specship` on PATH.
460
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
461
+ elif command -v specship >/dev/null 2>&1; then SS=specship
462
+ elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
463
+ elif [ -x dist/bin/specship.js ]; then SS="node dist/bin/specship.js"
464
+ else SS=""; fi
465
+ if [ -z "$SS" ]; then
466
+ echo "SUPPRESSION_GATE=skipped"
467
+ echo "SUPPRESSION_REASON=specship CLI not found — suppression scan did NOT run"
468
+ exit 0
469
+ fi
470
+ if OUT=$($SS suppressions 2>&1); then
471
+ printf '%s\n' "$OUT"
472
+ else
473
+ printf '%s\n' "$OUT"
474
+ echo "HALT_CAUSE=the change introduces lint/type suppression comments — fix the code instead of silencing the rule"
475
+ exit 1
476
+ fi
477
+
478
+ - id: diff
479
+ kind: bash
480
+ depends_on: [suppression_gate]
205
481
  output_type: diff
206
482
  bash: |
207
483
  # REQ-AUTHG-004.A1 — the full diff, from git, into a run artifact. The
@@ -252,7 +528,16 @@ nodes:
252
528
  fi
253
529
  fi
254
530
  if ! npm run build --if-present; then echo "VERIFY_RESULT=build-failed"; exit 1; fi
255
- if npm test; then echo "VERIFY_RESULT=ran-and-passed"; else echo "VERIFY_RESULT=ran-and-failed"; exit 1; fi
531
+ # REQ-PIPETRUST-006.A3 — a vitest project also leaves a JSON report in
532
+ # the run's artifacts, ingestible with `specship verify --report`.
533
+ TEST_ARGS=""
534
+ if [ -n "$SPECSHIP_ARTIFACTS_DIR" ] && node -e 'const s=((require("./package.json").scripts)||{}).test||"";process.exit(/^\s*vitest\b/.test(s)?0:1)' 2>/dev/null; then
535
+ mkdir -p "$SPECSHIP_ARTIFACTS_DIR"
536
+ REPORT="$SPECSHIP_ARTIFACTS_DIR/test-report.json"
537
+ TEST_ARGS="-- --reporter=default --reporter=json --outputFile.json=$REPORT"
538
+ echo "VERIFY_REPORT=$REPORT (ingest after merge: specship verify --report $REPORT)"
539
+ fi
540
+ if npm test $TEST_ARGS; then echo "VERIFY_RESULT=ran-and-passed"; else echo "VERIFY_RESULT=ran-and-failed"; exit 1; fi
256
541
  elif [ -f Cargo.toml ]; then
257
542
  if ! cargo build; then echo "VERIFY_RESULT=build-failed"; exit 1; fi
258
543
  if cargo test; then echo "VERIFY_RESULT=ran-and-passed"; else echo "VERIFY_RESULT=ran-and-failed"; exit 1; fi
@@ -302,49 +587,47 @@ nodes:
302
587
  depends_on: [route_verify]
303
588
  output_type: link_summary
304
589
  allowed_tools:
305
- - mcp__specship__specship_link_assert
306
- - mcp__specship__specship_link_verify
590
+ - Read
591
+ - Edit
307
592
  - mcp__specship__specship_spec
308
593
  prompt: |
309
- Assert spec→code links for the changes made in the implement step.
310
- For each symbol that implements $INPUT.SPEC_ID (or its child
311
- requirements), call specship_link_assert with the spec_id, the
312
- file path, and the qualified symbol name.
313
-
314
- You MUST NOT assert a `tests`-kind link (REQ-REVINT-005.A1). Every
315
- specship_link_assert call here is an implementation link — leave `kind`
316
- at its default and never pass kind: 'tests'. Test evidence is
317
- file-derived only: it comes from the spec's `verifies:` block or an
318
- `@verifies` comment on the test symbol, never from this node. A workflow
319
- that minted its own test evidence would be promoting itself past the
320
- gate that exists to check it.
321
-
322
- Then act on LINK_ACTION, which a bash node already computed from the
323
- VERIFY_RESULT marker (REQ-VSTATE-005.A1). Do NOT re-derive it from the
324
- test log — read it:
594
+ Record spec→code links for the changes made in the implement step —
595
+ durably, in the spec file (REQ-PIPETRUST-006). Do NOT call
596
+ specship_link_assert or specship_link_verify: runtime links vanish on a
597
+ full reindex, and a headless run cannot be granted them.
598
+
599
+ Open the spec file that declares $INPUT.SPEC_ID. Under the requirement:
600
+ - `implementations:` — one `path:Symbol` bullet per symbol that
601
+ implements it (qualified `Class.method` for methods). Add any that
602
+ are missing; never duplicate an existing bullet.
603
+ - `verifies:` — leave as the postcheck step left it (named test
604
+ functions only). Never add an it() title string.
605
+
606
+ You MUST NOT assert a `tests`-kind link (REQ-REVINT-005.A1) —
607
+ never pass kind: 'tests', and never mint test evidence: it comes only
608
+ from the spec's `verifies:` block or an `@verifies` comment on a test
609
+ symbol.
610
+
611
+ Verification state is not yours to set, so you
612
+ do NOT call specship_link_verify, whatever LINK_ACTION says. On
613
+ LINK_ACTION=assert-and-verify-pass, LINK_ACTION=assert-and-verify-fail
614
+ or LINK_ACTION=assert-only alike, record the implementations bullets
615
+ only: tests that ran are in the run's JSON test report (see the verify
616
+ output) and are ingested with `specship verify --report` after the
617
+ branch merges; tests that did not run are never reported as passing.
618
+
619
+ Routing context (computed by a bash node from VERIFY_RESULT):
325
620
 
326
621
  $route_verify.output
327
622
 
328
- - LINK_ACTION=assert-and-verify-pass → after each assert, call
329
- specship_link_verify with result="pass".
330
- - LINK_ACTION=assert-and-verify-fail → call specship_link_verify with
331
- result="fail" and the failing test name as the reason.
332
- - LINK_ACTION=assert-only → do NOT call specship_link_verify at all;
333
- the links stay in the `implemented` state. Tests that did not run
334
- are never reported as passing.
335
-
336
- A run whose environment or build broke never reaches this node — the
337
- routing step halts it first (REQ-VSTATE-005.A3).
338
-
339
623
  Implementation diff summary:
340
624
  $implement.output
341
625
 
342
626
  Test results:
343
627
  $verify.output
344
628
 
345
- Output: a short list of "spec_id → file:symbol [verified|implemented]"
346
- lines, ending with one line stating whether verification ran or was
347
- skipped.
629
+ Output: a short list of "spec_id → file:symbol" lines you recorded,
630
+ ending with the VERIFY_REPORT line from the verify output if present.
348
631
 
349
632
  - id: coverage
350
633
  kind: bash
@@ -356,7 +639,10 @@ nodes:
356
639
  # `getSpecCoverage` report the MCP tool and the dashboard read, so the
357
640
  # number on the approval gate cannot disagree with them. It used to be
358
641
  # counted by a prompt.
359
- if command -v specship >/dev/null 2>&1; then SS=specship
642
+ # REQ-PIPETRUST-006.A4 — prefer the CLI running this workflow over any
643
+ # (possibly older) `specship` on PATH.
644
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
645
+ elif command -v specship >/dev/null 2>&1; then SS=specship
360
646
  elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
361
647
  elif [ -x dist/bin/specship.js ]; then SS="node dist/bin/specship.js"
362
648
  else SS=""; fi
@@ -409,9 +695,144 @@ nodes:
409
695
  3. `Verdict:` one line — the most serious gap a reviewer should look at
410
696
  first, or `no gaps found`.
411
697
 
698
+ - id: probe_baseline
699
+ kind: bash
700
+ depends_on: [adversarial_review]
701
+ output_type: probe_baseline
702
+ bash: |
703
+ # REQ-THRU-008 — fingerprint every tracked change before the probe step,
704
+ # so the guard can prove the probes touched nothing tracked.
705
+ git add -A -N >/dev/null 2>&1 || true
706
+ git --no-pager diff HEAD | git hash-object --stdin > "$(git rev-parse --git-dir)/specship-probe-baseline"
707
+ echo "PROBE_BASELINE=recorded"
708
+
709
+ - id: review_probes
710
+ kind: prompt
711
+ depends_on: [probe_baseline]
712
+ output_type: review_probes
713
+ allowed_tools:
714
+ - Read
715
+ - Write
716
+ - Bash
717
+ - mcp__specship__specship_spec
718
+ prompt: |
719
+ Try to BREAK the change for $INPUT.SPEC_ID (REQ-THRU-008). You are not
720
+ the implementer. For EACH acceptance criterion write at least one small
721
+ probe test that would fail if the criterion were not really met — an
722
+ edge case, a boundary, a negative case — ONLY under
723
+ `.specship/review-probes/` (create it). NEVER edit any tracked file: a
724
+ guard step fails the run if you do.
725
+
726
+ Run each probe with the project's test runner. Report one line per
727
+ criterion: `<AC id>: held | broke | unrun — <probe file> — <one
728
+ sentence>`. `unrun` means the probe could not be executed (say why);
729
+ never report a probe you did not run as held.
730
+
731
+ The read-only review already found:
732
+ $adversarial_review.output
733
+
734
+ The change (from git):
735
+ $diff.output
736
+
737
+ - id: review_guard
738
+ kind: bash
739
+ depends_on: [review_probes]
740
+ output_type: review_guard
741
+ bash: |
742
+ # REQ-THRU-008.A2 — the probe step may not change tracked files.
743
+ git add -A -N >/dev/null 2>&1 || true
744
+ NOW=$(git --no-pager diff HEAD | git hash-object --stdin)
745
+ BEFORE=$(cat "$(git rev-parse --git-dir)/specship-probe-baseline" 2>/dev/null)
746
+ if [ -n "$BEFORE" ] && [ "$NOW" != "$BEFORE" ]; then
747
+ echo "REVIEW_GUARD=failed"
748
+ echo "HALT_CAUSE=the probe step changed tracked files — probes belong under .specship/review-probes/"
749
+ git --no-pager diff --stat HEAD
750
+ exit 1
751
+ fi
752
+ echo "REVIEW_GUARD=clean"
753
+
754
+ - id: knowledge_proposals
755
+ kind: prompt
756
+ depends_on: [review_guard]
757
+ output_type: knowledge_proposals
758
+ allowed_tools:
759
+ - Read
760
+ - Write
761
+ - mcp__specship__specship_spec
762
+ - mcp__specship__specship_explore
763
+ prompt: |
764
+ Propose knowledge this change relied on, for a HUMAN to confirm
765
+ (REQ-KNOW-004). Domain knowledge is human-confirmed, never
766
+ auto-extracted (DOM-SPECSHIP-003): you only PROPOSE.
767
+
768
+ Write 0–5 proposal files, one fact each, ONLY under
769
+ `.specship/knowledge/proposals/` (create the directory). NEVER edit
770
+ `specs/domain/` or any tracked file. Each file is a domain fact:
771
+
772
+ ---
773
+ title: <short name>
774
+ type: term | rule | decision | constraint | external
775
+ area: <AREA, e.g. the prefix used by existing DOM-<AREA>-NNN facts>
776
+ depends_on: $INPUT.SPEC_ID
777
+ # external facts ONLY — verified from the installed dependency, not memory:
778
+ dependency: <package or tool name>
779
+ version: <installed version you verified against>
780
+ source: <file and symbol in that dependency>
781
+ ---
782
+
783
+ # <title>
784
+
785
+ <one paragraph: the fact, stated plainly>
786
+
787
+ ## Enforced (optional — only for a mechanically checkable rule)
788
+ - `<glob>` must not match `/<regex>/`
789
+
790
+ Propose only what this change actually depended on and a future change
791
+ would otherwise rediscover — especially facts about third-party tools.
792
+ If there is nothing worth keeping, write no files.
793
+
794
+ Implementation diff summary:
795
+ $implement.output
796
+
797
+ Output one line per proposal file you wrote, or `NO_PROPOSALS`.
798
+
799
+ - id: knowledge_publish
800
+ kind: bash
801
+ depends_on: [knowledge_proposals]
802
+ output_type: knowledge_report
803
+ bash: |
804
+ # REQ-KNOW-004.A1 — the proposal step may write ONLY proposals. Any
805
+ # change under specs/domain/ halts the run. Proposals are then copied to
806
+ # the main project's .specship/knowledge/proposals/ (a run worktree's
807
+ # .specship/ is gitignored and would vanish), where
808
+ # `specship knowledge proposals` / `apply` / `reject` find them.
809
+ if [ -n "$(git status --porcelain -- specs/domain 2>/dev/null)" ]; then
810
+ echo "KNOWLEDGE_PROPOSALS=refused"
811
+ echo "HALT_CAUSE=the knowledge step changed specs/domain/ — only a human applies knowledge"
812
+ git status --porcelain -- specs/domain
813
+ exit 1
814
+ fi
815
+ SRC=".specship/knowledge/proposals"
816
+ N=0
817
+ if [ -d "$SRC" ]; then N=$(ls "$SRC"/*.md 2>/dev/null | wc -l | tr -d ' '); fi
818
+ echo "KNOWLEDGE_PROPOSALS=$N"
819
+ if [ "$N" -gt 0 ] && [ -n "$SPECSHIP_ARTIFACTS_DIR" ]; then
820
+ DEST="$(cd "$SPECSHIP_ARTIFACTS_DIR/../../.." 2>/dev/null && pwd)/knowledge/proposals"
821
+ mkdir -p "$DEST"
822
+ for f in "$SRC"/*.md; do
823
+ base=$(basename "$f")
824
+ target="$DEST/$base"
825
+ i=2
826
+ while [ -e "$target" ]; do target="$DEST/${base%.md}-$i.md"; i=$((i+1)); done
827
+ cp "$f" "$target"
828
+ echo "- $(basename "$target") ($(sed -n 's/^title: //p' "$f" | head -1))"
829
+ done
830
+ echo "Review with: specship knowledge proposals · apply <id> · reject <id>"
831
+ fi
832
+
412
833
  - id: final_review
413
834
  kind: approval
414
- depends_on: [adversarial_review]
835
+ depends_on: [adversarial_review, knowledge_publish]
415
836
  message: |
416
837
  Implementation complete for $INPUT.SPEC_ID.
417
838
 
@@ -421,7 +842,14 @@ nodes:
421
842
  Lint / typecheck:
422
843
  $quality_recheck.output
423
844
 
424
- Links asserted:
845
+ Mechanical postcheck (verifies symbols, CHANGELOG, project checks):
846
+ $postcheck_recheck.output
847
+
848
+ Suppression scan (new noqa / eslint-disable / @ts-ignore):
849
+ $suppression_gate.output
850
+
851
+ Links recorded in the spec (ingest the test report after merge with the
852
+ `specship verify --report` command named here):
425
853
  $link.output
426
854
 
427
855
  Acceptance-criteria test coverage:
@@ -430,5 +858,12 @@ nodes:
430
858
  Adversarial review:
431
859
  $adversarial_review.output
432
860
 
861
+ Review probes (held | broke | unrun per criterion):
862
+ $review_probes.output
863
+
864
+ Knowledge proposals (nothing is applied until you run
865
+ `specship knowledge apply <id>`):
866
+ $knowledge_publish.output
867
+
433
868
  Approve to finalize the run (worktree is left for you to inspect
434
869
  and merge), or reject to abandon.
@@ -43,4 +43,17 @@ export declare function discoverWorkflows(projectRoot: string): WorkflowLoadResu
43
43
  * Returns null if no workflow with that name exists in any scope.
44
44
  */
45
45
  export declare function loadWorkflowByName(projectRoot: string, name: string): WorkflowWithSource | null;
46
+ /**
47
+ * Resolve `extends: <workflow>` + `node_overrides` (THROUGHPUT-DOC,
48
+ * REQ-THRU-004): the result is the base workflow's raw definition with the
49
+ * extending file's top-level fields on top and each named node's fields
50
+ * shallow-merged from `node_overrides`. One source for shared nodes — a
51
+ * variant like spec-implement-mixed only states what differs. Chains resolve
52
+ * recursively; a cycle, an unknown base, or an override naming no base node
53
+ * is an error.
54
+ */
55
+ export declare function resolveExtends(raw: Record<string, unknown>, getBase: (name: string) => Record<string, unknown> | undefined, seen?: Set<string>): {
56
+ value?: Record<string, unknown>;
57
+ errors: ValidationError[];
58
+ };
46
59
  //# sourceMappingURL=discovery.d.ts.map