gsd-pi 2.76.0 → 2.77.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 (536) hide show
  1. package/README.md +45 -25
  2. package/dist/claude-cli-check.js +32 -3
  3. package/dist/mcp-server.d.ts +7 -0
  4. package/dist/mcp-server.js +35 -1
  5. package/dist/onboarding.js +45 -0
  6. package/dist/resource-loader.d.ts +1 -1
  7. package/dist/resource-loader.js +2 -8
  8. package/dist/resources/agents/researcher.md +1 -1
  9. package/dist/resources/extensions/claude-code-cli/readiness.js +31 -8
  10. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  11. package/dist/resources/extensions/gsd/auto/loop.js +9 -0
  12. package/dist/resources/extensions/gsd/auto/phases.js +104 -11
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
  14. package/dist/resources/extensions/gsd/auto/session.js +22 -1
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
  16. package/dist/resources/extensions/gsd/auto-model-selection.js +53 -16
  17. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
  18. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  19. package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
  20. package/dist/resources/extensions/gsd/auto-start.js +58 -57
  21. package/dist/resources/extensions/gsd/auto-verification.js +33 -0
  22. package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
  23. package/dist/resources/extensions/gsd/auto.js +70 -28
  24. package/dist/resources/extensions/gsd/blocked-models.js +68 -0
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +93 -1
  26. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  27. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  28. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +3 -0
  29. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +12 -0
  30. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
  31. package/dist/resources/extensions/gsd/bootstrap/system-context.js +84 -23
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  33. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  34. package/dist/resources/extensions/gsd/commands-extract-learnings.js +54 -89
  35. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  36. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  37. package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
  38. package/dist/resources/extensions/gsd/db-writer.js +88 -16
  39. package/dist/resources/extensions/gsd/doctor-git-checks.js +23 -29
  40. package/dist/resources/extensions/gsd/doctor-providers.js +51 -5
  41. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +1 -0
  42. package/dist/resources/extensions/gsd/error-classifier.js +31 -3
  43. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  44. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  45. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +168 -23
  47. package/dist/resources/extensions/gsd/guided-flow.js +190 -1
  48. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  49. package/dist/resources/extensions/gsd/hook-emitter.js +108 -0
  50. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  51. package/dist/resources/extensions/gsd/key-manager.js +28 -0
  52. package/dist/resources/extensions/gsd/memory-backfill.js +126 -0
  53. package/dist/resources/extensions/gsd/memory-store.js +19 -0
  54. package/dist/resources/extensions/gsd/model-router.js +36 -3
  55. package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
  56. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  57. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  58. package/dist/resources/extensions/gsd/preferences.js +17 -17
  59. package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
  60. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  62. package/dist/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  63. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  64. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  65. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
  66. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  67. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  68. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -0
  69. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  70. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  71. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  72. package/dist/resources/extensions/gsd/state.js +43 -4
  73. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  74. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  75. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  76. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  77. package/dist/resources/extensions/gsd/tools/memory-tools.js +26 -1
  78. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  79. package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
  80. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  81. package/dist/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  82. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  83. package/dist/resources/extensions/search-the-web/command-search-provider.js +5 -4
  84. package/dist/resources/extensions/search-the-web/native-search.js +45 -13
  85. package/dist/resources/skills/api-design/SKILL.md +190 -0
  86. package/dist/resources/skills/create-mcp-server/SKILL.md +121 -0
  87. package/dist/resources/skills/decompose-into-slices/SKILL.md +139 -0
  88. package/dist/resources/skills/dependency-upgrade/SKILL.md +158 -0
  89. package/dist/resources/skills/design-an-interface/SKILL.md +102 -0
  90. package/dist/resources/skills/forensics/SKILL.md +153 -0
  91. package/dist/resources/skills/grill-me/SKILL.md +93 -0
  92. package/dist/resources/skills/handoff/SKILL.md +121 -0
  93. package/dist/resources/skills/observability/SKILL.md +174 -0
  94. package/dist/resources/skills/security-review/SKILL.md +181 -0
  95. package/dist/resources/skills/spike-wrap-up/SKILL.md +138 -0
  96. package/dist/resources/skills/tdd/SKILL.md +112 -0
  97. package/dist/resources/skills/verify-before-complete/SKILL.md +98 -0
  98. package/dist/resources/skills/write-docs/SKILL.md +82 -0
  99. package/dist/resources/skills/write-milestone-brief/SKILL.md +135 -0
  100. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  101. package/dist/web/standalone/.next/BUILD_ID +1 -1
  102. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  103. package/dist/web/standalone/.next/build-manifest.json +2 -2
  104. package/dist/web/standalone/.next/required-server-files.json +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/index.html +1 -1
  122. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  129. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  130. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/middleware-manifest.json +1 -1
  132. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  133. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  134. package/dist/web/standalone/server.js +1 -1
  135. package/dist/welcome-screen.js +6 -1
  136. package/dist/wizard.js +2 -0
  137. package/package.json +1 -1
  138. package/packages/daemon/package.json +2 -2
  139. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  140. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  141. package/packages/mcp-server/dist/remote-questions.js +732 -0
  142. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  143. package/packages/mcp-server/dist/server.d.ts +7 -0
  144. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  145. package/packages/mcp-server/dist/server.js +70 -8
  146. package/packages/mcp-server/dist/server.js.map +1 -1
  147. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  148. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/session-manager.js +49 -1
  150. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  151. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  152. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  153. package/packages/mcp-server/dist/workflow-tools.js +163 -25
  154. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  155. package/packages/mcp-server/package.json +4 -3
  156. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  157. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  158. package/packages/mcp-server/src/remote-questions.ts +916 -0
  159. package/packages/mcp-server/src/server.ts +89 -14
  160. package/packages/mcp-server/src/session-manager.ts +43 -1
  161. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  162. package/packages/mcp-server/src/workflow-tools.ts +215 -43
  163. package/packages/mcp-server/tsconfig.test.json +19 -0
  164. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  165. package/packages/native/package.json +1 -1
  166. package/packages/pi-agent-core/dist/agent-loop.js +12 -0
  167. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  168. package/packages/pi-agent-core/dist/types.d.ts +30 -0
  169. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  170. package/packages/pi-agent-core/dist/types.js.map +1 -1
  171. package/packages/pi-agent-core/package.json +1 -1
  172. package/packages/pi-agent-core/src/agent-loop.ts +14 -0
  173. package/packages/pi-agent-core/src/types.ts +34 -0
  174. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  176. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models/custom.js +41 -0
  178. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  179. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  180. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  181. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts +2 -0
  182. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts.map +1 -0
  183. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +13 -0
  184. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -0
  185. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  186. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  187. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  188. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  189. package/packages/pi-ai/dist/providers/anthropic.js +13 -4
  190. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  191. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  192. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  193. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  194. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  195. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  196. package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
  197. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  198. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  199. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  200. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  201. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  202. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
  203. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
  204. package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
  205. package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
  206. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
  207. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
  208. package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
  209. package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
  210. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +12 -2
  212. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  213. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +164 -14
  214. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  215. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  216. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +15 -3
  217. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  218. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts +2 -0
  219. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts.map +1 -0
  220. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +67 -0
  221. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -0
  222. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  223. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +16 -3
  224. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  225. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts +2 -0
  226. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts.map +1 -0
  227. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +67 -0
  228. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -0
  229. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +2 -0
  230. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +1 -0
  231. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +289 -0
  232. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +1 -0
  233. package/packages/pi-ai/package.json +1 -1
  234. package/packages/pi-ai/src/models/custom.ts +42 -0
  235. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  236. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -0
  237. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  238. package/packages/pi-ai/src/providers/anthropic.ts +15 -4
  239. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  240. package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
  241. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  242. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  243. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  244. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +200 -23
  245. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +12 -2
  246. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +84 -0
  247. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +15 -5
  248. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +84 -0
  249. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +16 -5
  250. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +363 -0
  251. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  252. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  253. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  255. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  256. package/packages/pi-coding-agent/dist/core/agent-session.js +32 -2
  257. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  258. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  259. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  260. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  261. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/extensions/loader.js +4 -0
  263. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +35 -2
  265. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/extensions/runner.js +233 -0
  267. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +205 -2
  269. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  270. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts +53 -0
  272. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts.map +1 -0
  273. package/packages/pi-coding-agent/dist/core/hooks-runner.js +337 -0
  274. package/packages/pi-coding-agent/dist/core/hooks-runner.js.map +1 -0
  275. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts +2 -0
  276. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts.map +1 -0
  277. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +234 -0
  278. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -0
  279. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  280. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  282. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
  284. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
  286. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
  288. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts +2 -0
  290. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts.map +1 -0
  291. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js +40 -0
  292. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js.map +1 -0
  293. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  294. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  295. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  296. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  297. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
  298. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
  300. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
  302. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  304. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  305. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  306. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  308. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  310. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
  313. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
  315. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +55 -0
  317. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  318. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  319. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  320. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  321. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  322. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  323. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  324. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  325. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  326. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  327. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
  328. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  329. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  330. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  331. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  332. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  334. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  335. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  336. package/packages/pi-coding-agent/package.json +1 -1
  337. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  338. package/packages/pi-coding-agent/src/core/agent-session.ts +38 -2
  339. package/packages/pi-coding-agent/src/core/extensions/index.ts +16 -0
  340. package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
  341. package/packages/pi-coding-agent/src/core/extensions/runner.ts +351 -0
  342. package/packages/pi-coding-agent/src/core/extensions/types.ts +258 -0
  343. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +269 -0
  344. package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
  345. package/packages/pi-coding-agent/src/core/index.ts +10 -0
  346. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
  347. package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
  348. package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
  349. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  350. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
  351. package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
  352. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  353. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  354. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
  355. package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
  356. package/packages/pi-coding-agent/src/core/settings-manager.ts +57 -0
  357. package/packages/pi-coding-agent/src/index.ts +16 -0
  358. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  359. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
  360. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  361. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  362. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  363. package/packages/pi-tui/package.json +1 -1
  364. package/packages/rpc-client/package.json +1 -1
  365. package/pkg/package.json +1 -1
  366. package/scripts/link-workspace-packages.cjs +1 -0
  367. package/src/resources/agents/researcher.md +1 -1
  368. package/src/resources/extensions/claude-code-cli/readiness.ts +32 -8
  369. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  370. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  371. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
  372. package/src/resources/extensions/gsd/auto/loop.ts +9 -0
  373. package/src/resources/extensions/gsd/auto/phases.ts +131 -10
  374. package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
  375. package/src/resources/extensions/gsd/auto/session.ts +35 -2
  376. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
  377. package/src/resources/extensions/gsd/auto-model-selection.ts +71 -15
  378. package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
  379. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  380. package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
  381. package/src/resources/extensions/gsd/auto-start.ts +60 -68
  382. package/src/resources/extensions/gsd/auto-verification.ts +33 -0
  383. package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
  384. package/src/resources/extensions/gsd/auto.ts +73 -28
  385. package/src/resources/extensions/gsd/blocked-models.ts +98 -0
  386. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +120 -1
  387. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  388. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  389. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +5 -0
  390. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -0
  391. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
  392. package/src/resources/extensions/gsd/bootstrap/system-context.ts +89 -26
  393. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  394. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  395. package/src/resources/extensions/gsd/commands-extract-learnings.ts +55 -90
  396. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  397. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  398. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
  399. package/src/resources/extensions/gsd/db-writer.ts +88 -17
  400. package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -27
  401. package/src/resources/extensions/gsd/doctor-providers.ts +59 -6
  402. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +2 -0
  403. package/src/resources/extensions/gsd/error-classifier.ts +36 -3
  404. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  405. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  406. package/src/resources/extensions/gsd/gitignore.ts +1 -1
  407. package/src/resources/extensions/gsd/gsd-db.ts +186 -23
  408. package/src/resources/extensions/gsd/guided-flow.ts +222 -1
  409. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  410. package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
  411. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  412. package/src/resources/extensions/gsd/journal.ts +2 -1
  413. package/src/resources/extensions/gsd/key-manager.ts +28 -0
  414. package/src/resources/extensions/gsd/memory-backfill.ts +140 -0
  415. package/src/resources/extensions/gsd/memory-store.ts +26 -0
  416. package/src/resources/extensions/gsd/model-router.ts +42 -1
  417. package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
  418. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  419. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  420. package/src/resources/extensions/gsd/preferences.ts +17 -17
  421. package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
  422. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  423. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  424. package/src/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  425. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  426. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  427. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
  428. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  429. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  430. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -0
  431. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  432. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  433. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  434. package/src/resources/extensions/gsd/state.ts +45 -4
  435. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
  436. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +95 -1
  437. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
  439. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  440. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
  441. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
  442. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  443. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
  444. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +54 -0
  445. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  446. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +68 -66
  447. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  448. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  449. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  450. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  451. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
  452. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  453. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +42 -0
  454. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -4
  455. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +148 -3
  456. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  457. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +306 -1
  458. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  459. package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
  460. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  461. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  462. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +40 -9
  463. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +62 -0
  464. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
  465. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  466. package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +11 -0
  467. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +78 -0
  468. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
  469. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  470. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  471. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +1 -1
  472. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  473. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  474. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +37 -0
  475. package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
  476. package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
  477. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  479. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  480. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  481. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  482. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  483. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  484. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
  485. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  486. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  487. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  488. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +103 -4
  489. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  490. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  491. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  492. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  493. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  494. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  495. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  496. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  497. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  498. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  499. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
  500. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -3
  501. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  502. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  503. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  504. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  505. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  506. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  507. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  508. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  509. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  510. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  511. package/src/resources/extensions/gsd/tools/memory-tools.ts +31 -1
  512. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  513. package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
  514. package/src/resources/extensions/gsd/workflow-logger.ts +4 -1
  515. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  516. package/src/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  517. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  518. package/src/resources/extensions/search-the-web/command-search-provider.ts +5 -4
  519. package/src/resources/extensions/search-the-web/native-search.ts +48 -12
  520. package/src/resources/skills/api-design/SKILL.md +190 -0
  521. package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
  522. package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
  523. package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
  524. package/src/resources/skills/design-an-interface/SKILL.md +102 -0
  525. package/src/resources/skills/forensics/SKILL.md +153 -0
  526. package/src/resources/skills/grill-me/SKILL.md +93 -0
  527. package/src/resources/skills/handoff/SKILL.md +121 -0
  528. package/src/resources/skills/observability/SKILL.md +174 -0
  529. package/src/resources/skills/security-review/SKILL.md +181 -0
  530. package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
  531. package/src/resources/skills/tdd/SKILL.md +112 -0
  532. package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
  533. package/src/resources/skills/write-docs/SKILL.md +82 -0
  534. package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
  535. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_buildManifest.js +0 -0
  536. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → pV-mPo7rYGb5JBC09C8GG}/_ssgManifest.js +0 -0
@@ -245,7 +245,7 @@ describe("buildExtractLearningsPrompt", () => {
245
245
  assert.ok(result.includes("M001-VERIFICATION.md"));
246
246
  });
247
247
 
248
- it("does NOT reference phantom capture_thought tool (regression for #4429)", () => {
248
+ it("references capture_thought as the memory-store mirror write (Option A' dual-write)", () => {
249
249
  const result = buildExtractLearningsPrompt({
250
250
  milestoneId: "M001",
251
251
  milestoneName: "Test Milestone",
@@ -260,8 +260,8 @@ describe("buildExtractLearningsPrompt", () => {
260
260
  });
261
261
 
262
262
  assert.ok(
263
- !result.includes("capture_thought"),
264
- "prompt must not advertise the non-existent capture_thought tool",
263
+ result.includes("capture_thought"),
264
+ "prompt must instruct the LLM to mirror durable insights into the memory store via capture_thought",
265
265
  );
266
266
  });
267
267
 
@@ -452,84 +452,84 @@ describe("buildExtractionStepsBlock", () => {
452
452
  assert.ok(block.includes("M042-ROADMAP.md"));
453
453
  });
454
454
 
455
- it("points the LLM at .gsd/KNOWLEDGE.md for append", () => {
455
+ // ─── Removed by ADR-013 step 6 cutover ────────────────────────────────────
456
+ //
457
+ // The following nine tests asserted structural properties of the legacy
458
+ // KNOWLEDGE.md table scaffolding (Rules/Patterns/Lessons headers, P###/L###
459
+ // row templates, em-dash placeholders, append-only semantics, "missing file"
460
+ // template) and the gsd_save_decision call-out (parameter list, "never edit
461
+ // DECISIONS.md" prohibition). The cutover replaced both surfaces with
462
+ // capture_thought calls into the memories table; the extraction steps no
463
+ // longer reference KNOWLEDGE.md tables or gsd_save_decision at all, so each
464
+ // assertion is now structurally false.
465
+ //
466
+ // The replacement assertions ("removes the legacy KNOWLEDGE.md table append
467
+ // step", "removes the gsd_save_decision call", "requires structuredFields
468
+ // payload on architecture-category memories") below cover the inverse
469
+ // contract.
470
+ //
471
+ // Per ADR-013 cutover criterion: "No regression test in tests/ is silenced
472
+ // or removed without an explicit rationale comment in the diff." That
473
+ // criterion is satisfied by this comment block.
474
+
475
+ it("keeps Surprises milestone-local (not persisted to memory store, no MCP call)", () => {
456
476
  const block = buildExtractionStepsBlock(ctx);
457
- assert.ok(block.includes(".gsd/KNOWLEDGE.md"));
458
- });
459
-
460
- it("covers the missing-file case with the canonical KNOWLEDGE.md template", () => {
461
- const block = buildExtractionStepsBlock(ctx);
462
- assert.ok(block.includes("If the file does not exist yet, create it first"));
463
- // Canonical column headers must be inlined so the LLM does not have to guess.
464
- assert.ok(block.includes("| # | Scope | Rule | Why | Added |"));
465
- assert.ok(block.includes("| # | Pattern | Where | Notes |"));
466
- assert.ok(block.includes("| # | What Happened | Root Cause | Fix | Scope |"));
467
- });
468
-
469
- it("specifies the exact Patterns row format with milestone scope", () => {
470
- const block = buildExtractionStepsBlock(ctx);
471
- assert.ok(block.includes("| P<NNN>"));
472
- assert.ok(block.includes(`| ${ctx.milestoneId} |`));
473
- });
474
-
475
- it("specifies the exact Lessons row format with milestone scope", () => {
476
- const block = buildExtractionStepsBlock(ctx);
477
- assert.ok(block.includes("| L<NNN>"));
478
- });
479
-
480
- it("enforces zero-padded three-digit IDs", () => {
481
- const block = buildExtractionStepsBlock(ctx);
482
- assert.ok(/zero[- ]pad/i.test(block));
483
- assert.ok(block.includes("three digits") || block.includes("3 digits"));
484
- });
485
-
486
- it("instructs append-only behaviour (no edits to existing rows)", () => {
487
- const block = buildExtractionStepsBlock(ctx);
488
- assert.ok(block.includes("Append-only"));
489
- });
490
-
491
- it("uses em-dash as the placeholder for unknown column values", () => {
492
- const block = buildExtractionStepsBlock(ctx);
493
- assert.ok(block.includes("—"));
494
- assert.ok(!block.includes("N/A"));
495
- });
496
-
497
- it("forbids modifications to the Rules table", () => {
498
- const block = buildExtractionStepsBlock(ctx);
499
- assert.ok(/do not.*rules/i.test(block.toLowerCase()) || block.includes("Do NOT modify"));
500
- assert.ok(block.includes("## Rules"));
477
+ assert.ok(block.includes("Surprises stay only in LEARNINGS.md"));
501
478
  });
502
479
 
503
- it("routes Decisions through the gsd_save_decision MCP tool", () => {
480
+ it("enforces a deduplication rule across all persistence steps", () => {
504
481
  const block = buildExtractionStepsBlock(ctx);
505
- assert.ok(block.includes("gsd_save_decision"));
506
- assert.ok(block.includes("`scope`"));
507
- assert.ok(block.includes("`decision`"));
508
- assert.ok(block.includes("`choice`"));
509
- assert.ok(block.includes("`rationale`"));
510
- assert.ok(block.includes("`made_by`"));
482
+ assert.ok(/deduplication/i.test(block) || /dedup/i.test(block));
483
+ assert.ok(/semantically equivalent/i.test(block));
484
+ assert.ok(/skip/i.test(block));
511
485
  });
512
486
 
513
- it("forbids direct edits to DECISIONS.md (DB-authoritative)", () => {
487
+ it("instructs capture_thought as the sole persistence path for Patterns, Lessons, and Decisions (ADR-013 step 6 cutover)", () => {
514
488
  const block = buildExtractionStepsBlock(ctx);
515
- assert.ok(/never edit.+decisions\.md/i.test(block));
489
+ // Each of the three persistence steps must call capture_thought.
490
+ const captureThoughtMatches = block.match(/capture_thought/g) ?? [];
491
+ assert.ok(
492
+ captureThoughtMatches.length >= 3,
493
+ `expected at least 3 capture_thought references (Patterns + Lessons + Decisions); got ${captureThoughtMatches.length}`,
494
+ );
495
+ // Required category vocabulary for the three captures.
496
+ assert.ok(/category:\s*"pattern"/.test(block), "Patterns must use category: \"pattern\"");
497
+ assert.ok(/category:\s*"gotcha"/.test(block), "Lessons must reference category: \"gotcha\"");
498
+ assert.ok(/category:\s*"architecture"/.test(block), "Decisions must use category: \"architecture\"");
499
+ // Milestone scope must be threaded through.
500
+ assert.ok(block.includes(`scope: "${ctx.milestoneId}"`), "capture_thought calls must scope to the milestone ID");
516
501
  });
517
502
 
518
- it("keeps Surprises milestone-local (not in KNOWLEDGE.md, no tool call)", () => {
503
+ it("removes the legacy KNOWLEDGE.md table append step (ADR-013 step 6 cutover)", () => {
519
504
  const block = buildExtractionStepsBlock(ctx);
520
- assert.ok(block.includes("Surprises stay only in LEARNINGS.md"));
505
+ // ADR-013 Cutover: memories table is the single source of truth.
506
+ // KNOWLEDGE.md is no longer written by the extraction flow.
507
+ assert.ok(!block.includes("| # | Scope | Rule | Why | Added |"), "Rules table scaffolding must be removed");
508
+ assert.ok(!block.includes("| # | Pattern | Where | Notes |"), "Patterns table scaffolding must be removed");
509
+ assert.ok(!block.includes("| # | What Happened | Root Cause | Fix | Scope |"), "Lessons table scaffolding must be removed");
510
+ assert.ok(!/\| P<NNN>/.test(block), "Pattern row template must be removed");
511
+ assert.ok(!/\| L<NNN>/.test(block), "Lesson row template must be removed");
512
+ assert.ok(!block.includes(".gsd/KNOWLEDGE.md"), "extraction flow must not reference KNOWLEDGE.md as a write target");
521
513
  });
522
514
 
523
- it("enforces a deduplication rule across all persistence steps", () => {
515
+ it("removes the gsd_save_decision call (ADR-013 step 6 cutover)", () => {
524
516
  const block = buildExtractionStepsBlock(ctx);
525
- assert.ok(/deduplication/i.test(block) || /dedup/i.test(block));
526
- assert.ok(/semantically equivalent/i.test(block));
527
- assert.ok(/skip/i.test(block));
517
+ // ADR-013 Cutover: decisions are now persisted via capture_thought with
518
+ // category=architecture and a structuredFields payload that preserves the
519
+ // gsd_save_decision schema. The legacy MCP tool is no longer called from
520
+ // the extraction flow.
521
+ assert.ok(!block.includes("gsd_save_decision"), "gsd_save_decision must no longer appear in extraction steps");
528
522
  });
529
523
 
530
- it("does NOT reference the non-existent capture_thought tool (#4429 regression)", () => {
524
+ it("requires structuredFields payload on architecture-category memories (ADR-013 lossless projection)", () => {
531
525
  const block = buildExtractionStepsBlock(ctx);
532
- assert.ok(!block.includes("capture_thought"));
526
+ // ADR-013 Cutover: architecture-category memories must carry structured
527
+ // fields so projection back to a human-visible decisions register stays
528
+ // lossless. The Decisions persistence step must instruct the LLM to set
529
+ // structuredFields with the original gsd_save_decision schema fields.
530
+ assert.ok(/structuredFields/.test(block), "Decisions persistence step must instruct structuredFields use");
531
+ assert.ok(/scope/i.test(block) && /decision/i.test(block) && /choice/i.test(block) && /rationale/i.test(block),
532
+ "structuredFields must enumerate the preserved decision fields");
533
533
  });
534
534
 
535
535
  it("does NOT reference the non-existent gsd_graph tool (#4429 regression)", () => {
@@ -614,7 +614,9 @@ describe("complete-milestone loadPrompt round-trip (#4429)", () => {
614
614
  // Placeholder must be gone — real content must be in.
615
615
  assert.ok(!rendered.includes("{{extractLearningsSteps}}"));
616
616
  assert.ok(rendered.includes("Structured Learnings Extraction"));
617
- assert.ok(rendered.includes("gsd_save_decision"));
617
+ // ADR-013 cutover: gsd_save_decision is no longer in the rendered block;
618
+ // the new persistence path is capture_thought with structuredFields.
619
+ assert.ok(rendered.includes("capture_thought"));
618
620
  assert.ok(rendered.includes("M123"));
619
621
  });
620
622
  });
@@ -0,0 +1,123 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+
7
+ import {
8
+ buildSnapshot,
9
+ readCompactionSnapshot,
10
+ writeCompactionSnapshot,
11
+ DEFAULT_SNAPSHOT_BYTES,
12
+ } from '../compaction-snapshot.ts';
13
+ import { closeDatabase, openDatabase } from '../gsd-db.ts';
14
+ import { createMemory } from '../memory-store.ts';
15
+ import { executeResume } from '../tools/resume-tool.ts';
16
+
17
+ function freshBase(): string {
18
+ return mkdtempSync(join(tmpdir(), 'gsd-snap-'));
19
+ }
20
+
21
+ function cleanup(dir: string): void {
22
+ rmSync(dir, { recursive: true, force: true });
23
+ }
24
+
25
+ test('buildSnapshot: renders memories, exec history, and active context', () => {
26
+ const snap = buildSnapshot({
27
+ generatedAt: new Date('2026-04-20T12:00:00.000Z'),
28
+ activeContext: 'M001 / S01 / T01 — wire gsd_exec',
29
+ memories: [
30
+ { id: 'MEM001', category: 'gotcha', content: 'FTS5 needs Porter tokenizer', confidence: 0.9,
31
+ source_unit_type: null, source_unit_id: null, created_at: '', updated_at: '',
32
+ superseded_by: null, hit_count: 0, scope: 'project', seq: 1, tags: [], structured_fields: null },
33
+ ],
34
+ execHistory: [
35
+ {
36
+ id: 'abc',
37
+ runtime: 'bash',
38
+ purpose: 'count TODOs',
39
+ started_at: '', finished_at: '', duration_ms: 10,
40
+ exit_code: 0, signal: null, timed_out: false,
41
+ stdout_bytes: 1, stderr_bytes: 0, stdout_truncated: false, stderr_truncated: false,
42
+ stdout_path: '/tmp/abc.stdout', stderr_path: '/tmp/abc.stderr', meta_path: '/tmp/abc.meta.json',
43
+ },
44
+ ],
45
+ });
46
+ assert.match(snap, /Active context/);
47
+ assert.match(snap, /M001 \/ S01 \/ T01/);
48
+ assert.match(snap, /FTS5 needs Porter tokenizer/);
49
+ assert.match(snap, /\[abc\] bash exit:0 — count TODOs/);
50
+ });
51
+
52
+ test('buildSnapshot: enforces the byte cap with a truncation marker', () => {
53
+ const longMemories = Array.from({ length: 50 }, (_v, i) => ({
54
+ id: `MEM${String(i).padStart(3, '0')}`,
55
+ category: 'gotcha',
56
+ content: 'x'.repeat(200),
57
+ confidence: 0.8,
58
+ source_unit_type: null,
59
+ source_unit_id: null,
60
+ created_at: '',
61
+ updated_at: '',
62
+ superseded_by: null,
63
+ hit_count: 0,
64
+ scope: 'project',
65
+ seq: i,
66
+ tags: [] as string[],
67
+ structured_fields: null,
68
+ }));
69
+ const snap = buildSnapshot(
70
+ { generatedAt: new Date(), memories: longMemories, execHistory: [] },
71
+ { maxBytes: 512, maxMemories: 50 },
72
+ );
73
+ assert.ok(Buffer.byteLength(snap, 'utf-8') <= 512, 'should respect cap');
74
+ assert.match(snap, /\[truncated\]/, 'should include truncation marker');
75
+ });
76
+
77
+ test('buildSnapshot: handles empty state with an explanatory placeholder', () => {
78
+ const snap = buildSnapshot({ generatedAt: new Date(), memories: [], execHistory: [] });
79
+ assert.match(snap, /_No durable memories/);
80
+ assert.ok(Buffer.byteLength(snap, 'utf-8') <= DEFAULT_SNAPSHOT_BYTES);
81
+ });
82
+
83
+ test('writeCompactionSnapshot + readCompactionSnapshot + executeResume: end-to-end', () => {
84
+ const base = freshBase();
85
+ try {
86
+ openDatabase(':memory:');
87
+ createMemory({ category: 'architecture', content: 'Single-writer DB through gsd-db.ts', confidence: 0.95 });
88
+ createMemory({ category: 'convention', content: 'Prefer typed helpers over raw SQL', confidence: 0.9 });
89
+
90
+ const out = writeCompactionSnapshot(base, { activeContext: 'M099 resume check' });
91
+ assert.ok(out.path.endsWith('last-snapshot.md'));
92
+ assert.ok(out.bytes > 0);
93
+ assert.equal(out.memories, 2);
94
+
95
+ const contents = readCompactionSnapshot(base);
96
+ assert.ok(contents);
97
+ assert.match(contents!, /Single-writer DB through gsd-db\.ts/);
98
+ assert.match(contents!, /M099 resume check/);
99
+
100
+ const tool = executeResume({}, { baseDir: base });
101
+ assert.ok(!tool.isError);
102
+ assert.equal(tool.details.found, true);
103
+ assert.match(tool.content[0].text, /Single-writer DB through gsd-db\.ts/);
104
+
105
+ // also verify the file content matches (without trailing newline)
106
+ const raw = readFileSync(out.path, 'utf-8');
107
+ assert.ok(raw.endsWith('\n'));
108
+ } finally {
109
+ closeDatabase();
110
+ cleanup(base);
111
+ }
112
+ });
113
+
114
+ test('executeResume: reports friendly empty state when no snapshot exists', () => {
115
+ const base = freshBase();
116
+ try {
117
+ const result = executeResume({}, { baseDir: base });
118
+ assert.equal(result.details.found, false);
119
+ assert.match(result.content[0].text, /No snapshot found/);
120
+ } finally {
121
+ cleanup(base);
122
+ }
123
+ });
@@ -1,11 +1,14 @@
1
1
  import { describe, test, afterEach } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync, existsSync } from "node:fs";
4
4
  import { join, dirname } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { invalidateAllCaches } from '../cache.ts';
8
8
  import { parseUnitId } from "../unit-id.ts";
9
+ import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask } from "../gsd-db.ts";
10
+ import { clearPathCache } from "../paths.ts";
11
+ import { clearParseCache } from "../files.ts";
9
12
 
10
13
  // loadPrompt reads from ~/.gsd/agent/extensions/gsd/prompts/ (main checkout).
11
14
  // In a worktree the file may not exist there yet, so we resolve prompts
@@ -404,6 +407,63 @@ describe("complete-milestone", () => {
404
407
  }
405
408
  });
406
409
 
410
+ test("handleCompleteMilestone does not overwrite existing SUMMARY.md on re-dispatch (#4598)", async () => {
411
+ // This test verifies that when SUMMARY.md already exists (from a prior completion),
412
+ // re-calling handleCompleteMilestone does not overwrite it.
413
+ // Before the fix this test FAILS because the handler unconditionally writes SUMMARY.md.
414
+ const { handleCompleteMilestone } = await import("../tools/complete-milestone.ts");
415
+ const base = createFixtureBase();
416
+ const mid = "M001";
417
+ const dbPath = join(base, ".gsd", "gsd.db");
418
+ try {
419
+ // Set up DB with milestone and a complete slice + task
420
+ openDatabase(dbPath);
421
+ insertMilestone({ id: mid, title: "Test Milestone", status: "active" });
422
+ insertSlice({ id: "S01", milestoneId: mid, title: "Slice One", status: "complete" });
423
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: mid, title: "Task One", status: "complete" });
424
+
425
+ // Pre-write an existing SUMMARY.md to simulate a prior completion
426
+ const milestoneDir = join(base, ".gsd", "milestones", mid);
427
+ mkdirSync(milestoneDir, { recursive: true });
428
+ const summaryPath = join(milestoneDir, `${mid}-SUMMARY.md`);
429
+ const originalContent = "original content — must not be overwritten";
430
+ writeFileSync(summaryPath, originalContent, "utf-8");
431
+
432
+ // Call handleCompleteMilestone — this is the re-dispatch scenario
433
+ const params = {
434
+ milestoneId: mid,
435
+ title: "Test Milestone",
436
+ oneLiner: "Re-dispatched",
437
+ narrative: "This is a re-dispatch",
438
+ successCriteriaResults: "Met",
439
+ definitionOfDoneResults: "Done",
440
+ requirementOutcomes: "Covered",
441
+ keyDecisions: [],
442
+ keyFiles: [],
443
+ lessonsLearned: [],
444
+ followUps: "",
445
+ deviations: "",
446
+ verificationPassed: true,
447
+ };
448
+
449
+ const result = await handleCompleteMilestone(params, base);
450
+
451
+ // The call may return an error (milestone already complete) or success
452
+ // but in either case the SUMMARY.md must NOT be overwritten.
453
+ const actualContent = readFileSync(summaryPath, "utf-8");
454
+ assert.strictEqual(
455
+ actualContent,
456
+ originalContent,
457
+ "existing SUMMARY.md must not be overwritten on re-dispatch (#4598)",
458
+ );
459
+ } finally {
460
+ try { closeDatabase(); } catch { /* */ }
461
+ clearPathCache();
462
+ clearParseCache();
463
+ cleanup(base);
464
+ }
465
+ });
466
+
407
467
  test("deriveState completing-milestone integration", async () => {
408
468
  const { deriveState, isMilestoneComplete } = await import("../state.ts");
409
469
  const { invalidateAllCaches: invalidateAllCachesDynamic } = await import("../cache.ts");
@@ -125,9 +125,9 @@ console.log('\n=== complete-slice: schema v6 migration ===');
125
125
 
126
126
  const adapter = _getAdapter()!;
127
127
 
128
- // Verify schema version is current (v20memory system Phase 4 relations)
128
+ // Verify schema version is current (v22quality_gates DDL fix)
129
129
  const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
130
- assertEq(versionRow?.['v'], 20, 'schema version should be 20');
130
+ assertEq(versionRow?.['v'], 22, 'schema version should be 22');
131
131
 
132
132
  // Verify slices table has full_summary_md and full_uat_md columns
133
133
  const cols = adapter.prepare("PRAGMA table_info(slices)").all();
@@ -109,9 +109,9 @@ console.log('\n=== complete-task: schema v5 migration ===');
109
109
 
110
110
  const adapter = _getAdapter()!;
111
111
 
112
- // Verify schema version is current (v20memory system Phase 4 relations)
112
+ // Verify schema version is current (v22quality_gates DDL fix)
113
113
  const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
114
- assertEq(versionRow?.['v'], 20, 'schema version should be 20');
114
+ assertEq(versionRow?.['v'], 22, 'schema version should be 22');
115
115
 
116
116
  // Verify all 4 new tables exist
117
117
  const tables = adapter.prepare(
@@ -21,9 +21,9 @@ test("tierOrdinal returns correct ordering", () => {
21
21
 
22
22
  // ─── Unit Type Classification ────────────────────────────────────────────────
23
23
 
24
- test("complete-slice classifies as light", () => {
24
+ test("complete-slice classifies as standard", () => {
25
25
  const result = classifyUnitComplexity("complete-slice", "M001/S01", "/tmp/fake");
26
- assert.equal(result.tier, "light");
26
+ assert.equal(result.tier, "standard");
27
27
  });
28
28
 
29
29
  test("run-uat classifies as light", () => {
@@ -145,7 +145,7 @@ test("budget pressure at 90% downgrades standard to light", () => {
145
145
  assert.equal(result.downgraded, true);
146
146
  });
147
147
 
148
- test("budget pressure at 90% downgrades light stays light", () => {
148
+ test("budget pressure at 90% downgrades complete-slice standard to light", () => {
149
149
  const result = classifyUnitComplexity("complete-slice", "M001/S01", "/tmp/fake", 0.95);
150
150
  assert.equal(result.tier, "light");
151
151
  });
@@ -179,6 +179,8 @@ function makeMockDeps(overrides?: Partial<LoopDeps>): LoopDeps & { callLog: stri
179
179
  autoWorktreeBranch: () => "auto/M001",
180
180
  resolveMilestoneFile: () => null,
181
181
  reconcileMergeState: () => "clean",
182
+ preflightCleanRoot: () => ({ stashPushed: false, summary: "" }),
183
+ postflightPopStash: () => {},
182
184
  getLedger: () => null,
183
185
  getProjectTotals: () => ({ cost: 0 }),
184
186
  formatCost: (c: number) => `$${c.toFixed(2)}`,
@@ -694,6 +694,48 @@ describe('derive-state-db', async () => {
694
694
  }
695
695
  });
696
696
 
697
+ // ─── Test 14b: needs-remediation + all slices done → blocked (#4506) ──
698
+ test('derive-state-db: needs-remediation with all slices done returns blocked (#4506)', async () => {
699
+ const base = createFixtureBase();
700
+ try {
701
+ const doneRoadmap = `# M001: Stuck Remediation
702
+
703
+ **Vision:** Test needs-remediation loop guard.
704
+
705
+ ## Slices
706
+
707
+ - [x] **S01: Done Slice** \`risk:low\` \`depends:[]\`
708
+ > After this: Done.
709
+ `;
710
+ writeFile(base, 'milestones/M001/M001-ROADMAP.md', doneRoadmap);
711
+ writeFile(base, 'milestones/M001/M001-VALIDATION.md',
712
+ '---\nverdict: needs-remediation\nremediation_round: 1\n---\n\n# Validation\nNeeds fixes.');
713
+
714
+ invalidateStateCache();
715
+ const fileState = await _deriveStateImpl(base);
716
+
717
+ openDatabase(':memory:');
718
+ insertMilestone({ id: 'M001', title: 'Stuck Remediation', status: 'active' });
719
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Done Slice', status: 'complete', risk: 'low', depends: [] });
720
+
721
+ invalidateStateCache();
722
+ const dbState = await deriveStateFromDb(base);
723
+
724
+ assert.deepStrictEqual(dbState.phase, 'blocked', 'remediation-stuck-db: phase is blocked');
725
+ assert.deepStrictEqual(dbState.phase, fileState.phase, 'remediation-stuck-db: phase matches filesystem');
726
+ assert.deepStrictEqual(dbState.activeMilestone?.id, 'M001', 'remediation-stuck-db: activeMilestone is M001');
727
+ assert.ok(
728
+ dbState.blockers.some(b => b.includes('needs-remediation') && b.includes('M001')),
729
+ 'remediation-stuck-db: blocker message mentions milestone and verdict',
730
+ );
731
+
732
+ closeDatabase();
733
+ } finally {
734
+ closeDatabase();
735
+ cleanup(base);
736
+ }
737
+ });
738
+
697
739
  // ─── Test 15: Completing-milestone — terminal validation, no summary ──
698
740
  test('derive-state-db: completing-milestone via DB', async () => {
699
741
  const base = createFixtureBase();
@@ -446,8 +446,8 @@ describe('derive-state-helpers', () => {
446
446
  }
447
447
  });
448
448
 
449
- // ─── handleAllSlicesDone: needs-remediation re-triggers validation ──
450
- test('handleAllSlicesDone: needs-remediation verdict triggers validating-milestone', async () => {
449
+ // ─── handleAllSlicesDone: needs-remediation + all slices done → blocked (#4506) ──
450
+ test('handleAllSlicesDone: needs-remediation with all slices done returns blocked', async () => {
451
451
  const base = createFixtureBase();
452
452
  try {
453
453
  const doneRoadmap = `# M001: Remediation Test\n\n**Vision:** Test.\n\n## Slices\n\n- [x] **S01: Done** \`risk:low\` \`depends:[]\`\n > Done.\n`;
@@ -462,8 +462,12 @@ describe('derive-state-helpers', () => {
462
462
  invalidateStateCache();
463
463
  const state = await deriveStateFromDb(base);
464
464
 
465
- assert.equal(state.phase, 'validating-milestone', 'remediation: phase is validating-milestone');
466
- assert.equal(state.activeMilestone?.id, 'M001', 'remediation: activeMilestone is M001');
465
+ assert.equal(state.phase, 'blocked', 'remediation-stuck: phase is blocked (no infinite re-dispatch)');
466
+ assert.equal(state.activeMilestone?.id, 'M001', 'remediation-stuck: activeMilestone is M001');
467
+ assert.ok(
468
+ state.blockers.some(b => b.includes('needs-remediation') && b.includes('M001')),
469
+ 'remediation-stuck: blocker message mentions milestone and verdict',
470
+ );
467
471
  } finally {
468
472
  closeDatabase();
469
473
  cleanup(base);