gsd-pi 2.78.1-dev.b0759e59b → 2.78.1-dev.d8826a445

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 (300) hide show
  1. package/README.md +8 -5
  2. package/dist/headless-recover.d.ts +23 -0
  3. package/dist/headless-recover.js +93 -0
  4. package/dist/headless.js +9 -0
  5. package/dist/help-text.js +1 -0
  6. package/dist/resources/.managed-resources-content-hash +1 -1
  7. package/dist/resources/extensions/browser-tools/tools/intent.js +8 -1
  8. package/dist/resources/extensions/gsd/auto/phases.js +7 -2
  9. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +7 -58
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +14 -28
  12. package/dist/resources/extensions/gsd/auto-start.js +1 -8
  13. package/dist/resources/extensions/gsd/auto-worktree.js +244 -216
  14. package/dist/resources/extensions/gsd/auto.js +86 -7
  15. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +1 -1
  16. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -77
  17. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -16
  18. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +67 -55
  19. package/dist/resources/extensions/gsd/commands-codebase.js +2 -2
  20. package/dist/resources/extensions/gsd/commands-handlers.js +5 -5
  21. package/dist/resources/extensions/gsd/commands-logs.js +2 -2
  22. package/dist/resources/extensions/gsd/commands-scan.js +2 -2
  23. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  24. package/dist/resources/extensions/gsd/commands-workflow-templates.js +5 -5
  25. package/dist/resources/extensions/gsd/db-writer.js +106 -95
  26. package/dist/resources/extensions/gsd/delegation-policy.js +155 -0
  27. package/dist/resources/extensions/gsd/dispatch-guard.js +6 -10
  28. package/dist/resources/extensions/gsd/doctor-engine-checks.js +2 -2
  29. package/dist/resources/extensions/gsd/gsd-db.js +268 -8
  30. package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
  31. package/dist/resources/extensions/gsd/guided-flow.js +141 -32
  32. package/dist/resources/extensions/gsd/markdown-renderer.js +14 -51
  33. package/dist/resources/extensions/gsd/metrics.js +287 -1
  34. package/dist/resources/extensions/gsd/parallel-merge.js +14 -13
  35. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +5 -2
  36. package/dist/resources/extensions/gsd/paths.js +114 -9
  37. package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -4
  38. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -3
  39. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
  40. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
  41. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
  42. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -1
  43. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
  44. package/dist/resources/extensions/gsd/queue-order.js +6 -1
  45. package/dist/resources/extensions/gsd/rethink.js +2 -2
  46. package/dist/resources/extensions/gsd/state.js +91 -372
  47. package/dist/resources/extensions/gsd/templates/project.md +10 -0
  48. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -5
  49. package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -12
  50. package/dist/resources/extensions/gsd/tools/complete-task.js +19 -31
  51. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -5
  52. package/dist/resources/extensions/gsd/workflow-manifest.js +2 -1
  53. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -21
  54. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  55. package/dist/resources/extensions/gsd/workflow-reconcile.js +3 -3
  56. package/dist/resources/extensions/gsd/workspace.js +59 -0
  57. package/dist/resources/extensions/gsd/worktree-command.js +4 -3
  58. package/dist/resources/extensions/gsd/worktree-resolver.js +15 -2
  59. package/dist/resources/extensions/gsd/write-intercept.js +3 -3
  60. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  61. package/dist/web/standalone/.next/BUILD_ID +1 -1
  62. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  63. package/dist/web/standalone/.next/build-manifest.json +2 -2
  64. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  65. package/dist/web/standalone/.next/required-server-files.json +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  83. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  84. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  85. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  86. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  87. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  88. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  89. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  90. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  91. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  92. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  93. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  94. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  95. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  96. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  97. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  98. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  99. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  100. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  101. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  102. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  103. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  104. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  105. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  106. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  107. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  108. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  109. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  110. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  111. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  112. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  113. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  114. package/dist/web/standalone/.next/server/app/index.html +1 -1
  115. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  122. package/dist/web/standalone/.next/server/chunks/6336.js +1 -0
  123. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  124. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  126. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  127. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  128. package/dist/web/standalone/server.js +1 -1
  129. package/package.json +1 -1
  130. package/packages/mcp-server/README.md +2 -11
  131. package/packages/mcp-server/dist/remote-questions.d.ts +27 -0
  132. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  133. package/packages/mcp-server/dist/remote-questions.js +28 -0
  134. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  135. package/packages/mcp-server/dist/server.d.ts +28 -0
  136. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  137. package/packages/mcp-server/dist/server.js +94 -4
  138. package/packages/mcp-server/dist/server.js.map +1 -1
  139. package/packages/mcp-server/dist/workflow-tools.d.ts +6 -0
  140. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  141. package/packages/mcp-server/dist/workflow-tools.js +56 -2
  142. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  143. package/packages/mcp-server/src/mcp-server.test.ts +226 -0
  144. package/packages/mcp-server/src/parse-workflow-args.test.ts +80 -0
  145. package/packages/mcp-server/src/remote-questions.test.ts +103 -0
  146. package/packages/mcp-server/src/remote-questions.ts +35 -0
  147. package/packages/mcp-server/src/server.ts +129 -6
  148. package/packages/mcp-server/src/workflow-tools.ts +62 -3
  149. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  150. package/src/resources/extensions/browser-tools/tools/intent.ts +13 -2
  151. package/src/resources/extensions/gsd/auto/phases.ts +8 -2
  152. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  153. package/src/resources/extensions/gsd/auto-dispatch.ts +14 -62
  154. package/src/resources/extensions/gsd/auto-post-unit.ts +15 -27
  155. package/src/resources/extensions/gsd/auto-start.ts +1 -8
  156. package/src/resources/extensions/gsd/auto-worktree.ts +286 -251
  157. package/src/resources/extensions/gsd/auto.ts +102 -7
  158. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +1 -1
  159. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +9 -84
  160. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -17
  161. package/src/resources/extensions/gsd/bootstrap/tests/write-gate-basepath.test.ts +103 -0
  162. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -55
  163. package/src/resources/extensions/gsd/commands-codebase.ts +2 -2
  164. package/src/resources/extensions/gsd/commands-handlers.ts +5 -5
  165. package/src/resources/extensions/gsd/commands-logs.ts +2 -2
  166. package/src/resources/extensions/gsd/commands-scan.ts +2 -2
  167. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  168. package/src/resources/extensions/gsd/commands-workflow-templates.ts +5 -5
  169. package/src/resources/extensions/gsd/db-writer.ts +123 -94
  170. package/src/resources/extensions/gsd/delegation-policy.ts +197 -0
  171. package/src/resources/extensions/gsd/dispatch-guard.ts +6 -11
  172. package/src/resources/extensions/gsd/doctor-engine-checks.ts +2 -2
  173. package/src/resources/extensions/gsd/gsd-db.ts +269 -8
  174. package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
  175. package/src/resources/extensions/gsd/guided-flow.ts +181 -32
  176. package/src/resources/extensions/gsd/markdown-renderer.ts +13 -64
  177. package/src/resources/extensions/gsd/metrics.ts +321 -1
  178. package/src/resources/extensions/gsd/parallel-merge.ts +14 -13
  179. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +5 -2
  180. package/src/resources/extensions/gsd/paths.ts +122 -9
  181. package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -4
  182. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -3
  183. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
  184. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
  185. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
  186. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -1
  187. package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
  188. package/src/resources/extensions/gsd/queue-order.ts +6 -1
  189. package/src/resources/extensions/gsd/rethink.ts +2 -2
  190. package/src/resources/extensions/gsd/state.ts +91 -389
  191. package/src/resources/extensions/gsd/templates/project.md +10 -0
  192. package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +1 -0
  193. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +14 -14
  194. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +6 -0
  195. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +21 -34
  196. package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +331 -0
  197. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +176 -0
  198. package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +6 -7
  199. package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -6
  200. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +12 -27
  201. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +18 -5
  202. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
  203. package/src/resources/extensions/gsd/tests/db-writer-path-containment.test.ts +152 -0
  204. package/src/resources/extensions/gsd/tests/db-writer-root-artifact.test.ts +221 -0
  205. package/src/resources/extensions/gsd/tests/db-writer-scope.test.ts +230 -0
  206. package/src/resources/extensions/gsd/tests/db-writer.test.ts +14 -16
  207. package/src/resources/extensions/gsd/tests/delegation-policy.test.ts +151 -0
  208. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +6 -5
  209. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +10 -38
  210. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +136 -56
  211. package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +3 -0
  212. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +119 -61
  213. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -0
  214. package/src/resources/extensions/gsd/tests/dispatch-backgroundable-annotation.test.ts +55 -0
  215. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +6 -20
  216. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +4 -5
  217. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +14 -15
  218. package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +3 -23
  219. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +11 -16
  220. package/src/resources/extensions/gsd/tests/escalation.test.ts +2 -1
  221. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +193 -0
  222. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +246 -0
  223. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +218 -0
  224. package/src/resources/extensions/gsd/tests/gsd-db-failed-open-restore.test.ts +117 -0
  225. package/src/resources/extensions/gsd/tests/gsd-db-workspace-scope.test.ts +226 -0
  226. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -1
  227. package/src/resources/extensions/gsd/tests/gsd-root-canonical.test.ts +66 -0
  228. package/src/resources/extensions/gsd/tests/gsd-root-home-guard.test.ts +68 -5
  229. package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +15 -36
  230. package/src/resources/extensions/gsd/tests/guided-flow-prompt-consolidation.test.ts +4 -4
  231. package/src/resources/extensions/gsd/tests/handler-worktree-write-isolation.test.ts +57 -0
  232. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +15 -15
  233. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +15 -5
  234. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +371 -0
  235. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +14 -8
  236. package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -1
  237. package/src/resources/extensions/gsd/tests/memory-store.test.ts +3 -2
  238. package/src/resources/extensions/gsd/tests/metrics-atomic-merge.test.ts +222 -0
  239. package/src/resources/extensions/gsd/tests/metrics-lock-hardening.test.ts +400 -0
  240. package/src/resources/extensions/gsd/tests/metrics-lock-not-acquired.test.ts +141 -0
  241. package/src/resources/extensions/gsd/tests/metrics-lock-retry-sleep.test.ts +287 -0
  242. package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +149 -0
  243. package/src/resources/extensions/gsd/tests/metrics-scope.test.ts +378 -0
  244. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +329 -0
  245. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +2 -0
  246. package/src/resources/extensions/gsd/tests/path-cache-decoupled.test.ts +209 -0
  247. package/src/resources/extensions/gsd/tests/path-normalization-unified.test.ts +175 -0
  248. package/src/resources/extensions/gsd/tests/paths-cache.test.ts +170 -0
  249. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +120 -0
  250. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +25 -16
  251. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +1 -0
  252. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +150 -7
  253. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +184 -0
  254. package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +6 -1
  255. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +28 -16
  256. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +3 -0
  257. package/src/resources/extensions/gsd/tests/resolve-ts.mjs +4 -0
  258. package/src/resources/extensions/gsd/tests/resume-missing-worktree-warning.test.ts +209 -0
  259. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +3 -4
  260. package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +10 -56
  261. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +15 -16
  262. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
  263. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +23 -27
  264. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +13 -14
  265. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +4 -3
  266. package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +453 -0
  267. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +10 -33
  268. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +162 -0
  269. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +102 -0
  270. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +186 -0
  271. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +1 -1
  272. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +7 -8
  273. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -15
  274. package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +239 -0
  275. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +12 -7
  276. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +4 -4
  277. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +26 -3
  278. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +9 -15
  279. package/src/resources/extensions/gsd/tests/workspace.test.ts +190 -0
  280. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +13 -0
  281. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +65 -71
  282. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +26 -151
  283. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +35 -35
  284. package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -52
  285. package/src/resources/extensions/gsd/tests/write-intercept.test.ts +1 -1
  286. package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -5
  287. package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -14
  288. package/src/resources/extensions/gsd/tools/complete-task.ts +19 -34
  289. package/src/resources/extensions/gsd/tools/validate-milestone.ts +7 -5
  290. package/src/resources/extensions/gsd/workflow-manifest.ts +4 -1
  291. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -18
  292. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  293. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  294. package/src/resources/extensions/gsd/workspace.ts +95 -0
  295. package/src/resources/extensions/gsd/worktree-command.ts +4 -3
  296. package/src/resources/extensions/gsd/worktree-resolver.ts +16 -2
  297. package/src/resources/extensions/gsd/write-intercept.ts +3 -3
  298. package/dist/web/standalone/.next/server/chunks/8527.js +0 -1
  299. /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → AT5qi39nKXkdmQIOIoh0f}/_buildManifest.js +0 -0
  300. /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → AT5qi39nKXkdmQIOIoh0f}/_ssgManifest.js +0 -0
@@ -0,0 +1,175 @@
1
+ // GSD-2 + Unified path normalization tests: normalizeRealPath and tryRealpath parity
2
+
3
+ import { describe, test, before, beforeEach, afterEach } from "node:test";
4
+ import assert from "node:assert/strict";
5
+ import {
6
+ mkdtempSync,
7
+ mkdirSync,
8
+ writeFileSync,
9
+ existsSync,
10
+ rmSync,
11
+ realpathSync,
12
+ } from "node:fs";
13
+ import { tmpdir } from "node:os";
14
+ import { join } from "node:path";
15
+
16
+ import { normalizeRealPath } from "../paths.ts";
17
+ import { createWorkspace } from "../workspace.ts";
18
+
19
+ // ─── Helpers ────────────────────────────────────────────────────────────────
20
+
21
+ /**
22
+ * Detect whether the filesystem hosting `dir` is case-insensitive.
23
+ * Creates a file with a lowercase name, then probes it via an uppercase name.
24
+ */
25
+ function isCaseInsensitiveFs(dir: string): boolean {
26
+ const lower = join(dir, "ci_probe_lower.txt");
27
+ const upper = join(dir, "CI_PROBE_LOWER.TXT");
28
+ try {
29
+ writeFileSync(lower, "probe");
30
+ return existsSync(upper);
31
+ } finally {
32
+ try { rmSync(lower); } catch { /* ignore */ }
33
+ }
34
+ }
35
+
36
+ function makeProjectDir(): string {
37
+ const dir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-pathnorm-")));
38
+ mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
39
+ return dir;
40
+ }
41
+
42
+ // ─── Suite 1: normalizeRealPath and tryRealpath return identical strings ──────
43
+
44
+ describe("normalizeRealPath and tryRealpath produce identical results", () => {
45
+ let projectDir: string;
46
+
47
+ beforeEach(() => {
48
+ projectDir = makeProjectDir();
49
+ });
50
+
51
+ afterEach(() => {
52
+ rmSync(projectDir, { recursive: true, force: true });
53
+ });
54
+
55
+ test("normalizeRealPath on an existing directory matches realpathSync.native", () => {
56
+ const result = normalizeRealPath(projectDir);
57
+ // realpathSync.native is the canonical form — result must equal it
58
+ const expected = realpathSync.native(projectDir);
59
+ assert.equal(result, expected);
60
+ });
61
+
62
+ test("createWorkspace identityKey equals normalizeRealPath of projectRoot", () => {
63
+ const ws = createWorkspace(projectDir);
64
+ // identityKey is computed via tryRealpath → normalizeRealPath
65
+ assert.equal(ws.identityKey, normalizeRealPath(ws.projectRoot));
66
+ });
67
+
68
+ test("createWorkspace identityKey and normalizeRealPath agree on the same input", () => {
69
+ const ws = createWorkspace(projectDir);
70
+ const direct = normalizeRealPath(projectDir);
71
+ assert.equal(ws.identityKey, direct);
72
+ });
73
+ });
74
+
75
+ // ─── Suite 2: non-existent path fallback ─────────────────────────────────────
76
+
77
+ describe("normalizeRealPath: fallback for non-existent paths", () => {
78
+ test("returns a resolved (absolute) path for a non-existent input", () => {
79
+ const ghost = join(tmpdir(), "gsd-pathnorm-ghost-does-not-exist-" + Date.now());
80
+ const result = normalizeRealPath(ghost);
81
+ // Must be a string, must be absolute, must not throw
82
+ assert.equal(typeof result, "string");
83
+ assert.ok(result.startsWith("/") || /^[A-Za-z]:/.test(result), "result must be absolute");
84
+ });
85
+
86
+ test("normalizeRealPath of a non-existent path is idempotent", () => {
87
+ const ghost = join(tmpdir(), "gsd-pathnorm-ghost2-" + Date.now());
88
+ const first = normalizeRealPath(ghost);
89
+ const second = normalizeRealPath(first);
90
+ assert.equal(first, second);
91
+ });
92
+ });
93
+
94
+ // ─── Suite 3: idempotency on existing paths ───────────────────────────────────
95
+
96
+ describe("normalizeRealPath: idempotency on existing paths", () => {
97
+ let projectDir: string;
98
+
99
+ beforeEach(() => {
100
+ projectDir = makeProjectDir();
101
+ });
102
+
103
+ afterEach(() => {
104
+ rmSync(projectDir, { recursive: true, force: true });
105
+ });
106
+
107
+ test("normalizeRealPath of a normalizeRealPath result is the same", () => {
108
+ const once = normalizeRealPath(projectDir);
109
+ const twice = normalizeRealPath(once);
110
+ assert.equal(once, twice);
111
+ });
112
+
113
+ test("createWorkspace identityKey is idempotent across two calls with same path", () => {
114
+ const ws1 = createWorkspace(projectDir);
115
+ const ws2 = createWorkspace(projectDir);
116
+ assert.equal(ws1.identityKey, ws2.identityKey);
117
+ });
118
+ });
119
+
120
+ // ─── Suite 4: case-insensitive filesystem (macOS HFS+/APFS) ──────────────────
121
+
122
+ describe("normalizeRealPath: case normalization on case-insensitive volumes", () => {
123
+ let projectDir: string;
124
+ let caseInsensitive: boolean;
125
+
126
+ before(() => {
127
+ // Detect FS case sensitivity once for the suite
128
+ const probe = mkdtempSync(join(tmpdir(), "gsd-ci-probe-"));
129
+ caseInsensitive = isCaseInsensitiveFs(probe);
130
+ rmSync(probe, { recursive: true, force: true });
131
+ });
132
+
133
+ beforeEach(() => {
134
+ projectDir = makeProjectDir();
135
+ });
136
+
137
+ afterEach(() => {
138
+ rmSync(projectDir, { recursive: true, force: true });
139
+ });
140
+
141
+ test("upper and lower case paths resolve to the same canonical string on case-insensitive FS", (t) => {
142
+ if (!caseInsensitive) {
143
+ t.skip("case-sensitive filesystem — case-normalization check not applicable");
144
+ return;
145
+ }
146
+
147
+ const lower = projectDir.toLowerCase();
148
+ const upper = projectDir.toUpperCase();
149
+
150
+ const canonicalFromLower = normalizeRealPath(lower);
151
+ const canonicalFromUpper = normalizeRealPath(upper);
152
+
153
+ assert.equal(
154
+ canonicalFromLower,
155
+ canonicalFromUpper,
156
+ "both case variants must resolve to the same canonical path on case-insensitive FS",
157
+ );
158
+ });
159
+
160
+ test("createWorkspace identityKey is case-stable on case-insensitive FS", (t) => {
161
+ if (!caseInsensitive) {
162
+ t.skip("case-sensitive filesystem — case-normalization check not applicable");
163
+ return;
164
+ }
165
+
166
+ const wsLower = createWorkspace(projectDir.toLowerCase());
167
+ const wsUpper = createWorkspace(projectDir.toUpperCase());
168
+
169
+ assert.equal(
170
+ wsLower.identityKey,
171
+ wsUpper.identityKey,
172
+ "identityKey must be identical regardless of input case on case-insensitive FS",
173
+ );
174
+ });
175
+ });
@@ -0,0 +1,170 @@
1
+ // GSD2 — paths cache normalization and clearPathCache() invalidation tests
2
+
3
+ import { describe, test, beforeEach, afterEach } from 'node:test';
4
+ import assert from 'node:assert/strict';
5
+ import { mkdtempSync, mkdirSync, rmSync, renameSync, realpathSync } from 'node:fs';
6
+ import { tmpdir } from 'node:os';
7
+ import { join } from 'node:path';
8
+
9
+ import { gsdRoot, clearPathCache, _clearGsdRootCache } from '../paths.ts';
10
+
11
+ describe('gsdRootCache key normalization', () => {
12
+ let projectDir: string;
13
+ let fakeHome: string;
14
+ let savedHome: string | undefined;
15
+ let savedUserProfile: string | undefined;
16
+ let savedGsdHome: string | undefined;
17
+
18
+ beforeEach(() => {
19
+ projectDir = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-cache-norm-')));
20
+ mkdirSync(join(projectDir, '.gsd'), { recursive: true });
21
+
22
+ fakeHome = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-cache-home-')));
23
+
24
+ savedHome = process.env.HOME;
25
+ savedUserProfile = process.env.USERPROFILE;
26
+ savedGsdHome = process.env.GSD_HOME;
27
+
28
+ // Point HOME and GSD_HOME at an unrelated temp dir to prevent ~/.gsd interference.
29
+ process.env.HOME = fakeHome;
30
+ process.env.USERPROFILE = fakeHome;
31
+ process.env.GSD_HOME = join(fakeHome, '.gsd');
32
+
33
+ _clearGsdRootCache();
34
+ });
35
+
36
+ afterEach(() => {
37
+ if (savedHome === undefined) delete process.env.HOME;
38
+ else process.env.HOME = savedHome;
39
+ if (savedUserProfile === undefined) delete process.env.USERPROFILE;
40
+ else process.env.USERPROFILE = savedUserProfile;
41
+ if (savedGsdHome === undefined) delete process.env.GSD_HOME;
42
+ else process.env.GSD_HOME = savedGsdHome;
43
+
44
+ clearPathCache();
45
+ rmSync(projectDir, { recursive: true, force: true });
46
+ rmSync(fakeHome, { recursive: true, force: true });
47
+ });
48
+
49
+ test('gsdRoot with trailing slash returns same result as without', () => {
50
+ const withoutSlash = gsdRoot(projectDir);
51
+ _clearGsdRootCache();
52
+ const withSlash = gsdRoot(projectDir + '/');
53
+
54
+ assert.equal(
55
+ withoutSlash,
56
+ withSlash,
57
+ 'gsdRoot must return the same path regardless of trailing slash',
58
+ );
59
+ assert.equal(
60
+ withoutSlash,
61
+ join(projectDir, '.gsd'),
62
+ 'both calls should resolve to projectDir/.gsd',
63
+ );
64
+ });
65
+
66
+ test('second call with trailing slash hits cache set by first call without slash', () => {
67
+ // Prime the cache with the no-slash form.
68
+ const first = gsdRoot(projectDir);
69
+ // Now remove .gsd so a fresh probe would return a different path.
70
+ renameSync(join(projectDir, '.gsd'), join(projectDir, '.gsd-hidden'));
71
+ // Call with trailing slash — must hit the normalized cache entry (no re-probe).
72
+ const second = gsdRoot(projectDir + '/');
73
+ // Restore for cleanup.
74
+ renameSync(join(projectDir, '.gsd-hidden'), join(projectDir, '.gsd'));
75
+
76
+ assert.equal(
77
+ second,
78
+ first,
79
+ 'trailing-slash call must return cached result from the no-slash call',
80
+ );
81
+ });
82
+ });
83
+
84
+ describe('clearPathCache() does NOT invalidate gsdRootCache (process-lifetime semantics)', () => {
85
+ let projectDir: string;
86
+ let fakeHome: string;
87
+ let savedHome: string | undefined;
88
+ let savedUserProfile: string | undefined;
89
+ let savedGsdHome: string | undefined;
90
+
91
+ beforeEach(() => {
92
+ projectDir = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-cache-clear-')));
93
+ mkdirSync(join(projectDir, '.gsd'), { recursive: true });
94
+
95
+ fakeHome = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-cache-home2-')));
96
+
97
+ savedHome = process.env.HOME;
98
+ savedUserProfile = process.env.USERPROFILE;
99
+ savedGsdHome = process.env.GSD_HOME;
100
+
101
+ process.env.HOME = fakeHome;
102
+ process.env.USERPROFILE = fakeHome;
103
+ process.env.GSD_HOME = join(fakeHome, '.gsd');
104
+
105
+ _clearGsdRootCache();
106
+ });
107
+
108
+ afterEach(() => {
109
+ if (savedHome === undefined) delete process.env.HOME;
110
+ else process.env.HOME = savedHome;
111
+ if (savedUserProfile === undefined) delete process.env.USERPROFILE;
112
+ else process.env.USERPROFILE = savedUserProfile;
113
+ if (savedGsdHome === undefined) delete process.env.GSD_HOME;
114
+ else process.env.GSD_HOME = savedGsdHome;
115
+
116
+ _clearGsdRootCache();
117
+ clearPathCache();
118
+ rmSync(projectDir, { recursive: true, force: true });
119
+ rmSync(fakeHome, { recursive: true, force: true });
120
+ });
121
+
122
+ test('clearPathCache() does NOT evict a cached gsdRoot result', (t) => {
123
+ // Prime the cache.
124
+ const firstResult = gsdRoot(projectDir);
125
+ assert.equal(firstResult, join(projectDir, '.gsd'));
126
+
127
+ // Remove .gsd so a fresh probe would return a different (fallback) result.
128
+ renameSync(join(projectDir, '.gsd'), join(projectDir, '.gsd-hidden'));
129
+ t.after(() => {
130
+ try { renameSync(join(projectDir, '.gsd-hidden'), join(projectDir, '.gsd')); } catch { /* ignore */ }
131
+ });
132
+
133
+ // clearPathCache() only clears volatile dir caches — gsdRootCache is untouched.
134
+ clearPathCache();
135
+ const afterClearPath = gsdRoot(projectDir);
136
+ assert.equal(
137
+ afterClearPath,
138
+ firstResult,
139
+ 'clearPathCache must NOT evict gsdRootCache — result must still be the cached value',
140
+ );
141
+ });
142
+
143
+ test('_clearGsdRootCache() DOES evict gsdRootCache, causing re-probe', (t) => {
144
+ // Prime the cache.
145
+ const firstResult = gsdRoot(projectDir);
146
+ assert.equal(firstResult, join(projectDir, '.gsd'));
147
+
148
+ // Remove .gsd so a fresh probe returns the creation fallback.
149
+ renameSync(join(projectDir, '.gsd'), join(projectDir, '.gsd-hidden'));
150
+ t.after(() => {
151
+ try { renameSync(join(projectDir, '.gsd-hidden'), join(projectDir, '.gsd')); } catch { /* ignore */ }
152
+ });
153
+
154
+ // _clearGsdRootCache() evicts the entry — next call re-probes.
155
+ _clearGsdRootCache();
156
+ const afterClearRoot = gsdRoot(projectDir);
157
+ assert.equal(
158
+ afterClearRoot,
159
+ join(projectDir, '.gsd'),
160
+ 'after _clearGsdRootCache, gsdRoot must re-probe and return creation fallback',
161
+ );
162
+ // The two results are equal (same path) but the key point is re-probe occurred;
163
+ // the cached firstResult also happened to equal the fallback path.
164
+ // Verify: if we prime again without removing .gsd, clearing root re-probes to gsd.
165
+ renameSync(join(projectDir, '.gsd-hidden'), join(projectDir, '.gsd'));
166
+ _clearGsdRootCache();
167
+ const reprobe = gsdRoot(projectDir);
168
+ assert.equal(reprobe, join(projectDir, '.gsd'), 're-probe after restore returns .gsd');
169
+ });
170
+ });
@@ -0,0 +1,120 @@
1
+ // GSD-2 + Tests for MilestoneScope pinning in pendingAutoStartMap (C1 regression guard)
2
+
3
+ import { describe, test, beforeEach, afterEach } from "node:test";
4
+ import assert from "node:assert/strict";
5
+ import { mkdtempSync, mkdirSync, rmSync, realpathSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { tmpdir } from "node:os";
8
+
9
+ import {
10
+ setPendingAutoStart,
11
+ clearPendingAutoStart,
12
+ _getPendingAutoStart,
13
+ } from "../guided-flow.ts";
14
+
15
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
16
+
17
+ function makeProjectDir(): string {
18
+ const dir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-pas-scope-")));
19
+ mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
20
+ return dir;
21
+ }
22
+
23
+ // ─── Tests ───────────────────────────────────────────────────────────────────
24
+
25
+ describe("pendingAutoStart scope pinning (C1)", () => {
26
+ let base: string;
27
+
28
+ beforeEach(() => {
29
+ clearPendingAutoStart();
30
+ base = makeProjectDir();
31
+ });
32
+
33
+ afterEach(() => {
34
+ clearPendingAutoStart();
35
+ if (base) {
36
+ rmSync(base, { recursive: true, force: true });
37
+ }
38
+ });
39
+
40
+ test("setPendingAutoStart stores a scope whose paths derive from the basePath at reservation time", () => {
41
+ setPendingAutoStart(base, { basePath: base, milestoneId: "M001" });
42
+
43
+ const entry = _getPendingAutoStart(base);
44
+ assert.ok(entry, "entry should exist");
45
+ assert.ok(entry.scope, "entry.scope should be set");
46
+ assert.equal(entry.scope.milestoneId, "M001");
47
+
48
+ const expectedContext = join(base, ".gsd", "milestones", "M001", "M001-CONTEXT.md");
49
+ const expectedRoadmap = join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md");
50
+ const expectedState = join(base, ".gsd", "STATE.md");
51
+
52
+ assert.equal(entry.scope.contextFile(), expectedContext);
53
+ assert.equal(entry.scope.roadmapFile(), expectedRoadmap);
54
+ assert.equal(entry.scope.stateFile(), expectedState);
55
+ });
56
+
57
+ test("scope paths are unaffected by process.chdir after reservation", (t) => {
58
+ setPendingAutoStart(base, { basePath: base, milestoneId: "M002" });
59
+
60
+ const entry = _getPendingAutoStart(base);
61
+ assert.ok(entry, "entry should exist");
62
+
63
+ // Capture paths before cwd change
64
+ const ctxBefore = entry.scope.contextFile();
65
+ const roadmapBefore = entry.scope.roadmapFile();
66
+ const stateBefore = entry.scope.stateFile();
67
+
68
+ // Change cwd to a different directory, then check that scope is unchanged
69
+ const originalCwd = process.cwd();
70
+ const altDir = mkdtempSync(join(tmpdir(), "gsd-cwd-alt-"));
71
+ t.after(() => {
72
+ process.chdir(originalCwd);
73
+ rmSync(altDir, { recursive: true, force: true });
74
+ });
75
+
76
+ process.chdir(altDir);
77
+
78
+ assert.equal(entry.scope.contextFile(), ctxBefore, "contextFile must not change after cwd drift");
79
+ assert.equal(entry.scope.roadmapFile(), roadmapBefore, "roadmapFile must not change after cwd drift");
80
+ assert.equal(entry.scope.stateFile(), stateBefore, "stateFile must not change after cwd drift");
81
+ });
82
+
83
+ test("scope identityKey matches the realpath of the original basePath even with trailing slash", () => {
84
+ const baseWithSlash = base + "/";
85
+ setPendingAutoStart(base, { basePath: baseWithSlash, milestoneId: "M003" });
86
+
87
+ const entry = _getPendingAutoStart(base);
88
+ assert.ok(entry, "entry should exist");
89
+
90
+ const expectedIdentityKey = realpathSync(base);
91
+ assert.equal(
92
+ entry.scope.workspace.identityKey,
93
+ expectedIdentityKey,
94
+ "identityKey must match realpath of the original (non-canonical) basePath",
95
+ );
96
+ });
97
+
98
+ test("clearPendingAutoStart removes the entry", () => {
99
+ setPendingAutoStart(base, { basePath: base, milestoneId: "M001" });
100
+
101
+ const before = _getPendingAutoStart(base);
102
+ assert.ok(before, "entry should exist before clear");
103
+
104
+ clearPendingAutoStart(base);
105
+
106
+ const after = _getPendingAutoStart(base);
107
+ assert.equal(after, null, "entry should be null after clearPendingAutoStart(base)");
108
+ });
109
+
110
+ test("_getPendingAutoStart with no basePath argument returns the sole entry", () => {
111
+ setPendingAutoStart(base, { basePath: base, milestoneId: "M001" });
112
+
113
+ // No argument — should return the sole entry
114
+ const entry = _getPendingAutoStart();
115
+ assert.ok(entry, "sole entry should be returned when no basePath given");
116
+ assert.equal(entry.milestoneId, "M001");
117
+ assert.ok(entry.scope, "sole entry must have a scope");
118
+ assert.equal(entry.scope.milestoneId, "M001");
119
+ });
120
+ });
@@ -6,6 +6,7 @@ import assert from "node:assert/strict";
6
6
  import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
7
7
  import { join } from "node:path";
8
8
  import { tmpdir } from "node:os";
9
+ import { performance } from "node:perf_hooks";
9
10
 
10
11
  import {
11
12
  openDatabase,
@@ -99,21 +100,21 @@ test("ADR-011: sketch slice + progressive_planning ON → phase='refining'", asy
99
100
  assert.equal(state.phase, "refining", "sketch slice with flag ON must yield refining phase");
100
101
  });
101
102
 
102
- test("ADR-011: sketch slice + progressive_planning OFF → phase='planning' (backwards compat)", async (t) => {
103
+ test("ADR-011: sketch slice + progressive_planning OFF → DB sketch metadata still yields refining", async (t) => {
103
104
  const originalCwd = process.cwd();
104
105
  const base = makeFixtureBase();
105
106
  t.after(() => cleanup(base, originalCwd));
106
107
 
107
108
  seedMilestoneWithSketchedS02(base);
108
109
  writeS01Artifacts(base);
109
- // Write a PREFERENCES.md without the flag so loadEffectiveGSDPreferences finds
110
- // a valid file but progressive_planning resolves to undefined.
110
+ // Write a PREFERENCES.md without the flag. DB slice metadata remains
111
+ // authoritative for whether this slice needs refinement.
111
112
  writePreferences(base, "phases:\n skip_research: false");
112
113
  process.chdir(base);
113
114
 
114
115
  const state = await deriveStateFromDb(base);
115
116
  assert.equal(state.activeSlice?.id, "S02");
116
- assert.equal(state.phase, "planning", "flag absent must fall through to planning");
117
+ assert.equal(state.phase, "refining", "flag absent must not override DB sketch metadata");
117
118
  });
118
119
 
119
120
  test("ADR-011: dispatch rule maps refining → refine-slice unit", async (t) => {
@@ -516,24 +517,32 @@ test("ADR-011 P3 #26: refine-slice dispatch latency is bounded vs plan-slice bas
516
517
  await buildPlanSlicePrompt("M001", "Test", "S02", "Feature", base);
517
518
  await buildRefineSlicePrompt("M001", "Test", "S02", "Feature", base);
518
519
 
519
- const planStart = Date.now();
520
- await buildPlanSlicePrompt("M001", "Test", "S02", "Feature", base);
521
- const planElapsed = Date.now() - planStart;
520
+ const measure = async (fn: () => Promise<string>): Promise<number> => {
521
+ const start = performance.now();
522
+ await fn();
523
+ return performance.now() - start;
524
+ };
522
525
 
523
- const refineStart = Date.now();
524
- await buildRefineSlicePrompt("M001", "Test", "S02", "Feature", base);
525
- const refineElapsed = Date.now() - refineStart;
526
+ const planSamples: number[] = [];
527
+ const refineSamples: number[] = [];
528
+ for (let i = 0; i < 5; i++) {
529
+ planSamples.push(await measure(() => buildPlanSlicePrompt("M001", "Test", "S02", "Feature", base)));
530
+ refineSamples.push(await measure(() => buildRefineSlicePrompt("M001", "Test", "S02", "Feature", base)));
531
+ }
532
+ const bestPlan = Math.min(...planSamples);
533
+ const bestRefine = Math.min(...refineSamples);
526
534
 
527
535
  assert.ok(
528
- refineElapsed < 500,
529
- `refine-slice prompt build must complete under 500ms (took ${refineElapsed}ms)`,
536
+ bestRefine < 500,
537
+ `refine-slice prompt build must complete under 500ms (best=${bestRefine.toFixed(1)}ms, samples=${refineSamples.map(n => n.toFixed(1)).join(",")})`,
530
538
  );
531
539
  // Guard the ratio only when the baseline is large enough to be meaningful —
532
- // if plan-slice measures 0-2ms the ratio is dominated by timer noise.
533
- if (planElapsed >= 5) {
540
+ // if plan-slice measures in single-digit milliseconds, the ratio is dominated
541
+ // by scheduler and filesystem noise under the concurrent test runner.
542
+ if (bestPlan >= 20) {
534
543
  assert.ok(
535
- refineElapsed < planElapsed * 3,
536
- `refine-slice must not exceed 3x plan-slice baseline (refine=${refineElapsed}ms, plan=${planElapsed}ms)`,
544
+ bestRefine < bestPlan * 3,
545
+ `refine-slice must not exceed 3x plan-slice baseline (refine=${bestRefine.toFixed(1)}ms, plan=${bestPlan.toFixed(1)}ms)`,
537
546
  );
538
547
  }
539
548
  });
@@ -91,6 +91,7 @@ function makeMilestoneRow() {
91
91
  definition_of_done: [],
92
92
  requirement_coverage: '',
93
93
  boundary_map_markdown: '',
94
+ sequence: 0,
94
95
  };
95
96
  }
96
97