@opengsd/gsd-pi 1.1.1-dev.3ea310e → 1.1.1-dev.595401e

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 (314) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
  3. package/dist/resources/extensions/gsd/auto/phases.js +4 -3
  4. package/dist/resources/extensions/gsd/auto-dashboard.js +92 -17
  5. package/dist/resources/extensions/gsd/auto-dispatch.js +5 -0
  6. package/dist/resources/extensions/gsd/auto-post-unit.js +132 -8
  7. package/dist/resources/extensions/gsd/auto-prompts.js +68 -22
  8. package/dist/resources/extensions/gsd/auto-start.js +41 -12
  9. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +2 -1
  10. package/dist/resources/extensions/gsd/auto.js +12 -5
  11. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +82 -3
  12. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
  13. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +30 -9
  14. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
  15. package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
  16. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
  17. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
  18. package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
  19. package/dist/resources/extensions/gsd/config-overlay.js +2 -1
  20. package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
  21. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  22. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
  23. package/dist/resources/extensions/gsd/error-classifier.js +2 -1
  24. package/dist/resources/extensions/gsd/escalation.js +4 -4
  25. package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
  26. package/dist/resources/extensions/gsd/forensics.js +74 -2
  27. package/dist/resources/extensions/gsd/gsd-db.js +5 -2
  28. package/dist/resources/extensions/gsd/guided-flow.js +29 -68
  29. package/dist/resources/extensions/gsd/memory-store.js +4 -1
  30. package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
  31. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  32. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  33. package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
  34. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  35. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  36. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  37. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  38. package/dist/resources/extensions/gsd/prompts/run-uat.md +48 -24
  39. package/dist/resources/extensions/gsd/prompts/system.md +3 -1
  40. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  41. package/dist/resources/extensions/gsd/rule-registry.js +428 -52
  42. package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
  43. package/dist/resources/extensions/gsd/skill-activation.js +20 -3
  44. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
  45. package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
  46. package/dist/resources/extensions/gsd/state.js +3 -3
  47. package/dist/resources/extensions/gsd/templates/plan.md +3 -1
  48. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
  49. package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
  50. package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
  51. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +403 -3
  52. package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
  53. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  54. package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
  55. package/dist/resources/extensions/gsd/verification-gate.js +72 -1
  56. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +1 -1
  57. package/dist/resources/extensions/gsd/workflow-mcp.js +5 -1
  58. package/dist/rtk.d.ts +7 -1
  59. package/dist/rtk.js +27 -11
  60. package/dist/web/standalone/.next/BUILD_ID +1 -1
  61. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  62. package/dist/web/standalone/.next/build-manifest.json +2 -2
  63. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  64. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  65. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.html +1 -1
  81. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  88. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  89. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  91. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  92. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  93. package/package.json +3 -2
  94. package/packages/cloud-mcp-gateway/package.json +2 -2
  95. package/packages/contracts/dist/workflow.d.ts +14 -0
  96. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  97. package/packages/contracts/dist/workflow.js +16 -0
  98. package/packages/contracts/dist/workflow.js.map +1 -1
  99. package/packages/contracts/package.json +1 -1
  100. package/packages/daemon/package.json +4 -4
  101. package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
  102. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  103. package/packages/gsd-agent-core/dist/agent-session.js +32 -0
  104. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  105. package/packages/gsd-agent-core/dist/index.d.ts +1 -0
  106. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  107. package/packages/gsd-agent-core/dist/index.js +1 -0
  108. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  109. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
  110. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
  111. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
  112. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
  113. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
  114. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  115. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  116. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  117. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
  118. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  119. package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
  120. package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
  121. package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
  122. package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
  123. package/packages/gsd-agent-core/package.json +6 -6
  124. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
  125. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
  126. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
  127. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
  128. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  129. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  130. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  132. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
  133. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  134. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +89 -31
  135. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  136. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  137. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
  138. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
  140. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
  141. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
  142. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
  143. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
  144. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
  145. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
  146. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  147. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
  148. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  149. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  150. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
  151. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  152. package/packages/gsd-agent-modes/package.json +7 -7
  153. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  154. package/packages/mcp-server/dist/remote-questions.js +23 -9
  155. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  156. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  157. package/packages/mcp-server/dist/workflow-tools.js +84 -2
  158. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  159. package/packages/mcp-server/package.json +3 -3
  160. package/packages/native/package.json +1 -1
  161. package/packages/pi-agent-core/dist/agent-loop.js +38 -0
  162. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  163. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  164. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  165. package/packages/pi-agent-core/dist/agent.js +2 -0
  166. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  167. package/packages/pi-agent-core/dist/types.d.ts +3 -0
  168. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  169. package/packages/pi-agent-core/dist/types.js.map +1 -1
  170. package/packages/pi-agent-core/package.json +1 -1
  171. package/packages/pi-ai/dist/api-registry.d.ts +2 -0
  172. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  173. package/packages/pi-ai/dist/api-registry.js +23 -0
  174. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  175. package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
  176. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/image-models.generated.js +15 -0
  178. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  179. package/packages/pi-ai/dist/models.generated.d.ts +86 -18
  180. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  181. package/packages/pi-ai/dist/models.generated.js +108 -40
  182. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  183. package/packages/pi-ai/dist/stream.js +6 -6
  184. package/packages/pi-ai/dist/stream.js.map +1 -1
  185. package/packages/pi-ai/package.json +1 -1
  186. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  188. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  190. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  192. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  193. package/packages/pi-coding-agent/package.json +7 -7
  194. package/packages/pi-tui/dist/terminal.d.ts +1 -0
  195. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  196. package/packages/pi-tui/dist/terminal.js +8 -4
  197. package/packages/pi-tui/dist/terminal.js.map +1 -1
  198. package/packages/pi-tui/package.json +1 -1
  199. package/packages/rpc-client/package.json +2 -2
  200. package/pkg/package.json +1 -1
  201. package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
  202. package/src/resources/extensions/gsd/auto/phases.ts +5 -3
  203. package/src/resources/extensions/gsd/auto-dashboard.ts +98 -18
  204. package/src/resources/extensions/gsd/auto-dispatch.ts +5 -0
  205. package/src/resources/extensions/gsd/auto-post-unit.ts +164 -7
  206. package/src/resources/extensions/gsd/auto-prompts.ts +102 -15
  207. package/src/resources/extensions/gsd/auto-start.ts +54 -14
  208. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +2 -1
  209. package/src/resources/extensions/gsd/auto.ts +15 -4
  210. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +89 -3
  211. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
  212. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +51 -14
  213. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
  214. package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
  215. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
  216. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
  217. package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
  218. package/src/resources/extensions/gsd/config-overlay.ts +3 -1
  219. package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
  220. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  221. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
  222. package/src/resources/extensions/gsd/error-classifier.ts +2 -1
  223. package/src/resources/extensions/gsd/escalation.ts +4 -4
  224. package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
  225. package/src/resources/extensions/gsd/forensics.ts +99 -5
  226. package/src/resources/extensions/gsd/gsd-db.ts +5 -2
  227. package/src/resources/extensions/gsd/guided-flow.ts +90 -82
  228. package/src/resources/extensions/gsd/memory-store.ts +4 -1
  229. package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
  230. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  231. package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
  232. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  233. package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
  234. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  235. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  236. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  237. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  238. package/src/resources/extensions/gsd/prompts/run-uat.md +48 -24
  239. package/src/resources/extensions/gsd/prompts/system.md +3 -1
  240. package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  241. package/src/resources/extensions/gsd/rule-registry.ts +558 -58
  242. package/src/resources/extensions/gsd/rule-types.ts +2 -0
  243. package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
  244. package/src/resources/extensions/gsd/skill-activation.ts +20 -2
  245. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
  246. package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
  247. package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
  248. package/src/resources/extensions/gsd/state.ts +3 -3
  249. package/src/resources/extensions/gsd/templates/plan.md +3 -1
  250. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +156 -4
  251. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +37 -0
  252. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +16 -3
  253. package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
  254. package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
  255. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
  256. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
  257. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
  258. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
  259. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
  260. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -0
  261. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
  262. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
  263. package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
  264. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
  265. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
  266. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
  267. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
  268. package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
  269. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
  270. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
  271. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
  272. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
  273. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +66 -10
  274. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
  275. package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
  276. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
  277. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
  278. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
  279. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
  280. package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
  281. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +53 -1
  282. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
  283. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
  284. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
  285. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
  286. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +35 -0
  287. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
  288. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
  289. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
  290. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
  291. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
  292. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
  293. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
  294. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
  295. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
  296. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
  297. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
  298. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
  299. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +2 -2
  300. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +213 -0
  301. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
  302. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
  303. package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
  304. package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
  305. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +489 -3
  306. package/src/resources/extensions/gsd/types.ts +67 -4
  307. package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
  308. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  309. package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
  310. package/src/resources/extensions/gsd/verification-gate.ts +87 -1
  311. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +1 -1
  312. package/src/resources/extensions/gsd/workflow-mcp.ts +5 -1
  313. /package/dist/web/standalone/.next/static/{xACmObbrDjwLriepRgaa9 → IDKjyRHLIaumjgonPcYiX}/_buildManifest.js +0 -0
  314. /package/dist/web/standalone/.next/static/{xACmObbrDjwLriepRgaa9 → IDKjyRHLIaumjgonPcYiX}/_ssgManifest.js +0 -0
@@ -4,7 +4,7 @@
4
4
  // checkboxes) and the DB slice rows for that milestone, then re-renders the
5
5
  // ROADMAP projection from the authoritative DB rows.
6
6
  import { existsSync, readFileSync } from "node:fs";
7
- import { getMilestone, getMilestoneSlices, isDbAvailable, } from "../../gsd-db.js";
7
+ import { getMilestone, getMilestoneSlices, getSliceTasks, isDbAvailable, } from "../../gsd-db.js";
8
8
  import { renderRoadmapFromDb } from "../../markdown-renderer.js";
9
9
  import { findMilestoneIds } from "../../milestone-ids.js";
10
10
  import { parseRoadmap } from "../../parsers-legacy.js";
@@ -18,6 +18,15 @@ function arraysEqual(a, b) {
18
18
  return false;
19
19
  return true;
20
20
  }
21
+ function getSlicesReadyForDivergenceCheck(milestoneId, dbSlices) {
22
+ const ready = new Set();
23
+ for (const slice of dbSlices) {
24
+ if (isClosedStatus(slice.status) || getSliceTasks(milestoneId, slice.id).length > 0) {
25
+ ready.add(slice.id);
26
+ }
27
+ }
28
+ return ready;
29
+ }
21
30
  function milestoneHasDivergence(basePath, milestoneId) {
22
31
  const roadmapPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
23
32
  if (!roadmapPath || !existsSync(roadmapPath))
@@ -31,6 +40,10 @@ function milestoneHasDivergence(basePath, milestoneId) {
31
40
  }
32
41
  const dbSlices = getMilestoneSlices(milestoneId);
33
42
  const dbSliceMap = new Map(dbSlices.map((s) => [s.id, s]));
43
+ const readySliceIds = getSlicesReadyForDivergenceCheck(milestoneId, dbSlices);
44
+ if (dbSlices.length > 0 && readySliceIds.size === 0) {
45
+ return false;
46
+ }
34
47
  const roadmapSliceIds = new Set();
35
48
  for (let i = 0; i < roadmap.slices.length; i++) {
36
49
  const roadmapSlice = roadmap.slices[i];
@@ -39,6 +52,8 @@ function milestoneHasDivergence(basePath, milestoneId) {
39
52
  const dbSlice = dbSliceMap.get(roadmapSlice.id);
40
53
  if (!dbSlice)
41
54
  return true; // Roadmap has a slice the DB doesn't.
55
+ if (!readySliceIds.has(dbSlice.id))
56
+ continue;
42
57
  if (dbSlice.sequence !== expectedSequence)
43
58
  return true;
44
59
  if (!arraysEqual(dbSlice.depends, roadmapSlice.depends))
@@ -47,6 +62,8 @@ function milestoneHasDivergence(basePath, milestoneId) {
47
62
  return true;
48
63
  }
49
64
  for (const dbSlice of dbSlices) {
65
+ if (!readySliceIds.has(dbSlice.id))
66
+ continue;
50
67
  if (!roadmapSliceIds.has(dbSlice.id))
51
68
  return true;
52
69
  }
@@ -2,6 +2,7 @@
2
2
  // File Purpose: ADR-017 drift-driven State Reconciliation Module entry point.
3
3
  // reconcileBeforeDispatch runs before every Dispatch decision and worker spawn.
4
4
  import { deriveState as defaultDeriveState, invalidateStateCache as defaultInvalidate, } from "../state.js";
5
+ import { clearParseCache as defaultClearParseCache } from "../files.js";
5
6
  import { ReconciliationFailedError, } from "./errors.js";
6
7
  import { DRIFT_REGISTRY } from "./registry.js";
7
8
  export { ReconciliationFailedError } from "./errors.js";
@@ -10,6 +11,7 @@ const MAX_PASSES = 2;
10
11
  const defaultDeps = {
11
12
  invalidateStateCache: defaultInvalidate,
12
13
  deriveState: defaultDeriveState,
14
+ clearParseCache: defaultClearParseCache,
13
15
  };
14
16
  /**
15
17
  * Drift-driven pre-dispatch reconciliation per ADR-017.
@@ -27,6 +29,7 @@ const defaultDeps = {
27
29
  */
28
30
  export async function reconcileBeforeDispatch(basePath, deps = defaultDeps) {
29
31
  const registry = deps.registry ?? DRIFT_REGISTRY;
32
+ const clearParseCache = deps.clearParseCache ?? defaultClearParseCache;
30
33
  const repaired = [];
31
34
  for (let pass = 0; pass < MAX_PASSES; pass++) {
32
35
  deps.invalidateStateCache();
@@ -67,6 +70,9 @@ export async function reconcileBeforeDispatch(basePath, deps = defaultDeps) {
67
70
  failures.push({ drift: record, cause });
68
71
  }
69
72
  }
73
+ if (repairedThisPass) {
74
+ clearParseCache();
75
+ }
70
76
  if (blockers.length > 0) {
71
77
  let blockerState = stateSnapshot;
72
78
  if (repairedThisPass) {
@@ -35,7 +35,7 @@ function formatNeedsRemediationBlocker(milestoneId) {
35
35
  return [
36
36
  `Milestone ${milestoneId} is blocked because milestone validation returned needs-remediation, but all slices are complete.`,
37
37
  `Fix options:`,
38
- `1. Add remediation slices with \`gsd_reassess_roadmap\`, then run \`/gsd auto\``,
38
+ `1. Run \`/gsd dispatch reassess\` to add remediation slices, then run \`/gsd auto\``,
39
39
  `2. If the finding is acceptable, override it: \`/gsd verdict pass --rationale "why this is okay"\``,
40
40
  `3. If this should wait, defer it explicitly: \`/gsd park ${milestoneId}\``,
41
41
  ].join("\n");
@@ -724,8 +724,8 @@ export async function deriveStateFromDb(basePath, artifactReadRoot = basePath) {
724
724
  }
725
725
  }
726
726
  // ADR-011 Phase 2: pause-on-escalation takes precedence over dispatching the
727
- // next task. `awaiting_review` tasks (continueWithDefault=true) are NOT
728
- // surfaced here they let the loop continue.
727
+ // next task. `awaiting_review` tasks (continueWithDefault=true) still pause
728
+ // here so silence is never treated as consent.
729
729
  //
730
730
  // We do NOT gate this on `phases.mid_execution_escalation` — creation of
731
731
  // new escalations is gated at the write site (tools/complete-task.ts:315),
@@ -132,14 +132,16 @@
132
132
  Verify field rules:
133
133
  - MUST be a mechanically executable command: `npm test`, `grep -q "pattern" file`, `test -f path`
134
134
  - MUST NOT use shell pipes, redirects, semicolons, backticks, command substitution, output trimming, or grep regex alternation with `|`
135
+ - For absence checks, use `! grep -q "pattern" file` or `! rg -q "pattern" file`; do not use `grep -c` or `rg -c` to assert zero matches because count commands exit 1 when they find zero matches
135
136
  - MUST NOT use inline `node -e` assertions for verification; put assertions in a real test file and run it with `node --test` or a package test script
136
137
  - For content/document tasks: verify file existence, section count, YAML validity, or word count
137
138
  NOT exact phrasing, specific formulas, or "zero TBD" aspirational criteria
138
139
  - If no command can verify the output, write: "Manual review — file exists and is non-empty"
139
140
  - BAD: `python3 -m pytest tests/ -q --tb=short 2>&1 | tail -5`
141
+ - BAD: `grep -c "old_api" src/index.ts`
140
142
  - BAD: "Sections 3.1 and 3.2 exist with exact formulas. Zero TBD/TODO."
141
143
  - GOOD: `python3 -m pytest tests/ -q --tb=short`
142
- - GOOD: `node --test tests/verify-doc.test.js`, `grep -q "Required heading" doc.md`, `test -s doc.md`
144
+ - GOOD: `node --test tests/verify-doc.test.js`, `grep -q "Required heading" doc.md`, `! grep -q "old_api" src/index.ts`, `test -s doc.md`
143
145
 
144
146
  Integration closure rule:
145
147
  - At least one slice in any multi-boundary milestone should perform real composition/wiring, not just contract hardening
@@ -314,9 +314,18 @@ export async function handleCompleteTask(params, basePath) {
314
314
  // overwrite it; gate rows are UPSERT-keyed per task and will also be
315
315
  // overwritten. This restores the invariant that deriveState() sees a
316
316
  // consistent "task not done" view so the loop re-dispatches the task.
317
+ let escalationMetadata;
317
318
  if (validatedEscalationArtifact) {
318
319
  try {
319
- writeEscalationArtifact(artifactBasePath, validatedEscalationArtifact);
320
+ const escalationPath = writeEscalationArtifact(artifactBasePath, validatedEscalationArtifact);
321
+ escalationMetadata = {
322
+ artifactPath: escalationPath,
323
+ question: validatedEscalationArtifact.question,
324
+ options: validatedEscalationArtifact.options,
325
+ recommendation: validatedEscalationArtifact.recommendation,
326
+ recommendationRationale: validatedEscalationArtifact.recommendationRationale,
327
+ continueWithDefault: validatedEscalationArtifact.continueWithDefault,
328
+ };
320
329
  }
321
330
  catch (escalationErr) {
322
331
  const msg = `complete-task escalation write failed for ${params.milestoneId}/${params.sliceId}/${params.taskId}: ${escalationErr.message}`;
@@ -378,6 +387,7 @@ export async function handleCompleteTask(params, basePath) {
378
387
  sliceId: params.sliceId,
379
388
  milestoneId: params.milestoneId,
380
389
  summaryPath,
390
+ ...(escalationMetadata ? { escalation: escalationMetadata } : {}),
381
391
  ...(projectionStale ? { stale: true } : {}),
382
392
  };
383
393
  }
@@ -5,6 +5,27 @@ import { realpathSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { isContextModeEnabled } from "../preferences-types.js";
7
7
  import { contextModeDisabledResult } from "./context-mode-tool-result.js";
8
+ const UAT_EXEC_INTENTS = [
9
+ "uat-artifact-check",
10
+ "uat-runtime-check",
11
+ "uat-browser-check",
12
+ "uat-service-start",
13
+ "uat-log-inspection",
14
+ ];
15
+ const UAT_EXEC_INTENT_ALIASES = {
16
+ artifact: "uat-artifact-check",
17
+ "artifact-driven": "uat-artifact-check",
18
+ runtime: "uat-runtime-check",
19
+ "runtime-executable": "uat-runtime-check",
20
+ "live-runtime": "uat-runtime-check",
21
+ browser: "uat-browser-check",
22
+ "browser-executable": "uat-browser-check",
23
+ service: "uat-service-start",
24
+ "service-start": "uat-service-start",
25
+ log: "uat-log-inspection",
26
+ logs: "uat-log-inspection",
27
+ "log-inspection": "uat-log-inspection",
28
+ };
8
29
  export function buildExecOptions(baseDir, cfg, extras) {
9
30
  const allowlist = Array.isArray(cfg?.exec_env_allowlist) ? cfg.exec_env_allowlist : EXEC_DEFAULTS.envAllowlist;
10
31
  const stdoutCap = clampNumber(cfg?.exec_stdout_cap_bytes, EXEC_DEFAULTS.stdoutCapBytes, 4_096, 16_777_216);
@@ -73,6 +94,39 @@ function normalizeScript(params) {
73
94
  }
74
95
  return paramError("script is required and must be a non-empty string");
75
96
  }
97
+ function normalizeRequiredString(value, field) {
98
+ if (typeof value !== "string" || value.trim().length === 0) {
99
+ return paramError(`${field} is required and must be a non-empty string`);
100
+ }
101
+ return value.trim();
102
+ }
103
+ function normalizeUatIntent(value) {
104
+ if (typeof value !== "string") {
105
+ return paramError(`intent is required and must be one of: ${UAT_EXEC_INTENTS.join(", ")}`);
106
+ }
107
+ const normalized = value.trim().toLowerCase();
108
+ if (UAT_EXEC_INTENTS.includes(normalized))
109
+ return normalized;
110
+ const alias = UAT_EXEC_INTENT_ALIASES[normalized];
111
+ if (alias)
112
+ return alias;
113
+ return paramError(`invalid intent "${value}" — must be one of: ${UAT_EXEC_INTENTS.join(", ")}`);
114
+ }
115
+ function rejectUatScript(script) {
116
+ const patterns = [
117
+ { re: /\b(?:npm|pnpm|yarn|bun)\s+(?:i|install|add|remove|update|upgrade)\b/i, reason: "package dependency mutation is not allowed during UAT" },
118
+ { re: /\b(?:pip|pip3|python\s+-m\s+pip)\s+install\b/i, reason: "package dependency mutation is not allowed during UAT" },
119
+ { re: /\bgit\s+(?:add|commit|push|reset|checkout|switch|merge|rebase|clean|rm|mv|tag|branch)\b/i, reason: "git mutations are not allowed during UAT" },
120
+ { re: /\brm\s+-[^\n\r;|&]*r[^\n\r;|&]*f\b/i, reason: "destructive filesystem cleanup is not allowed during UAT" },
121
+ { re: /\b(?:env|printenv)\b(?:\s|$)/i, reason: "dumping environment variables is not allowed during UAT" },
122
+ { re: /\bcat\s+\.env(?:\b|\.|$)/i, reason: "reading credential files is not allowed during UAT" },
123
+ ];
124
+ for (const pattern of patterns) {
125
+ if (pattern.re.test(script))
126
+ return pattern.reason;
127
+ }
128
+ return null;
129
+ }
76
130
  function isToolExecutionResult(value) {
77
131
  return typeof value === "object" && value !== null && Array.isArray(value.content);
78
132
  }
@@ -207,6 +261,7 @@ export async function executeGsdExec(params, deps) {
207
261
  runtime,
208
262
  script,
209
263
  ...(typeof params.purpose === "string" ? { purpose: params.purpose } : {}),
264
+ ...(params.metadata && typeof params.metadata === "object" ? { metadata: params.metadata } : {}),
210
265
  ...(typeof params.timeout_ms === "number" ? { timeout_ms: params.timeout_ms } : {}),
211
266
  }, opts);
212
267
  return formatResult(result);
@@ -220,6 +275,60 @@ export async function executeGsdExec(params, deps) {
220
275
  };
221
276
  }
222
277
  }
278
+ export async function executeUatExec(params, deps) {
279
+ const milestoneId = normalizeRequiredString(params.milestoneId, "milestoneId");
280
+ if (isToolExecutionResult(milestoneId))
281
+ return milestoneId;
282
+ const sliceId = normalizeRequiredString(params.sliceId, "sliceId");
283
+ if (isToolExecutionResult(sliceId))
284
+ return sliceId;
285
+ const checkId = normalizeRequiredString(params.checkId, "checkId");
286
+ if (isToolExecutionResult(checkId))
287
+ return checkId;
288
+ const intent = normalizeUatIntent(params.intent);
289
+ if (isToolExecutionResult(intent))
290
+ return intent;
291
+ const script = normalizeScript(params);
292
+ if (isToolExecutionResult(script))
293
+ return script;
294
+ const rejected = rejectUatScript(script);
295
+ if (rejected) {
296
+ return {
297
+ content: [{ type: "text", text: `Error: gsd_uat_exec blocked command — ${rejected}` }],
298
+ details: { operation: "gsd_uat_exec", error: "uat_exec_policy_block", reason: rejected },
299
+ isError: true,
300
+ };
301
+ }
302
+ const result = await executeGsdExec({
303
+ ...params,
304
+ script,
305
+ purpose: typeof params.purpose === "string" && params.purpose.trim().length > 0
306
+ ? params.purpose
307
+ : `UAT ${milestoneId}/${sliceId}/${checkId} (${intent})`,
308
+ metadata: {
309
+ kind: "uat_exec",
310
+ milestoneId,
311
+ sliceId,
312
+ checkId,
313
+ intent,
314
+ ...(typeof params.expected === "string" && params.expected.trim().length > 0
315
+ ? { expected: params.expected.trim() }
316
+ : {}),
317
+ },
318
+ }, deps);
319
+ const details = result.details ?? {};
320
+ return {
321
+ ...result,
322
+ details: {
323
+ ...details,
324
+ operation: "gsd_uat_exec",
325
+ milestoneId,
326
+ sliceId,
327
+ checkId,
328
+ intent,
329
+ },
330
+ };
331
+ }
223
332
  function formatResult(result) {
224
333
  const headerLines = [
225
334
  `gsd_exec[${result.id}] runtime=${result.runtime} exit=${formatExit(result)} duration=${result.duration_ms}ms`,
@@ -44,19 +44,12 @@ function getRequiredVerificationClasses(milestoneId) {
44
44
  required.push("UAT");
45
45
  return required;
46
46
  }
47
- async function collectPersistedBrowserEvidence(basePath, milestoneId) {
48
- const chunks = [];
49
- for (const slice of getMilestoneSlices(milestoneId)) {
50
- const artifactPath = `milestones/${milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
51
- const artifact = getArtifact(artifactPath);
52
- if (artifact?.full_content)
53
- chunks.push(artifact.full_content);
54
- const assessmentPath = resolveSliceFile(basePath, milestoneId, slice.id, "ASSESSMENT");
55
- const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
56
- if (assessmentContent)
57
- chunks.push(assessmentContent);
58
- }
59
- return chunks.join("\n\n");
47
+ function hasRuntimeExecutableUatEvidenceText(text) {
48
+ if (!/\buatType:\s*runtime-executable\b/i.test(text))
49
+ return false;
50
+ if (!/\bverdict:\s*PASS\b/i.test(text))
51
+ return false;
52
+ return /^\|\s*[^|\n]+\s*\|\s*runtime\s*\|\s*PASS\s*\|[^|\n]*\bgsd_uat_exec\b/mi.test(text);
60
53
  }
61
54
  async function browserEvidenceGateRequiresAttention(params, basePath) {
62
55
  if (params.verdict !== "pass")
@@ -77,7 +70,36 @@ async function browserEvidenceGateRequiresAttention(params, basePath) {
77
70
  ]);
78
71
  if (!hasBrowserRequiredText(requirementText))
79
72
  return false;
80
- const persistedEvidence = await collectPersistedBrowserEvidence(basePath, params.milestoneId);
73
+ // Collect per-slice evidence so the runtime bypass is checked independently
74
+ // for each slice. Concatenating all slices before checking would allow runtime
75
+ // evidence from one slice to cover another slice's browser requirements.
76
+ const sliceEvidencePairs = [];
77
+ for (const slice of slices) {
78
+ const chunks = [];
79
+ const artifactPath = `milestones/${params.milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
80
+ const artifact = getArtifact(artifactPath);
81
+ if (artifact?.full_content)
82
+ chunks.push(artifact.full_content);
83
+ const assessmentPath = resolveSliceFile(basePath, params.milestoneId, slice.id, "ASSESSMENT");
84
+ const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
85
+ if (assessmentContent)
86
+ chunks.push(assessmentContent);
87
+ sliceEvidencePairs.push({
88
+ sliceRequirementText: compactTextParts([slice.demo, slice.goal, slice.success_criteria]),
89
+ evidenceText: chunks.join("\n\n"),
90
+ });
91
+ }
92
+ const persistedEvidence = sliceEvidencePairs.map((s) => s.evidenceText).join("\n\n");
93
+ // Runtime bypass: each slice whose own requirement text has browser-observable
94
+ // criteria must have its own runtime-executable UAT evidence. When no individual
95
+ // slice has slice-level browser requirements (e.g., they come from milestone-level
96
+ // fields only), fall back to checking whether any slice has runtime evidence.
97
+ const browserRequiringSlices = sliceEvidencePairs.filter((s) => hasBrowserRequiredText(s.sliceRequirementText));
98
+ const runtimeBypasses = browserRequiringSlices.length > 0
99
+ ? browserRequiringSlices.every((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText))
100
+ : sliceEvidencePairs.some((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText));
101
+ if (runtimeBypasses)
102
+ return false;
81
103
  const validationEvidence = compactTextParts([
82
104
  params.successCriteriaChecklist,
83
105
  params.verificationClasses,
@@ -138,12 +160,20 @@ export async function handleValidateMilestone(params, basePath, opts) {
138
160
  const requiredClasses = getRequiredVerificationClasses(params.milestoneId);
139
161
  if (requiredClasses.length > 0) {
140
162
  const verificationClasses = params.verificationClasses ?? "";
141
- const missingClass = requiredClasses.find((className) => !new RegExp(`\\b${className}\\b`, "i").test(verificationClasses));
142
- if (missingClass) {
163
+ const missingClasses = requiredClasses.filter((className) => !new RegExp(`\\b${className}\\b`, "i").test(verificationClasses));
164
+ if (missingClasses.length === 1) {
165
+ const missingClass = missingClasses[0];
143
166
  return {
144
167
  error: `verificationClasses must include canonical row "${missingClass}" because this milestone planned ${missingClass.toLowerCase()} verification`,
145
168
  };
146
169
  }
170
+ if (missingClasses.length > 1) {
171
+ const quotedClasses = missingClasses.map((className) => `"${className}"`).join(", ");
172
+ const plannedClasses = missingClasses.map((className) => className.toLowerCase()).join(", ");
173
+ return {
174
+ error: `verificationClasses must include canonical rows ${quotedClasses} because this milestone planned ${plannedClasses} verification`,
175
+ };
176
+ }
147
177
  }
148
178
  const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, params.milestoneId);
149
179
  const shouldApplyBrowserEvidenceGate = !opts?.skipBrowserEvidenceGate &&