@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.74e8dd1

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 (232) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +167 -16
  3. package/dist/resources/extensions/gsd/auto/phases.js +4 -3
  4. package/dist/resources/extensions/gsd/auto-dashboard.js +15 -4
  5. package/dist/resources/extensions/gsd/auto-dispatch.js +39 -0
  6. package/dist/resources/extensions/gsd/auto-post-unit.js +113 -7
  7. package/dist/resources/extensions/gsd/auto-prompts.js +9 -0
  8. package/dist/resources/extensions/gsd/auto-recovery.js +4 -4
  9. package/dist/resources/extensions/gsd/auto-start.js +94 -15
  10. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +2 -1
  11. package/dist/resources/extensions/gsd/auto.js +22 -4
  12. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +79 -0
  13. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
  14. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +30 -9
  15. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
  16. package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
  17. package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
  18. package/dist/resources/extensions/gsd/commands/handlers/ops.js +7 -3
  19. package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
  20. package/dist/resources/extensions/gsd/commands-mcp-status.js +107 -59
  21. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
  22. package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
  23. package/dist/resources/extensions/gsd/config-overlay.js +2 -1
  24. package/dist/resources/extensions/gsd/error-classifier.js +2 -1
  25. package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
  26. package/dist/resources/extensions/gsd/gsd-db.js +37 -4
  27. package/dist/resources/extensions/gsd/guided-flow.js +1 -1
  28. package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
  29. package/dist/resources/extensions/gsd/mcp-project-config.js +67 -8
  30. package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
  31. package/dist/resources/extensions/gsd/prompts/run-uat.md +10 -4
  32. package/dist/resources/extensions/gsd/prompts/system.md +3 -1
  33. package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
  34. package/dist/resources/extensions/gsd/skill-activation.js +20 -3
  35. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
  36. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
  37. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
  38. package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
  39. package/dist/resources/extensions/gsd/state.js +15 -12
  40. package/dist/resources/extensions/gsd/tool-presentation-plan.js +120 -0
  41. package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
  42. package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
  43. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  44. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +366 -3
  45. package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
  46. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  47. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
  48. package/dist/resources/extensions/gsd/workflow-mcp.js +5 -1
  49. package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
  50. package/dist/resources/extensions/mcp-client/manager.js +31 -1
  51. package/dist/web/standalone/.next/BUILD_ID +1 -1
  52. package/dist/web/standalone/.next/app-path-routes-manifest.json +4 -4
  53. package/dist/web/standalone/.next/build-manifest.json +2 -2
  54. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  55. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  56. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  64. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/index.html +1 -1
  72. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app-paths-manifest.json +4 -4
  79. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  80. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  82. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  83. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  84. package/package.json +2 -2
  85. package/packages/cloud-mcp-gateway/package.json +2 -2
  86. package/packages/contracts/dist/workflow.d.ts +14 -0
  87. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  88. package/packages/contracts/dist/workflow.js +16 -0
  89. package/packages/contracts/dist/workflow.js.map +1 -1
  90. package/packages/contracts/package.json +1 -1
  91. package/packages/daemon/package.json +4 -4
  92. package/packages/gsd-agent-core/package.json +5 -5
  93. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  94. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  95. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  96. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  97. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
  98. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  99. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +72 -31
  100. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  101. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
  102. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
  103. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  104. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
  105. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
  106. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
  107. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
  108. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  109. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
  110. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  111. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  112. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
  113. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  114. package/packages/gsd-agent-modes/package.json +7 -7
  115. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  116. package/packages/mcp-server/dist/workflow-tools.js +82 -0
  117. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  118. package/packages/mcp-server/package.json +3 -3
  119. package/packages/native/package.json +1 -1
  120. package/packages/pi-agent-core/package.json +1 -1
  121. package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
  122. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  123. package/packages/pi-ai/dist/image-models.generated.js +15 -0
  124. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  125. package/packages/pi-ai/dist/models.generated.d.ts +338 -17
  126. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  127. package/packages/pi-ai/dist/models.generated.js +412 -112
  128. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  129. package/packages/pi-ai/package.json +1 -1
  130. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  131. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  133. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  134. package/packages/pi-coding-agent/package.json +7 -7
  135. package/packages/pi-tui/dist/terminal.d.ts +1 -0
  136. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  137. package/packages/pi-tui/dist/terminal.js +8 -4
  138. package/packages/pi-tui/dist/terminal.js.map +1 -1
  139. package/packages/pi-tui/package.json +1 -1
  140. package/packages/rpc-client/package.json +2 -2
  141. package/pkg/package.json +1 -1
  142. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
  143. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
  144. package/src/resources/extensions/gsd/auto/phases.ts +5 -3
  145. package/src/resources/extensions/gsd/auto-dashboard.ts +16 -4
  146. package/src/resources/extensions/gsd/auto-dispatch.ts +48 -0
  147. package/src/resources/extensions/gsd/auto-post-unit.ts +138 -7
  148. package/src/resources/extensions/gsd/auto-prompts.ts +9 -0
  149. package/src/resources/extensions/gsd/auto-recovery.ts +4 -4
  150. package/src/resources/extensions/gsd/auto-start.ts +112 -17
  151. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +2 -1
  152. package/src/resources/extensions/gsd/auto.ts +35 -3
  153. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +86 -0
  154. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
  155. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +51 -14
  156. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
  157. package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
  158. package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
  159. package/src/resources/extensions/gsd/commands/handlers/ops.ts +7 -3
  160. package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
  161. package/src/resources/extensions/gsd/commands-mcp-status.ts +134 -57
  162. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
  163. package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
  164. package/src/resources/extensions/gsd/config-overlay.ts +3 -1
  165. package/src/resources/extensions/gsd/error-classifier.ts +2 -1
  166. package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
  167. package/src/resources/extensions/gsd/gsd-db.ts +41 -6
  168. package/src/resources/extensions/gsd/guided-flow.ts +1 -1
  169. package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
  170. package/src/resources/extensions/gsd/mcp-project-config.ts +92 -10
  171. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  172. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  173. package/src/resources/extensions/gsd/prompts/run-uat.md +10 -4
  174. package/src/resources/extensions/gsd/prompts/system.md +3 -1
  175. package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
  176. package/src/resources/extensions/gsd/skill-activation.ts +20 -2
  177. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
  178. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
  179. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
  180. package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
  181. package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
  182. package/src/resources/extensions/gsd/state.ts +16 -12
  183. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +51 -0
  184. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +86 -0
  185. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
  186. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
  187. package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
  188. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
  189. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
  190. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
  191. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
  192. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
  193. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
  194. package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
  195. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
  196. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
  197. package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
  198. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +68 -0
  199. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +177 -0
  200. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
  201. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
  202. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
  203. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -0
  204. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
  205. package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
  206. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +35 -0
  207. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
  208. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
  209. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
  210. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
  211. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
  212. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
  213. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
  214. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
  215. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
  216. package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
  217. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +83 -0
  218. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
  219. package/src/resources/extensions/gsd/tool-presentation-plan.ts +167 -0
  220. package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
  221. package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
  222. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  223. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +440 -2
  224. package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
  225. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  226. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
  227. package/src/resources/extensions/gsd/workflow-mcp.ts +5 -1
  228. package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
  229. package/src/resources/extensions/mcp-client/manager.ts +33 -1
  230. package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
  231. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → eRWf-RI9bzbrwEurm_3uI}/_buildManifest.js +0 -0
  232. /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → eRWf-RI9bzbrwEurm_3uI}/_ssgManifest.js +0 -0
@@ -22,23 +22,31 @@ import { tmpdir } from "node:os";
22
22
 
23
23
  import { loadSkills } from "@gsd/pi-coding-agent";
24
24
  import {
25
- buildResearchSlicePrompt,
25
+ buildCompleteSlicePrompt,
26
26
  buildParallelResearchSlicesPrompt,
27
+ buildResearchSlicePrompt,
27
28
  } from "../auto-prompts.ts";
28
29
 
29
30
  const SKILL_NAME = "testskill";
31
+ const COMPLETE_SLICE_SKILL_NAME = "complete-slice-policies";
30
32
  const SKILL_ACTIVATION_SUBSTRING = `Call Skill({ skill: '${SKILL_NAME}' })`;
33
+ const COMPLETE_SLICE_SKILL_ACTIVATION_SUBSTRING = `Call Skill({ skill: '${COMPLETE_SLICE_SKILL_NAME}' })`;
31
34
 
32
35
  const tmpDirs: string[] = [];
33
36
  let savedCwd: string | undefined;
34
37
 
35
- function setupProjectWithSkill(): string {
38
+ function setupProjectWithSkill(options: {
39
+ skillName?: string;
40
+ preferencesLines?: string[];
41
+ } = {}): string {
42
+ const skillName = options.skillName ?? SKILL_NAME;
36
43
  const base = mkdtempSync(join(tmpdir(), "gsd-worker-skill-int-"));
37
44
  tmpDirs.push(base);
38
45
 
39
46
  // Milestone roadmap — buildResearchSlicePrompt inlines the roadmap excerpt.
40
47
  const milestoneDir = join(base, ".gsd", "milestones", "M001");
41
- mkdirSync(join(milestoneDir, "slices", "S01"), { recursive: true });
48
+ const sliceOneDir = join(milestoneDir, "slices", "S01");
49
+ mkdirSync(join(sliceOneDir, "tasks"), { recursive: true });
42
50
  mkdirSync(join(milestoneDir, "slices", "S02"), { recursive: true });
43
51
  writeFileSync(
44
52
  join(milestoneDir, "M001-ROADMAP.md"),
@@ -55,27 +63,41 @@ function setupProjectWithSkill(): string {
55
63
  ].join("\n"),
56
64
  "utf-8",
57
65
  );
66
+ writeFileSync(
67
+ join(sliceOneDir, "S01-PLAN.md"),
68
+ [
69
+ "# S01: Alpha",
70
+ "",
71
+ "**Goal:** Verify worker x skill prompt plumbing.",
72
+ "**Demo:** Rendered prompts include the skill activation block.",
73
+ "",
74
+ "## Tasks",
75
+ "- [x] **T01: Task** `est:10m`",
76
+ "",
77
+ ].join("\n"),
78
+ "utf-8",
79
+ );
58
80
 
59
81
  // Project preferences — buildSkillActivationBlock picks these up via
60
82
  // loadEffectiveGSDPreferences(), which reads from `${cwd}/.gsd/PREFERENCES.md`.
61
83
  writeFileSync(
62
84
  join(base, ".gsd", "PREFERENCES.md"),
63
- ["---", `always_use_skills:`, ` - ${SKILL_NAME}`, "---", ""].join("\n"),
85
+ ["---", ...(options.preferencesLines ?? [`always_use_skills:`, ` - ${skillName}`]), "---", ""].join("\n"),
64
86
  "utf-8",
65
87
  );
66
88
 
67
89
  // Project-scoped skill — resolveSkillReference scans `${cwd}/.agents/skills/`.
68
- const skillDir = join(base, ".agents", "skills", SKILL_NAME);
90
+ const skillDir = join(base, ".agents", "skills", skillName);
69
91
  mkdirSync(skillDir, { recursive: true });
70
92
  writeFileSync(
71
93
  join(skillDir, "SKILL.md"),
72
94
  [
73
95
  "---",
74
- `name: ${SKILL_NAME}`,
96
+ `name: ${skillName}`,
75
97
  `description: Integration-test skill for worker × skill prompt plumbing.`,
76
98
  "---",
77
99
  "",
78
- `# ${SKILL_NAME}`,
100
+ `# ${skillName}`,
79
101
  "",
80
102
  "Test skill body.",
81
103
  ].join("\n"),
@@ -122,6 +144,31 @@ test("worker prompt (buildResearchSlicePrompt) includes <skill_activation> from
122
144
  );
123
145
  });
124
146
 
147
+ test("complete-slice prompt includes <skill_activation> from unit-specific skill_rules", async () => {
148
+ const base = setupProjectWithSkill({
149
+ skillName: COMPLETE_SLICE_SKILL_NAME,
150
+ preferencesLines: [
151
+ "skill_rules:",
152
+ " - when: complete-slice",
153
+ " use:",
154
+ ` - ${COMPLETE_SLICE_SKILL_NAME}`,
155
+ ],
156
+ });
157
+ savedCwd = process.cwd();
158
+ process.chdir(base);
159
+
160
+ const prompt = await buildCompleteSlicePrompt("M001", "Test Milestone", "S01", "Alpha", base, "minimal");
161
+
162
+ assert.ok(
163
+ prompt.includes("<skill_activation>"),
164
+ "complete-slice prompt should contain a <skill_activation> block",
165
+ );
166
+ assert.ok(
167
+ prompt.includes(COMPLETE_SLICE_SKILL_ACTIVATION_SUBSTRING),
168
+ `complete-slice prompt should reference the skill-rule skill '${COMPLETE_SLICE_SKILL_NAME}'`,
169
+ );
170
+ });
171
+
125
172
  test("subagent dispatch prompt (buildParallelResearchSlicesPrompt) carries <skill_activation> into each embedded per-slice section", async () => {
126
173
  const base = setupProjectWithSkill();
127
174
  savedCwd = process.cwd();
@@ -6,7 +6,7 @@ import { mkdtempSync, mkdirSync, rmSync, readFileSync, existsSync, writeFileSync
6
6
  import { join } from 'node:path';
7
7
  import { tmpdir } from 'node:os';
8
8
 
9
- import { openDatabase, closeDatabase, insertMilestone, insertSlice, getSlice, getSliceTasks, getTask, getGateResults, updateTaskStatus } from '../gsd-db.ts';
9
+ import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask, getSlice, getSliceTasks, getTask, getGateResults, updateTaskStatus } from '../gsd-db.ts';
10
10
  import { handlePlanSlice } from '../tools/plan-slice.ts';
11
11
  import { parsePlan } from '../parsers-legacy.ts';
12
12
  import { parseTaskPlanFile } from '../files.ts';
@@ -265,6 +265,44 @@ test('handlePlanSlice renders plan artifacts under worktree-local .gsd while usi
265
265
  }
266
266
  });
267
267
 
268
+ test('handlePlanSlice preserves completed task closeout state when replanning the same task', async () => {
269
+ const base = makeTmpBase();
270
+ openDatabase(join(base, '.gsd', 'gsd.db'));
271
+
272
+ try {
273
+ seedParentSlice();
274
+ insertTask({
275
+ id: 'T01',
276
+ sliceId: 'S02',
277
+ milestoneId: 'M001',
278
+ title: 'Completed implementation',
279
+ status: 'complete',
280
+ oneLiner: 'Completed implementation',
281
+ narrative: 'Already finished.',
282
+ verificationResult: 'passed',
283
+ fullSummaryMd: '# T01 Summary\n\nAlready finished.\n',
284
+ });
285
+
286
+ const before = getTask('M001', 'S02', 'T01');
287
+ assert.equal(before?.status, 'complete');
288
+ assert.ok(before?.completed_at, 'completed task should have a completion timestamp');
289
+ assert.equal(before?.full_summary_md, '# T01 Summary\n\nAlready finished.\n');
290
+
291
+ const result = await handlePlanSlice(validParams(), base);
292
+ assert.ok(!('error' in result), `unexpected error: ${'error' in result ? result.error : ''}`);
293
+
294
+ const after = getTask('M001', 'S02', 'T01');
295
+ assert.equal(after?.status, 'complete', 'replanning must not reset completed task status to pending');
296
+ assert.equal(after?.completed_at, before?.completed_at, 'replanning must not clear completed_at');
297
+ assert.equal(after?.full_summary_md, before?.full_summary_md, 'replanning must not clear task summary content');
298
+ assert.equal(after?.verification_result, 'passed', 'replanning must not clear closeout verification');
299
+ assert.equal(after?.description, 'Implement the slice planning handler.', 'planning fields should still refresh');
300
+ assert.equal(getTask('M001', 'S02', 'T02')?.status, 'pending', 'new tasks are still inserted as pending');
301
+ } finally {
302
+ cleanup(base);
303
+ }
304
+ });
305
+
268
306
  test('handlePlanSlice advances DB-derived state out of planning immediately', async () => {
269
307
  const base = makeTmpBase();
270
308
  openDatabase(join(base, '.gsd', 'gsd.db'));
@@ -32,6 +32,16 @@ test("run-uat prompt branches on dynamic UAT mode and supports runtime evidence"
32
32
  assert.doesNotMatch(prompt, /uatType:\s*artifact-driven/);
33
33
  });
34
34
 
35
+ test("run-uat prompt lists canonical gsd_uat_exec intent values", () => {
36
+ const prompt = readPrompt("run-uat");
37
+ assert.match(prompt, /`uat-artifact-check`/);
38
+ assert.match(prompt, /`uat-runtime-check`/);
39
+ assert.match(prompt, /`uat-browser-check`/);
40
+ assert.match(prompt, /`uat-service-start`/);
41
+ assert.match(prompt, /`uat-log-inspection`/);
42
+ assert.match(prompt, /do not use `artifact`, `runtime`, or `human-follow-up` as `intent`/i);
43
+ });
44
+
35
45
  test("workflow-start prompt defaults to autonomy instead of per-phase confirmation", () => {
36
46
  const prompt = readPrompt("workflow-start");
37
47
  assert.match(prompt, /Keep moving by default/i);
@@ -17,7 +17,10 @@ import {
17
17
  shouldDeferTransientErrorToCoreRetry,
18
18
  suppressTerminalDeletedWorktreeMessageEnd,
19
19
  } from "../bootstrap/agent-end-recovery.ts";
20
- import { _buildCancelledUnitStopReason } from "../auto/phases.ts";
20
+ import {
21
+ _buildCancelledUnitStopReason,
22
+ _classifyZeroToolProviderMessageForTest,
23
+ } from "../auto/phases.ts";
21
24
  import { autoSession } from "../auto-runtime-state.ts";
22
25
  import { getNextFallbackModel } from "../preferences.ts";
23
26
  // Zero-import module — imported by path rather than through the package
@@ -53,6 +56,20 @@ test("classifyError treats usage-limit phrasing as transient rate-limit (#4373)"
53
56
  assert.equal(result.kind, "rate-limit");
54
57
  });
55
58
 
59
+ test("zero-tool provider classifier treats Claude session-limit wording as transient rate-limit (#371)", () => {
60
+ const result = _classifyZeroToolProviderMessageForTest("Claude Code session limit reached. Limit resets at 5 PM.");
61
+ assert.ok(result, "session-limit wording should be recognized");
62
+ assert.ok(isTransient(result));
63
+ assert.equal(result.kind, "rate-limit");
64
+ });
65
+
66
+ test("zero-tool provider classifier treats weekly limit wording as transient rate-limit (#371)", () => {
67
+ const result = _classifyZeroToolProviderMessageForTest("You've reached your weekly limit. Try again later.");
68
+ assert.ok(result, "weekly limit wording should be recognized");
69
+ assert.ok(isTransient(result));
70
+ assert.equal(result.kind, "rate-limit");
71
+ });
72
+
56
73
  test("classifyError treats extra-usage phrasing as transient rate-limit (#4397)", () => {
57
74
  const result = classifyError("You are out of extra usage. Please wait before retrying.");
58
75
  assert.ok(isTransient(result));
@@ -17,6 +17,10 @@ import { validatePreferences } from "../preferences-validation.ts";
17
17
  import type { ReactiveExecutionState } from "../types.ts";
18
18
  import { parseUnitId } from "../unit-id.ts";
19
19
  import { resolveDispatch } from "../auto-dispatch.ts";
20
+ import {
21
+ _getPlannedKeyFilesForTest,
22
+ _parseReactiveBatchTaskIdsForTest,
23
+ } from "../auto-post-unit.ts";
20
24
 
21
25
  // ─── Preference Validation ────────────────────────────────────────────────
22
26
 
@@ -71,6 +75,38 @@ test("reactive_execution validation warns on unknown keys", () => {
71
75
  assert.ok(result.warnings.some((w) => w.includes("unknown_thing")));
72
76
  });
73
77
 
78
+ test("reactive batch unit ids are parsed and deduped for commit context", () => {
79
+ assert.deepEqual(
80
+ _parseReactiveBatchTaskIdsForTest("M001/S01/reactive+T01,t02,T01"),
81
+ ["T01", "T02"],
82
+ );
83
+ assert.deepEqual(_parseReactiveBatchTaskIdsForTest("M001/S01/T01"), []);
84
+ });
85
+
86
+ test("reactive commit context key files include planned output, files, and key_files once", () => {
87
+ const result = _getPlannedKeyFilesForTest([
88
+ {
89
+ expected_output: ["src/new.ts", "src/shared.ts"],
90
+ files: ["src/input.ts", "src/shared.ts"],
91
+ key_files: ["src/key.ts"],
92
+ },
93
+ {
94
+ expected_output: ["src/new.ts"],
95
+ files: ["src/other.ts"],
96
+ key_files: ["src/key.ts", "src/final.ts"],
97
+ },
98
+ ]);
99
+
100
+ assert.deepEqual(result, [
101
+ "src/new.ts",
102
+ "src/shared.ts",
103
+ "src/input.ts",
104
+ "src/key.ts",
105
+ "src/other.ts",
106
+ "src/final.ts",
107
+ ]);
108
+ });
109
+
74
110
  // ─── Dispatch Rule Matching Logic ─────────────────────────────────────────
75
111
 
76
112
  test("reactive dispatch requires enabled config and multiple ready tasks", async () => {
@@ -10,6 +10,7 @@ import {
10
10
  resetWriteGateState,
11
11
  shouldBlockContextArtifactSave,
12
12
  } from "../bootstrap/write-gate.ts";
13
+ import { classifyCommand } from "../safety/destructive-guard.ts";
13
14
  import { toRoundResultResponse } from "../../remote-questions/manager.ts";
14
15
 
15
16
  function makeTempDir(prefix: string): string {
@@ -35,6 +36,40 @@ async function armDepthGate(
35
36
  }
36
37
  }
37
38
 
39
+ test("destructive guard classifies infrastructure mutation commands", () => {
40
+ assert.deepEqual(classifyCommand("terraform destroy -auto-approve").labels, ["IaC apply/destroy"]);
41
+ assert.deepEqual(classifyCommand("terragrunt apply").labels, ["IaC apply/destroy"]);
42
+ assert.deepEqual(classifyCommand("aws s3 delete-bucket --bucket example").labels, ["AWS mutation"]);
43
+ assert.deepEqual(classifyCommand("kubectl delete namespace prod").labels, ["kubectl mutation"]);
44
+ });
45
+
46
+ test("register-hooks hard-blocks destructive bash commands outside auto-mode", async () => {
47
+ const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
48
+ const pi = {
49
+ on(event: string, handler: (event: any, ctx?: any) => Promise<any> | any) {
50
+ const existing = handlers.get(event) ?? [];
51
+ existing.push(handler);
52
+ handlers.set(event, existing);
53
+ },
54
+ } as any;
55
+
56
+ registerHooks(pi, []);
57
+
58
+ let block: any;
59
+ for (const handler of handlers.get("tool_call") ?? []) {
60
+ const result = await handler({
61
+ toolCallId: "call-1",
62
+ toolName: "bash",
63
+ input: { command: "terraform apply -auto-approve" },
64
+ });
65
+ if (result?.block) block = result;
66
+ }
67
+
68
+ assert.equal(block?.block, true);
69
+ assert.match(block?.reason ?? "", /HARD BLOCK: destructive Bash command requires explicit human confirmation/);
70
+ assert.match(block?.reason ?? "", /IaC apply\/destroy/);
71
+ });
72
+
38
73
  test("register-hooks unlocks milestone depth verification from question id without guided-flow state (#4047)", async (t) => {
39
74
  const dir = makeTempDir("manual");
40
75
  const originalCwd = process.cwd();
@@ -51,7 +51,7 @@ test("discuss workflow scopes tools for the queued turn and restores the full to
51
51
  // discuss allowlist: gsd_summary_save and gsd_plan_milestone (the latter
52
52
  // is needed for the discuss.md output phase — see DISCUSS_TOOLS_ALLOWLIST).
53
53
  // gsd_task_complete and the broad shell_exec tool are scoped out.
54
- assert.deepEqual(sentTools, ["gsd_summary_save", "gsd_plan_milestone", "ToolSearch"]);
54
+ assert.deepEqual(sentTools, ["gsd_plan_milestone", "gsd_summary_save", "ToolSearch"]);
55
55
  assert.deepEqual(activeTools, originalTools);
56
56
  assert.equal(triggerTurn, true);
57
57
  } finally {
@@ -5,6 +5,7 @@ import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { loadSkills } from "@gsd/pi-coding-agent";
7
7
  import {
8
+ buildCompleteSlicePrompt,
8
9
  buildPlanMilestonePrompt,
9
10
  buildResearchMilestonePrompt,
10
11
  buildSkillActivationBlock,
@@ -143,6 +144,29 @@ test("buildSkillActivationBlock includes skill_rules matches and task-plan skill
143
144
  }
144
145
  });
145
146
 
147
+ test("buildSkillActivationBlock matches skill_rules against exact unit type context", () => {
148
+ const base = makeTempBase();
149
+ try {
150
+ writeSkill(base, "complete-slice-policies", "Use for complete-slice closeout policy checks.");
151
+ writeSkill(base, "slice-broad", "Use for broad slice work.");
152
+ loadOnlyTestSkills(base);
153
+
154
+ const result = buildBlock(base, {
155
+ unitType: "complete-slice",
156
+ }, {
157
+ skill_rules: [
158
+ { when: "complete-slice", use: ["complete-slice-policies"] },
159
+ { when: "slice", use: ["slice-broad"] },
160
+ ],
161
+ });
162
+
163
+ assert.match(result, /Call Skill\(\{ skill: 'complete-slice-policies' \}\)/);
164
+ assert.doesNotMatch(result, /slice-broad/);
165
+ } finally {
166
+ cleanup(base);
167
+ }
168
+ });
169
+
146
170
  test("buildSkillActivationBlock honors avoid_skills against always_use_skills", () => {
147
171
  const base = makeTempBase();
148
172
  try {
@@ -328,6 +352,37 @@ test("milestone prompt builders propagate always_use_skills through buildSkillAc
328
352
  }
329
353
  });
330
354
 
355
+ test("complete-slice prompt propagates always_use_skills through buildSkillActivationBlock", async () => {
356
+ const base = makeTempBase();
357
+ try {
358
+ writeSkill(base, "write-docs", "Use when writing docs or RFCs.");
359
+ writeProjectPreferences(base, "always_use_skills:\n - write-docs\n");
360
+ loadOnlyTestSkills(base);
361
+
362
+ const milestoneDir = join(base, ".gsd", "milestones", "M001");
363
+ const sliceDir = join(milestoneDir, "slices", "S01");
364
+ mkdirSync(sliceDir, { recursive: true });
365
+ writeFileSync(
366
+ join(milestoneDir, "M001-ROADMAP.md"),
367
+ [
368
+ "# M001: Test",
369
+ "",
370
+ "## Slices",
371
+ "",
372
+ "- [ ] **S01: Slice** `risk:low` `depends:[]`",
373
+ "",
374
+ ].join("\n"),
375
+ );
376
+ writeFileSync(join(sliceDir, "S01-PLAN.md"), "# S01: Slice\n\n## Tasks\n\n- [x] **T01: Done**\n");
377
+
378
+ const prompt = await buildCompleteSlicePrompt("M001", "Test", "S01", "Slice", base);
379
+
380
+ assert.match(prompt, /Call Skill\(\{ skill: 'write-docs' \}\)/);
381
+ } finally {
382
+ cleanup(base);
383
+ }
384
+ });
385
+
331
386
  test("skill manifest strict warnings require GSD_SKILL_MANIFEST_STRICT=1", (t) => {
332
387
  const previousStrict = process.env.GSD_SKILL_MANIFEST_STRICT;
333
388
  const previousStderr = setStderrLoggingEnabled(false);
@@ -148,6 +148,7 @@ test("fresh start registers the auto worker before bootstrap enters worktree flo
148
148
  const freshStartSectionIdx = startAutoBody.indexOf("// ── Fresh start path — delegated to auto-start.ts ──");
149
149
  const resumeBody = startAutoBody.slice(resumeSectionIdx, freshStartSectionIdx);
150
150
  const resumeDbOpenIdx = resumeBody.indexOf("await openProjectDbIfPresent(base);");
151
+ const resumeMergeReconcileIdx = resumeBody.indexOf("reconcileMergedMilestonesFromJournal(base);");
151
152
  const resumeRegisterIdx = resumeBody.indexOf("registerAutoWorkerForSession(s, base);");
152
153
  const resumeEnterMilestoneIdx = resumeBody.indexOf("buildLifecycle().enterMilestone");
153
154
  const dbOpenIdx = bootstrapBody.indexOf("await openProjectDbIfPresent(base);");
@@ -164,6 +165,7 @@ test("fresh start registers the auto worker before bootstrap enters worktree flo
164
165
  assert.ok(resumeSectionIdx > -1, "startAuto should have resume milestone entry flow");
165
166
  assert.ok(freshStartSectionIdx > resumeSectionIdx, "resume assertions should be scoped before fresh start");
166
167
  assert.ok(resumeDbOpenIdx > -1, "resume should open DB before milestone entry");
168
+ assert.ok(resumeMergeReconcileIdx > -1, "resume should reconcile merged milestones before deriving dispatch state");
167
169
  assert.ok(resumeRegisterIdx > -1, "resume should register worker before milestone entry");
168
170
  assert.ok(resumeEnterMilestoneIdx > -1, "resume should enter milestones through lifecycle");
169
171
  assert.ok(bootstrapIdx > -1, "bootstrapAutoSession should exist");
@@ -179,8 +181,10 @@ test("fresh start registers the auto worker before bootstrap enters worktree flo
179
181
  "bootstrap must open DB and register worker before first enterMilestone",
180
182
  );
181
183
  assert.ok(
182
- resumeDbOpenIdx < resumeRegisterIdx && resumeRegisterIdx < resumeEnterMilestoneIdx,
183
- "resume must open DB and register worker before first enterMilestone",
184
+ resumeDbOpenIdx < resumeMergeReconcileIdx &&
185
+ resumeMergeReconcileIdx < resumeRegisterIdx &&
186
+ resumeRegisterIdx < resumeEnterMilestoneIdx,
187
+ "resume must open DB, reconcile merged milestones, and register worker before first enterMilestone",
184
188
  );
185
189
  });
186
190
 
@@ -906,6 +906,51 @@ test("ADR-017 (#5704): registered milestone (DB row present) → no drift", asyn
906
906
 
907
907
  // ─── #5705: roadmap-divergence drift ─────────────────────────────────────────
908
908
 
909
+ test("ADR-017 (#391): roadmap-divergence skips slices before task planning completes", async (t) => {
910
+ const base = mkdtempSync(join(tmpdir(), "gsd-adr017-roadmap-unplanned-"));
911
+ const milestoneDir = join(base, ".gsd", "milestones", "M001");
912
+ const roadmapPath = join(milestoneDir, "M001-ROADMAP.md");
913
+ mkdirSync(milestoneDir, { recursive: true });
914
+ const originalRoadmap = [
915
+ "# M001: Test",
916
+ "",
917
+ "**Vision:** Verify transient milestone planning state",
918
+ "",
919
+ "## Slices",
920
+ "",
921
+ "- [ ] **S01: Foundation** `risk:medium` `depends:[]`",
922
+ "- [ ] **S02: Feature** `risk:medium` `depends:[S01]`",
923
+ "",
924
+ ].join("\n");
925
+ writeFileSync(roadmapPath, originalRoadmap);
926
+ t.after(() => {
927
+ try { closeDatabase(); } catch { /* noop */ }
928
+ rmSync(base, { recursive: true, force: true });
929
+ });
930
+
931
+ openDatabase(join(base, ".gsd", "gsd.db"));
932
+ insertMilestone({ id: "M001", title: "Test", status: "active" });
933
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Foundation", status: "pending", risk: "medium", depends: [], demo: "", sequence: 1 });
934
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Feature", status: "pending", risk: "medium", depends: [], demo: "", sequence: 2 });
935
+
936
+ assert.equal(getSliceTasks("M001", "S01").length, 0, "pre: S01 has not been planned");
937
+ assert.equal(getSliceTasks("M001", "S02").length, 0, "pre: S02 has not been planned");
938
+
939
+ const result = await reconcileBeforeDispatch(base, {
940
+ invalidateStateCache: () => {},
941
+ deriveState: async () => makeState(),
942
+ });
943
+
944
+ assert.equal(result.ok, true);
945
+ assert.equal(
946
+ result.repaired.some((d) => d.kind === "roadmap-divergence"),
947
+ false,
948
+ "unplanned slices should not trigger roadmap-divergence repair",
949
+ );
950
+ assert.equal(readFileSync(roadmapPath, "utf-8"), originalRoadmap);
951
+ assert.deepEqual(getSlice("M001", "S02")?.depends, [], "DB remains unchanged");
952
+ });
953
+
909
954
  test("ADR-017 (#5705): roadmap-divergence re-renders projection without syncing depends into DB", async (t) => {
910
955
  const base = mkdtempSync(join(tmpdir(), "gsd-adr017-roadmap-"));
911
956
  const milestoneDir = join(base, ".gsd", "milestones", "M001");
@@ -936,6 +981,8 @@ test("ADR-017 (#5705): roadmap-divergence re-renders projection without syncing
936
981
  // Seed DB with S02 depending on [] — diverges from ROADMAP.md
937
982
  insertSlice({ id: "S01", milestoneId: "M001", title: "Foundation", status: "pending", risk: "medium", depends: [], demo: "", sequence: 1 });
938
983
  insertSlice({ id: "S02", milestoneId: "M001", title: "Feature", status: "pending", risk: "medium", depends: [], demo: "", sequence: 2 });
984
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Plan S01", status: "pending" });
985
+ insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", title: "Plan S02", status: "pending" });
939
986
 
940
987
  assert.deepEqual(getSlice("M001", "S02")?.depends, [], "pre: DB has S02.depends = []");
941
988
 
@@ -987,6 +1034,7 @@ test("ADR-017 (#5705): ROADMAP-only slice is removed from projection and not ins
987
1034
  insertMilestone({ id: "M001", title: "Test", status: "active" });
988
1035
  // Only insert S01 — S02 is intentionally absent from the DB.
989
1036
  insertSlice({ id: "S01", milestoneId: "M001", title: "Foundation", status: "pending", risk: "medium", depends: [], demo: "", sequence: 1 });
1037
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Plan S01", status: "pending" });
990
1038
 
991
1039
  assert.equal(getSlice("M001", "S02"), null, "pre: S02 has no DB row");
992
1040
 
@@ -1035,6 +1083,8 @@ test("ADR-017 (#5705): ROADMAP sequence drift re-renders from DB order without m
1035
1083
  insertMilestone({ id: "M001", title: "Test", status: "active" });
1036
1084
  insertSlice({ id: "S01", milestoneId: "M001", title: "Foundation", status: "pending", risk: "medium", depends: [], demo: "", sequence: 1 });
1037
1085
  insertSlice({ id: "S02", milestoneId: "M001", title: "Feature", status: "pending", risk: "medium", depends: [], demo: "", sequence: 2 });
1086
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Plan S01", status: "pending" });
1087
+ insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", title: "Plan S02", status: "pending" });
1038
1088
 
1039
1089
  const result = await reconcileBeforeDispatch(base, {
1040
1090
  invalidateStateCache: () => {},
@@ -1078,6 +1128,7 @@ test("ADR-017 (#5705): ROADMAP checkbox drift re-renders from DB status without
1078
1128
  openDatabase(join(base, ".gsd", "gsd.db"));
1079
1129
  insertMilestone({ id: "M001", title: "Test", status: "active" });
1080
1130
  insertSlice({ id: "S01", milestoneId: "M001", title: "Foundation", status: "pending", risk: "medium", depends: [], demo: "", sequence: 1 });
1131
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Plan S01", status: "pending" });
1081
1132
 
1082
1133
  const result = await reconcileBeforeDispatch(base, {
1083
1134
  invalidateStateCache: () => {},
@@ -1119,6 +1170,7 @@ test("ADR-017 (#5705): in-sync ROADMAP and DB → no roadmap-divergence drift",
1119
1170
  openDatabase(join(base, ".gsd", "gsd.db"));
1120
1171
  insertMilestone({ id: "M001", title: "Test", status: "active" });
1121
1172
  insertSlice({ id: "S01", milestoneId: "M001", title: "Foundation", status: "pending", risk: "low", depends: [], demo: "", sequence: 1 });
1173
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Plan S01", status: "pending" });
1122
1174
 
1123
1175
  const result = await reconcileBeforeDispatch(base, {
1124
1176
  invalidateStateCache: () => {},