@specship/specship-win32-arm64 0.25.0 → 0.28.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 (274) 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 +762 -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 +12 -0
  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/enforce/changed-files.d.ts +11 -0
  35. package/lib/dist/enforce/changed-files.d.ts.map +1 -1
  36. package/lib/dist/enforce/changed-files.js +42 -0
  37. package/lib/dist/enforce/changed-files.js.map +1 -1
  38. package/lib/dist/enforce/enforce.d.ts +25 -1
  39. package/lib/dist/enforce/enforce.d.ts.map +1 -1
  40. package/lib/dist/enforce/enforce.js +58 -3
  41. package/lib/dist/enforce/enforce.js.map +1 -1
  42. package/lib/dist/enforce/mutation.d.ts +46 -0
  43. package/lib/dist/enforce/mutation.d.ts.map +1 -0
  44. package/lib/dist/enforce/mutation.js +104 -0
  45. package/lib/dist/enforce/mutation.js.map +1 -0
  46. package/lib/dist/enforce/suppressions.d.ts +33 -0
  47. package/lib/dist/enforce/suppressions.d.ts.map +1 -0
  48. package/lib/dist/enforce/suppressions.js +159 -0
  49. package/lib/dist/enforce/suppressions.js.map +1 -0
  50. package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
  51. package/lib/dist/extraction/specs/markdown-spec-extractor.js +16 -2
  52. package/lib/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
  53. package/lib/dist/graph/spec-coverage.d.ts +57 -1
  54. package/lib/dist/graph/spec-coverage.d.ts.map +1 -1
  55. package/lib/dist/graph/spec-coverage.js +129 -5
  56. package/lib/dist/graph/spec-coverage.js.map +1 -1
  57. package/lib/dist/health/smoke-check.js +2 -2
  58. package/lib/dist/health/smoke-check.js.map +1 -1
  59. package/lib/dist/index.d.ts +8 -3
  60. package/lib/dist/index.d.ts.map +1 -1
  61. package/lib/dist/index.js +65 -9
  62. package/lib/dist/index.js.map +1 -1
  63. package/lib/dist/installer/gemini-commands.d.ts +107 -0
  64. package/lib/dist/installer/gemini-commands.d.ts.map +1 -0
  65. package/lib/dist/installer/gemini-commands.js +264 -0
  66. package/lib/dist/installer/gemini-commands.js.map +1 -0
  67. package/lib/dist/installer/index.d.ts +23 -1
  68. package/lib/dist/installer/index.d.ts.map +1 -1
  69. package/lib/dist/installer/index.js +22 -3
  70. package/lib/dist/installer/index.js.map +1 -1
  71. package/lib/dist/installer/install-defaults.d.ts +19 -0
  72. package/lib/dist/installer/install-defaults.d.ts.map +1 -1
  73. package/lib/dist/installer/install-defaults.js +28 -0
  74. package/lib/dist/installer/install-defaults.js.map +1 -1
  75. package/lib/dist/installer/instructions-template.d.ts +22 -0
  76. package/lib/dist/installer/instructions-template.d.ts.map +1 -1
  77. package/lib/dist/installer/instructions-template.js +37 -1
  78. package/lib/dist/installer/instructions-template.js.map +1 -1
  79. package/lib/dist/installer/targets/claude.d.ts +4 -0
  80. package/lib/dist/installer/targets/claude.d.ts.map +1 -1
  81. package/lib/dist/installer/targets/claude.js +8 -25
  82. package/lib/dist/installer/targets/claude.js.map +1 -1
  83. package/lib/dist/installer/targets/gemini.d.ts +85 -12
  84. package/lib/dist/installer/targets/gemini.d.ts.map +1 -1
  85. package/lib/dist/installer/targets/gemini.js +527 -30
  86. package/lib/dist/installer/targets/gemini.js.map +1 -1
  87. package/lib/dist/installer/targets/shared.d.ts +13 -0
  88. package/lib/dist/installer/targets/shared.d.ts.map +1 -1
  89. package/lib/dist/installer/targets/shared.js +18 -0
  90. package/lib/dist/installer/targets/shared.js.map +1 -1
  91. package/lib/dist/installer/targets/types.d.ts +12 -0
  92. package/lib/dist/installer/targets/types.d.ts.map +1 -1
  93. package/lib/dist/jira/auto-publish.d.ts +71 -4
  94. package/lib/dist/jira/auto-publish.d.ts.map +1 -1
  95. package/lib/dist/jira/auto-publish.js +186 -17
  96. package/lib/dist/jira/auto-publish.js.map +1 -1
  97. package/lib/dist/jira/reconcile.d.ts +24 -1
  98. package/lib/dist/jira/reconcile.d.ts.map +1 -1
  99. package/lib/dist/jira/reconcile.js +46 -2
  100. package/lib/dist/jira/reconcile.js.map +1 -1
  101. package/lib/dist/jira/repo-config.d.ts +9 -0
  102. package/lib/dist/jira/repo-config.d.ts.map +1 -1
  103. package/lib/dist/jira/repo-config.js +11 -0
  104. package/lib/dist/jira/repo-config.js.map +1 -1
  105. package/lib/dist/jira/types.d.ts +7 -0
  106. package/lib/dist/jira/types.d.ts.map +1 -1
  107. package/lib/dist/jira/types.js.map +1 -1
  108. package/lib/dist/knowledge/enforce.d.ts +75 -0
  109. package/lib/dist/knowledge/enforce.d.ts.map +1 -0
  110. package/lib/dist/knowledge/enforce.js +250 -0
  111. package/lib/dist/knowledge/enforce.js.map +1 -0
  112. package/lib/dist/knowledge/facts.d.ts +33 -0
  113. package/lib/dist/knowledge/facts.d.ts.map +1 -0
  114. package/lib/dist/knowledge/facts.js +117 -0
  115. package/lib/dist/knowledge/facts.js.map +1 -0
  116. package/lib/dist/knowledge/proposals.d.ts +88 -0
  117. package/lib/dist/knowledge/proposals.d.ts.map +1 -0
  118. package/lib/dist/knowledge/proposals.js +360 -0
  119. package/lib/dist/knowledge/proposals.js.map +1 -0
  120. package/lib/dist/knowledge/stale.d.ts +64 -0
  121. package/lib/dist/knowledge/stale.d.ts.map +1 -0
  122. package/lib/dist/knowledge/stale.js +174 -0
  123. package/lib/dist/knowledge/stale.js.map +1 -0
  124. package/lib/dist/mcp/gemini-session.d.ts +50 -0
  125. package/lib/dist/mcp/gemini-session.d.ts.map +1 -0
  126. package/lib/dist/mcp/gemini-session.js +159 -0
  127. package/lib/dist/mcp/gemini-session.js.map +1 -0
  128. package/lib/dist/mcp/jira-tools.d.ts.map +1 -1
  129. package/lib/dist/mcp/jira-tools.js +25 -0
  130. package/lib/dist/mcp/jira-tools.js.map +1 -1
  131. package/lib/dist/mcp/model-context.d.ts +22 -9
  132. package/lib/dist/mcp/model-context.d.ts.map +1 -1
  133. package/lib/dist/mcp/model-context.js +35 -13
  134. package/lib/dist/mcp/model-context.js.map +1 -1
  135. package/lib/dist/mcp/proxy.js +1 -1
  136. package/lib/dist/mcp/proxy.js.map +1 -1
  137. package/lib/dist/mcp/server-instructions.d.ts +16 -15
  138. package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
  139. package/lib/dist/mcp/server-instructions.js +67 -1
  140. package/lib/dist/mcp/server-instructions.js.map +1 -1
  141. package/lib/dist/mcp/session.js +1 -1
  142. package/lib/dist/mcp/session.js.map +1 -1
  143. package/lib/dist/mcp/spec-tools.d.ts +9 -1
  144. package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
  145. package/lib/dist/mcp/spec-tools.js +69 -21
  146. package/lib/dist/mcp/spec-tools.js.map +1 -1
  147. package/lib/dist/mcp/tools.d.ts +37 -1
  148. package/lib/dist/mcp/tools.d.ts.map +1 -1
  149. package/lib/dist/mcp/tools.js +120 -9
  150. package/lib/dist/mcp/tools.js.map +1 -1
  151. package/lib/dist/pulse/pulse.d.ts +93 -0
  152. package/lib/dist/pulse/pulse.d.ts.map +1 -0
  153. package/lib/dist/pulse/pulse.js +401 -0
  154. package/lib/dist/pulse/pulse.js.map +1 -0
  155. package/lib/dist/reflect/apply.d.ts.map +1 -1
  156. package/lib/dist/reflect/apply.js +38 -3
  157. package/lib/dist/reflect/apply.js.map +1 -1
  158. package/lib/dist/reflect/auto-sweep.d.ts +26 -0
  159. package/lib/dist/reflect/auto-sweep.d.ts.map +1 -0
  160. package/lib/dist/reflect/auto-sweep.js +90 -0
  161. package/lib/dist/reflect/auto-sweep.js.map +1 -0
  162. package/lib/dist/reflect/cli.d.ts +62 -0
  163. package/lib/dist/reflect/cli.d.ts.map +1 -0
  164. package/lib/dist/reflect/cli.js +163 -0
  165. package/lib/dist/reflect/cli.js.map +1 -0
  166. package/lib/dist/reflect/miner.d.ts.map +1 -1
  167. package/lib/dist/reflect/miner.js +119 -0
  168. package/lib/dist/reflect/miner.js.map +1 -1
  169. package/lib/dist/reflect/sweep.d.ts +1 -0
  170. package/lib/dist/reflect/sweep.d.ts.map +1 -1
  171. package/lib/dist/reflect/sweep.js +62 -13
  172. package/lib/dist/reflect/sweep.js.map +1 -1
  173. package/lib/dist/reflect/targets.d.ts +2 -0
  174. package/lib/dist/reflect/targets.d.ts.map +1 -1
  175. package/lib/dist/reflect/targets.js +33 -0
  176. package/lib/dist/reflect/targets.js.map +1 -1
  177. package/lib/dist/reflect/types.d.ts +19 -2
  178. package/lib/dist/reflect/types.d.ts.map +1 -1
  179. package/lib/dist/resolution/test-title-links.d.ts.map +1 -1
  180. package/lib/dist/resolution/test-title-links.js +3 -14
  181. package/lib/dist/resolution/test-title-links.js.map +1 -1
  182. package/lib/dist/server/routes/claude.js +15 -7
  183. package/lib/dist/server/routes/knowledge.js +118 -0
  184. package/lib/dist/server/server.js +2 -0
  185. package/lib/dist/spec-lint/lint.d.ts +1 -1
  186. package/lib/dist/spec-lint/lint.d.ts.map +1 -1
  187. package/lib/dist/spec-lint/lint.js +63 -2
  188. package/lib/dist/spec-lint/lint.js.map +1 -1
  189. package/lib/dist/spec-quality/criterion-ids.d.ts +13 -0
  190. package/lib/dist/spec-quality/criterion-ids.d.ts.map +1 -0
  191. package/lib/dist/spec-quality/criterion-ids.js +38 -0
  192. package/lib/dist/spec-quality/criterion-ids.js.map +1 -0
  193. package/lib/dist/spec-quality/evidence-kind.d.ts +54 -0
  194. package/lib/dist/spec-quality/evidence-kind.d.ts.map +1 -0
  195. package/lib/dist/spec-quality/evidence-kind.js +183 -0
  196. package/lib/dist/spec-quality/evidence-kind.js.map +1 -0
  197. package/lib/dist/spec-quality/link-persist.d.ts +65 -0
  198. package/lib/dist/spec-quality/link-persist.d.ts.map +1 -0
  199. package/lib/dist/spec-quality/link-persist.js +249 -0
  200. package/lib/dist/spec-quality/link-persist.js.map +1 -0
  201. package/lib/dist/spec-quality/plan-scope.d.ts +38 -0
  202. package/lib/dist/spec-quality/plan-scope.d.ts.map +1 -0
  203. package/lib/dist/spec-quality/plan-scope.js +129 -0
  204. package/lib/dist/spec-quality/plan-scope.js.map +1 -0
  205. package/lib/dist/spec-quality/postcheck.d.ts +85 -0
  206. package/lib/dist/spec-quality/postcheck.d.ts.map +1 -0
  207. package/lib/dist/spec-quality/postcheck.js +390 -0
  208. package/lib/dist/spec-quality/postcheck.js.map +1 -0
  209. package/lib/dist/spec-quality/readiness.d.ts +72 -0
  210. package/lib/dist/spec-quality/readiness.d.ts.map +1 -0
  211. package/lib/dist/spec-quality/readiness.js +226 -0
  212. package/lib/dist/spec-quality/readiness.js.map +1 -0
  213. package/lib/dist/workflows/agents/claude.d.ts +16 -0
  214. package/lib/dist/workflows/agents/claude.d.ts.map +1 -0
  215. package/lib/dist/workflows/agents/claude.js +82 -0
  216. package/lib/dist/workflows/agents/claude.js.map +1 -0
  217. package/lib/dist/workflows/agents/gemini.d.ts +21 -0
  218. package/lib/dist/workflows/agents/gemini.d.ts.map +1 -0
  219. package/lib/dist/workflows/agents/gemini.js +124 -0
  220. package/lib/dist/workflows/agents/gemini.js.map +1 -0
  221. package/lib/dist/workflows/agents/index.d.ts +28 -0
  222. package/lib/dist/workflows/agents/index.d.ts.map +1 -0
  223. package/lib/dist/workflows/agents/index.js +104 -0
  224. package/lib/dist/workflows/agents/index.js.map +1 -0
  225. package/lib/dist/workflows/agents/types.d.ts +55 -0
  226. package/lib/dist/workflows/agents/types.d.ts.map +1 -0
  227. package/lib/dist/workflows/agents/types.js +46 -0
  228. package/lib/dist/workflows/agents/types.js.map +1 -0
  229. package/lib/dist/workflows/batch.d.ts +63 -0
  230. package/lib/dist/workflows/batch.d.ts.map +1 -0
  231. package/lib/dist/workflows/batch.js +151 -0
  232. package/lib/dist/workflows/batch.js.map +1 -0
  233. package/lib/dist/workflows/defaults/claude-design-implement.yaml +3 -4
  234. package/lib/dist/workflows/defaults/spec-author.yaml +11 -9
  235. package/lib/dist/workflows/defaults/spec-implement-mixed.yaml +21 -436
  236. package/lib/dist/workflows/defaults/spec-implement.yaml +465 -46
  237. package/lib/dist/workflows/discovery.d.ts +13 -0
  238. package/lib/dist/workflows/discovery.d.ts.map +1 -1
  239. package/lib/dist/workflows/discovery.js +79 -17
  240. package/lib/dist/workflows/discovery.js.map +1 -1
  241. package/lib/dist/workflows/executor.d.ts +18 -0
  242. package/lib/dist/workflows/executor.d.ts.map +1 -1
  243. package/lib/dist/workflows/executor.js +130 -33
  244. package/lib/dist/workflows/executor.js.map +1 -1
  245. package/lib/dist/workflows/gc.d.ts +50 -0
  246. package/lib/dist/workflows/gc.d.ts.map +1 -0
  247. package/lib/dist/workflows/gc.js +120 -0
  248. package/lib/dist/workflows/gc.js.map +1 -0
  249. package/lib/dist/workflows/merge-queue.d.ts +64 -0
  250. package/lib/dist/workflows/merge-queue.d.ts.map +1 -0
  251. package/lib/dist/workflows/merge-queue.js +162 -0
  252. package/lib/dist/workflows/merge-queue.js.map +1 -0
  253. package/lib/dist/workflows/runners/approval.d.ts +1 -1
  254. package/lib/dist/workflows/runners/approval.d.ts.map +1 -1
  255. package/lib/dist/workflows/runners/approval.js +11 -2
  256. package/lib/dist/workflows/runners/approval.js.map +1 -1
  257. package/lib/dist/workflows/runners/bash.d.ts +15 -0
  258. package/lib/dist/workflows/runners/bash.d.ts.map +1 -1
  259. package/lib/dist/workflows/runners/bash.js +50 -1
  260. package/lib/dist/workflows/runners/bash.js.map +1 -1
  261. package/lib/dist/workflows/runners/prompt.d.ts +16 -41
  262. package/lib/dist/workflows/runners/prompt.d.ts.map +1 -1
  263. package/lib/dist/workflows/runners/prompt.js +55 -120
  264. package/lib/dist/workflows/runners/prompt.js.map +1 -1
  265. package/lib/dist/workflows/runners/types.d.ts +12 -0
  266. package/lib/dist/workflows/runners/types.d.ts.map +1 -1
  267. package/lib/dist/workflows/schemas/workflow.d.ts +17 -0
  268. package/lib/dist/workflows/schemas/workflow.d.ts.map +1 -1
  269. package/lib/dist/workflows/schemas/workflow.js +27 -0
  270. package/lib/dist/workflows/schemas/workflow.js.map +1 -1
  271. package/lib/node_modules/.package-lock.json +1 -1
  272. package/lib/package.json +2 -2
  273. package/package.json +5 -3
  274. package/node.exe +0 -4
@@ -14,8 +14,9 @@ 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.
19
20
 
20
21
  JIRA-backed specs (REQ-JIRAPUB-004): if the spec file's frontmatter
21
22
  carries a `jira_issue:` key, EVERY git commit message you write for this
@@ -41,9 +42,30 @@ nodes:
41
42
  (b) which code areas / symbols are most relevant, and (c) whether
42
43
  any code currently claims to implement it (look at linked_code).
43
44
 
45
+ - id: readiness
46
+ kind: bash
47
+ depends_on: [fetch_spec]
48
+ output_type: readiness_report
49
+ timeout: 120000
50
+ bash: |
51
+ # REQ-PIPETRUST-004 — implement must not start on a spec that is not
52
+ # ready (lint errors, no criteria, a criterion still [needs review]).
53
+ # Also records the run's base commit so postcheck can diff against it.
54
+ git rev-parse HEAD > "$(git rev-parse --git-dir)/specship-run-base" 2>/dev/null || true
55
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
56
+ elif command -v specship >/dev/null 2>&1; then SS=specship
57
+ elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
58
+ else SS=""
59
+ fi
60
+ if [ -z "$SS" ]; then
61
+ echo "READY=unavailable — specship CLI not found; the readiness gate did NOT run"
62
+ exit 1
63
+ fi
64
+ $SS ready $INPUT.SPEC_ID --path .
65
+
44
66
  - id: plan
45
67
  kind: prompt
46
- depends_on: [fetch_spec]
68
+ depends_on: [fetch_spec, readiness]
47
69
  output_type: plan
48
70
  allowed_tools:
49
71
  - mcp__specship__specship_explore
@@ -55,6 +77,17 @@ nodes:
55
77
 
56
78
  $fetch_spec.output
57
79
 
80
+ Readiness + evidence plan (every acceptance criterion needs a test of
81
+ the stated kind, written as a NAMED function passed to it() with the
82
+ criterion id in its title):
83
+ $readiness.output
84
+
85
+ Domain facts that `specship_spec` returns with the requirement are
86
+ constraints, not background: honour each external fact's verified
87
+ version, and treat every `## Enforced` rule (`<glob>` must not match
88
+ `/<regex>/`) as a hard constraint — `specship knowledge check` fails the
89
+ run on a violation (REQ-KNOW-005).
90
+
58
91
  The plan should list:
59
92
  - Files to create or modify (with project-relative paths)
60
93
  - Specific functions/methods/classes to add or change
@@ -63,23 +96,93 @@ nodes:
63
96
 
64
97
  Keep it tight (≤500 words). Do NOT edit code in this step.
65
98
 
99
+ - id: plan_scope
100
+ kind: bash
101
+ depends_on: [plan]
102
+ output_type: plan_scope
103
+ bash: |
104
+ # REQ-THRU-003 — opt-in auto-approval of a small, in-scope plan. Prints
105
+ # AUTO_APPROVE=yes only when specship.config.json opts in, the plan
106
+ # names only the requirement's implementation files (plus tests, its
107
+ # spec and CHANGELOG.md), and the requirement has few criteria.
108
+ PLAN=$plan.output
109
+ F="$(mktemp)"
110
+ printf '%s\n' "$PLAN" > "$F"
111
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" plan-scope $INPUT.SPEC_ID --plan-file "$F" --path .
112
+ elif command -v specship >/dev/null 2>&1; then specship plan-scope $INPUT.SPEC_ID --plan-file "$F" --path . || echo "AUTO_APPROVE=no"
113
+ else echo "AUTO_APPROVE=no"; echo "- specship CLI not found"
114
+ fi
115
+ rm -f "$F"
116
+
66
117
  - id: approve_plan
67
118
  kind: approval
68
- depends_on: [plan]
119
+ depends_on: [plan, plan_scope]
120
+ auto_approve:
121
+ from: plan_scope
122
+ marker: AUTO_APPROVE=yes
69
123
  message: |
70
124
  Plan ready for $INPUT.SPEC_ID. Review the plan output and approve
71
125
  to proceed with implementation, or reject with feedback to revise.
72
126
  capture_response: true
73
127
  on_reject:
128
+ # The reviewer's rejection reason is appended to this prompt
129
+ # automatically; the revision replaces $plan.output downstream.
74
130
  prompt: |
75
- The plan was rejected with this feedback. Revise:
131
+ The plan was rejected (feedback follows). Revise the plan to
132
+ address it and output the full revised plan.
76
133
 
77
- $approve_plan.output
134
+ Current plan:
135
+ $plan.output
136
+ revises: plan
78
137
  max_attempts: 3
79
138
 
139
+ - id: quality_baseline
140
+ kind: bash
141
+ depends_on: [approve_plan]
142
+ output_type: quality_report
143
+ timeout: 600000
144
+ bash: |
145
+ # REQ-AUTHG-008.A1 — run the project's quality command BEFORE implement
146
+ # edits anything, so the gate can tell errors this change introduced
147
+ # from errors the worktree already had (a sub-package with no built
148
+ # parent, known lint debt). The baseline lives under the worktree's git
149
+ # dir, so it never shows up in the diff. It is written ONLY when the
150
+ # pre-change command fails: a clean baseline means any later failure is
151
+ # the change's, so the gate keeps its full strictness (A5 fallback).
152
+ 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; }
153
+ BASELINE="$(git rev-parse --git-dir 2>/dev/null)/specship-quality-baseline.txt"
154
+ rm -f "$BASELINE"
155
+ QUALITY_CMD=""
156
+ if [ -f package.json ]; then
157
+ if [ ! -d node_modules ]; then
158
+ npm ci --no-audit --no-fund >/dev/null 2>&1 || npm install --no-audit --no-fund >/dev/null 2>&1 || true
159
+ fi
160
+ if node -e 'const s=(require("./package.json").scripts)||{};process.exit(s.lint?0:1)' 2>/dev/null; then
161
+ QUALITY_CMD="npm run lint --if-present"
162
+ elif [ -f tsconfig.json ]; then
163
+ QUALITY_CMD="npx --no-install tsc --noEmit"
164
+ fi
165
+ elif [ -f Cargo.toml ]; then
166
+ if command -v cargo >/dev/null 2>&1; then QUALITY_CMD="cargo clippy --no-deps"; fi
167
+ elif [ -f pyproject.toml ] || [ -f requirements.txt ]; then
168
+ if command -v ruff >/dev/null 2>&1; then QUALITY_CMD="ruff check ."; fi
169
+ fi
170
+ if [ -z "$QUALITY_CMD" ]; then
171
+ echo "QUALITY_BASELINE=skipped"
172
+ exit 0
173
+ fi
174
+ if OUT=$($QUALITY_CMD 2>&1); then
175
+ echo "QUALITY_BASELINE=clean"
176
+ else
177
+ printf '%s\n' "$OUT" | qnorm > "$BASELINE"
178
+ echo "QUALITY_BASELINE=recorded"
179
+ echo "QUALITY_BASELINE_LINES=$(wc -l < "$BASELINE" | tr -d ' ')"
180
+ fi
181
+ exit 0
182
+
80
183
  - id: implement
81
184
  kind: prompt
82
- depends_on: [approve_plan]
185
+ depends_on: [approve_plan, quality_baseline]
83
186
  output_type: diff
84
187
  allowed_tools:
85
188
  - Read
@@ -92,12 +195,23 @@ nodes:
92
195
  prompt: |
93
196
  Implement the approved plan. Follow it closely.
94
197
 
198
+ Domain facts that `specship_spec` returns with the requirement are
199
+ constraints, not background: honour each external fact's verified
200
+ version, and treat every `## Enforced` rule (`<glob>` must not match
201
+ `/<regex>/`) as a hard constraint — `specship knowledge check` fails the
202
+ run on a violation (REQ-KNOW-005).
203
+
95
204
  Plan:
96
205
  $plan.output
97
206
 
98
207
  Approval feedback (if any):
99
208
  $approve_plan.output
100
209
 
210
+ Readiness + evidence plan (every acceptance criterion needs a test of
211
+ the stated kind, written as a NAMED function passed to it() with the
212
+ criterion id in its title):
213
+ $readiness.output
214
+
101
215
  When done, output a short diff summary (which files changed and why).
102
216
 
103
217
  - id: quality_gate
@@ -135,8 +249,26 @@ nodes:
135
249
  exit 0
136
250
  fi
137
251
  echo "QUALITY_CMD=$QUALITY_CMD"
252
+ 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; }
253
+ BASELINE="$(git rev-parse --git-dir 2>/dev/null)/specship-quality-baseline.txt"
138
254
  if OUT=$($QUALITY_CMD 2>&1); then
139
255
  echo "QUALITY_GATE=passed"
256
+ elif [ -f "$BASELINE" ]; then
257
+ # REQ-AUTHG-008.A2/A3 — judge only error lines absent from the
258
+ # pre-change baseline; report pre-existing ones, never hide them.
259
+ NEW=$(printf '%s\n' "$OUT" | qnorm | comm -13 "$BASELINE" - | grep -iE 'error' || true)
260
+ PRE=$(printf '%s\n' "$OUT" | qnorm | comm -12 "$BASELINE" - | grep -ciE 'error' || true)
261
+ if [ -z "$NEW" ]; then
262
+ echo "QUALITY_GATE=passed"
263
+ echo "QUALITY_PREEXISTING=$PRE"
264
+ echo "Pre-existing errors (already failing before implement; not caused by this change), sample:"
265
+ printf '%s\n' "$OUT" | grep -iE 'error' | head -n 5
266
+ else
267
+ echo "QUALITY_GATE=failed"
268
+ echo "QUALITY_PREEXISTING=$PRE"
269
+ echo "New errors introduced by this change:"
270
+ printf '%s\n' "$NEW" | tail -n 80
271
+ fi
140
272
  else
141
273
  echo "QUALITY_GATE=failed"
142
274
  printf '%s\n' "$OUT" | tail -n 80
@@ -194,14 +326,142 @@ nodes:
194
326
  echo "QUALITY_RESULT=clean"
195
327
  exit 0
196
328
  fi
197
- echo "QUALITY_RESULT=failed"
198
- printf '%s\n' "$OUT" | tail -n 80
329
+ 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; }
330
+ BASELINE="$(git rev-parse --git-dir 2>/dev/null)/specship-quality-baseline.txt"
331
+ if [ -f "$BASELINE" ]; then
332
+ # REQ-AUTHG-008.A2/A3 — only errors absent from the baseline halt.
333
+ NEW=$(printf '%s\n' "$OUT" | qnorm | comm -13 "$BASELINE" - | grep -iE 'error' || true)
334
+ if [ -z "$NEW" ]; then
335
+ echo "QUALITY_RESULT=clean"
336
+ echo "QUALITY_PREEXISTING=$(printf '%s\n' "$OUT" | qnorm | comm -12 "$BASELINE" - | grep -ciE 'error' || true)"
337
+ exit 0
338
+ fi
339
+ echo "QUALITY_RESULT=failed"
340
+ printf '%s\n' "$NEW" | tail -n 80
341
+ else
342
+ echo "QUALITY_RESULT=failed"
343
+ printf '%s\n' "$OUT" | tail -n 80
344
+ fi
199
345
  echo "HALT_CAUSE=lint/typecheck still fails after the fix attempt — the change is not reviewable yet"
200
346
  exit 1
201
347
 
202
- - id: diff
348
+ - id: postcheck
203
349
  kind: bash
204
350
  depends_on: [quality_recheck]
351
+ output_type: postcheck_report
352
+ timeout: 600000
353
+ bash: |
354
+ # REQ-PIPETRUST-005 — check the agent's work mechanically: verifies
355
+ # bullets are real named test symbols covering every criterion, a src
356
+ # change has a CHANGELOG entry, and project-configured checks pass
357
+ # (their fix commands run first). Exit 0 always: the POSTCHECK marker
358
+ # routes the fix step; postcheck_recheck is what halts.
359
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
360
+ elif command -v specship >/dev/null 2>&1; then SS=specship
361
+ elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
362
+ else SS=""
363
+ fi
364
+ if [ -z "$SS" ]; then
365
+ echo "POSTCHECK=failed"
366
+ echo "specship CLI not found — postcheck did NOT run"
367
+ exit 0
368
+ fi
369
+ $SS postcheck $INPUT.SPEC_ID --path . --fix || true
370
+
371
+ - id: fix_postcheck
372
+ kind: prompt
373
+ depends_on: [postcheck]
374
+ output_type: postcheck_fix
375
+ allowed_tools:
376
+ - Read
377
+ - Edit
378
+ - Write
379
+ - Bash
380
+ - mcp__specship__specship_spec
381
+ prompt: |
382
+ Mechanical post-implement check for $INPUT.SPEC_ID:
383
+
384
+ $postcheck.output
385
+
386
+ Route on the POSTCHECK marker — do not re-judge:
387
+
388
+ - POSTCHECK=passed → change NOTHING. Output exactly
389
+ `FIX_POSTCHECK=not-needed` and stop.
390
+ - POSTCHECK=failed → fix every ✗ finding:
391
+ - [verifies] — every acceptance criterion needs a test written as a
392
+ NAMED function passed to it(), with the criterion id in the it()
393
+ title, listed under the requirement's `verifies:` block in its spec
394
+ file as `path:FunctionName` (never an it() title string).
395
+ - [changelog] — add a plain-sentence, user-facing entry under
396
+ `## [Unreleased]` in CHANGELOG.md (no internal paths or symbols).
397
+ - [command] — make the named check pass by fixing the cause.
398
+ A bash step re-runs postcheck after you; any finding left halts the run.
399
+
400
+ Output `FIX_POSTCHECK=fixed` or `FIX_POSTCHECK=still-failing` followed
401
+ by what remains.
402
+
403
+ - id: postcheck_recheck
404
+ kind: bash
405
+ depends_on: [fix_postcheck]
406
+ output_type: postcheck_result
407
+ timeout: 600000
408
+ bash: |
409
+ # REQ-PIPETRUST-005.A5 — the authoritative half: re-run and halt while
410
+ # anything still fails, so an unlinked or undocumented change never
411
+ # reaches verify or the human gate.
412
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
413
+ elif command -v specship >/dev/null 2>&1; then SS=specship
414
+ elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
415
+ else SS=""
416
+ fi
417
+ if [ -z "$SS" ]; then
418
+ echo "POSTCHECK_RESULT=failed"
419
+ echo "HALT_CAUSE=specship CLI not found — postcheck did NOT run"
420
+ exit 1
421
+ fi
422
+ if OUT=$($SS postcheck $INPUT.SPEC_ID --path . 2>&1); then
423
+ echo "POSTCHECK_RESULT=clean"
424
+ printf '%s\n' "$OUT"
425
+ exit 0
426
+ fi
427
+ echo "POSTCHECK_RESULT=failed"
428
+ printf '%s\n' "$OUT"
429
+ echo "HALT_CAUSE=postcheck still fails after the fix attempt — the change is not reviewable yet"
430
+ exit 1
431
+
432
+ - id: suppression_gate
433
+ kind: bash
434
+ depends_on: [postcheck_recheck]
435
+ output_type: suppression_report
436
+ bash: |
437
+ # REQ-QGATE-004.A3 — deterministic scan for lint/type suppression
438
+ # comments the change introduces (noqa, eslint-disable, @ts-ignore, …).
439
+ # The fix_quality prompt forbids silencing rules; this node enforces it
440
+ # in code. SUPPRESSION_GATE is the marker contract: a scan that could
441
+ # not run is `skipped`, never `clean`.
442
+ # REQ-PIPETRUST-006.A4 — prefer the CLI running this workflow over any
443
+ # (possibly older) `specship` on PATH.
444
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
445
+ elif command -v specship >/dev/null 2>&1; then SS=specship
446
+ elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
447
+ elif [ -x dist/bin/specship.js ]; then SS="node dist/bin/specship.js"
448
+ else SS=""; fi
449
+ if [ -z "$SS" ]; then
450
+ echo "SUPPRESSION_GATE=skipped"
451
+ echo "SUPPRESSION_REASON=specship CLI not found — suppression scan did NOT run"
452
+ exit 0
453
+ fi
454
+ if OUT=$($SS suppressions 2>&1); then
455
+ printf '%s\n' "$OUT"
456
+ else
457
+ printf '%s\n' "$OUT"
458
+ echo "HALT_CAUSE=the change introduces lint/type suppression comments — fix the code instead of silencing the rule"
459
+ exit 1
460
+ fi
461
+
462
+ - id: diff
463
+ kind: bash
464
+ depends_on: [suppression_gate]
205
465
  output_type: diff
206
466
  bash: |
207
467
  # REQ-AUTHG-004.A1 — the full diff, from git, into a run artifact. The
@@ -252,7 +512,16 @@ nodes:
252
512
  fi
253
513
  fi
254
514
  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
515
+ # REQ-PIPETRUST-006.A3 — a vitest project also leaves a JSON report in
516
+ # the run's artifacts, ingestible with `specship verify --report`.
517
+ TEST_ARGS=""
518
+ 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
519
+ mkdir -p "$SPECSHIP_ARTIFACTS_DIR"
520
+ REPORT="$SPECSHIP_ARTIFACTS_DIR/test-report.json"
521
+ TEST_ARGS="-- --reporter=default --reporter=json --outputFile.json=$REPORT"
522
+ echo "VERIFY_REPORT=$REPORT (ingest after merge: specship verify --report $REPORT)"
523
+ fi
524
+ if npm test $TEST_ARGS; then echo "VERIFY_RESULT=ran-and-passed"; else echo "VERIFY_RESULT=ran-and-failed"; exit 1; fi
256
525
  elif [ -f Cargo.toml ]; then
257
526
  if ! cargo build; then echo "VERIFY_RESULT=build-failed"; exit 1; fi
258
527
  if cargo test; then echo "VERIFY_RESULT=ran-and-passed"; else echo "VERIFY_RESULT=ran-and-failed"; exit 1; fi
@@ -302,49 +571,47 @@ nodes:
302
571
  depends_on: [route_verify]
303
572
  output_type: link_summary
304
573
  allowed_tools:
305
- - mcp__specship__specship_link_assert
306
- - mcp__specship__specship_link_verify
574
+ - Read
575
+ - Edit
307
576
  - mcp__specship__specship_spec
308
577
  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:
578
+ Record spec→code links for the changes made in the implement step —
579
+ durably, in the spec file (REQ-PIPETRUST-006). Do NOT call
580
+ specship_link_assert or specship_link_verify: runtime links vanish on a
581
+ full reindex, and a headless run cannot be granted them.
582
+
583
+ Open the spec file that declares $INPUT.SPEC_ID. Under the requirement:
584
+ - `implementations:` — one `path:Symbol` bullet per symbol that
585
+ implements it (qualified `Class.method` for methods). Add any that
586
+ are missing; never duplicate an existing bullet.
587
+ - `verifies:` — leave as the postcheck step left it (named test
588
+ functions only). Never add an it() title string.
589
+
590
+ You MUST NOT assert a `tests`-kind link (REQ-REVINT-005.A1) —
591
+ never pass kind: 'tests', and never mint test evidence: it comes only
592
+ from the spec's `verifies:` block or an `@verifies` comment on a test
593
+ symbol.
594
+
595
+ Verification state is not yours to set, so you
596
+ do NOT call specship_link_verify, whatever LINK_ACTION says. On
597
+ LINK_ACTION=assert-and-verify-pass, LINK_ACTION=assert-and-verify-fail
598
+ or LINK_ACTION=assert-only alike, record the implementations bullets
599
+ only: tests that ran are in the run's JSON test report (see the verify
600
+ output) and are ingested with `specship verify --report` after the
601
+ branch merges; tests that did not run are never reported as passing.
602
+
603
+ Routing context (computed by a bash node from VERIFY_RESULT):
325
604
 
326
605
  $route_verify.output
327
606
 
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
607
  Implementation diff summary:
340
608
  $implement.output
341
609
 
342
610
  Test results:
343
611
  $verify.output
344
612
 
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.
613
+ Output: a short list of "spec_id → file:symbol" lines you recorded,
614
+ ending with the VERIFY_REPORT line from the verify output if present.
348
615
 
349
616
  - id: coverage
350
617
  kind: bash
@@ -356,7 +623,10 @@ nodes:
356
623
  # `getSpecCoverage` report the MCP tool and the dashboard read, so the
357
624
  # number on the approval gate cannot disagree with them. It used to be
358
625
  # counted by a prompt.
359
- if command -v specship >/dev/null 2>&1; then SS=specship
626
+ # REQ-PIPETRUST-006.A4 — prefer the CLI running this workflow over any
627
+ # (possibly older) `specship` on PATH.
628
+ if [ -n "$SPECSHIP_CLI_SCRIPT" ]; then ss_cli() { "$SPECSHIP_CLI_NODE" "$SPECSHIP_CLI_SCRIPT" "$@"; }; SS=ss_cli
629
+ elif command -v specship >/dev/null 2>&1; then SS=specship
360
630
  elif [ -x node_modules/.bin/specship ]; then SS=node_modules/.bin/specship
361
631
  elif [ -x dist/bin/specship.js ]; then SS="node dist/bin/specship.js"
362
632
  else SS=""; fi
@@ -409,9 +679,144 @@ nodes:
409
679
  3. `Verdict:` one line — the most serious gap a reviewer should look at
410
680
  first, or `no gaps found`.
411
681
 
682
+ - id: probe_baseline
683
+ kind: bash
684
+ depends_on: [adversarial_review]
685
+ output_type: probe_baseline
686
+ bash: |
687
+ # REQ-THRU-008 — fingerprint every tracked change before the probe step,
688
+ # so the guard can prove the probes touched nothing tracked.
689
+ git add -A -N >/dev/null 2>&1 || true
690
+ git --no-pager diff HEAD | git hash-object --stdin > "$(git rev-parse --git-dir)/specship-probe-baseline"
691
+ echo "PROBE_BASELINE=recorded"
692
+
693
+ - id: review_probes
694
+ kind: prompt
695
+ depends_on: [probe_baseline]
696
+ output_type: review_probes
697
+ allowed_tools:
698
+ - Read
699
+ - Write
700
+ - Bash
701
+ - mcp__specship__specship_spec
702
+ prompt: |
703
+ Try to BREAK the change for $INPUT.SPEC_ID (REQ-THRU-008). You are not
704
+ the implementer. For EACH acceptance criterion write at least one small
705
+ probe test that would fail if the criterion were not really met — an
706
+ edge case, a boundary, a negative case — ONLY under
707
+ `.specship/review-probes/` (create it). NEVER edit any tracked file: a
708
+ guard step fails the run if you do.
709
+
710
+ Run each probe with the project's test runner. Report one line per
711
+ criterion: `<AC id>: held | broke | unrun — <probe file> — <one
712
+ sentence>`. `unrun` means the probe could not be executed (say why);
713
+ never report a probe you did not run as held.
714
+
715
+ The read-only review already found:
716
+ $adversarial_review.output
717
+
718
+ The change (from git):
719
+ $diff.output
720
+
721
+ - id: review_guard
722
+ kind: bash
723
+ depends_on: [review_probes]
724
+ output_type: review_guard
725
+ bash: |
726
+ # REQ-THRU-008.A2 — the probe step may not change tracked files.
727
+ git add -A -N >/dev/null 2>&1 || true
728
+ NOW=$(git --no-pager diff HEAD | git hash-object --stdin)
729
+ BEFORE=$(cat "$(git rev-parse --git-dir)/specship-probe-baseline" 2>/dev/null)
730
+ if [ -n "$BEFORE" ] && [ "$NOW" != "$BEFORE" ]; then
731
+ echo "REVIEW_GUARD=failed"
732
+ echo "HALT_CAUSE=the probe step changed tracked files — probes belong under .specship/review-probes/"
733
+ git --no-pager diff --stat HEAD
734
+ exit 1
735
+ fi
736
+ echo "REVIEW_GUARD=clean"
737
+
738
+ - id: knowledge_proposals
739
+ kind: prompt
740
+ depends_on: [review_guard]
741
+ output_type: knowledge_proposals
742
+ allowed_tools:
743
+ - Read
744
+ - Write
745
+ - mcp__specship__specship_spec
746
+ - mcp__specship__specship_explore
747
+ prompt: |
748
+ Propose knowledge this change relied on, for a HUMAN to confirm
749
+ (REQ-KNOW-004). Domain knowledge is human-confirmed, never
750
+ auto-extracted (DOM-SPECSHIP-003): you only PROPOSE.
751
+
752
+ Write 0–5 proposal files, one fact each, ONLY under
753
+ `.specship/knowledge/proposals/` (create the directory). NEVER edit
754
+ `specs/domain/` or any tracked file. Each file is a domain fact:
755
+
756
+ ---
757
+ title: <short name>
758
+ type: term | rule | decision | constraint | external
759
+ area: <AREA, e.g. the prefix used by existing DOM-<AREA>-NNN facts>
760
+ depends_on: $INPUT.SPEC_ID
761
+ # external facts ONLY — verified from the installed dependency, not memory:
762
+ dependency: <package or tool name>
763
+ version: <installed version you verified against>
764
+ source: <file and symbol in that dependency>
765
+ ---
766
+
767
+ # <title>
768
+
769
+ <one paragraph: the fact, stated plainly>
770
+
771
+ ## Enforced (optional — only for a mechanically checkable rule)
772
+ - `<glob>` must not match `/<regex>/`
773
+
774
+ Propose only what this change actually depended on and a future change
775
+ would otherwise rediscover — especially facts about third-party tools.
776
+ If there is nothing worth keeping, write no files.
777
+
778
+ Implementation diff summary:
779
+ $implement.output
780
+
781
+ Output one line per proposal file you wrote, or `NO_PROPOSALS`.
782
+
783
+ - id: knowledge_publish
784
+ kind: bash
785
+ depends_on: [knowledge_proposals]
786
+ output_type: knowledge_report
787
+ bash: |
788
+ # REQ-KNOW-004.A1 — the proposal step may write ONLY proposals. Any
789
+ # change under specs/domain/ halts the run. Proposals are then copied to
790
+ # the main project's .specship/knowledge/proposals/ (a run worktree's
791
+ # .specship/ is gitignored and would vanish), where
792
+ # `specship knowledge proposals` / `apply` / `reject` find them.
793
+ if [ -n "$(git status --porcelain -- specs/domain 2>/dev/null)" ]; then
794
+ echo "KNOWLEDGE_PROPOSALS=refused"
795
+ echo "HALT_CAUSE=the knowledge step changed specs/domain/ — only a human applies knowledge"
796
+ git status --porcelain -- specs/domain
797
+ exit 1
798
+ fi
799
+ SRC=".specship/knowledge/proposals"
800
+ N=0
801
+ if [ -d "$SRC" ]; then N=$(ls "$SRC"/*.md 2>/dev/null | wc -l | tr -d ' '); fi
802
+ echo "KNOWLEDGE_PROPOSALS=$N"
803
+ if [ "$N" -gt 0 ] && [ -n "$SPECSHIP_ARTIFACTS_DIR" ]; then
804
+ DEST="$(cd "$SPECSHIP_ARTIFACTS_DIR/../../.." 2>/dev/null && pwd)/knowledge/proposals"
805
+ mkdir -p "$DEST"
806
+ for f in "$SRC"/*.md; do
807
+ base=$(basename "$f")
808
+ target="$DEST/$base"
809
+ i=2
810
+ while [ -e "$target" ]; do target="$DEST/${base%.md}-$i.md"; i=$((i+1)); done
811
+ cp "$f" "$target"
812
+ echo "- $(basename "$target") ($(sed -n 's/^title: //p' "$f" | head -1))"
813
+ done
814
+ echo "Review with: specship knowledge proposals · apply <id> · reject <id>"
815
+ fi
816
+
412
817
  - id: final_review
413
818
  kind: approval
414
- depends_on: [adversarial_review]
819
+ depends_on: [adversarial_review, knowledge_publish]
415
820
  message: |
416
821
  Implementation complete for $INPUT.SPEC_ID.
417
822
 
@@ -421,7 +826,14 @@ nodes:
421
826
  Lint / typecheck:
422
827
  $quality_recheck.output
423
828
 
424
- Links asserted:
829
+ Mechanical postcheck (verifies symbols, CHANGELOG, project checks):
830
+ $postcheck_recheck.output
831
+
832
+ Suppression scan (new noqa / eslint-disable / @ts-ignore):
833
+ $suppression_gate.output
834
+
835
+ Links recorded in the spec (ingest the test report after merge with the
836
+ `specship verify --report` command named here):
425
837
  $link.output
426
838
 
427
839
  Acceptance-criteria test coverage:
@@ -430,5 +842,12 @@ nodes:
430
842
  Adversarial review:
431
843
  $adversarial_review.output
432
844
 
845
+ Review probes (held | broke | unrun per criterion):
846
+ $review_probes.output
847
+
848
+ Knowledge proposals (nothing is applied until you run
849
+ `specship knowledge apply <id>`):
850
+ $knowledge_publish.output
851
+
433
852
  Approve to finalize the run (worktree is left for you to inspect
434
853
  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
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/workflows/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EACL,kBAAkB,EAElB,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,uCAAuC;IACvC,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,CAoCzE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,kBAAkB,GAAG,IAAI,CAG3B"}
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/workflows/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EACL,kBAAkB,EAElB,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,uCAAuC;IACvC,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,CA4CzE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,kBAAkB,GAAG,IAAI,CAG3B;AAuFD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC9D,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,GAC5B;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,CAAA;CAAE,CAiChE"}