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

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 (203) 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-dispatch.js +4 -56
  9. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -27
  10. package/dist/resources/extensions/gsd/auto-start.js +1 -8
  11. package/dist/resources/extensions/gsd/auto-worktree.js +59 -176
  12. package/dist/resources/extensions/gsd/auto.js +24 -6
  13. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -77
  14. package/dist/resources/extensions/gsd/commands-codebase.js +2 -2
  15. package/dist/resources/extensions/gsd/commands-handlers.js +5 -5
  16. package/dist/resources/extensions/gsd/commands-logs.js +2 -2
  17. package/dist/resources/extensions/gsd/commands-scan.js +2 -2
  18. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  19. package/dist/resources/extensions/gsd/commands-workflow-templates.js +5 -5
  20. package/dist/resources/extensions/gsd/db-writer.js +16 -85
  21. package/dist/resources/extensions/gsd/dispatch-guard.js +6 -10
  22. package/dist/resources/extensions/gsd/doctor-engine-checks.js +2 -2
  23. package/dist/resources/extensions/gsd/gsd-db.js +74 -8
  24. package/dist/resources/extensions/gsd/guided-flow.js +31 -8
  25. package/dist/resources/extensions/gsd/markdown-renderer.js +14 -51
  26. package/dist/resources/extensions/gsd/parallel-merge.js +14 -13
  27. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +5 -2
  28. package/dist/resources/extensions/gsd/paths.js +35 -1
  29. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
  30. package/dist/resources/extensions/gsd/queue-order.js +6 -1
  31. package/dist/resources/extensions/gsd/rethink.js +2 -2
  32. package/dist/resources/extensions/gsd/state.js +91 -372
  33. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -5
  34. package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -12
  35. package/dist/resources/extensions/gsd/tools/complete-task.js +19 -31
  36. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -5
  37. package/dist/resources/extensions/gsd/workflow-manifest.js +2 -1
  38. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -21
  39. package/dist/resources/extensions/gsd/workflow-reconcile.js +3 -3
  40. package/dist/resources/extensions/gsd/worktree-command.js +4 -3
  41. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  42. package/dist/web/standalone/.next/BUILD_ID +1 -1
  43. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  44. package/dist/web/standalone/.next/build-manifest.json +2 -2
  45. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  46. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  47. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  55. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  63. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  64. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  65. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  66. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  67. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  68. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  69. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  70. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  71. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  72. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  73. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  74. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  75. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  76. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  77. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  78. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  79. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  80. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  81. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  82. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  83. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  84. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  85. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  86. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  87. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  88. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  89. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  90. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  91. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  92. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  93. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  94. package/dist/web/standalone/.next/server/app/index.html +1 -1
  95. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  102. package/dist/web/standalone/.next/server/chunks/6336.js +1 -0
  103. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  104. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  106. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  107. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  108. package/package.json +1 -1
  109. package/packages/mcp-server/dist/workflow-tools.d.ts +6 -0
  110. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  111. package/packages/mcp-server/dist/workflow-tools.js +56 -2
  112. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  113. package/packages/mcp-server/src/parse-workflow-args.test.ts +80 -0
  114. package/packages/mcp-server/src/workflow-tools.ts +61 -2
  115. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  116. package/src/resources/extensions/browser-tools/tools/intent.ts +13 -2
  117. package/src/resources/extensions/gsd/auto-dispatch.ts +4 -60
  118. package/src/resources/extensions/gsd/auto-post-unit.ts +7 -26
  119. package/src/resources/extensions/gsd/auto-start.ts +1 -8
  120. package/src/resources/extensions/gsd/auto-worktree.ts +61 -204
  121. package/src/resources/extensions/gsd/auto.ts +23 -6
  122. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +9 -84
  123. package/src/resources/extensions/gsd/commands-codebase.ts +2 -2
  124. package/src/resources/extensions/gsd/commands-handlers.ts +5 -5
  125. package/src/resources/extensions/gsd/commands-logs.ts +2 -2
  126. package/src/resources/extensions/gsd/commands-scan.ts +2 -2
  127. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  128. package/src/resources/extensions/gsd/commands-workflow-templates.ts +5 -5
  129. package/src/resources/extensions/gsd/db-writer.ts +16 -83
  130. package/src/resources/extensions/gsd/dispatch-guard.ts +6 -11
  131. package/src/resources/extensions/gsd/doctor-engine-checks.ts +2 -2
  132. package/src/resources/extensions/gsd/gsd-db.ts +85 -8
  133. package/src/resources/extensions/gsd/guided-flow.ts +35 -8
  134. package/src/resources/extensions/gsd/markdown-renderer.ts +13 -64
  135. package/src/resources/extensions/gsd/parallel-merge.ts +14 -13
  136. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +5 -2
  137. package/src/resources/extensions/gsd/paths.ts +55 -1
  138. package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
  139. package/src/resources/extensions/gsd/queue-order.ts +6 -1
  140. package/src/resources/extensions/gsd/rethink.ts +2 -2
  141. package/src/resources/extensions/gsd/state.ts +91 -389
  142. package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +1 -0
  143. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +6 -0
  144. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +21 -34
  145. package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +6 -7
  146. package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -6
  147. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +12 -27
  148. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +18 -5
  149. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
  150. package/src/resources/extensions/gsd/tests/db-writer.test.ts +14 -16
  151. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +6 -5
  152. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +10 -38
  153. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +136 -56
  154. package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +3 -0
  155. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +119 -61
  156. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -0
  157. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +6 -20
  158. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +4 -5
  159. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +14 -15
  160. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +11 -16
  161. package/src/resources/extensions/gsd/tests/escalation.test.ts +2 -1
  162. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -1
  163. package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +15 -36
  164. package/src/resources/extensions/gsd/tests/handler-worktree-write-isolation.test.ts +57 -0
  165. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +15 -15
  166. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +15 -5
  167. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +14 -8
  168. package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -1
  169. package/src/resources/extensions/gsd/tests/memory-store.test.ts +3 -2
  170. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +2 -0
  171. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +25 -16
  172. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +1 -0
  173. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +184 -0
  174. package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +6 -1
  175. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +3 -0
  176. package/src/resources/extensions/gsd/tests/resolve-ts.mjs +4 -0
  177. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +3 -4
  178. package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +10 -56
  179. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +15 -16
  180. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
  181. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +23 -27
  182. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +13 -14
  183. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +4 -3
  184. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +10 -33
  185. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +7 -8
  186. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -15
  187. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +12 -7
  188. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +4 -4
  189. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +24 -1
  190. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +13 -0
  191. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +65 -71
  192. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +26 -151
  193. package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -5
  194. package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -14
  195. package/src/resources/extensions/gsd/tools/complete-task.ts +19 -34
  196. package/src/resources/extensions/gsd/tools/validate-milestone.ts +7 -5
  197. package/src/resources/extensions/gsd/workflow-manifest.ts +4 -1
  198. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -18
  199. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  200. package/src/resources/extensions/gsd/worktree-command.ts +4 -3
  201. package/dist/web/standalone/.next/server/chunks/8527.js +0 -1
  202. /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → oZGTPvJBQX_IDKKnuV8Bt}/_buildManifest.js +0 -0
  203. /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → oZGTPvJBQX_IDKKnuV8Bt}/_ssgManifest.js +0 -0
@@ -1,8 +1,9 @@
1
1
  /**
2
- * worktree-sync-tasks.test.ts — Regression test for #1678.
2
+ * worktree-sync-tasks.test.ts
3
3
  *
4
- * Verifies that syncWorktreeStateBack() correctly syncs task summaries
5
- * from the tasks/ subdirectory within each slice, not just slice-level files.
4
+ * DB-authoritative worktree contract: task and milestone markdown under a
5
+ * worktree .gsd directory are legacy projections. syncWorktreeStateBack must
6
+ * not copy them into the canonical project .gsd tree.
6
7
  */
7
8
 
8
9
  import test from "node:test";
@@ -11,7 +12,6 @@ import {
11
12
  existsSync,
12
13
  mkdirSync,
13
14
  mkdtempSync,
14
- readFileSync,
15
15
  rmSync,
16
16
  writeFileSync,
17
17
  } from "node:fs";
@@ -20,19 +20,13 @@ import { tmpdir } from "node:os";
20
20
 
21
21
  import { syncWorktreeStateBack } from "../auto-worktree.ts";
22
22
 
23
- // ─── Helpers ─────────────────────────────────────────────────────────
24
-
25
23
  function makeTempDir(prefix: string): string {
26
24
  return mkdtempSync(join(tmpdir(), `gsd-sync-test-${prefix}-`));
27
25
  }
28
26
 
29
27
  function cleanup(...dirs: string[]): void {
30
28
  for (const dir of dirs) {
31
- try {
32
- rmSync(dir, { recursive: true, force: true });
33
- } catch {
34
- // ignore
35
- }
29
+ rmSync(dir, { recursive: true, force: true });
36
30
  }
37
31
  }
38
32
 
@@ -42,168 +36,49 @@ function writeFile(dir: string, relativePath: string, content: string): void {
42
36
  writeFileSync(fullPath, content, "utf-8");
43
37
  }
44
38
 
45
- // ─── Tests ───────────────────────────────────────────────────────────
46
-
47
- test("syncWorktreeStateBack copies task summaries from tasks/ subdirectory (#1678)", () => {
39
+ test("syncWorktreeStateBack does not copy task markdown projections from worktree", () => {
48
40
  const mainBase = makeTempDir("main");
49
41
  const wtBase = makeTempDir("wt");
50
- const currentMid = "M000"; // milestone being merged (skipped by sync)
51
- const mid = "M001"; // other milestone that should be synced
52
42
 
53
43
  try {
54
- // Set up worktree with milestone, slice, and task files
55
- writeFile(wtBase, `.gsd/milestones/${mid}/${mid}-ROADMAP.md`, "# Roadmap\n");
56
- writeFile(wtBase, `.gsd/milestones/${mid}/${mid}-SUMMARY.md`, "# Summary\n");
57
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-PLAN.md`, "# Plan\n");
58
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-SUMMARY.md`, "# Slice Summary\n");
59
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-UAT.md`, "# UAT\n");
60
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-PLAN.md`, "# Task 1 Plan\n");
61
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`, "# Task 1 Summary\n");
62
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T02-PLAN.md`, "# Task 2 Plan\n");
63
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T02-SUMMARY.md`, "# Task 2 Summary\n");
64
-
65
- // Set up main with empty .gsd
44
+ writeFile(wtBase, ".gsd/milestones/M001/M001-ROADMAP.md", "# Roadmap\n");
45
+ writeFile(wtBase, ".gsd/milestones/M001/slices/S01/S01-PLAN.md", "# Plan\n");
46
+ writeFile(wtBase, ".gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md", "# Task Summary\n");
66
47
  mkdirSync(join(mainBase, ".gsd"), { recursive: true });
67
48
 
68
- // Run sync currentMid is skipped, mid (M001) should be synced
69
- const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
70
-
71
- // Verify milestone-level files synced
72
- assert.ok(
73
- existsSync(join(mainBase, `.gsd/milestones/${mid}/${mid}-ROADMAP.md`)),
74
- "ROADMAP should be synced",
75
- );
76
- assert.ok(
77
- existsSync(join(mainBase, `.gsd/milestones/${mid}/${mid}-SUMMARY.md`)),
78
- "SUMMARY should be synced",
79
- );
80
-
81
- // Verify slice-level files synced
82
- assert.ok(
83
- existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/S01-PLAN.md`)),
84
- "S01-PLAN should be synced",
85
- );
86
- assert.ok(
87
- existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/S01-SUMMARY.md`)),
88
- "S01-SUMMARY should be synced",
89
- );
49
+ const result = syncWorktreeStateBack(mainBase, wtBase, "M000");
90
50
 
91
- // Verify task-level files synced (THE BUG FIX)
92
- assert.ok(
93
- existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-PLAN.md`)),
94
- "T01-PLAN should be synced (was dropped before fix)",
95
- );
96
- assert.ok(
97
- existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`)),
98
- "T01-SUMMARY should be synced (was dropped before fix)",
99
- );
100
- assert.ok(
101
- existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T02-PLAN.md`)),
102
- "T02-PLAN should be synced (was dropped before fix)",
103
- );
104
- assert.ok(
105
- existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T02-SUMMARY.md`)),
106
- "T02-SUMMARY should be synced (was dropped before fix)",
107
- );
108
-
109
- // Verify task files appear in synced list
110
- const taskSynced = result.synced.filter(p => p.includes("/tasks/"));
111
- assert.ok(
112
- taskSynced.length >= 4,
113
- `Expected at least 4 task files in synced list, got ${taskSynced.length}: ${taskSynced.join(", ")}`,
114
- );
115
-
116
- // Verify content integrity
117
- const t1Summary = readFileSync(
118
- join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`),
119
- "utf-8",
51
+ assert.equal(result.synced.some((p) => p.includes("milestones/")), false);
52
+ assert.equal(
53
+ existsSync(join(mainBase, ".gsd/milestones/M001/M001-ROADMAP.md")),
54
+ false,
55
+ "milestone markdown projection must not be copied",
120
56
  );
121
- assert.equal(t1Summary, "# Task 1 Summary\n");
122
- } finally {
123
- cleanup(mainBase, wtBase);
124
- }
125
- });
126
-
127
- test("syncWorktreeStateBack handles multiple slices with tasks (#1678)", () => {
128
- const mainBase = makeTempDir("main");
129
- const wtBase = makeTempDir("wt");
130
- const currentMid = "M000"; // milestone being merged (skipped)
131
- const mid = "M002"; // other milestone that should be synced
132
-
133
- try {
134
- // Set up two slices with tasks
135
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-SUMMARY.md`, "# S01\n");
136
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`, "# S01-T01\n");
137
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S02/S02-SUMMARY.md`, "# S02\n");
138
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S02/tasks/T01-SUMMARY.md`, "# S02-T01\n");
139
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S02/tasks/T02-SUMMARY.md`, "# S02-T02\n");
140
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S02/tasks/T03-SUMMARY.md`, "# S02-T03\n");
141
-
142
- mkdirSync(join(mainBase, ".gsd"), { recursive: true });
143
-
144
- const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
145
-
146
- // All task summaries from both slices should be synced
147
- assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`)));
148
- assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S02/tasks/T01-SUMMARY.md`)));
149
- assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S02/tasks/T02-SUMMARY.md`)));
150
- assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S02/tasks/T03-SUMMARY.md`)));
151
-
152
- // Verify content integrity across slices
153
57
  assert.equal(
154
- readFileSync(join(mainBase, `.gsd/milestones/${mid}/slices/S02/tasks/T03-SUMMARY.md`), "utf-8"),
155
- "# S02-T03\n",
58
+ existsSync(join(mainBase, ".gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md")),
59
+ false,
60
+ "task summary projection must not be copied",
156
61
  );
157
62
  } finally {
158
63
  cleanup(mainBase, wtBase);
159
64
  }
160
65
  });
161
66
 
162
- test("syncWorktreeStateBack handles slices without tasks/ directory", () => {
163
- const mainBase = makeTempDir("main");
164
- const wtBase = makeTempDir("wt");
165
- const currentMid = "M000"; // milestone being merged (skipped)
166
- const mid = "M003"; // other milestone that should be synced
167
-
168
- try {
169
- // Slice with no tasks/ subdirectory (legitimate case: pre-planning)
170
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-RESEARCH.md`, "# Research\n");
171
-
172
- mkdirSync(join(mainBase, ".gsd"), { recursive: true });
173
-
174
- const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
175
-
176
- // Should sync the slice file without errors
177
- assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/S01-RESEARCH.md`)));
178
- // Should not have any task entries
179
- const taskSynced = result.synced.filter(p => p.includes("/tasks/"));
180
- assert.equal(taskSynced.length, 0);
181
- } finally {
182
- cleanup(mainBase, wtBase);
183
- }
184
- });
185
-
186
- test("syncWorktreeStateBack ignores non-md files in tasks/", () => {
67
+ test("syncWorktreeStateBack still copies diagnostic root files", () => {
187
68
  const mainBase = makeTempDir("main");
188
69
  const wtBase = makeTempDir("wt");
189
- const currentMid = "M000"; // milestone being merged (skipped)
190
- const mid = "M004"; // other milestone that should be synced
191
70
 
192
71
  try {
193
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-PLAN.md`, "# Plan\n");
194
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`, "# T01\n");
195
- // Non-md file should be ignored
196
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/.DS_Store`, "junk");
197
- writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/notes.txt`, "notes");
198
-
72
+ writeFile(wtBase, ".gsd/completed-units.json", JSON.stringify({ units: ["M001/S01/T01"] }));
73
+ writeFile(wtBase, ".gsd/metrics.json", JSON.stringify({ version: 1, units: [] }));
199
74
  mkdirSync(join(mainBase, ".gsd"), { recursive: true });
200
75
 
201
- const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
76
+ const result = syncWorktreeStateBack(mainBase, wtBase, "M001");
202
77
 
203
- // Only .md files should be synced
204
- assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`)));
205
- assert.ok(!existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/.DS_Store`)));
206
- assert.ok(!existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/notes.txt`)));
78
+ assert.ok(result.synced.includes("completed-units.json"));
79
+ assert.ok(result.synced.includes("metrics.json"));
80
+ assert.ok(existsSync(join(mainBase, ".gsd/completed-units.json")));
81
+ assert.ok(existsSync(join(mainBase, ".gsd/metrics.json")));
207
82
  } finally {
208
83
  cleanup(mainBase, wtBase);
209
84
  }
@@ -56,6 +56,7 @@ export interface CompleteMilestoneParams {
56
56
  export interface CompleteMilestoneResult {
57
57
  milestoneId: string;
58
58
  summaryPath: string;
59
+ stale?: boolean;
59
60
  }
60
61
 
61
62
  function renderMilestoneSummaryMarkdown(params: CompleteMilestoneParams): string {
@@ -206,15 +207,15 @@ export async function handleCompleteMilestone(
206
207
  // This handles re-dispatch scenarios (DB/disk state divergence) where a prior
207
208
  // completion already wrote the file. Overwriting would silently destroy the
208
209
  // richer content the agent produced during the original completion run.
210
+ let projectionStale = false;
209
211
  if (!existsSync(summaryPath)) {
210
212
  try {
211
213
  await saveFile(summaryPath, summaryMd);
212
214
  } catch (renderErr) {
213
- // Disk render failed — roll back DB status so state stays consistent
214
- logWarning("tool", `complete_milestone disk render failed, rolling back DB status: ${(renderErr as Error).message}`);
215
- updateMilestoneStatus(params.milestoneId, 'active', null);
216
- invalidateStateCache();
217
- return { error: `disk render failed: ${(renderErr as Error).message}` };
215
+ projectionStale = true;
216
+ logWarning("projection", `complete_milestone projection write failed for ${params.milestoneId}; DB completion remains committed`, {
217
+ error: (renderErr as Error).message,
218
+ });
218
219
  }
219
220
  }
220
221
 
@@ -252,5 +253,6 @@ export async function handleCompleteMilestone(
252
253
  return {
253
254
  milestoneId: params.milestoneId,
254
255
  summaryPath,
256
+ ...(projectionStale ? { stale: true } : {}),
255
257
  };
256
258
  }
@@ -4,7 +4,8 @@
4
4
  * Validates inputs, checks all tasks are complete, writes slice row to DB in
5
5
  * a transaction, then (outside the transaction) renders SUMMARY.md + UAT.md
6
6
  * to disk, toggles the roadmap checkbox, stores rendered markdown in DB for
7
- * D004 recovery, and invalidates caches.
7
+ * D004 recovery, and invalidates caches. Projection write failures are stale
8
+ * projection diagnostics and do not roll back committed DB state.
8
9
  */
9
10
 
10
11
  import { join } from "node:path";
@@ -277,7 +278,6 @@ export async function handleCompleteSlice(
277
278
 
278
279
  // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
279
280
  const completedAt = new Date().toISOString();
280
- const originalSliceStatus = getSlice(params.milestoneId, params.sliceId)?.status ?? "pending";
281
281
  let guardError: string | null = null;
282
282
 
283
283
  transaction(() => {
@@ -349,10 +349,6 @@ export async function handleCompleteSlice(
349
349
  return { error: guardError };
350
350
  }
351
351
 
352
- // ── Filesystem operations (outside transaction) ─────────────────────────
353
- // If disk render fails, roll back the DB status so deriveState() and
354
- // verifyExpectedArtifact() stay consistent (both say "not done").
355
-
356
352
  // Render summary markdown
357
353
  const summaryMd = renderSliceSummaryMarkdown(params);
358
354
 
@@ -371,6 +367,8 @@ export async function handleCompleteSlice(
371
367
 
372
368
  const uatMd = renderUatMarkdown(params);
373
369
  const uatPath = summaryPath.replace(/-SUMMARY\.md$/, "-UAT.md");
370
+ setSliceSummaryMd(params.milestoneId, params.sliceId, summaryMd, uatMd);
371
+ let projectionStale = false;
374
372
 
375
373
  try {
376
374
  await saveFile(summaryPath, summaryMd);
@@ -382,16 +380,10 @@ export async function handleCompleteSlice(
382
380
  logWarning("tool", `complete_slice — could not find roadmap for ${params.milestoneId}, skipping checkbox toggle`);
383
381
  }
384
382
  } catch (renderErr) {
385
- // Disk render failed — roll back DB status so state stays consistent
386
- logWarning("tool", `complete_slice disk render failed for ${params.milestoneId}/${params.sliceId}, rolling back DB status`, { error: (renderErr as Error).message });
387
- updateSliceStatus(params.milestoneId, params.sliceId, originalSliceStatus);
388
- invalidateStateCache();
389
- return { error: `disk render failed: ${(renderErr as Error).message}` };
383
+ projectionStale = true;
384
+ logWarning("projection", `complete_slice projection write failed for ${params.milestoneId}/${params.sliceId}; DB completion remains committed`, { error: (renderErr as Error).message });
390
385
  }
391
386
 
392
- // Store rendered markdown in DB for D004 recovery
393
- setSliceSummaryMd(params.milestoneId, params.sliceId, summaryMd, uatMd);
394
-
395
387
  // ── Close gates owned by complete-slice (Q8) ───────────────────────────
396
388
  // Each owned gate maps to a specific summary section via the registry.
397
389
  // If the caller populated the corresponding field, record `pass`; if the
@@ -493,5 +485,6 @@ export async function handleCompleteSlice(
493
485
  milestoneId: params.milestoneId,
494
486
  summaryPath,
495
487
  uatPath,
488
+ ...(projectionStale ? { stale: true } : {}),
496
489
  };
497
490
  }
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * complete-task handler — the core operation behind gsd_complete_task.
3
3
  *
4
- * Validates inputs, writes task row to DB in a transaction, then (outside
5
- * the transaction) renders SUMMARY.md to disk, toggles the plan checkbox,
6
- * stores the rendered markdown in the DB for D004 recovery, and invalidates
7
- * caches.
4
+ * Validates inputs, writes task row and rendered SUMMARY.md to DB in a
5
+ * transaction, then renders projections to disk and invalidates caches.
6
+ * Projection write failures are reported as stale projections and do not roll
7
+ * back committed DB state.
8
8
  */
9
9
 
10
10
  import { join } from "node:path";
@@ -22,13 +22,12 @@ import {
22
22
  getSlice,
23
23
  getTask,
24
24
  updateTaskStatus,
25
- setTaskSummaryMd,
26
25
  deleteVerificationEvidence,
27
26
  saveGateResult,
28
27
  getPendingGatesForTurn,
29
28
  } from "../gsd-db.js";
30
29
  import { getGatesForTurn } from "../gate-registry.js";
31
- import { resolveSliceFile, resolveTasksDir, clearPathCache } from "../paths.js";
30
+ import { resolveTasksDir, clearPathCache } from "../paths.js";
32
31
  import { checkOwnership, taskUnitKey } from "../unit-ownership.js";
33
32
  import { saveFile, clearParseCache } from "../files.js";
34
33
  import { invalidateStateCache } from "../state.js";
@@ -168,6 +167,7 @@ export async function handleCompleteTask(
168
167
  // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
169
168
  const completedAt = new Date().toISOString();
170
169
  let guardError: string | null = null;
170
+ let summaryMd = "";
171
171
 
172
172
  // ── ADR-011 Phase 2: validate escalation payload BEFORE any side effects ─
173
173
  // Building the artifact runs the full shape validation (2-4 options, unique
@@ -237,6 +237,9 @@ export async function handleCompleteTask(
237
237
  }
238
238
 
239
239
  // All guards passed — perform writes
240
+ const taskRow = paramsToTaskRow(params, completedAt);
241
+ summaryMd = renderSummaryContent(taskRow, params.sliceId, params.milestoneId, params.verificationEvidence ?? []);
242
+
240
243
  insertMilestone({ id: params.milestoneId, title: params.milestoneId });
241
244
  insertSlice({ id: params.sliceId, milestoneId: params.milestoneId, title: params.sliceId });
242
245
  insertTask({
@@ -254,6 +257,7 @@ export async function handleCompleteTask(
254
257
  knownIssues: params.knownIssues ?? "None.",
255
258
  keyFiles: params.keyFiles ?? [],
256
259
  keyDecisions: params.keyDecisions ?? [],
260
+ fullSummaryMd: summaryMd,
257
261
  });
258
262
 
259
263
  for (const evidence of (params.verificationEvidence ?? [])) {
@@ -301,13 +305,7 @@ export async function handleCompleteTask(
301
305
  return { error: guardError };
302
306
  }
303
307
 
304
- // ── Filesystem operations (outside transaction) ─────────────────────────
305
- // If disk render fails, roll back the DB status so deriveState() and
306
- // verifyExpectedArtifact() stay consistent (both say "not done").
307
-
308
- // Render summary markdown via the single source of truth (#2720)
309
- const taskRow = paramsToTaskRow(params, completedAt);
310
- const summaryMd = renderSummaryContent(taskRow, params.sliceId, params.milestoneId, params.verificationEvidence ?? []);
308
+ let projectionStale = false;
311
309
 
312
310
  // Resolve and write summary to disk
313
311
  let summaryPath: string;
@@ -325,30 +323,16 @@ export async function handleCompleteTask(
325
323
  try {
326
324
  await saveFile(summaryPath, summaryMd);
327
325
 
328
- // Toggle plan checkbox via renderer module
329
- const planPath = resolveSliceFile(basePath, params.milestoneId, params.sliceId, "PLAN");
330
- if (planPath) {
331
- await renderPlanCheckboxes(basePath, params.milestoneId, params.sliceId);
332
- } else {
333
- process.stderr.write(
334
- `gsd-db: complete_task — could not find plan file for ${params.sliceId}/${params.milestoneId}, skipping checkbox toggle\n`,
335
- );
336
- }
326
+ // Toggle or regenerate the plan projection from DB. Missing projection
327
+ // files are rebuilt by the renderer instead of being skipped.
328
+ await renderPlanCheckboxes(basePath, params.milestoneId, params.sliceId);
337
329
  } catch (renderErr) {
338
- // Disk render failed — roll back DB status so state stays consistent
339
- logWarning("tool", `complete_task disk render failed, rolling back DB status: ${(renderErr as Error).message}`);
340
- // Delete orphaned verification_evidence rows first (FK constraint
341
- // references tasks, so evidence must go before status change).
342
- // Without this, retries accumulate duplicate evidence rows (#2724).
343
- deleteVerificationEvidence(params.milestoneId, params.sliceId, params.taskId);
344
- updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, 'pending');
345
- invalidateStateCache();
346
- return { error: `disk render failed: ${(renderErr as Error).message}` };
330
+ projectionStale = true;
331
+ logWarning("projection", `complete_task projection write failed for ${params.milestoneId}/${params.sliceId}/${params.taskId}; DB completion remains committed`, {
332
+ error: (renderErr as Error).message,
333
+ });
347
334
  }
348
335
 
349
- // Store rendered markdown in DB for D004 recovery
350
- setTaskSummaryMd(params.milestoneId, params.sliceId, params.taskId, summaryMd);
351
-
352
336
  // ── Close gates owned by execute-task (Q5/Q6/Q7) for this task ────────
353
337
  // Each gate id maps to a specific params field via taskGateFieldForId.
354
338
  // When the model populates the field, record `pass`; when it's empty,
@@ -471,5 +455,6 @@ export async function handleCompleteTask(
471
455
  sliceId: params.sliceId,
472
456
  milestoneId: params.milestoneId,
473
457
  summaryPath,
458
+ ...(projectionStale ? { stale: true } : {}),
474
459
  };
475
460
  }
@@ -14,7 +14,6 @@ import { join } from "node:path";
14
14
  import {
15
15
  transaction,
16
16
  insertAssessment,
17
- deleteAssessmentByScope,
18
17
  getMilestoneSlices,
19
18
  } from "../gsd-db.js";
20
19
  import { resolveMilestonePath, clearPathCache } from "../paths.js";
@@ -45,6 +44,7 @@ export interface ValidateMilestoneResult {
45
44
  milestoneId: string;
46
45
  verdict: string;
47
46
  validationPath: string;
47
+ stale?: boolean;
48
48
  }
49
49
 
50
50
  export interface ValidateMilestoneOptions {
@@ -150,13 +150,14 @@ export async function handleValidateMilestone(
150
150
  });
151
151
 
152
152
  // ── Filesystem render (outside transaction) ────────────────────────────
153
- // If disk render fails, roll back the DB row so state stays consistent.
153
+ let projectionStale = false;
154
154
  try {
155
155
  await saveFile(validationPath, validationMd);
156
156
  } catch (renderErr) {
157
- logWarning("tool", `validate_milestone — disk render failed, rolling back DB row: ${(renderErr as Error).message}`);
158
- deleteAssessmentByScope(params.milestoneId, 'milestone-validation');
159
- return { error: `disk render failed: ${(renderErr as Error).message}` };
157
+ projectionStale = true;
158
+ logWarning("projection", `validate_milestone projection write failed for ${params.milestoneId}; DB validation remains committed`, {
159
+ error: (renderErr as Error).message,
160
+ });
160
161
  }
161
162
 
162
163
  invalidateStateCache();
@@ -202,5 +203,6 @@ export async function handleValidateMilestone(
202
203
  milestoneId: params.milestoneId,
203
204
  verdict: params.verdict,
204
205
  validationPath,
206
+ ...(projectionStale ? { stale: true } : {}),
205
207
  };
206
208
  }
@@ -76,7 +76,9 @@ export function snapshotState(): StateManifest {
76
76
  // Wrap all reads in a deferred transaction so the snapshot is consistent
77
77
  // (all SELECTs see the same DB state even if a concurrent write lands between them).
78
78
  return readTransaction(() => {
79
- const rawMilestones = db.prepare("SELECT * FROM milestones ORDER BY id").all() as Record<string, unknown>[];
79
+ const rawMilestones = db.prepare(
80
+ "SELECT * FROM milestones ORDER BY CASE WHEN sequence > 0 THEN 0 ELSE 1 END, sequence, id",
81
+ ).all() as Record<string, unknown>[];
80
82
  const milestones: MilestoneRow[] = rawMilestones.map((r) => ({
81
83
  id: r["id"] as string,
82
84
  title: r["title"] as string,
@@ -95,6 +97,7 @@ export function snapshotState(): StateManifest {
95
97
  definition_of_done: JSON.parse((r["definition_of_done"] as string) || "[]"),
96
98
  requirement_coverage: (r["requirement_coverage"] as string) ?? "",
97
99
  boundary_map_markdown: (r["boundary_map_markdown"] as string) ?? "",
100
+ sequence: Number(r["sequence"] ?? 0),
98
101
  }));
99
102
 
100
103
  const rawSlices = db.prepare("SELECT * FROM slices ORDER BY milestone_id, sequence, id").all() as Record<string, unknown>[];
@@ -29,29 +29,13 @@ function getAuthModeSafe(
29
29
  }
30
30
  }
31
31
 
32
- function hasClaudeCodeProvider(ctx: WorkflowMcpAutoPrepContext): boolean {
33
- return getAuthModeSafe(ctx, "claude-code") === "externalCli";
34
- }
35
-
36
- function isClaudeCodeProviderReady(ctx: WorkflowMcpAutoPrepContext): boolean {
37
- const readyCheck = ctx.modelRegistry?.isProviderRequestReady;
38
- if (typeof readyCheck !== "function") return false;
39
- try {
40
- return readyCheck("claude-code");
41
- } catch {
42
- return false;
43
- }
44
- }
45
-
46
32
  export function shouldAutoPrepareWorkflowMcp(ctx: WorkflowMcpAutoPrepContext): boolean {
47
33
  const provider = ctx.model?.provider;
48
34
  const baseUrl = ctx.model?.baseUrl;
49
35
  const authMode = getAuthModeSafe(ctx, provider);
50
36
 
51
- if (usesWorkflowMcpTransport(authMode as any, baseUrl)) return true;
52
- if (provider === "claude-code") return true;
53
- if (hasClaudeCodeProvider(ctx)) return true;
54
- return isClaudeCodeProviderReady(ctx);
37
+ if (provider !== "claude-code") return false;
38
+ return usesWorkflowMcpTransport(authMode as any, baseUrl) || authMode === "externalCli";
55
39
  }
56
40
 
57
41
  export function prepareWorkflowMcpForProject(
@@ -20,7 +20,7 @@ import {
20
20
  } from "./gsd-db.js";
21
21
  import { isClosedStatus } from "./status-guards.js";
22
22
  import { invalidateStateCache } from "./state.js";
23
- import { clearPathCache } from "./paths.js";
23
+ import { clearPathCache, resolveGsdPathContract } from "./paths.js";
24
24
  import { clearParseCache } from "./files.js";
25
25
  import { writeManifest } from "./workflow-manifest.js";
26
26
  import { atomicWriteSync } from "./atomic-write.js";
@@ -492,7 +492,7 @@ function _reconcileWorktreeLogsInner(
492
492
  atomicWriteSync(join(mainBasePath, ".gsd", "event-log.jsonl"), logContent);
493
493
 
494
494
  // Step 8: Replay into DB (wrapped in a transaction by replayEvents)
495
- openDatabase(join(mainBasePath, ".gsd", "gsd.db"));
495
+ openDatabase(resolveGsdPathContract(mainBasePath).projectDb);
496
496
  replayEvents(merged);
497
497
 
498
498
  // Step 9: Write manifest
@@ -647,7 +647,7 @@ export function resolveConflict(
647
647
  writeEventLog(targetBasePath, targetBaseEvents.concat(rewrittenTargetEvents));
648
648
 
649
649
  // Replay resolved events through the DB (updates DB state)
650
- openDatabase(join(basePath, ".gsd", "gsd.db"));
650
+ openDatabase(resolveGsdPathContract(basePath).projectDb);
651
651
  replayEvents(eventsToReplay);
652
652
  invalidateStateCache();
653
653
  clearPathCache();
@@ -15,7 +15,7 @@ import { loadPrompt } from "./prompt-loader.js";
15
15
  import { autoCommitCurrentBranch, getMainBranch, resolveGitHeadPath, nudgeGitBranchCache } from "./worktree.js";
16
16
  import { runWorktreePostCreateHook } from "./auto-worktree.js";
17
17
  import { showConfirm } from "../shared/tui.js";
18
- import { gsdRoot, milestonesDir } from "./paths.js";
18
+ import { gsdRoot, milestonesDir, resolveGsdPathContract } from "./paths.js";
19
19
  import {
20
20
  createWorktree,
21
21
  listWorktrees,
@@ -651,8 +651,9 @@ async function handleMerge(
651
651
  const commitMessage = `${commitType}: merge worktree ${name}\n\nGSD-Worktree: ${name}`;
652
652
 
653
653
  // Reconcile worktree DB into main DB before squash merge
654
- const wtDbPath = join(worktreePath(basePath, name), ".gsd", "gsd.db");
655
- const mainDbPath = join(basePath, ".gsd", "gsd.db");
654
+ const contract = resolveGsdPathContract(worktreePath(basePath, name), basePath);
655
+ const wtDbPath = join(contract.worktreeGsd ?? join(contract.workRoot, ".gsd"), "gsd.db");
656
+ const mainDbPath = contract.projectDb;
656
657
  if (existsSync(wtDbPath) && existsSync(mainDbPath)) {
657
658
  try {
658
659
  const { reconcileWorktreeDb } = await import("./gsd-db.js");
@@ -1 +0,0 @@
1
- exports.id=8527,exports.ids=[8527],exports.modules={18527:(a,b,c)=>{"use strict";c.d(b,{isOnboardingComplete:()=>l,readOnboardingRecord:()=>k});var d=c(73024),e=c(76760);c(77598);var f=c(16698),g=c(48161);c(31421),process.env.GSD_ENABLE_NATIVE_GSD_PARSER,Symbol("native-unavailable"),new f.AsyncLocalStorage,c(89134),Object.values({Q3:{id:"Q3",scope:"slice",ownerTurn:"gate-evaluate",question:"How can this be exploited?",guidance:"Identify abuse scenarios: parameter tampering, replay attacks, privilege escalation.\nMap data exposure risks: PII, tokens, secrets accessible through this slice.\nDefine input trust boundaries: untrusted user input reaching DB, API, or filesystem.\nIf none apply, return verdict 'omitted' with rationale explaining why.",promptSection:"Abuse Surface"},Q4:{id:"Q4",scope:"slice",ownerTurn:"gate-evaluate",question:"Which existing requirements (R-IDs) does this slice touch, and which must be re-tested?",guidance:"List the R-IDs (e.g. R001, R003) touched by this slice; see the milestone requirements artifact at .gsd/milestones/<id>/REQUIREMENTS.md.\nIdentify what must be re-tested after shipping.\nFlag decisions that should be revisited given the new scope.\nIf no existing requirements are affected, return verdict 'omitted'.",promptSection:"Broken Promises"},Q5:{id:"Q5",scope:"task",ownerTurn:"execute-task",question:"What breaks when dependencies fail?",guidance:"Enumerate the task's external dependencies (APIs, filesystem, network, subprocesses).\nDescribe the failure path for each: timeout, malformed response, connection loss.\nVerify the implementation handles each failure or explicitly bubbles the error.\nReturn verdict 'omitted' only if the task has no external dependencies.",promptSection:"Failure Modes"},Q6:{id:"Q6",scope:"task",ownerTurn:"execute-task",question:"What is the 10x load breakpoint?",guidance:"Identify the resource that saturates first at 10x the expected load.\nDescribe the protection applied (pool sizing, rate limiting, pagination, caching).\nReturn verdict 'omitted' if the task has no runtime load dimension.",promptSection:"Load Profile"},Q7:{id:"Q7",scope:"task",ownerTurn:"execute-task",question:"What negative tests protect this task?",guidance:"List malformed inputs, error paths, and boundary conditions the tests cover.\nPoint to the specific test files or cases that assert each negative scenario.\nReturn verdict 'omitted' only if the task has no meaningful negative surface.",promptSection:"Negative Tests"},Q8:{id:"Q8",scope:"slice",ownerTurn:"complete-slice",question:"How will ops know this slice is healthy or broken?",guidance:"Describe the health signal (metric, log line, dashboard) that proves the slice works.\nDescribe the failure signal that triggers an alert or paging.\nDocument the recovery procedure and any monitoring gaps.\nReturn verdict 'omitted' only for slices with no runtime behavior at all.",promptSection:"Operational Readiness"},MV01:{id:"MV01",scope:"milestone",ownerTurn:"validate-milestone",question:"Is every success criterion in the milestone roadmap satisfied?",guidance:"Walk the success-criteria checklist from the milestone roadmap.\nFor each criterion, point to the slice / assessment / verification evidence that proves it.\nReturn verdict 'flag' if any criterion is unmet or unverifiable.",promptSection:"Success Criteria Checklist"},MV02:{id:"MV02",scope:"milestone",ownerTurn:"validate-milestone",question:"Does every slice have a SUMMARY.md and a passing assessment?",guidance:"Confirm every slice listed in the roadmap has a SUMMARY.md.\nConfirm each slice has an ASSESSMENT verdict of 'pass' (or justified 'omitted').\nFlag missing artifacts and slices with outstanding follow-ups or known limitations.",promptSection:"Slice Delivery Audit"},MV03:{id:"MV03",scope:"milestone",ownerTurn:"validate-milestone",question:"Do the slices integrate end-to-end?",guidance:"Trace at least one cross-slice flow proving the pieces compose.\nFlag gaps where two slices were built in isolation with no integration evidence.",promptSection:"Cross-Slice Integration"},MV04:{id:"MV04",scope:"milestone",ownerTurn:"validate-milestone",question:"Are all touched requirements covered and still coherent?",guidance:"For each requirement advanced, validated, surfaced, or invalidated across the milestone's slices, confirm the milestone-level evidence matches.\nFlag requirements that slices claim to advance but no artifact proves.",promptSection:"Requirement Coverage"}});let h=process.env.GSD_CODING_AGENT_DIR||(0,e.join)(process.env.GSD_HOME?(0,e.resolve)(process.env.GSD_HOME):(0,e.join)((0,g.homedir)(),".gsd"),"agent"),i=(0,e.join)(h,"onboarding.json"),j={version:1,flowVersion:1,completedAt:null,completedSteps:[],skippedSteps:[],lastResumePoint:null};function k(){if(!(0,d.existsSync)(i))return{...j};try{let a=JSON.parse((0,d.readFileSync)(i,"utf-8"));return{version:"number"==typeof a.version?a.version:1,flowVersion:"number"==typeof a.flowVersion?a.flowVersion:0,completedAt:"string"==typeof a.completedAt?a.completedAt:null,completedSteps:Array.isArray(a.completedSteps)?a.completedSteps.filter(a=>"string"==typeof a):[],skippedSteps:Array.isArray(a.skippedSteps)?a.skippedSteps.filter(a=>"string"==typeof a):[],lastResumePoint:"string"==typeof a.lastResumePoint?a.lastResumePoint:null}}catch{return{...j}}}function l(){let a=k();return null!==a.completedAt&&1===a.flowVersion}},65168:a=>{function b(a){var b=Error("Cannot find module '"+a+"'");throw b.code="MODULE_NOT_FOUND",b}b.keys=()=>[],b.resolve=b,b.id=65168,a.exports=b},89134:(a,b,c)=>{"use strict";c.d(b,{DZ:()=>e,rs:()=>d});let d="GSD_GIT_ERROR";class e extends Error{constructor(a,b,c){super(b,c),this.name="GSDError",this.code=a}}}};