@opengsd/gsd-pi 1.1.1-dev.9f86580 → 1.1.1-dev.b2556262

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 (261) hide show
  1. package/dist/headless-recover.js +56 -1
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/browser-tools/index.js +39 -22
  4. package/dist/resources/extensions/browser-tools/state.js +12 -0
  5. package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
  6. package/dist/resources/extensions/browser-tools/utils.js +3 -3
  7. package/dist/resources/extensions/gsd/auto/loop.js +4 -2
  8. package/dist/resources/extensions/gsd/auto/phases.js +43 -10
  9. package/dist/resources/extensions/gsd/auto/session.js +20 -1
  10. package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +72 -12
  12. package/dist/resources/extensions/gsd/auto-model-selection.js +128 -9
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
  14. package/dist/resources/extensions/gsd/auto-prompts.js +24 -19
  15. package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
  16. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  17. package/dist/resources/extensions/gsd/auto-start.js +1 -1
  18. package/dist/resources/extensions/gsd/auto.js +14 -11
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
  20. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +172 -65
  21. package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
  22. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
  23. package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
  24. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
  25. package/dist/resources/extensions/gsd/db-writer.js +35 -0
  26. package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
  27. package/dist/resources/extensions/gsd/gsd-db.js +480 -172
  28. package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
  29. package/dist/resources/extensions/gsd/md-importer.js +38 -3
  30. package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
  31. package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
  32. package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
  33. package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
  34. package/dist/resources/extensions/gsd/preferences-models.js +110 -43
  35. package/dist/resources/extensions/gsd/preferences-types.js +13 -0
  36. package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
  37. package/dist/resources/extensions/gsd/preferences.js +4 -1
  38. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  39. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  40. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  41. package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
  42. package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
  43. package/dist/resources/extensions/gsd/source-observations.js +306 -0
  44. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
  45. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
  46. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
  47. package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
  48. package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
  49. package/dist/resources/extensions/gsd/state.js +7 -3
  50. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  51. package/dist/resources/extensions/gsd/tool-presentation-plan.js +1 -9
  52. package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -6
  53. package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
  54. package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
  55. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +57 -429
  56. package/dist/resources/extensions/gsd/uat-policy.js +130 -0
  57. package/dist/resources/extensions/gsd/uat-run.js +414 -0
  58. package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
  59. package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
  60. package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
  61. package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
  62. package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
  63. package/dist/resources/extensions/subagent/agents.js +1 -0
  64. package/dist/resources/extensions/subagent/index.js +27 -12
  65. package/dist/resources/extensions/subagent/launch.js +7 -2
  66. package/dist/web/standalone/.next/BUILD_ID +1 -1
  67. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  68. package/dist/web/standalone/.next/build-manifest.json +2 -2
  69. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  70. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/index.html +1 -1
  87. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  94. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  95. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  97. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  98. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  99. package/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
  100. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  101. package/package.json +4 -4
  102. package/packages/cloud-mcp-gateway/package.json +2 -2
  103. package/packages/contracts/package.json +1 -1
  104. package/packages/daemon/package.json +4 -4
  105. package/packages/gsd-agent-core/package.json +5 -5
  106. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  107. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
  108. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
  109. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
  110. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  111. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -0
  112. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  113. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
  114. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  115. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
  116. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  117. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  118. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
  119. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  120. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  121. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
  122. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  123. package/packages/gsd-agent-modes/package.json +7 -7
  124. package/packages/mcp-server/dist/workflow-tools.js +1 -1
  125. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  126. package/packages/mcp-server/package.json +3 -3
  127. package/packages/native/dist/native.js +22 -0
  128. package/packages/native/package.json +1 -1
  129. package/packages/pi-agent-core/package.json +1 -1
  130. package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
  131. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  132. package/packages/pi-ai/dist/image-models.generated.js +30 -0
  133. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  134. package/packages/pi-ai/dist/models.generated.d.ts +23 -17
  135. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  136. package/packages/pi-ai/dist/models.generated.js +25 -24
  137. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  138. package/packages/pi-ai/package.json +1 -1
  139. package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
  140. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  141. package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
  142. package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
  143. package/packages/pi-coding-agent/package.json +7 -7
  144. package/packages/pi-tui/dist/utils.d.ts +11 -0
  145. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  146. package/packages/pi-tui/dist/utils.js +119 -6
  147. package/packages/pi-tui/dist/utils.js.map +1 -1
  148. package/packages/pi-tui/package.json +2 -1
  149. package/packages/rpc-client/package.json +2 -2
  150. package/pkg/dist/theme/themes.js +1 -1
  151. package/pkg/dist/theme/themes.js.map +1 -1
  152. package/pkg/package.json +1 -1
  153. package/src/resources/extensions/browser-tools/index.ts +39 -22
  154. package/src/resources/extensions/browser-tools/state.ts +13 -0
  155. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
  156. package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
  157. package/src/resources/extensions/browser-tools/utils.ts +3 -3
  158. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  159. package/src/resources/extensions/gsd/auto/loop.ts +4 -2
  160. package/src/resources/extensions/gsd/auto/phases.ts +42 -10
  161. package/src/resources/extensions/gsd/auto/session.ts +22 -1
  162. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
  163. package/src/resources/extensions/gsd/auto-dispatch.ts +85 -12
  164. package/src/resources/extensions/gsd/auto-model-selection.ts +164 -12
  165. package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
  166. package/src/resources/extensions/gsd/auto-prompts.ts +23 -20
  167. package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
  168. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  169. package/src/resources/extensions/gsd/auto-start.ts +1 -1
  170. package/src/resources/extensions/gsd/auto.ts +13 -10
  171. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
  172. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +225 -72
  173. package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
  174. package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
  175. package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
  176. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
  177. package/src/resources/extensions/gsd/db-writer.ts +38 -0
  178. package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
  179. package/src/resources/extensions/gsd/gsd-db.ts +564 -186
  180. package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
  181. package/src/resources/extensions/gsd/md-importer.ts +49 -2
  182. package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
  183. package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
  184. package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
  185. package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
  186. package/src/resources/extensions/gsd/preferences-models.ts +112 -43
  187. package/src/resources/extensions/gsd/preferences-types.ts +39 -0
  188. package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
  189. package/src/resources/extensions/gsd/preferences.ts +5 -0
  190. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
  191. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  192. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  193. package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
  194. package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
  195. package/src/resources/extensions/gsd/source-observations.ts +402 -0
  196. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
  197. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
  198. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
  199. package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
  200. package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
  201. package/src/resources/extensions/gsd/state.ts +7 -4
  202. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +15 -0
  203. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
  204. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
  205. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
  206. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
  207. package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
  208. package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
  209. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
  210. package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
  211. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +16 -2
  212. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
  213. package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
  214. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
  215. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
  216. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +15 -0
  217. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
  218. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
  219. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
  220. package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
  221. package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
  222. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
  223. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +9 -0
  224. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
  225. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
  226. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +8 -0
  227. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
  228. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
  229. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
  230. package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
  231. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
  232. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
  233. package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
  234. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
  235. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
  236. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
  237. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
  238. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +73 -6
  239. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
  240. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
  241. package/src/resources/extensions/gsd/tool-contract.ts +28 -0
  242. package/src/resources/extensions/gsd/tool-presentation-plan.ts +1 -11
  243. package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -6
  244. package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
  245. package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
  246. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +66 -526
  247. package/src/resources/extensions/gsd/types.ts +1 -0
  248. package/src/resources/extensions/gsd/uat-policy.ts +191 -0
  249. package/src/resources/extensions/gsd/uat-run.ts +550 -0
  250. package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
  251. package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
  252. package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
  253. package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
  254. package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
  255. package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
  256. package/src/resources/extensions/subagent/agents.ts +4 -0
  257. package/src/resources/extensions/subagent/index.ts +28 -3
  258. package/src/resources/extensions/subagent/launch.ts +8 -0
  259. package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
  260. /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
  261. /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
@@ -9,9 +9,17 @@ import * as os from 'node:os';
9
9
  import {
10
10
  openDatabase,
11
11
  closeDatabase,
12
+ insertRequirement,
13
+ insertArtifact,
12
14
  insertMilestone,
13
15
  insertSlice,
14
16
  insertTask,
17
+ insertMemoryRow,
18
+ insertAssessment,
19
+ insertGateRow,
20
+ insertReplanHistory,
21
+ recordMilestoneCommitAttribution,
22
+ saveGateResult,
15
23
  _getAdapter,
16
24
  } from '../gsd-db.ts';
17
25
  import {
@@ -20,6 +28,7 @@ import {
20
28
  snapshotState,
21
29
  bootstrapFromManifest,
22
30
  } from '../workflow-manifest.ts';
31
+ import { getAllDecisionsFromMemories } from '../context-store.ts';
23
32
 
24
33
  function tempDir(): string {
25
34
  return fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-manifest-'));
@@ -33,6 +42,33 @@ function cleanupDir(dirPath: string): void {
33
42
  try { fs.rmSync(dirPath, { recursive: true, force: true }); } catch { /* best effort */ }
34
43
  }
35
44
 
45
+ function insertMemoryBackedDecision(id: string): void {
46
+ const now = '2026-01-01T00:00:00.000Z';
47
+ insertMemoryRow({
48
+ id: `MEM-${id}`,
49
+ category: 'architecture',
50
+ content: `Decision ${id} content`,
51
+ confidence: 0.85,
52
+ sourceUnitType: null,
53
+ sourceUnitId: null,
54
+ createdAt: now,
55
+ updatedAt: now,
56
+ scope: 'project',
57
+ tags: [],
58
+ structuredFields: {
59
+ sourceDecisionId: id,
60
+ when_context: 'M001',
61
+ scope: 'architecture',
62
+ decision: `Decision ${id}`,
63
+ choice: `Choice ${id}`,
64
+ rationale: `Rationale ${id}`,
65
+ made_by: 'agent',
66
+ revisable: 'Yes',
67
+ superseded_by: null,
68
+ },
69
+ });
70
+ }
71
+
36
72
  // ─── readManifest: no file ────────────────────────────────────────────────
37
73
 
38
74
  test('workflow-manifest: readManifest returns null when file does not exist', () => {
@@ -75,6 +111,12 @@ test('workflow-manifest: readManifest parses manifest written by writeManifest',
75
111
  assert.ok(Array.isArray(manifest!.slices));
76
112
  assert.ok(Array.isArray(manifest!.tasks));
77
113
  assert.ok(Array.isArray(manifest!.decisions));
114
+ assert.ok(Array.isArray(manifest!.requirements));
115
+ assert.ok(Array.isArray(manifest!.artifacts));
116
+ assert.ok(Array.isArray(manifest!.replan_history));
117
+ assert.ok(Array.isArray(manifest!.assessments));
118
+ assert.ok(Array.isArray(manifest!.quality_gates));
119
+ assert.ok(Array.isArray(manifest!.milestone_commit_attributions));
78
120
  assert.ok(Array.isArray(manifest!.verification_evidence));
79
121
  } finally {
80
122
  closeDatabase();
@@ -120,6 +162,136 @@ test('workflow-manifest: snapshotState captures tasks', () => {
120
162
  }
121
163
  });
122
164
 
165
+ test('workflow-manifest: snapshotState captures memory-backed decisions', () => {
166
+ const base = tempDir();
167
+ openDatabase(tempDbPath(base));
168
+ try {
169
+ insertMemoryBackedDecision('D900');
170
+
171
+ const snap = snapshotState();
172
+ const decision = snap.decisions.find((r) => r.id === 'D900');
173
+
174
+ assert.ok(decision !== undefined, 'D900 should appear in manifest decisions');
175
+ assert.strictEqual(decision!.decision, 'Decision D900');
176
+ assert.strictEqual(decision!.choice, 'Choice D900');
177
+ assert.strictEqual(decision!.rationale, 'Rationale D900');
178
+ } finally {
179
+ closeDatabase();
180
+ cleanupDir(base);
181
+ }
182
+ });
183
+
184
+ test('workflow-manifest: bootstrapFromManifest restores extended correctness rows', () => {
185
+ const base = tempDir();
186
+ openDatabase(tempDbPath(base));
187
+ try {
188
+ insertRequirement({
189
+ id: 'R100',
190
+ class: 'functional',
191
+ status: 'active',
192
+ description: 'Persist requirements',
193
+ why: 'Recovery needs requirements',
194
+ source: 'test',
195
+ primary_owner: 'S01',
196
+ supporting_slices: 'S00',
197
+ validation: 'manifest round-trip',
198
+ notes: 'important',
199
+ full_content: 'Full requirement content',
200
+ superseded_by: null,
201
+ });
202
+ insertArtifact({
203
+ path: '.gsd/milestones/M001/M001-VALIDATION.md',
204
+ artifact_type: 'VALIDATION',
205
+ milestone_id: 'M001',
206
+ slice_id: null,
207
+ task_id: null,
208
+ full_content: '# Validation\n\nPASS',
209
+ });
210
+ insertArtifact({
211
+ path: 'milestones/M001/slices/S01/S01-ASSESSMENT.md',
212
+ artifact_type: 'ASSESSMENT',
213
+ milestone_id: 'M001',
214
+ slice_id: 'S01',
215
+ task_id: null,
216
+ full_content: '# Assessment\n\nPASS',
217
+ });
218
+ insertMilestone({ id: 'M001', title: 'Tracked Milestone' });
219
+ insertSlice({ id: 'S00', milestoneId: 'M001', title: 'Dependency Slice' });
220
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Dependent Slice', depends: ['S00'] });
221
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Tracked Task' });
222
+ insertAssessment({
223
+ path: '.gsd/milestones/M001/slices/S01/S01-ASSESSMENT.md',
224
+ milestoneId: 'M001',
225
+ sliceId: 'S01',
226
+ taskId: null,
227
+ status: 'pass',
228
+ scope: 'run-uat',
229
+ fullContent: '# UAT\n\nPASS',
230
+ });
231
+ insertReplanHistory({
232
+ milestoneId: 'M001',
233
+ sliceId: 'S01',
234
+ taskId: 'T01',
235
+ summary: 'Replan preserved',
236
+ previousArtifactPath: 'old.md',
237
+ replacementArtifactPath: 'new.md',
238
+ });
239
+ insertGateRow({ milestoneId: 'M001', sliceId: 'S01', gateId: 'Q3', scope: 'slice' });
240
+ saveGateResult({
241
+ milestoneId: 'M001',
242
+ sliceId: 'S01',
243
+ gateId: 'Q3',
244
+ verdict: 'pass',
245
+ rationale: 'Gate passed',
246
+ findings: 'No findings',
247
+ });
248
+ recordMilestoneCommitAttribution({
249
+ commitSha: 'abc123',
250
+ milestoneId: 'M001',
251
+ sliceId: 'S01',
252
+ taskId: 'T01',
253
+ source: 'recorded',
254
+ confidence: 0.95,
255
+ files: ['src/example.ts'],
256
+ createdAt: '2026-06-05T00:00:00.000Z',
257
+ });
258
+
259
+ writeManifest(base);
260
+ closeDatabase();
261
+
262
+ const newDbPath = path.join(base, 'new.db');
263
+ openDatabase(newDbPath);
264
+ const restored = bootstrapFromManifest(base);
265
+ assert.strictEqual(restored, true);
266
+
267
+ const snap = snapshotState();
268
+ assert.strictEqual(snap.requirements?.find((r) => r.id === 'R100')?.full_content, 'Full requirement content');
269
+ const artifact = snap.artifacts?.find((r) => r.path === '.gsd/milestones/M001/M001-VALIDATION.md');
270
+ assert.strictEqual(artifact?.full_content, '# Validation\n\nPASS');
271
+ assert.ok(artifact?.content_hash, 'artifact content_hash should round-trip through manifest restore');
272
+ assert.strictEqual(
273
+ fs.readFileSync(path.join(base, '.gsd', 'milestones', 'M001', 'M001-VALIDATION.md'), 'utf-8'),
274
+ '# Validation\n\nPASS',
275
+ );
276
+ assert.strictEqual(
277
+ fs.readFileSync(path.join(base, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'S01-ASSESSMENT.md'), 'utf-8'),
278
+ '# Assessment\n\nPASS',
279
+ );
280
+ assert.strictEqual(snap.assessments?.find((r) => r.scope === 'run-uat')?.status, 'pass');
281
+ assert.strictEqual(snap.replan_history?.find((r) => r.summary === 'Replan preserved')?.replacement_artifact_path, 'new.md');
282
+ assert.strictEqual(snap.quality_gates?.find((r) => r.gate_id === 'Q3')?.rationale, 'Gate passed');
283
+ assert.strictEqual(snap.milestone_commit_attributions?.find((r) => r.commit_sha === 'abc123')?.files_json, '["src/example.ts"]');
284
+
285
+ const dep = _getAdapter()!.prepare(
286
+ 'SELECT depends_on_slice_id FROM slice_dependencies WHERE milestone_id = ? AND slice_id = ?',
287
+ ).get('M001', 'S01') as Record<string, unknown> | undefined;
288
+ assert.strictEqual(dep?.['depends_on_slice_id'], 'S00');
289
+ } finally {
290
+ closeDatabase();
291
+ cleanupDir(base);
292
+ }
293
+ });
294
+
123
295
  // ─── bootstrapFromManifest ────────────────────────────────────────────────
124
296
 
125
297
  test('workflow-manifest: bootstrapFromManifest returns false when no manifest file', () => {
@@ -152,7 +324,7 @@ test('workflow-manifest: bootstrapFromManifest restores DB from manifest (round-
152
324
  milestoneId: 'M001',
153
325
  title: 'Restored Task',
154
326
  status: 'complete',
155
- planning: { targetRepositories: ['project'] },
327
+ planning: { fullPlanMd: '# Full Task Plan\n\nKeep this body.', targetRepositories: ['project'] },
156
328
  });
157
329
  writeManifest(base);
158
330
  closeDatabase();
@@ -176,6 +348,7 @@ test('workflow-manifest: bootstrapFromManifest restores DB from manifest (round-
176
348
  const t = snap.tasks.find((r) => r.id === 'T01');
177
349
  assert.ok(t !== undefined, 'T01 should be restored');
178
350
  assert.strictEqual(t!.status, 'complete');
351
+ assert.strictEqual(t!.full_plan_md, '# Full Task Plan\n\nKeep this body.');
179
352
  assert.deepEqual(t!.target_repositories, ['project']);
180
353
  } finally {
181
354
  closeDatabase();
@@ -207,6 +380,138 @@ test('workflow-manifest: bootstrapFromManifest preserves target_repositories', (
207
380
  }
208
381
  });
209
382
 
383
+ test('workflow-manifest: bootstrapFromManifest preserves optional rows from old manifests', () => {
384
+ const base = tempDir();
385
+ openDatabase(tempDbPath(base));
386
+ try {
387
+ insertMilestone({ id: 'M001', title: 'Old Manifest Milestone' });
388
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Old Manifest Slice' });
389
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Old Manifest Task' });
390
+ writeManifest(base);
391
+
392
+ const manifestPath = path.join(base, '.gsd', 'state-manifest.json');
393
+ const oldManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as Record<string, unknown>;
394
+ delete oldManifest['replan_history'];
395
+ delete oldManifest['assessments'];
396
+ delete oldManifest['quality_gates'];
397
+ delete oldManifest['milestone_commit_attributions'];
398
+ fs.writeFileSync(manifestPath, JSON.stringify(oldManifest, null, 2));
399
+ closeDatabase();
400
+
401
+ const newDbPath = path.join(base, 'new.db');
402
+ openDatabase(newDbPath);
403
+ insertMilestone({ id: 'M001', title: 'Existing Milestone' });
404
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Existing Slice' });
405
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Existing Task' });
406
+ insertAssessment({
407
+ path: '.gsd/milestones/M001/M001-VALIDATION.md',
408
+ milestoneId: 'M001',
409
+ status: 'pass',
410
+ scope: 'validate-milestone',
411
+ fullContent: '# Existing Validation',
412
+ });
413
+ insertReplanHistory({
414
+ milestoneId: 'M001',
415
+ sliceId: 'S01',
416
+ taskId: 'T01',
417
+ summary: 'Existing replan row',
418
+ previousArtifactPath: 'before.md',
419
+ replacementArtifactPath: 'after.md',
420
+ });
421
+ insertGateRow({ milestoneId: 'M001', sliceId: 'S01', gateId: 'Q3', scope: 'slice' });
422
+ saveGateResult({
423
+ milestoneId: 'M001',
424
+ sliceId: 'S01',
425
+ gateId: 'Q3',
426
+ verdict: 'pass',
427
+ rationale: 'Existing gate',
428
+ findings: 'No findings',
429
+ });
430
+ recordMilestoneCommitAttribution({
431
+ commitSha: 'def456',
432
+ milestoneId: 'M001',
433
+ source: 'recorded',
434
+ confidence: 0.8,
435
+ files: ['src/kept.ts'],
436
+ createdAt: '2026-06-05T00:00:00.000Z',
437
+ });
438
+
439
+ const restored = bootstrapFromManifest(base);
440
+ assert.strictEqual(restored, true);
441
+
442
+ const snap = snapshotState();
443
+ assert.strictEqual(snap.assessments?.find((r) => r.path.endsWith('VALIDATION.md'))?.full_content, '# Existing Validation');
444
+ assert.strictEqual(snap.replan_history?.find((r) => r.summary === 'Existing replan row')?.replacement_artifact_path, 'after.md');
445
+ assert.strictEqual(snap.quality_gates?.find((r) => r.gate_id === 'Q3')?.rationale, 'Existing gate');
446
+ assert.strictEqual(snap.milestone_commit_attributions?.find((r) => r.commit_sha === 'def456')?.files_json, '["src/kept.ts"]');
447
+ } finally {
448
+ closeDatabase();
449
+ cleanupDir(base);
450
+ }
451
+ });
452
+
453
+ test('workflow-manifest: bootstrapFromManifest restores memory-backed decisions', () => {
454
+ const base = tempDir();
455
+ openDatabase(tempDbPath(base));
456
+ try {
457
+ insertMemoryBackedDecision('D901');
458
+ writeManifest(base);
459
+ closeDatabase();
460
+
461
+ const newDbPath = path.join(base, 'new.db');
462
+ openDatabase(newDbPath);
463
+ const restored = bootstrapFromManifest(base);
464
+ assert.strictEqual(restored, true);
465
+
466
+ const decision = getAllDecisionsFromMemories().find((r) => r.id === 'D901');
467
+ assert.ok(decision !== undefined, 'D901 should be restored into the memory-backed decision surface');
468
+ assert.strictEqual(decision!.decision, 'Decision D901');
469
+ } finally {
470
+ closeDatabase();
471
+ cleanupDir(base);
472
+ }
473
+ });
474
+
475
+ test('workflow-manifest: bootstrapFromManifest replaces stale memory-backed decisions', () => {
476
+ const base = tempDir();
477
+ openDatabase(tempDbPath(base));
478
+ try {
479
+ insertMemoryBackedDecision('D902');
480
+ writeManifest(base);
481
+ closeDatabase();
482
+
483
+ const newDbPath = path.join(base, 'new.db');
484
+ openDatabase(newDbPath);
485
+ insertMemoryBackedDecision('D-STALE');
486
+ insertMemoryRow({
487
+ id: 'MEM-NOTE',
488
+ category: 'note',
489
+ content: 'Keep this non-decision memory',
490
+ confidence: 0.9,
491
+ sourceUnitType: null,
492
+ sourceUnitId: null,
493
+ createdAt: '2026-01-01T00:00:00.000Z',
494
+ updatedAt: '2026-01-01T00:00:00.000Z',
495
+ scope: 'project',
496
+ tags: ['keep'],
497
+ structuredFields: { kind: 'ordinary-note' },
498
+ });
499
+
500
+ const restored = bootstrapFromManifest(base);
501
+ assert.strictEqual(restored, true);
502
+
503
+ const decisions = getAllDecisionsFromMemories();
504
+ assert.ok(decisions.some((r) => r.id === 'D902'), 'manifest decision should be restored into memories');
505
+ assert.equal(decisions.some((r) => r.id === 'D-STALE'), false, 'stale memory-backed decision should be removed');
506
+
507
+ const note = _getAdapter()!.prepare('SELECT id FROM memories WHERE id = ?').get('MEM-NOTE') as Record<string, unknown> | undefined;
508
+ assert.strictEqual(note?.['id'], 'MEM-NOTE');
509
+ } finally {
510
+ closeDatabase();
511
+ cleanupDir(base);
512
+ }
513
+ });
514
+
210
515
  test('workflow-manifest: insertTask can clear target_repositories with explicit empty array', () => {
211
516
  const base = tempDir();
212
517
  openDatabase(tempDbPath(base));
@@ -9,7 +9,8 @@ import {
9
9
  openDatabase,
10
10
  closeDatabase,
11
11
  _getAdapter,
12
- insertGateRow,
12
+ getArtifact,
13
+ getAssessment,
13
14
  insertAssessment,
14
15
  upsertRequirement,
15
16
  getAllMilestones,
@@ -632,16 +633,40 @@ test("executeUatResultSave accepts gsd_uat_exec evidence written in a milestone
632
633
  assert.equal(result.isError, undefined);
633
634
  assert.equal(result.details.operation, "save_uat_result");
634
635
  assert.equal(result.details.verdict, "PASS");
636
+ assert.equal(result.details.runId, "uat:M001:S02:attempt-1");
637
+ assert.equal(result.details.worktreeRoot, worktree);
638
+ assert.equal(result.details.browserToolsPresented, false);
635
639
  assert.ok(
636
640
  existsSync(join(base, ".gsd", "uat", "M001", "S02", "attempt-1.json")),
637
641
  "attempt JSON should be persisted under the authoritative project .gsd",
638
642
  );
643
+ const attempt = JSON.parse(readFileSync(
644
+ join(base, ".gsd", "uat", "M001", "S02", "attempt-1.json"),
645
+ "utf-8",
646
+ )) as {
647
+ runId?: string;
648
+ worktreeRoot?: string;
649
+ browserToolsPresented?: boolean;
650
+ modePolicy?: { requiredAnyModes?: string[] };
651
+ };
652
+ assert.equal(attempt.runId, "uat:M001:S02:attempt-1");
653
+ assert.equal(attempt.worktreeRoot, worktree);
654
+ assert.equal(attempt.browserToolsPresented, false);
655
+ assert.deepEqual(attempt.modePolicy?.requiredAnyModes, ["runtime"]);
639
656
  const assessment = readFileSync(
640
657
  join(base, ".gsd", "milestones", "M001", "slices", "S02", "S02-ASSESSMENT.md"),
641
658
  "utf-8",
642
659
  );
660
+ assert.match(assessment, /runId: uat:M001:S02:attempt-1/);
661
+ assert.ok(assessment.includes(`worktreeRoot: ${worktree}`));
643
662
  assert.match(assessment, /Runtime path C:\\\\tmp\\\|uat evidence/);
644
663
  assert.match(assessment, /backslash \\\\ and pipe \\\|/);
664
+
665
+ const artifactPath = "milestones/M001/slices/S02/S02-ASSESSMENT.md";
666
+ const assessmentPath = `.gsd/${artifactPath}`;
667
+ assert.equal(getArtifact(artifactPath)?.artifact_type, "ASSESSMENT");
668
+ assert.equal(getAssessment(assessmentPath)?.scope, "run-uat");
669
+ assert.equal(getAssessment(assessmentPath)?.status, "pass");
645
670
  } finally {
646
671
  closeDatabase();
647
672
  cleanup(base);
@@ -750,8 +775,10 @@ test("executeUatResultSave supplies direct browser tools for browser-executable
750
775
  const attempt = JSON.parse(readFileSync(
751
776
  join(base, ".gsd", "uat", "M001", "S06", "attempt-1.json"),
752
777
  "utf-8",
753
- )) as { presentation?: { presentedTools?: string[] } };
778
+ )) as { browserToolsPresented?: boolean; presentation?: { presentedTools?: string[] } };
754
779
 
780
+ assert.equal(result.details.browserToolsPresented, true);
781
+ assert.equal(attempt.browserToolsPresented, true);
755
782
  assert.ok(attempt.presentation?.presentedTools?.includes("browser_navigate"));
756
783
  assert.ok(attempt.presentation?.presentedTools?.includes("browser_assert"));
757
784
  assert.equal(
@@ -1447,12 +1474,25 @@ test("executeSaveGateResult validates inputs and persists verdicts", async () =>
1447
1474
  openTestDb(base);
1448
1475
  seedMilestone("M005", "Milestone Five");
1449
1476
  seedSlice("M005", "S05", "pending");
1450
- insertGateRow({
1477
+ mkdirSync(join(base, "src"), { recursive: true });
1478
+ writeFileSync(join(base, "src", "gate.ts"), "export const gate = true;\n", "utf-8");
1479
+ await inProjectDir(base, () => executePlanSlice({
1451
1480
  milestoneId: "M005",
1452
1481
  sliceId: "S05",
1453
- gateId: "Q3",
1454
- scope: "slice",
1455
- });
1482
+ goal: "Plan gate save projection.",
1483
+ tasks: [
1484
+ {
1485
+ taskId: "T01",
1486
+ title: "Add gate fixture",
1487
+ description: "Create a fixture touched by gate evaluation.",
1488
+ estimate: "10m",
1489
+ files: ["src/gate.ts"],
1490
+ verify: "node --test",
1491
+ inputs: [],
1492
+ expectedOutput: ["src/gate.ts"],
1493
+ },
1494
+ ],
1495
+ }, base));
1456
1496
 
1457
1497
  const result = await inProjectDir(base, () => executeSaveGateResult({
1458
1498
  milestoneId: "M005",
@@ -1471,6 +1511,33 @@ test("executeSaveGateResult validates inputs and persists verdicts", async () =>
1471
1511
  assert.equal(row?.status, "complete");
1472
1512
  assert.equal(row?.verdict, "pass");
1473
1513
  assert.equal(row?.rationale, "Looks good.");
1514
+ const planPath = join(base, ".gsd", "milestones", "M005", "slices", "S05", "S05-PLAN.md");
1515
+ assert.match(readFileSync(planPath, "utf-8"), /No issues found\./);
1516
+ } finally {
1517
+ closeDatabase();
1518
+ cleanup(base);
1519
+ }
1520
+ });
1521
+
1522
+ test("executeSaveGateResult fails when no canonical gate row is updated", async () => {
1523
+ const base = makeTmpBase();
1524
+ try {
1525
+ openTestDb(base);
1526
+ seedMilestone("M005", "Milestone Five");
1527
+ seedSlice("M005", "S05", "pending");
1528
+
1529
+ const result = await inProjectDir(base, () => executeSaveGateResult({
1530
+ milestoneId: "M005",
1531
+ sliceId: "S05",
1532
+ gateId: "Q3",
1533
+ verdict: "pass",
1534
+ rationale: "Looks good.",
1535
+ findings: "No issues found.",
1536
+ }, base));
1537
+
1538
+ assert.equal(result.isError, true);
1539
+ assert.equal(result.details.operation, "save_gate_result");
1540
+ assert.match(String(result.details.error), /quality gate row not found/);
1474
1541
  } finally {
1475
1542
  closeDatabase();
1476
1543
  cleanup(base);