@opengsd/gsd-pi 1.8.1 → 1.9.0-dev.5c1a3ff2

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 (546) hide show
  1. package/README.md +10 -8
  2. package/dist/cli.js +5 -1
  3. package/dist/headless-events.d.ts +2 -1
  4. package/dist/headless-events.js +11 -3
  5. package/dist/headless-milestone-readiness.d.ts +29 -0
  6. package/dist/headless-milestone-readiness.js +161 -0
  7. package/dist/headless.js +25 -2
  8. package/dist/print-mode-exit.d.ts +12 -0
  9. package/dist/print-mode-exit.js +14 -0
  10. package/dist/resources/.managed-resources-content-hash +1 -1
  11. package/dist/resources/GSD-WORKFLOW.md +18 -49
  12. package/dist/resources/extensions/browser-tools/capture.js +2 -77
  13. package/dist/resources/extensions/browser-tools/screenshot-constraints.js +83 -0
  14. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +17 -2
  15. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +30 -2
  16. package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
  17. package/dist/resources/extensions/gsd/auto-artifact-paths.js +16 -10
  18. package/dist/resources/extensions/gsd/auto-dispatch.js +74 -19
  19. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -0
  20. package/dist/resources/extensions/gsd/auto-prompts.js +125 -18
  21. package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
  22. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
  23. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
  24. package/dist/resources/extensions/gsd/auto.js +5 -1
  25. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +80 -4
  26. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +31 -5
  27. package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
  28. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +88 -50
  29. package/dist/resources/extensions/gsd/command-feedback.js +16 -12
  30. package/dist/resources/extensions/gsd/compat/compat-marker.js +19 -2
  31. package/dist/resources/extensions/gsd/constants.js +12 -13
  32. package/dist/resources/extensions/gsd/context-masker.js +97 -21
  33. package/dist/resources/extensions/gsd/db/command-queue.js +7 -2
  34. package/dist/resources/extensions/gsd/db/engine.js +51 -16
  35. package/dist/resources/extensions/gsd/db/writers/cascades.js +5 -1
  36. package/dist/resources/extensions/gsd/db/writers/status.js +13 -3
  37. package/dist/resources/extensions/gsd/db-base-schema.js +28 -0
  38. package/dist/resources/extensions/gsd/db-migration-steps.js +30 -0
  39. package/dist/resources/extensions/gsd/db-schema-metadata.js +4 -1
  40. package/dist/resources/extensions/gsd/docs/preferences-reference.md +26 -4
  41. package/dist/resources/extensions/gsd/doctor-engine-checks.js +3 -6
  42. package/dist/resources/extensions/gsd/flat-phase-migration.js +156 -21
  43. package/dist/resources/extensions/gsd/git-service.js +19 -7
  44. package/dist/resources/extensions/gsd/gsd-db.js +187 -45
  45. package/dist/resources/extensions/gsd/guided-flow.js +38 -13
  46. package/dist/resources/extensions/gsd/markdown-renderer.js +17 -13
  47. package/dist/resources/extensions/gsd/md-importer.js +107 -20
  48. package/dist/resources/extensions/gsd/migrate/command.js +19 -162
  49. package/dist/resources/extensions/gsd/migrate/execution.js +98 -0
  50. package/dist/resources/extensions/gsd/migrate/plan.js +49 -0
  51. package/dist/resources/extensions/gsd/migrate/planning-writer.js +12 -17
  52. package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
  53. package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
  54. package/dist/resources/extensions/gsd/model-router.js +11 -0
  55. package/dist/resources/extensions/gsd/parallel-eligibility.js +5 -4
  56. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +28 -43
  57. package/dist/resources/extensions/gsd/paths.js +55 -11
  58. package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
  59. package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
  60. package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
  61. package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
  62. package/dist/resources/extensions/gsd/preferences-types.js +5 -0
  63. package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
  64. package/dist/resources/extensions/gsd/preferences.js +17 -0
  65. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  66. package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
  67. package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
  68. package/dist/resources/extensions/gsd/safety/evidence-collector.js +26 -1
  69. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
  70. package/dist/resources/extensions/gsd/skill-activation.js +17 -3
  71. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +27 -13
  72. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +13 -3
  73. package/dist/resources/extensions/gsd/stop-notice.js +15 -1
  74. package/dist/resources/extensions/gsd/sync-lock.js +13 -7
  75. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  76. package/dist/resources/extensions/gsd/tools/complete-task.js +94 -6
  77. package/dist/resources/extensions/gsd/tools/plan-task.js +13 -15
  78. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +18 -15
  79. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
  80. package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
  81. package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
  82. package/dist/resources/extensions/gsd/tools/replan-task.js +128 -0
  83. package/dist/resources/extensions/gsd/tools/rework-brief.js +74 -0
  84. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -0
  85. package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
  86. package/dist/resources/extensions/gsd/unit-registry.js +4 -0
  87. package/dist/resources/extensions/gsd/uok/plan-v2.js +19 -3
  88. package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
  89. package/dist/resources/extensions/gsd/workspace.js +2 -1
  90. package/dist/resources/extensions/gsd/worktree-state-projection.js +6 -0
  91. package/dist/resources/extensions/mac-tools/index.js +31 -9
  92. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  93. package/dist/web/standalone/.next/BUILD_ID +1 -1
  94. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  95. package/dist/web/standalone/.next/build-manifest.json +3 -3
  96. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  97. package/dist/web/standalone/.next/required-server-files.json +3 -3
  98. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  99. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  109. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  112. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  118. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  125. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  137. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  159. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  169. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  175. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  191. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  195. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  199. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app/index.html +1 -1
  205. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  206. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  207. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  208. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  209. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  210. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  211. package/dist/web/standalone/.next/server/app/page.js +2 -2
  212. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  213. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  214. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  215. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  216. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  217. package/dist/web/standalone/.next/server/middleware.js +3 -3
  218. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  219. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  220. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  221. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  222. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  223. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  224. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  225. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  226. package/dist/web/standalone/.next/static/css/3b1ceb7abfb9a230.css +1 -0
  227. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  228. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  229. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  230. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  231. package/dist/web/standalone/package.json +0 -1
  232. package/dist/web/standalone/server.js +1 -1
  233. package/dist/web-mode.js +31 -3
  234. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  235. package/integrations/hermes/pyproject.toml +1 -1
  236. package/package.json +12 -10
  237. package/packages/cloud-mcp-gateway/package.json +2 -2
  238. package/packages/contracts/dist/workflow.d.ts +14 -0
  239. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  240. package/packages/contracts/dist/workflow.js +16 -0
  241. package/packages/contracts/dist/workflow.js.map +1 -1
  242. package/packages/contracts/package.json +1 -1
  243. package/packages/daemon/dist/cloud-config.d.ts +1 -1
  244. package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
  245. package/packages/daemon/dist/cloud-config.js +5 -1
  246. package/packages/daemon/dist/cloud-config.js.map +1 -1
  247. package/packages/daemon/dist/cloud-config.test.js +51 -1
  248. package/packages/daemon/dist/cloud-config.test.js.map +1 -1
  249. package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
  250. package/packages/daemon/dist/local-tool-executor.js +2 -0
  251. package/packages/daemon/dist/local-tool-executor.js.map +1 -1
  252. package/packages/daemon/package.json +6 -6
  253. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  254. package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
  255. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  256. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  257. package/packages/gsd-agent-core/dist/sdk.js +1 -0
  258. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  259. package/packages/gsd-agent-core/package.json +5 -5
  260. package/packages/gsd-agent-modes/package.json +7 -7
  261. package/packages/gsd-cloud/dist/cli.d.ts +5 -0
  262. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
  263. package/packages/gsd-cloud/dist/cli.js +160 -0
  264. package/packages/gsd-cloud/dist/cli.js.map +1 -0
  265. package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
  266. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
  267. package/packages/gsd-cloud/dist/cloud-config.js +231 -0
  268. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
  269. package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
  270. package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
  271. package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
  272. package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
  273. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
  274. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
  275. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
  276. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
  277. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
  278. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
  279. package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
  280. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
  281. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
  282. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
  283. package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
  284. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
  285. package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
  286. package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
  287. package/packages/gsd-cloud/dist/cloud-token.js +37 -0
  288. package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
  289. package/packages/gsd-cloud/dist/config.d.ts +17 -0
  290. package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
  291. package/packages/gsd-cloud/dist/config.js +146 -0
  292. package/packages/gsd-cloud/dist/config.js.map +1 -0
  293. package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
  294. package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
  295. package/packages/gsd-cloud/dist/device-flow.js +128 -0
  296. package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
  297. package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
  298. package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
  299. package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
  300. package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
  301. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
  302. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
  303. package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
  304. package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
  305. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
  306. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
  307. package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
  308. package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
  309. package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
  310. package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
  311. package/packages/gsd-cloud/dist/executors/executor.js +11 -0
  312. package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
  313. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
  314. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
  315. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
  316. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
  317. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
  318. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
  319. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
  320. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
  321. package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
  322. package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
  323. package/packages/gsd-cloud/dist/executors/index.js +29 -0
  324. package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
  325. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
  326. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
  327. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
  328. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
  329. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
  330. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
  331. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
  332. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
  333. package/packages/gsd-cloud/dist/index.d.ts +7 -0
  334. package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
  335. package/packages/gsd-cloud/dist/index.js +8 -0
  336. package/packages/gsd-cloud/dist/index.js.map +1 -0
  337. package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
  338. package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
  339. package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
  340. package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
  341. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
  342. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
  343. package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
  344. package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
  345. package/packages/gsd-cloud/dist/logger.d.ts +25 -0
  346. package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
  347. package/packages/gsd-cloud/dist/logger.js +72 -0
  348. package/packages/gsd-cloud/dist/logger.js.map +1 -0
  349. package/packages/gsd-cloud/dist/types.d.ts +51 -0
  350. package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
  351. package/packages/gsd-cloud/dist/types.js +9 -0
  352. package/packages/gsd-cloud/dist/types.js.map +1 -0
  353. package/packages/gsd-cloud/package.json +3 -3
  354. package/packages/mcp-server/README.md +15 -2
  355. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  356. package/packages/mcp-server/dist/server.js +5 -5
  357. package/packages/mcp-server/dist/server.js.map +1 -1
  358. package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
  359. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  360. package/packages/mcp-server/dist/workflow-tools.js +64 -2
  361. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  362. package/packages/mcp-server/package.json +4 -4
  363. package/packages/native/package.json +1 -1
  364. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  365. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  366. package/packages/pi-agent-core/dist/agent.js +2 -0
  367. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  368. package/packages/pi-agent-core/package.json +1 -1
  369. package/packages/pi-ai/dist/models.generated.d.ts +119 -0
  370. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  371. package/packages/pi-ai/dist/models.generated.js +107 -0
  372. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  373. package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
  374. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  375. package/packages/pi-ai/dist/providers/anthropic.js +25 -1
  376. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  377. package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
  378. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  379. package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
  380. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  381. package/packages/pi-ai/package.json +1 -1
  382. package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
  383. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  384. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
  385. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  386. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +11 -1
  387. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  388. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  389. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  390. package/packages/pi-coding-agent/package.json +7 -7
  391. package/packages/pi-tui/package.json +2 -2
  392. package/packages/rpc-client/package.json +2 -2
  393. package/pkg/package.json +1 -1
  394. package/src/resources/GSD-WORKFLOW.md +18 -49
  395. package/src/resources/extensions/browser-tools/capture.ts +2 -86
  396. package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
  397. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
  398. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
  399. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
  400. package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
  401. package/src/resources/extensions/gsd/auto-artifact-paths.ts +16 -9
  402. package/src/resources/extensions/gsd/auto-dispatch.ts +86 -19
  403. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
  404. package/src/resources/extensions/gsd/auto-prompts.ts +142 -16
  405. package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
  406. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
  407. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
  408. package/src/resources/extensions/gsd/auto.ts +5 -1
  409. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +92 -4
  410. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -10
  411. package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
  412. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +87 -53
  413. package/src/resources/extensions/gsd/command-feedback.ts +19 -12
  414. package/src/resources/extensions/gsd/compat/compat-marker.ts +21 -4
  415. package/src/resources/extensions/gsd/constants.ts +14 -13
  416. package/src/resources/extensions/gsd/context-masker.ts +98 -2
  417. package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
  418. package/src/resources/extensions/gsd/db/engine.ts +53 -17
  419. package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
  420. package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
  421. package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
  422. package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
  423. package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
  424. package/src/resources/extensions/gsd/docs/preferences-reference.md +26 -4
  425. package/src/resources/extensions/gsd/doctor-engine-checks.ts +3 -5
  426. package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
  427. package/src/resources/extensions/gsd/git-service.ts +19 -6
  428. package/src/resources/extensions/gsd/gsd-db.ts +255 -52
  429. package/src/resources/extensions/gsd/guided-flow.ts +48 -12
  430. package/src/resources/extensions/gsd/markdown-renderer.ts +25 -21
  431. package/src/resources/extensions/gsd/md-importer.ts +114 -16
  432. package/src/resources/extensions/gsd/migrate/command.ts +21 -227
  433. package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
  434. package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
  435. package/src/resources/extensions/gsd/migrate/planning-writer.ts +12 -20
  436. package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
  437. package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
  438. package/src/resources/extensions/gsd/model-router.ts +12 -0
  439. package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
  440. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
  441. package/src/resources/extensions/gsd/paths.ts +62 -11
  442. package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
  443. package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
  444. package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
  445. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
  446. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  447. package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
  448. package/src/resources/extensions/gsd/preferences.ts +25 -0
  449. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  450. package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
  451. package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
  452. package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
  453. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
  454. package/src/resources/extensions/gsd/skill-activation.ts +17 -3
  455. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +30 -13
  456. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +16 -3
  457. package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
  458. package/src/resources/extensions/gsd/stop-notice.ts +18 -1
  459. package/src/resources/extensions/gsd/sync-lock.ts +14 -6
  460. package/src/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
  461. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
  462. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
  463. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
  464. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
  465. package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
  466. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +104 -0
  467. package/src/resources/extensions/gsd/tests/complete-task.test.ts +362 -1
  468. package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
  469. package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
  470. package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
  471. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
  472. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
  473. package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
  474. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
  475. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
  476. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
  477. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
  478. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
  479. package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
  480. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +202 -0
  481. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
  482. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +25 -0
  483. package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
  484. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
  485. package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
  486. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
  487. package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
  488. package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
  489. package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
  490. package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
  491. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  492. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  493. package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
  494. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
  495. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
  496. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
  497. package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
  498. package/src/resources/extensions/gsd/tests/planning-writer.test.ts +29 -0
  499. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
  500. package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
  501. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
  502. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +66 -0
  503. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
  504. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
  505. package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
  506. package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
  507. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  508. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
  509. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
  510. package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
  511. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +17 -0
  512. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
  513. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
  514. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
  515. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +73 -0
  516. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
  517. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
  518. package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
  519. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
  520. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
  521. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +34 -0
  522. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
  523. package/src/resources/extensions/gsd/tools/complete-task.ts +140 -5
  524. package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
  525. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
  526. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
  527. package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
  528. package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
  529. package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
  530. package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
  531. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
  532. package/src/resources/extensions/gsd/types.ts +11 -0
  533. package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
  534. package/src/resources/extensions/gsd/unit-registry.ts +4 -0
  535. package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
  536. package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
  537. package/src/resources/extensions/gsd/workspace.ts +2 -1
  538. package/src/resources/extensions/gsd/worktree-state-projection.ts +12 -0
  539. package/src/resources/extensions/mac-tools/index.ts +52 -9
  540. package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
  541. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  542. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  543. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  544. package/dist/web/standalone/.next/static/css/18c2fdf261bfc1b7.css +0 -1
  545. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_buildManifest.js +0 -0
  546. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_ssgManifest.js +0 -0
@@ -17,11 +17,13 @@ import {
17
17
  insertVerificationEvidence,
18
18
  insertGateRow,
19
19
  getGateResults,
20
+ saveReworkBrief,
20
21
  updateMilestoneStatus,
21
22
  updateSliceStatus,
22
23
  SCHEMA_VERSION,
23
24
  } from '../gsd-db.ts';
24
25
  import { handleCompleteTask } from '../tools/complete-task.ts';
26
+ import { resolveTaskFile } from '../paths.ts';
25
27
 
26
28
  const { assertEq, assertTrue, assertMatch, report } = createTestContext();
27
29
 
@@ -380,6 +382,80 @@ console.log('\n=== complete-task: handler happy path ===');
380
382
  cleanup(dbPath);
381
383
  }
382
384
 
385
+ // ═══════════════════════════════════════════════════════════════════════════
386
+ // complete-task: Flat-phase duplicate task IDs are slice-qualified
387
+ // ═══════════════════════════════════════════════════════════════════════════
388
+
389
+ console.log('\n=== complete-task: flat-phase duplicate task IDs are slice-qualified ===');
390
+ {
391
+ const dbPath = tempDbPath();
392
+ openDatabase(dbPath);
393
+
394
+ const basePath = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-flat-task-summary-'));
395
+ const phaseDir = path.join(basePath, '.gsd', 'phases', '01-test');
396
+ fs.mkdirSync(phaseDir, { recursive: true });
397
+ fs.writeFileSync(path.join(phaseDir, '01-01-PLAN.md'), `# S01: First Slice
398
+
399
+ ## Tasks
400
+
401
+ - [ ] **T03: Shared task id** \`est:30m\`
402
+ - Do: Complete first slice task
403
+ - Verify: Run first check
404
+ `);
405
+ fs.writeFileSync(path.join(phaseDir, '01-02-PLAN.md'), `# S02: Second Slice
406
+
407
+ ## Tasks
408
+
409
+ - [ ] **T03: Shared task id** \`est:30m\`
410
+ - Do: Complete second slice task
411
+ - Verify: Run second check
412
+ `);
413
+
414
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
415
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'First Slice', sequence: 1 });
416
+ insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Second Slice', sequence: 2 });
417
+
418
+ const first = await handleCompleteTask({
419
+ ...makeValidParams(),
420
+ taskId: 'T03',
421
+ sliceId: 'S01',
422
+ oneLiner: 'Completed first slice T03',
423
+ }, basePath);
424
+ const second = await handleCompleteTask({
425
+ ...makeValidParams(),
426
+ taskId: 'T03',
427
+ sliceId: 'S02',
428
+ oneLiner: 'Completed second slice T03',
429
+ }, basePath);
430
+
431
+ assertTrue(!('error' in first), 'first duplicate task ID completion should succeed');
432
+ assertTrue(!('error' in second), 'second duplicate task ID completion should succeed');
433
+ if (!('error' in first) && !('error' in second)) {
434
+ const firstSummary = path.join(phaseDir, 'S01-T03-SUMMARY.md');
435
+ const secondSummary = path.join(phaseDir, 'S02-T03-SUMMARY.md');
436
+ const legacySummary = path.join(phaseDir, 'T03-SUMMARY.md');
437
+
438
+ assertEq(first.summaryPath, firstSummary, 'S01/T03 should write a slice-qualified summary path');
439
+ assertEq(second.summaryPath, secondSummary, 'S02/T03 should write a slice-qualified summary path');
440
+ assertTrue(fs.existsSync(firstSummary), 'S01/T03 summary should exist');
441
+ assertTrue(fs.existsSync(secondSummary), 'S02/T03 summary should exist');
442
+ assertTrue(!fs.existsSync(legacySummary), 'flat-phase completion should not create legacy T03-SUMMARY.md');
443
+
444
+ const firstContent = fs.readFileSync(firstSummary, 'utf-8');
445
+ const secondContent = fs.readFileSync(secondSummary, 'utf-8');
446
+ assertMatch(firstContent, /parent: S01/, 'S01/T03 summary should keep parent S01');
447
+ assertMatch(secondContent, /parent: S02/, 'S02/T03 summary should keep parent S02');
448
+ assertEq(resolveTaskFile(basePath, 'M001', 'S02', 'T03', 'SUMMARY'), secondSummary, 'resolver should prefer S02-specific summary');
449
+
450
+ const legacyFallback = path.join(phaseDir, 'T99-SUMMARY.md');
451
+ fs.writeFileSync(legacyFallback, '# Legacy task summary\n');
452
+ assertEq(resolveTaskFile(basePath, 'M001', 'S09', 'T99', 'SUMMARY'), legacyFallback, 'resolver should fall back to old flat summary names');
453
+ }
454
+
455
+ cleanupDir(basePath);
456
+ cleanup(dbPath);
457
+ }
458
+
383
459
  // ═══════════════════════════════════════════════════════════════════════════
384
460
  // complete-task: Projection failure rolls DB completion back
385
461
  // ═══════════════════════════════════════════════════════════════════════════
@@ -415,7 +491,7 @@ console.log('\n=== complete-task: projection failure rolls DB completion back ==
415
491
  ).all();
416
492
  assertEq(evRows.length, 0, 'verification evidence should be deleted when projection rollback runs');
417
493
 
418
- const summaryPath = path.join(path.dirname(planPath), 'T01-SUMMARY.md');
494
+ const summaryPath = path.join(path.dirname(planPath), 'S01-T01-SUMMARY.md');
419
495
  assertTrue(!fs.existsSync(summaryPath), 'SUMMARY.md should be removed so disk state stays pending');
420
496
 
421
497
  cleanupDir(basePath);
@@ -507,6 +583,77 @@ console.log('\n=== complete-task: disabled hard-blocker escalation rolls back co
507
583
  cleanup(dbPath);
508
584
  }
509
585
 
586
+ // ═══════════════════════════════════════════════════════════════════════════
587
+ // complete-task: rollback reverts applied rework resolutions
588
+ // ═══════════════════════════════════════════════════════════════════════════
589
+
590
+ console.log('\n=== complete-task: rollback reverts applied rework resolutions ===');
591
+ {
592
+ const dbPath = tempDbPath();
593
+ openDatabase(dbPath);
594
+
595
+ const { basePath } = createTempProject();
596
+ writeProjectPreferences(basePath, 'phases:\n mid_execution_escalation: false\n');
597
+
598
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
599
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
600
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
601
+ saveReworkBrief({
602
+ briefId: 'RB-001',
603
+ milestoneId: 'M001',
604
+ sliceId: 'S01',
605
+ taskId: 'T01',
606
+ findings: [{
607
+ findingId: 'F1',
608
+ severity: 'blocking',
609
+ description: 'Compile regression',
610
+ requiredFix: 'Fix compile error',
611
+ verificationCommands: ['pnpm run typecheck:extensions'],
612
+ }],
613
+ });
614
+
615
+ // Completion resolves the blocking finding but then rolls back because the
616
+ // hard-blocker escalation is disabled. The rollback must also revert the
617
+ // finding. Otherwise a retry would see no unresolved blocking findings and
618
+ // silently skip the blocking gate.
619
+ const result = await withWorkingDirectory(basePath, () => handleCompleteTask({
620
+ ...makeValidParams(),
621
+ blockerDiscovered: true,
622
+ reworkResolution: [{
623
+ findingId: 'F1',
624
+ status: 'resolved',
625
+ evidence: 'Fixed compile error and reran pnpm run typecheck:extensions.',
626
+ }],
627
+ escalation: {
628
+ question: 'Should execution pause for the hard blocker?',
629
+ options: makeEscalationOptions(),
630
+ recommendation: 'pause',
631
+ recommendationRationale: 'The blocker should not be silently advanced.',
632
+ continueWithDefault: false,
633
+ },
634
+ }, basePath));
635
+
636
+ assertTrue('error' in result, 'completion should roll back when hard-blocker escalation is disabled');
637
+ assertEq(getTask('M001', 'S01', 'T01')?.status, 'pending', 'task status should roll back to pending');
638
+
639
+ const finding = _getAdapter()!.prepare(
640
+ "SELECT status, evidence, decision_ref FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'"
641
+ ).get() as { status: string; evidence: string; decision_ref: string };
642
+ assertEq(finding.status, 'pending', 'rework finding should revert to pending after rollback');
643
+ assertEq(finding.evidence, '', 'rework finding evidence should be cleared after rollback');
644
+
645
+ // Retry-safety invariant: the blocking gate must fire again because the
646
+ // finding is unresolved once more.
647
+ const retry = await withWorkingDirectory(basePath, () => handleCompleteTask(makeValidParams(), basePath));
648
+ assertTrue('error' in retry, 'retry without reworkResolution should be blocked again');
649
+ if ('error' in retry) {
650
+ assertMatch(retry.error, /unresolved blocking rework finding/i, 'retry should re-trigger the blocking gate');
651
+ }
652
+
653
+ cleanupDir(basePath);
654
+ cleanup(dbPath);
655
+ }
656
+
510
657
  // ═══════════════════════════════════════════════════════════════════════════
511
658
  // complete-task: soft escalation with mid-execution escalation disabled
512
659
  // ═══════════════════════════════════════════════════════════════════════════
@@ -838,6 +985,220 @@ console.log('\n=== complete-task: closes Q5/Q6/Q7 gates (pass vs omitted) ===');
838
985
  cleanup(dbPath);
839
986
  }
840
987
 
988
+
989
+ // ═══════════════════════════════════════════════════════════════════════════
990
+ // complete-task: unresolved blocking rework findings reject completion
991
+ // ═══════════════════════════════════════════════════════════════════════════
992
+
993
+ console.log('\n=== complete-task: rejects unresolved blocking rework findings ===');
994
+ {
995
+ const dbPath = tempDbPath();
996
+ openDatabase(dbPath);
997
+ const { basePath } = createTempProject();
998
+
999
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
1000
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
1001
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
1002
+
1003
+ saveReworkBrief({
1004
+ briefId: 'RB-001',
1005
+ milestoneId: 'M001',
1006
+ sliceId: 'S01',
1007
+ taskId: 'T01',
1008
+ findings: [{
1009
+ findingId: 'F1',
1010
+ severity: 'blocking',
1011
+ description: 'Compile regression',
1012
+ requiredFix: 'Fix compile error',
1013
+ verificationCommands: ['pnpm run typecheck:extensions'],
1014
+ }],
1015
+ });
1016
+
1017
+ const result = await handleCompleteTask(makeValidParams(), basePath);
1018
+ assertTrue('error' in result, 'completion should reject unresolved blocking rework findings');
1019
+ if ('error' in result) {
1020
+ assertMatch(result.error, /unresolved blocking rework finding/i, 'error should explain unresolved rework');
1021
+ assertMatch(result.error, /F1/, 'error should name the unresolved finding id');
1022
+ }
1023
+
1024
+ cleanupDir(basePath);
1025
+ cleanup(dbPath);
1026
+ }
1027
+
1028
+
1029
+ console.log('\n=== complete-task: accepts resolved blocking rework evidence ===');
1030
+ {
1031
+ const dbPath = tempDbPath();
1032
+ openDatabase(dbPath);
1033
+ const { basePath } = createTempProject();
1034
+
1035
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
1036
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
1037
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
1038
+ saveReworkBrief({
1039
+ briefId: 'RB-001',
1040
+ milestoneId: 'M001',
1041
+ sliceId: 'S01',
1042
+ taskId: 'T01',
1043
+ findings: [{
1044
+ findingId: 'F1',
1045
+ severity: 'blocking',
1046
+ description: 'Compile regression',
1047
+ requiredFix: 'Fix compile error',
1048
+ verificationCommands: ['pnpm run typecheck:extensions'],
1049
+ }],
1050
+ });
1051
+
1052
+ const result = await handleCompleteTask({
1053
+ ...makeValidParams(),
1054
+ reworkResolution: [{
1055
+ findingId: 'F1',
1056
+ status: 'resolved',
1057
+ evidence: 'Fixed compile error and reran pnpm run typecheck:extensions.',
1058
+ }],
1059
+ }, basePath);
1060
+
1061
+ assertTrue(!('error' in result), 'completion should accept resolved blocking rework evidence');
1062
+ assertEq(getTask('M001', 'S01', 'T01')?.status, 'complete', 'task should complete after resolving rework');
1063
+ const finding = _getAdapter()!.prepare("SELECT status, evidence FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'").get() as { status: string; evidence: string };
1064
+ assertEq(finding.status, 'resolved', 'finding status should be updated');
1065
+ assertMatch(finding.evidence, /Fixed compile error/, 'resolution evidence should be persisted');
1066
+
1067
+ cleanupDir(basePath);
1068
+ cleanup(dbPath);
1069
+ }
1070
+
1071
+ console.log('\n=== complete-task: accepts deferred blocking rework with decision reference ===');
1072
+ {
1073
+ const dbPath = tempDbPath();
1074
+ openDatabase(dbPath);
1075
+ const { basePath } = createTempProject();
1076
+
1077
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
1078
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
1079
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
1080
+ saveReworkBrief({
1081
+ briefId: 'RB-001',
1082
+ milestoneId: 'M001',
1083
+ sliceId: 'S01',
1084
+ taskId: 'T01',
1085
+ findings: [{
1086
+ findingId: 'F1',
1087
+ severity: 'blocking',
1088
+ description: 'Compile regression',
1089
+ requiredFix: 'Fix compile error',
1090
+ verificationCommands: ['pnpm run typecheck:extensions'],
1091
+ }],
1092
+ });
1093
+
1094
+ const result = await handleCompleteTask({
1095
+ ...makeValidParams(),
1096
+ reworkResolution: [{
1097
+ findingId: 'F1',
1098
+ status: 'deferred-with-override',
1099
+ evidence: 'Maintainer accepted temporary deferral.',
1100
+ decisionRef: 'DEC-2026-07-07-rework-deferral',
1101
+ }],
1102
+ }, basePath);
1103
+
1104
+ assertTrue(!('error' in result), 'completion should accept deferred blocking rework with decision reference');
1105
+ const finding = _getAdapter()!.prepare("SELECT status, decision_ref FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'").get() as { status: string; decision_ref: string };
1106
+ assertEq(finding.status, 'deferred-with-override', 'finding status should record the override');
1107
+ assertEq(finding.decision_ref, 'DEC-2026-07-07-rework-deferral', 'decision reference should be persisted');
1108
+
1109
+ cleanupDir(basePath);
1110
+ cleanup(dbPath);
1111
+ }
1112
+
1113
+ console.log('\n=== complete-task: invalid duplicate rework resolution cannot overwrite a valid one ===');
1114
+ {
1115
+ const dbPath = tempDbPath();
1116
+ openDatabase(dbPath);
1117
+ const { basePath } = createTempProject();
1118
+
1119
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
1120
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
1121
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
1122
+ saveReworkBrief({
1123
+ briefId: 'RB-001',
1124
+ milestoneId: 'M001',
1125
+ sliceId: 'S01',
1126
+ taskId: 'T01',
1127
+ findings: [{
1128
+ findingId: 'F1',
1129
+ severity: 'blocking',
1130
+ description: 'Compile regression',
1131
+ requiredFix: 'Fix compile error',
1132
+ verificationCommands: ['pnpm run typecheck:extensions'],
1133
+ }],
1134
+ });
1135
+
1136
+ // The guard admits F1 because a satisfying entry exists, but a later
1137
+ // non-satisfying duplicate for the same finding must NOT overwrite the valid
1138
+ // resolution and leave F1 resolved with no evidence.
1139
+ const result = await handleCompleteTask({
1140
+ ...makeValidParams(),
1141
+ reworkResolution: [
1142
+ { findingId: 'F1', status: 'resolved', evidence: 'Fixed compile error and reran pnpm run typecheck:extensions.' },
1143
+ { findingId: 'F1', status: 'resolved', evidence: '' },
1144
+ ],
1145
+ }, basePath);
1146
+
1147
+ assertTrue(!('error' in result), 'completion should succeed on the valid resolution');
1148
+ const finding = _getAdapter()!.prepare(
1149
+ "SELECT status, evidence FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'"
1150
+ ).get() as { status: string; evidence: string };
1151
+ assertEq(finding.status, 'resolved', 'finding should remain resolved');
1152
+ assertMatch(finding.evidence, /Fixed compile error/, 'valid evidence must survive the invalid duplicate');
1153
+
1154
+ cleanupDir(basePath);
1155
+ cleanup(dbPath);
1156
+ }
1157
+
1158
+ console.log('\n=== complete-task: invalid deferred duplicate cannot strip decisionRef ===');
1159
+ {
1160
+ const dbPath = tempDbPath();
1161
+ openDatabase(dbPath);
1162
+ const { basePath } = createTempProject();
1163
+
1164
+ insertMilestone({ id: 'M001', title: 'Test Milestone' });
1165
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
1166
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Test task', status: 'pending' });
1167
+ saveReworkBrief({
1168
+ briefId: 'RB-001',
1169
+ milestoneId: 'M001',
1170
+ sliceId: 'S01',
1171
+ taskId: 'T01',
1172
+ findings: [{
1173
+ findingId: 'F1',
1174
+ severity: 'blocking',
1175
+ description: 'Compile regression',
1176
+ requiredFix: 'Fix compile error',
1177
+ verificationCommands: ['pnpm run typecheck:extensions'],
1178
+ }],
1179
+ });
1180
+
1181
+ // A deferred-with-override duplicate that omits decisionRef is non-satisfying
1182
+ // and must not overwrite the valid deferral.
1183
+ const result = await handleCompleteTask({
1184
+ ...makeValidParams(),
1185
+ reworkResolution: [
1186
+ { findingId: 'F1', status: 'deferred-with-override', evidence: 'Maintainer accepted temporary deferral.', decisionRef: 'DEC-2026-07-07-rework-deferral' },
1187
+ { findingId: 'F1', status: 'deferred-with-override', evidence: 'Maintainer accepted temporary deferral.' },
1188
+ ],
1189
+ }, basePath);
1190
+
1191
+ assertTrue(!('error' in result), 'completion should succeed on the valid deferral');
1192
+ const finding = _getAdapter()!.prepare(
1193
+ "SELECT status, decision_ref FROM rework_brief_findings WHERE brief_id = 'RB-001' AND finding_id = 'F1'"
1194
+ ).get() as { status: string; decision_ref: string };
1195
+ assertEq(finding.status, 'deferred-with-override', 'finding should remain deferred-with-override');
1196
+ assertEq(finding.decision_ref, 'DEC-2026-07-07-rework-deferral', 'valid decisionRef must survive the invalid duplicate');
1197
+
1198
+ cleanupDir(basePath);
1199
+ cleanup(dbPath);
1200
+ }
1201
+
841
1202
  // ═══════════════════════════════════════════════════════════════════════════
842
1203
 
843
1204
  report();
@@ -4,9 +4,12 @@ import assert from "node:assert/strict";
4
4
  import {
5
5
  createObservationMask,
6
6
  createResponsesInputObservationMask,
7
+ filterSupersededContextInjections,
8
+ filterSupersededResponsesContextInjections,
7
9
  truncateContextResultMessages,
8
10
  truncateResponsesInputResultItems,
9
11
  } from "../context-masker.js";
12
+ import { GSD_CONTEXT_MESSAGE_SENTINEL } from "../bootstrap/system-context.js";
10
13
 
11
14
  // These helpers produce messages in the pi-ai LLM payload format
12
15
  // (post-convertToLlm, pre-provider), which is what before_provider_request sees.
@@ -43,25 +46,35 @@ test("masks nothing when message count is within keepRecentTurns", () => {
43
46
  assert.deepEqual((result[2].content as any)[0].text, "file contents");
44
47
  });
45
48
 
46
- test("masks tool results older than keepRecentTurns", () => {
49
+ test("masks tool results older than a full quantization block", () => {
50
+ // With keepRecentTurns=2, masking is quantized in blocks of 2 turns: nothing
51
+ // is masked until a full block (2 turns) of excess history accumulates.
47
52
  const mask = createObservationMask(2);
48
53
  const messages = [
49
54
  userMsg("turn 1"),
50
- toolResult("old tool output"),
55
+ toolResult("turn 1 tool output"),
51
56
  assistantMsg("response 1"),
52
57
  userMsg("turn 2"),
53
- toolResult("newer tool output"),
58
+ toolResult("turn 2 tool output"),
54
59
  assistantMsg("response 2"),
55
60
  userMsg("turn 3"),
56
- toolResult("newest tool output"),
61
+ toolResult("turn 3 tool output"),
57
62
  assistantMsg("response 3"),
63
+ userMsg("turn 4"),
64
+ toolResult("turn 4 tool output"),
65
+ assistantMsg("response 4"),
66
+ userMsg("turn 5"),
67
+ toolResult("turn 5 tool output"),
68
+ assistantMsg("response 5"),
58
69
  ];
59
70
  const result = mask(messages as any);
60
- // Old tool result (before boundary) should be masked
71
+ // First block (turns 1-2) is masked
61
72
  assert.equal((result[1].content as any)[0].text, MASK_TEXT);
62
- // Recent tool results (within keep window) should be preserved
63
- assert.equal((result[4].content as any)[0].text, "newer tool output");
64
- assert.equal((result[7].content as any)[0].text, "newest tool output");
73
+ assert.equal((result[4].content as any)[0].text, MASK_TEXT);
74
+ // Remaining turns (3-5) are within the unmasked window
75
+ assert.equal((result[7].content as any)[0].text, "turn 3 tool output");
76
+ assert.equal((result[10].content as any)[0].text, "turn 4 tool output");
77
+ assert.equal((result[13].content as any)[0].text, "turn 5 tool output");
65
78
  });
66
79
 
67
80
  test("never masks assistant messages", () => {
@@ -126,6 +139,67 @@ test("masks toolResult by role, not by type field", () => {
126
139
  assert.equal((result[1].content as any)[0].text, MASK_TEXT);
127
140
  });
128
141
 
142
+ function buildTurns(count: number) {
143
+ const messages: unknown[] = [];
144
+ for (let i = 1; i <= count; i++) {
145
+ messages.push(userMsg(`turn ${i}`));
146
+ messages.push(toolResult(`turn ${i} tool output`));
147
+ messages.push(assistantMsg(`response ${i}`));
148
+ }
149
+ return messages;
150
+ }
151
+
152
+ function maskedTextsByTurn(mask: (m: any) => any[], messages: unknown[], turnCount: number): (string | undefined)[] {
153
+ const result = mask(messages as any);
154
+ const texts: (string | undefined)[] = [];
155
+ for (let i = 0; i < turnCount; i++) {
156
+ const toolResultIndex = i * 3 + 1;
157
+ texts.push((result[toolResultIndex].content as any)[0].text);
158
+ }
159
+ return texts;
160
+ }
161
+
162
+ test("quantized mask invariant: at least keepRecentTurns most recent turns are always unmasked", () => {
163
+ const N = 3;
164
+ const mask = createObservationMask(N);
165
+ for (let totalTurns = 1; totalTurns <= 20; totalTurns++) {
166
+ const messages = buildTurns(totalTurns);
167
+ const texts = maskedTextsByTurn(mask, messages, totalTurns);
168
+ for (let i = Math.max(0, totalTurns - N); i < totalTurns; i++) {
169
+ assert.notEqual(texts[i], MASK_TEXT, `turn ${i + 1} of ${totalTurns} should be unmasked`);
170
+ }
171
+ }
172
+ });
173
+
174
+ test("quantized mask invariant: at most 2*keepRecentTurns-1 turns are unmasked", () => {
175
+ const N = 3;
176
+ const mask = createObservationMask(N);
177
+ for (let totalTurns = 1; totalTurns <= 20; totalTurns++) {
178
+ const messages = buildTurns(totalTurns);
179
+ const texts = maskedTextsByTurn(mask, messages, totalTurns);
180
+ const unmaskedCount = texts.filter((t) => t !== MASK_TEXT).length;
181
+ assert.ok(unmaskedCount <= 2 * N - 1, `expected <= ${2 * N - 1} unmasked turns at total=${totalTurns}, got ${unmaskedCount}`);
182
+ }
183
+ });
184
+
185
+ test("quantized mask invariant: prefix is byte-stable except at block rollover", () => {
186
+ const N = 3;
187
+ const mask = createObservationMask(N);
188
+ let previousTexts: (string | undefined)[] = [];
189
+ for (let totalTurns = 1; totalTurns <= 20; totalTurns++) {
190
+ const messages = buildTurns(totalTurns);
191
+ const texts = maskedTextsByTurn(mask, messages, totalTurns);
192
+ // Compare the shared prefix (turns 1..totalTurns-1) against the previous turn's run.
193
+ let changedCount = 0;
194
+ for (let i = 0; i < previousTexts.length; i++) {
195
+ if (previousTexts[i] !== texts[i]) changedCount++;
196
+ }
197
+ // A block rollover flips at most N turns from unmasked to masked; otherwise 0 should change.
198
+ assert.ok(changedCount === 0 || changedCount <= N, `turn ${totalTurns}: ${changedCount} prefix turns changed status`);
199
+ previousTexts = texts;
200
+ }
201
+ });
202
+
129
203
  test("truncates recent bash result user messages", () => {
130
204
  const messages = [
131
205
  userMsg("turn 1"),
@@ -175,3 +249,125 @@ test("truncates Responses API function outputs and recent bash result items", ()
175
249
  assert.ok((result[1].output as string).length < (items[1].output as string).length);
176
250
  assert.ok((result[2].content as any)[0].text.length < (items[2].content as any)[0].text.length);
177
251
  });
252
+
253
+ function contextInjectionMsg(label: string) {
254
+ return userMsg(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n[MEMORY] turn=${label}`);
255
+ }
256
+
257
+ test("filterSupersededContextInjections keeps only the latest of three same-kind injections", () => {
258
+ const messages = [
259
+ userMsg("turn 1 prompt"),
260
+ contextInjectionMsg("1"),
261
+ assistantMsg("response 1"),
262
+ userMsg("turn 2 prompt"),
263
+ contextInjectionMsg("2"),
264
+ assistantMsg("response 2"),
265
+ userMsg("turn 3 prompt"),
266
+ contextInjectionMsg("3"),
267
+ ];
268
+ const original = JSON.parse(JSON.stringify(messages));
269
+
270
+ const result = filterSupersededContextInjections(messages as any);
271
+
272
+ const survivors = result.filter((m: any) => (m.content?.[0]?.text ?? "").startsWith(GSD_CONTEXT_MESSAGE_SENTINEL));
273
+ assert.equal(survivors.length, 1);
274
+ assert.match((survivors[0] as any).content[0].text, /turn=3/);
275
+ assert.equal(result.length, messages.length - 2);
276
+ // Pure function — input array is untouched.
277
+ assert.deepEqual(messages, original);
278
+ });
279
+
280
+ test("filterSupersededContextInjections keeps the latest injection overall across mixed kinds", () => {
281
+ // buildContextMessage emits one message per turn (guided > forensics > memory);
282
+ // the latest one already embeds the memory block when present, so "keep the
283
+ // latest overall" is correct — no separate per-kind tracking needed.
284
+ const memoryOnly = userMsg(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n[GSD Context Metadata]\n- Memory supplied: yes\n\n[MEMORY]`);
285
+ const guided = userMsg(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n[GSD Context Metadata]\n- Memory supplied: yes\n\n[GUIDED EXECUTE]`);
286
+ const messages = [userMsg("turn 1"), memoryOnly, assistantMsg("r1"), userMsg("turn 2"), guided];
287
+
288
+ const result = filterSupersededContextInjections(messages as any);
289
+
290
+ const survivors = result.filter((m: any) => (m.content?.[0]?.text ?? "").startsWith(GSD_CONTEXT_MESSAGE_SENTINEL));
291
+ assert.equal(survivors.length, 1);
292
+ assert.match((survivors[0] as any).content[0].text, /GUIDED EXECUTE/);
293
+ });
294
+
295
+ test("filterSupersededContextInjections dedupes legacy pre-sentinel injections via bracketed GSD markers", () => {
296
+ // Sessions created before the sentinel existed carry the stable
297
+ // "[GSD Context Metadata]" / "[GSD Guided Execute Context]" labels but no
298
+ // sentinel prefix; resuming them must still collapse to the latest injection.
299
+ const legacyMemory1 = userMsg("[GSD Context Metadata]\n- Memory supplied: yes\n\n[MEMORY] turn=1");
300
+ const legacyMemory2 = userMsg("[GSD Context Metadata]\n- Memory supplied: yes\n\n[MEMORY] turn=2");
301
+ const messages = [userMsg("turn 1"), legacyMemory1, assistantMsg("r1"), userMsg("turn 2"), legacyMemory2];
302
+
303
+ const result = filterSupersededContextInjections(messages as any);
304
+
305
+ const survivors = result.filter((m: any) => (m.content?.[0]?.text ?? "").startsWith("[GSD Context Metadata]"));
306
+ assert.equal(survivors.length, 1);
307
+ assert.match((survivors[0] as any).content[0].text, /turn=2/);
308
+ assert.equal(result.length, messages.length - 1);
309
+ });
310
+
311
+ test("filterSupersededContextInjections never drops a real user message that starts with forensics prose", () => {
312
+ // "Debug GSD itself." is the forensics prompt text — generic prose, not a
313
+ // bracketed GSD marker. A user can legitimately type it; treating it as an
314
+ // injection would silently delete real user input. Only sentinel/bracketed
315
+ // injections may be superseded.
316
+ const userAsk = userMsg("Debug GSD itself. Why does resume hang after a crash?");
317
+ const injection = userMsg(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n[GSD Context Metadata]\n- Memory supplied: yes\n\n[MEMORY]`);
318
+ const messages = [userAsk, assistantMsg("r1"), userMsg("turn 2"), injection];
319
+
320
+ const result = filterSupersededContextInjections(messages as any);
321
+
322
+ assert.ok(result.some((m: any) => (m.content?.[0]?.text ?? "").startsWith("Debug GSD itself.")));
323
+ assert.equal(result.length, messages.length);
324
+ });
325
+
326
+ test("filterSupersededContextInjections returns the array unchanged when no injections present", () => {
327
+ const messages = [userMsg("hi"), assistantMsg("hello"), toolResult("data")];
328
+ const result = filterSupersededContextInjections(messages as any);
329
+ assert.equal(result, messages);
330
+ });
331
+
332
+ test("filterSupersededContextInjections preserves forensics opening prompt across follow-up reinjection", () => {
333
+ const forensicsOpening =
334
+ "Debug GSD itself. Trace the symptom to root cause in current source and produce a filing-ready GitHub issue.";
335
+ const messages = [
336
+ userMsg(forensicsOpening),
337
+ assistantMsg("I found the root cause in auto-loop.ts."),
338
+ userMsg("yes, create the issue"),
339
+ userMsg(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n${forensicsOpening}`),
340
+ assistantMsg("Creating the issue now."),
341
+ userMsg("also add the stack trace"),
342
+ userMsg(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n${forensicsOpening}\n\n## Follow-up\nalso add the stack trace`),
343
+ ];
344
+
345
+ const result = filterSupersededContextInjections(messages as any);
346
+
347
+ assert.equal(result.length, messages.length - 1);
348
+ assert.equal((result[0] as any).content[0].text, forensicsOpening);
349
+ assert.match((result[5] as any).content[0].text, /Follow-up/);
350
+ });
351
+
352
+ test("filterSupersededResponsesContextInjections keeps only the latest injection in payload.input", () => {
353
+ const items = [
354
+ { role: "user", content: [{ type: "input_text", text: "turn 1" }] },
355
+ { role: "user", content: [{ type: "input_text", text: `${GSD_CONTEXT_MESSAGE_SENTINEL}\n[MEMORY] turn=1` }] },
356
+ { type: "function_call_output", call_id: "call_1", output: "ok" },
357
+ { role: "user", content: [{ type: "input_text", text: `${GSD_CONTEXT_MESSAGE_SENTINEL}\n[MEMORY] turn=2` }] },
358
+ ];
359
+ const original = JSON.parse(JSON.stringify(items));
360
+
361
+ const result = filterSupersededResponsesContextInjections(items as any);
362
+
363
+ const survivors = result.filter((i: any) => (i.content?.[0]?.text ?? "").startsWith(GSD_CONTEXT_MESSAGE_SENTINEL));
364
+ assert.equal(survivors.length, 1);
365
+ assert.match((survivors[0] as any).content[0].text, /turn=2/);
366
+ assert.deepEqual(items, original);
367
+ });
368
+
369
+ test("filterSupersededResponsesContextInjections returns the array unchanged when no injections present", () => {
370
+ const items = [{ role: "user", content: [{ type: "input_text", text: "hi" }] }];
371
+ const result = filterSupersededResponsesContextInjections(items as any);
372
+ assert.equal(result, items);
373
+ });