@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.738160b9

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 (488) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +17 -4
  3. package/dist/headless-answers.js +1 -1
  4. package/dist/headless-ui.d.ts +1 -1
  5. package/dist/headless-ui.js +1 -1
  6. package/dist/headless.js +1 -1
  7. package/dist/resources/.managed-resources-content-hash +1 -1
  8. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  9. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +11 -2
  10. package/dist/resources/extensions/google-cli/stream-adapter.js +82 -15
  11. package/dist/resources/extensions/gsd/artifact-verification.js +427 -0
  12. package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -3
  13. package/dist/resources/extensions/gsd/auto/session.js +11 -0
  14. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +1 -1
  15. package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
  16. package/dist/resources/extensions/gsd/auto-budget.js +5 -1
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +34 -20
  18. package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
  19. package/dist/resources/extensions/gsd/auto-prompts.js +29 -14
  20. package/dist/resources/extensions/gsd/auto-recovery.js +9 -510
  21. package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
  22. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +3 -3
  23. package/dist/resources/extensions/gsd/auto-verification.js +5 -2
  24. package/dist/resources/extensions/gsd/auto.js +19 -10
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
  26. package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +39 -0
  27. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +11 -5
  28. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
  29. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  30. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +41 -21
  31. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
  32. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +96 -10
  33. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
  34. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +3 -1
  35. package/dist/resources/extensions/gsd/commands/handlers/auto.js +1 -1
  36. package/dist/resources/extensions/gsd/commands-context.js +19 -1
  37. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +17 -11
  38. package/dist/resources/extensions/gsd/commands-usage.js +1 -1
  39. package/dist/resources/extensions/gsd/commands-worktree.js +12 -10
  40. package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -3
  41. package/dist/resources/extensions/gsd/db/engine.js +4 -1
  42. package/dist/resources/extensions/gsd/db/queries.js +60 -0
  43. package/dist/resources/extensions/gsd/db-memory-fts-schema.js +34 -0
  44. package/dist/resources/extensions/gsd/db-workspace.js +55 -3
  45. package/dist/resources/extensions/gsd/delegation-policy.js +1 -1
  46. package/dist/resources/extensions/gsd/docs/preferences-reference.md +2 -2
  47. package/dist/resources/extensions/gsd/doctor-engine-checks.js +192 -4
  48. package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
  49. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +3 -0
  50. package/dist/resources/extensions/gsd/exec-sandbox.js +53 -11
  51. package/dist/resources/extensions/gsd/flat-phase-migration.js +45 -0
  52. package/dist/resources/extensions/gsd/forensics.js +2 -32
  53. package/dist/resources/extensions/gsd/git-service.js +61 -4
  54. package/dist/resources/extensions/gsd/gitignore.js +4 -1
  55. package/dist/resources/extensions/gsd/guided-flow-queue.js +66 -5
  56. package/dist/resources/extensions/gsd/health-widget.js +55 -29
  57. package/dist/resources/extensions/gsd/json-persistence.js +20 -0
  58. package/dist/resources/extensions/gsd/knowledge-backfill.js +18 -11
  59. package/dist/resources/extensions/gsd/layout-policy.js +3 -1
  60. package/dist/resources/extensions/gsd/markdown-renderer.js +8 -9
  61. package/dist/resources/extensions/gsd/memory-backfill.js +28 -21
  62. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
  63. package/dist/resources/extensions/gsd/metrics.js +4 -4
  64. package/dist/resources/extensions/gsd/migrate-external.js +11 -2
  65. package/dist/resources/extensions/gsd/migration-auto-check.js +22 -0
  66. package/dist/resources/extensions/gsd/milestone-ids.js +32 -2
  67. package/dist/resources/extensions/gsd/milestone-implementation-evidence.js +26 -20
  68. package/dist/resources/extensions/gsd/orphan-stash-audit.js +92 -16
  69. package/dist/resources/extensions/gsd/prompts/code-review.md +6 -4
  70. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
  71. package/dist/resources/extensions/gsd/prompts/plan-slice.md +3 -3
  72. package/dist/resources/extensions/gsd/quick.js +45 -2
  73. package/dist/resources/extensions/gsd/root-write-leak-guard.js +7 -1
  74. package/dist/resources/extensions/gsd/safety/destructive-guard.js +8 -1
  75. package/dist/resources/extensions/gsd/safety/evidence-collector.js +16 -1
  76. package/dist/resources/extensions/gsd/safety/file-change-validator.js +5 -2
  77. package/dist/resources/extensions/gsd/session-forensics.js +11 -1
  78. package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
  79. package/dist/resources/extensions/gsd/state/derive/cache.js +28 -0
  80. package/dist/resources/extensions/gsd/state/derive/db-open.js +39 -0
  81. package/dist/resources/extensions/gsd/state/derive/from-db.js +452 -0
  82. package/dist/resources/extensions/gsd/state/derive/index.js +75 -0
  83. package/dist/resources/extensions/gsd/state/derive/interrupted-work.js +21 -0
  84. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +45 -2
  85. package/dist/resources/extensions/gsd/state-reconciliation/index.js +48 -23
  86. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +32 -28
  87. package/dist/resources/extensions/gsd/state.js +12 -611
  88. package/dist/resources/extensions/gsd/tools/complete-milestone.js +4 -2
  89. package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
  90. package/dist/resources/extensions/gsd/tools/complete-task.js +43 -14
  91. package/dist/resources/extensions/gsd/tools/exec-tool.js +7 -2
  92. package/dist/resources/extensions/gsd/tools/plan-slice.js +59 -44
  93. package/dist/resources/extensions/gsd/tools/plan-task.js +28 -5
  94. package/dist/resources/extensions/gsd/undo.js +43 -6
  95. package/dist/resources/extensions/gsd/unit-context-composer.js +23 -7
  96. package/dist/resources/extensions/gsd/unit-registry.js +36 -6
  97. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +33 -3
  98. package/dist/resources/extensions/gsd/validation-block-guard.js +9 -4
  99. package/dist/resources/extensions/gsd/verification-gate.js +7 -0
  100. package/dist/resources/extensions/gsd/workflow-manifest.js +126 -13
  101. package/dist/resources/extensions/gsd/workflow-projections.js +19 -14
  102. package/dist/resources/extensions/gsd/workspace-git-preflight.js +30 -1
  103. package/dist/resources/extensions/gsd/worktree-manager.js +44 -2
  104. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  105. package/dist/web/standalone/.next/BUILD_ID +1 -1
  106. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  107. package/dist/web/standalone/.next/build-manifest.json +3 -3
  108. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  109. package/dist/web/standalone/.next/react-loadable-manifest.json +9 -9
  110. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/index.html +1 -1
  130. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  131. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  132. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  133. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  138. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  139. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  142. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  143. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  144. package/dist/web/standalone/.next/static/chunks/{2659.b7b129ee6a769448.js → 2659.58e950899a9bb82f.js} +1 -1
  145. package/dist/web/standalone/.next/static/chunks/2772.a7c1fcc69a4685ef.js +1 -0
  146. package/dist/web/standalone/.next/static/chunks/{3616.3c60753b8ffcbd2e.js → 3616.61a2af74bb8833c8.js} +1 -1
  147. package/dist/web/standalone/.next/static/chunks/{4283.8e446784528ed9dc.js → 4283.d0d9e0a955e441cb.js} +1 -1
  148. package/dist/web/standalone/.next/static/chunks/{5826.a46ecdd1cfe8dabc.js → 5826.5421d66c72b9f34e.js} +1 -1
  149. package/dist/web/standalone/.next/static/chunks/{8785.481aa5869991b760.js → 8785.e29b3134cab1d153.js} +1 -1
  150. package/dist/web/standalone/.next/static/chunks/8937.640dc9c2aaa1dfad.js +10 -0
  151. package/dist/web/standalone/.next/static/chunks/app/{page-6644fc6ee8ca1247.js → page-72a856634ad14c10.js} +1 -1
  152. package/dist/web/standalone/.next/static/chunks/webpack-9c401904f87ded16.js +1 -0
  153. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  154. package/package.json +1 -1
  155. package/packages/cloud-mcp-gateway/package.json +2 -2
  156. package/packages/contracts/dist/workflow.d.ts +1 -0
  157. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  158. package/packages/contracts/dist/workflow.js +2 -0
  159. package/packages/contracts/dist/workflow.js.map +1 -1
  160. package/packages/contracts/package.json +1 -1
  161. package/packages/daemon/package.json +4 -4
  162. package/packages/gsd-agent-core/dist/agent-session.d.ts +1 -0
  163. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  164. package/packages/gsd-agent-core/dist/agent-session.js +3 -0
  165. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  166. package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts +41 -0
  167. package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts.map +1 -0
  168. package/packages/gsd-agent-core/dist/extension-ui-snapshot.js +62 -0
  169. package/packages/gsd-agent-core/dist/extension-ui-snapshot.js.map +1 -0
  170. package/packages/gsd-agent-core/dist/index.d.ts +2 -0
  171. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  172. package/packages/gsd-agent-core/dist/index.js +2 -0
  173. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  174. package/packages/gsd-agent-core/dist/session/agent-session-events.js +1 -1
  175. package/packages/gsd-agent-core/dist/session/agent-session-events.js.map +1 -1
  176. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +1 -0
  177. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  178. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  179. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts +5 -0
  180. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  181. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +60 -3
  182. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  183. package/packages/gsd-agent-core/dist/transcript-store.d.ts +58 -0
  184. package/packages/gsd-agent-core/dist/transcript-store.d.ts.map +1 -0
  185. package/packages/gsd-agent-core/dist/transcript-store.js +132 -0
  186. package/packages/gsd-agent-core/dist/transcript-store.js.map +1 -0
  187. package/packages/gsd-agent-core/package.json +5 -5
  188. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +2 -0
  189. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  190. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -11
  191. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  192. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts +4 -0
  193. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts.map +1 -0
  194. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js +7 -0
  195. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js.map +1 -0
  196. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -24
  197. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  198. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +26 -829
  199. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  200. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts +58 -0
  201. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts.map +1 -0
  202. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js +312 -0
  203. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js.map +1 -0
  204. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts +31 -0
  205. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts.map +1 -0
  206. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js +130 -0
  207. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js.map +1 -0
  208. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts +15 -0
  209. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -0
  210. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +258 -0
  211. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -0
  212. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts +13 -0
  213. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts.map +1 -0
  214. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js +118 -0
  215. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js.map +1 -0
  216. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +9 -0
  217. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  218. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js +1 -1
  219. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  220. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts +54 -0
  221. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts.map +1 -0
  222. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js +20 -0
  223. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js.map +1 -0
  224. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +4 -1
  225. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  226. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +9 -0
  227. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  228. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts +56 -0
  229. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts.map +1 -0
  230. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js +44 -0
  231. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js.map +1 -0
  232. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts +5 -0
  233. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts.map +1 -0
  234. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js +77 -0
  235. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js.map +1 -0
  236. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts +2 -0
  237. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  238. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +23 -5
  239. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
  240. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  241. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +18 -0
  242. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  243. package/packages/gsd-agent-modes/package.json +7 -7
  244. package/packages/mcp-server/README.md +1 -1
  245. package/packages/mcp-server/dist/server.d.ts +1 -1
  246. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  247. package/packages/mcp-server/dist/server.js +3 -3
  248. package/packages/mcp-server/dist/server.js.map +1 -1
  249. package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
  250. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  251. package/packages/mcp-server/dist/workflow-tools.js +35 -21
  252. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  253. package/packages/mcp-server/package.json +4 -4
  254. package/packages/native/package.json +1 -1
  255. package/packages/pi-agent-core/dist/agent-loop.js +3 -2
  256. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  257. package/packages/pi-agent-core/package.json +1 -1
  258. package/packages/pi-ai/dist/models.generated.d.ts +46 -0
  259. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  260. package/packages/pi-ai/dist/models.generated.js +38 -0
  261. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  262. package/packages/pi-ai/package.json +1 -1
  263. package/packages/pi-coding-agent/README.md +3 -2
  264. package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts +9 -0
  265. package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts.map +1 -0
  266. package/packages/pi-coding-agent/dist/core/session-manager-context.js +94 -0
  267. package/packages/pi-coding-agent/dist/core/session-manager-context.js.map +1 -0
  268. package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts +8 -0
  269. package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts.map +1 -0
  270. package/packages/pi-coding-agent/dist/core/session-manager-list.js +244 -0
  271. package/packages/pi-coding-agent/dist/core/session-manager-list.js.map +1 -0
  272. package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts +12 -0
  273. package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts.map +1 -0
  274. package/packages/pi-coding-agent/dist/core/session-manager-migration.js +84 -0
  275. package/packages/pi-coding-agent/dist/core/session-manager-migration.js.map +1 -0
  276. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +135 -0
  277. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -0
  278. package/packages/pi-coding-agent/dist/core/session-manager-types.js +2 -0
  279. package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -0
  280. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +6 -154
  281. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  282. package/packages/pi-coding-agent/dist/core/session-manager.js +22 -459
  283. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  284. package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts +75 -75
  285. package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts.map +1 -1
  286. package/packages/pi-coding-agent/dist/theme/theme-schema.js +1 -1
  287. package/packages/pi-coding-agent/dist/theme/theme-schema.js.map +1 -1
  288. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  289. package/packages/pi-coding-agent/dist/theme/theme.js +11 -7
  290. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  291. package/packages/pi-coding-agent/package.json +7 -7
  292. package/packages/pi-tui/package.json +2 -2
  293. package/packages/rpc-client/package.json +2 -2
  294. package/pkg/dist/theme/theme-schema.d.ts +75 -75
  295. package/pkg/dist/theme/theme-schema.d.ts.map +1 -1
  296. package/pkg/dist/theme/theme-schema.js +1 -1
  297. package/pkg/dist/theme/theme-schema.js.map +1 -1
  298. package/pkg/dist/theme/theme.d.ts.map +1 -1
  299. package/pkg/dist/theme/theme.js +11 -7
  300. package/pkg/dist/theme/theme.js.map +1 -1
  301. package/pkg/package.json +1 -1
  302. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  303. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
  304. package/src/resources/extensions/claude-code-cli/tests/index.test.ts +14 -0
  305. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -0
  306. package/src/resources/extensions/google-cli/stream-adapter.ts +106 -19
  307. package/src/resources/extensions/gsd/artifact-verification.ts +464 -0
  308. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  309. package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
  310. package/src/resources/extensions/gsd/auto/session.ts +14 -0
  311. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +3 -1
  312. package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
  313. package/src/resources/extensions/gsd/auto-budget.ts +12 -1
  314. package/src/resources/extensions/gsd/auto-dispatch.ts +35 -24
  315. package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
  316. package/src/resources/extensions/gsd/auto-prompts.ts +41 -15
  317. package/src/resources/extensions/gsd/auto-recovery.ts +13 -511
  318. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
  319. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +3 -2
  320. package/src/resources/extensions/gsd/auto-verification.ts +5 -1
  321. package/src/resources/extensions/gsd/auto.ts +23 -8
  322. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
  323. package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +44 -0
  324. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +11 -5
  325. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
  326. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  327. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +52 -21
  328. package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
  329. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +104 -10
  330. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
  331. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +2 -1
  332. package/src/resources/extensions/gsd/commands/handlers/auto.ts +1 -1
  333. package/src/resources/extensions/gsd/commands-context.ts +18 -1
  334. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -10
  335. package/src/resources/extensions/gsd/commands-usage.ts +1 -1
  336. package/src/resources/extensions/gsd/commands-worktree.ts +12 -10
  337. package/src/resources/extensions/gsd/dashboard-overlay.ts +32 -3
  338. package/src/resources/extensions/gsd/db/engine.ts +8 -1
  339. package/src/resources/extensions/gsd/db/queries.ts +79 -0
  340. package/src/resources/extensions/gsd/db-memory-fts-schema.ts +45 -0
  341. package/src/resources/extensions/gsd/db-workspace.ts +61 -3
  342. package/src/resources/extensions/gsd/delegation-policy.ts +1 -1
  343. package/src/resources/extensions/gsd/docs/preferences-reference.md +2 -2
  344. package/src/resources/extensions/gsd/doctor-engine-checks.ts +233 -5
  345. package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
  346. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +3 -0
  347. package/src/resources/extensions/gsd/doctor-types.ts +3 -0
  348. package/src/resources/extensions/gsd/exec-sandbox.ts +56 -11
  349. package/src/resources/extensions/gsd/flat-phase-migration.ts +44 -0
  350. package/src/resources/extensions/gsd/forensics.ts +2 -33
  351. package/src/resources/extensions/gsd/git-service.ts +69 -5
  352. package/src/resources/extensions/gsd/gitignore.ts +4 -1
  353. package/src/resources/extensions/gsd/guided-flow-queue.ts +89 -4
  354. package/src/resources/extensions/gsd/health-widget.ts +69 -32
  355. package/src/resources/extensions/gsd/json-persistence.ts +20 -0
  356. package/src/resources/extensions/gsd/knowledge-backfill.ts +16 -10
  357. package/src/resources/extensions/gsd/layout-policy.ts +2 -1
  358. package/src/resources/extensions/gsd/markdown-renderer.ts +8 -11
  359. package/src/resources/extensions/gsd/memory-backfill.ts +26 -20
  360. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
  361. package/src/resources/extensions/gsd/metrics.ts +4 -4
  362. package/src/resources/extensions/gsd/migrate-external.ts +8 -2
  363. package/src/resources/extensions/gsd/migration-auto-check.ts +23 -0
  364. package/src/resources/extensions/gsd/milestone-ids.ts +31 -2
  365. package/src/resources/extensions/gsd/milestone-implementation-evidence.ts +35 -21
  366. package/src/resources/extensions/gsd/orphan-stash-audit.ts +108 -20
  367. package/src/resources/extensions/gsd/prompts/code-review.md +6 -4
  368. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
  369. package/src/resources/extensions/gsd/prompts/plan-slice.md +3 -3
  370. package/src/resources/extensions/gsd/quick.ts +43 -2
  371. package/src/resources/extensions/gsd/root-write-leak-guard.ts +13 -1
  372. package/src/resources/extensions/gsd/safety/destructive-guard.ts +9 -1
  373. package/src/resources/extensions/gsd/safety/evidence-collector.ts +16 -1
  374. package/src/resources/extensions/gsd/safety/file-change-validator.ts +8 -2
  375. package/src/resources/extensions/gsd/session-forensics.ts +11 -1
  376. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
  377. package/src/resources/extensions/gsd/state/derive/cache.ts +46 -0
  378. package/src/resources/extensions/gsd/state/derive/db-open.ts +45 -0
  379. package/src/resources/extensions/gsd/state/derive/from-db.ts +561 -0
  380. package/src/resources/extensions/gsd/state/derive/index.ts +104 -0
  381. package/src/resources/extensions/gsd/state/derive/interrupted-work.ts +31 -0
  382. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +81 -7
  383. package/src/resources/extensions/gsd/state-reconciliation/index.ts +50 -24
  384. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +43 -28
  385. package/src/resources/extensions/gsd/state.ts +32 -732
  386. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +4 -3
  387. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +98 -1
  388. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +14 -5
  389. package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +36 -0
  390. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +182 -4
  391. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +146 -1
  392. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +30 -0
  393. package/src/resources/extensions/gsd/tests/commands-context.test.ts +26 -0
  394. package/src/resources/extensions/gsd/tests/commands-gsd-core.test.ts +1 -0
  395. package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +80 -0
  396. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +28 -0
  397. package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +69 -0
  398. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +11 -0
  399. package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +48 -8
  400. package/src/resources/extensions/gsd/tests/complete-task.test.ts +75 -0
  401. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +55 -2
  402. package/src/resources/extensions/gsd/tests/db-memory-fts-schema.test.ts +58 -3
  403. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +51 -0
  404. package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +44 -0
  405. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +143 -0
  406. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +26 -1
  407. package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +70 -2
  408. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +107 -0
  409. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +239 -2
  410. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
  411. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +16 -0
  412. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
  413. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +40 -0
  414. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +37 -2
  415. package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -0
  416. package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +4 -0
  417. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +42 -0
  418. package/src/resources/extensions/gsd/tests/health-widget.test.ts +268 -3
  419. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +130 -3
  420. package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts +93 -0
  421. package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +56 -9
  422. package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +47 -0
  423. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +35 -0
  424. package/src/resources/extensions/gsd/tests/knowledge-cold-start.test.ts +14 -0
  425. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +78 -0
  426. package/src/resources/extensions/gsd/tests/memory-store.test.ts +48 -0
  427. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +31 -1
  428. package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +6 -0
  429. package/src/resources/extensions/gsd/tests/metrics.test.ts +1 -0
  430. package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +57 -0
  431. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +70 -0
  432. package/src/resources/extensions/gsd/tests/orchestrator-logs.test.ts +43 -1
  433. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +91 -7
  434. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +26 -0
  435. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -1
  436. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
  437. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +10 -0
  438. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +103 -4
  439. package/src/resources/extensions/gsd/tests/plan-task.test.ts +44 -1
  440. package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +4 -2
  441. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +54 -1
  442. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +50 -14
  443. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +58 -0
  444. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -6
  445. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +195 -1
  446. package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +185 -0
  447. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +87 -0
  448. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +103 -0
  449. package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +20 -1
  450. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +15 -3
  451. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +56 -0
  452. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
  453. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +208 -0
  454. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +32 -3
  455. package/src/resources/extensions/gsd/tests/undo.test.ts +74 -0
  456. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +193 -14
  457. package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +25 -0
  458. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +38 -0
  459. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +79 -0
  460. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +69 -4
  461. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
  462. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +96 -15
  463. package/src/resources/extensions/gsd/tests/workflow-mcp-preflight.test.ts +1 -0
  464. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -4
  465. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +6 -5
  466. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +151 -2
  467. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
  468. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
  469. package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
  470. package/src/resources/extensions/gsd/tools/complete-task.ts +53 -15
  471. package/src/resources/extensions/gsd/tools/exec-tool.ts +7 -3
  472. package/src/resources/extensions/gsd/tools/plan-slice.ts +60 -47
  473. package/src/resources/extensions/gsd/tools/plan-task.ts +30 -5
  474. package/src/resources/extensions/gsd/undo.ts +47 -6
  475. package/src/resources/extensions/gsd/unit-context-composer.ts +33 -7
  476. package/src/resources/extensions/gsd/unit-registry.ts +36 -6
  477. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +41 -5
  478. package/src/resources/extensions/gsd/validation-block-guard.ts +13 -7
  479. package/src/resources/extensions/gsd/verification-gate.ts +8 -0
  480. package/src/resources/extensions/gsd/workflow-manifest.ts +141 -7
  481. package/src/resources/extensions/gsd/workflow-projections.ts +20 -14
  482. package/src/resources/extensions/gsd/workspace-git-preflight.ts +31 -0
  483. package/src/resources/extensions/gsd/worktree-manager.ts +41 -1
  484. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
  485. package/dist/web/standalone/.next/static/chunks/796.e0bdc932325d7e03.js +0 -10
  486. package/dist/web/standalone/.next/static/chunks/webpack-f46ea08200a0227e.js +0 -1
  487. /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → 2A_WqqCS-EoYZxN9_v3d2}/_buildManifest.js +0 -0
  488. /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → 2A_WqqCS-EoYZxN9_v3d2}/_ssgManifest.js +0 -0
@@ -17,7 +17,8 @@ import {
17
17
  getSlice,
18
18
  } from "../gsd-db.ts";
19
19
  import { autoHealSketchFlags } from "../state-reconciliation/drift/sketch-flag.ts";
20
- import { deriveState, deriveStateFromDb } from "../state.ts";
20
+ import { deriveState, deriveStateFromDb, invalidateStateCache } from "../state.ts";
21
+ import { reconcileBeforeDispatch } from "../state-reconciliation.ts";
21
22
  import { resolveDispatch } from "../auto-dispatch.ts";
22
23
  import type { DispatchContext } from "../auto-dispatch.ts";
23
24
 
@@ -174,7 +175,7 @@ test("ADR-011: refining + flag flipped OFF mid-milestone → falls through to pl
174
175
  }
175
176
  });
176
177
 
177
- test("ADR-011: existing PLAN heals stale sketch flag via deriveStateFromDb (progressive_planning ON)", async (t) => {
178
+ test("ADR-011: existing PLAN + stale sketch flag heals via reconcileBeforeDispatch, then dispatch routes past refining (progressive_planning ON)", async (t) => {
178
179
  const originalCwd = process.cwd();
179
180
  const base = makeFixtureBase();
180
181
  t.after(() => cleanup(base, originalCwd));
@@ -188,11 +189,22 @@ test("ADR-011: existing PLAN heals stale sketch flag via deriveStateFromDb (prog
188
189
  );
189
190
  process.chdir(base);
190
191
 
191
- // deriveStateFromDb auto-heals the stale sketch flag when PLAN.md exists,
192
- // regardless of the progressive_planning preference.
192
+ // Derivation is pure (ADR-017): a stale sketch flag (PLAN on disk but
193
+ // is_sketch=1) yields 'refining' and must NOT mutate the DB. Healing is
194
+ // owned by reconcileBeforeDispatch, which runs before every dispatch.
195
+ invalidateStateCache();
196
+ const beforeReconcile = await deriveStateFromDb(base);
197
+ assert.equal(beforeReconcile.activeSlice?.id, "S02");
198
+ assert.equal(beforeReconcile.phase, "refining", "derive alone must not heal the stale sketch flag");
199
+ assert.equal(getSlice("M001", "S02")?.is_sketch, 1, "derive must not mutate is_sketch");
200
+
201
+ const reconcile = await reconcileBeforeDispatch(base);
202
+ assert.equal(reconcile.ok, true);
203
+ assert.equal(getSlice("M001", "S02")?.is_sketch, 0, "reconcile clears the stale sketch flag once PLAN exists");
204
+
205
+ invalidateStateCache();
193
206
  const state = await deriveStateFromDb(base);
194
- assert.equal(getSlice("M001", "S02")?.is_sketch, 0, "derive: flag cleared when PLAN exists");
195
- assert.equal(state.phase, "planning", "derive: phase advances past refining once flag is healed");
207
+ assert.equal(state.phase, "planning", "re-derive advances past refining once the flag is healed");
196
208
 
197
209
  const ctx: DispatchContext = {
198
210
  basePath: base,
@@ -229,7 +241,7 @@ test("ADR-011: autoHealSketchFlags flips is_sketch=0 when PLAN file exists", asy
229
241
  assert.equal(getSlice("M001", "S02")?.is_sketch, 0, "post-heal: flag cleared");
230
242
  });
231
243
 
232
- test("ADR-011: deriveStateFromDb auto-heals stale sketch flag when PLAN exists", async (t) => {
244
+ test("ADR-011: reconcileBeforeDispatch auto-heals stale sketch flag when PLAN exists", async (t) => {
233
245
  const originalCwd = process.cwd();
234
246
  const base = makeFixtureBase();
235
247
  t.after(() => cleanup(base, originalCwd));
@@ -244,12 +256,23 @@ test("ADR-011: deriveStateFromDb auto-heals stale sketch flag when PLAN exists",
244
256
  );
245
257
  process.chdir(base);
246
258
 
247
- const state = await deriveStateFromDb(base);
248
- assert.equal(getSlice("M001", "S02")?.is_sketch, 0, "derive should clear stale is_sketch");
249
- assert.equal(state.phase, "planning", "state should advance past refining once stale flag is healed");
259
+ // Pure derivation reports the stale flag as 'refining' without repairing it.
260
+ invalidateStateCache();
261
+ const stale = await deriveStateFromDb(base);
262
+ assert.equal(stale.phase, "refining", "derive alone must not heal the stale flag");
263
+ assert.equal(getSlice("M001", "S02")?.is_sketch, 1, "is_sketch unchanged before reconcile");
264
+
265
+ // Reconciliation owns the repair (ADR-017 stale-sketch-flag drift handler).
266
+ const reconcile = await reconcileBeforeDispatch(base);
267
+ assert.equal(reconcile.ok, true);
268
+ assert.equal(getSlice("M001", "S02")?.is_sketch, 0, "reconcile should clear stale is_sketch");
269
+
270
+ invalidateStateCache();
271
+ const healed = await deriveStateFromDb(base);
272
+ assert.equal(healed.phase, "planning", "state advances past refining once the stale flag is healed");
250
273
  });
251
274
 
252
- test("ADR-011: deriveState uses canonical artifact root for sketch-flag healing", async (t) => {
275
+ test("ADR-011: deriveState stays pure across worktree/canonical-root; healing belongs to reconcile at the canonical artifact root", async (t) => {
253
276
  const originalCwd = process.cwd();
254
277
  const base = makeFixtureBase();
255
278
  t.after(() => cleanup(base, originalCwd));
@@ -265,9 +288,22 @@ test("ADR-011: deriveState uses canonical artifact root for sketch-flag healing"
265
288
  mkdirSync(worktreePath, { recursive: true });
266
289
  process.chdir(worktreePath);
267
290
 
268
- const state = await deriveState(worktreePath, { projectRootForReads: base });
269
- assert.equal(getSlice("M001", "S02")?.is_sketch, 0, "deriveState should heal from canonical artifact root");
270
- assert.equal(state.phase, "planning", "state should advance past refining when PLAN exists at canonical root");
291
+ // Deriving from the worktree with reads routed to the canonical artifact
292
+ // root resolves DB state but never mutates it (ADR-017: derive is pure).
293
+ // The legacy projectRootForReads-driven heal is gone; healing now happens
294
+ // in reconcileBeforeDispatch, which auto runs against canonicalProjectRoot.
295
+ invalidateStateCache();
296
+ const beforeReconcile = await deriveState(worktreePath, { projectRootForReads: base });
297
+ assert.equal(beforeReconcile.phase, "refining", "derive alone must not heal, even via projectRootForReads");
298
+ assert.equal(getSlice("M001", "S02")?.is_sketch, 1, "derive must not mutate is_sketch");
299
+
300
+ const reconcile = await reconcileBeforeDispatch(base);
301
+ assert.equal(reconcile.ok, true);
302
+ assert.equal(getSlice("M001", "S02")?.is_sketch, 0, "reconcile at the canonical root heals the stale flag");
303
+
304
+ invalidateStateCache();
305
+ const healed = await deriveState(worktreePath, { projectRootForReads: base });
306
+ assert.equal(healed.phase, "planning", "re-derive advances past refining once healed at the canonical root");
271
307
  });
272
308
 
273
309
  test("ADR-011: schema v16 is idempotent — re-opening DB preserves is_sketch and sketch_scope columns", async (t) => {
@@ -72,6 +72,25 @@ function setupDependencyFixture(
72
72
  mkdirSync(targetSliceDir, { recursive: true });
73
73
  }
74
74
 
75
+ function setupFlatPhaseSlicePlan(base: string): void {
76
+ const phaseDir = join(base, ".gsd", "phases", "01-flat-phase");
77
+ mkdirSync(phaseDir, { recursive: true });
78
+ writeFileSync(
79
+ join(phaseDir, "01-01-PLAN.md"),
80
+ [
81
+ "# S01: Flat phase slice",
82
+ "",
83
+ "## Tasks",
84
+ "",
85
+ "- [ ] **T01: Flat task** `est:15m`",
86
+ "",
87
+ "## Verification",
88
+ "",
89
+ "- Rendered prompt points at this slice plan.",
90
+ ].join("\n"),
91
+ );
92
+ }
93
+
75
94
  // ─── inlineDependencySummaries truncation ─────────────────────────────────────
76
95
 
77
96
  describe("prompt-budget: inlineDependencySummaries truncation", () => {
@@ -412,6 +431,26 @@ describe("prompt-budget: execute-task template", () => {
412
431
  }
413
432
  });
414
433
 
434
+ it("flat-phase execute-task fallback points at the slice plan", async () => {
435
+ const base = createFixtureBase();
436
+ try {
437
+ setupFlatPhaseSlicePlan(base);
438
+
439
+ const prompt = await buildExecuteTaskPrompt("M001", "S01", "Slice", "T01", "Task", base, {
440
+ level: "minimal",
441
+ sessionContextWindow: 128_000,
442
+ });
443
+
444
+ assert.match(
445
+ prompt,
446
+ /Task plan not found at dispatch time\. Read `\.gsd\/phases\/01-flat-phase\/01-01-PLAN\.md` before executing\./,
447
+ );
448
+ assert.doesNotMatch(prompt, /\.gsd\/phases\/01-flat-phase\/tasks\/T01-PLAN\.md/);
449
+ } finally {
450
+ cleanup(base);
451
+ }
452
+ });
453
+
415
454
  it("verificationBudget format varies with context window size", () => {
416
455
  const budget128K = computeBudgets(128_000);
417
456
  const budget1M = computeBudgets(1_000_000);
@@ -566,6 +605,25 @@ describe("prompt-budget: execute-task builder truncation pattern", () => {
566
605
  });
567
606
 
568
607
  describe("prompt-budget: reactive-execute builder", () => {
608
+ it("flat-phase subagent fallback points at the slice plan", async () => {
609
+ const base = createFixtureBase();
610
+ try {
611
+ setupFlatPhaseSlicePlan(base);
612
+
613
+ const prompt = await buildReactiveExecutePrompt("M001", "Milestone", "S01", "Slice", ["T01"], base, undefined, {
614
+ sessionContextWindow: 128_000,
615
+ });
616
+
617
+ assert.match(
618
+ prompt,
619
+ /Task plan not found at dispatch time\. Read `\.gsd\/phases\/01-flat-phase\/01-01-PLAN\.md` before executing\./,
620
+ );
621
+ assert.doesNotMatch(prompt, /\.gsd\/phases\/01-flat-phase\/tasks\/T01-PLAN\.md/);
622
+ } finally {
623
+ cleanup(base);
624
+ }
625
+ });
626
+
569
627
  it("caps dependency carry-forward per ready subagent", async () => {
570
628
  const base = createFixtureBase();
571
629
  try {
@@ -533,6 +533,7 @@ test("plan-milestone prompt references DB-backed planning tool and explicitly fo
533
533
  assert.match(prompt, /Do \*\*not\*\* write `?\{\{outputPath\}\}`?, `?ROADMAP\.md`?, or other planning artifacts manually/i);
534
534
  assert.match(prompt, /NEVER call `gsd_plan_milestone` with only `milestoneId` and `sliceId`/);
535
535
  assert.match(prompt, /gsd_plan_slice/);
536
+ assert.match(prompt, /gsd_plan_task/);
536
537
  });
537
538
 
538
539
  test("discuss prompts forbid gsd_plan_milestone slice-only tool args", () => {
@@ -548,12 +549,12 @@ test("plan-slice prompt no longer frames direct PLAN writes as the source of tru
548
549
  assert.match(prompt, /Do \*\*not\*\* rely on direct `PLAN\.md` writes as the source of truth/i);
549
550
  });
550
551
 
551
- test("plan-slice prompt explicitly names gsd_plan_slice as DB-backed planning tool", () => {
552
+ test("plan-slice prompt explicitly names incremental DB-backed planning tools", () => {
552
553
  const prompt = readPrompt("plan-slice");
553
554
  assert.match(prompt, /gsd_plan_slice/);
554
555
  assert.match(prompt, /gsd_plan_task/);
555
- // The prompt should describe the DB-backed tool as the canonical write path
556
- assert.match(prompt, /DB-backed tool is the canonical write path/i);
556
+ assert.match(prompt, /Persist incrementally through DB-backed tools/i);
557
+ assert.match(prompt, /DB-backed tools are the canonical write path/i);
557
558
  });
558
559
 
559
560
  test("plan-slice prompt does not instruct direct file writes as a primary step", () => {
@@ -562,11 +563,12 @@ test("plan-slice prompt does not instruct direct file writes as a primary step",
562
563
  assert.doesNotMatch(prompt, /^\d+\.\s+Write `?\{\{outputPath\}\}`?\s*$/m);
563
564
  });
564
565
 
565
- test("plan-slice prompt clarifies gsd_plan_slice handles task persistence", () => {
566
+ test("plan-slice prompt requires per-task incremental persistence", () => {
566
567
  const prompt = readPrompt("plan-slice");
567
- // gsd_plan_slice persists tasks in its transaction — no separate gsd_plan_task calls needed
568
568
  assert.match(prompt, /gsd_plan_task/);
569
- assert.match(prompt, /gsd_plan_slice` handles task persistence/i);
569
+ assert.match(prompt, /omit `tasks` for this metadata call/i);
570
+ assert.match(prompt, /call `gsd_plan_task` once per task/i);
571
+ assert.doesNotMatch(prompt, /do not call `gsd_plan_task`/i);
570
572
  });
571
573
 
572
574
  test("plan-slice prompt references web app UAT guidance when planning browser work", () => {
@@ -7,7 +7,7 @@
7
7
 
8
8
  import test from "node:test";
9
9
  import assert from "node:assert/strict";
10
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
10
+ import { mkdtempSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
11
11
  import { tmpdir } from "node:os";
12
12
  import { join } from "node:path";
13
13
  import { classifyError, isTransient, isTransientNetworkError } from "../error-classifier.ts";
@@ -26,6 +26,10 @@ import { _buildCancelledUnitStopReason } from "../auto/phase-helpers.ts";
26
26
  import { _classifyZeroToolProviderMessageForTest } from "../auto/unit-phase.ts";
27
27
  import { autoSession } from "../auto-runtime-state.ts";
28
28
  import { getNextFallbackModel } from "../preferences.ts";
29
+ import { clearGuidedUnitContext, getGuidedUnitContext, setGuidedUnitContext } from "../guided-unit-context.ts";
30
+ import { initNotificationStore, readNotifications, _resetNotificationStore } from "../notification-store.ts";
31
+ import { installNotifyInterceptor } from "../bootstrap/notify-interceptor.ts";
32
+ import { extractTrace } from "../session-forensics.ts";
29
33
  // Zero-import module — imported by path rather than through the package
30
34
  // barrel to avoid pulling the full AgentSession / @gsd/pi-ai dep graph into
31
35
  // this unit test (see #4837).
@@ -488,6 +492,63 @@ test("pauseAutoForProviderError falls back to indefinite pause when not rate lim
488
492
  ]);
489
493
  });
490
494
 
495
+ test("agent_end retries when empty errorMessage has stream failure in content (#956)", async () => {
496
+ const originalSetTimeout = globalThis.setTimeout;
497
+ const notifications: Array<{ message: string; level?: string }> = [];
498
+ const sendMessageCalls: unknown[][] = [];
499
+ const timers: Array<{ fn: () => void; delay: number }> = [];
500
+
501
+ resetTransientRetryState();
502
+ autoSession.reset();
503
+ // handleAgentEnd returns at the isAutoActive() guard unless auto-mode is
504
+ // active. Set the minimum fields needed to reach the stopReason === "error"
505
+ // branch without requiring a real DB or worktree.
506
+ autoSession.active = true;
507
+ autoSession.currentUnit = { type: "execute-task", id: "M001/S01/T01", startedAt: Date.now() };
508
+
509
+ globalThis.setTimeout = ((fn: () => void, delay?: number) => {
510
+ timers.push({ fn, delay: delay ?? 0 });
511
+ return 0 as unknown as ReturnType<typeof setTimeout>;
512
+ }) as typeof setTimeout;
513
+
514
+ try {
515
+ await handleAgentEnd({
516
+ sendMessage: (...args: unknown[]) => {
517
+ sendMessageCalls.push(args);
518
+ },
519
+ } as any, {
520
+ messages: [{
521
+ role: "assistant",
522
+ stopReason: "error",
523
+ errorMessage: "",
524
+ content: [{ type: "text", text: "API Error: stream idle timeout - partial response received" }],
525
+ }],
526
+ } as any, {
527
+ model: { provider: "openai-codex", id: "gpt-5.5" },
528
+ ui: {
529
+ notify(message: string, level?: "info" | "warning" | "error" | "success") {
530
+ notifications.push({ message, level });
531
+ },
532
+ },
533
+ } as any);
534
+
535
+ assert.equal(timers.length, 1, "empty errorMessage stream failures should use the network retry path");
536
+ assert.equal(timers[0].delay, 3_000);
537
+ assert.deepEqual(notifications[0], {
538
+ message: "Network error on gpt-5.5: API Error: stream idle timeout - partial response received. Retry 1/2 in 3s...",
539
+ level: "warning",
540
+ });
541
+
542
+ timers[0].fn();
543
+ assert.equal(sendMessageCalls.length, 1);
544
+ assert.deepEqual(sendMessageCalls[0][1], { triggerTurn: true });
545
+ } finally {
546
+ globalThis.setTimeout = originalSetTimeout;
547
+ resetTransientRetryState();
548
+ autoSession.reset();
549
+ }
550
+ });
551
+
491
552
  test("rate-limit agent_end walks past unavailable fallback models before pausing (#716 follow-up)", async () => {
492
553
  const originalCwd = process.cwd();
493
554
  const originalSetTimeout = globalThis.setTimeout;
@@ -648,6 +709,139 @@ test("does not suppress deleted-worktree provider errors outside terminal comple
648
709
  assert.equal(event.message.stopReason, "error");
649
710
  });
650
711
 
712
+ test("manual guided discuss provider error records warning and activity marker (#944)", async () => {
713
+ const originalCwd = process.cwd();
714
+ const base = mkdtempSync(join(tmpdir(), "gsd-manual-discuss-error-"));
715
+ const notifications: Array<{ message: string; level?: string }> = [];
716
+ const sendMessageCalls: unknown[][] = [];
717
+
718
+ try {
719
+ autoSession.reset();
720
+ mkdirSync(join(base, ".git"), { recursive: true });
721
+ mkdirSync(join(base, ".gsd"), { recursive: true });
722
+ process.chdir(base);
723
+ initNotificationStore(base);
724
+
725
+ // Use base as the guided context path so gsdRoot(base) hits the fast path
726
+ // (.gsd exists at base directly) and doesn't need git to walk up from a
727
+ // subdirectory — the empty .git folder is not a real repo and git resolution
728
+ // from a child directory would return the wrong .gsd path.
729
+ setGuidedUnitContext(base, "discuss-slice");
730
+
731
+ const ctx = {
732
+ model: { provider: "openai-codex", id: "gpt-5.1-codex" },
733
+ modelRegistry: { getAvailable: () => [] },
734
+ ui: {
735
+ notify(message: string, level?: "info" | "warning" | "error" | "success") {
736
+ notifications.push({ message, level });
737
+ },
738
+ },
739
+ } as any;
740
+ installNotifyInterceptor(ctx);
741
+
742
+ const pi = {
743
+ sendMessage: (...args: unknown[]) => {
744
+ sendMessageCalls.push(args);
745
+ },
746
+ } as any;
747
+
748
+ await handleAgentEnd(pi, {
749
+ messages: [{
750
+ role: "assistant",
751
+ stopReason: "error",
752
+ errorMessage: "",
753
+ content: [{ type: "text", text: "stream idle timeout while saving summary" }],
754
+ }],
755
+ } as any, ctx);
756
+
757
+ assert.deepEqual(sendMessageCalls, [], "manual discuss terminal errors must not auto-retry or redispatch");
758
+ assert.equal(getGuidedUnitContext(base), null, "guided unit context must still be cleared after the turn");
759
+ assert.equal(notifications.length, 1);
760
+ assert.equal(notifications[0]?.level, "warning");
761
+ assert.match(notifications[0]?.message ?? "", /Manual \/gsd discuss discuss-slice ended with a provider error/);
762
+ assert.match(notifications[0]?.message ?? "", /openai-codex\/gpt-5\.1-codex/);
763
+ assert.match(notifications[0]?.message ?? "", /stream idle timeout/);
764
+
765
+ const persisted = readNotifications(base);
766
+ assert.equal(persisted.length, 1, "wrapped notify should persist exactly one warning notification");
767
+ assert.equal(persisted[0]?.severity, "warning");
768
+ assert.equal(persisted[0]?.source, "notify");
769
+
770
+ const activityDir = join(base, ".gsd", "activity");
771
+ const files = readdirSync(activityDir).filter((file) => file.endsWith(".jsonl"));
772
+ assert.equal(files.length, 1, "manual guided provider error should write one activity marker");
773
+ const entries = readFileSync(join(activityDir, files[0]!), "utf-8")
774
+ .split("\n")
775
+ .filter(Boolean)
776
+ .map((line) => JSON.parse(line));
777
+ const trace = extractTrace(entries);
778
+ assert.equal(trace.errors.length, 1);
779
+ assert.match(trace.errors[0] ?? "", /discuss-slice/);
780
+ assert.match(trace.errors[0] ?? "", /openai-codex\/gpt-5\.1-codex/);
781
+ assert.match(trace.errors[0] ?? "", /stream idle timeout/);
782
+ } finally {
783
+ clearGuidedUnitContext();
784
+ _resetNotificationStore();
785
+ autoSession.reset();
786
+ process.chdir(originalCwd);
787
+ rmSync(base, { recursive: true, force: true });
788
+ }
789
+ });
790
+
791
+ test("manual guided discuss user-cancel is not treated as a provider error (#944)", async () => {
792
+ const originalCwd = process.cwd();
793
+ const base = mkdtempSync(join(tmpdir(), "gsd-manual-discuss-cancel-"));
794
+ const guidedBase = join(base, "slice-work");
795
+ const notifications: Array<{ message: string; level?: string }> = [];
796
+
797
+ try {
798
+ autoSession.reset();
799
+ mkdirSync(join(base, ".git"), { recursive: true });
800
+ mkdirSync(join(base, ".gsd"), { recursive: true });
801
+ mkdirSync(guidedBase, { recursive: true });
802
+ process.chdir(base);
803
+ initNotificationStore(base);
804
+
805
+ setGuidedUnitContext(guidedBase, "discuss-slice");
806
+
807
+ const ctx = {
808
+ model: { provider: "anthropic", id: "claude-opus-4" },
809
+ modelRegistry: { getAvailable: () => [] },
810
+ ui: {
811
+ notify(message: string, level?: "info" | "warning" | "error" | "success") {
812
+ notifications.push({ message, level });
813
+ },
814
+ },
815
+ } as any;
816
+ installNotifyInterceptor(ctx);
817
+
818
+ const pi = { sendMessage: () => {} } as any;
819
+
820
+ await handleAgentEnd(pi, {
821
+ messages: [{
822
+ role: "assistant",
823
+ stopReason: "error",
824
+ errorMessage: "Request aborted by user",
825
+ content: [],
826
+ }],
827
+ } as any, ctx);
828
+
829
+ assert.deepEqual(notifications, [], "user-cancel stopReason=error must not emit a provider-error warning");
830
+ assert.equal(getGuidedUnitContext(guidedBase), null, "context must be cleared even for user-cancel");
831
+
832
+ // No activity directory should have been created
833
+ let activityExists = false;
834
+ try { readdirSync(join(base, ".gsd", "activity")); activityExists = true; } catch { /* expected */ }
835
+ assert.equal(activityExists, false, "user-cancel must not write an activity error marker");
836
+ } finally {
837
+ clearGuidedUnitContext();
838
+ _resetNotificationStore();
839
+ autoSession.reset();
840
+ process.chdir(originalCwd);
841
+ rmSync(base, { recursive: true, force: true });
842
+ }
843
+ });
844
+
651
845
  // ── resumeAutoAfterProviderDelay ────────────────────────────────────────────
652
846
 
653
847
  test("resumeAutoAfterProviderDelay restarts paused auto-mode from the recorded base path", async () => {
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Behavioural regression test for the milestone-closeout UAT gate —
3
+ * `readUatGateVerdict`.
4
+ *
5
+ * The gate (ADR-017: DB-authoritative UAT sign-off) reads a slice's UAT
6
+ * verdict from its ASSESSMENT artifact via the *canonical* expected path
7
+ * (`resolveSliceFile` + a path-keyed `getAssessment`). When a milestone
8
+ * artifact-layout migration orphans the ASSESSMENT markdown from that canonical
9
+ * path (e.g. `phases/…` → `milestones/…`), the gate used to return `null` and
10
+ * block milestone closure with "missing UAT PASS verdict" — even though the
11
+ * verdict was correctly recorded in the `assessments` table by
12
+ * `gsd_uat_result_save`.
13
+ *
14
+ * The DB fallback added to `readUatGateVerdict` consults the authoritative
15
+ * `assessments` table by (milestoneId, sliceId, scope='run-uat') identity,
16
+ * independent of path. These tests pin that behaviour.
17
+ */
18
+
19
+ import { describe, test, beforeEach, afterEach } from 'node:test';
20
+ import assert from 'node:assert/strict';
21
+ import * as fs from 'node:fs';
22
+ import * as path from 'node:path';
23
+ import * as os from 'node:os';
24
+
25
+ import {
26
+ openDatabase,
27
+ closeDatabase,
28
+ insertMilestone,
29
+ insertSlice,
30
+ insertAssessment,
31
+ } from '../gsd-db.ts';
32
+ import { readUatGateVerdict } from '../auto-dispatch.ts';
33
+
34
+ function tempDbPath(): string {
35
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-uat-gate-'));
36
+ return path.join(dir, 'test.db');
37
+ }
38
+
39
+ function cleanupDb(dbPath: string): void {
40
+ closeDatabase();
41
+ try { fs.rmSync(path.dirname(dbPath), { recursive: true, force: true }); } catch { /* */ }
42
+ }
43
+
44
+ const MID = 'M001';
45
+ const SLICE = 'S01';
46
+
47
+ /** Canonical on-disk ASSESSMENT path produced by `resolveSliceFile`. */
48
+ function canonicalAssessmentPath(basePath: string): string {
49
+ return path.join(basePath, '.gsd', 'milestones', MID, 'slices', SLICE, `${SLICE}-ASSESSMENT.md`);
50
+ }
51
+
52
+ /** An ASSESSMENT body that declares a runtime-executable UAT type and a PASS verdict. */
53
+ const RUNTIME_PASS_BODY = [
54
+ '---',
55
+ 'verdict: pass',
56
+ '---',
57
+ '',
58
+ '# S01 UAT Assessment',
59
+ '',
60
+ '## UAT Type',
61
+ '- UAT mode: runtime-executable',
62
+ '',
63
+ '## Result',
64
+ 'All checks passed.',
65
+ ].join('\n');
66
+
67
+ describe('readUatGateVerdict — DB fallback for orphaned ASSESSMENT', () => {
68
+ let dbPath: string;
69
+ let basePath: string;
70
+
71
+ beforeEach(() => {
72
+ dbPath = tempDbPath();
73
+ openDatabase(dbPath);
74
+ basePath = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-uat-gate-proj-'));
75
+ insertMilestone({ id: MID });
76
+ insertSlice({ id: SLICE, milestoneId: MID });
77
+ });
78
+
79
+ afterEach(() => {
80
+ cleanupDb(dbPath);
81
+ try { fs.rmSync(basePath, { recursive: true, force: true }); } catch { /* */ }
82
+ });
83
+
84
+ test('returns pass when the ASSESSMENT is keyed by a legacy/orphaned path (the bug)', async () => {
85
+ // Reproduces milestone 15: `gsd_uat_result_save` wrote S01's assessment row
86
+ // under a now-migrated path; the canonical file never existed on disk and
87
+ // the `assessments.path` is not what `resolveSliceFile` computes.
88
+ insertAssessment({
89
+ // Deliberately non-canonical — a legacy `phases/…` path.
90
+ path: `.gsd/phases/01-some-feature/01-01-ASSESSMENT.md`,
91
+ milestoneId: MID,
92
+ sliceId: SLICE,
93
+ status: 'pass',
94
+ scope: 'run-uat',
95
+ fullContent: RUNTIME_PASS_BODY,
96
+ });
97
+
98
+ const result = await readUatGateVerdict(basePath, MID, SLICE);
99
+
100
+ assert.ok(result, 'expected the DB fallback to resolve a verdict, got null');
101
+ assert.equal(result!.verdict, 'pass');
102
+ });
103
+
104
+ test('the DB fallback derives uatType from the assessment body when no file exists', async () => {
105
+ insertAssessment({
106
+ path: `.gsd/phases/01-some-feature/01-01-ASSESSMENT.md`,
107
+ milestoneId: MID,
108
+ sliceId: SLICE,
109
+ status: 'pass',
110
+ scope: 'run-uat',
111
+ fullContent: RUNTIME_PASS_BODY,
112
+ });
113
+
114
+ const result = await readUatGateVerdict(basePath, MID, SLICE);
115
+
116
+ assert.ok(result);
117
+ assert.equal(result!.verdict, 'pass');
118
+ assert.equal(result!.uatType, 'runtime-executable');
119
+ });
120
+
121
+ test('canonical ASSESSMENT file on disk still resolves (regression guard)', async () => {
122
+ // When the file is present at the canonical path, the existing path-keyed
123
+ // lookup must resolve it without needing the fallback.
124
+ const file = canonicalAssessmentPath(basePath);
125
+ fs.mkdirSync(path.dirname(file), { recursive: true });
126
+ fs.writeFileSync(file, RUNTIME_PASS_BODY);
127
+ // Also seed the path-keyed assessments row, mirroring a normal save.
128
+ insertAssessment({
129
+ path: `.gsd/milestones/${MID}/slices/${SLICE}/${SLICE}-ASSESSMENT.md`,
130
+ milestoneId: MID,
131
+ sliceId: SLICE,
132
+ status: 'pass',
133
+ scope: 'run-uat',
134
+ fullContent: RUNTIME_PASS_BODY,
135
+ });
136
+
137
+ const result = await readUatGateVerdict(basePath, MID, SLICE);
138
+
139
+ assert.ok(result);
140
+ assert.equal(result!.verdict, 'pass');
141
+ assert.equal(result!.uatType, 'runtime-executable');
142
+ });
143
+
144
+ test('a roadmap-scoped assessment does NOT satisfy the UAT gate', async () => {
145
+ // `reassess-roadmap` writes roadmap-scoped assessments to the same
146
+ // S##-ASSESSMENT path; those must never be treated as a UAT verdict. The
147
+ // legacy-path fallback queries scope='run-uat', so a roadmap-only row is
148
+ // invisible and the gate returns null.
149
+ insertAssessment({
150
+ path: `.gsd/milestones/${MID}/slices/${SLICE}/${SLICE}-ASSESSMENT.md`,
151
+ milestoneId: MID,
152
+ sliceId: SLICE,
153
+ status: 'pass',
154
+ scope: 'roadmap',
155
+ fullContent: RUNTIME_PASS_BODY,
156
+ });
157
+
158
+ const result = await readUatGateVerdict(basePath, MID, SLICE);
159
+
160
+ assert.equal(result, null, 'roadmap-scoped assessments must not satisfy the UAT gate');
161
+ });
162
+
163
+ test('returns null when no assessment and no file exist (fallback does not hallucinate)', async () => {
164
+ const result = await readUatGateVerdict(basePath, MID, SLICE);
165
+ assert.equal(result, null);
166
+ });
167
+
168
+ test('surfaces a recorded non-pass verdict via the DB fallback', async () => {
169
+ // A failing verdict stored under a legacy path must surface (not be masked
170
+ // as "missing") so the gate's non-PASS branch can act on it.
171
+ insertAssessment({
172
+ path: `.gsd/phases/01-some-feature/01-01-ASSESSMENT.md`,
173
+ milestoneId: MID,
174
+ sliceId: SLICE,
175
+ status: 'fail',
176
+ scope: 'run-uat',
177
+ fullContent: RUNTIME_PASS_BODY.replace('verdict: pass', 'verdict: fail'),
178
+ });
179
+
180
+ const result = await readUatGateVerdict(basePath, MID, SLICE);
181
+
182
+ assert.ok(result);
183
+ assert.equal(result!.verdict, 'fail');
184
+ });
185
+ });