@north-light/crouter 0.3.312 → 0.3.314

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 (497) 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 +757 -746
  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 +13 -1
  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/fresh-home-commands.test.js +49 -0
  121. package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
  122. package/dist/core/__tests__/integration/lifecycle-hooks.test.js +16 -3
  123. package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
  124. package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
  125. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
  126. package/dist/core/__tests__/integration/revive.test.js +67 -21
  127. package/dist/core/__tests__/integration/spawn-root.test.js +51 -8
  128. package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
  129. package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
  130. package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
  131. package/dist/core/__tests__/kickoff.test.js +36 -39
  132. package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
  133. package/dist/core/__tests__/lifecycle.test.js +2 -1
  134. package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
  135. package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
  136. package/dist/core/__tests__/migration.test.js +145 -31
  137. package/dist/core/__tests__/model-pin-durability.test.js +4 -1
  138. package/dist/core/__tests__/model-routes-config.test.js +13 -5
  139. package/dist/core/__tests__/node-outcome.test.js +93 -26
  140. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
  141. package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
  142. package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
  143. package/dist/core/__tests__/passive-subscription.test.js +50 -157
  144. package/dist/core/__tests__/plugin-kinds.test.js +6 -4
  145. package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
  146. package/dist/core/__tests__/plugin-page-components.test.js +6 -4
  147. package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
  148. package/dist/core/__tests__/profile-project-memory-delivery.test.js +4 -1
  149. package/dist/core/__tests__/prune.test.js +11 -5
  150. package/dist/core/__tests__/push-final-guard.test.js +14 -7
  151. package/dist/core/__tests__/relaunch-root.test.js +30 -2
  152. package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
  153. package/dist/core/__tests__/repository-root-identity.test.js +4 -0
  154. package/dist/core/__tests__/review-model-floor.test.js +6 -3
  155. package/dist/core/__tests__/revive-all.test.js +13 -3
  156. package/dist/core/__tests__/revive-capacity.test.js +26 -4
  157. package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
  158. package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
  159. package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
  160. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
  161. package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
  162. package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
  163. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
  164. package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
  165. package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
  166. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +2 -1
  167. package/dist/core/__tests__/stop-guard.test.js +2 -1
  168. package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
  169. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +18 -4
  170. package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
  171. package/dist/core/bootstrap.js +2 -0
  172. package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
  173. package/dist/core/broker-client/transport-socket.d.ts +1 -0
  174. package/dist/core/broker-client/transport-socket.js +13 -5
  175. package/dist/core/canvas/__tests__/attention.test.js +29 -35
  176. package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
  177. package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
  178. package/dist/core/canvas/attention.d.ts +2 -5
  179. package/dist/core/canvas/attention.js +15 -64
  180. package/dist/core/canvas/boot.d.ts +6 -7
  181. package/dist/core/canvas/boot.js +5 -9
  182. package/dist/core/canvas/canvas.d.ts +13 -109
  183. package/dist/core/canvas/canvas.js +140 -401
  184. package/dist/core/canvas/crons.d.ts +2 -0
  185. package/dist/core/canvas/crons.js +16 -15
  186. package/dist/core/canvas/daemon-owner.js +10 -0
  187. package/dist/core/canvas/db.d.ts +2 -2
  188. package/dist/core/canvas/db.js +2 -18
  189. package/dist/core/canvas/deliveries.d.ts +104 -0
  190. package/dist/core/canvas/deliveries.js +354 -0
  191. package/dist/core/canvas/executions.d.ts +29 -0
  192. package/dist/core/canvas/executions.js +68 -0
  193. package/dist/core/canvas/history.js +35 -35
  194. package/dist/core/canvas/index.d.ts +3 -1
  195. package/dist/core/canvas/index.js +3 -1
  196. package/dist/core/canvas/migrations.js +20 -12
  197. package/dist/core/canvas/nav-model.js +1 -3
  198. package/dist/core/canvas/nav-render.d.ts +4 -4
  199. package/dist/core/canvas/nav-render.js +11 -21
  200. package/dist/core/canvas/node-sql-migration.d.ts +3 -0
  201. package/dist/core/canvas/node-sql-migration.js +261 -0
  202. package/dist/core/canvas/paths.d.ts +2 -16
  203. package/dist/core/canvas/paths.js +2 -31
  204. package/dist/core/canvas/recovery.d.ts +76 -0
  205. package/dist/core/canvas/recovery.js +588 -0
  206. package/dist/core/canvas/remote-canvas-source.js +4 -0
  207. package/dist/core/canvas/render-source.d.ts +16 -27
  208. package/dist/core/canvas/render-source.js +16 -45
  209. package/dist/core/canvas/sessions.d.ts +33 -0
  210. package/dist/core/canvas/sessions.js +78 -0
  211. package/dist/core/canvas/types.d.ts +33 -33
  212. package/dist/core/canvas/types.js +2 -5
  213. package/dist/core/canvas/waits.d.ts +18 -0
  214. package/dist/core/canvas/waits.js +70 -0
  215. package/dist/core/canvas/worktrees.d.ts +40 -0
  216. package/dist/core/canvas/worktrees.js +93 -0
  217. package/dist/core/command.js +11 -0
  218. package/dist/core/config.d.ts +17 -12
  219. package/dist/core/config.js +106 -155
  220. package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
  221. package/dist/core/feed/feed.d.ts +0 -6
  222. package/dist/core/feed/feed.js +68 -56
  223. package/dist/core/feed/inbox.d.ts +7 -81
  224. package/dist/core/feed/inbox.js +46 -378
  225. package/dist/core/feed/messages.d.ts +58 -0
  226. package/dist/core/feed/messages.js +217 -0
  227. package/dist/core/fs-utils.d.ts +4 -0
  228. package/dist/core/fs-utils.js +21 -1
  229. package/dist/core/human/answer.d.ts +1 -1
  230. package/dist/core/human/answer.js +1 -1
  231. package/dist/core/human/claim.d.ts +1 -1
  232. package/dist/core/human/claim.js +2 -4
  233. package/dist/core/human/component-docs.js +1 -1
  234. package/dist/core/human/feedback-companion.js +3 -2
  235. package/dist/core/human/feedback.d.ts +5 -8
  236. package/dist/core/human/feedback.js +57 -85
  237. package/dist/core/human/page-authoring.d.ts +30 -0
  238. package/dist/core/human/page-authoring.js +19 -0
  239. package/dist/core/human/requests.d.ts +136 -0
  240. package/dist/core/human/requests.js +515 -0
  241. package/dist/core/human/root.d.ts +0 -7
  242. package/dist/core/human/root.js +0 -17
  243. package/dist/core/human/scan.d.ts +2 -7
  244. package/dist/core/human/scan.js +48 -132
  245. package/dist/core/human/summary.d.ts +1 -1
  246. package/dist/core/human/summary.js +1 -1
  247. package/dist/core/human/tickets.d.ts +23 -83
  248. package/dist/core/human/tickets.js +92 -243
  249. package/dist/core/human/types.d.ts +5 -1
  250. package/dist/core/installed-plugins.js +8 -3
  251. package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
  252. package/dist/core/locked-file.d.ts +6 -3
  253. package/dist/core/locked-file.js +36 -9
  254. package/dist/core/memory/extensions.js +2 -0
  255. package/dist/core/preview-registry.js +0 -1
  256. package/dist/core/profiles/__tests__/env-store.test.js +2 -0
  257. package/dist/core/profiles/default-binding.d.ts +0 -4
  258. package/dist/core/profiles/default-binding.js +12 -58
  259. package/dist/core/profiles/env-store.js +8 -3
  260. package/dist/core/profiles/manifest.d.ts +2 -37
  261. package/dist/core/profiles/manifest.js +35 -161
  262. package/dist/core/profiles/select.js +3 -0
  263. package/dist/core/review/__tests__/capture-origin.test.js +13 -2
  264. package/dist/core/review/__tests__/comments.test.js +28 -10
  265. package/dist/core/review/__tests__/remap.test.js +28 -10
  266. package/dist/core/review/__tests__/stage-identity.test.js +17 -7
  267. package/dist/core/review/birth.d.ts +1 -1
  268. package/dist/core/review/birth.js +34 -5
  269. package/dist/core/review/comments.js +1 -1
  270. package/dist/core/review/document.js +1 -1
  271. package/dist/core/review/project.d.ts +5 -1
  272. package/dist/core/review/project.js +14 -36
  273. package/dist/core/review/realize.d.ts +3 -6
  274. package/dist/core/review/realize.js +51 -168
  275. package/dist/core/review/remap.js +1 -1
  276. package/dist/core/review/stage.d.ts +3 -2
  277. package/dist/core/review/stage.js +2 -3
  278. package/dist/core/review/store.d.ts +3 -21
  279. package/dist/core/review/store.js +140 -186
  280. package/dist/core/review/types.d.ts +0 -1
  281. package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
  282. package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
  283. package/dist/core/runtime/broker/auth-reload.js +9 -10
  284. package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
  285. package/dist/core/runtime/broker/daemon-ops.js +42 -9
  286. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  287. package/dist/core/runtime/broker/extension-abort.js +11 -0
  288. package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
  289. package/dist/core/runtime/broker/fault-retry.js +142 -95
  290. package/dist/core/runtime/broker/inbox.d.ts +4 -32
  291. package/dist/core/runtime/broker/inbox.js +4 -92
  292. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  293. package/dist/core/runtime/broker/rebind.js +21 -12
  294. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  295. package/dist/core/runtime/broker-persona-guidance.js +2 -13
  296. package/dist/core/runtime/broker.js +28 -22
  297. package/dist/core/runtime/close.d.ts +3 -9
  298. package/dist/core/runtime/close.js +16 -27
  299. package/dist/core/runtime/fault.d.ts +3 -93
  300. package/dist/core/runtime/fault.js +9 -419
  301. package/dist/core/runtime/kickoff.d.ts +3 -6
  302. package/dist/core/runtime/kickoff.js +12 -18
  303. package/dist/core/runtime/launch.js +1 -1
  304. package/dist/core/runtime/lifecycle.js +40 -7
  305. package/dist/core/runtime/placement.js +2 -2
  306. package/dist/core/runtime/recycle.js +8 -2
  307. package/dist/core/runtime/reset.js +22 -6
  308. package/dist/core/runtime/revive.js +226 -218
  309. package/dist/core/runtime/spawn.js +14 -3
  310. package/dist/core/scoped-state/db.d.ts +18 -0
  311. package/dist/core/scoped-state/db.js +135 -0
  312. package/dist/core/scoped-state/migrate.d.ts +8 -0
  313. package/dist/core/scoped-state/migrate.js +181 -0
  314. package/dist/core/scoped-state/paths.d.ts +9 -0
  315. package/dist/core/scoped-state/paths.js +27 -0
  316. package/dist/core/scoped-state/profiles.d.ts +12 -0
  317. package/dist/core/scoped-state/profiles.js +62 -0
  318. package/dist/core/scoped-state/providers.d.ts +16 -0
  319. package/dist/core/scoped-state/providers.js +8 -0
  320. package/dist/core/scoped-state/schema.d.ts +3 -0
  321. package/dist/core/scoped-state/schema.js +26 -0
  322. package/dist/core/scoped-state/settings.d.ts +28 -0
  323. package/dist/core/scoped-state/settings.js +82 -0
  324. package/dist/core/subscription-state.d.ts +29 -48
  325. package/dist/core/subscription-state.js +176 -712
  326. package/dist/core/worktree-close.js +4 -4
  327. package/dist/core/worktree-mutation-async.js +2 -2
  328. package/dist/core/worktree-sweep.js +11 -16
  329. package/dist/core/worktree.js +6 -12
  330. package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
  331. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
  332. package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
  333. package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
  334. package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
  335. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +39 -15
  336. package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
  337. package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
  338. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
  339. package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
  340. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
  341. package/dist/daemon/api/__tests__/model-config.test.js +8 -8
  342. package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
  343. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
  344. package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
  345. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +4 -1
  346. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
  347. package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
  348. package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
  349. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
  350. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
  351. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +27 -41
  352. package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
  353. package/dist/daemon/api/bridge.js +1 -1
  354. package/dist/daemon/api/handlers/bash-jobs.js +6 -7
  355. package/dist/daemon/api/handlers/broker-ops.js +47 -84
  356. package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
  357. package/dist/daemon/api/handlers/broker-recovery.js +251 -0
  358. package/dist/daemon/api/handlers/canvas.js +2 -44
  359. package/dist/daemon/api/handlers/daemon.js +41 -0
  360. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  361. package/dist/daemon/api/handlers/health.js +10 -5
  362. package/dist/daemon/api/handlers/human-requests.js +168 -188
  363. package/dist/daemon/api/handlers/human.js +3 -151
  364. package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
  365. package/dist/daemon/api/handlers/inbox-page.js +89 -0
  366. package/dist/daemon/api/handlers/inbox.js +21 -120
  367. package/dist/daemon/api/handlers/messages.d.ts +1 -0
  368. package/dist/daemon/api/handlers/messages.js +73 -15
  369. package/dist/daemon/api/handlers/node-outcomes.js +58 -13
  370. package/dist/daemon/api/handlers/nodes.js +7 -13
  371. package/dist/daemon/api/handlers/reviews.js +4 -29
  372. package/dist/daemon/api/map.d.ts +25 -3
  373. package/dist/daemon/api/map.js +84 -14
  374. package/dist/daemon/api/server.js +68 -9
  375. package/dist/daemon/control.d.ts +18 -0
  376. package/dist/daemon/cron/disposition.d.ts +2 -0
  377. package/dist/daemon/cron/disposition.js +8 -5
  378. package/dist/daemon/cron/settle.js +37 -13
  379. package/dist/daemon/cron/sinks.d.ts +18 -1
  380. package/dist/daemon/cron/sinks.js +47 -93
  381. package/dist/daemon/crtrd-cli.js +4 -19
  382. package/dist/daemon/crtrd.d.ts +2 -0
  383. package/dist/daemon/crtrd.js +206 -81
  384. package/dist/daemon/fleet.js +5 -6
  385. package/dist/daemon/human/finish.d.ts +12 -24
  386. package/dist/daemon/human/finish.js +88 -285
  387. package/dist/daemon/human/settle.d.ts +40 -0
  388. package/dist/daemon/human/settle.js +89 -0
  389. package/dist/daemon/human/sweep.d.ts +20 -5
  390. package/dist/daemon/human/sweep.js +56 -60
  391. package/dist/daemon/manage.d.ts +21 -16
  392. package/dist/daemon/manage.js +85 -51
  393. package/dist/daemon/messaging/node-message.d.ts +1 -1
  394. package/dist/daemon/messaging/node-message.js +9 -12
  395. package/dist/daemon/park-activity.js +3 -3
  396. package/dist/daemon/reconcilers/bash-deadline.js +6 -7
  397. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  398. package/dist/daemon/reconcilers/broker-supervision.js +41 -19
  399. package/dist/daemon/reconcilers/controller-death.js +6 -18
  400. package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
  401. package/dist/daemon/reconcilers/delivery-lane.js +130 -0
  402. package/dist/daemon/reconcilers/live-obligation.js +3 -3
  403. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  404. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
  405. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
  406. package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
  407. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  408. package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
  409. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
  410. package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
  411. package/dist/daemon/review/companion.js +5 -11
  412. package/dist/daemon/review/deliver.d.ts +1 -5
  413. package/dist/daemon/review/deliver.js +3 -52
  414. package/dist/daemon/review/finish.d.ts +2 -27
  415. package/dist/daemon/review/finish.js +79 -263
  416. package/dist/daemon/review/sweep.d.ts +3 -10
  417. package/dist/daemon/review/sweep.js +13 -131
  418. package/dist/daemon/startup-policy.d.ts +0 -5
  419. package/dist/daemon/startup-policy.js +0 -5
  420. package/dist/index.d.ts +2 -1
  421. package/dist/index.js +1 -1
  422. package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
  423. package/dist/migrations/__tests__/activation.test.js +9 -6
  424. package/dist/migrations/activation.d.ts +3 -2
  425. package/dist/migrations/activation.js +2 -4
  426. package/dist/migrations/corpus.d.ts +2 -5
  427. package/dist/migrations/corpus.js +9 -20
  428. package/dist/migrations/runner.d.ts +3 -1
  429. package/dist/migrations/runner.js +6 -2
  430. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
  431. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
  432. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
  433. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
  434. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
  435. package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
  436. package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
  437. package/dist/pi-extensions/canvas-passive-context.js +85 -37
  438. package/dist/pi-extensions/canvas-stophook.js +47 -31
  439. package/dist/shared/env.d.ts +1 -0
  440. package/dist/shared/env.js +3 -0
  441. package/package.json +1 -1
  442. package/runtime.lock.json +5 -5
  443. package/dist/clients/attach/__tests__/page-block.test.js +0 -54
  444. package/dist/clients/inbox/review-visibility.d.ts +0 -5
  445. package/dist/clients/inbox/review-visibility.js +0 -19
  446. package/dist/commands/canvas-rebuild-index.d.ts +0 -2
  447. package/dist/commands/canvas-rebuild-index.js +0 -46
  448. package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
  449. package/dist/core/__tests__/human-deliver.test.js +0 -256
  450. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
  451. package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
  452. package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
  453. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
  454. package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
  455. package/dist/core/__tests__/phase4-review-store.test.js +0 -144
  456. package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
  457. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
  458. package/dist/core/canvas/human-deliveries.d.ts +0 -39
  459. package/dist/core/canvas/human-deliveries.js +0 -75
  460. package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
  461. package/dist/core/canvas/node-outcome-deliveries.js +0 -159
  462. package/dist/core/feed/passive.d.ts +0 -3
  463. package/dist/core/feed/passive.js +0 -53
  464. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
  465. package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
  466. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
  467. package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
  468. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
  469. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
  470. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
  471. package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
  472. package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
  473. package/dist/core/human/__tests__/page-tickets.test.js +0 -161
  474. package/dist/core/review/ticket-filter.d.ts +0 -17
  475. package/dist/core/review/ticket-filter.js +0 -21
  476. package/dist/core/runtime/broker/passive.d.ts +0 -17
  477. package/dist/core/runtime/broker/passive.js +0 -44
  478. package/dist/core/runtime/busy.d.ts +0 -46
  479. package/dist/core/runtime/busy.js +0 -150
  480. package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
  481. package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
  482. package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
  483. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
  484. package/dist/daemon/human/deliver-action.d.ts +0 -3
  485. package/dist/daemon/human/deliver-action.js +0 -9
  486. package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
  487. package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
  488. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
  489. package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
  490. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
  491. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
  492. package/dist/daemon/startup-block-marker.d.ts +0 -25
  493. package/dist/daemon/startup-block-marker.js +0 -99
  494. /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
  495. /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
  496. /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
  497. /package/dist/core/__tests__/{human-deliver.test.d.ts → integration/fresh-home-commands.test.d.ts} +0 -0
@@ -5,27 +5,26 @@
5
5
  import { test, before, after, beforeEach, afterEach } from 'node:test';
6
6
  import assert from 'node:assert/strict';
7
7
  import { existsSync, mkdtempSync, mkdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
8
- import { createServer } from 'node:http';
9
8
  import { tmpdir } from 'node:os';
10
9
  import { join } from 'node:path';
11
10
  import { registerCanvasContextIntro, CONTEXT_INTRO_CUSTOM_TYPE, } from '../canvas-context-intro.js';
12
11
  import { registerCanvasDocSubstrate } from '../canvas-doc-substrate.js';
13
12
  import { buildContextBearings as buildContextIntro } from '../../core/runtime/bearings.js';
14
13
  import { installPersonaTransitionGate } from '../../core/runtime/broker-persona-guidance.js';
15
- import { FaultRetry } from '../../core/runtime/broker/fault-retry.js';
16
- import { readFault } from '../../core/runtime/fault.js';
17
- import { ApiError } from '../../api/errors.js';
18
14
  import { createNode, deleteNode, getNode, updateNode } from '../../core/canvas/canvas.js';
19
15
  import { apiSocketPath } from '../../core/canvas/paths.js';
20
16
  import { createApiServer } from '../../daemon/api/server.js';
21
- import { closeDb } from '../../core/canvas/db.js';
17
+ import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
18
+ import { beginExecution } from '../../core/canvas/executions.js';
22
19
  import { resetScopeCache } from '../../core/scope.js';
20
+ import { initializeFreshScopedStore } from '../../core/scoped-state/migrate.js';
23
21
  import { clearSessionCache } from '../../core/substrate/session-cache.js';
24
22
  import { emptyContextExposureState, exposureTarget, initializeForkContextExposure, loadContextExposureState, registerExposure, saveContextExposureState, } from '../../core/substrate/injected-store.js';
25
23
  let home;
26
24
  let origCwd;
27
25
  let origHome;
28
26
  let origNode;
27
+ let origExecution;
29
28
  let origProfile;
30
29
  let server;
31
30
  async function waitForSocket(path) {
@@ -36,22 +35,9 @@ async function waitForSocket(path) {
36
35
  }
37
36
  throw new Error(`api socket never bound at ${path}`);
38
37
  }
39
- async function listenUnavailableApi(path) {
40
- const unavailable = createServer((_request, response) => {
41
- response.writeHead(503, { 'content-type': 'application/json' });
42
- response.end(JSON.stringify({ error: { code: 'daemon_unavailable', message: 'local daemon connection refused' } }));
43
- });
44
- await new Promise((resolve, reject) => {
45
- unavailable.once('error', reject);
46
- unavailable.listen(path, () => {
47
- unavailable.off('error', reject);
48
- resolve();
49
- });
50
- });
51
- return unavailable;
52
- }
53
- function closeHttpServer(server) {
54
- return new Promise((resolve, reject) => server.close((error) => error === undefined ? resolve() : reject(error)));
38
+ function activateBroker(id) {
39
+ process.env['CRTR_NODE_ID'] = id;
40
+ process.env['CRTR_EXECUTION_ID'] = beginExecution(id, { daemonEpoch: null });
55
41
  }
56
42
  function node(id, over = {}) {
57
43
  return {
@@ -102,6 +88,7 @@ before(() => {
102
88
  origCwd = process.cwd();
103
89
  origHome = process.env['HOME'];
104
90
  origNode = process.env['CRTR_NODE_ID'];
91
+ origExecution = process.env['CRTR_EXECUTION_ID'];
105
92
  origProfile = process.env['CRTR_PROFILE_ID'];
106
93
  });
107
94
  beforeEach(async () => {
@@ -116,9 +103,12 @@ beforeEach(async () => {
116
103
  process.env['HOME'] = userHome;
117
104
  process.env['CRTR_HOME'] = home;
118
105
  delete process.env['CRTR_NODE_ID'];
106
+ delete process.env['CRTR_EXECUTION_ID'];
119
107
  delete process.env['CRTR_PROFILE_ID'];
120
108
  resetScopeCache();
121
109
  clearSessionCache();
110
+ initializeFreshScopedStore({ kind: 'user', root: join(userHome, '.crouter') });
111
+ migrate(openDb());
122
112
  server = createApiServer();
123
113
  await waitForSocket(apiSocketPath());
124
114
  });
@@ -146,6 +136,10 @@ after(() => {
146
136
  delete process.env['CRTR_NODE_ID'];
147
137
  else
148
138
  process.env['CRTR_NODE_ID'] = origNode;
139
+ if (origExecution === undefined)
140
+ delete process.env['CRTR_EXECUTION_ID'];
141
+ else
142
+ process.env['CRTR_EXECUTION_ID'] = origExecution;
149
143
  if (origProfile === undefined)
150
144
  delete process.env['CRTR_PROFILE_ID'];
151
145
  else
@@ -167,7 +161,7 @@ test('session_start appends compact fork bearings after an inherited source base
167
161
  const forkExposure = loadContextExposureState('forkB');
168
162
  assert.deepEqual(forkExposure.exposures.get('inherited-source-document'), { transcript: 3 }, 'a pre-bind retry preserves the transcript exposure seed after its source disappears');
169
163
  assert.equal(forkExposure.exposures.has('source-system-only'), false, 'a fork never inherits source system exposure');
170
- process.env['CRTR_NODE_ID'] = 'forkB';
164
+ activateBroker('forkB');
171
165
  const pi = makeFakePi();
172
166
  registerCanvasContextIntro(pi);
173
167
  await pi.fireSessionStart([inheritedSourceBlock]);
@@ -184,7 +178,7 @@ test('session_start appends compact fork bearings after an inherited source base
184
178
  const unknownPreState = loadContextExposureState('unknownF');
185
179
  assert.equal(unknownPreState.exposures.size, 0);
186
180
  assert.equal(unknownPreState.preferenceSnapshot, null);
187
- process.env['CRTR_NODE_ID'] = 'unknownF';
181
+ activateBroker('unknownF');
188
182
  const unknownPi = makeFakePi();
189
183
  registerCanvasContextIntro(unknownPi);
190
184
  await unknownPi.fireSessionStart([inheritedSourceBlock]);
@@ -202,7 +196,7 @@ test('root /new leaves baseline assembly to the replacement broker', async () =>
202
196
  exposure.preferenceSnapshot = 'ORIGINAL-SNAPSHOT';
203
197
  registerExposure(exposureTarget(exposure, 'transcript'), 'original-transcript', 'content');
204
198
  saveContextExposureState('root-new', exposure);
205
- process.env['CRTR_NODE_ID'] = 'root-new';
199
+ activateBroker('root-new');
206
200
  const pi = makeFakePi();
207
201
  registerCanvasContextIntro(pi);
208
202
  await pi.fireSessionStart([], 'new');
@@ -240,7 +234,7 @@ test('child /new commits its baseline before ack and the provider gate delivers
240
234
  persona_ack: oldPersona,
241
235
  }));
242
236
  mkdirSync(join(home, 'nodes', 'new-child'), { recursive: true });
243
- process.env['CRTR_NODE_ID'] = 'new-child';
237
+ activateBroker('new-child');
244
238
  const sessionStartHandlers = [];
245
239
  const sent = [];
246
240
  const branch = [];
@@ -343,68 +337,6 @@ test('child /new commits its baseline before ack and the provider gate delivers
343
337
  process.env['CRTR_PROFILE_ID'] = previousProfile;
344
338
  }
345
339
  });
346
- test('a typed local API error remains a retryable broker-to-daemon fault after settlement', async () => {
347
- createNode(node('persona-transport', {
348
- persona_ack: { kind: 'review', mode: 'base', lifecycle: 'terminal' },
349
- }));
350
- await server.close();
351
- let unavailable;
352
- try {
353
- unavailable = await listenUnavailableApi(apiSocketPath());
354
- const messages = [];
355
- const agent = {
356
- state: { messages },
357
- transformContext: async (context) => context,
358
- };
359
- installPersonaTransitionGate('persona-transport', {
360
- agent,
361
- sessionManager: {
362
- appendCustomMessageEntry: () => undefined,
363
- },
364
- });
365
- await assert.rejects(() => agent.transformContext([{ role: 'user', content: 'continue' }]), (error) => error instanceof ApiError && error.status === 503 && error.code === 'daemon_unavailable');
366
- assert.deepEqual(readFault('persona-transport'), {
367
- link: 'broker↔crtrd',
368
- op: 'persona transition',
369
- kind: 'connection',
370
- retry: { disposition: 'manual' },
371
- message: 'local daemon connection refused',
372
- since: readFault('persona-transport')?.since,
373
- operation_id: readFault('persona-transport')?.operation_id,
374
- }, 'the typed daemon transport error is recorded before Pi turns it into a generic agent error');
375
- const session = {
376
- sessionManager: { getLeafId: () => 'persona-transport-leaf' },
377
- model: undefined,
378
- };
379
- const generation = {
380
- id: 1,
381
- session,
382
- fallback: { blocked: false },
383
- stagedProviderAgentEnd: {
384
- messages: [{ role: 'assistant', stopReason: 'error', errorMessage: 'local daemon connection refused' }],
385
- },
386
- stagedWatchdogAbort: false,
387
- stagedRefreshAbort: false,
388
- stagedOverflowFailure: null,
389
- executingTools: new Set(),
390
- };
391
- new FaultRetry({
392
- nodeId: 'persona-transport',
393
- currentSession: () => session,
394
- installedGeneration: () => generation,
395
- }).publishSettledProviderFault(generation);
396
- const fault = readFault('persona-transport');
397
- assert.equal(fault?.link, 'broker↔crtrd');
398
- assert.equal(fault?.kind, 'connection');
399
- assert.equal(fault?.retry.disposition, 'manual');
400
- }
401
- finally {
402
- if (unavailable !== undefined)
403
- await closeHttpServer(unavailable);
404
- server = createApiServer();
405
- await waitForSocket(apiSocketPath());
406
- }
407
- });
408
340
  test('resume idempotency uses the exact details stamp independent of block text', async () => {
409
341
  createNode(node('stampD'));
410
342
  // The exact node-id stamp is authoritative even when prose carries no id.
@@ -414,7 +346,7 @@ test('resume idempotency uses the exact details stamp independent of block text'
414
346
  content: '<crtr-context dir="/elsewhere">bearings with no id in the text</crtr-context>',
415
347
  details: { nodeId: 'stampD' },
416
348
  };
417
- process.env['CRTR_NODE_ID'] = 'stampD';
349
+ activateBroker('stampD');
418
350
  const pi = makeFakePi();
419
351
  registerCanvasContextIntro(pi);
420
352
  await pi.fireSessionStart([stampedNoIdInText]);
@@ -424,7 +356,7 @@ test('session_start stays idempotent on a genuine resume', async () => {
424
356
  createNode(node('resumeC'));
425
357
  // A resume restores this node's already-stamped bearings.
426
358
  const ownBlock = introEntry(buildContextIntro('resumeC'));
427
- process.env['CRTR_NODE_ID'] = 'resumeC';
359
+ activateBroker('resumeC');
428
360
  const pi = makeFakePi();
429
361
  registerCanvasContextIntro(pi);
430
362
  await pi.fireSessionStart([ownBlock]);
@@ -22,9 +22,10 @@ import { tmpdir } from 'node:os';
22
22
  import { join } from 'node:path';
23
23
  import registerCanvasGoalCapture from '../canvas-goal-capture.js';
24
24
  import { createNode } from '../../core/canvas/canvas.js';
25
- import { closeDb } from '../../core/canvas/db.js';
25
+ import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
26
26
  import { apiSocketPath } from '../../core/canvas/paths.js';
27
27
  import { buildReviveKickoff, drainBearings } from '../../core/runtime/kickoff.js';
28
+ import { beginExecution } from '../../core/canvas/executions.js';
28
29
  let home;
29
30
  let socket;
30
31
  /** Every request line the extension's naming path sent to the daemon socket. */
@@ -62,6 +63,7 @@ async function waitForRequestMentioning(id) {
62
63
  before(async () => {
63
64
  home = mkdtempSync(join(tmpdir(), 'crtr-goal-capture-'));
64
65
  process.env['CRTR_HOME'] = home;
66
+ migrate(openDb());
65
67
  // A stub daemon: it records the request and answers a typed error, so the
66
68
  // naming path fails fast (and silently, as it must) without any model call.
67
69
  // It must ANSWER rather than hang up — the api client reads a mid-request
@@ -89,7 +91,7 @@ after(async () => {
89
91
  });
90
92
  test('a fresh-revive kickoff seeds no mandate and no name; a human first message seeds both', async () => {
91
93
  const revived = createNode(node('revived-node'));
92
- const kickoff = buildReviveKickoff(revived, drainBearings(revived));
94
+ const kickoff = buildReviveKickoff(revived, drainBearings(revived, beginExecution(revived.node_id, { daemonEpoch: 'test' })));
93
95
  process.env['CRTR_NODE_ID'] = revived.node_id;
94
96
  handler()({ type: 'input', text: kickoff, source: 'interactive' });
95
97
  const bare = createNode(node('bare-root'));
@@ -17,20 +17,26 @@ import { join } from 'node:path';
17
17
  import registerCanvasStophook from '../canvas-stophook.js';
18
18
  import { createNode, subscribe, getNode, setStatus } from '../../core/canvas/canvas.js';
19
19
  import { openFocusRow, getFocusByNode, getFocusById, listFocuses } from '../../core/canvas/focuses.js';
20
- import { closeDb } from '../../core/canvas/db.js';
20
+ import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
21
21
  import { apiSocketPath } from '../../core/canvas/paths.js';
22
22
  import { createApiServer } from '../../daemon/api/server.js';
23
23
  import { CrtrClient } from '../../api/client.js';
24
24
  import { reportsDir } from '../../core/canvas/paths.js';
25
- import { readInboxSince, appendInbox } from '../../core/feed/inbox.js';
25
+ import { enqueueNodeMail } from '../../core/feed/messages.js';
26
+ import { hasUnseenWakeMail } from '../../core/canvas/deliveries.js';
26
27
  import { STALL_REPROMPT } from '../../core/runtime/stop-guard.js';
27
28
  import { markStopSignal } from '../../core/runtime/stop-signals.js';
28
- import { isBusy } from '../../core/runtime/busy.js';
29
- import { recordFault, readFault } from '../../core/runtime/fault.js';
29
+ import { readFault, readLiveTurn, recordFault } from '../../core/canvas/recovery.js';
30
+ import { beginExecution } from '../../core/canvas/executions.js';
30
31
  let home;
31
32
  let server;
32
33
  let origNode;
34
+ let origExecution;
33
35
  let origPane;
36
+ function activateBroker(nodeId) {
37
+ process.env['CRTR_NODE_ID'] = nodeId;
38
+ process.env['CRTR_EXECUTION_ID'] = beginExecution(nodeId, { daemonEpoch: null });
39
+ }
34
40
  function node(id, over = {}) {
35
41
  return {
36
42
  node_id: id,
@@ -54,6 +60,9 @@ function makeFakePi() {
54
60
  };
55
61
  }
56
62
  async function settle(pi, event, ctx) {
63
+ const nodeId = process.env['CRTR_NODE_ID'];
64
+ if (nodeId !== undefined && process.env['CRTR_EXECUTION_ID'] === undefined && getNode(nodeId) !== null)
65
+ activateBroker(nodeId);
57
66
  await pi.fire('agent_end', event, ctx);
58
67
  await pi.fire('agent_settled', { type: 'agent_settled' }, ctx);
59
68
  }
@@ -68,6 +77,7 @@ function reportCount(id) {
68
77
  }
69
78
  before(() => {
70
79
  origNode = process.env['CRTR_NODE_ID'];
80
+ origExecution = process.env['CRTR_EXECUTION_ID'];
71
81
  origPane = process.env['TMUX_PANE'];
72
82
  });
73
83
  async function waitForSocket() {
@@ -92,11 +102,13 @@ beforeEach(async () => {
92
102
  rmSync(home, { recursive: true, force: true });
93
103
  home = mkdtempSync(join(tmpdir(), 'crtr-stophook-end-'));
94
104
  process.env['CRTR_HOME'] = home;
105
+ migrate(openDb());
95
106
  server = createApiServer();
96
107
  await waitForSocket();
97
108
  // Force the clean-shutdown path (no in-place respawn) so the refresh test is
98
109
  // deterministic even when the suite runs inside a tmux pane.
99
110
  delete process.env['TMUX_PANE'];
111
+ delete process.env['CRTR_EXECUTION_ID'];
100
112
  });
101
113
  afterEach(async () => {
102
114
  await server?.close();
@@ -112,6 +124,10 @@ after(() => {
112
124
  delete process.env['CRTR_NODE_ID'];
113
125
  else
114
126
  process.env['CRTR_NODE_ID'] = origNode;
127
+ if (origExecution === undefined)
128
+ delete process.env['CRTR_EXECUTION_ID'];
129
+ else
130
+ process.env['CRTR_EXECUTION_ID'] = origExecution;
115
131
  if (origPane === undefined)
116
132
  delete process.env['TMUX_PANE'];
117
133
  else
@@ -123,7 +139,7 @@ test('natural stop commits idle-release only at agent_settled', { timeout: 1_000
123
139
  createNode(node('worker', { parent: 'mgr', lifecycle: 'terminal', status: 'active' }));
124
140
  subscribe('root', 'mgr', true); // root would receive any push mgr emits
125
141
  subscribe('mgr', 'worker', true); // mgr holds an active live subscription → "awaiting"
126
- process.env['CRTR_NODE_ID'] = 'mgr';
142
+ activateBroker('mgr');
127
143
  const pi = makeFakePi();
128
144
  registerCanvasStophook(pi);
129
145
  let shutdown = false;
@@ -131,51 +147,50 @@ test('natural stop commits idle-release only at agent_settled', { timeout: 1_000
131
147
  await pi.fire('agent_start', { type: 'agent_start' }, ctx);
132
148
  await pi.fire('agent_end', stopEvent('still waiting on the worker'), ctx);
133
149
  assert.equal(getNode('mgr')?.status, 'active', 'agent_end is staging-only');
134
- assert.equal(isBusy('mgr'), true, 'agent_end cannot clear whole-run busy state');
150
+ assert.equal(readLiveTurn('mgr')?.busy, true, 'agent_end cannot close the active turn');
135
151
  assert.equal(shutdown, false, 'agent_end cannot route a natural stop');
136
152
  await pi.fire('agent_settled', { type: 'agent_settled' }, ctx);
137
153
  const m = getNode('mgr');
138
- assert.equal(isBusy('mgr'), false, 'agent_settled clears whole-run busy state');
154
+ assert.equal(readLiveTurn('mgr')?.busy, false, 'agent_settled closes the active turn');
139
155
  assert.equal(m?.intent, 'idle-release', 'mgr idle-released');
140
156
  assert.equal(m?.status, 'idle', 'mgr marked idle');
141
157
  assert.equal(shutdown, true, 'pi shut down');
142
158
  assert.equal(reportCount('mgr'), 0, 'NO report file written');
143
- assert.equal(readInboxSince('root').length, 0, 'NO inbox pointer fanned to subscriber');
159
+ assert.equal(hasUnseenWakeMail('root'), false, 'NO SQL inbox delivery fanned to subscriber');
144
160
  assert.equal(pi.injected.length, 0, 'no reprompt on a legitimate idle-release');
145
161
  // §5.1 case 6 (awaiting + UNFOCUSED → idle-release, no focus): the awaiting
146
162
  // branch must never create/touch a focus row. Non-vacuous: an impl that ran
147
163
  // the done-branch handoff/openFocus on an idle-release would leave a row here.
148
164
  assert.equal(listFocuses().length, 0, 'awaiting+unfocused leaves the focuses table empty');
149
165
  });
150
- test('gh-451: idle-release does NOT release while a non-deferred inbox entry sits past the cursor', { timeout: 1_000 }, async () => {
166
+ test('gh-451: idle-release does NOT release while a non-deferred SQL delivery is pending', { timeout: 1_000 }, async () => {
151
167
  // Reproduces the #451 race: a subscriber's push landed in mgr's inbox but the
152
- // in-process watcher has not yet flushed/committed the durable cursor past it
153
- // (its DEBOUNCE_MS hold). If this settle released anyway, the daemon would
154
- // immediately re-wake mgr on the very entry the watcher was mid-delivery on.
168
+ // in-process watcher has not yet claimed and acknowledged its SQL delivery.
169
+ // If this settle released anyway, the daemon would immediately re-wake mgr on
170
+ // the delivery the watcher was mid-handoff on.
155
171
  createNode(node('root', { parent: null, lifecycle: 'resident' }));
156
172
  createNode(node('mgr', { parent: 'root', lifecycle: 'terminal', mode: 'orchestrator' }));
157
173
  createNode(node('worker', { parent: 'mgr', lifecycle: 'terminal', status: 'active' }));
158
174
  subscribe('root', 'mgr', true);
159
175
  subscribe('mgr', 'worker', true); // mgr awaits a live worker → would idle-release once caught up
160
- // A push landed in mgr's own inbox, strictly after its (unset) cursor —
161
- // exactly the pre-flush window the watcher hasn't committed yet.
162
- appendInbox('mgr', { from: 'worker', tier: 'normal', kind: 'update', label: 'worker made progress' });
176
+ // A push landed in mgr's SQL inbox delivery set, before the watcher claims it.
177
+ enqueueNodeMail('mgr', { senderNodeId: 'worker', kind: 'update', label: 'worker made progress', urgency: 'normal', wake: 1 });
163
178
  process.env['CRTR_NODE_ID'] = 'mgr';
164
179
  const pi = makeFakePi();
165
180
  registerCanvasStophook(pi);
166
181
  let shutdown = false;
167
182
  const ctx = { shutdown: () => { shutdown = true; } };
168
183
  await settle(pi, stopEvent('still waiting on the worker'), ctx);
169
- assert.equal(getNode('mgr')?.status, 'active', 'mgr stays active — NOT idle-released while behind the cursor');
184
+ assert.equal(getNode('mgr')?.status, 'active', 'mgr stays active — NOT idle-released while a delivery is pending');
170
185
  assert.equal(getNode('mgr')?.intent ?? null, null, 'no idle-release intent while a non-deferred entry is unseen');
171
186
  assert.equal(shutdown, false, 'pi stays alive so the in-process watcher can still deliver/commit');
172
187
  });
173
- test('gh-451: finished does NOT shut down while a non-deferred inbox entry sits past the cursor', { timeout: 1_000 }, async () => {
174
- // A canonical final can settle while the in-process watcher has delivered a
175
- // child report into the inbox but has not yet committed the durable cursor.
176
- // The finished branch must keep this broker alive for that delivery.
188
+ test('gh-451: finished does NOT shut down while a non-deferred SQL delivery is pending', { timeout: 1_000 }, async () => {
189
+ // A canonical final can settle while the in-process watcher has a child
190
+ // report delivery pending. The finished branch must keep this broker alive
191
+ // for that delivery.
177
192
  createNode(node('mgr', { parent: null, lifecycle: 'terminal', final_report: 'mgr-final.md' }));
178
- appendInbox('mgr', { from: 'worker', tier: 'normal', kind: 'update', label: 'worker made progress' });
193
+ enqueueNodeMail('mgr', { senderNodeId: 'worker', kind: 'update', label: 'worker made progress', urgency: 'normal', wake: 1 });
179
194
  process.env['CRTR_NODE_ID'] = 'mgr';
180
195
  const pi = makeFakePi();
181
196
  registerCanvasStophook(pi);
@@ -192,7 +207,7 @@ test('a deferred send to a TERMINAL node was raised on append, so it holds the s
192
207
  createNode(node('worker', { parent: 'mgr', lifecycle: 'terminal', status: 'active' }));
193
208
  subscribe('root', 'mgr', true);
194
209
  subscribe('mgr', 'worker', true);
195
- appendInbox('mgr', { from: null, tier: 'deferred', kind: 'message', label: 'a scheduled deferred note' });
210
+ enqueueNodeMail('mgr', { kind: 'message', label: 'a scheduled deferred note', urgency: 'deferred', wake: 1 });
196
211
  process.env['CRTR_NODE_ID'] = 'mgr';
197
212
  const pi = makeFakePi();
198
213
  registerCanvasStophook(pi);
@@ -206,6 +221,7 @@ test('a deferred send to a TERMINAL node was raised on append, so it holds the s
206
221
  test('queued continuation finishes before natural-stop routing commits', { timeout: 1_000 }, async () => {
207
222
  createNode(node('leaf', { parent: null, lifecycle: 'terminal' }));
208
223
  process.env['CRTR_NODE_ID'] = 'leaf';
224
+ activateBroker('leaf');
209
225
  const pi = makeFakePi();
210
226
  registerCanvasStophook(pi);
211
227
  let shutdown = false;
@@ -318,7 +334,7 @@ test('refresh-yield (intent=refresh) writes NO push — silent to subscribers',
318
334
  await settle(pi, stopEvent('checkpoint before refreshing'), { shutdown: () => { shutdown = true; } });
319
335
  assert.equal(shutdown, true, 'pi shut down (no tmux pane → clean shutdown)');
320
336
  assert.equal(reportCount('orch'), 0, 'a yield is silent: NO report file');
321
- assert.equal(readInboxSince('root').length, 0, 'a yield is silent: NO inbox pointer');
337
+ assert.equal(hasUnseenWakeMail('root'), false, 'a yield is silent: NO SQL inbox delivery');
322
338
  assert.equal(pi.injected.length, 0, 'no reprompt on a refresh-yield');
323
339
  });
324
340
  // turn_end — stale-⚠ fix: reaching turn_end proves the current provider
@@ -327,7 +343,7 @@ test('refresh-yield (intent=refresh) writes NO push — silent to subscribers',
327
343
  function turnEndEvent(text) {
328
344
  return { message: { role: 'assistant', content: [{ type: 'text', text }] } };
329
345
  }
330
- test('turn_end clears a stale pi→provider fatal fault (a completed round-trip proves the episode is over)', () => {
346
+ test('turn_end clears a stale pi→provider fatal fault (a completed round-trip proves the episode is over)', async () => {
331
347
  createNode(node('leaf', { parent: null, lifecycle: 'terminal' }));
332
348
  recordFault('leaf', {
333
349
  link: 'pi→provider',
@@ -336,14 +352,14 @@ test('turn_end clears a stale pi→provider fatal fault (a completed round-trip
336
352
  retry: { disposition: 'fatal' },
337
353
  message: 'terminated',
338
354
  });
339
- assert.notEqual(readFault('leaf'), null, 'precondition: fault marker recorded');
340
- process.env['CRTR_NODE_ID'] = 'leaf';
355
+ assert.notEqual(readFault('leaf'), null, 'precondition: SQL recovery fault recorded');
356
+ activateBroker('leaf');
341
357
  const pi = makeFakePi();
342
358
  registerCanvasStophook(pi);
343
- pi.fire('turn_end', turnEndEvent('all good now'), {});
359
+ await pi.fire('turn_end', turnEndEvent('all good now'), {});
344
360
  assert.equal(readFault('leaf'), null, 'the pi→provider fault is cleared at turn_end');
345
361
  });
346
- test('turn_end still clears a daemon→node wedge fault (existing behavior, unchanged)', () => {
362
+ test('turn_end still clears a daemon→node wedge fault (existing behavior, unchanged)', async () => {
347
363
  createNode(node('leaf', { parent: null, lifecycle: 'terminal' }));
348
364
  recordFault('leaf', {
349
365
  link: 'daemon→node',
@@ -352,16 +368,18 @@ test('turn_end still clears a daemon→node wedge fault (existing behavior, unch
352
368
  retry: { disposition: 'manual' },
353
369
  message: 'no progress for 20m',
354
370
  });
355
- assert.notEqual(readFault('leaf'), null, 'precondition: wedge fault recorded');
356
- process.env['CRTR_NODE_ID'] = 'leaf';
371
+ assert.notEqual(readFault('leaf'), null, 'precondition: SQL recovery wedge fault recorded');
372
+ activateBroker('leaf');
357
373
  const pi = makeFakePi();
358
374
  registerCanvasStophook(pi);
359
- pi.fire('turn_end', turnEndEvent('turn completed'), {});
375
+ await pi.fire('turn_end', turnEndEvent('turn completed'), {});
360
376
  assert.equal(readFault('leaf'), null, 'the daemon→node wedge fault is still cleared at turn_end');
361
377
  });
362
- test('a successful final or requested human reply suppresses the stop reprompt without a canvas read', async () => {
378
+ test('a successful final or requested human reply suppresses the stop reprompt', async () => {
379
+ createNode(node('signal-only', { parent: null, lifecycle: 'terminal' }));
363
380
  for (const [signal, shutsDown] of [['pushedFinal', true], ['requestedHumanReply', false]]) {
364
381
  process.env['CRTR_NODE_ID'] = 'signal-only';
382
+ activateBroker('signal-only');
365
383
  markStopSignal('signal-only', signal);
366
384
  const pi = makeFakePi();
367
385
  registerCanvasStophook(pi);
@@ -410,5 +428,5 @@ test('stalled leaf (nothing live to await, no final) is still reprompted', async
410
428
  assert.equal(shutdown, false, 'a stalled leaf is NOT shut down — it is re-prompted to finish');
411
429
  assert.notEqual(getNode('leaf')?.intent, 'idle-release', 'a stalled leaf does not idle-release');
412
430
  assert.equal(reportCount('leaf'), 0, 'NO report file written on a stall');
413
- assert.equal(readInboxSince('mgr').length, 0, 'NO inbox pointer fanned on a stall');
431
+ assert.equal(hasUnseenWakeMail('mgr'), false, 'NO SQL inbox delivery fanned on a stall');
414
432
  });
@@ -20,11 +20,13 @@ import { tmpdir } from 'node:os';
20
20
  import { join } from 'node:path';
21
21
  import registerCanvasStophook from '../canvas-stophook.js';
22
22
  import { createNode } from '../../core/canvas/canvas.js';
23
- import { closeDb } from '../../core/canvas/db.js';
23
+ import { beginExecution } from '../../core/canvas/executions.js';
24
+ import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
24
25
  import { apiSocketPath } from '../../core/canvas/paths.js';
25
26
  import { createApiServer } from '../../daemon/api/server.js';
26
27
  let home;
27
28
  let origNode;
29
+ let origExecution;
28
30
  let server;
29
31
  async function waitForSocket(path) {
30
32
  for (let i = 0; i < 200; i++) {
@@ -66,7 +68,10 @@ function turnEnd(content, stopReason = 'stop') {
66
68
  return { message: { role: 'assistant', stopReason, content, usage: { input: 1, output: 1 } }, toolResults: [] };
67
69
  }
68
70
  const ctxAt = (tokens) => ({ getContextUsage: () => ({ tokens }) });
69
- before(() => { origNode = process.env['CRTR_NODE_ID']; });
71
+ before(() => {
72
+ origNode = process.env['CRTR_NODE_ID'];
73
+ origExecution = process.env['CRTR_EXECUTION_ID'];
74
+ });
70
75
  beforeEach(async () => {
71
76
  closeDb();
72
77
  if (home)
@@ -74,6 +79,7 @@ beforeEach(async () => {
74
79
  home = mkdtempSync(join(tmpdir(), 'crtr-stophook-nudge-'));
75
80
  process.env['CRTR_HOME'] = home;
76
81
  mkdirSync(home, { recursive: true });
82
+ migrate(openDb());
77
83
  server = createApiServer();
78
84
  await waitForSocket(apiSocketPath());
79
85
  });
@@ -89,10 +95,15 @@ after(() => {
89
95
  delete process.env['CRTR_NODE_ID'];
90
96
  else
91
97
  process.env['CRTR_NODE_ID'] = origNode;
98
+ if (origExecution === undefined)
99
+ delete process.env['CRTR_EXECUTION_ID'];
100
+ else
101
+ process.env['CRTR_EXECUTION_ID'] = origExecution;
92
102
  });
93
103
  test('band crossing mid-run (tool calls present) → context nudge is a STEER', async () => {
94
104
  createNode(node('midrun'));
95
105
  process.env['CRTR_NODE_ID'] = 'midrun';
106
+ process.env['CRTR_EXECUTION_ID'] = beginExecution('midrun', { daemonEpoch: null });
96
107
  const pi = makeFakePi();
97
108
  registerCanvasStophook(pi);
98
109
  await pi.fire('turn_end', turnEnd([{ type: 'toolCall', id: 't1', name: 'bash', arguments: {} }], 'toolUse'), ctxAt(150_000));
@@ -104,6 +115,7 @@ test('band crossing mid-run (tool calls present) → context nudge is a STEER',
104
115
  test('band crossing on the FINAL message (no tool calls) → nudge is HELD as nextTurn, never a steer', async () => {
105
116
  createNode(node('final'));
106
117
  process.env['CRTR_NODE_ID'] = 'final';
118
+ process.env['CRTR_EXECUTION_ID'] = beginExecution('final', { daemonEpoch: null });
107
119
  const pi = makeFakePi();
108
120
  registerCanvasStophook(pi);
109
121
  await pi.fire('turn_end', turnEnd([{ type: 'text', text: 'here is my summary' }]), ctxAt(150_000));
@@ -117,6 +129,7 @@ test('band crossing on the FINAL message (no tool calls) → nudge is HELD as ne
117
129
  test('a truncated tool-calling turn (stopReason length) still steers — the loop continues past failed calls', async () => {
118
130
  createNode(node('lengthrun'));
119
131
  process.env['CRTR_NODE_ID'] = 'lengthrun';
132
+ process.env['CRTR_EXECUTION_ID'] = beginExecution('lengthrun', { daemonEpoch: null });
120
133
  const pi = makeFakePi();
121
134
  registerCanvasStophook(pi);
122
135
  await pi.fire('turn_end', turnEnd([{ type: 'toolCall', id: 't1', name: 'bash', arguments: {} }], 'length'), ctxAt(150_000));
@@ -127,6 +140,7 @@ test('a truncated tool-calling turn (stopReason length) still steers — the loo
127
140
  test('an aborted final turn also holds (the loop ends unconditionally on abort)', async () => {
128
141
  createNode(node('aborted'));
129
142
  process.env['CRTR_NODE_ID'] = 'aborted';
143
+ process.env['CRTR_EXECUTION_ID'] = beginExecution('aborted', { daemonEpoch: null });
130
144
  const pi = makeFakePi();
131
145
  registerCanvasStophook(pi);
132
146
  // Aborted mid-tool-call: toolCall content present, but the run ends anyway —
@@ -27,9 +27,11 @@ import { tmpdir } from 'node:os';
27
27
  import { join } from 'node:path';
28
28
  import { registerCanvasDocSubstrate } from '../canvas-doc-substrate.js';
29
29
  import { createNode } from '../../core/canvas/canvas.js';
30
- import { closeDb } from '../../core/canvas/db.js';
30
+ import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
31
+ import { beginExecution } from '../../core/canvas/executions.js';
31
32
  import { apiSocketPath } from '../../core/canvas/paths.js';
32
33
  import { resetScopeCache } from '../../core/scope.js';
34
+ import { initializeFreshScopedStore } from '../../core/scoped-state/migrate.js';
33
35
  import { loadContextExposureState } from '../../core/substrate/injected-store.js';
34
36
  import { clearSessionCache } from '../../core/substrate/session-cache.js';
35
37
  import { createApiServer } from '../../daemon/api/server.js';
@@ -40,6 +42,7 @@ let server = null;
40
42
  let origCwd;
41
43
  let origHome;
42
44
  let origNode;
45
+ let origExecution;
43
46
  let origProfile;
44
47
  async function waitForSocket(path) {
45
48
  for (let i = 0; i < 200; i++) {
@@ -83,6 +86,7 @@ function seedNode(id) {
83
86
  });
84
87
  mkdirSync(join(home, 'nodes', id), { recursive: true });
85
88
  process.env['CRTR_NODE_ID'] = id;
89
+ process.env['CRTR_EXECUTION_ID'] = beginExecution(id, { daemonEpoch: null });
86
90
  }
87
91
  /** The registered extension, driven through the pi events it actually binds. */
88
92
  function registerSubstrate() {
@@ -117,6 +121,7 @@ before(() => {
117
121
  origCwd = process.cwd();
118
122
  origHome = process.env['HOME'];
119
123
  origNode = process.env['CRTR_NODE_ID'];
124
+ origExecution = process.env['CRTR_EXECUTION_ID'];
120
125
  origProfile = process.env['CRTR_PROFILE_ID'];
121
126
  });
122
127
  beforeEach(async () => {
@@ -130,9 +135,12 @@ beforeEach(async () => {
130
135
  process.env['HOME'] = join(home, 'user');
131
136
  process.env['CRTR_HOME'] = home;
132
137
  delete process.env['CRTR_NODE_ID'];
138
+ delete process.env['CRTR_EXECUTION_ID'];
133
139
  delete process.env['CRTR_PROFILE_ID'];
134
140
  resetScopeCache();
135
141
  clearSessionCache();
142
+ initializeFreshScopedStore({ kind: 'user', root: join(home, 'user', '.crouter') });
143
+ migrate(openDb());
136
144
  server = createApiServer();
137
145
  await waitForSocket(apiSocketPath());
138
146
  });
@@ -160,6 +168,10 @@ after(() => {
160
168
  delete process.env['CRTR_NODE_ID'];
161
169
  else
162
170
  process.env['CRTR_NODE_ID'] = origNode;
171
+ if (origExecution === undefined)
172
+ delete process.env['CRTR_EXECUTION_ID'];
173
+ else
174
+ process.env['CRTR_EXECUTION_ID'] = origExecution;
163
175
  if (origProfile === undefined)
164
176
  delete process.env['CRTR_PROFILE_ID'];
165
177
  else