@north-light/crouter 0.3.311 → 0.3.313

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 (520) hide show
  1. package/dist/api/client.d.ts +27 -30
  2. package/dist/api/client.js +80 -67
  3. package/dist/api/dto/broker-ops.d.ts +10 -20
  4. package/dist/api/dto/canvas.d.ts +1 -10
  5. package/dist/api/dto/health.d.ts +113 -0
  6. package/dist/api/dto/human-requests.d.ts +14 -3
  7. package/dist/api/dto/human.d.ts +2 -48
  8. package/dist/api/dto/human.js +3 -2
  9. package/dist/api/dto/inbox.d.ts +14 -0
  10. package/dist/api/dto/mail.d.ts +43 -0
  11. package/dist/api/dto/nodes.d.ts +11 -8
  12. package/dist/api/dto/recovery.d.ts +96 -0
  13. package/dist/api/dto/reviews.d.ts +2 -2
  14. package/dist/api/routes.d.ts +9 -6
  15. package/dist/api/routes.js +11 -11
  16. package/dist/build-root.d.ts +4 -0
  17. package/dist/build-root.js +11 -1
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
  22. package/dist/cli.js +10 -1
  23. package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
  24. package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
  25. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  26. package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
  27. package/dist/clients/attach/chrome/inbox-strip.js +17 -9
  28. package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
  29. package/dist/clients/attach/chrome/ticket-panel.js +77 -46
  30. package/dist/clients/attach/overlays/graph.js +6 -9
  31. package/dist/clients/attach/render/chat-view.d.ts +5 -4
  32. package/dist/clients/attach/render/chat-view.js +22 -13
  33. package/dist/clients/attach/render/page-block.d.ts +11 -7
  34. package/dist/clients/attach/render/page-block.js +64 -55
  35. package/dist/clients/attach/viewer.js +746 -735
  36. package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
  37. package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
  38. package/dist/clients/inbox/controller.d.ts +42 -14
  39. package/dist/clients/inbox/controller.js +240 -124
  40. package/dist/clients/inbox/dto-adapt.d.ts +28 -0
  41. package/dist/clients/inbox/dto-adapt.js +93 -0
  42. package/dist/clients/inbox/page-adapter.d.ts +5 -4
  43. package/dist/clients/inbox/page-adapter.js +12 -12
  44. package/dist/clients/inbox/resolve.d.ts +10 -5
  45. package/dist/clients/inbox/resolve.js +13 -12
  46. package/dist/clients/inbox/review/review-client.d.ts +0 -1
  47. package/dist/clients/inbox/review/review-client.js +0 -4
  48. package/dist/clients/inbox/review-adapter.d.ts +2 -1
  49. package/dist/clients/inbox/review-adapter.js +3 -5
  50. package/dist/clients/inbox/surface.d.ts +2 -2
  51. package/dist/clients/inbox/surface.js +19 -8
  52. package/dist/clients/inbox/tui.d.ts +3 -3
  53. package/dist/commands/__tests__/human.test.js +31 -15
  54. package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
  55. package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
  56. package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
  57. package/dist/commands/api-client.d.ts +5 -4
  58. package/dist/commands/api-client.js +13 -7
  59. package/dist/commands/canvas-history/shared.js +1 -1
  60. package/dist/commands/canvas-history.js +1 -1
  61. package/dist/commands/canvas-roster.js +1 -1
  62. package/dist/commands/canvas.js +1 -2
  63. package/dist/commands/human/feedback.js +20 -17
  64. package/dist/commands/human/prompts.js +45 -36
  65. package/dist/commands/human/queue.js +73 -123
  66. package/dist/commands/human/review.js +6 -16
  67. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
  68. package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
  69. package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
  70. package/dist/commands/node-inspect-artifacts.js +1 -1
  71. package/dist/commands/node-lifecycle-revive.d.ts +2 -2
  72. package/dist/commands/node-lifecycle-revive.js +9 -19
  73. package/dist/commands/pkg/plugin-manage.js +0 -1
  74. package/dist/commands/profile/show.js +4 -12
  75. package/dist/commands/surface-tmux-spread.js +1 -5
  76. package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
  77. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
  78. package/dist/commands/sys/branch.d.ts +2 -0
  79. package/dist/commands/sys/branch.js +19 -0
  80. package/dist/commands/sys/config.js +106 -33
  81. package/dist/commands/sys/daemon.d.ts +2 -0
  82. package/dist/commands/sys/daemon.js +130 -7
  83. package/dist/commands/sys/doctor.js +5 -15
  84. package/dist/commands/sys/migrate.js +21 -92
  85. package/dist/commands/sys/setup-settings-runner.js +4 -2
  86. package/dist/commands/sys.js +2 -15
  87. package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
  88. package/dist/core/__tests__/boot.test.js +32 -25
  89. package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
  90. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
  91. package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
  92. package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
  93. package/dist/core/__tests__/canvas.test.js +18 -47
  94. package/dist/core/__tests__/child-death-wake.test.js +29 -7
  95. package/dist/core/__tests__/cli-help-contract.test.js +2 -0
  96. package/dist/core/__tests__/close.test.js +29 -10
  97. package/dist/core/__tests__/collectible.test.js +2 -1
  98. package/dist/core/__tests__/config-change-delta.test.js +2 -0
  99. package/dist/core/__tests__/context-intro.test.js +17 -5
  100. package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
  101. package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
  102. package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
  103. package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
  104. package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
  105. package/dist/core/__tests__/daemon-boot.test.js +51 -14
  106. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  107. package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
  108. package/dist/core/__tests__/focuses.test.js +10 -5
  109. package/dist/core/__tests__/helpers/harness.js +50 -18
  110. package/dist/core/__tests__/history-inbox.test.js +12 -16
  111. package/dist/core/__tests__/human-action-delivery.test.js +48 -28
  112. package/dist/core/__tests__/human-actions.test.js +7 -3
  113. package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
  114. package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
  115. package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
  116. package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
  117. package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
  118. package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
  119. package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
  120. package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
  121. package/dist/core/__tests__/integration/lifecycle-hooks.test.js +312 -1
  122. package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
  123. package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
  124. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
  125. package/dist/core/__tests__/integration/revive.test.js +67 -21
  126. package/dist/core/__tests__/integration/spawn-root.test.js +62 -19
  127. package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
  128. package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
  129. package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
  130. package/dist/core/__tests__/kickoff.test.js +36 -39
  131. package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
  132. package/dist/core/__tests__/lifecycle.test.js +2 -1
  133. package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
  134. package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
  135. package/dist/core/__tests__/migration.test.js +145 -31
  136. package/dist/core/__tests__/model-pin-durability.test.js +4 -1
  137. package/dist/core/__tests__/model-routes-config.test.js +13 -5
  138. package/dist/core/__tests__/node-outcome.test.js +93 -26
  139. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +4 -3
  140. package/dist/core/__tests__/on-read-dedup-resume.test.js +8 -7
  141. package/dist/core/__tests__/on-read-nested-store.test.js +8 -7
  142. package/dist/core/__tests__/passive-subscription.test.js +50 -157
  143. package/dist/core/__tests__/plugin-kinds.test.js +6 -4
  144. package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
  145. package/dist/core/__tests__/plugin-page-components.test.js +6 -4
  146. package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
  147. package/dist/core/__tests__/profile-project-memory-delivery.test.js +35 -32
  148. package/dist/core/__tests__/prune.test.js +11 -5
  149. package/dist/core/__tests__/push-final-guard.test.js +14 -7
  150. package/dist/core/__tests__/relaunch-root.test.js +30 -2
  151. package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
  152. package/dist/core/__tests__/repository-root-identity.test.js +4 -0
  153. package/dist/core/__tests__/review-model-floor.test.js +6 -3
  154. package/dist/core/__tests__/revive-all.test.js +13 -3
  155. package/dist/core/__tests__/revive-capacity.test.js +26 -4
  156. package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
  157. package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
  158. package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
  159. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
  160. package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
  161. package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
  162. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
  163. package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
  164. package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
  165. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +5 -4
  166. package/dist/core/__tests__/stop-guard.test.js +2 -1
  167. package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
  168. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +19 -5
  169. package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
  170. package/dist/core/bootstrap.js +2 -0
  171. package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
  172. package/dist/core/broker-client/transport-socket.d.ts +1 -0
  173. package/dist/core/broker-client/transport-socket.js +13 -5
  174. package/dist/core/canvas/__tests__/attention.test.js +29 -35
  175. package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
  176. package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
  177. package/dist/core/canvas/attention.d.ts +2 -5
  178. package/dist/core/canvas/attention.js +15 -64
  179. package/dist/core/canvas/boot.d.ts +6 -7
  180. package/dist/core/canvas/boot.js +5 -9
  181. package/dist/core/canvas/canvas.d.ts +13 -109
  182. package/dist/core/canvas/canvas.js +140 -401
  183. package/dist/core/canvas/crons.d.ts +2 -0
  184. package/dist/core/canvas/crons.js +16 -15
  185. package/dist/core/canvas/daemon-owner.js +10 -0
  186. package/dist/core/canvas/db.d.ts +2 -2
  187. package/dist/core/canvas/db.js +2 -18
  188. package/dist/core/canvas/deliveries.d.ts +104 -0
  189. package/dist/core/canvas/deliveries.js +354 -0
  190. package/dist/core/canvas/executions.d.ts +29 -0
  191. package/dist/core/canvas/executions.js +68 -0
  192. package/dist/core/canvas/history.js +35 -35
  193. package/dist/core/canvas/index.d.ts +3 -1
  194. package/dist/core/canvas/index.js +3 -1
  195. package/dist/core/canvas/migrations.js +20 -12
  196. package/dist/core/canvas/nav-model.js +1 -3
  197. package/dist/core/canvas/nav-render.d.ts +4 -4
  198. package/dist/core/canvas/nav-render.js +11 -21
  199. package/dist/core/canvas/node-sql-migration.d.ts +3 -0
  200. package/dist/core/canvas/node-sql-migration.js +261 -0
  201. package/dist/core/canvas/paths.d.ts +2 -16
  202. package/dist/core/canvas/paths.js +2 -31
  203. package/dist/core/canvas/recovery.d.ts +76 -0
  204. package/dist/core/canvas/recovery.js +588 -0
  205. package/dist/core/canvas/remote-canvas-source.js +4 -0
  206. package/dist/core/canvas/render-source.d.ts +16 -27
  207. package/dist/core/canvas/render-source.js +16 -45
  208. package/dist/core/canvas/sessions.d.ts +33 -0
  209. package/dist/core/canvas/sessions.js +78 -0
  210. package/dist/core/canvas/types.d.ts +33 -33
  211. package/dist/core/canvas/types.js +2 -5
  212. package/dist/core/canvas/waits.d.ts +18 -0
  213. package/dist/core/canvas/waits.js +70 -0
  214. package/dist/core/canvas/worktrees.d.ts +40 -0
  215. package/dist/core/canvas/worktrees.js +93 -0
  216. package/dist/core/command-hooks/artifact.d.ts +6 -0
  217. package/dist/core/command-hooks/artifact.js +22 -6
  218. package/dist/core/command-hooks/discovery.d.ts +2 -0
  219. package/dist/core/command-hooks/discovery.js +2 -0
  220. package/dist/core/command-hooks/lifecycle-catalog.d.ts +20 -2
  221. package/dist/core/command-hooks/lifecycle-catalog.js +7 -2
  222. package/dist/core/command-hooks/lifecycle-create.d.ts +4 -0
  223. package/dist/core/command-hooks/lifecycle-create.js +51 -0
  224. package/dist/core/command-hooks/schema.d.ts +2 -2
  225. package/dist/core/command-hooks/schema.js +5 -4
  226. package/dist/core/command-hooks/transport/exec-invoke.js +3 -1
  227. package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +18 -8
  228. package/dist/core/command-hooks/transport/exec-lifecycle.js +89 -30
  229. package/dist/core/config.d.ts +17 -12
  230. package/dist/core/config.js +106 -155
  231. package/dist/core/errors.d.ts +1 -0
  232. package/dist/core/errors.js +4 -0
  233. package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
  234. package/dist/core/feed/feed.d.ts +0 -6
  235. package/dist/core/feed/feed.js +68 -56
  236. package/dist/core/feed/inbox.d.ts +7 -81
  237. package/dist/core/feed/inbox.js +46 -378
  238. package/dist/core/feed/messages.d.ts +58 -0
  239. package/dist/core/feed/messages.js +217 -0
  240. package/dist/core/fs-utils.d.ts +4 -0
  241. package/dist/core/fs-utils.js +21 -1
  242. package/dist/core/human/answer.d.ts +1 -1
  243. package/dist/core/human/answer.js +1 -1
  244. package/dist/core/human/claim.d.ts +1 -1
  245. package/dist/core/human/claim.js +2 -4
  246. package/dist/core/human/component-docs.js +1 -1
  247. package/dist/core/human/feedback-companion.js +4 -3
  248. package/dist/core/human/feedback.d.ts +5 -8
  249. package/dist/core/human/feedback.js +57 -85
  250. package/dist/core/human/page-authoring.d.ts +30 -0
  251. package/dist/core/human/page-authoring.js +19 -0
  252. package/dist/core/human/requests.d.ts +136 -0
  253. package/dist/core/human/requests.js +515 -0
  254. package/dist/core/human/root.d.ts +0 -7
  255. package/dist/core/human/root.js +0 -17
  256. package/dist/core/human/scan.d.ts +2 -7
  257. package/dist/core/human/scan.js +48 -132
  258. package/dist/core/human/summary.d.ts +1 -1
  259. package/dist/core/human/summary.js +1 -1
  260. package/dist/core/human/tickets.d.ts +23 -83
  261. package/dist/core/human/tickets.js +92 -243
  262. package/dist/core/human/types.d.ts +5 -1
  263. package/dist/core/installed-plugins.js +8 -3
  264. package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
  265. package/dist/core/locked-file.d.ts +6 -3
  266. package/dist/core/locked-file.js +36 -9
  267. package/dist/core/memory/extensions.js +2 -0
  268. package/dist/core/preview-registry.js +0 -1
  269. package/dist/core/profiles/__tests__/env-store.test.js +2 -0
  270. package/dist/core/profiles/default-binding.d.ts +0 -4
  271. package/dist/core/profiles/default-binding.js +12 -58
  272. package/dist/core/profiles/env-store.js +8 -3
  273. package/dist/core/profiles/manifest.d.ts +2 -37
  274. package/dist/core/profiles/manifest.js +35 -161
  275. package/dist/core/profiles/select.js +3 -0
  276. package/dist/core/review/__tests__/capture-origin.test.js +13 -2
  277. package/dist/core/review/__tests__/comments.test.js +28 -10
  278. package/dist/core/review/__tests__/remap.test.js +28 -10
  279. package/dist/core/review/__tests__/stage-identity.test.js +17 -7
  280. package/dist/core/review/birth.d.ts +1 -1
  281. package/dist/core/review/birth.js +34 -5
  282. package/dist/core/review/comments.js +1 -1
  283. package/dist/core/review/companion.d.ts +1 -1
  284. package/dist/core/review/companion.js +2 -2
  285. package/dist/core/review/document.js +1 -1
  286. package/dist/core/review/project.d.ts +5 -1
  287. package/dist/core/review/project.js +14 -36
  288. package/dist/core/review/realize.d.ts +3 -6
  289. package/dist/core/review/realize.js +51 -168
  290. package/dist/core/review/remap.js +1 -1
  291. package/dist/core/review/stage.d.ts +3 -2
  292. package/dist/core/review/stage.js +2 -3
  293. package/dist/core/review/store.d.ts +3 -21
  294. package/dist/core/review/store.js +140 -186
  295. package/dist/core/review/types.d.ts +0 -1
  296. package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
  297. package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
  298. package/dist/core/runtime/broker/auth-reload.js +9 -10
  299. package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
  300. package/dist/core/runtime/broker/daemon-ops.js +42 -9
  301. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  302. package/dist/core/runtime/broker/extension-abort.js +11 -0
  303. package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
  304. package/dist/core/runtime/broker/fault-retry.js +142 -95
  305. package/dist/core/runtime/broker/inbox.d.ts +4 -32
  306. package/dist/core/runtime/broker/inbox.js +4 -92
  307. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  308. package/dist/core/runtime/broker/rebind.js +21 -12
  309. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  310. package/dist/core/runtime/broker-persona-guidance.js +2 -13
  311. package/dist/core/runtime/broker.js +28 -22
  312. package/dist/core/runtime/close.d.ts +3 -9
  313. package/dist/core/runtime/close.js +16 -27
  314. package/dist/core/runtime/fault.d.ts +3 -93
  315. package/dist/core/runtime/fault.js +9 -419
  316. package/dist/core/runtime/kickoff.d.ts +3 -6
  317. package/dist/core/runtime/kickoff.js +12 -18
  318. package/dist/core/runtime/launch.js +1 -1
  319. package/dist/core/runtime/lifecycle.js +40 -7
  320. package/dist/core/runtime/nodes.d.ts +5 -1
  321. package/dist/core/runtime/nodes.js +26 -11
  322. package/dist/core/runtime/placement.js +2 -2
  323. package/dist/core/runtime/recycle.js +24 -14
  324. package/dist/core/runtime/reset.js +26 -7
  325. package/dist/core/runtime/revive.js +226 -217
  326. package/dist/core/runtime/spawn.d.ts +4 -1
  327. package/dist/core/runtime/spawn.js +43 -5
  328. package/dist/core/runtime/warm-pool.d.ts +2 -2
  329. package/dist/core/runtime/warm-pool.js +23 -3
  330. package/dist/core/scoped-state/db.d.ts +7 -0
  331. package/dist/core/scoped-state/db.js +92 -0
  332. package/dist/core/scoped-state/migrate.d.ts +11 -0
  333. package/dist/core/scoped-state/migrate.js +198 -0
  334. package/dist/core/scoped-state/paths.d.ts +9 -0
  335. package/dist/core/scoped-state/paths.js +27 -0
  336. package/dist/core/scoped-state/profiles.d.ts +12 -0
  337. package/dist/core/scoped-state/profiles.js +62 -0
  338. package/dist/core/scoped-state/providers.d.ts +16 -0
  339. package/dist/core/scoped-state/providers.js +8 -0
  340. package/dist/core/scoped-state/schema.d.ts +3 -0
  341. package/dist/core/scoped-state/schema.js +26 -0
  342. package/dist/core/scoped-state/settings.d.ts +28 -0
  343. package/dist/core/scoped-state/settings.js +82 -0
  344. package/dist/core/subscription-state.d.ts +29 -48
  345. package/dist/core/subscription-state.js +176 -712
  346. package/dist/core/worktree-close.js +4 -4
  347. package/dist/core/worktree-mutation-async.js +2 -2
  348. package/dist/core/worktree-sweep.js +11 -16
  349. package/dist/core/worktree.js +6 -12
  350. package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
  351. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
  352. package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
  353. package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
  354. package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
  355. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +41 -17
  356. package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
  357. package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
  358. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
  359. package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
  360. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
  361. package/dist/daemon/api/__tests__/model-config.test.js +8 -8
  362. package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
  363. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
  364. package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
  365. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +6 -3
  366. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
  367. package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
  368. package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
  369. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
  370. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
  371. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +29 -43
  372. package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
  373. package/dist/daemon/api/bridge.js +1 -1
  374. package/dist/daemon/api/handlers/bash-jobs.js +6 -7
  375. package/dist/daemon/api/handlers/broker-ops.js +47 -84
  376. package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
  377. package/dist/daemon/api/handlers/broker-recovery.js +251 -0
  378. package/dist/daemon/api/handlers/canvas.js +2 -44
  379. package/dist/daemon/api/handlers/daemon.js +41 -0
  380. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  381. package/dist/daemon/api/handlers/health.js +10 -5
  382. package/dist/daemon/api/handlers/human-requests.js +168 -188
  383. package/dist/daemon/api/handlers/human.js +3 -148
  384. package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
  385. package/dist/daemon/api/handlers/inbox-page.js +89 -0
  386. package/dist/daemon/api/handlers/inbox.js +21 -120
  387. package/dist/daemon/api/handlers/messages.d.ts +1 -0
  388. package/dist/daemon/api/handlers/messages.js +73 -15
  389. package/dist/daemon/api/handlers/node-outcomes.js +58 -13
  390. package/dist/daemon/api/handlers/nodes.d.ts +1 -0
  391. package/dist/daemon/api/handlers/nodes.js +41 -42
  392. package/dist/daemon/api/handlers/reviews.js +4 -29
  393. package/dist/daemon/api/map.d.ts +25 -3
  394. package/dist/daemon/api/map.js +84 -14
  395. package/dist/daemon/api/server.js +68 -9
  396. package/dist/daemon/control.d.ts +18 -0
  397. package/dist/daemon/cron/disposition.d.ts +2 -0
  398. package/dist/daemon/cron/disposition.js +8 -5
  399. package/dist/daemon/cron/settle.js +37 -13
  400. package/dist/daemon/cron/sinks.d.ts +18 -1
  401. package/dist/daemon/cron/sinks.js +47 -93
  402. package/dist/daemon/crtrd-cli.js +4 -19
  403. package/dist/daemon/crtrd.d.ts +2 -0
  404. package/dist/daemon/crtrd.js +206 -81
  405. package/dist/daemon/fleet.js +5 -6
  406. package/dist/daemon/human/finish.d.ts +12 -24
  407. package/dist/daemon/human/finish.js +88 -285
  408. package/dist/daemon/human/settle.d.ts +40 -0
  409. package/dist/daemon/human/settle.js +89 -0
  410. package/dist/daemon/human/sweep.d.ts +20 -5
  411. package/dist/daemon/human/sweep.js +56 -60
  412. package/dist/daemon/manage.d.ts +21 -16
  413. package/dist/daemon/manage.js +85 -51
  414. package/dist/daemon/messaging/node-message.d.ts +1 -1
  415. package/dist/daemon/messaging/node-message.js +9 -12
  416. package/dist/daemon/park-activity.js +3 -3
  417. package/dist/daemon/reconcilers/bash-deadline.js +6 -7
  418. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  419. package/dist/daemon/reconcilers/broker-supervision.js +41 -19
  420. package/dist/daemon/reconcilers/controller-death.js +6 -18
  421. package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
  422. package/dist/daemon/reconcilers/delivery-lane.js +130 -0
  423. package/dist/daemon/reconcilers/live-obligation.js +3 -3
  424. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  425. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
  426. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
  427. package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
  428. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  429. package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
  430. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
  431. package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
  432. package/dist/daemon/review/companion.js +5 -11
  433. package/dist/daemon/review/deliver.d.ts +1 -5
  434. package/dist/daemon/review/deliver.js +3 -52
  435. package/dist/daemon/review/finish.d.ts +2 -27
  436. package/dist/daemon/review/finish.js +79 -263
  437. package/dist/daemon/review/sweep.d.ts +3 -10
  438. package/dist/daemon/review/sweep.js +13 -131
  439. package/dist/daemon/startup-policy.d.ts +0 -5
  440. package/dist/daemon/startup-policy.js +0 -5
  441. package/dist/hook-authoring.d.ts +28 -2
  442. package/dist/hook-authoring.js +53 -1
  443. package/dist/index.d.ts +3 -2
  444. package/dist/index.js +1 -1
  445. package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
  446. package/dist/migrations/__tests__/activation.test.js +9 -6
  447. package/dist/migrations/activation.d.ts +3 -2
  448. package/dist/migrations/activation.js +2 -4
  449. package/dist/migrations/corpus.d.ts +2 -5
  450. package/dist/migrations/corpus.js +9 -20
  451. package/dist/migrations/runner.d.ts +3 -1
  452. package/dist/migrations/runner.js +6 -2
  453. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
  454. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
  455. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
  456. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
  457. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
  458. package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
  459. package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
  460. package/dist/pi-extensions/canvas-passive-context.js +85 -37
  461. package/dist/pi-extensions/canvas-stophook.js +47 -31
  462. package/dist/shared/env.d.ts +1 -0
  463. package/dist/shared/env.js +3 -0
  464. package/package.json +1 -1
  465. package/runtime.lock.json +5 -5
  466. package/dist/clients/attach/__tests__/page-block.test.js +0 -54
  467. package/dist/clients/inbox/review-visibility.d.ts +0 -5
  468. package/dist/clients/inbox/review-visibility.js +0 -19
  469. package/dist/commands/canvas-rebuild-index.d.ts +0 -2
  470. package/dist/commands/canvas-rebuild-index.js +0 -46
  471. package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
  472. package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
  473. package/dist/core/__tests__/human-deliver.test.js +0 -256
  474. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
  475. package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
  476. package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
  477. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
  478. package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
  479. package/dist/core/__tests__/phase4-review-store.test.js +0 -144
  480. package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
  481. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
  482. package/dist/core/canvas/human-deliveries.d.ts +0 -39
  483. package/dist/core/canvas/human-deliveries.js +0 -75
  484. package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
  485. package/dist/core/canvas/node-outcome-deliveries.js +0 -159
  486. package/dist/core/feed/passive.d.ts +0 -3
  487. package/dist/core/feed/passive.js +0 -53
  488. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
  489. package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
  490. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
  491. package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
  492. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
  493. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
  494. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
  495. package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
  496. package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
  497. package/dist/core/human/__tests__/page-tickets.test.js +0 -161
  498. package/dist/core/review/ticket-filter.d.ts +0 -17
  499. package/dist/core/review/ticket-filter.js +0 -21
  500. package/dist/core/runtime/broker/passive.d.ts +0 -17
  501. package/dist/core/runtime/broker/passive.js +0 -44
  502. package/dist/core/runtime/busy.d.ts +0 -46
  503. package/dist/core/runtime/busy.js +0 -150
  504. package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
  505. package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
  506. package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
  507. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
  508. package/dist/daemon/human/deliver-action.d.ts +0 -3
  509. package/dist/daemon/human/deliver-action.js +0 -9
  510. package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
  511. package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
  512. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
  513. package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
  514. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
  515. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
  516. package/dist/daemon/startup-block-marker.d.ts +0 -25
  517. package/dist/daemon/startup-block-marker.js +0 -99
  518. /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
  519. /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
  520. /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
@@ -17,7 +17,8 @@ import { tmpdir } from 'node:os';
17
17
  import { join } from 'node:path';
18
18
  import * as tar from 'tar';
19
19
  import { resetScopeCache } from '../scope.js';
20
- import { readMergedLaunchConfig } from '../config.js';
20
+ import { readMergedLaunchConfig, updateRawConfigAtomically, writeRawConfig } from '../config.js';
21
+ import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
21
22
  import { validatePluginBundle } from '../command-plugins/bundle.js';
22
23
  let isolatedHome;
23
24
  let isolatedCwd;
@@ -32,6 +33,7 @@ beforeEach(() => {
32
33
  isolatedCwd = realpathSync(mkdtempSync(join(tmpdir(), 'crtr-plugin-kinds-cwd-')));
33
34
  process.env.HOME = isolatedHome;
34
35
  process.chdir(isolatedCwd);
36
+ initializeFreshScopedStore({ kind: 'user', root: join(isolatedHome, '.crouter') });
35
37
  resetScopeCache();
36
38
  });
37
39
  afterEach(() => {
@@ -76,7 +78,7 @@ test('the scope\u2019s own config.json overrides its plugins; a disabled plugin
76
78
  const root = userRoot();
77
79
  plantPlugin(root, 'northlight', { 'applet-builder': { whenToUse: 'plugin gloss', model: 'anthropic/strong' } });
78
80
  plantPlugin(root, 'zzz-disabled', { ghost: { whenToUse: 'never registers' } });
79
- writeFileSync(join(root, 'config.json'), JSON.stringify({
81
+ updateRawConfigAtomically('user', () => ({
80
82
  plugins: { 'zzz-disabled': { enabled: false } },
81
83
  kinds: { 'applet-builder': { model: 'openai/medium' } },
82
84
  }));
@@ -91,7 +93,7 @@ test('a whenToUse-only entry re-glosses an existing kind without stripping its m
91
93
  // Now every entry field-merges over an existing kind; only a NEW kind
92
94
  // requires whenToUse (a whenToUse-less new kind is dropped).
93
95
  const root = userRoot();
94
- writeFileSync(join(root, 'config.json'), JSON.stringify({ kinds: { explore: { whenToUse: 'custom explore gloss' }, 'new-glossless': { model: 'openai/light' } } }));
96
+ updateRawConfigAtomically('user', () => ({ kinds: { explore: { whenToUse: 'custom explore gloss' }, 'new-glossless': { model: 'openai/light' } } }));
95
97
  const kinds = readMergedLaunchConfig().kinds;
96
98
  assert.equal(kinds['explore']?.whenToUse, 'custom explore gloss');
97
99
  assert.equal(kinds['explore']?.model, 'openai/light'); // builtin tier survives
@@ -100,7 +102,7 @@ test('a whenToUse-only entry re-glosses an existing kind without stripping its m
100
102
  });
101
103
  test('a project-root plugin layers above user config, and the project config above the plugin', () => {
102
104
  const uRoot = userRoot();
103
- writeFileSync(join(uRoot, 'config.json'), JSON.stringify({ kinds: { shared: { whenToUse: 'user gloss', model: 'openai/light' } } }));
105
+ writeRawConfig('user', { kinds: { shared: { whenToUse: 'user gloss', model: 'openai/light' } } });
104
106
  const pRoot = projectRoot();
105
107
  plantPlugin(pRoot, 'proj-plugin', { shared: { model: 'anthropic/strong' }, 'proj-kind': { whenToUse: 'project plugin kind' } });
106
108
  writeFileSync(join(pRoot, 'config.json'), JSON.stringify({ kinds: { 'proj-kind': { model: 'openai/medium' } } }));
@@ -11,8 +11,11 @@ import assert from 'node:assert/strict';
11
11
  import { mkdtempSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
12
12
  import { tmpdir } from 'node:os';
13
13
  import { join } from 'node:path';
14
+ import { realpathSync } from 'node:fs';
14
15
  import { linkOrCopy } from '../fs-utils.js';
15
16
  import { listInstalledPluginsInRoot } from '../resolver.js';
17
+ import { closeScopedStores } from '../scoped-state/db.js';
18
+ import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
16
19
  describe('plugin link through a symlinked scope-root ancestor', () => {
17
20
  test('the installed plugin resolves on the next invocation', () => {
18
21
  const base = mkdtempSync(join(tmpdir(), 'crtr-plugin-link-'));
@@ -28,10 +31,12 @@ describe('plugin link through a symlinked scope-root ancestor', () => {
28
31
  symlinkSync(join('physical', 'home'), join(base, 'home'), 'dir');
29
32
  const scopeRootPath = join(base, 'home', '.crouter');
30
33
  mkdirSync(join(scopeRootPath, 'plugins'), { recursive: true });
34
+ initializeFreshScopedStore({ kind: 'user', root: scopeRootPath });
31
35
  linkOrCopy(source, join(scopeRootPath, 'plugins', 'search'));
32
- assert.deepEqual(listInstalledPluginsInRoot('user', scopeRootPath).map((p) => p.name), ['search']);
36
+ assert.deepEqual(listInstalledPluginsInRoot('user', realpathSync(scopeRootPath)).map((p) => p.name), ['search']);
33
37
  }
34
38
  finally {
39
+ closeScopedStores();
35
40
  rmSync(base, { recursive: true, force: true });
36
41
  }
37
42
  });
@@ -15,7 +15,8 @@ import { tmpdir } from 'node:os';
15
15
  import { join } from 'node:path';
16
16
  import * as tar from 'tar';
17
17
  import { resetScopeCache } from '../scope.js';
18
- import { resolvePageComponents } from '../config.js';
18
+ import { resolvePageComponents, updateRawConfigAtomically, writeRawConfig } from '../config.js';
19
+ import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
19
20
  import { validatePluginBundle } from '../command-plugins/bundle.js';
20
21
  let isolatedHome;
21
22
  let isolatedCwd;
@@ -30,6 +31,7 @@ beforeEach(() => {
30
31
  isolatedCwd = realpathSync(mkdtempSync(join(tmpdir(), 'crtr-page-components-cwd-')));
31
32
  process.env.HOME = isolatedHome;
32
33
  process.chdir(isolatedCwd);
34
+ initializeFreshScopedStore({ kind: 'user', root: join(isolatedHome, '.crouter') });
33
35
  resetScopeCache();
34
36
  });
35
37
  afterEach(() => {
@@ -60,7 +62,7 @@ test('an enabled user-scope plugin contributes its page components; a disabled o
60
62
  { kind: 'applet-card', display: true },
61
63
  ]);
62
64
  plantPlugin(root, 'zzz-disabled', ['ghost']);
63
- writeFileSync(join(root, 'config.json'), JSON.stringify({ plugins: { 'zzz-disabled': { enabled: false } } }));
65
+ writeRawConfig('user', { plugins: { 'zzz-disabled': { enabled: false } } });
64
66
  const components = resolvePageComponents();
65
67
  assert.deepEqual(components, [
66
68
  { kind: 'connector', description: 'Connector decision', useWhen: 'Use for a connector decision.', doc: 'Product contract.' },
@@ -70,9 +72,9 @@ test('an enabled user-scope plugin contributes its page components; a disabled o
70
72
  test('user config entries and plugin contributions resolve together, and a colliding kind is rejected', () => {
71
73
  const root = userRoot();
72
74
  plantPlugin(root, 'northlight', ['connector']);
73
- writeFileSync(join(root, 'config.json'), JSON.stringify({ page_components: ['approval'] }));
75
+ updateRawConfigAtomically('user', () => ({ page_components: ['approval'] }));
74
76
  assert.deepEqual(resolvePageComponents().map((component) => component.kind), ['approval', 'connector']);
75
- writeFileSync(join(root, 'config.json'), JSON.stringify({ page_components: ['connector'] }));
77
+ updateRawConfigAtomically('user', () => ({ page_components: ['connector'] }));
76
78
  assert.throws(() => resolvePageComponents(), /page component kind "connector" is registered by both config.json and plugin "northlight"/);
77
79
  });
78
80
  test('two plugins whose kinds derive one JSX tag are rejected, naming both sources', () => {
@@ -16,6 +16,7 @@ import { tmpdir } from 'node:os';
16
16
  import { join } from 'node:path';
17
17
  import { buildRoot } from '../../build-root.js';
18
18
  import { SUPPRESS_OUTPUT_LEAVES, LEAF_ICON_CP, SUMMARIZERS } from '../preview-registry.js';
19
+ import { ensureScopeInitialized } from '../config.js';
19
20
  import { resetScopeCache } from '../scope.js';
20
21
  // buildRoot() composes external command-plugin branches from the effective
21
22
  // enabled plugins (user scope + project ancestors). Pin HOME + profile to an
@@ -31,6 +32,7 @@ before(() => {
31
32
  process.env['HOME'] = home;
32
33
  delete process.env['CRTR_PROFILE_ID'];
33
34
  resetScopeCache();
35
+ ensureScopeInitialized('user', join(home, '.crouter'));
34
36
  });
35
37
  after(() => {
36
38
  if (realHome !== undefined)
@@ -18,9 +18,10 @@ import assert from 'node:assert/strict';
18
18
  import { mkdtempSync, mkdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
19
19
  import { tmpdir } from 'node:os';
20
20
  import { dirname, join } from 'node:path';
21
- import { closeDb } from '../canvas/db.js';
21
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
22
22
  import { resetScopeCache } from '../scope.js';
23
23
  import { createProfile } from '../profiles/manifest.js';
24
+ import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
24
25
  import { spawnNode } from '../runtime/nodes.js';
25
26
  import { memoryDir } from '../runtime/memory.js';
26
27
  import { clearSessionCache } from '../substrate/session-cache.js';
@@ -115,6 +116,8 @@ before(() => {
115
116
  canvasHome = realpathSync(mkdtempSync(join(tmpdir(), 'crtr-ppm-canvas-')));
116
117
  process.env['HOME'] = home;
117
118
  process.env['CRTR_HOME'] = canvasHome;
119
+ initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
120
+ migrate(openDb());
118
121
  // A project store answers only under the namespace its root INDEX.md
119
122
  // declares; without that declaration the store does not mount at all.
120
123
  const store = (slug, namespace) => {
@@ -350,11 +353,11 @@ after(() => {
350
353
  restore('CRTR_PROFILE_ID', prevProfile);
351
354
  restore('CRTR_NODE_ID', prevNode);
352
355
  });
353
- function newNode(kind = 'general') {
354
- return spawnNode({ kind, cwd: cwdProject, parent: null, profile_id: profileId }).node_id;
356
+ async function newNode(kind = 'general') {
357
+ return (await spawnNode({ kind, cwd: cwdProject, parent: null, profile_id: profileId })).node_id;
355
358
  }
356
- test('boot delivery caps every profile project at its relationship, including the one used as cwd', () => {
357
- const boot = renderKnowledgeBlock(newNode(), freshTranscriptTarget());
359
+ test('boot delivery caps every profile project at its relationship, including the one used as cwd', async () => {
360
+ const boot = renderKnowledgeBlock(await newNode(), freshTranscriptTarget());
358
361
  // The control: an uncapped relationship still renders its authored content.
359
362
  assert.ok(boot.includes(B.pcontent), `the content-capped project renders its body; got:\n${boot}`);
360
363
  // The reported failure. cwd reaches this root before the manifest pointer
@@ -369,22 +372,22 @@ test('boot delivery caps every profile project at its relationship, including th
369
372
  assert.match(boot, /[├└]─ t9-pname-doc$/m, `the name-capped doc discloses as a bare name; got:\n${boot}`);
370
373
  assert.ok(!boot.includes('When the name project delivers'), 'a name-capped doc discloses no preview line');
371
374
  });
372
- test('surface-entry gates select the rung by node kind while the document gate remains absolute', () => {
375
+ test('surface-entry gates select the rung by node kind while the document gate remains absolute', async () => {
373
376
  for (const kind of ['design', 'spec', 'plan', 'developer']) {
374
- const boot = renderKnowledgeBlock(newNode(kind), freshTranscriptTarget());
377
+ const boot = renderKnowledgeBlock(await newNode(kind), freshTranscriptTarget());
375
378
  assert.ok(boot.includes(B.kindSplit), `${kind} receives the content rung; got:\n${boot}`);
376
379
  }
377
380
  for (const kind of ['general', 'review', 'advisor']) {
378
- const boot = renderKnowledgeBlock(newNode(kind), freshTranscriptTarget());
381
+ const boot = renderKnowledgeBlock(await newNode(kind), freshTranscriptTarget());
379
382
  assert.match(boot, /t9-kind-split {2}# read when: When the node needs this kind-specific guide\./, `${kind} receives the preview rung; got:\n${boot}`);
380
383
  assert.ok(!boot.includes(B.kindSplit), `${kind} does not receive the body`);
381
384
  }
382
385
  for (const kind of ['explore', 'personal-assistant']) {
383
- const boot = renderKnowledgeBlock(newNode(kind), freshTranscriptTarget());
386
+ const boot = renderKnowledgeBlock(await newNode(kind), freshTranscriptTarget());
384
387
  assert.ok(!boot.includes('t9-kind-split'), `${kind} receives no kind-split entry; got:\n${boot}`);
385
388
  assert.ok(!boot.includes(B.kindSplit), `${kind} receives no kind-split body`);
386
389
  }
387
- const developer = renderKnowledgeBlock(newNode('developer'), freshTranscriptTarget());
390
+ const developer = renderKnowledgeBlock(await newNode('developer'), freshTranscriptTarget());
388
391
  assert.ok(!developer.includes('t9-document-gate-wins'), `a failing document gate excludes every entry; got:\n${developer}`);
389
392
  assert.ok(!developer.includes(B.documentGateWins), 'a failing document gate excludes its content');
390
393
  assert.ok(developer.includes(B.codeCraftIndex), 'the directory document delivers its boot content');
@@ -394,8 +397,8 @@ test('surface-entry gates select the rung by node kind while the document gate r
394
397
  // The ancestor listing, not just the doc's own directory.
395
398
  assert.match(developer, /sibling {2}# read when: When the dev sibling applies\./, `content delivery exposes the enclosing directory's members too; got:\n${developer}`);
396
399
  });
397
- test('context docs accounting reports content attachment raises from the renderer', () => {
398
- const node = newNode('developer');
400
+ test('context docs accounting reports content attachment raises from the renderer', async () => {
401
+ const node = await newNode('developer');
399
402
  const subject = assembleNodeSubject(node);
400
403
  assert.ok(subject !== null, 'the fixture node assembles a subject');
401
404
  const target = { cwd: cwdProject, profileId, nodeId: node };
@@ -431,8 +434,8 @@ test('context docs accounting reports content attachment raises from the rendere
431
434
  assert.equal(viewerRecord?.deliveryCause, 'directory listing attached to content delivery');
432
435
  plans.dispose();
433
436
  });
434
- test('context docs accounting adds full-view workspace content attachments', () => {
435
- const node = newNode();
437
+ test('context docs accounting adds full-view workspace content attachments', async () => {
438
+ const node = await newNode();
436
439
  const subject = assembleNodeSubject(node);
437
440
  assert.ok(subject !== null, 'the fixture node assembles a subject');
438
441
  const target = { cwd: outsideProject, profileId, nodeId: node };
@@ -446,8 +449,8 @@ test('context docs accounting adds full-view workspace content attachments', ()
446
449
  assert.equal(companion?.final_rung, 'content');
447
450
  assert.equal(companion?.delivery_cause, 'memory-read companion of content delivery');
448
451
  });
449
- test('boot content triggers memory-read companions to a deduplicated fixpoint', () => {
450
- const boot = renderKnowledgeBlock(newNode(), freshTranscriptTarget());
452
+ test('boot content triggers memory-read companions to a deduplicated fixpoint', async () => {
453
+ const boot = renderKnowledgeBlock(await newNode(), freshTranscriptTarget());
451
454
  for (const body of [B.companionSource, B.companionA, B.companionB]) {
452
455
  assert.equal(boot.split(body).length - 1, 1, `content companion ${body} delivers once; got:\n${boot}`);
453
456
  }
@@ -455,8 +458,8 @@ test('boot content triggers memory-read companions to a deduplicated fixpoint',
455
458
  // discloses its members exactly as the doc that routed to it did.
456
459
  assert.match(boot, /member-1 {2}# read when: When the companion member applies\./, `a content companion exposes its own directory's members; got:\n${boot}`);
457
460
  });
458
- test('one body delivered across both boot partitions renders exactly once', () => {
459
- const node = newNode();
461
+ test('one body delivered across both boot partitions renders exactly once', async () => {
462
+ const node = await newNode();
460
463
  const subject = assembleNodeSubject(node);
461
464
  assert.ok(subject !== null, 'the fixture node assembles a subject');
462
465
  const state = emptyContextExposureState();
@@ -470,8 +473,8 @@ test('one body delivered across both boot partitions renders exactly once', () =
470
473
  const occurrences = (preferences.split(B.crossPartition).length - 1) + (knowledge.split(B.crossPartition).length - 1);
471
474
  assert.equal(occurrences, 1, `the companion body renders once across both partitions; got:\n${preferences}\n---\n${knowledge}`);
472
475
  });
473
- test('a node-local doc floors to name only without boot entries', () => {
474
- const node = newNode('explore');
476
+ test('a node-local doc floors to name only without boot entries', async () => {
477
+ const node = await newNode('explore');
475
478
  writeDoc(memoryDir(node), 't9-node-local-bootless', bootlessDoc('When the node-local fallback applies', 'BODY-T9-NODE-LOCAL-BOOTLESS'));
476
479
  writeDoc(memoryDir(node), 't9-node-local-entry-gated', [
477
480
  '---',
@@ -491,8 +494,8 @@ test('a node-local doc floors to name only without boot entries', () => {
491
494
  assert.ok(!boot.includes('t9-node-local-entry-gated'), `ineligible boot entries keep a node-local doc absent; got:\n${boot}`);
492
495
  assert.ok(!boot.includes('BODY-T9-NODE-LOCAL-ENTRY-GATED'), 'ineligible boot entries disclose no body');
493
496
  });
494
- test('a `none` project contributes nothing to boot — no body, no name, no hidden count, no shadow', () => {
495
- const boot = renderKnowledgeBlock(newNode(), freshTranscriptTarget());
497
+ test('a `none` project contributes nothing to boot — no body, no name, no hidden count, no shadow', async () => {
498
+ const boot = renderKnowledgeBlock(await newNode(), freshTranscriptTarget());
496
499
  assert.ok(!boot.includes(B.pnone), 'a none-capped body must not render');
497
500
  assert.ok(!boot.includes('pnone'), 'a none-capped store must not appear as a name either — not even its namespace row');
498
501
  // Hidden counts are disclosure too: the control project's namespace row proves
@@ -512,7 +515,7 @@ test('a capped nearer candidate yields the shared identity instead of suppressin
512
515
  // physical candidates. Automatic delivery filters candidates by the profile
513
516
  // cap BEFORE dedupe, so the `none`-capped nearer one drops out and the farther
514
517
  // one delivers; a deliberate read stays winner-only on source order.
515
- const boot = renderKnowledgeBlock(newNode(), freshTranscriptTarget());
518
+ const boot = renderKnowledgeBlock(await newNode(), freshTranscriptTarget());
516
519
  assert.ok(boot.includes(B.dupFar), `the farther uncapped candidate delivers the shared identity; got:\n${boot}`);
517
520
  assert.ok(!boot.includes(B.dupNear), 'the none-capped nearer candidate delivers nothing');
518
521
  const read = (await readLeaf.run({
@@ -524,14 +527,14 @@ test('a capped nearer candidate yields the shared identity instead of suppressin
524
527
  }));
525
528
  assert.ok(read.content.includes(B.dupNear) && !read.content.includes(B.dupFar), `a deliberate read resolves the source-order winner; got:\n${read.content}`);
526
529
  });
527
- test('a non-none cap keeps its project precedence and discloses the duplicate at the capped rung', () => {
528
- const boot = renderKnowledgeBlock(newNode(), freshTranscriptTarget());
530
+ test('a non-none cap keeps its project precedence and discloses the duplicate at the capped rung', async () => {
531
+ const boot = renderKnowledgeBlock(await newNode(), freshTranscriptTarget());
529
532
  assert.match(boot, /[├└]─ t9-namedup-doc$/m, `the name-capped project discloses its doc as a bare name; got:\n${boot}`);
530
533
  assert.ok(!boot.includes(B.nameFromPname), 'a name-capped doc discloses at `name`, never its body');
531
534
  assert.ok(boot.includes(B.nameFromPcontent), 'the content project delivers its own distinct identity in full');
532
535
  });
533
- test('workspace-open clamps each project store the same way boot does', () => {
534
- const opened = renderWorkspaceOpenDocs(newNode(), freshTranscriptTarget());
536
+ test('workspace-open clamps each project store the same way boot does', async () => {
537
+ const opened = renderWorkspaceOpenDocs(await newNode(), freshTranscriptTarget());
535
538
  assert.ok(opened.includes(B.pcontent), `the content-capped project delivers its body; got:\n${opened}`);
536
539
  assert.ok(!opened.includes(B.ppreview), `the cwd project must not deliver its body; got:\n${opened}`);
537
540
  assert.match(opened, /name="ppreview\/t9-ppreview-doc" readWhen="When the cwd project delivers\./, `the cwd project delivers its preview line under its canonical name; got:\n${opened}`);
@@ -539,8 +542,8 @@ test('workspace-open clamps each project store the same way boot does', () => {
539
542
  assert.ok(!opened.includes('t9-pnone-doc'), 'the none-capped project delivers nothing at workspace-open');
540
543
  assert.ok(!opened.includes(B.sharedFromPnone), 'nor its side of a name collision');
541
544
  });
542
- test('workspace-open answers its listings from the workspace it opened, not the ambient one', () => {
543
- const node = newNode();
545
+ test('workspace-open answers its listings from the workspace it opened, not the ambient one', async () => {
546
+ const node = await newNode();
544
547
  const subject = assembleNodeSubject(node);
545
548
  assert.ok(subject !== null, 'the fixture node assembles a subject');
546
549
  // The process cwd is `ppreview`; this workspace is outside the profile
@@ -551,7 +554,7 @@ test('workspace-open answers its listings from the workspace it opened, not the
551
554
  assert.match(opened, /\[\[poutside\/t9-ws-guide\/member-1\]\]: When the outside guide member applies\./, `the listing carries that directory's own members; got:\n${opened}`);
552
555
  });
553
556
  test('memory list and find record synthetic pages without crediting matched documents', async () => {
554
- const node = newNode();
557
+ const node = await newNode();
555
558
  process.env['CRTR_NODE_ID'] = node;
556
559
  try {
557
560
  const listed = await listLeaf.run({
@@ -589,7 +592,7 @@ test('memory list and find record synthetic pages without crediting matched docu
589
592
  }
590
593
  });
591
594
  test('an explicit read after boot content adds no duplicate directory attachments', async () => {
592
- const node = newNode('developer');
595
+ const node = await newNode('developer');
593
596
  process.env['CRTR_NODE_ID'] = node;
594
597
  try {
595
598
  const state = loadContextExposureState(node);
@@ -614,7 +617,7 @@ test('an explicit read after boot content adds no duplicate directory attachment
614
617
  }
615
618
  });
616
619
  test('an explicit `crtr memory read` returns and records the full body a cap withheld', async () => {
617
- const node = newNode();
620
+ const node = await newNode();
618
621
  process.env['CRTR_NODE_ID'] = node;
619
622
  const state = loadContextExposureState(node);
620
623
  const transcript = exposureTarget(state, 'transcript');
@@ -3,8 +3,9 @@ import assert from 'node:assert/strict';
3
3
  import { mkdtempSync, rmSync, existsSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
- import { createNode, getRow, subscribe, recordPid, recordSpawn, subscribersOf, subscriptionsOf, pruneNodes, pruneToLimit, transitionStatusIntent, } from '../canvas/canvas.js';
7
- import { closeDb, openDb } from '../canvas/db.js';
6
+ import { createNode, getRow, subscribe, recordSpawn, subscribersOf, subscriptionsOf, pruneNodes, pruneToLimit, transitionStatusIntent, } from '../canvas/canvas.js';
7
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
8
+ import { beginExecution, recordExecutionPid } from '../canvas/executions.js';
8
9
  import { nodeDir } from '../canvas/paths.js';
9
10
  let home;
10
11
  const DAY = 86_400_000;
@@ -33,6 +34,10 @@ function totalEdges() {
33
34
  function markCollectibleTerminal(nodeId) {
34
35
  transitionStatusIntent(nodeId, { terminal_reason: 'closed' });
35
36
  }
37
+ function recordExecution(nodeId, pid) {
38
+ const executionId = beginExecution(nodeId, { daemonEpoch: 'test' });
39
+ recordExecutionPid(executionId, nodeId, pid);
40
+ }
36
41
  /** The standard fixture: three prunable terminal nodes (old), three survivors
37
42
  * (two old-but-live, one recent-but-dead), and edges that touch a pruned node
38
43
  * so cascade is observable. */
@@ -55,6 +60,7 @@ before(() => {
55
60
  beforeEach(() => {
56
61
  closeDb();
57
62
  rmSync(home, { recursive: true, force: true });
63
+ migrate(openDb());
58
64
  });
59
65
  after(() => {
60
66
  closeDb();
@@ -146,7 +152,7 @@ test('count pruning keeps all live nodes even when liveCount exceeds the cap', (
146
152
  // fall beyond rank 5 and are pruned.
147
153
  for (let i = 0; i < 5; i++) {
148
154
  createNode(node(`live-${i}`, { status: 'active', created: at(i) }));
149
- recordPid(`live-${i}`, process.pid); // process.pid is alive → isPidAlive true
155
+ recordExecution(`live-${i}`, process.pid); // process.pid is alive → isPidAlive true
150
156
  }
151
157
  createNode(node('old-a', { status: 'dead', created: at(100) }));
152
158
  createNode(node('old-b', { status: 'done', created: at(101) }));
@@ -164,7 +170,7 @@ test('count pruning deletes the oldest terminal nodes beyond max(cap, liveCount)
164
170
  // Ranked by recency DESC: live-0, term-0, term-1 (top 3, kept), then
165
171
  // term-2, term-3, term-4 (rank >= 3, pruned).
166
172
  createNode(node('live-0', { status: 'idle', created: at(0) }));
167
- recordPid('live-0', process.pid);
173
+ recordExecution('live-0', process.pid);
168
174
  for (let i = 0; i < 5; i++) {
169
175
  const id = `term-${i}`;
170
176
  createNode(node(id, { status: 'dead', created: at(10 + i) }));
@@ -185,7 +191,7 @@ test('count pruning deletes the oldest terminal nodes beyond max(cap, liveCount)
185
191
  });
186
192
  test('count pruning dry-run reports candidates without deleting rows or dirs', () => {
187
193
  createNode(node('live-0', { status: 'idle', created: at(0) }));
188
- recordPid('live-0', process.pid);
194
+ recordExecution('live-0', process.pid);
189
195
  for (let i = 0; i < 5; i++) {
190
196
  const id = `term-${i}`;
191
197
  createNode(node(id, { status: 'dead', created: at(10 + i) }));
@@ -4,21 +4,28 @@ import { mkdtempSync, rmSync, mkdirSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
6
  import { createNode, getNode, setStatus } from '../canvas/canvas.js';
7
- import { closeDb } from '../canvas/db.js';
7
+ import { closeDb, openDb, migrate } from '../canvas/db.js';
8
8
  import { InputError } from '../io.js';
9
9
  import { messageRoutes } from '../../daemon/api/handlers/messages.js';
10
10
  import { pushFinal, FinalizationError } from '../feed/feed.js';
11
11
  import { assertNotFinalized, assertFinalizedForReopen, commitReopen } from '../runtime/reopen.js';
12
12
  import { reviveNode } from '../runtime/revive.js';
13
13
  import { headlessBrokerHost } from '../runtime/host.js';
14
- import { readInboxSince } from '../feed/inbox.js';
14
+ function nodeMailCount(nodeId) {
15
+ return Number(openDb().prepare(`SELECT COUNT(*) AS count FROM deliveries
16
+ WHERE destination_kind = 'node_inbox' AND destination_id = ?`).get(nodeId).count);
17
+ }
15
18
  import { writeGoal } from '../runtime/kickoff.js';
16
19
  import { situationalContextPath } from '../canvas/paths.js';
17
20
  let home;
18
21
  const prevNodeId = process.env['CRTR_NODE_ID'];
19
22
  function node(id) { return { node_id: id, name: id, created: new Date().toISOString(), cwd: '/tmp/work', kind: 'general', mode: 'base', lifecycle: 'terminal', status: 'active' }; }
20
23
  before(() => { home = mkdtempSync(join(tmpdir(), 'crtr-pushfinal-')); process.env['CRTR_HOME'] = home; });
21
- beforeEach(() => { closeDb(); rmSync(home, { recursive: true, force: true }); });
24
+ beforeEach(() => {
25
+ closeDb();
26
+ rmSync(home, { recursive: true, force: true });
27
+ migrate(openDb());
28
+ });
22
29
  after(() => { closeDb(); rmSync(home, { recursive: true, force: true }); delete process.env['CRTR_HOME']; if (prevNodeId === undefined)
23
30
  delete process.env['CRTR_NODE_ID'];
24
31
  else
@@ -66,13 +73,13 @@ test('a finalized node re-tasked via node message send without --reopen is rejec
66
73
  const firstFinal = getNode(id)?.final_report;
67
74
  assert.ok(firstFinal);
68
75
  // A message to the now-finalized node, no --reopen: rejected before the
69
- // handler ever reaches appendInbox/reviveNode. Prove BOTH: the latch is
76
+ // handler ever creates a delivery or reaches reviveNode. Prove BOTH: the latch is
70
77
  // untouched, AND (per #340's Minor finding) no side effect landed first —
71
78
  // spy on the exact revive seam reviveNode calls (headlessBrokerHost.launch,
72
79
  // the same seam revive.test.ts already uses to instrument reviveNode without
73
80
  // a real engine) and assert it was never invoked, plus the inbox is
74
81
  // unchanged.
75
- const inboxBefore = readInboxSince(id, undefined).length;
82
+ const inboxBefore = nodeMailCount(id);
76
83
  const originalLaunch = headlessBrokerHost.launch;
77
84
  let launchCalls = 0;
78
85
  headlessBrokerHost.launch = ((...args) => { launchCalls++; return originalLaunch(...args); });
@@ -84,7 +91,7 @@ test('a finalized node re-tasked via node message send without --reopen is rejec
84
91
  }
85
92
  assert.equal(launchCalls, 0, 'a rejected retask must never attempt a revive');
86
93
  assert.equal(getNode(id)?.final_report, firstFinal, 'a rejected retask must not touch the latch');
87
- assert.equal(readInboxSince(id, undefined).length, inboxBefore, 'a rejected retask must not append an inbox entry');
94
+ assert.equal(nodeMailCount(id), inboxBefore, 'a rejected retask must not create a delivery');
88
95
  // The successful path, driven through the ACTUAL daemon message handler (the
89
96
  // real seam --reopen now lives behind, not a direct call into the gate
90
97
  // internals) — stub the revive seam so no real engine process is spawned,
@@ -105,7 +112,7 @@ test('a finalized node re-tasked via node message send without --reopen is rejec
105
112
  headlessBrokerHost.launch = originalLaunch;
106
113
  }
107
114
  assert.equal(getNode(id)?.final_report, null, '--reopen cleared the latch through the real handler seam');
108
- assert.equal(readInboxSince(id, undefined).length, inboxBefore + 1, 'the re-task message was actually appended to the inbox');
115
+ assert.equal(nodeMailCount(id), inboxBefore + 1, 'the re-task message created one durable delivery');
109
116
  // The re-tasked node can now finish its new mandate and re-latch cleanly.
110
117
  process.env['CRTR_NODE_ID'] = id;
111
118
  await pushFinal(id, 'round 2 verdict');
@@ -15,13 +15,19 @@ import { CrtrClient } from '../../api/client.js';
15
15
  import { createApiServer } from '../../daemon/api/server.js';
16
16
  import registerCanvasStophook from '../../pi-extensions/canvas-stophook.js';
17
17
  import { createNode, getNode, subscribe } from '../canvas/canvas.js';
18
- import { closeDb } from '../canvas/db.js';
18
+ import { beginExecution, recordExecutionPid } from '../canvas/executions.js';
19
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
20
+ import { resetScopeCache } from '../scope.js';
21
+ import { closeScopedStores } from '../scoped-state/db.js';
22
+ import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
19
23
  import { apiSocketPath } from '../canvas/paths.js';
20
24
  import { brokerCapReached, resetFleetForTests } from '../runtime/fleet.js';
21
25
  import { buildPiArgv } from '../runtime/launch.js';
22
26
  import { relaunchRoot } from '../runtime/reset.js';
23
27
  import { bindTestFleet } from './helpers/fleet.js';
24
28
  let home;
29
+ let tf;
30
+ const previousHome = process.env['HOME'];
25
31
  function node(id, over = {}) {
26
32
  return {
27
33
  node_id: id,
@@ -67,16 +73,30 @@ function makeDeps(pid) {
67
73
  }
68
74
  before(() => {
69
75
  home = mkdtempSync(join(tmpdir(), 'crtr-relaunch-'));
70
- process.env['CRTR_HOME'] = home;
76
+ process.env['HOME'] = home;
77
+ process.env['CRTR_HOME'] = join(home, 'canvas');
71
78
  });
72
79
  beforeEach(() => {
73
80
  closeDb();
81
+ closeScopedStores();
74
82
  rmSync(home, { recursive: true, force: true });
83
+ resetScopeCache();
84
+ initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
85
+ migrate(openDb());
86
+ tf = bindTestFleet();
75
87
  });
76
88
  after(() => {
77
89
  closeDb();
90
+ closeScopedStores();
91
+ tf.fleet.dispose();
92
+ resetFleetForTests();
78
93
  rmSync(home, { recursive: true, force: true });
79
94
  delete process.env['CRTR_HOME'];
95
+ if (previousHome === undefined)
96
+ delete process.env['HOME'];
97
+ else
98
+ process.env['HOME'] = previousHome;
99
+ resetScopeCache();
80
100
  });
81
101
  test('relaunchRoot parks the old root done and mints a fresh active root, reaping descendants', async () => {
82
102
  // root → child → grandchild (a parent that subscribes to its workers).
@@ -169,6 +189,10 @@ test('root /new capacity refusal reaches the attached human through broker UI no
169
189
  process.env['CRTR_NODE_ID'] = 'root';
170
190
  createNode(node('root', { parent: null, lifecycle: 'resident' }));
171
191
  const tf = bindTestFleet();
192
+ const executionId = beginExecution('root', { daemonEpoch: tf.fleet.epoch() });
193
+ assert.equal(recordExecutionPid(executionId, 'root', process.pid), 'recorded');
194
+ const previousExecutionId = process.env['CRTR_EXECUTION_ID'];
195
+ process.env['CRTR_EXECUTION_ID'] = executionId;
172
196
  const never = new Promise(() => { });
173
197
  tf.fleet.register('filler-a', { pid: 700_001, exited: never });
174
198
  tf.fleet.register('filler-b', { pid: 700_002, exited: never });
@@ -207,6 +231,10 @@ test('root /new capacity refusal reaches the attached human through broker UI no
207
231
  resetFleetForTests();
208
232
  delete process.env['CRTR_MAX_LIVE_BROKERS'];
209
233
  delete process.env['CRTR_NODE_ID'];
234
+ if (previousExecutionId === undefined)
235
+ delete process.env['CRTR_EXECUTION_ID'];
236
+ else
237
+ process.env['CRTR_EXECUTION_ID'] = previousExecutionId;
210
238
  }
211
239
  });
212
240
  test('relaunchRoot is a no-op for a non-root child and an already-parked root', async () => {
@@ -11,7 +11,9 @@ import assert from 'node:assert/strict';
11
11
  import { mkdtempSync, rmSync } from 'node:fs';
12
12
  import { tmpdir } from 'node:os';
13
13
  import { join } from 'node:path';
14
- import { readConfig, updateConfig } from '../config.js';
14
+ import { ensureScopeInitialized, readConfig, updateConfig } from '../config.js';
15
+ import { closeScopedStores } from '../scoped-state/db.js';
16
+ import { resetScopeCache } from '../scope.js';
15
17
  import { setRelayToken } from '../secrets.js';
16
18
  import { getRemoteCanvasTarget, resolveRemoteCanvasTarget } from '../remote-canvas-target.js';
17
19
  let home;
@@ -22,9 +24,13 @@ before(() => {
22
24
  process.env['HOME'] = home;
23
25
  });
24
26
  beforeEach(() => {
27
+ closeScopedStores();
25
28
  rmSync(home, { recursive: true, force: true });
29
+ resetScopeCache();
30
+ ensureScopeInitialized('user', join(home, '.crouter'));
26
31
  });
27
32
  after(() => {
33
+ closeScopedStores();
28
34
  rmSync(home, { recursive: true, force: true });
29
35
  if (realHome !== undefined)
30
36
  process.env['HOME'] = realHome;
@@ -8,9 +8,11 @@ import assert from 'node:assert/strict';
8
8
  import { mkdtempSync, mkdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
9
9
  import { tmpdir } from 'node:os';
10
10
  import { join } from 'node:path';
11
+ import { ensureScopeInitialized } from '../config.js';
11
12
  import { gitSync } from '../git.js';
12
13
  import { createProfile } from '../profiles/manifest.js';
13
14
  import { loadMemoryStoreView, memoryStoresInPrecedence, openProjectMemoryStore, resolveMemoryDocForTarget, } from '../memory-resolver.js';
15
+ import { closeScopedStores } from '../scoped-state/db.js';
14
16
  import { resetScopeCache } from '../scope.js';
15
17
  const cleanups = [];
16
18
  let previousHome;
@@ -20,8 +22,10 @@ before(() => {
20
22
  beforeEach(() => {
21
23
  process.env.HOME = fixtureDir('crtr-repository-root-identity-home-');
22
24
  resetScopeCache();
25
+ ensureScopeInitialized('user', join(process.env.HOME, '.crouter'));
23
26
  });
24
27
  after(() => {
28
+ closeScopedStores();
25
29
  resetScopeCache();
26
30
  for (const path of cleanups)
27
31
  rmSync(path, { recursive: true, force: true });
@@ -5,11 +5,13 @@
5
5
  // persona keeps the stronger default needed to synthesise a broad review.
6
6
  import { after, before, test } from 'node:test';
7
7
  import assert from 'node:assert/strict';
8
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
8
+ import { mkdirSync, mkdtempSync, rmSync } from 'node:fs';
9
9
  import { tmpdir } from 'node:os';
10
10
  import { join } from 'node:path';
11
11
  import { defaultKindsConfig, defaultModelLaddersConfig } from '../../types.js';
12
12
  import { buildLaunchSpec, normalizeModel } from '../runtime/launch.js';
13
+ import { writeRawConfig } from '../config.js';
14
+ import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
13
15
  const priorHome = process.env['HOME'];
14
16
  const ladders = defaultModelLaddersConfig();
15
17
  // Review's own kind default IS its floor — an explicit override weaker than
@@ -20,14 +22,15 @@ before(() => {
20
22
  home = mkdtempSync(join(tmpdir(), 'crtr-review-model-floor-'));
21
23
  process.env['HOME'] = home;
22
24
  mkdirSync(join(home, '.crouter'), { recursive: true });
23
- writeFileSync(join(home, '.crouter', 'config.json'), JSON.stringify({
25
+ initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
26
+ writeRawConfig('user', {
24
27
  kinds: {
25
28
  'audit/reviewers/security': {
26
29
  whenToUse: 'Review one security surface.',
27
30
  model: 'medium',
28
31
  },
29
32
  },
30
- }));
33
+ });
31
34
  });
32
35
  after(() => {
33
36
  if (priorHome === undefined)