create-walle 0.10.2 → 0.10.3

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 (488) hide show
  1. package/README.md +3 -1
  2. package/lib/release-schema.json +2 -2
  3. package/lib/runtime-closure-policy.json +8 -7
  4. package/package.json +1 -1
  5. package/template/coding-task-manager/api-prompts.js +45 -7
  6. package/template/coding-task-manager/bin/claude-hook.js +55 -1
  7. package/template/coding-task-manager/bin/ctm-relay-client.js +35 -12
  8. package/template/coding-task-manager/bin/land.js +2069 -0
  9. package/template/coding-task-manager/bin/memory-census.js +4 -2
  10. package/template/coding-task-manager/bin/memory-sync-verify.js +151 -0
  11. package/template/coding-task-manager/bin/probe-refusal-scope.js +530 -0
  12. package/template/coding-task-manager/db.js +156 -32
  13. package/template/coding-task-manager/lib/acp/acp-client.js +383 -0
  14. package/template/coding-task-manager/lib/acp/dsh-context-truth.js +176 -0
  15. package/template/coding-task-manager/lib/acp/dsh-launch-model.js +302 -0
  16. package/template/coding-task-manager/lib/acp/dsh-mcp-servers.js +194 -0
  17. package/template/coding-task-manager/lib/acp/dsh-prompt-lane.js +616 -0
  18. package/template/coding-task-manager/lib/acp/dsh-route-patch.js +308 -0
  19. package/template/coding-task-manager/lib/acp/dsh-session-runtime.js +522 -0
  20. package/template/coding-task-manager/lib/acp/dsh-transcript.js +395 -0
  21. package/template/coding-task-manager/lib/acp/dsh-usage-log.js +162 -0
  22. package/template/coding-task-manager/lib/acp/ndjson-stdio-transport.js +225 -0
  23. package/template/coding-task-manager/lib/adopted-host-redial.js +47 -11
  24. package/template/coding-task-manager/lib/adopted-launch-environment.js +123 -0
  25. package/template/coding-task-manager/lib/agent-auto-update-runtime.js +0 -3
  26. package/template/coding-task-manager/lib/agent-auto-update.js +26 -10
  27. package/template/coding-task-manager/lib/agent-bundle/build.js +657 -0
  28. package/template/coding-task-manager/lib/agent-bundle/codex-install.js +558 -0
  29. package/template/coding-task-manager/lib/agent-bundle/drift.js +120 -0
  30. package/template/coding-task-manager/lib/agent-bundle/gc.js +522 -0
  31. package/template/coding-task-manager/lib/agent-bundle/inventory.js +346 -0
  32. package/template/coding-task-manager/lib/agent-bundle/push.js +717 -0
  33. package/template/coding-task-manager/lib/agent-bundle/skill-transfer.js +724 -0
  34. package/template/coding-task-manager/lib/agent-bundle/spawn.js +119 -0
  35. package/template/coding-task-manager/lib/agent-bundle/store.js +568 -0
  36. package/template/coding-task-manager/lib/agent-capabilities.js +142 -12
  37. package/template/coding-task-manager/lib/agent-cli-cache.js +30 -5
  38. package/template/coding-task-manager/lib/agent-definitions.js +19 -0
  39. package/template/coding-task-manager/lib/agent-hooks-codex-toml.js +28 -16
  40. package/template/coding-task-manager/lib/agent-hooks-codex-workspace.js +9 -1
  41. package/template/coding-task-manager/lib/agent-hooks-installer.js +23 -8
  42. package/template/coding-task-manager/lib/agent-hooks-prune.js +37 -11
  43. package/template/coding-task-manager/lib/agent-hooks-shim.js +105 -0
  44. package/template/coding-task-manager/lib/agent-presets.js +84 -1
  45. package/template/coding-task-manager/lib/agent-upgrade-jobs.js +12 -1
  46. package/template/coding-task-manager/lib/agent-version-service.js +74 -11
  47. package/template/coding-task-manager/lib/all-sessions-query.js +6 -2
  48. package/template/coding-task-manager/lib/api/agent-bundles.js +436 -0
  49. package/template/coding-task-manager/lib/api/backup-retention.js +83 -0
  50. package/template/coding-task-manager/lib/api/conversation-sync-routes.js +124 -0
  51. package/template/coding-task-manager/lib/api/diagnostics.js +549 -69
  52. package/template/coding-task-manager/lib/api/fleet.js +118 -0
  53. package/template/coding-task-manager/lib/api/hub-bridge.js +243 -0
  54. package/template/coding-task-manager/lib/api/ingress.js +9 -1
  55. package/template/coding-task-manager/lib/api/landing.js +403 -0
  56. package/template/coding-task-manager/lib/api/machines.js +691 -2
  57. package/template/coding-task-manager/lib/api/memory-sync-routes.js +335 -0
  58. package/template/coding-task-manager/lib/api/misc-ops.js +8 -3
  59. package/template/coding-task-manager/lib/api/remote-sessions.js +1326 -0
  60. package/template/coding-task-manager/lib/api/session-attach.js +623 -0
  61. package/template/coding-task-manager/lib/api/session-messages.js +1384 -0
  62. package/template/coding-task-manager/lib/api/sessions.js +77 -51
  63. package/template/coding-task-manager/lib/api/setup-network.js +544 -16
  64. package/template/coding-task-manager/lib/api/setup-wizard-handlers.js +884 -0
  65. package/template/coding-task-manager/lib/api/setup.js +829 -10
  66. package/template/coding-task-manager/lib/api/walle-bridge.js +9 -1
  67. package/template/coding-task-manager/lib/attachment-reconciler-wiring.js +5 -2
  68. package/template/coding-task-manager/lib/auth-rate-limit.js +23 -0
  69. package/template/coding-task-manager/lib/auth-rules.js +292 -21
  70. package/template/coding-task-manager/lib/background-stop.js +369 -0
  71. package/template/coding-task-manager/lib/best-of-attempts.js +4 -1
  72. package/template/coding-task-manager/lib/best-of-launch-plan.js +52 -0
  73. package/template/coding-task-manager/lib/box-keep-awake.js +89 -0
  74. package/template/coding-task-manager/lib/broadcast-reason-stats.js +152 -0
  75. package/template/coding-task-manager/lib/broadcast-serialize.js +5 -0
  76. package/template/coding-task-manager/lib/build-info.js +4 -2
  77. package/template/coding-task-manager/lib/claude-model-truth.js +13 -2
  78. package/template/coding-task-manager/lib/claude-transcript-terminal-renderer.js +17 -13
  79. package/template/coding-task-manager/lib/client-diag-handler.js +64 -2
  80. package/template/coding-task-manager/lib/codex-app-server-client.js +14 -16
  81. package/template/coding-task-manager/lib/codex-configuration-history.js +55 -0
  82. package/template/coding-task-manager/lib/codex-harness-qualification.js +43 -20
  83. package/template/coding-task-manager/lib/codex-rollout-history.js +743 -0
  84. package/template/coding-task-manager/lib/coding-agent-models.js +27 -12
  85. package/template/coding-task-manager/lib/coding-cli-skill-installer.js +44 -14
  86. package/template/coding-task-manager/lib/coding-session-model-adapters.js +43 -2
  87. package/template/coding-task-manager/lib/coding-session-model-owner.js +1 -1
  88. package/template/coding-task-manager/lib/coding-session-model-public.js +7 -1
  89. package/template/coding-task-manager/lib/coding-session-model-runtime.js +23 -4
  90. package/template/coding-task-manager/lib/coding-session-model-scan.js +31 -0
  91. package/template/coding-task-manager/lib/coding-session-model-state.js +7 -0
  92. package/template/coding-task-manager/lib/conversation-freshness-diagnostics.js +280 -0
  93. package/template/coding-task-manager/lib/conversation-item-clock.js +261 -0
  94. package/template/coding-task-manager/lib/conversation-source-registry.js +5 -0
  95. package/template/coding-task-manager/lib/conversation-store-v2.js +44 -0
  96. package/template/coding-task-manager/lib/conversation-sync.js +355 -0
  97. package/template/coding-task-manager/lib/create/resolve-launch-params.js +96 -12
  98. package/template/coding-task-manager/lib/create/worker-role-profile.js +4 -4
  99. package/template/coding-task-manager/lib/create-intent-lease.js +51 -0
  100. package/template/coding-task-manager/lib/ctm-session-context-api.js +97 -6
  101. package/template/coding-task-manager/lib/db-domain-tables.js +1 -0
  102. package/template/coding-task-manager/lib/db-domains.js +1 -0
  103. package/template/coding-task-manager/lib/db-owner-dispatch-probe.js +32 -0
  104. package/template/coding-task-manager/lib/db-owner-request-counts.js +178 -0
  105. package/template/coding-task-manager/lib/db-owner-worker-client.js +68 -14
  106. package/template/coding-task-manager/lib/db-schema-source-files.js +5 -0
  107. package/template/coding-task-manager/lib/deferred-restore-attempt.js +6 -2
  108. package/template/coding-task-manager/lib/feature-manifest.js +4 -0
  109. package/template/coding-task-manager/lib/fleet-conversation-route.js +97 -0
  110. package/template/coding-task-manager/lib/fleet-fanout.js +78 -0
  111. package/template/coding-task-manager/lib/fleet-hub.js +762 -0
  112. package/template/coding-task-manager/lib/fleet-origin-follower.js +252 -0
  113. package/template/coding-task-manager/lib/fleet-resolver-effects.js +147 -0
  114. package/template/coding-task-manager/lib/fleet-resolver-tick.js +148 -0
  115. package/template/coding-task-manager/lib/fleet-resolver.js +454 -0
  116. package/template/coding-task-manager/lib/fleet-session-list-routes.js +114 -0
  117. package/template/coding-task-manager/lib/fleet-session-lists.js +672 -0
  118. package/template/coding-task-manager/lib/fleet-update.js +798 -0
  119. package/template/coding-task-manager/lib/fs-watcher-root-watch.js +141 -0
  120. package/template/coding-task-manager/lib/fs-watcher.js +58 -42
  121. package/template/coding-task-manager/lib/harness-history-transition.js +50 -9
  122. package/template/coding-task-manager/lib/headless-term-service.js +84 -8
  123. package/template/coding-task-manager/lib/hermetic-agent-launch-guard.js +10 -0
  124. package/template/coding-task-manager/lib/history-transition-read-op.js +175 -8
  125. package/template/coding-task-manager/lib/host-cpu-categories.js +310 -0
  126. package/template/coding-task-manager/lib/host-fseventsd-sampler.js +399 -0
  127. package/template/coding-task-manager/lib/host-handoff.js +16 -19
  128. package/template/coding-task-manager/lib/host-stats.js +150 -3
  129. package/template/coding-task-manager/lib/hosted-sync-worker.js +43 -320
  130. package/template/coding-task-manager/lib/hub-bridge-access.js +798 -0
  131. package/template/coding-task-manager/lib/hub-bridge-box.js +409 -0
  132. package/template/coding-task-manager/lib/hub-bridge-mcp.js +380 -0
  133. package/template/coding-task-manager/lib/hub-bridge-mesh.js +313 -0
  134. package/template/coding-task-manager/lib/hub-bridge-ops.js +721 -0
  135. package/template/coding-task-manager/lib/hub-bridge.js +398 -0
  136. package/template/coding-task-manager/lib/idle-notify.js +491 -0
  137. package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +8 -0
  138. package/template/coding-task-manager/lib/instance-manifest.js +5 -1
  139. package/template/coding-task-manager/lib/instance-sync-status.js +18 -8
  140. package/template/coding-task-manager/lib/landing/agent-rule.txt +1 -0
  141. package/template/coding-task-manager/lib/landing/batch-runner.js +366 -0
  142. package/template/coding-task-manager/lib/landing/config.js +536 -0
  143. package/template/coding-task-manager/lib/landing/ctm-view.js +256 -0
  144. package/template/coding-task-manager/lib/landing/gate.js +360 -0
  145. package/template/coding-task-manager/lib/landing/git.js +344 -0
  146. package/template/coding-task-manager/lib/landing/lease.js +247 -0
  147. package/template/coding-task-manager/lib/landing/merge-delta.js +380 -0
  148. package/template/coding-task-manager/lib/landing/proof.js +223 -0
  149. package/template/coding-task-manager/lib/landing/queue.js +998 -0
  150. package/template/coding-task-manager/lib/landing/radar.js +489 -0
  151. package/template/coding-task-manager/lib/landing/resolve-cli.js +424 -0
  152. package/template/coding-task-manager/lib/landing/state.js +263 -0
  153. package/template/coding-task-manager/lib/landing/stop.js +49 -0
  154. package/template/coding-task-manager/lib/landing/sync-cli.js +475 -0
  155. package/template/coding-task-manager/lib/landing/sync.js +456 -0
  156. package/template/coding-task-manager/lib/landing/train.js +885 -0
  157. package/template/coding-task-manager/lib/landing/window.js +57 -0
  158. package/template/coding-task-manager/lib/launch-environment.js +121 -0
  159. package/template/coding-task-manager/lib/launch-model-override.js +36 -10
  160. package/template/coding-task-manager/lib/launch-plan-pool.js +2 -1
  161. package/template/coding-task-manager/lib/launch-plan-warm-cache.js +6 -0
  162. package/template/coding-task-manager/lib/lead-model-observer.js +57 -1
  163. package/template/coding-task-manager/lib/lead-model-options.js +160 -3
  164. package/template/coding-task-manager/lib/lead-model-restore-reconciliation.js +106 -24
  165. package/template/coding-task-manager/lib/lead-model-switch-runtime.js +352 -68
  166. package/template/coding-task-manager/lib/lead-model-switch.js +114 -10
  167. package/template/coding-task-manager/lib/lead-model-transition-runtime.js +14 -2
  168. package/template/coding-task-manager/lib/lead-model-transition-store.js +24 -6
  169. package/template/coding-task-manager/lib/lead-route-preflight.js +179 -0
  170. package/template/coding-task-manager/lib/lead-switch-history-mode.js +110 -0
  171. package/template/coding-task-manager/lib/lead-wire-agent.js +7 -0
  172. package/template/coding-task-manager/lib/lifecycle-wake-experiment.js +9 -2
  173. package/template/coding-task-manager/lib/live-defer-announce.js +45 -0
  174. package/template/coding-task-manager/lib/machine-registry.js +750 -5
  175. package/template/coding-task-manager/lib/macos-capabilities.js +32 -15
  176. package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +433 -53
  177. package/template/coding-task-manager/lib/mainloop-observability.js +14 -9
  178. package/template/coding-task-manager/lib/media-draft-owner.js +16 -3
  179. package/template/coding-task-manager/lib/memory-join.js +337 -0
  180. package/template/coding-task-manager/lib/memory-sync-verify.js +393 -0
  181. package/template/coding-task-manager/lib/memory-sync.js +565 -0
  182. package/template/coding-task-manager/lib/migrations/v57-delegate-pref-mirror-opencode.js +68 -0
  183. package/template/coding-task-manager/lib/migrations/v58-subagent-launch-native-subagents.js +42 -0
  184. package/template/coding-task-manager/lib/migrations/v59-coding-session-model-state-dsh.js +73 -0
  185. package/template/coding-task-manager/lib/migrations/v60-delegate-pref-mirror-dsh.js +78 -0
  186. package/template/coding-task-manager/lib/migrations/v61-conversation-item-clock.js +71 -0
  187. package/template/coding-task-manager/lib/model-availability.js +727 -0
  188. package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +4 -6
  189. package/template/coding-task-manager/lib/model-host-receipt.js +6 -3
  190. package/template/coding-task-manager/lib/model-id-rule.js +19 -0
  191. package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
  192. package/template/coding-task-manager/lib/model-proxy/auto-mode-review.js +110 -23
  193. package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
  194. package/template/coding-task-manager/lib/model-proxy/generation-probe.js +60 -17
  195. package/template/coding-task-manager/lib/model-proxy/historical-tool-declarations.js +37 -0
  196. package/template/coding-task-manager/lib/model-proxy/lead-request-validation.js +1 -0
  197. package/template/coding-task-manager/lib/model-proxy/lead-token-admin.js +130 -0
  198. package/template/coding-task-manager/lib/model-proxy/refusal-scope.js +151 -0
  199. package/template/coding-task-manager/lib/model-proxy/request-budget-store.js +11 -2
  200. package/template/coding-task-manager/lib/model-proxy/tokens.js +69 -5
  201. package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
  202. package/template/coding-task-manager/lib/native-agent-model-args.js +25 -22
  203. package/template/coding-task-manager/lib/native-history-control.js +6 -4
  204. package/template/coding-task-manager/lib/native-lead-settings-client.js +44 -4
  205. package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +173 -36
  206. package/template/coding-task-manager/lib/online-backup-worker-client.js +2 -0
  207. package/template/coding-task-manager/lib/opencode-cli.js +480 -0
  208. package/template/coding-task-manager/lib/opencode-launch-model.js +471 -0
  209. package/template/coding-task-manager/lib/opencode-v1-plugin/model-carrier.mjs +35 -0
  210. package/template/coding-task-manager/lib/opencode-v2-plugin/server.js +118 -0
  211. package/template/coding-task-manager/lib/owner-action-manifest-data.json +1 -1
  212. package/template/coding-task-manager/lib/park-composer-draft.js +54 -0
  213. package/template/coding-task-manager/lib/park-fresh-relaunch.js +41 -10
  214. package/template/coding-task-manager/lib/perf-phase-trace.js +72 -0
  215. package/template/coding-task-manager/lib/perf-summary.js +7 -0
  216. package/template/coding-task-manager/lib/perf-tracker.js +63 -2
  217. package/template/coding-task-manager/lib/project-config.js +7 -0
  218. package/template/coding-task-manager/lib/prompt-purge-v2.js +52 -1
  219. package/template/coding-task-manager/lib/provider-login-broker.js +72 -15
  220. package/template/coding-task-manager/lib/provider-login-tab.js +10 -2
  221. package/template/coding-task-manager/lib/read-pool-client.js +89 -2
  222. package/template/coding-task-manager/lib/read-pool-worker-handle.js +29 -4
  223. package/template/coding-task-manager/lib/recent-catalog-query.js +15 -0
  224. package/template/coding-task-manager/lib/recent-session-catalog-response.js +67 -10
  225. package/template/coding-task-manager/lib/recovery-evidence.js +26 -11
  226. package/template/coding-task-manager/lib/relay-client.js +57 -3
  227. package/template/coding-task-manager/lib/relink-audit.js +34 -5
  228. package/template/coding-task-manager/lib/remote-machine-catalog.js +321 -26
  229. package/template/coding-task-manager/lib/remote-machine-create.js +576 -36
  230. package/template/coding-task-manager/lib/remote-machine-link.js +546 -59
  231. package/template/coding-task-manager/lib/remote-machine-proxy.js +143 -9
  232. package/template/coding-task-manager/lib/remote-session-forward.js +65 -7
  233. package/template/coding-task-manager/lib/remote-terminal-target.js +9 -2
  234. package/template/coding-task-manager/lib/restart-guard.js +18 -6
  235. package/template/coding-task-manager/lib/restore-seed-modes.js +87 -0
  236. package/template/coding-task-manager/lib/restored-scrollback-hydration-runtime.js +22 -2
  237. package/template/coding-task-manager/lib/resume-admission.js +17 -3
  238. package/template/coding-task-manager/lib/review-repo-registry.js +58 -19
  239. package/template/coding-task-manager/lib/root-delivery-runtime.js +2 -2
  240. package/template/coding-task-manager/lib/root-prompt-flow.js +1 -1
  241. package/template/coding-task-manager/lib/runtime-contract.js +3 -1
  242. package/template/coding-task-manager/lib/schema-indexes.js +1 -0
  243. package/template/coding-task-manager/lib/session-context-locator.js +742 -0
  244. package/template/coding-task-manager/lib/session-create/attachment.js +2 -2
  245. package/template/coding-task-manager/lib/session-create/create-phases.js +118 -0
  246. package/template/coding-task-manager/lib/session-create/delegate-worker.js +86 -16
  247. package/template/coding-task-manager/lib/session-create/dsh-session.js +930 -0
  248. package/template/coding-task-manager/lib/session-create/lead-route-launch.js +186 -13
  249. package/template/coding-task-manager/lib/session-create/native-lead-lifetime.js +55 -3
  250. package/template/coding-task-manager/lib/session-create/opencode-lead-provider.js +50 -0
  251. package/template/coding-task-manager/lib/session-create/prepared.js +162 -38
  252. package/template/coding-task-manager/lib/session-create/provider-process.js +160 -28
  253. package/template/coding-task-manager/lib/session-create/response.js +7 -7
  254. package/template/coding-task-manager/lib/session-create/structured-session.js +27 -0
  255. package/template/coding-task-manager/lib/session-create/subagent-pick-table.js +3 -1
  256. package/template/coding-task-manager/lib/session-create/subagent-pick.js +458 -9
  257. package/template/coding-task-manager/lib/session-create/transcript.js +1 -1
  258. package/template/coding-task-manager/lib/session-create/worker-budget-setup.js +21 -2
  259. package/template/coding-task-manager/lib/session-create/worker-continuation.js +7 -1
  260. package/template/coding-task-manager/lib/session-create/worker-launch-sandbox.js +39 -10
  261. package/template/coding-task-manager/lib/session-create/worker-observability.js +2 -2
  262. package/template/coding-task-manager/lib/session-empty.js +13 -10
  263. package/template/coding-task-manager/lib/session-host-manager.js +60 -0
  264. package/template/coding-task-manager/lib/session-jobs.js +3 -1
  265. package/template/coding-task-manager/lib/session-lifecycle.js +10 -4
  266. package/template/coding-task-manager/lib/session-model-action-preconditions.js +6 -2
  267. package/template/coding-task-manager/lib/session-model-intent-contract.js +11 -8
  268. package/template/coding-task-manager/lib/session-park.js +738 -0
  269. package/template/coding-task-manager/lib/session-path-grant.js +13 -4
  270. package/template/coding-task-manager/lib/session-status-ledger.js +106 -4
  271. package/template/coding-task-manager/lib/session-transport.js +17 -0
  272. package/template/coding-task-manager/lib/session-workspace-projection.js +54 -5
  273. package/template/coding-task-manager/lib/session-workspace-tracking-runtime.js +213 -1
  274. package/template/coding-task-manager/lib/skill-autocomplete-query.js +120 -3
  275. package/template/coding-task-manager/lib/skill-autocomplete.js +15 -1
  276. package/template/coding-task-manager/lib/sqlite-file-set.js +39 -0
  277. package/template/coding-task-manager/lib/standup-search-adapter.js +16 -2
  278. package/template/coding-task-manager/lib/state-sync/client-ledger.js +12 -0
  279. package/template/coding-task-manager/lib/state-sync/frame-emitter.js +319 -100
  280. package/template/coding-task-manager/lib/storage/coding-session-model-store.js +4 -1
  281. package/template/coding-task-manager/lib/storage/delegate-pref-mirror-store.js +32 -9
  282. package/template/coding-task-manager/lib/structured-session-boot-sweep.js +235 -0
  283. package/template/coding-task-manager/lib/submission-ack.js +90 -2
  284. package/template/coding-task-manager/lib/systemd-scope.js +115 -0
  285. package/template/coding-task-manager/lib/telemetry-receiver.js +39 -0
  286. package/template/coding-task-manager/lib/terminal-attach-geometry.js +985 -0
  287. package/template/coding-task-manager/lib/terminal-bootstrap.js +30 -0
  288. package/template/coding-task-manager/lib/terminal-draft-operation.js +357 -0
  289. package/template/coding-task-manager/lib/terminal-input-admission.js +17 -1
  290. package/template/coding-task-manager/lib/terminal-input-prepared.js +563 -0
  291. package/template/coding-task-manager/lib/transcript-cache-temps.js +171 -0
  292. package/template/coding-task-manager/lib/transcript-frame-cache.js +8 -3
  293. package/template/coding-task-manager/lib/transcript-source.js +36 -4
  294. package/template/coding-task-manager/lib/transcript-store.js +9 -0
  295. package/template/coding-task-manager/lib/typing-interaction-trace.js +106 -3
  296. package/template/coding-task-manager/lib/usage-ledger/backfill.js +40 -5
  297. package/template/coding-task-manager/lib/usage-ledger/client.js +4 -1
  298. package/template/coding-task-manager/lib/usage-ledger/dsh-parse.js +152 -0
  299. package/template/coding-task-manager/lib/usage-ledger/dsh-read.js +73 -0
  300. package/template/coding-task-manager/lib/usage-ledger/ingest.js +34 -6
  301. package/template/coding-task-manager/lib/usage-ledger/live.js +35 -8
  302. package/template/coding-task-manager/lib/usage-ledger/read.js +29 -20
  303. package/template/coding-task-manager/lib/usage-ledger/schema.js +61 -1
  304. package/template/coding-task-manager/lib/usage-ledger/task-coordinator.js +4 -2
  305. package/template/coding-task-manager/lib/wake-skip-reasons.js +1 -0
  306. package/template/coding-task-manager/lib/walle/turn.js +1 -1
  307. package/template/coding-task-manager/lib/walle-history-serve.js +838 -0
  308. package/template/coding-task-manager/lib/walle-kill-authority.js +2 -2
  309. package/template/coding-task-manager/lib/walle-log-rotation.js +164 -1
  310. package/template/coding-task-manager/lib/walle-mcp-auto-config.js +56 -2
  311. package/template/coding-task-manager/lib/walle-row-history.js +495 -0
  312. package/template/coding-task-manager/lib/walle-supervisor.js +33 -14
  313. package/template/coding-task-manager/lib/watch-worker-client.js +203 -0
  314. package/template/coding-task-manager/lib/worker-terminal-output.js +5 -2
  315. package/template/coding-task-manager/lib/ws/hub-bridge.js +35 -0
  316. package/template/coding-task-manager/lib/ws/lifecycle.js +6 -11
  317. package/template/coding-task-manager/lib/ws/misc.js +1 -1
  318. package/template/coding-task-manager/lib/ws/state-sync.js +106 -4
  319. package/template/coding-task-manager/lib/ws/terminal-attach.js +91 -0
  320. package/template/coding-task-manager/oauth-proxy.js +112 -115
  321. package/template/coding-task-manager/package-lock.json +10 -94
  322. package/template/coding-task-manager/package.json +4 -3
  323. package/template/coding-task-manager/protocol/message-table.json +10 -0
  324. package/template/coding-task-manager/protocol/messages.js +10 -0
  325. package/template/coding-task-manager/protocol/ws-schema.json +20 -0
  326. package/template/coding-task-manager/protocol/ws-schema.md +2 -0
  327. package/template/coding-task-manager/public/css/app.css +170 -0
  328. package/template/coding-task-manager/public/css/walle-session.css +4 -0
  329. package/template/coding-task-manager/public/index.html +473 -243
  330. package/template/coding-task-manager/public/js/agent-command.js +86 -0
  331. package/template/coding-task-manager/public/js/app/backups-panel.js +111 -5
  332. package/template/coding-task-manager/public/js/app/coding-agent-upgrade.js +103 -4
  333. package/template/coding-task-manager/public/js/app/machines-page.js +1328 -8
  334. package/template/coding-task-manager/public/js/app/models-tab.js +113 -38
  335. package/template/coding-task-manager/public/js/app/restart-banner.js +53 -0
  336. package/template/coding-task-manager/public/js/app/worktrees-panel.js +184 -2
  337. package/template/coding-task-manager/public/js/background-work.js +196 -27
  338. package/template/coding-task-manager/public/js/coding-session-model-presentation.js +138 -10
  339. package/template/coding-task-manager/public/js/core/active-session-groups.js +179 -0
  340. package/template/coding-task-manager/public/js/core/pending-create.js +238 -0
  341. package/template/coding-task-manager/public/js/core/recent-machine-source.js +228 -0
  342. package/template/coding-task-manager/public/js/core/session-commands.js +180 -14
  343. package/template/coding-task-manager/public/js/dashboard-client-function-order.json +8 -0
  344. package/template/coding-task-manager/public/js/document-review-links.js +9 -1
  345. package/template/coding-task-manager/public/js/file-resolution-client.js +52 -1
  346. package/template/coding-task-manager/public/js/history-app-seam.js +22 -2
  347. package/template/coding-task-manager/public/js/machine-pool-shared.js +558 -3
  348. package/template/coding-task-manager/public/js/message-renderer.js +4 -3
  349. package/template/coding-task-manager/public/js/model-picker.js +3 -1
  350. package/template/coding-task-manager/public/js/native-subagent-review.js +15 -2
  351. package/template/coding-task-manager/public/js/new-session-agent-grid.js +346 -0
  352. package/template/coding-task-manager/public/js/pasted-content.js +236 -0
  353. package/template/coding-task-manager/public/js/pe-private-content-lifetime.js +39 -7
  354. package/template/coding-task-manager/public/js/private-model-lifetime.js +6 -2
  355. package/template/coding-task-manager/public/js/prompts.js +11 -10
  356. package/template/coding-task-manager/public/js/protocol.js +10 -0
  357. package/template/coding-task-manager/public/js/restart-banner-policy.js +29 -1
  358. package/template/coding-task-manager/public/js/session-model-picker.js +447 -57
  359. package/template/coding-task-manager/public/js/session-search-utils.js +18 -2
  360. package/template/coding-task-manager/public/js/session-usage-view.js +2 -1
  361. package/template/coding-task-manager/public/js/session-workspace-tracking.js +51 -1
  362. package/template/coding-task-manager/public/js/state-sync-client.js +10 -1
  363. package/template/coding-task-manager/public/js/stream-view.js +6 -5
  364. package/template/coding-task-manager/public/js/terminal/conv-only-session.js +287 -0
  365. package/template/coding-task-manager/public/js/terminal/runtime-09.js +2 -0
  366. package/template/coding-task-manager/public/js/terminal/runtime-10.js +5 -5
  367. package/template/coding-task-manager/public/js/terminal/runtime-12.js +8 -1
  368. package/template/coding-task-manager/public/js/terminal/runtime-16.js +4 -0
  369. package/template/coding-task-manager/public/js/terminal/runtime-20.js +1 -1
  370. package/template/coding-task-manager/public/js/terminal-attachment-draft.js +67 -13
  371. package/template/coding-task-manager/public/js/terminal-image-orchestration.js +52 -6
  372. package/template/coding-task-manager/public/js/terminal-wheel.js +23 -3
  373. package/template/coding-task-manager/public/js/walle/chat-conversation.js +4 -4
  374. package/template/coding-task-manager/public/js/walle.js +6 -0
  375. package/template/coding-task-manager/public/js/ws/live-dispatch.js +10 -0
  376. package/template/coding-task-manager/public/m/app.css +140 -0
  377. package/template/coding-task-manager/public/m/app.js +507 -68
  378. package/template/coding-task-manager/public/m/index.html +17 -0
  379. package/template/coding-task-manager/public/m/machines.js +838 -4
  380. package/template/coding-task-manager/public/m/private-api.js +31 -1
  381. package/template/coding-task-manager/public/usage.html +1 -0
  382. package/template/coding-task-manager/scripts/dev-route-fixture/synthetic-route-upstream.js +104 -0
  383. package/template/coding-task-manager/scripts/dev-route-fixture.js +339 -0
  384. package/template/coding-task-manager/scripts/opencode-lead-route-probe.js +195 -0
  385. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/fake-anthropic.js +168 -0
  386. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/probe-plugin/server.js +95 -0
  387. package/template/coding-task-manager/scripts/opencode-v2-contract-probe.js +673 -0
  388. package/template/coding-task-manager/server.js +1950 -11679
  389. package/template/coding-task-manager/session-integrity.js +64 -4
  390. package/template/coding-task-manager/workers/db-owner-worker.js +19 -2
  391. package/template/coding-task-manager/workers/online-backup-worker.js +1 -0
  392. package/template/coding-task-manager/workers/read-pool-model-collector.js +51 -3
  393. package/template/coding-task-manager/workers/read-pool-worker.js +76 -6
  394. package/template/coding-task-manager/workers/session-host-pool-process.js +6 -6
  395. package/template/coding-task-manager/workers/session-host-process.js +5 -5
  396. package/template/coding-task-manager/workers/watch-worker.js +105 -0
  397. package/template/coding-task-manager/workers/worktree-worker.js +168 -33
  398. package/template/ctm-relay/lib/protocol.js +14 -1
  399. package/template/package-lock.json +2 -2
  400. package/template/package.json +1 -1
  401. package/template/shared/backup-retention.js +82 -0
  402. package/template/shared/conversation-admission.js +2 -0
  403. package/template/shared/conversation-provenance.js +3 -7
  404. package/template/shared/conversation-storage-v2-contract.js +5 -0
  405. package/template/shared/linked-worktree.js +51 -0
  406. package/template/shared/macos-fda-target.js +57 -0
  407. package/template/shared/orphan-parents.js +55 -0
  408. package/template/shared/release-schema.json +2 -2
  409. package/template/shared/storage/contract.js +3 -0
  410. package/template/wall-e/adapters/imessage.js +12 -0
  411. package/template/wall-e/agent.js +71 -4
  412. package/template/wall-e/api-walle.js +21 -1
  413. package/template/wall-e/bin/train-gemma-e4b-tooluse.js +2 -2
  414. package/template/wall-e/bin/walle-mcp-stdio.js +5 -5
  415. package/template/wall-e/brain/brain-join.js +859 -0
  416. package/template/wall-e/brain/brain-sync-membership.js +20 -0
  417. package/template/wall-e/brain/brain-sync-store.js +131 -77
  418. package/template/wall-e/brain/brain-sync-v2-schema.js +203 -0
  419. package/template/wall-e/brain/brain-sync-v2.js +578 -0
  420. package/template/wall-e/brain/delegate-model-prefs-store.js +13 -4
  421. package/template/wall-e/brain/deterministic-id.js +51 -0
  422. package/template/wall-e/brain/memories.js +2 -2
  423. package/template/wall-e/brain/migrations.js +40 -6
  424. package/template/wall-e/brain/model-identity-migration.js +1 -1
  425. package/template/wall-e/brain/owner-call-whitelist.js +23 -7
  426. package/template/wall-e/brain/schema.js +45 -85
  427. package/template/wall-e/brain.js +171 -35
  428. package/template/wall-e/chat.js +3 -3
  429. package/template/wall-e/coding/agent-shell-env.js +7 -2
  430. package/template/wall-e/coding/prompt-bundle.js +66 -21
  431. package/template/wall-e/config/main-loop-exemptions.json +2 -2
  432. package/template/wall-e/http/admin-api.js +37 -0
  433. package/template/wall-e/http/gws-api.js +4 -0
  434. package/template/wall-e/http/helper-rules-api.js +7 -1
  435. package/template/wall-e/http/model-admin.js +8 -1
  436. package/template/wall-e/http/model-delegate-pref-admin.js +3 -3
  437. package/template/wall-e/http/model-proxy-providers.js +174 -1
  438. package/template/wall-e/http/model-route-health.js +157 -0
  439. package/template/wall-e/http/sync-api.js +278 -464
  440. package/template/wall-e/jobs/job-runner.js +28 -1
  441. package/template/wall-e/lib/brain-owner-op-priority.js +9 -1
  442. package/template/wall-e/lib/ctm-data-dir.js +26 -0
  443. package/template/wall-e/lib/derivation-home.js +147 -0
  444. package/template/wall-e/lib/helper-rules/evaluate.js +50 -9
  445. package/template/wall-e/lib/helper-rules/grade.js +51 -8
  446. package/template/wall-e/lib/helper-rules/lead-call-hook.js +38 -5
  447. package/template/wall-e/lib/helper-rules/store.js +4 -2
  448. package/template/wall-e/lib/landing-mcp-tools.js +170 -0
  449. package/template/wall-e/lib/mcp-client-config.js +133 -14
  450. package/template/wall-e/lib/mcp-gateway-migrate.js +28 -64
  451. package/template/wall-e/lib/mcp-integration.js +58 -13
  452. package/template/wall-e/lib/parent-death.js +7 -1
  453. package/template/wall-e/lib/scheduler-worker-jobs.js +6 -4
  454. package/template/wall-e/llm/delegate-lead-prefs.js +16 -1
  455. package/template/wall-e/llm/delegate-vendor-default.js +12 -5
  456. package/template/wall-e/llm/model-roles.js +1 -1
  457. package/template/wall-e/llm/native-delegate-selection.js +56 -8
  458. package/template/wall-e/llm/worker-delegate-args.js +72 -7
  459. package/template/wall-e/llm/worker-mcp-routing.js +66 -17
  460. package/template/wall-e/loops/brain-custom-writes.js +19 -0
  461. package/template/wall-e/loops/ingest.js +17 -1
  462. package/template/wall-e/loops/think.js +19 -4
  463. package/template/wall-e/mcp-contract.js +222 -6
  464. package/template/wall-e/mcp-protocol-contract.js +40 -5
  465. package/template/wall-e/mcp-server.js +128 -29
  466. package/template/wall-e/mcp-worker-schemas.js +5 -5
  467. package/template/wall-e/memory/ctm-context-client.js +85 -0
  468. package/template/wall-e/memory/ctm-session-context.js +9 -3
  469. package/template/wall-e/memory/hub-bridge-client.js +388 -0
  470. package/template/wall-e/memory/replica-origin.js +56 -0
  471. package/template/wall-e/memory/session-pool.js +135 -0
  472. package/template/wall-e/runtime/live-capabilities.js +8 -3
  473. package/template/wall-e/server.js +4 -2
  474. package/template/wall-e/shared/release-schema.json +2 -2
  475. package/template/wall-e/shared/sqlite-file-set.js +39 -0
  476. package/template/wall-e/shared/storage/contract.js +3 -0
  477. package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
  478. package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +7 -1
  479. package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +4 -4
  480. package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +6 -6
  481. package/template/wall-e/skills/_templates/fleet-sync/VERSION +1 -0
  482. package/template/wall-e/skills/_templates/fleet-sync/released-sha256.json +16 -0
  483. package/template/wall-e/skills/_templates/fleet-sync/templates/claude/SKILL.md +64 -0
  484. package/template/wall-e/skills/_templates/fleet-sync/templates/codex/SKILL.md +64 -0
  485. package/template/wall-e/tools/chrome-automation.js +6 -0
  486. package/template/wall-e/training/setup-cuda-train-env.sh +2 -2
  487. package/template/wall-e/workers/brain-owner-worker.js +18 -4
  488. package/template/wall-e/workers/mcp-gateway-process.js +5 -5
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  const conversationChangeFeed = require('./conversation-change-feed');
4
+ const SessionSearchUtils = require('../public/js/session-search-utils');
5
+ const sessionContextLocator = require('./session-context-locator');
4
6
 
5
7
  let ctmSessionContext = null;
6
8
  let ctmSessionContextLoadError = null;
@@ -47,7 +49,13 @@ function makeSplitRoutingHandle(dbModule) {
47
49
  });
48
50
  }
49
51
 
50
- function handleCtmSessionContextApi(req, res, url, { db, dbModule, runHeavy, runMutation } = {}) {
52
+ function handleCtmSessionContextApi(req, res, url, {
53
+ db, dbModule, runHeavy, runMutation,
54
+ // WP-2 (docs/cross-machine-session-context-2026-10-31.html §6.1): test seams for the hub owner
55
+ // resolver. Production passes neither — server.js (inside the file-size-frozen `handleApi`) is
56
+ // untouched and every default is lazy in lib/session-context-locator.js.
57
+ locatorDeps = {}, env = process.env,
58
+ } = {}) {
51
59
  const rangeMatch = /^\/api\/sessions\/([^/]+)\/messages\/range$/.exec(url.pathname);
52
60
  // WP-0 (one-transcript-ingestor §6.1): the conversation change-feed routes live here
53
61
  // beside the session-memory reads. The guard must admit them or dispatch never reaches
@@ -129,8 +137,10 @@ function handleCtmSessionContextApi(req, res, url, { db, dbModule, runHeavy, run
129
137
  query: url.searchParams.get('q') || url.searchParams.get('query') || '',
130
138
  limit: url.searchParams.get('limit') || undefined,
131
139
  };
132
- return serveHeavy('ctmSessionMemorySearch', args,
133
- () => context.searchCtmSessions({ ...args, db }));
140
+ // WP-4 (§6.2/R-7): `scope=pool` (the default) fans the search out to every dialable member
141
+ // under one deadline and merges by RRF; `scope=local` keeps today's local-only answer.
142
+ const scope = url.searchParams.get('scope') || 'pool';
143
+ return serveSearchAnywhere({ args, scope, res, context, runHeavy, db, locatorDeps, env });
134
144
  }
135
145
 
136
146
  if ((url.pathname === '/api/ctm/session-memory/context' || rangeMatch) && req.method === 'GET') {
@@ -151,9 +161,25 @@ function handleCtmSessionContextApi(req, res, url, { db, dbModule, runHeavy, run
151
161
  format: url.searchParams.get('format') || 'messages',
152
162
  projection: url.searchParams.get('projection') || 'envelope',
153
163
  };
154
- return serveHeavy('ctmSessionMemoryContext', args,
155
- () => context.getCtmSessionContext({ ...args, db }),
156
- { typedRangeStatus: true });
164
+ // WP-2 (§6.2/R-3): the RANGE route stays LOCAL-ONLY and unchanged — it keeps today's
165
+ // args verbatim (no `ref`, no `scope`) and never leaves this machine.
166
+ if (rangeMatch) {
167
+ return serveHeavy('ctmSessionMemoryContext', args,
168
+ () => context.getCtmSessionContext({ ...args, db }),
169
+ { typedRangeStatus: true });
170
+ }
171
+ // R-1 (§6.2): `ref` is any identity string parseSessionIdentityQuery understands — a
172
+ // `#session=<id>` link, `review=<id>`, or a bare uuid — merged into session_ids. The context
173
+ // route is answered by the hub owner resolver, which reads locally first and only leaves this
174
+ // machine on a local miss. `scope=pool` is the default; lib/session-context-locator.js is the
175
+ // single reader of the R-11 flag (an off flag skips both the owner forward and the probe).
176
+ const ref = String(url.searchParams.get('ref') || '').trim();
177
+ if (ref) {
178
+ const parsedRef = SessionSearchUtils.parseSessionIdentityQuery(ref);
179
+ if (parsedRef.sessionIds.length) args.session_ids = [...args.session_ids, ...parsedRef.sessionIds];
180
+ }
181
+ args.scope = url.searchParams.get('scope') || 'pool';
182
+ return serveContextAnywhere({ args, res, context, runHeavy, db, locatorDeps, env });
157
183
  }
158
184
 
159
185
  if (
@@ -300,6 +326,71 @@ function handleCtmSessionContextApi(req, res, url, { db, dbModule, runHeavy, run
300
326
  }
301
327
  }
302
328
 
329
+ /**
330
+ * WP-2 (§6.2, R-3/R-5): answer `GET /api/ctm/session-memory/context` through the hub owner
331
+ * resolver. The local read is today's off-thread path (`runHeavy` when wired, `computeSync`
332
+ * otherwise), so a local hit is today's answer plus `location`; only a local MISS leaves this
333
+ * machine (one forwarded GET to the directory's owner, else a deadline-bounded parallel probe).
334
+ */
335
+ function serveContextAnywhere({ args, res, context, runHeavy, db, locatorDeps, env }) {
336
+ const readLocal = (localArgs) => {
337
+ // `scope` is the locator's key, never a worker argument: the worker re-runs today's op.
338
+ const workerArgs = { ...localArgs };
339
+ delete workerArgs.scope;
340
+ const computeSync = () => context.getCtmSessionContext({ ...workerArgs, db });
341
+ if (typeof runHeavy !== 'function') return Promise.resolve().then(computeSync);
342
+ return Promise.resolve().then(() => runHeavy('ctmSessionMemoryContext', workerArgs, computeSync));
343
+ };
344
+ Promise.resolve()
345
+ .then(() => sessionContextLocator.readSessionContextAnywhere(
346
+ { args, excludeMachineId: '', env: env || process.env },
347
+ { ...locatorDeps, readLocal },
348
+ ))
349
+ .then((result) => {
350
+ const payload = asApiResult(result);
351
+ return respondJson(res, rangeHttpStatus(payload), payload);
352
+ })
353
+ .catch((err) => respondJson(res, 500, {
354
+ ok: false,
355
+ source: 'ctm-api',
356
+ authority: 'ctm',
357
+ reason: 'ctm_session_context_failed',
358
+ error: err.message,
359
+ }));
360
+ return true;
361
+ }
362
+
363
+ /**
364
+ * WP-4 (§6.2, R-7): answer `GET /api/ctm/session-memory/search` through the pool fan-out. The local
365
+ * search IS today's off-thread path (`runHeavy` when wired, `computeSync` otherwise) so a local-only
366
+ * read answers with today's rows — only the MERGE adds `machine_id`/`machine_name`/`rank`, and only
367
+ * when the pool is on does anything leave this machine (one `scope=local` GET per dialable member).
368
+ * A deferred local read (`null`) still renders today's deferred envelope.
369
+ */
370
+ function serveSearchAnywhere({ args, scope, res, context, runHeavy, db, locatorDeps, env }) {
371
+ const searchLocal = (localArgs) => {
372
+ const computeSync = () => context.searchCtmSessions({ ...localArgs, db });
373
+ if (typeof runHeavy !== 'function') return Promise.resolve().then(computeSync);
374
+ return Promise.resolve().then(() => runHeavy('ctmSessionMemorySearch', localArgs, computeSync));
375
+ };
376
+ Promise.resolve()
377
+ .then(() => sessionContextLocator.searchSessionsAnywhere(
378
+ {
379
+ query: args.query, limit: args.limit, scope, env: env || process.env,
380
+ },
381
+ { ...locatorDeps, searchLocal },
382
+ ))
383
+ .then((result) => respondJson(res, 200, asApiResult(result)))
384
+ .catch((err) => respondJson(res, 500, {
385
+ ok: false,
386
+ source: 'ctm-api',
387
+ authority: 'ctm',
388
+ reason: 'ctm_session_context_failed',
389
+ error: err.message,
390
+ }));
391
+ return true;
392
+ }
393
+
303
394
  async function handleMessageIndexBackfill({ body, res, context, db, dbModule }) {
304
395
  const limit = clampInt(body.limit, 100, 1, 1000);
305
396
  const chunkSize = clampInt(body.chunk_size ?? body.chunkSize, 250, 25, 2000);
@@ -169,6 +169,7 @@ const TABLE_DOMAINS = Object.freeze({
169
169
  // intentionally base/firehose-resident so the preflight and its guarded
170
170
  // rows remain atomic across core/telemetry extraction.
171
171
  conversation_retained_history_guard_v2: 'firehose', conversation_projection_deletes_v2: 'firehose', conversation_store_epoch_v2: 'firehose', conversation_usage_turn_changes_v1: 'firehose', // v36 change feed; v41 usage turn-change outbox schema
172
+ conversation_item_clock: 'firehose', conversation_vv: 'firehose', conversation_local_seq: 'firehose', // v61 shared-memory replica clock: same file as conversation_text_items_v2
172
173
 
173
174
  // firehose — transcript row store + FTS + ingest cursors (lib/transcript-store.js)
174
175
  transcript_files: 'firehose',
@@ -262,6 +262,7 @@ const CTM_WRITE_OPS = Object.freeze([
262
262
  'commitConversationDelta', 'enrollConversationSource',
263
263
  'markConversationUpdatePublished', 'markConversationUpdateUnresolvable',
264
264
  'redriveConversationSourceDebt', 'recordResumeLineage', 'ackConversationChanges',
265
+ 'conversationSyncVector', 'conversationSyncChanges', 'conversationSyncApply',
265
266
  // Not in §9 table A (the gate is derived from the action REGISTRY, so it sees the
266
267
  // 14 extra actions the design's 205-action count predates — see the contract.js
267
268
  // comment beside their OP_META rows). Both write/repair conversation-store tables
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ // WP-0c (docs/session-create-accept-then-complete-2026-11-01.html §6.5 D-13, AC-0e): the
4
+ // low-over-signalled probe that workers/db-owner-worker.js _pump() calls after dequeuing a `low`
5
+ // task. The work signal counts requests the main thread has issued, including ones that have not
6
+ // reached the queue's lanes yet, so a signalled total above the queue's own ready high/urgent
7
+ // depth means a `low` task was dispatched while higher-priority work was waiting.
8
+ // A factory with no worker globals, so the decision and its 10 s emit window are unit-testable
9
+ // without spawning the worker thread; read-only — it never reorders dispatch.
10
+ const DISPATCH_PROBE_WINDOW_MS = 10 * 1000;
11
+ function createLowOverSignalledProbe({ windowMs = DISPATCH_PROBE_WINDOW_MS, log = (line) => console.log(line) } = {}) {
12
+ let lastEmitAt = 0;
13
+ let suppressed = 0;
14
+ return function observeLowDispatch({ op, snapshot, queuedUrgent = 0, queuedHigh = 0, at = Date.now() }) {
15
+ if (!snapshot) return null;
16
+ const signalledHigh = Number(snapshot.interactivePending || 0);
17
+ const signalledUrgent = Number(snapshot.urgentPending || 0);
18
+ if (signalledHigh + signalledUrgent <= Number(queuedUrgent || 0) + Number(queuedHigh || 0)) return null;
19
+ if (lastEmitAt && at - lastEmitAt < windowMs) {
20
+ suppressed += 1;
21
+ return null;
22
+ }
23
+ const line = `[db-owner-dispatch] low-over-signalled op=${op} signalledHigh=${signalledHigh} signalledUrgent=${signalledUrgent} `
24
+ + `queuedHigh=${Number(queuedHigh || 0)} queuedUrgent=${Number(queuedUrgent || 0)} suppressed=${suppressed}`;
25
+ lastEmitAt = at;
26
+ suppressed = 0;
27
+ try { log(line); } catch { /* expected: a throwing injected log must not break dispatch */ }
28
+ return line;
29
+ };
30
+ }
31
+
32
+ module.exports = { DISPATCH_PROBE_WINDOW_MS, createLowOverSignalledProbe };
@@ -0,0 +1,178 @@
1
+ 'use strict';
2
+
3
+ // WP-0 M-5 (docs/hub-local-cpu-memory-burn-2026-10-31.html §3.5, §7 M-5). MEASUREMENT ONLY.
4
+ //
5
+ // After every hub boot the DB-owner worker absorbs a 1-2 min storm of expired requests
6
+ // (200k-1.8M, mostly runtime-event / session-diagnostic writes) while catchUpTranscriptFiles
7
+ // occupies the writer. Nothing on the client side says WHICH producers issue them, so these
8
+ // counters attribute every request() attempt — including the ones REFUSED before they ever
9
+ // reach the worker — to the minute it was issued: per worker op, and per runtime-event /
10
+ // session-diagnostic NAME for the event writers.
11
+ //
12
+ // Stated bounds (enforced below, no I/O and no allocation beyond the current bucket):
13
+ // * a fixed ring of the last REQUEST_COUNT_RING_MINUTES one-minute buckets;
14
+ // * at most REQUEST_COUNT_KEY_MAX distinct op keys and REQUEST_COUNT_KEY_MAX distinct event
15
+ // keys per bucket — every further key folds into `_other`;
16
+ // * O(1) work per request (one clock read, one ring index, one map write).
17
+ const REQUEST_COUNT_RING_MINUTES = 30;
18
+ const REQUEST_COUNT_KEY_MAX = 64;
19
+ const REQUEST_COUNT_KEY_CLIP = 80;
20
+ // `refused` = the client never handed the op to the worker (quarantine, circuit breaker, worker
21
+ // not running, worker died/recycled mid-flight). Non-timeout failures are `error`.
22
+ const REQUEST_COUNT_OUTCOMES = Object.freeze(['ok', 'timeout', 'refused', 'error']);
23
+
24
+ // Errors that mean "the client refused / could not reach the worker" rather than "the op ran
25
+ // and failed" — the refused share of the boot storm.
26
+ const REQUEST_REFUSED_CODES = new Set([
27
+ 'CTM_DB_OWNER_OP_QUARANTINED',
28
+ 'CTM_DB_OWNER_WORKER_DEGRADED',
29
+ 'CTM_DB_OWNER_WORKER_DISABLED',
30
+ 'CTM_DB_OWNER_WORKER_EXITED',
31
+ 'CTM_DB_OWNER_WORKER_FATAL',
32
+ 'CTM_DB_OWNER_WORKER_RECYCLED',
33
+ 'CTM_DB_OWNER_ISOLATION_RECYCLED',
34
+ 'CTM_DB_OWNER_CLOSED',
35
+ 'CTM_DB_OWNER_CLOSING',
36
+ ]);
37
+
38
+ function _requestCountOutcome(error) {
39
+ return error && REQUEST_REFUSED_CODES.has(error.code) ? 'refused' : 'error';
40
+ }
41
+
42
+ // Ops whose payload carries a runtime-event / session-diagnostic NAME. BOTH dispatch shapes
43
+ // reach this client: the direct worker op (payload = { events | entries } — see
44
+ // workers/db-owner-worker.js case 'appendRuntimeEventsBatch' and db.js flushSessionDiagnostics)
45
+ // and the generic `runDbMutation` wrapper (payload = { action, args } — server.js's
46
+ // configureOwnerMutations dispatch for db.js's appendRuntimeEvent/addSessionDiagnostic).
47
+ // addSessionDiagnostic has no separate batch op: db.js's flushSessionDiagnostics IS its batch
48
+ // form (its entries each carry the diagnostic name in `event`).
49
+ const RUNTIME_EVENT_WRITE_OPS = new Set([
50
+ 'appendRuntimeEvent',
51
+ 'appendRuntimeEventsBatch',
52
+ 'addSessionDiagnostic',
53
+ 'flushSessionDiagnostics',
54
+ ]);
55
+
56
+ function _eventNameText(value) {
57
+ if (typeof value !== 'string') return '';
58
+ const text = value.trim();
59
+ return text ? text.slice(0, REQUEST_COUNT_KEY_CLIP) : '';
60
+ }
61
+
62
+ // The NAME a runtime-event / diagnostic row is written under: `type` for ctm_runtime_events
63
+ // (db.js normalizeRuntimeEvent) and `event` for session_diagnostics (db.js addSessionDiagnostic's
64
+ // second argument, and a flush entry's `event`). Tolerates the object or the bare-string form.
65
+ function _runtimeEventName(candidate) {
66
+ if (typeof candidate === 'string') return _eventNameText(candidate);
67
+ if (!candidate || typeof candidate !== 'object') return '';
68
+ return _eventNameText(candidate.type) || _eventNameText(candidate.event)
69
+ || _eventNameText(candidate.kind) || _eventNameText(candidate.name);
70
+ }
71
+
72
+ // Names contributed by ONE request, or null when this op is not an event/diagnostic write.
73
+ // A batch contributes one entry per element. An unnamed write still counts, as 'unknown'.
74
+ function _runtimeEventNamesFor(op, payload) {
75
+ if (!payload || typeof payload !== 'object') return null;
76
+ const action = op === 'runDbMutation' ? String(payload.action || '') : String(op || '');
77
+ if (!RUNTIME_EVENT_WRITE_OPS.has(action)) return null;
78
+ const args = Array.isArray(payload.args) ? payload.args : null;
79
+ const batch = Array.isArray(payload.events) ? payload.events
80
+ : (Array.isArray(payload.entries) ? payload.entries : null);
81
+ if (batch) return batch.map((item) => _runtimeEventName(item) || 'unknown');
82
+ if (args && Array.isArray(args[0])) {
83
+ return args[0].map((item) => _runtimeEventName(item) || 'unknown');
84
+ }
85
+ // Diagnostics take their name from the second db.js argument (the first is the session id);
86
+ // runtime events are the event object itself.
87
+ const single = action === 'addSessionDiagnostic'
88
+ ? (_runtimeEventName(payload.event) || _runtimeEventName(payload.kind) || _runtimeEventName(args?.[1]))
89
+ : (_runtimeEventName(payload.event) || _runtimeEventName(args?.[0]) || _runtimeEventName(payload));
90
+ return [single || 'unknown'];
91
+ }
92
+
93
+ function _minuteStartMs(nowMs) {
94
+ return Math.floor(nowMs / 60000) * 60000;
95
+ }
96
+
97
+ function _newOpCounts() {
98
+ return { requested: 0, ok: 0, timeout: 0, refused: 0, error: 0 };
99
+ }
100
+
101
+ // Fixed-size per-minute request counter. Takes its clock as an option so tests can drive
102
+ // simulated minutes without sleeping (the client itself has no time injection).
103
+ class DbOwnerRequestsPerMinute {
104
+ constructor(options = {}) {
105
+ this.enabled = options.enabled !== false;
106
+ this.now = typeof options.now === 'function' ? options.now : Date.now;
107
+ this.ringMinutes = Math.max(1, Math.trunc(Number(options.ringMinutes)) || REQUEST_COUNT_RING_MINUTES);
108
+ this.keyMax = Math.max(1, Math.trunc(Number(options.keyMax)) || REQUEST_COUNT_KEY_MAX);
109
+ this._buckets = [];
110
+ }
111
+
112
+ // The current minute's bucket, created on demand — at most one push + one eviction per
113
+ // minute boundary, so the per-request cost stays O(1).
114
+ _bucket() {
115
+ const minuteStartMs = _minuteStartMs(this.now());
116
+ const last = this._buckets[this._buckets.length - 1];
117
+ if (last && last.minuteStartMs === minuteStartMs) return last;
118
+ const bucket = { minuteStartMs, byOp: {}, byEvent: {}, opKeys: 0, eventKeys: 0 };
119
+ this._buckets.push(bucket);
120
+ while (this._buckets.length > this.ringMinutes) this._buckets.shift();
121
+ return bucket;
122
+ }
123
+
124
+ _opEntry(bucket, op) {
125
+ const key = String(op || 'unknown').slice(0, REQUEST_COUNT_KEY_CLIP);
126
+ const existing = bucket.byOp[key];
127
+ if (existing) return existing;
128
+ if (bucket.opKeys >= this.keyMax) {
129
+ if (!bucket.byOp._other) bucket.byOp._other = _newOpCounts();
130
+ return bucket.byOp._other;
131
+ }
132
+ const entry = _newOpCounts();
133
+ bucket.byOp[key] = entry;
134
+ bucket.opKeys += 1;
135
+ return entry;
136
+ }
137
+
138
+ _bumpEvent(bucket, name) {
139
+ const key = String(name || 'unknown').slice(0, REQUEST_COUNT_KEY_CLIP);
140
+ if (bucket.byEvent[key] !== undefined) {
141
+ bucket.byEvent[key] += 1;
142
+ return;
143
+ }
144
+ if (bucket.eventKeys >= this.keyMax) {
145
+ bucket.byEvent._other = (bucket.byEvent._other || 0) + 1;
146
+ return;
147
+ }
148
+ bucket.byEvent[key] = 1;
149
+ bucket.eventKeys += 1;
150
+ }
151
+
152
+ recordRequest(op, payload) {
153
+ if (!this.enabled) return;
154
+ const bucket = this._bucket();
155
+ this._opEntry(bucket, op).requested += 1;
156
+ const names = _runtimeEventNamesFor(op, payload);
157
+ if (!names) return;
158
+ for (const name of names) this._bumpEvent(bucket, name);
159
+ }
160
+
161
+ recordOutcome(op, outcome) {
162
+ if (!this.enabled) return;
163
+ const key = REQUEST_COUNT_OUTCOMES.includes(outcome) ? outcome : 'error';
164
+ this._opEntry(this._bucket(), op)[key] += 1;
165
+ }
166
+
167
+ // Oldest bucket first, the current minute last. Empty when the flag turns attribution off.
168
+ snapshot() {
169
+ if (!this.enabled) return [];
170
+ return this._buckets.map((bucket) => {
171
+ const byOp = {};
172
+ for (const [op, counts] of Object.entries(bucket.byOp)) byOp[op] = { ...counts };
173
+ return { minuteStartMs: bucket.minuteStartMs, byOp, byEvent: { ...bucket.byEvent } };
174
+ });
175
+ }
176
+ }
177
+
178
+ module.exports = { DbOwnerRequestsPerMinute, requestCountOutcome: _requestCountOutcome };
@@ -17,6 +17,8 @@ const { createFailureRollup } = require('./db-owner-failure-rollup');
17
17
  const os = require('node:os');
18
18
  const fs = require('node:fs');
19
19
  const { hydrateCleanupError } = require('./worker-error-metadata');
20
+ const { boolFlag } = require('./env-flags');
21
+ const { DbOwnerRequestsPerMinute, requestCountOutcome: _requestCountOutcome } = require('./db-owner-request-counts');
20
22
 
21
23
  const activeClientsByDbPath = new Map();
22
24
  const cooperativeCapabilities = new WeakMap();
@@ -213,6 +215,8 @@ function _writerLabelForDbPath(dbPath) {
213
215
  // oldest entry is evicted first.
214
216
  const TIMED_OUT_MAX = 256;
215
217
 
218
+ // WP-0 M-5 request counts per minute: lib/db-owner-request-counts.js.
219
+
216
220
  class CtmDbOwnerWorkerClient {
217
221
  constructor(options = {}) {
218
222
  if (!options.dbPath) throw new Error('CtmDbOwnerWorkerClient requires dbPath');
@@ -360,6 +364,12 @@ class CtmDbOwnerWorkerClient {
360
364
  };
361
365
  this._lastStatusAt = 0;
362
366
  this._statusWaiters = [];
367
+ // WP-0 M-5 (§3.5): per-minute request attribution. On by default IN SOURCE —
368
+ // CTM_PERF_ATTRIBUTION=0 disables it (read through lib/env-flags.js so this file keeps
369
+ // zero raw process.env reads of its own).
370
+ this._requestsPerMinute = new DbOwnerRequestsPerMinute({
371
+ enabled: boolFlag('CTM_PERF_ATTRIBUTION', true),
372
+ });
363
373
  }
364
374
 
365
375
  start() {
@@ -706,24 +716,27 @@ class CtmDbOwnerWorkerClient {
706
716
  const canLog = this.logger && typeof this.logger.warn === 'function';
707
717
  if (!canLog) return;
708
718
  const now = Date.now();
709
- // `startedAt` is stamped by the worker's 'started' message if it arrived before the
710
- // timeout; otherwise the request never started and the whole span is queue time.
719
+ // `startedAt` is the worker's 'started' stamp; without it the whole span is queue time, printed as
720
+ // `started=0 queueMs=<span> serviceMs=0` (WP-0c D-13: 2026-11-01's unstarted hub requests hid as serviceMs).
711
721
  const started = record.startedAt || 0;
712
- const serviceMs = started ? Math.max(0, now - started) : Math.max(0, now - record.enqueuedAt);
713
- const queueMs = started ? Math.max(0, started - record.enqueuedAt) : 0;
722
+ const serviceMs = started ? Math.max(0, now - started) : 0;
723
+ const queueMs = started ? Math.max(0, started - record.enqueuedAt) : Math.max(0, now - record.enqueuedAt);
714
724
  const lateByMs = Math.max(0, now - record.timedOutAt);
715
- const result = msg.error
716
- ? `error:${msg.error.code || 'unknown'}`
717
- : 'ok';
725
+ const result = msg.error ? `error:${msg.error.code || 'unknown'}` : 'ok';
726
+ const span = started
727
+ ? `serviceMs=${Math.round(serviceMs)} queueMs=${Math.round(queueMs)} lateByMs=${Math.round(lateByMs)} result=${result} started=1`
728
+ : `started=0 queueMs=${Math.round(queueMs)} serviceMs=0 lateByMs=${Math.round(lateByMs)} result=${result}`;
718
729
  try {
719
730
  this.logger.warn(
720
- `[db-owner-late] writer=${this.writer} op=${record.op} action=${record.action} ` +
721
- `serviceMs=${Math.round(serviceMs)} queueMs=${Math.round(queueMs)} lateByMs=${Math.round(lateByMs)} result=${result}`
731
+ `[db-owner-late] writer=${this.writer} op=${record.op} action=${record.action} ` + span
722
732
  );
723
733
  } catch { /* expected: a throwing injected logger must not break the response path */ }
724
734
  }
725
735
 
726
736
  _recordTimeout(op) {
737
+ // WP-0 M-5: the request settled as a timeout (the timer path rejects directly, so this is
738
+ // the one place that sees the timed-out op).
739
+ this._requestsPerMinute.recordOutcome(op, 'timeout');
727
740
  this._consecutiveTimeouts += 1;
728
741
  if (this._consecutiveTimeouts >= this._degradeAfter) {
729
742
  const wasDegraded = this.isDegraded();
@@ -776,14 +789,29 @@ class CtmDbOwnerWorkerClient {
776
789
 
777
790
  async request(op, payload = {}, options = {}) {
778
791
  if (!op) throw new Error('DB owner worker request requires op');
779
- if (options.signal?.aborted) throw _abortError(options.signal);
780
- if (this._recyclePromise) await _awaitWithAbort(this._recyclePromise, options.signal);
792
+ // WP-0 M-5: count the ATTEMPT before any early throw below, so the requests this client
793
+ // refuses (quarantine / degraded / not running) are attributed to their producer too —
794
+ // they are a large share of the post-boot storm.
795
+ this._requestsPerMinute.recordRequest(op, payload);
796
+ if (options.signal?.aborted) {
797
+ this._requestsPerMinute.recordOutcome(op, 'error');
798
+ throw _abortError(options.signal);
799
+ }
800
+ if (this._recyclePromise) {
801
+ try {
802
+ await _awaitWithAbort(this._recyclePromise, options.signal);
803
+ } catch (error) {
804
+ this._requestsPerMinute.recordOutcome(op, _requestCountOutcome(error));
805
+ throw error; // RETHROW: attribution must not swallow a recycle/abort failure
806
+ }
807
+ }
781
808
  const sourceKey = sourceKeyForDbOwnerPayload(payload);
782
809
  const quarantine = this._opQuarantine.admit(op, sourceKey);
783
810
  if (!quarantine.allowed) {
784
811
  const err = new Error(`DB owner operation is cooling down after consecutive deadlines: ${op}`);
785
812
  err.code = 'CTM_DB_OWNER_OP_QUARANTINED';
786
813
  err.retryAfterMs = quarantine.retryAfterMs;
814
+ this._requestsPerMinute.recordOutcome(op, 'refused');
787
815
  throw err;
788
816
  }
789
817
  // Circuit breaker: when the worker is degraded, fail best-effort ops fast
@@ -793,11 +821,23 @@ class CtmDbOwnerWorkerClient {
793
821
  if (options.bestEffort && options.priority !== 'urgent' && this.isDegraded()) {
794
822
  const err = new Error(`DB owner worker degraded; skipped best-effort op: ${op}`);
795
823
  err.code = 'CTM_DB_OWNER_WORKER_DEGRADED';
824
+ this._requestsPerMinute.recordOutcome(op, 'refused');
796
825
  throw err;
797
826
  }
798
- await _awaitWithAbort(this.start(), options.signal);
799
- if (options.signal?.aborted) throw _abortError(options.signal);
800
- if (!this._worker) throw new Error('DB owner worker is not running');
827
+ try {
828
+ await _awaitWithAbort(this.start(), options.signal);
829
+ } catch (error) {
830
+ this._requestsPerMinute.recordOutcome(op, _requestCountOutcome(error));
831
+ throw error; // RETHROW: attribution must not change a failed start into a success
832
+ }
833
+ if (options.signal?.aborted) {
834
+ this._requestsPerMinute.recordOutcome(op, 'error');
835
+ throw _abortError(options.signal);
836
+ }
837
+ if (!this._worker) {
838
+ this._requestsPerMinute.recordOutcome(op, 'refused');
839
+ throw new Error('DB owner worker is not running');
840
+ }
801
841
  const requestId = this._nextRequestId++;
802
842
  const timeoutMs = _durationMs(options.timeoutMs, this.requestTimeoutMs);
803
843
  const deadline = timeoutMs > 0 ? Date.now() + timeoutMs : 0;
@@ -872,6 +912,7 @@ class CtmDbOwnerWorkerClient {
872
912
  this._invalidateRowCursorSources(sourceIds, { all: sourceIds.length === 0 });
873
913
  }
874
914
  this._status.pendingClientRequests = this._pending.size;
915
+ this._requestsPerMinute.recordOutcome(op, 'error');
875
916
  reject(_abortError(options.signal));
876
917
  };
877
918
  this._pending.get(requestId).abortHandler = abortHandler;
@@ -975,6 +1016,10 @@ class CtmDbOwnerWorkerClient {
975
1016
  workSignal: this._workSignal.snapshot(),
976
1017
  ingestAdmission: this._ingestAdmissionSignal.snapshot(),
977
1018
  opQuarantine: this._opQuarantine.snapshot(),
1019
+ // WP-0 M-5 (§3.5): the last 30 one-minute request buckets, oldest first. Reaches
1020
+ // perf-summary (lib/perf-summary.js:196 passes this whole status through as
1021
+ // workers.dbOwner) and the diagnostics routes with no change to either.
1022
+ requestsPerMinute: this._requestsPerMinute.snapshot(),
978
1023
  lastStatusAt: this._lastStatusAt,
979
1024
  dbPath: this.dbPath,
980
1025
  resourceLimits: { ...this.resourceLimits },
@@ -1062,6 +1107,9 @@ class CtmDbOwnerWorkerClient {
1062
1107
  if (pending.abortHandler) {
1063
1108
  pending.signal?.removeEventListener?.('abort', pending.abortHandler);
1064
1109
  }
1110
+ // WP-0 M-5: the request settled on the worker's reply (or on a postMessage failure) —
1111
+ // attribute it to the op the client recorded at request() time.
1112
+ this._requestsPerMinute.recordOutcome(pending.op, error ? _requestCountOutcome(error) : 'ok');
1065
1113
  if (error) {
1066
1114
  const err = error instanceof Error ? error : new Error(String(error.message || error || 'DB owner worker request failed'));
1067
1115
  if (error.code) err.code = error.code;
@@ -1181,6 +1229,9 @@ class CtmDbOwnerWorkerClient {
1181
1229
  if (req.abortHandler) {
1182
1230
  req.signal?.removeEventListener?.('abort', req.abortHandler);
1183
1231
  }
1232
+ // WP-0 M-5: a worker death / recycle / close rejects work the client had already
1233
+ // accepted — "refused: not running", the other half of the storm's refusals.
1234
+ this._requestsPerMinute.recordOutcome(req.op, 'refused');
1184
1235
  req.reject(err);
1185
1236
  }
1186
1237
  }
@@ -1355,4 +1406,7 @@ module.exports = {
1355
1406
  requestOnActiveDbOwner,
1356
1407
  getActiveClientForDbPath,
1357
1408
  startParentWedgeWatchdog,
1409
+ // WP-0 M-5: exported so the ring/key-bound/flag behaviour can be unit-tested with an
1410
+ // injected clock (the client itself spawns a worker and has no time injection).
1411
+ DbOwnerRequestsPerMinute,
1358
1412
  };
@@ -40,6 +40,11 @@ const SCHEMA_SOURCE_FILES = Object.freeze([
40
40
  'lib/migrations/v53-session-model-intent.js',
41
41
  'lib/migrations/v54-session-lead-model.js',
42
42
  'lib/migrations/v56-host-samples-and-machine-pool.js',
43
+ 'lib/migrations/v57-delegate-pref-mirror-opencode.js',
44
+ 'lib/migrations/v58-subagent-launch-native-subagents.js',
45
+ 'lib/migrations/v59-coding-session-model-state-dsh.js',
46
+ 'lib/migrations/v60-delegate-pref-mirror-dsh.js',
47
+ 'lib/migrations/v61-conversation-item-clock.js', // shared-memory WP-5: conversation replica clock
43
48
  'lib/migrations/v29-usage-accounting.js', 'lib/migrations/v30-usage-reporting.js', 'lib/migrations/v36-conversation-projection-deletes.js',
44
49
  '../shared/usage-store.js', '../shared/usage-reporting-schema.js',
45
50
  'lib/delete-ctm-session-saga.js',
@@ -165,8 +165,12 @@ function captureDeferredRestoreLaunchOwnership(sourceSession) {
165
165
  if (Object.hasOwn(launchContext, 'providerThreadId') && launchContext.providerThreadId !== null
166
166
  && !sourceThreadIdentities(sourceSession, recipe).has(launchContext.providerThreadId)) return null;
167
167
  }
168
- const launchEnvironment = capturePrivateSourceEnvironment(
169
- Object.hasOwn(sourceSession, '_launchEnvOverrides') ? sourceSession._launchEnvOverrides : null);
168
+ // §5 D-7: a session whose launch environment the host could not capture parks as unavailable, not as a
169
+ // captured environment re-read off a roots-only override set. Every other state keeps today's capture.
170
+ const launchEnvironment = sourceSession._launchEnvOverridesCaptureState === 'unavailable'
171
+ ? Object.freeze({ state: 'unavailable', values: null })
172
+ : capturePrivateSourceEnvironment(
173
+ Object.hasOwn(sourceSession, '_launchEnvOverrides') ? sourceSession._launchEnvOverrides : null);
170
174
  const leadRoute = sourceSession.lead_route && typeof sourceSession.lead_route === 'object'
171
175
  ? copyCapturedData(sourceSession.lead_route, copyState) : null;
172
176
  const leadRouteTokenOwnership = sourceSession._leadRouteTokenOwnership
@@ -989,6 +989,10 @@ const FEATURES = [
989
989
  { id: "ctm_ctm_opencode_import_slice_size", env: "CTM_OPENCODE_IMPORT_SLICE_SIZE", owner: "ctm-core-team", stage: "ops", tunable: true, default: 1, since: "2026-08-24", expires: null, note: "numeric tunable" },
990
990
  // numeric-tunable suffix/read shape; 1 site(s); first: server.js:9929
991
991
  { id: "ctm_ctm_opencode_import_worker_timeout_ms", env: "CTM_OPENCODE_IMPORT_WORKER_TIMEOUT_MS", owner: "ctm-core-team", stage: "ops", tunable: true, default: 5, since: "2026-08-24", expires: null, note: "numeric tunable" },
992
+ // spawn-env carrier for the OpenCode 1.x switch relaunch (WP-5); 1 site(s); first: lib/opencode-v1-plugin/model-carrier.mjs:19
993
+ { id: "ctm_ctm_opencode_switch_model", env: "CTM_OPENCODE_SWITCH_MODEL", owner: "ctm-core-team", stage: "ops", defaultOn: true, since: "2026-10-30", expires: null, note: "genuine config" },
994
+ // spawn-env carrier for the OpenCode 1.x switch relaunch (WP-5); 1 site(s); first: lib/opencode-v1-plugin/model-carrier.mjs:20
995
+ { id: "ctm_ctm_opencode_switch_session", env: "CTM_OPENCODE_SWITCH_SESSION", owner: "ctm-core-team", stage: "ops", defaultOn: true, since: "2026-10-30", expires: null, note: "genuine config" },
992
996
  // !== '0' comparison found; 1 site(s); first: lib/conversation-commit-kernel.js:179
993
997
  { id: "ctm_ctm_order_key_migration", env: "CTM_ORDER_KEY_MIGRATION", owner: "ctm-core-team", stage: "stable", defaultOn: true, since: "2026-08-24", expires: null },
994
998
  // !== '0' comparison found; 1 site(s); first: server.js:13369