@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
@@ -46,11 +46,10 @@ import { writeFileSync, readFileSync, rmSync, mkdirSync, } from 'node:fs';
46
46
  import { dirname } from 'node:path';
47
47
  import { randomBytes } from 'node:crypto';
48
48
  import { crtrHome } from '../core/canvas/paths.js';
49
- import { listNodes, migrateLegacyPidIdentities, } from '../core/canvas/index.js';
49
+ import { listNodeMemoryTargets, listNodes, } from '../core/canvas/index.js';
50
50
  import { createApiServer } from './api/server.js';
51
51
  import { reconcileUndeliveredTickets } from './human/sweep.js';
52
- import { recoverRunningActionDeliveries } from '../core/canvas/human-deliveries.js';
53
- import { recoverRunningOutcomeDeliveries } from '../core/canvas/node-outcome-deliveries.js';
52
+ import { resetHandedOffDeliveries } from '../core/canvas/deliveries.js';
54
53
  import { sweepReviews } from './review/sweep.js';
55
54
  import { pidfilePath } from './pidfile.js';
56
55
  import { rendererWarning } from '../core/runtime/package-health.js';
@@ -60,12 +59,12 @@ import { ControllerDeathReconciler } from './reconcilers/controller-death.js';
60
59
  import { NodeLifecycleReconciler } from './reconcilers/node-lifecycle/tick.js';
61
60
  import { NodeDeadlineReconciler } from './reconcilers/node-deadline.js';
62
61
  import { CronLaneReconciler } from './reconcilers/cron-lane.js';
63
- import { HumanDeliveryLaneReconciler } from './reconcilers/human-delivery-lane.js';
64
- import { NodeOutcomeDeliveryLaneReconciler } from './reconcilers/node-outcome-delivery-lane.js';
62
+ import { DeliveryLaneReconciler } from './reconcilers/delivery-lane.js';
63
+ import { migrateLegacyExecutionIdentities } from '../core/canvas/executions.js';
65
64
  import { PendingReviewSubmitReconciler } from './reconcilers/pending-review-submit.js';
66
65
  import { StorageMaintenanceReconciler } from './reconcilers/storage-maintenance.js';
67
66
  import { BashDeadlineReconciler } from './reconcilers/bash-deadline.js';
68
- import { captureLivenessSnapshot, capturePidCommand, captureTeardownSnapshot, isPidAlive, killProcessTreePids, } from '../core/canvas/pid.js';
67
+ import { captureLivenessSnapshot, capturePidCommand, captureTeardownSnapshot, isPidAlive, isAnyPidAlive, killProcessTreePids, } from '../core/canvas/pid.js';
69
68
  import { bindFleet, boundFleet } from '../core/runtime/fleet.js';
70
69
  import { bindDaemonControl, clearDaemonControl } from './control.js';
71
70
  import { execDaemon, spawnDaemon } from './manage.js';
@@ -73,14 +72,19 @@ import { reconcileAndMigrateBoot } from '../core/canvas/boot.js';
73
72
  import { resolveInstallId } from '../core/canvas/install-id.js';
74
73
  import { setInstallId } from '../core/runtime/nodes.js';
75
74
  import { claimDaemonOwnership, releaseDaemonOwnership } from '../core/canvas/daemon-owner.js';
75
+ import { migrate, openDb } from '../core/canvas/db.js';
76
76
  import { prewarmRecentRecipes, reapStaleSpares } from '../core/runtime/warm-pool.js';
77
77
  import { DaemonFleet } from './fleet.js';
78
78
  import { BOOT_MIGRATIONS } from './boot-migrations.js';
79
79
  import { emitEvent } from '../core/events/emit.js';
80
80
  import { operationIdContext } from '../core/events/operation-id.js';
81
81
  import { bindDaemonEventSource } from '../core/events/source.js';
82
- import { ensureOnDiskMigrations } from '../migrations/activation.js';
83
- import { clearDaemonStartupBlocked } from './startup-block-marker.js';
82
+ import { activateOnDiskMigrations, MigrationBlockedError, runForcedOnDiskMigrations } from '../migrations/activation.js';
83
+ import { profilesRoot, withProfileManifestLock } from '../core/profiles/manifest.js';
84
+ import { runProfileManifestMigrations } from '../migrations/profile-manifests.js';
85
+ import { convertLegacyProviderStore, convertLegacyScopedStore } from '../core/scoped-state/migrate.js';
86
+ import { userScopeRoot } from '../core/scope.js';
87
+ import { piAgentDir } from '../core/runtime/package-health.js';
84
88
  // A broker DECLARES its owning canvas in argv at spawn (host.ts launch:
85
89
  // `broker-cli.js --canvas-home <home> --epoch <id> <nodeId>`), so ownership is
86
90
  // an exact match on this daemon's own canvas home — no path inference. An
@@ -113,15 +117,12 @@ const CENSUS_POLL_MS = 150;
113
117
  async function reapPriorEpochBrokers(epoch) {
114
118
  const snapshot = captureLivenessSnapshot();
115
119
  if (snapshot === null) {
116
- // No process table — the census cannot run. The supervision tick still
117
- // classifies rows; a surviving prior-epoch broker is at worst a duplicate
118
- // engine risk the next daemon boot's census retries.
119
120
  emitEvent({
120
121
  level: 'error',
121
122
  event: 'daemon.census.snapshot_failed',
122
123
  fields: { invariant: 'prior-epoch brokers are reaped before readiness' },
123
124
  });
124
- return;
125
+ throw new Error('prior-epoch broker census could not capture the process table');
125
126
  }
126
127
  const home = crtrHome();
127
128
  const victims = [];
@@ -168,16 +169,43 @@ async function reapPriorEpochBrokers(epoch) {
168
169
  }
169
170
  // Bounded graceful wait, then SIGKILL each survivor's captured tree.
170
171
  const deadline = Date.now() + PRIOR_EPOCH_TERM_GRACE_MS;
171
- while (Date.now() < deadline && signaled.some((s) => isPidAlive(s.pid))) {
172
+ while (Date.now() < deadline && signaled.some((s) => isAnyPidAlive(s.snap.tree.length > 0 ? s.snap.tree : [s.pid]))) {
172
173
  await new Promise((resolve) => setTimeout(resolve, CENSUS_POLL_MS));
173
174
  }
174
175
  let sigkilled = 0;
175
176
  for (const s of signaled) {
176
- if (!isPidAlive(s.pid))
177
+ const tree = s.snap.tree.length > 0 ? s.snap.tree : [s.pid];
178
+ if (!isAnyPidAlive(tree))
177
179
  continue;
178
- killProcessTreePids(s.snap.tree.length > 0 ? s.snap.tree : [s.pid], 'SIGKILL', s.snap.identities);
180
+ killProcessTreePids(tree, 'SIGKILL', s.snap.identities);
179
181
  sigkilled++;
180
182
  }
183
+ if (sigkilled > 0)
184
+ await new Promise((resolve) => setTimeout(resolve, CENSUS_POLL_MS));
185
+ // Only a fresh full table sample proves a prior writer is gone.
186
+ const finalSnapshot = captureLivenessSnapshot();
187
+ if (finalSnapshot === null) {
188
+ emitEvent({
189
+ level: 'error',
190
+ event: 'daemon.census.snapshot_failed',
191
+ fields: { invariant: 'prior-epoch brokers are reaped before readiness', stage: 'final' },
192
+ });
193
+ throw new Error('prior-epoch broker census could not capture the final process table');
194
+ }
195
+ const survivors = [];
196
+ for (const [pid, processInfo] of finalSnapshot.processes) {
197
+ const command = processInfo.command;
198
+ if (processInfo.zombie || !command.includes('broker-cli.js'))
199
+ continue;
200
+ if (!brokerCommandDeclaresCanvasHome(command, home))
201
+ continue;
202
+ if (brokerCommandEpoch(command) === epoch)
203
+ continue;
204
+ survivors.push(pid);
205
+ }
206
+ if (survivors.length > 0) {
207
+ throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${survivors.join(', ')}`);
208
+ }
181
209
  emitEvent({
182
210
  level: 'info',
183
211
  event: 'daemon.census.completed',
@@ -220,17 +248,21 @@ async function teardownFleet(fleet) {
220
248
  t.unref();
221
249
  });
222
250
  await Promise.allSettled(items.map((item) => Promise.race([item.exited.then(() => { }), timeout])));
223
- let sigkilled = 0;
251
+ const sigkilled = [];
224
252
  for (const item of items) {
225
253
  if (!isPidAlive(item.pid))
226
254
  continue;
227
255
  killProcessTreePids(item.snap.tree.length > 0 ? item.snap.tree : [item.pid], 'SIGKILL', item.snap.identities);
228
- sigkilled++;
256
+ sigkilled.push(item);
229
257
  }
258
+ // A signal only requests termination. The handle's exit promise is the
259
+ // authoritative proof that each escalated broker has exited, so cleanup must
260
+ // not release its daemon ownership claim before these promises settle.
261
+ await Promise.all(sigkilled.map((item) => item.exited));
230
262
  emitEvent({
231
263
  level: 'info',
232
264
  event: 'daemon.fleet_teardown.completed',
233
- fields: { brokers: items.length, sigkilled },
265
+ fields: { brokers: items.length, sigkilled: sigkilled.length },
234
266
  });
235
267
  }
236
268
  // Pidfile
@@ -277,8 +309,7 @@ const controllerDeath = new ControllerDeathReconciler();
277
309
  const nodeLifecycle = new NodeLifecycleReconciler();
278
310
  const nodeDeadline = new NodeDeadlineReconciler();
279
311
  const cronLane = new CronLaneReconciler();
280
- const humanDeliveryLane = new HumanDeliveryLaneReconciler();
281
- const nodeOutcomeDeliveryLane = new NodeOutcomeDeliveryLaneReconciler();
312
+ const deliveryLane = new DeliveryLaneReconciler();
282
313
  const pendingReviewSubmit = new PendingReviewSubmitReconciler();
283
314
  const storageMaintenance = new StorageMaintenanceReconciler();
284
315
  const bashDeadline = new BashDeadlineReconciler();
@@ -310,8 +341,7 @@ export async function superviseTick(now = Date.now(), lifecycle = directTickLife
310
341
  // canceled and terminalized here, after the lifecycle pass has had its say.
311
342
  nodeDeadline.run(now);
312
343
  cronLane.run(now, { lifecycle });
313
- humanDeliveryLane.run(now, { lifecycle });
314
- nodeOutcomeDeliveryLane.run(now, { lifecycle });
344
+ deliveryLane.run(now, { lifecycle });
315
345
  pendingReviewSubmit.run(now, { lifecycle });
316
346
  storageMaintenance.run(now, { lifecycle, fleet });
317
347
  await bashDeadline.run(now, { rows });
@@ -348,11 +378,11 @@ export async function runDaemon(opts = {}) {
348
378
  }
349
379
  const claim = ownership.claim;
350
380
  try {
351
- await ensureOnDiskMigrations();
352
- // Migrations passed, so whatever once blocked startup here is resolved.
353
- // Retire the suppression marker on the success path rather than making any
354
- // repair route remember to: the daemon getting this far IS the proof.
355
- clearDaemonStartupBlocked();
381
+ await reapPriorEpochBrokers(claim.token);
382
+ runProfileManifestMigrations(profilesRoot(), { dryRun: false, withLock: withProfileManifestLock });
383
+ convertLegacyScopedStore({ kind: 'user', root: userScopeRoot() });
384
+ await convertLegacyProviderStore(piAgentDir());
385
+ migrate(openDb());
356
386
  }
357
387
  catch (migrationError) {
358
388
  try {
@@ -377,6 +407,18 @@ export async function runDaemon(opts = {}) {
377
407
  let cleanupInFlight;
378
408
  let apiServer;
379
409
  let apiServerClosed = false;
410
+ let startup = {
411
+ phase: 'initializing',
412
+ message: 'daemon startup is initializing its on-disk memory migration and normal services are unavailable',
413
+ blockerPaths: [],
414
+ };
415
+ // This slot is occupied before the repair socket binds, and remains occupied
416
+ // through normal startup. A request never receives another request's report.
417
+ let migrationInFlight = 'initial startup activation';
418
+ let resume = null;
419
+ function startupBlock() {
420
+ return startup.phase === 'ready' ? null : { phase: startup.phase, message: startup.message, blockerPaths: startup.blockerPaths };
421
+ }
380
422
  function registerDetached(work) {
381
423
  detached.add(work);
382
424
  void work.finally(() => {
@@ -591,23 +633,88 @@ export async function runDaemon(opts = {}) {
591
633
  }
592
634
  });
593
635
  }
594
- try {
595
- process.on('SIGINT', onSigint);
596
- process.on('SIGTERM', onSigterm);
597
- process.on('exit', onExit);
598
- bindDaemonEventSource();
636
+ let admissionFailure = null;
637
+ async function admitStartup() {
638
+ if (admissionFailure !== null) {
639
+ const message = admissionFailure instanceof Error ? admissionFailure.message : String(admissionFailure);
640
+ throw { status: 500, code: 'admission_failed', message: `daemon admission previously failed: ${message}` };
641
+ }
642
+ if (startup.phase === 'ready') {
643
+ return { admitted: false, already_admitted: true, startup_phase: 'ready' };
644
+ }
645
+ if (startup.phase !== 'prepared' && startup.phase !== 'recovering') {
646
+ throw {
647
+ status: 409,
648
+ code: 'not_prepared',
649
+ message: startup.message,
650
+ };
651
+ }
652
+ const admitted = startup.phase === 'prepared';
653
+ try {
654
+ await resumeStartup();
655
+ startup = { phase: 'ready', message: '', blockerPaths: [] };
656
+ return admitted
657
+ ? { admitted: true, already_admitted: false, startup_phase: 'ready' }
658
+ : { admitted: false, already_admitted: true, startup_phase: 'ready' };
659
+ }
660
+ catch (error) {
661
+ admissionFailure = error;
662
+ const message = error instanceof Error ? error.message : String(error);
663
+ throw { status: 500, code: 'admission_failed', message: `daemon admission failed: ${message}` };
664
+ }
665
+ }
666
+ async function repairMigrations(req) {
667
+ if (migrationInFlight !== null) {
668
+ throw {
669
+ status: 409,
670
+ code: 'migration_in_progress',
671
+ message: `on-disk migration is already running (${migrationInFlight})`,
672
+ };
673
+ }
674
+ migrationInFlight = 'repair';
675
+ try {
676
+ const result = await runForcedOnDiskMigrations({
677
+ dryRun: req.dryRun,
678
+ explicitDirs: req.dirs,
679
+ nodes: listNodeMemoryTargets(),
680
+ });
681
+ if (req.dryRun || !result.finalVerificationSucceeded || startup.phase !== 'blocked') {
682
+ return { result, resumed: false };
683
+ }
684
+ if (opts.prepare) {
685
+ startup = {
686
+ phase: 'prepared',
687
+ message: 'daemon storage is prepared and normal services are unavailable until admission',
688
+ blockerPaths: [],
689
+ };
690
+ return { result, resumed: false };
691
+ }
692
+ try {
693
+ await resumeStartup();
694
+ startup = { phase: 'ready', message: '', blockerPaths: [] };
695
+ return { result, resumed: true };
696
+ }
697
+ catch (error) {
698
+ const resumeError = error instanceof Error ? error.message : String(error);
699
+ // The route must flush this result before cleanup closes its connection.
700
+ setTimeout(() => { void requestCleanup().catch(() => { }); }, 1_000);
701
+ return { result, resumed: false, resumeError };
702
+ }
703
+ }
704
+ finally {
705
+ migrationInFlight = null;
706
+ }
707
+ }
708
+ async function completeStartup() {
599
709
  interval = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
600
- // Mint this daemon's epoch and bind the ONE fleet registry for the process
601
- // BEFORE anything can launch a broker (the API server or any tick): every
602
- // launch funnels through headlessBrokerHost.launch, which
603
- // registers with the bound fleet — an unbound launch throws (design D-2).
604
- const epoch = randomBytes(8).toString('hex');
710
+ const epoch = claim.token;
605
711
  fleet = new DaemonFleet({ epoch, enqueue });
606
712
  bindFleet(fleet);
607
- // The self-control seam the API's handover handler reaches this closure
608
- // through (see control.ts). Bound alongside the fleet so anything that can
609
- // launch a broker can also hand the fleet over.
610
- bindDaemonControl({ epoch, requestHandover, registerDetached });
713
+ startup = {
714
+ phase: 'recovering',
715
+ message: 'daemon startup recovery is running and normal services are unavailable',
716
+ blockerPaths: [],
717
+ };
611
718
  operationIdContext.fresh(() => {
612
719
  emitEvent({
613
720
  level: 'info',
@@ -615,18 +722,11 @@ export async function runDaemon(opts = {}) {
615
722
  fields: { pid: process.pid, interval_ms: interval },
616
723
  });
617
724
  });
618
- // Resolve the canvas-install id EARLY — before any other startup work
619
- // that might mint a node id. A thrown error here (invalid CRTR_INSTALL_ID,
620
- // or a stored/env mismatch) propagates out of this try block into the
621
- // existing `catch (startupError)` below, which is exactly the "hard fail
622
- // daemon boot" requirement — no separate catch/rethrow needed.
623
725
  const installId = resolveInstallId();
624
726
  setInstallId(installId);
625
727
  operationIdContext.fresh(() => {
626
728
  emitEvent({ level: 'info', event: 'daemon.install_id.resolved', fields: { install_id: installId } });
627
729
  });
628
- // The pinned termrender renderer is an advisory dependency; setup repairs
629
- // an unprovisioned venv without blocking supervision.
630
730
  operationIdContext.fresh(() => {
631
731
  let warning;
632
732
  try {
@@ -643,21 +743,13 @@ export async function runDaemon(opts = {}) {
643
743
  });
644
744
  }
645
745
  });
646
- // Complete ticket delivery before API traffic can observe terminal answers.
647
746
  await operationIdContext.fresh(async () => {
648
747
  await sweepReviews();
649
748
  await reconcileUndeliveredTickets();
650
- // Unlike a cron one-shot, a completion is at-least-once: destinations deduplicate request IDs, so a dead daemon's running delivery is re-queued immediately.
651
- recoverRunningActionDeliveries(Date.now());
652
- // Same at-least-once contract for node outcome deliveries: a delivery the
653
- // dead daemon had marked running is re-queued rather than stranded.
654
- recoverRunningOutcomeDeliveries(Date.now());
749
+ resetHandedOffDeliveries(Date.now());
655
750
  });
656
- // Boot reconciliation clears stale process identities before any tick can
657
- // inspect them, then migrates legacy identities only with proven same-boot
658
- // provenance.
659
751
  operationIdContext.fresh(() => {
660
- const { reconcile, migrated } = reconcileAndMigrateBoot(migrateLegacyPidIdentities);
752
+ const { reconcile, migrated } = reconcileAndMigrateBoot(migrateLegacyExecutionIdentities);
661
753
  if (reconcile.changed) {
662
754
  emitEvent({
663
755
  level: 'info',
@@ -676,11 +768,6 @@ export async function runDaemon(opts = {}) {
676
768
  });
677
769
  }
678
770
  });
679
- // Boot-time filesystem repairs (design: src/daemon/boot-migrations.ts) run
680
- // unconditionally, in order, before supervision can revive anything.
681
- // Today's one entry is the pre-cutover inbox-identity migration: rows
682
- // without identities or ISO-timestamp cursors are fatal to the strict
683
- // reader and crash-loop every legacy broker at inbox seed.
684
771
  operationIdContext.fresh(() => {
685
772
  for (const migration of BOOT_MIGRATIONS) {
686
773
  const result = migration.apply();
@@ -693,27 +780,65 @@ export async function runDaemon(opts = {}) {
693
780
  }
694
781
  }
695
782
  });
696
- // Startup epoch census (design flow C step 1): reap every prior-epoch
697
- // broker on this canvas BEFORE the readiness mirror invites API traffic —
698
- // no adoption across epochs, ever.
699
- await operationIdContext.fresh(() => reapPriorEpochBrokers(epoch));
700
- writePidfile();
701
- // The Unix API socket is the daemon's readiness boundary. A rejected bind
702
- // enters the existing startup catch, which closes resources and releases
703
- // this invocation's pidfile mirror and ownership claim before propagating.
704
- apiServer = createApiServer({ tcp: opts.tcp });
705
- await apiServer.ready;
706
- // Pre-warm the node pool for the most recent project recipes, so the first
707
- // create after a boot is warm too. Fire-and-forget (the mints run off the
708
- // work lane), so it never delays supervision. Boot-time dead rows are the
709
- // node-lifecycle tick's business: the first tick classifies every one of
710
- // them through the same policy table exit events use, under the same cap.
711
- // Collect the spares this daemon's predecessor left behind BEFORE minting
712
- // new ones: every broker of the prior epoch was torn down, and no sweep
713
- // resumes a spare, so each is a dead row holding a node dir.
714
783
  enqueue(() => { reapStaleSpares(); prewarmRecentRecipes(); });
715
784
  intervalTimer = setInterval(enqueueTick, interval);
716
785
  enqueueTick();
786
+ }
787
+ function resumeStartup() {
788
+ return resume ??= completeStartup().catch((error) => {
789
+ startup = {
790
+ phase: 'initializing',
791
+ message: 'daemon startup recovery failed and normal services are unavailable',
792
+ blockerPaths: [],
793
+ };
794
+ throw error;
795
+ });
796
+ }
797
+ try {
798
+ process.on('SIGINT', onSigint);
799
+ process.on('SIGTERM', onSigterm);
800
+ process.on('exit', onExit);
801
+ // Bind restricted diagnostics and repair before the socket can accept a
802
+ // request. No normal route is admitted until `startup` becomes ready.
803
+ bindDaemonEventSource();
804
+ const epoch = claim.token;
805
+ bindDaemonControl({ epoch, requestHandover, registerDetached, startupBlock, admitStartup, repairMigrations });
806
+ writePidfile();
807
+ // The socket is the repair boundary, not readiness. A rejected bind still
808
+ // enters this catch and releases this invocation's pidfile and ownership.
809
+ apiServer = createApiServer({ tcp: opts.tcp });
810
+ await apiServer.ready;
811
+ try {
812
+ await activateOnDiskMigrations({ nodes: listNodeMemoryTargets() });
813
+ }
814
+ catch (error) {
815
+ migrationInFlight = null;
816
+ if (error instanceof MigrationBlockedError) {
817
+ startup = {
818
+ phase: 'blocked',
819
+ message: error.message,
820
+ blockerPaths: error.blockerPaths,
821
+ };
822
+ return requestCleanup;
823
+ }
824
+ throw error;
825
+ }
826
+ try {
827
+ if (opts.prepare) {
828
+ startup = {
829
+ phase: 'prepared',
830
+ message: 'daemon storage is prepared and normal services are unavailable until admission',
831
+ blockerPaths: [],
832
+ };
833
+ }
834
+ else {
835
+ await resumeStartup();
836
+ startup = { phase: 'ready', message: '', blockerPaths: [] };
837
+ }
838
+ }
839
+ finally {
840
+ migrationInFlight = null;
841
+ }
717
842
  return requestCleanup;
718
843
  }
719
844
  catch (startupError) {
@@ -17,7 +17,7 @@ import { fullName } from '../core/canvas/labels.js';
17
17
  import { isSafeNodeId } from '../core/canvas/paths.js';
18
18
  import { transition } from '../core/runtime/lifecycle.js';
19
19
  import { fanDoctrineWake } from '../core/runtime/close.js';
20
- import { hasCleanAbort, isBusy, readTransportPoisonVerdict } from '../core/runtime/busy.js';
20
+ import { readInterruptedTurn, readTransportPoisonVerdict } from '../core/canvas/recovery.js';
21
21
  import { hasPendingWake } from './reconcilers/live-obligation.js';
22
22
  import { clearRespawnPolicy, deferRespawnWhileOffline, MAX_RESPAWN_ATTEMPTS, OFFLINE_RESPAWN_RETRY_MS, recordRespawnPolicy, respawnBackoffMs, } from './reconcilers/node-lifecycle/respawn-policy.js';
23
23
  import { probeOnline as probeOnlineReal } from '../core/runtime/connectivity.js';
@@ -300,11 +300,10 @@ export class DaemonFleet {
300
300
  clearRespawnPolicy(nodeId);
301
301
  return 'forget';
302
302
  }
303
- // Two durable witnesses mean the dead broker had a turn in flight. A dirty
304
- // death leaves the busy marker behind; a bounded graceful abort clears busy
305
- // as the run settles, then writes the clean-abort certificate. Both need the
306
- // same recovery: resume the saved transcript and re-drive the stopped turn.
307
- const interruptedTurn = isBusy(nodeId) || hasCleanAbort(nodeId);
303
+ // The execution-scoped turn witness survives either a dirty death or a
304
+ // broker-certified abort. Both need the same recovery: resume the saved
305
+ // transcript and re-drive the stopped turn.
306
+ const interruptedTurn = readInterruptedTurn(nodeId)?.interrupted === true;
308
307
  const action = classifyDeadNode(meta, interruptedTurn, hasPendingWake(nodeId));
309
308
  switch (action) {
310
309
  case 'forget':
@@ -1,28 +1,16 @@
1
- import { type CancelTicketOptions, type CompletePageOptions } from '../../core/human/tickets.js';
2
1
  import type { TicketResult } from '../../core/human/types.js';
3
- /** Every ticket-ending action retires the ticket's feedback companion — done
4
- * with a canonical final when approved, never left resident. Idempotent and replay-safe; a
5
- * corrupt feedback file must not block result publication. Exported for the
6
- * daemon-start sweep, which must settle terminal tickets whether or not a
7
- * reply bridge exists. */
8
- export declare function settleFeedbackCompanion(ticketId: string, outcome: 'approved' | 'canceled'): Promise<void>;
9
- /**
10
- * The one completion path for a page ticket: claim takeover, exclusive result
11
- * publication, then optional reply delivery. Every addressing surface routes
12
- * through this function, so the reply-route descriptor is the sole authority
13
- * on whether completion reaches a bridge.
14
- */
2
+ export interface CompletePageOptions {
3
+ completedAt?: string;
4
+ actor?: string;
5
+ }
6
+ export interface CancelTicketOptions {
7
+ reason?: string;
8
+ actor?: string;
9
+ disposition?: 'canceled' | 'dismissed';
10
+ }
11
+ /** Settle a page request directly in human_requests; result files and bridge nodes are not part of this path. */
15
12
  export declare function resolvePageTicket(ticketId: string, responses: unknown, opts?: CompletePageOptions): Promise<TicketResult>;
16
- /** Cancel a ticket with the store's first-writer-wins publication. */
17
13
  export declare function cancelHumanTicket(ticketId: string, opts: CancelTicketOptions): Promise<TicketResult>;
18
- /** Schedule the settled request's completion action, if it bound one. Only the
19
- * settlement winner calls this; the daemon-start sweep replays it for a
20
- * settlement that died before enqueueing, and the insert is idempotent on the
21
- * request id so neither path can create a second delivery. */
22
- export declare function releaseActionDelivery(ticketId: string): void;
23
- /**
24
- * Deliver a terminal ticket result to its bridge. The canonical response is the
25
- * receipt: every action below is replay-safe, so lost delivery can be retried
26
- * by a later resolve/cancel attempt or the daemon-start sweep.
27
- */
14
+ /** Legacy callers use this as a replay hook. Settlement effects are repaired by sweepHumanRequests. */
28
15
  export declare function deliverTerminalResult(ticketId: string): Promise<boolean>;
16
+ export declare function settleFeedbackCompanion(ticketId: string, outcome: 'approved' | 'canceled'): Promise<void>;