@north-light/crouter 0.3.312 → 0.3.313

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/dist/api/client.d.ts +27 -30
  2. package/dist/api/client.js +80 -67
  3. package/dist/api/dto/broker-ops.d.ts +10 -20
  4. package/dist/api/dto/canvas.d.ts +1 -10
  5. package/dist/api/dto/health.d.ts +113 -0
  6. package/dist/api/dto/human-requests.d.ts +14 -3
  7. package/dist/api/dto/human.d.ts +2 -48
  8. package/dist/api/dto/human.js +3 -2
  9. package/dist/api/dto/inbox.d.ts +14 -0
  10. package/dist/api/dto/mail.d.ts +43 -0
  11. package/dist/api/dto/nodes.d.ts +11 -8
  12. package/dist/api/dto/recovery.d.ts +96 -0
  13. package/dist/api/dto/reviews.d.ts +2 -2
  14. package/dist/api/routes.d.ts +9 -6
  15. package/dist/api/routes.js +11 -11
  16. package/dist/build-root.d.ts +4 -0
  17. package/dist/build-root.js +11 -1
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
  22. package/dist/cli.js +10 -1
  23. package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
  24. package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
  25. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  26. package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
  27. package/dist/clients/attach/chrome/inbox-strip.js +17 -9
  28. package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
  29. package/dist/clients/attach/chrome/ticket-panel.js +77 -46
  30. package/dist/clients/attach/overlays/graph.js +6 -9
  31. package/dist/clients/attach/render/chat-view.d.ts +5 -4
  32. package/dist/clients/attach/render/chat-view.js +22 -13
  33. package/dist/clients/attach/render/page-block.d.ts +11 -7
  34. package/dist/clients/attach/render/page-block.js +64 -55
  35. package/dist/clients/attach/viewer.js +746 -735
  36. package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
  37. package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
  38. package/dist/clients/inbox/controller.d.ts +42 -14
  39. package/dist/clients/inbox/controller.js +240 -124
  40. package/dist/clients/inbox/dto-adapt.d.ts +28 -0
  41. package/dist/clients/inbox/dto-adapt.js +93 -0
  42. package/dist/clients/inbox/page-adapter.d.ts +5 -4
  43. package/dist/clients/inbox/page-adapter.js +12 -12
  44. package/dist/clients/inbox/resolve.d.ts +10 -5
  45. package/dist/clients/inbox/resolve.js +13 -12
  46. package/dist/clients/inbox/review/review-client.d.ts +0 -1
  47. package/dist/clients/inbox/review/review-client.js +0 -4
  48. package/dist/clients/inbox/review-adapter.d.ts +2 -1
  49. package/dist/clients/inbox/review-adapter.js +3 -5
  50. package/dist/clients/inbox/surface.d.ts +2 -2
  51. package/dist/clients/inbox/surface.js +19 -8
  52. package/dist/clients/inbox/tui.d.ts +3 -3
  53. package/dist/commands/__tests__/human.test.js +31 -15
  54. package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
  55. package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
  56. package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
  57. package/dist/commands/api-client.d.ts +5 -4
  58. package/dist/commands/api-client.js +13 -7
  59. package/dist/commands/canvas-history/shared.js +1 -1
  60. package/dist/commands/canvas-history.js +1 -1
  61. package/dist/commands/canvas-roster.js +1 -1
  62. package/dist/commands/canvas.js +1 -2
  63. package/dist/commands/human/feedback.js +20 -17
  64. package/dist/commands/human/prompts.js +45 -36
  65. package/dist/commands/human/queue.js +73 -123
  66. package/dist/commands/human/review.js +6 -16
  67. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
  68. package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
  69. package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
  70. package/dist/commands/node-inspect-artifacts.js +1 -1
  71. package/dist/commands/node-lifecycle-revive.d.ts +2 -2
  72. package/dist/commands/node-lifecycle-revive.js +9 -19
  73. package/dist/commands/pkg/plugin-manage.js +0 -1
  74. package/dist/commands/profile/show.js +4 -12
  75. package/dist/commands/surface-tmux-spread.js +1 -5
  76. package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
  77. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
  78. package/dist/commands/sys/branch.d.ts +2 -0
  79. package/dist/commands/sys/branch.js +19 -0
  80. package/dist/commands/sys/config.js +106 -33
  81. package/dist/commands/sys/daemon.d.ts +2 -0
  82. package/dist/commands/sys/daemon.js +130 -7
  83. package/dist/commands/sys/doctor.js +5 -15
  84. package/dist/commands/sys/migrate.js +21 -92
  85. package/dist/commands/sys/setup-settings-runner.js +4 -2
  86. package/dist/commands/sys.js +2 -15
  87. package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
  88. package/dist/core/__tests__/boot.test.js +32 -25
  89. package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
  90. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
  91. package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
  92. package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
  93. package/dist/core/__tests__/canvas.test.js +18 -47
  94. package/dist/core/__tests__/child-death-wake.test.js +29 -7
  95. package/dist/core/__tests__/cli-help-contract.test.js +2 -0
  96. package/dist/core/__tests__/close.test.js +29 -10
  97. package/dist/core/__tests__/collectible.test.js +2 -1
  98. package/dist/core/__tests__/config-change-delta.test.js +2 -0
  99. package/dist/core/__tests__/context-intro.test.js +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/host-teardown-process-group.test.js +9 -5
  121. package/dist/core/__tests__/integration/lifecycle-hooks.test.js +16 -3
  122. package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
  123. package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
  124. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
  125. package/dist/core/__tests__/integration/revive.test.js +67 -21
  126. package/dist/core/__tests__/integration/spawn-root.test.js +51 -8
  127. package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
  128. package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
  129. package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
  130. package/dist/core/__tests__/kickoff.test.js +36 -39
  131. package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
  132. package/dist/core/__tests__/lifecycle.test.js +2 -1
  133. package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
  134. package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
  135. package/dist/core/__tests__/migration.test.js +145 -31
  136. package/dist/core/__tests__/model-pin-durability.test.js +4 -1
  137. package/dist/core/__tests__/model-routes-config.test.js +13 -5
  138. package/dist/core/__tests__/node-outcome.test.js +93 -26
  139. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
  140. package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
  141. package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
  142. package/dist/core/__tests__/passive-subscription.test.js +50 -157
  143. package/dist/core/__tests__/plugin-kinds.test.js +6 -4
  144. package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
  145. package/dist/core/__tests__/plugin-page-components.test.js +6 -4
  146. package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
  147. package/dist/core/__tests__/profile-project-memory-delivery.test.js +4 -1
  148. package/dist/core/__tests__/prune.test.js +11 -5
  149. package/dist/core/__tests__/push-final-guard.test.js +14 -7
  150. package/dist/core/__tests__/relaunch-root.test.js +30 -2
  151. package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
  152. package/dist/core/__tests__/repository-root-identity.test.js +4 -0
  153. package/dist/core/__tests__/review-model-floor.test.js +6 -3
  154. package/dist/core/__tests__/revive-all.test.js +13 -3
  155. package/dist/core/__tests__/revive-capacity.test.js +26 -4
  156. package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
  157. package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
  158. package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
  159. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
  160. package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
  161. package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
  162. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
  163. package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
  164. package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
  165. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +2 -1
  166. package/dist/core/__tests__/stop-guard.test.js +2 -1
  167. package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
  168. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +18 -4
  169. package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
  170. package/dist/core/bootstrap.js +2 -0
  171. package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
  172. package/dist/core/broker-client/transport-socket.d.ts +1 -0
  173. package/dist/core/broker-client/transport-socket.js +13 -5
  174. package/dist/core/canvas/__tests__/attention.test.js +29 -35
  175. package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
  176. package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
  177. package/dist/core/canvas/attention.d.ts +2 -5
  178. package/dist/core/canvas/attention.js +15 -64
  179. package/dist/core/canvas/boot.d.ts +6 -7
  180. package/dist/core/canvas/boot.js +5 -9
  181. package/dist/core/canvas/canvas.d.ts +13 -109
  182. package/dist/core/canvas/canvas.js +140 -401
  183. package/dist/core/canvas/crons.d.ts +2 -0
  184. package/dist/core/canvas/crons.js +16 -15
  185. package/dist/core/canvas/daemon-owner.js +10 -0
  186. package/dist/core/canvas/db.d.ts +2 -2
  187. package/dist/core/canvas/db.js +2 -18
  188. package/dist/core/canvas/deliveries.d.ts +104 -0
  189. package/dist/core/canvas/deliveries.js +354 -0
  190. package/dist/core/canvas/executions.d.ts +29 -0
  191. package/dist/core/canvas/executions.js +68 -0
  192. package/dist/core/canvas/history.js +35 -35
  193. package/dist/core/canvas/index.d.ts +3 -1
  194. package/dist/core/canvas/index.js +3 -1
  195. package/dist/core/canvas/migrations.js +20 -12
  196. package/dist/core/canvas/nav-model.js +1 -3
  197. package/dist/core/canvas/nav-render.d.ts +4 -4
  198. package/dist/core/canvas/nav-render.js +11 -21
  199. package/dist/core/canvas/node-sql-migration.d.ts +3 -0
  200. package/dist/core/canvas/node-sql-migration.js +261 -0
  201. package/dist/core/canvas/paths.d.ts +2 -16
  202. package/dist/core/canvas/paths.js +2 -31
  203. package/dist/core/canvas/recovery.d.ts +76 -0
  204. package/dist/core/canvas/recovery.js +588 -0
  205. package/dist/core/canvas/remote-canvas-source.js +4 -0
  206. package/dist/core/canvas/render-source.d.ts +16 -27
  207. package/dist/core/canvas/render-source.js +16 -45
  208. package/dist/core/canvas/sessions.d.ts +33 -0
  209. package/dist/core/canvas/sessions.js +78 -0
  210. package/dist/core/canvas/types.d.ts +33 -33
  211. package/dist/core/canvas/types.js +2 -5
  212. package/dist/core/canvas/waits.d.ts +18 -0
  213. package/dist/core/canvas/waits.js +70 -0
  214. package/dist/core/canvas/worktrees.d.ts +40 -0
  215. package/dist/core/canvas/worktrees.js +93 -0
  216. package/dist/core/config.d.ts +17 -12
  217. package/dist/core/config.js +106 -155
  218. package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
  219. package/dist/core/feed/feed.d.ts +0 -6
  220. package/dist/core/feed/feed.js +68 -56
  221. package/dist/core/feed/inbox.d.ts +7 -81
  222. package/dist/core/feed/inbox.js +46 -378
  223. package/dist/core/feed/messages.d.ts +58 -0
  224. package/dist/core/feed/messages.js +217 -0
  225. package/dist/core/fs-utils.d.ts +4 -0
  226. package/dist/core/fs-utils.js +21 -1
  227. package/dist/core/human/answer.d.ts +1 -1
  228. package/dist/core/human/answer.js +1 -1
  229. package/dist/core/human/claim.d.ts +1 -1
  230. package/dist/core/human/claim.js +2 -4
  231. package/dist/core/human/component-docs.js +1 -1
  232. package/dist/core/human/feedback-companion.js +3 -2
  233. package/dist/core/human/feedback.d.ts +5 -8
  234. package/dist/core/human/feedback.js +57 -85
  235. package/dist/core/human/page-authoring.d.ts +30 -0
  236. package/dist/core/human/page-authoring.js +19 -0
  237. package/dist/core/human/requests.d.ts +136 -0
  238. package/dist/core/human/requests.js +515 -0
  239. package/dist/core/human/root.d.ts +0 -7
  240. package/dist/core/human/root.js +0 -17
  241. package/dist/core/human/scan.d.ts +2 -7
  242. package/dist/core/human/scan.js +48 -132
  243. package/dist/core/human/summary.d.ts +1 -1
  244. package/dist/core/human/summary.js +1 -1
  245. package/dist/core/human/tickets.d.ts +23 -83
  246. package/dist/core/human/tickets.js +92 -243
  247. package/dist/core/human/types.d.ts +5 -1
  248. package/dist/core/installed-plugins.js +8 -3
  249. package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
  250. package/dist/core/locked-file.d.ts +6 -3
  251. package/dist/core/locked-file.js +36 -9
  252. package/dist/core/memory/extensions.js +2 -0
  253. package/dist/core/preview-registry.js +0 -1
  254. package/dist/core/profiles/__tests__/env-store.test.js +2 -0
  255. package/dist/core/profiles/default-binding.d.ts +0 -4
  256. package/dist/core/profiles/default-binding.js +12 -58
  257. package/dist/core/profiles/env-store.js +8 -3
  258. package/dist/core/profiles/manifest.d.ts +2 -37
  259. package/dist/core/profiles/manifest.js +35 -161
  260. package/dist/core/profiles/select.js +3 -0
  261. package/dist/core/review/__tests__/capture-origin.test.js +13 -2
  262. package/dist/core/review/__tests__/comments.test.js +28 -10
  263. package/dist/core/review/__tests__/remap.test.js +28 -10
  264. package/dist/core/review/__tests__/stage-identity.test.js +17 -7
  265. package/dist/core/review/birth.d.ts +1 -1
  266. package/dist/core/review/birth.js +34 -5
  267. package/dist/core/review/comments.js +1 -1
  268. package/dist/core/review/document.js +1 -1
  269. package/dist/core/review/project.d.ts +5 -1
  270. package/dist/core/review/project.js +14 -36
  271. package/dist/core/review/realize.d.ts +3 -6
  272. package/dist/core/review/realize.js +51 -168
  273. package/dist/core/review/remap.js +1 -1
  274. package/dist/core/review/stage.d.ts +3 -2
  275. package/dist/core/review/stage.js +2 -3
  276. package/dist/core/review/store.d.ts +3 -21
  277. package/dist/core/review/store.js +140 -186
  278. package/dist/core/review/types.d.ts +0 -1
  279. package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
  280. package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
  281. package/dist/core/runtime/broker/auth-reload.js +9 -10
  282. package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
  283. package/dist/core/runtime/broker/daemon-ops.js +42 -9
  284. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  285. package/dist/core/runtime/broker/extension-abort.js +11 -0
  286. package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
  287. package/dist/core/runtime/broker/fault-retry.js +142 -95
  288. package/dist/core/runtime/broker/inbox.d.ts +4 -32
  289. package/dist/core/runtime/broker/inbox.js +4 -92
  290. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  291. package/dist/core/runtime/broker/rebind.js +21 -12
  292. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  293. package/dist/core/runtime/broker-persona-guidance.js +2 -13
  294. package/dist/core/runtime/broker.js +28 -22
  295. package/dist/core/runtime/close.d.ts +3 -9
  296. package/dist/core/runtime/close.js +16 -27
  297. package/dist/core/runtime/fault.d.ts +3 -93
  298. package/dist/core/runtime/fault.js +9 -419
  299. package/dist/core/runtime/kickoff.d.ts +3 -6
  300. package/dist/core/runtime/kickoff.js +12 -18
  301. package/dist/core/runtime/launch.js +1 -1
  302. package/dist/core/runtime/lifecycle.js +40 -7
  303. package/dist/core/runtime/placement.js +2 -2
  304. package/dist/core/runtime/recycle.js +8 -2
  305. package/dist/core/runtime/reset.js +22 -6
  306. package/dist/core/runtime/revive.js +226 -218
  307. package/dist/core/runtime/spawn.js +14 -3
  308. package/dist/core/scoped-state/db.d.ts +7 -0
  309. package/dist/core/scoped-state/db.js +92 -0
  310. package/dist/core/scoped-state/migrate.d.ts +11 -0
  311. package/dist/core/scoped-state/migrate.js +198 -0
  312. package/dist/core/scoped-state/paths.d.ts +9 -0
  313. package/dist/core/scoped-state/paths.js +27 -0
  314. package/dist/core/scoped-state/profiles.d.ts +12 -0
  315. package/dist/core/scoped-state/profiles.js +62 -0
  316. package/dist/core/scoped-state/providers.d.ts +16 -0
  317. package/dist/core/scoped-state/providers.js +8 -0
  318. package/dist/core/scoped-state/schema.d.ts +3 -0
  319. package/dist/core/scoped-state/schema.js +26 -0
  320. package/dist/core/scoped-state/settings.d.ts +28 -0
  321. package/dist/core/scoped-state/settings.js +82 -0
  322. package/dist/core/subscription-state.d.ts +29 -48
  323. package/dist/core/subscription-state.js +176 -712
  324. package/dist/core/worktree-close.js +4 -4
  325. package/dist/core/worktree-mutation-async.js +2 -2
  326. package/dist/core/worktree-sweep.js +11 -16
  327. package/dist/core/worktree.js +6 -12
  328. package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
  329. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
  330. package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
  331. package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
  332. package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
  333. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +39 -15
  334. package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
  335. package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
  336. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
  337. package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
  338. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
  339. package/dist/daemon/api/__tests__/model-config.test.js +8 -8
  340. package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
  341. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
  342. package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
  343. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +4 -1
  344. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
  345. package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
  346. package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
  347. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
  348. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
  349. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +27 -41
  350. package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
  351. package/dist/daemon/api/bridge.js +1 -1
  352. package/dist/daemon/api/handlers/bash-jobs.js +6 -7
  353. package/dist/daemon/api/handlers/broker-ops.js +47 -84
  354. package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
  355. package/dist/daemon/api/handlers/broker-recovery.js +251 -0
  356. package/dist/daemon/api/handlers/canvas.js +2 -44
  357. package/dist/daemon/api/handlers/daemon.js +41 -0
  358. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  359. package/dist/daemon/api/handlers/health.js +10 -5
  360. package/dist/daemon/api/handlers/human-requests.js +168 -188
  361. package/dist/daemon/api/handlers/human.js +3 -151
  362. package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
  363. package/dist/daemon/api/handlers/inbox-page.js +89 -0
  364. package/dist/daemon/api/handlers/inbox.js +21 -120
  365. package/dist/daemon/api/handlers/messages.d.ts +1 -0
  366. package/dist/daemon/api/handlers/messages.js +73 -15
  367. package/dist/daemon/api/handlers/node-outcomes.js +58 -13
  368. package/dist/daemon/api/handlers/nodes.js +7 -13
  369. package/dist/daemon/api/handlers/reviews.js +4 -29
  370. package/dist/daemon/api/map.d.ts +25 -3
  371. package/dist/daemon/api/map.js +84 -14
  372. package/dist/daemon/api/server.js +68 -9
  373. package/dist/daemon/control.d.ts +18 -0
  374. package/dist/daemon/cron/disposition.d.ts +2 -0
  375. package/dist/daemon/cron/disposition.js +8 -5
  376. package/dist/daemon/cron/settle.js +37 -13
  377. package/dist/daemon/cron/sinks.d.ts +18 -1
  378. package/dist/daemon/cron/sinks.js +47 -93
  379. package/dist/daemon/crtrd-cli.js +4 -19
  380. package/dist/daemon/crtrd.d.ts +2 -0
  381. package/dist/daemon/crtrd.js +206 -81
  382. package/dist/daemon/fleet.js +5 -6
  383. package/dist/daemon/human/finish.d.ts +12 -24
  384. package/dist/daemon/human/finish.js +88 -285
  385. package/dist/daemon/human/settle.d.ts +40 -0
  386. package/dist/daemon/human/settle.js +89 -0
  387. package/dist/daemon/human/sweep.d.ts +20 -5
  388. package/dist/daemon/human/sweep.js +56 -60
  389. package/dist/daemon/manage.d.ts +21 -16
  390. package/dist/daemon/manage.js +85 -51
  391. package/dist/daemon/messaging/node-message.d.ts +1 -1
  392. package/dist/daemon/messaging/node-message.js +9 -12
  393. package/dist/daemon/park-activity.js +3 -3
  394. package/dist/daemon/reconcilers/bash-deadline.js +6 -7
  395. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  396. package/dist/daemon/reconcilers/broker-supervision.js +41 -19
  397. package/dist/daemon/reconcilers/controller-death.js +6 -18
  398. package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
  399. package/dist/daemon/reconcilers/delivery-lane.js +130 -0
  400. package/dist/daemon/reconcilers/live-obligation.js +3 -3
  401. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  402. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
  403. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
  404. package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
  405. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  406. package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
  407. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
  408. package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
  409. package/dist/daemon/review/companion.js +5 -11
  410. package/dist/daemon/review/deliver.d.ts +1 -5
  411. package/dist/daemon/review/deliver.js +3 -52
  412. package/dist/daemon/review/finish.d.ts +2 -27
  413. package/dist/daemon/review/finish.js +79 -263
  414. package/dist/daemon/review/sweep.d.ts +3 -10
  415. package/dist/daemon/review/sweep.js +13 -131
  416. package/dist/daemon/startup-policy.d.ts +0 -5
  417. package/dist/daemon/startup-policy.js +0 -5
  418. package/dist/index.d.ts +2 -1
  419. package/dist/index.js +1 -1
  420. package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
  421. package/dist/migrations/__tests__/activation.test.js +9 -6
  422. package/dist/migrations/activation.d.ts +3 -2
  423. package/dist/migrations/activation.js +2 -4
  424. package/dist/migrations/corpus.d.ts +2 -5
  425. package/dist/migrations/corpus.js +9 -20
  426. package/dist/migrations/runner.d.ts +3 -1
  427. package/dist/migrations/runner.js +6 -2
  428. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
  429. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
  430. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
  431. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
  432. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
  433. package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
  434. package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
  435. package/dist/pi-extensions/canvas-passive-context.js +85 -37
  436. package/dist/pi-extensions/canvas-stophook.js +47 -31
  437. package/dist/shared/env.d.ts +1 -0
  438. package/dist/shared/env.js +3 -0
  439. package/package.json +1 -1
  440. package/runtime.lock.json +5 -5
  441. package/dist/clients/attach/__tests__/page-block.test.js +0 -54
  442. package/dist/clients/inbox/review-visibility.d.ts +0 -5
  443. package/dist/clients/inbox/review-visibility.js +0 -19
  444. package/dist/commands/canvas-rebuild-index.d.ts +0 -2
  445. package/dist/commands/canvas-rebuild-index.js +0 -46
  446. package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
  447. package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
  448. package/dist/core/__tests__/human-deliver.test.js +0 -256
  449. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
  450. package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
  451. package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
  452. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
  453. package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
  454. package/dist/core/__tests__/phase4-review-store.test.js +0 -144
  455. package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
  456. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
  457. package/dist/core/canvas/human-deliveries.d.ts +0 -39
  458. package/dist/core/canvas/human-deliveries.js +0 -75
  459. package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
  460. package/dist/core/canvas/node-outcome-deliveries.js +0 -159
  461. package/dist/core/feed/passive.d.ts +0 -3
  462. package/dist/core/feed/passive.js +0 -53
  463. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
  464. package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
  465. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
  466. package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
  467. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
  468. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
  469. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
  470. package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
  471. package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
  472. package/dist/core/human/__tests__/page-tickets.test.js +0 -161
  473. package/dist/core/review/ticket-filter.d.ts +0 -17
  474. package/dist/core/review/ticket-filter.js +0 -21
  475. package/dist/core/runtime/broker/passive.d.ts +0 -17
  476. package/dist/core/runtime/broker/passive.js +0 -44
  477. package/dist/core/runtime/busy.d.ts +0 -46
  478. package/dist/core/runtime/busy.js +0 -150
  479. package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
  480. package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
  481. package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
  482. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
  483. package/dist/daemon/human/deliver-action.d.ts +0 -3
  484. package/dist/daemon/human/deliver-action.js +0 -9
  485. package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
  486. package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
  487. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
  488. package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
  489. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
  490. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
  491. package/dist/daemon/startup-block-marker.d.ts +0 -25
  492. package/dist/daemon/startup-block-marker.js +0 -99
  493. /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
  494. /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
  495. /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { existsSync, realpathSync } from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
- import { getNode, updateNode } from './canvas/index.js';
3
+ import { getNode, recordDisposalGrant, recordLandIntent } from './canvas/index.js';
4
4
  import { withExclusiveDirectoryLockAsync } from './exclusive-lock.js';
5
5
  import { gitAsync } from './git.js';
6
6
  import { proveBranchContained } from './worktree-containment.js';
@@ -66,8 +66,7 @@ function recordBlockedLandIntent(nodeId, blocked) {
66
66
  const current = getNode(nodeId)?.managed_worktree;
67
67
  if (current === undefined || current === null || current.state !== 'open')
68
68
  return;
69
- const { sweep: _sweep, ...retained } = current;
70
- updateNode(nodeId, { managed_worktree: { ...retained, land_intent: { at: new Date().toISOString(), blocked } } });
69
+ recordLandIntent(nodeId, { at: new Date().toISOString(), blocked });
71
70
  }
72
71
  async function dropStashIfStillTip(cwd, stashSha) {
73
72
  const tip = await gitAsync(['rev-parse', '--verify', '--quiet', 'refs/stash'], cwd);
@@ -144,7 +143,8 @@ async function closeLocked(nodeId) {
144
143
  if (!(await registeredWorktree(wt.repo_root, wt.path, branch)) || (await runGit(wt.path, ['rev-parse', '--abbrev-ref', 'HEAD'], 'branch_check_failed', 'Inspect the worktree manually, then retry.')) !== branch || (await runGit(wt.path, ['rev-parse', 'HEAD'], 'branch_check_failed', 'Inspect the worktree manually, then retry.')) !== head) {
145
144
  throw new WorktreeError('wrong_branch', `managed worktree at ${wt.path} changed while closing`, `Inspect ${wt.path}, then rerun \`crtr node worktree close\`.`);
146
145
  }
147
- persistClosedWorktreeState(nodeId, { ...wt, disposal: { observed_branch: branch, observed_sha: head, common_dir: commonDir, authorized: new Date().toISOString() } }, 'pending');
146
+ recordDisposalGrant(nodeId, { observed_branch: branch, observed_sha: head, common_dir: commonDir, authorized: new Date().toISOString() });
147
+ persistClosedWorktreeState(nodeId, wt, 'pending');
148
148
  return { node_id: nodeId, branch, worktree_path: wt.path, landed_sha: head, ...deferredCleanupResult(wt), branch_delete_error: `${branch} is not a crtr-managed branch and will never be deleted automatically; it is preserved once the checkout above is removed.` };
149
149
  }
150
150
  // Decide whether landing remains before resolving a destination. A diverged
@@ -1,6 +1,6 @@
1
1
  import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
2
2
  import { dirname, join, resolve } from 'node:path';
3
- import { getNode, updateNode } from './canvas/index.js';
3
+ import { abandonWorktreeAndRepoint, getNode } from './canvas/index.js';
4
4
  import { isPidAlive } from './canvas/pid.js';
5
5
  import { CONFIG_FILE, CRTR_DIR_NAME, STATE_FILE } from '../types.js';
6
6
  import { withExclusiveDirectoryLockAsync } from './exclusive-lock.js';
@@ -211,7 +211,7 @@ async function rebaseInProgress(cwd) {
211
211
  return false;
212
212
  }
213
213
  function persistAbandoned(nodeId, wt, tip, at, by, branch = wt.branch) {
214
- updateNode(nodeId, { cwd: wt.repo_root, managed_worktree: { ...wt, state: 'abandoned', abandoned: { branch, tip_sha: tip, at, by } } });
214
+ abandonWorktreeAndRepoint(nodeId, { cwd: wt.repo_root, abandoned: { branch, tip_sha: tip, at, by } });
215
215
  }
216
216
  export async function abandonManagedWorktreeAsync(nodeId, by) {
217
217
  const wt = getNode(nodeId)?.managed_worktree;
@@ -18,13 +18,13 @@
18
18
  import { createHash } from 'node:crypto';
19
19
  import { existsSync, realpathSync } from 'node:fs';
20
20
  import { resolve } from 'node:path';
21
- import { getNode, updateNode } from './canvas/index.js';
21
+ import { completeCleanup, getNode, recordSweepAttempt } from './canvas/index.js';
22
22
  import { withExclusiveDirectoryLockAsync } from './exclusive-lock.js';
23
23
  import { gitAsync } from './git.js';
24
24
  import { proveBranchContained, upstreamTip } from './worktree-containment.js';
25
25
  import { parseStatusPorcelain, planLandIntoCheckout, refDeleteTransactionStdin } from './worktree-landing.js';
26
26
  import { shellQuote } from '../shared/shell-quote.js';
27
- import { WORKTREE_LOCK_WAIT_MS, checkoutPathForBranchInList, persistClosedWorktreeState, samePath, worktreeLockPathForCommonDir } from './worktree.js';
27
+ import { WORKTREE_LOCK_WAIT_MS, checkoutPathForBranchInList, samePath, worktreeLockPathForCommonDir } from './worktree.js';
28
28
  /** Escalating recheck interval, in minutes, indexed by consecutive refusal. The
29
29
  * last tier is the cap AND the quarantine threshold: at that point the record
30
30
  * needs a human, so it is listed by `crtr sys worktrees` and costs one cheap
@@ -147,19 +147,14 @@ function recordUnfinished(nodeId, wt, outcome, observed, now, guard) {
147
147
  const current = getNode(nodeId)?.managed_worktree;
148
148
  if (current == null || !isReconcilable(current))
149
149
  return;
150
- updateNode(nodeId, {
151
- managed_worktree: {
152
- ...current,
153
- sweep: {
154
- reason: outcome.reason,
155
- ...(outcome.detail === undefined ? {} : { detail: outcome.detail }),
156
- observed,
157
- attempts,
158
- last_attempt: new Date(now).toISOString(),
159
- next_attempt: new Date(now + minutes * 60_000).toISOString(),
160
- ...(attempts >= QUARANTINE_ATTEMPTS ? { quarantined: true } : {}),
161
- },
162
- },
150
+ recordSweepAttempt(nodeId, {
151
+ reason: outcome.reason,
152
+ ...(outcome.detail === undefined ? {} : { detail: outcome.detail }),
153
+ observed,
154
+ attempts,
155
+ lastAttemptAt: new Date(now).toISOString(),
156
+ nextAttemptAt: new Date(now + minutes * 60_000).toISOString(),
157
+ quarantined: attempts >= QUARANTINE_ATTEMPTS,
163
158
  });
164
159
  }
165
160
  // Landing a blocked close the sweep is allowed to finish
@@ -327,7 +322,7 @@ function persistComplete(nodeId, wt, guard) {
327
322
  if (current == null || current.path !== wt.path || current.branch !== wt.branch) {
328
323
  return { status: 'skipped', reason: 'record_changed' };
329
324
  }
330
- persistClosedWorktreeState(nodeId, current, 'complete');
325
+ completeCleanup(nodeId);
331
326
  return { status: 'complete' };
332
327
  }
333
328
  /** Resume a record whose checkout is already gone — the crash-after-removal
@@ -3,7 +3,7 @@ import { createHash } from 'node:crypto';
3
3
  import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
4
4
  import { gitAsync, gitSync } from './git.js';
5
5
  import { crtrHome } from './canvas/paths.js';
6
- import { getNode, updateNode } from './canvas/index.js';
6
+ import { closeWorktreeAndRepoint, getNode, recordLandIntent } from './canvas/index.js';
7
7
  import { CONFIG_FILE, CRTR_DIR_NAME, STATE_FILE } from '../types.js';
8
8
  import { withExclusiveDirectoryLock } from './exclusive-lock.js';
9
9
  import { parseStatusPorcelain, planLandIntoCheckout, refDeleteTransactionStdin } from './worktree-landing.js';
@@ -344,16 +344,11 @@ export function isRebaseInProgress(cwd) {
344
344
  * sync. */
345
345
  export function persistClosedWorktreeState(nodeId, wt, cleanup = 'pending') {
346
346
  const node = getNode(nodeId);
347
- const sessionInvalidated = node?.pi_session_id != null || node?.pi_session_file != null;
348
- // Every caller reaches this only after CONCLUDING the land — it succeeded, or
349
- // the record was proven to have nothing to land. So a recorded land intent is
350
- // discharged here, and a recorded refusal describes a state that no longer
351
- // holds; dropping both leaves the sweep re-examining this record fresh.
352
- const { land_intent: _landIntent, sweep: _sweep, ...retained } = wt;
353
- updateNode(nodeId, {
347
+ closeWorktreeAndRepoint(nodeId, {
354
348
  cwd: wt.repo_root,
355
- ...(sessionInvalidated ? { pi_session_id: null, pi_session_file: null } : {}),
356
- managed_worktree: { ...retained, state: 'closed', cleanup, closed: new Date().toISOString() },
349
+ cleanup,
350
+ closedAt: new Date().toISOString(),
351
+ unbindSession: node?.pi_session_id != null || node?.pi_session_file != null,
357
352
  });
358
353
  }
359
354
  /** Record that this node ASKED to land and was blocked, so the daemon sweep may
@@ -366,8 +361,7 @@ function recordBlockedLandIntent(nodeId, blocked) {
366
361
  const current = getNode(nodeId)?.managed_worktree;
367
362
  if (current == null || current.state !== 'open')
368
363
  return;
369
- const { sweep: _sweep, ...retained } = current;
370
- updateNode(nodeId, { managed_worktree: { ...retained, land_intent: { at: new Date().toISOString(), blocked } } });
364
+ recordLandIntent(nodeId, { at: new Date().toISOString(), blocked });
371
365
  }
372
366
  /** Fast-forward a base branch that is CHECKED OUT somewhere, landing underneath
373
367
  * whatever local changes that checkout holds.
@@ -3,9 +3,7 @@ import assert from 'node:assert/strict';
3
3
  import { mkdtempSync, rmSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
- import { spawn } from 'node:child_process';
7
- import { DaemonStartupBlockedError, daemonAutostartSuppression, ensureDaemon, resetDaemonAutostart, verifyDaemonStartup, } from '../manage.js';
8
- import { DAEMON_EXIT_STARTUP_BLOCKED } from '../startup-policy.js';
6
+ import { ensureDaemon, resetDaemonAutostart, } from '../manage.js';
9
7
  import { withExclusiveDirectoryLockAsync } from '../../core/exclusive-lock.js';
10
8
  // REGRESSION (daemon respawn storm): a daemon whose startup hit a STANDING
11
9
  // condition — a blocked on-disk migration — exited, its attach clients saw a
@@ -31,42 +29,6 @@ after(() => {
31
29
  process.env['CRTR_NO_DAEMON_AUTOSTART'] = autostartEnv;
32
30
  resetDaemonAutostart();
33
31
  });
34
- test('the blocked-startup exit code surfaces as a typed terminal error, not a generic exit', async () => {
35
- let exited = null;
36
- const child = spawn(process.execPath, ['-e', `process.exit(${DAEMON_EXIT_STARTUP_BLOCKED})`], { stdio: 'ignore' });
37
- child.once('exit', (code, signal) => {
38
- exited = { code, signal };
39
- });
40
- await assert.rejects(async () => verifyDaemonStartup(77, 2_000, {
41
- readPidfile: () => null,
42
- isPidAlive: () => false,
43
- isDaemonServing: async () => false,
44
- childExited: () => exited,
45
- }), (error) => {
46
- assert.ok(error instanceof DaemonStartupBlockedError, 'must be typed, so the spawner can stop retrying');
47
- assert.match(error.message, /crtr sys migrate/);
48
- return true;
49
- });
50
- });
51
- test('a blocked start suppresses every later autostart instead of respawning into the same wall', async () => {
52
- let spawns = 0;
53
- const deps = {
54
- isDaemonRunning: () => false,
55
- spawnDaemon: async () => {
56
- spawns += 1;
57
- throw new DaemonStartupBlockedError(4242);
58
- },
59
- };
60
- ensureDaemon(deps);
61
- await settle();
62
- assert.equal(spawns, 1);
63
- assert.match(daemonAutostartSuppression() ?? '', /crtr sys migrate/);
64
- // The storm: every redial of every attach client lands here. None may spawn.
65
- for (let i = 0; i < 50; i++)
66
- ensureDaemon(deps);
67
- await settle();
68
- assert.equal(spawns, 1, 'a standing failure must never be retried');
69
- });
70
32
  test('an ordinary spawn failure backs off, then retries once the window passes', async () => {
71
33
  let spawns = 0;
72
34
  let now = 1_000_000;
@@ -22,8 +22,8 @@ export interface SourceDaemonProcess {
22
22
  signal: NodeJS.Signals | null;
23
23
  }>;
24
24
  }
25
- export declare function createSourceDaemonFixture(): Promise<SourceDaemonFixture>;
26
- export declare function startSourceDaemon(fixture: SourceDaemonFixture): SourceDaemonProcess;
25
+ export declare function createSourceDaemonFixture(opts?: Partial<Pick<SourceDaemonFixture, 'root' | 'home' | 'cwd' | 'canvasHome'>>): Promise<SourceDaemonFixture>;
26
+ export declare function startSourceDaemon(fixture: SourceDaemonFixture, envOverrides?: NodeJS.ProcessEnv): SourceDaemonProcess;
27
27
  export declare function healthRequest(port: number, timeoutMs?: number): Promise<boolean>;
28
28
  export declare function waitForHealth(process: SourceDaemonProcess, port: number, timeoutMs?: number): Promise<void>;
29
29
  export declare function healthWasReadyBeforeExit(process: SourceDaemonProcess, port: number): Promise<boolean>;
@@ -20,11 +20,11 @@ async function reserveTcpPort() {
20
20
  await new Promise((resolve, reject) => server.close((error) => error === undefined ? resolve() : reject(error)));
21
21
  return address.port;
22
22
  }
23
- export async function createSourceDaemonFixture() {
24
- const root = mkdtempSync('/tmp/crtr-migration-daemon-');
25
- const home = join(root, 'home');
26
- const cwd = join(home, 'work');
27
- const canvasHome = join(root, 'canvas');
23
+ export async function createSourceDaemonFixture(opts = {}) {
24
+ const root = opts.root ?? mkdtempSync('/tmp/crtr-migration-daemon-');
25
+ const home = opts.home ?? join(root, 'home');
26
+ const cwd = opts.cwd ?? join(home, 'work');
27
+ const canvasHome = opts.canvasHome ?? join(root, 'canvas');
28
28
  const pidfile = join(canvasHome, 'ready.pid');
29
29
  const socket = join(canvasHome, 'crtrd.sock');
30
30
  mkdirSync(cwd, { recursive: true });
@@ -41,7 +41,7 @@ export async function createSourceDaemonFixture() {
41
41
  dispose: () => rmSync(root, { recursive: true, force: true }),
42
42
  };
43
43
  }
44
- export function startSourceDaemon(fixture) {
44
+ export function startSourceDaemon(fixture, envOverrides = {}) {
45
45
  const require = createRequire(import.meta.url);
46
46
  const tsxLoader = pathToFileURL(require.resolve('tsx/esm')).href;
47
47
  const entry = fileURLToPath(new URL('../../crtrd-cli.ts', import.meta.url));
@@ -72,6 +72,7 @@ export function startSourceDaemon(fixture) {
72
72
  'NODE_OPTIONS',
73
73
  ])
74
74
  delete env[key];
75
+ Object.assign(env, envOverrides);
75
76
  const child = spawn(process.execPath, [
76
77
  '--conditions=crtr-src',
77
78
  '--import', tsxLoader,
@@ -1,9 +1,9 @@
1
1
  import assert from 'node:assert/strict';
2
- import { existsSync, mkdirSync, readFileSync, statSync, watch, writeFileSync } from 'node:fs';
2
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import test from 'node:test';
5
5
  import { onDiskMigrationIdentity } from '../../../migrations/registry.js';
6
- import { brokerPidsForCanvas, createSourceDaemonFixture, healthWasReadyBeforeExit, startSourceDaemon, waitForHealth, } from '../helpers/source-daemon.js';
6
+ import { brokerPidsForCanvas, createSourceDaemonFixture, startSourceDaemon, waitForHealth, } from '../helpers/source-daemon.js';
7
7
  const PRE_MIGRATION_DOC = `---
8
8
  kind: knowledge
9
9
  name: daemon-ordering
@@ -24,7 +24,11 @@ function writeUserMemory(home, name, source) {
24
24
  writeFileSync(path, source, 'utf8');
25
25
  return path;
26
26
  }
27
- test('source daemon migrates the pre-migration corpus and writes its marker before API readiness', { timeout: 30_000 }, async () => {
27
+ async function requestJson(port, path, init = {}) {
28
+ const response = await fetch(`http://127.0.0.1:${port}${path}`, init);
29
+ return { status: response.status, body: await response.json() };
30
+ }
31
+ test('source daemon migrates the pre-migration corpus before full readiness', { timeout: 30_000 }, async () => {
28
32
  const fixture = await createSourceDaemonFixture();
29
33
  const docPath = writeUserMemory(fixture.home, 'daemon-ordering.md', PRE_MIGRATION_DOC);
30
34
  const markerPath = join(fixture.canvasHome, 'on-disk-migrations.json');
@@ -41,8 +45,8 @@ test('source daemon migrates the pre-migration corpus and writes its marker befo
41
45
  assert.equal(existsSync(markerPath), true, `marker was not written; stderr:\n${daemon.stderr()}`);
42
46
  const migratedAtMarker = readFileSync(docPath, 'utf8');
43
47
  assert.doesNotMatch(migratedAtMarker, /system-prompt-visibility:|file-read-visibility:|applies-to:|read-when:/);
44
- assert.equal(existsSync(fixture.pidfile), false, 'pidfile readiness is not published when the marker first appears');
45
- assert.equal(existsSync(fixture.socket), false, 'API readiness is not published when the marker first appears');
48
+ assert.equal(existsSync(fixture.pidfile), true, 'the live owner mirror is published at the restricted repair boundary');
49
+ assert.equal(existsSync(fixture.socket), true, 'the repair listener is bound before corpus activation completes');
46
50
  await waitForHealth(daemon, fixture.tcpPort);
47
51
  const migrated = readFileSync(docPath, 'utf8');
48
52
  assert.doesNotMatch(migrated, /system-prompt-visibility:|file-read-visibility:|applies-to:|read-when:/);
@@ -53,8 +57,8 @@ test('source daemon migrates the pre-migration corpus and writes its marker befo
53
57
  assert.equal(existsSync(fixture.pidfile), true, 'health readiness follows the pidfile readiness mirror');
54
58
  assert.equal(existsSync(fixture.socket), true, 'the unique unix API listener is bound at readiness');
55
59
  assert.equal(existsSync(dbPath), true, 'daemon ownership has opened canvas.db by readiness');
56
- assert.ok(statSync(markerPath).mtimeMs <= statSync(fixture.pidfile).mtimeMs, 'the completion marker is written no later than the readiness pidfile');
57
- assert.ok(statSync(markerPath).mtimeMs <= statSync(fixture.socket).mtimeMs, 'the completion marker is written no later than the API listener');
60
+ assert.ok(statSync(fixture.pidfile).mtimeMs <= statSync(markerPath).mtimeMs, 'the pidfile is written before the completion marker');
61
+ assert.ok(statSync(fixture.socket).mtimeMs <= statSync(markerPath).mtimeMs, 'the repair listener is bound before the completion marker');
58
62
  }
59
63
  finally {
60
64
  const exit = await daemon.stop();
@@ -62,33 +66,62 @@ test('source daemon migrates the pre-migration corpus and writes its marker befo
62
66
  assert.deepEqual(exit, { code: 0, signal: null }, `daemon must stop cleanly; stderr:\n${daemon.stderr()}`);
63
67
  }
64
68
  });
65
- test('a real migration blocker exits before pidfile, listeners, or broker effects', { timeout: 30_000 }, async () => {
69
+ test('a real migration blocker keeps a restricted daemon alive for repair', { timeout: 30_000 }, async () => {
66
70
  const fixture = await createSourceDaemonFixture();
67
71
  const blockerPath = writeUserMemory(fixture.home, 'blocked.md', `---\nkind: knowledge\nbroken: [\n---\n# Blocked\n`);
68
- const effectNames = new Set();
69
- const effects = watch(fixture.canvasHome, (_event, filename) => {
70
- if (filename !== null)
71
- effectNames.add(filename.toString());
72
- });
73
72
  const daemon = startSourceDaemon(fixture);
74
- const readiness = healthWasReadyBeforeExit(daemon, fixture.tcpPort);
75
- const exit = await daemon.exited;
76
- const wasReady = await readiness;
77
- await new Promise((resolve) => setTimeout(resolve, 20));
78
- effects.close();
79
73
  try {
80
- assert.equal(exit.signal, null);
81
- assert.notEqual(exit.code, 0, `blocker must exit nonzero; stderr:\n${daemon.stderr()}`);
82
- assert.match(daemon.stderr(), new RegExp(blockerPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
83
- assert.match(daemon.stderr(), /Repair: crtr sys migrate/);
84
- assert.equal(wasReady, false, 'the unique TCP endpoint never answered health');
85
- assert.equal(existsSync(fixture.pidfile), false, 'readiness pidfile was never created');
86
- assert.equal(existsSync(fixture.socket), false, 'unix API listener was never created');
74
+ const deadline = Date.now() + 20_000;
75
+ let health;
76
+ while (Date.now() < deadline) {
77
+ try {
78
+ const response = await requestJson(fixture.tcpPort, '/healthz');
79
+ if (response.status === 503) {
80
+ health = response;
81
+ break;
82
+ }
83
+ }
84
+ catch {
85
+ // The repair listener has not bound yet.
86
+ }
87
+ await new Promise((resolve) => setTimeout(resolve, 10));
88
+ }
89
+ assert.ok(health, `source daemon did not reach restricted startup:\n${daemon.stderr()}`);
90
+ assert.equal(daemon.child.exitCode, null, `blocker must keep daemon alive; stderr:\n${daemon.stderr()}`);
91
+ assert.deepEqual(health.body, {
92
+ ok: false,
93
+ daemon_up: true,
94
+ store_accessible: true,
95
+ brokers_reconciled: false,
96
+ startup_phase: 'blocked',
97
+ startup_blocked: health.body.startup_blocked,
98
+ });
99
+ assert.match(health.body.startup_blocked, new RegExp(blockerPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
100
+ assert.match(health.body.startup_blocked, /Repair: crtr sys migrate/);
101
+ const status = await requestJson(fixture.tcpPort, '/v1/status');
102
+ assert.equal(status.status, 200, 'restricted startup keeps daemon status diagnostic available');
103
+ const refused = await requestJson(fixture.tcpPort, '/v1/nodes', { method: 'POST', body: '{}' });
104
+ assert.equal(refused.status, 503, 'normal node creation is refused during restricted startup');
105
+ assert.deepEqual(refused.body, {
106
+ error: { code: 'startup_blocked', message: health.body.startup_blocked },
107
+ });
108
+ const repair = await requestJson(fixture.tcpPort, '/v1/daemon/migrate', {
109
+ method: 'POST',
110
+ headers: { 'content-type': 'application/json' },
111
+ body: JSON.stringify({ dry_run: true }),
112
+ });
113
+ assert.equal(repair.status, 200, 'the restricted daemon serves a repair preview');
114
+ assert.equal(repair.body.blocked, true);
115
+ assert.equal(repair.body.dryRun, true);
116
+ assert.equal(repair.body.resumed, false);
117
+ assert.equal(existsSync(fixture.pidfile), true, 'the live owner mirror remains while startup is blocked');
118
+ assert.equal(existsSync(fixture.socket), true, 'the repair socket remains while startup is blocked');
87
119
  assert.equal(existsSync(join(fixture.canvasHome, 'on-disk-migrations.json')), false, 'blocker never gets a completion marker');
88
120
  assert.deepEqual(brokerPidsForCanvas(fixture.canvasHome), [], 'no broker process declares the isolated canvas');
89
- assert.deepEqual([...effectNames].filter((name) => name === 'ready.pid' || name === 'crtrd.sock'), [], `filesystem watcher saw no transient readiness or broker effects (all events: ${[...effectNames].join(', ')})`);
90
121
  }
91
122
  finally {
123
+ const exit = await daemon.stop();
92
124
  fixture.dispose();
125
+ assert.deepEqual(exit, { code: 0, signal: null }, `daemon must stop cleanly; stderr:\n${daemon.stderr()}`);
93
126
  }
94
127
  });
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict';
3
3
  import { mkdtempSync, rmSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
- import { closeDb } from '../../core/canvas/db.js';
6
+ import { closeDb, migrate, openDb } from '../../core/canvas/db.js';
7
7
  import { createNode, dueNodeDeadlines, getRow } from '../../core/canvas/canvas.js';
8
8
  import { pushFinal } from '../../core/feed/feed.js';
9
9
  import { transition } from '../../core/runtime/lifecycle.js';
@@ -30,6 +30,7 @@ beforeEach(() => {
30
30
  closeDb();
31
31
  home = mkdtempSync(join(tmpdir(), 'crtr-node-deadline-'));
32
32
  process.env['CRTR_HOME'] = home;
33
+ migrate(openDb());
33
34
  });
34
35
  afterEach(() => {
35
36
  closeDb();
@@ -3,15 +3,17 @@ import assert from 'node:assert/strict';
3
3
  import { mkdtempSync, rmSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
- import { closeDb } from '../../core/canvas/db.js';
6
+ import { closeDb, migrate, openDb, withCanvasWrite } from '../../core/canvas/db.js';
7
+ import { initializeFreshScopedStore } from '../../core/scoped-state/migrate.js';
7
8
  import { createNode, getRow, transitionStatusIntent } from '../../core/canvas/canvas.js';
8
- import { armOutcomeDelivery, readOutcomeDelivery } from '../../core/canvas/node-outcome-deliveries.js';
9
+ import { armExternalActionDelivery, messageBodyForDelivery, readExternalActionDelivery } from '../../core/canvas/deliveries.js';
9
10
  import { pushFinal } from '../../core/feed/feed.js';
10
11
  import { transition } from '../../core/runtime/lifecycle.js';
11
12
  import { spawnNode } from '../../core/runtime/nodes.js';
12
13
  import { spawnChildPrepared } from '../../core/runtime/spawn.js';
13
14
  let home;
14
15
  const priorHome = process.env.CRTR_HOME;
16
+ const priorUserHome = process.env.HOME;
15
17
  function node(nodeId, opts = {}) {
16
18
  return {
17
19
  node_id: nodeId,
@@ -32,10 +34,27 @@ const binding = {
32
34
  configOrigin: 'test',
33
35
  payload: { callback: 'one' },
34
36
  };
37
+ function outcomeDelivery(nodeId) {
38
+ return readExternalActionDelivery(`node-outcome:${nodeId}`);
39
+ }
40
+ function outcomePayload(nodeId) {
41
+ const adapter = outcomeDelivery(nodeId)?.adapter;
42
+ return adapter?.payload ?? null;
43
+ }
44
+ function armOutcomeAction(nodeId, input = binding) {
45
+ withCanvasWrite((db) => armExternalActionDelivery(db, {
46
+ destinationId: input.actionName,
47
+ adapter: { adapter: 'subprocess', argv: input.argv, cwd: input.cwd, config_origin: input.configOrigin, payload: input.payload },
48
+ idempotencyKey: `node-outcome:${nodeId}`,
49
+ }));
50
+ }
35
51
  beforeEach(() => {
36
52
  closeDb();
37
53
  home = mkdtempSync(join(tmpdir(), 'crtr-outcome-birth-'));
38
54
  process.env.CRTR_HOME = home;
55
+ process.env.HOME = home;
56
+ initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
57
+ migrate(openDb());
39
58
  });
40
59
  afterEach(() => {
41
60
  closeDb();
@@ -46,6 +65,10 @@ after(() => {
46
65
  delete process.env.CRTR_HOME;
47
66
  else
48
67
  process.env.CRTR_HOME = priorHome;
68
+ if (priorUserHome === undefined)
69
+ delete process.env.HOME;
70
+ else
71
+ process.env.HOME = priorUserHome;
49
72
  });
50
73
  test('birth commits the requested deadline and outcome registration before spawn orchestration can launch a broker', async () => {
51
74
  const deadlineAt = '2026-01-01T00:00:00.000Z';
@@ -57,10 +80,10 @@ test('birth commits the requested deadline and outcome registration before spawn
57
80
  outcomeDelivery: binding,
58
81
  });
59
82
  assert.equal(getRow(born.node_id)?.deadline_at, deadlineAt);
60
- assert.deepEqual(readOutcomeDelivery(born.node_id) && {
61
- state: readOutcomeDelivery(born.node_id).state,
62
- action: readOutcomeDelivery(born.node_id).actionName,
63
- payload: readOutcomeDelivery(born.node_id).payload,
83
+ assert.deepEqual(outcomeDelivery(born.node_id) && {
84
+ state: outcomeDelivery(born.node_id).state,
85
+ action: outcomeDelivery(born.node_id).destinationId,
86
+ payload: outcomePayload(born.node_id),
64
87
  }, {
65
88
  state: 'armed',
66
89
  action: 'test-action',
@@ -71,7 +94,7 @@ test('a pre-launch spawn failure leaves its caller-requested outcome delivery pe
71
94
  let nodeId;
72
95
  await assert.rejects(() => spawnChildPrepared({
73
96
  kind: 'general',
74
- cwd: process.cwd(),
97
+ cwd: home,
75
98
  root: true,
76
99
  profile: null,
77
100
  prompt: '',
@@ -83,12 +106,12 @@ test('a pre-launch spawn failure leaves its caller-requested outcome delivery pe
83
106
  }), /simulated pre-launch failure/);
84
107
  assert.ok(nodeId);
85
108
  assert.equal(getRow(nodeId)?.outcome_reason, 'launch_failed');
86
- assert.equal(readOutcomeDelivery(nodeId)?.state, 'pending');
87
- assert.ok(readOutcomeDelivery(nodeId)?.document);
109
+ assert.equal(outcomeDelivery(nodeId)?.state, 'pending');
110
+ assert.ok(messageBodyForDelivery(outcomeDelivery(nodeId).deliveryId));
88
111
  });
89
112
  test('an armed delivery cannot become pending without its outcome document', () => {
90
113
  createNode(node('guarded'));
91
- armOutcomeDelivery({ nodeId: 'guarded', ...binding });
114
+ armOutcomeAction('guarded');
92
115
  transitionStatusIntent('guarded', { status: 'dead', terminal_reason: 'crashed' }, {
93
116
  outcome: {
94
117
  kind: 'failure',
@@ -98,16 +121,17 @@ test('an armed delivery cannot become pending without its outcome document', ()
98
121
  documentJson: null,
99
122
  },
100
123
  });
101
- const delivery = readOutcomeDelivery('guarded');
124
+ const delivery = outcomeDelivery('guarded');
102
125
  assert.equal(delivery?.state, 'armed');
103
- assert.equal(delivery?.document, null);
126
+ assert.equal(messageBodyForDelivery(delivery.deliveryId), null);
104
127
  });
105
- test('late registration composes the latched terminal view from hydrated node identity', () => {
128
+ test('terminal transition composes the latched terminal view from hydrated node identity', () => {
106
129
  createNode(node('late', { spawned_by: 'origin' }));
130
+ armOutcomeAction('late');
107
131
  transition('late', 'crash');
108
132
  transition('late', 'revive');
109
- const delivery = armOutcomeDelivery({ nodeId: 'late', ...binding });
110
- const document = delivery?.document;
133
+ const delivery = outcomeDelivery('late');
134
+ const document = messageBodyForDelivery(delivery.deliveryId);
111
135
  assert.equal(document.node.status, 'dead');
112
136
  assert.equal(document.node.terminalReason, 'crashed');
113
137
  assert.equal(document.node.spawnedBy, 'origin');
@@ -3,27 +3,48 @@ import assert from 'node:assert/strict';
3
3
  import { chmodSync, existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
- import { closeDb } from '../../core/canvas/db.js';
6
+ import { closeDb, migrate, openDb, withCanvasWrite } from '../../core/canvas/db.js';
7
+ import { initializeFreshScopedStore } from '../../core/scoped-state/migrate.js';
8
+ import { closeScopedStores } from '../../core/scoped-state/db.js';
7
9
  import { createNode } from '../../core/canvas/canvas.js';
8
10
  import { isPidAlive, killProcessGroup } from '../../core/canvas/pid.js';
9
- import { armOutcomeDelivery, claimOutcomeDelivery, readOutcomeDelivery } from '../../core/canvas/node-outcome-deliveries.js';
11
+ import { armExternalActionDelivery, claimExternalActionDelivery, messageBodyForDelivery, readExternalActionDelivery, settleDelivery } from '../../core/canvas/deliveries.js';
10
12
  import { transition } from '../../core/runtime/lifecycle.js';
11
13
  import { DELIVERY_TIMEOUT_MS } from '../delivery/run-delivery.js';
12
- import { deliverOutcome } from '../node-outcome/deliver-outcome.js';
14
+ import { runDelivery } from '../delivery/run-delivery.js';
13
15
  let home;
14
16
  let processGroupFiles;
15
17
  const priorHome = process.env.CRTR_HOME;
18
+ const priorUserHome = process.env.HOME;
16
19
  function node(nodeId) {
17
20
  return { node_id: nodeId, name: nodeId, created: new Date().toISOString(), cwd: home, kind: 'general', mode: 'base', lifecycle: 'terminal', status: 'active' };
18
21
  }
22
+ function outcomeDelivery(nodeId) {
23
+ return readExternalActionDelivery(`node-outcome:${nodeId}`);
24
+ }
25
+ async function deliverOutcome(delivery, claimOwner) {
26
+ const adapter = delivery.adapter;
27
+ if (adapter?.adapter !== 'subprocess' || !Array.isArray(adapter.argv) || !adapter.argv.every((entry) => typeof entry === 'string') || typeof adapter.cwd !== 'string')
28
+ throw new Error(`outcome delivery ${delivery.deliveryId} has an invalid subprocess adapter`);
29
+ const document = messageBodyForDelivery(delivery.deliveryId);
30
+ if (document === null)
31
+ throw new Error(`outcome delivery ${delivery.deliveryId} has no document`);
32
+ await runDelivery({ argv: adapter.argv, cwd: adapter.cwd, document, attempt: delivery.attempts }, (settlement) => settleDelivery(delivery.deliveryId, delivery.attempts, claimOwner, settlement, Date.now()));
33
+ }
19
34
  function claimScript(id, script) {
20
35
  const path = join(home, `${id}.sh`);
21
36
  writeFileSync(path, script);
22
37
  chmodSync(path, 0o755);
23
38
  createNode(node(id));
24
- armOutcomeDelivery({ nodeId: id, actionName: 'test', argv: [path], cwd: home, configOrigin: 'test' });
39
+ withCanvasWrite((db) => armExternalActionDelivery(db, {
40
+ destinationId: 'test',
41
+ adapter: { adapter: 'subprocess', argv: [path], cwd: home, config_origin: 'test' },
42
+ idempotencyKey: `node-outcome:${id}`,
43
+ }));
25
44
  transition(id, 'crash');
26
- const delivery = claimOutcomeDelivery(id, Date.now(), 'test-daemon');
45
+ const action = outcomeDelivery(id);
46
+ assert.ok(action);
47
+ const delivery = claimExternalActionDelivery(action.deliveryId, Date.now(), 'test-daemon');
27
48
  assert.ok(delivery);
28
49
  return delivery;
29
50
  }
@@ -31,6 +52,9 @@ beforeEach(() => {
31
52
  closeDb();
32
53
  home = mkdtempSync(join(tmpdir(), 'crtr-outcome-delivery-'));
33
54
  process.env.CRTR_HOME = home;
55
+ process.env.HOME = home;
56
+ initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
57
+ migrate(openDb());
34
58
  processGroupFiles = [];
35
59
  });
36
60
  afterEach(() => {
@@ -42,6 +66,7 @@ afterEach(() => {
42
66
  killProcessGroup(pid, 'SIGKILL');
43
67
  }
44
68
  closeDb();
69
+ closeScopedStores();
45
70
  rmSync(home, { recursive: true, force: true });
46
71
  });
47
72
  after(() => {
@@ -49,19 +74,23 @@ after(() => {
49
74
  delete process.env.CRTR_HOME;
50
75
  else
51
76
  process.env.CRTR_HOME = priorHome;
77
+ if (priorUserHome === undefined)
78
+ delete process.env.HOME;
79
+ else
80
+ process.env.HOME = priorUserHome;
52
81
  });
53
82
  test('exit acknowledgments settle outcome delivery durably', async () => {
54
83
  const accepted = claimScript('accepted', '#!/bin/sh\necho ignored\necho diagnostic >&2\nexit 0\n');
55
84
  await deliverOutcome(accepted, 'test-daemon');
56
- assert.equal(readOutcomeDelivery('accepted')?.state, 'accepted');
85
+ assert.equal(outcomeDelivery('accepted')?.state, 'acknowledged');
57
86
  const permanent = claimScript('permanent', '#!/bin/sh\nexit 78\n');
58
87
  await deliverOutcome(permanent, 'test-daemon');
59
- assert.equal(readOutcomeDelivery('permanent')?.state, 'permanent_failed');
88
+ assert.equal(outcomeDelivery('permanent')?.state, 'permanent_failed');
60
89
  const retry = claimScript('retry', '#!/bin/sh\necho retry-stderr >&2\nexit 1\n');
61
90
  await deliverOutcome(retry, 'test-daemon');
62
- const row = readOutcomeDelivery('retry');
91
+ const row = outcomeDelivery('retry');
63
92
  assert.equal(row?.state, 'pending');
64
- assert.ok(row.nextAttemptAt > Date.now());
93
+ assert.ok(row?.nextAttemptAt !== null && row?.nextAttemptAt !== undefined && row.nextAttemptAt > Date.now());
65
94
  assert.equal(row?.lastFailure?.kind, 'exit');
66
95
  assert.equal(row?.lastFailure?.stderr, 'retry-stderr\n');
67
96
  });
@@ -78,7 +107,7 @@ test('timeout SIGKILL escalation reaps a SIGTERM-ignoring descendant after its l
78
107
  finally {
79
108
  global.setTimeout = originalSetTimeout;
80
109
  }
81
- const row = readOutcomeDelivery('timeout');
110
+ const row = outcomeDelivery('timeout');
82
111
  assert.equal(row?.state, 'pending');
83
112
  assert.equal(row?.lastFailure?.kind, 'timeout');
84
113
  const pid = Number(readFileSync(childPid, 'utf8').trim());
@@ -12,7 +12,7 @@ import { BrokerSupervisionReconciler } from '../reconcilers/broker-supervision.j
12
12
  import { ControllerDeathReconciler } from '../reconcilers/controller-death.js';
13
13
  import { NodeLifecycleReconciler } from '../reconcilers/node-lifecycle/tick.js';
14
14
  import { CronLaneReconciler } from '../reconcilers/cron-lane.js';
15
- import { HumanDeliveryLaneReconciler } from '../reconcilers/human-delivery-lane.js';
15
+ import { DeliveryLaneReconciler } from '../reconcilers/delivery-lane.js';
16
16
  import { PendingReviewSubmitReconciler } from '../reconcilers/pending-review-submit.js';
17
17
  import { StorageMaintenanceReconciler } from '../reconcilers/storage-maintenance.js';
18
18
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -21,7 +21,7 @@ const RECONCILERS = [
21
21
  ['ControllerDeathReconciler', ControllerDeathReconciler],
22
22
  ['NodeLifecycleReconciler', NodeLifecycleReconciler],
23
23
  ['CronLaneReconciler', CronLaneReconciler],
24
- ['HumanDeliveryLaneReconciler', HumanDeliveryLaneReconciler],
24
+ ['DeliveryLaneReconciler', DeliveryLaneReconciler],
25
25
  ['PendingReviewSubmitReconciler', PendingReviewSubmitReconciler],
26
26
  ['StorageMaintenanceReconciler', StorageMaintenanceReconciler],
27
27
  ];