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
@@ -0,0 +1,280 @@
1
+ 'use strict';
2
+
3
+ // Landing-throughput WP-6 shard S14 (design doc §5 D-10 "move-only", §6 "Shard module
4
+ // seam"): the conversation-freshness diagnostics pair (_conversationFreshnessDiagnostics plus its
5
+ // private helper _conversationPermanentStaleSnapshot) moves out of server.js VERBATIM into this
6
+ // module behind the same configure(deps) seam as lib/api/session-attach.js and
7
+ // lib/terminal-attach-geometry.js (S6), lib/walle-history-serve.js (S8),
8
+ // lib/codex-rollout-history.js (S9), lib/terminal-input-prepared.js (S10), lib/idle-notify.js
9
+ // (S11), lib/session-park.js (S12) and lib/terminal-draft-operation.js (S13). It registers NO
10
+ // route and NO socket handler: server.js keeps the one pass-through call site as
11
+ // conversationFreshnessDiagnostics._conversationFreshnessDiagnostics(id) (inside
12
+ // apiDiagnosticsConversationFreshness) and this configure() seam. Bodies are identical to the
13
+ // server.js declarations except for the `_deps.` prefix on every identifier that used to resolve
14
+ // to a server.js top-level binding (D-10 rule 1), proven by `node bin/move-only-check.js`.
15
+ // Two inline `require('./lib/...')` calls are rebased to this module's own `require('./...')`
16
+ // (S8 precedent: one move-only DIFF per rebased require -- the remainder is proven by re-running
17
+ // against a copy with `sed "s#require('\./#require('./lib/#g"` applied).
18
+ //
19
+ // The module deliberately lives at lib/conversation-freshness-diagnostics.js and NOT under lib/ws/:
20
+ // this is the read-only /api/diagnostics/conversation-freshness view, not a ws-router handler.
21
+ //
22
+ // Injected deps, per function:
23
+ // _conversationFreshnessDiagnostics: _conversationFreshnessDebtSnapshot, _coopScheduler, _ctmDbWorker, _jsonlWatcher, _resolveCanonicalRowSources, _sessionMessageRowsHwm, _sessionRowsFreshnessForSource, crypto, dbModule, getConversationImportConvergenceStats, historySourceSupport, listSelfLinkedConversationPartitions, path, providerAdapterKind
24
+ // _conversationPermanentStaleSnapshot: _conversationPermanentStale, _conversationPermanentStaleCount
25
+ //
26
+ // Mutable module state (D-10 rule 2 / S9 lesson 7): _coopScheduler, _ctmDbWorker, _jsonlWatcher and
27
+ // _conversationPermanentStaleCount are server.js `let`s, so each is injected as a GETTER -- never a
28
+ // copy. No moved body ASSIGNS a server.js top-level binding, so this seam carries no get/set pair.
29
+ // _conversationPermanentStale (a `const` Map) and every function dep are by-value references.
30
+ // Calls between the two moved functions stay direct (no `_deps.`).
31
+
32
+ let _deps = null;
33
+
34
+ function configure(deps = {}) {
35
+ _deps = deps;
36
+ }
37
+
38
+ function _conversationFreshnessDiagnostics(requestedId) {
39
+ const id = String(requestedId || '').trim();
40
+ const resolution = _deps._resolveCanonicalRowSources(id);
41
+ const sourceIds = [
42
+ id,
43
+ resolution?.canonicalSessionId,
44
+ ...(Array.isArray(resolution?.sources) ? resolution.sources.map(s => s.id) : []),
45
+ ].filter(Boolean);
46
+ const uniqueSourceIds = [...new Set(sourceIds)];
47
+ const db = _deps.dbModule.getDb();
48
+ const sources = (Array.isArray(resolution?.sources) ? resolution.sources : []).map((source) => {
49
+ const rowHwm = _deps._sessionMessageRowsHwm(source.id);
50
+ let freshness = null;
51
+ try { freshness = _deps._sessionRowsFreshnessForSource(id, source.id, { knownRowCount: rowHwm.rowCount }); } catch {}
52
+ return {
53
+ id: source.id,
54
+ rank: source.rank || 0,
55
+ reason: source.reason || '',
56
+ resolverRowCount: source.rowCount || 0,
57
+ resolverRowMaxTimestamp: source.rowMaxTimestamp || '',
58
+ rowHwm,
59
+ freshness,
60
+ };
61
+ });
62
+
63
+ const transcriptFiles = [];
64
+ const seenFiles = new Set();
65
+ for (const sourceId of uniqueSourceIds) {
66
+ let rows = [];
67
+ try {
68
+ rows = db.prepare(`
69
+ SELECT jsonl_path, agent_session_id, ctm_session_id, provider, size, offset, mtime_ms, status, last_error, updated_at
70
+ FROM transcript_files
71
+ WHERE ctm_session_id = ? OR agent_session_id = ?
72
+ ORDER BY updated_at DESC, jsonl_path
73
+ LIMIT 50
74
+ `).all(sourceId, sourceId);
75
+ } catch {}
76
+ for (const row of rows) {
77
+ const key = String(row.jsonl_path || '');
78
+ if (!key || seenFiles.has(key)) continue;
79
+ seenFiles.add(key);
80
+ const size = Number(row.size || 0);
81
+ const offset = Number(row.offset || 0);
82
+ transcriptFiles.push({
83
+ locatorBasename: _deps.path.basename(key),
84
+ locatorHash: _deps.crypto.createHash('sha256').update(key).digest('hex'),
85
+ agentSessionId: row.agent_session_id || '',
86
+ ctmSessionId: row.ctm_session_id || '',
87
+ provider: row.provider || '',
88
+ size,
89
+ offset,
90
+ lagBytes: Math.max(0, size - offset),
91
+ mtimeMs: Number(row.mtime_ms || 0),
92
+ status: row.status || '',
93
+ lastError: row.last_error || '',
94
+ updatedAt: row.updated_at || '',
95
+ });
96
+ }
97
+ }
98
+
99
+ let rowBackfillCursor = null;
100
+ try {
101
+ rowBackfillCursor = db.prepare(`
102
+ SELECT ctm_session_id, max_event_id, updated_at, last_scanned, last_inserted, last_error
103
+ FROM transcript_row_backfill_cursors
104
+ WHERE ctm_session_id = ?
105
+ `).get(resolution?.canonicalSessionId || id) || null;
106
+ } catch {}
107
+
108
+ let worker = null;
109
+ try { worker = _deps._ctmDbWorker ? _deps._ctmDbWorker.getStatus?.() : null; } catch {}
110
+ let publicationDebt = { pending: 0, oldestCommittedAt: '', oldestAgeMs: 0 };
111
+ try {
112
+ const debt = db.prepare(`
113
+ SELECT COUNT(*) AS pending, MIN(committed_at) AS oldest_committed_at
114
+ FROM conversation_update_outbox
115
+ WHERE published_at IS NULL
116
+ `).get();
117
+ const oldestCommittedAt = String(debt?.oldest_committed_at || '');
118
+ publicationDebt = {
119
+ pending: Number(debt?.pending || 0),
120
+ oldestCommittedAt,
121
+ oldestAgeMs: oldestCommittedAt ? Math.max(0, Date.now() - Date.parse(`${oldestCommittedAt}Z`)) : 0,
122
+ };
123
+ } catch {}
124
+ let kernelSources = [];
125
+ let projection = null;
126
+ let migration = null;
127
+ let rangeProtocol = null;
128
+ try {
129
+ const canonicalId = resolution?.canonicalSessionId || id;
130
+ const sourceRows = db.prepare(`
131
+ SELECT source_id, provider, adapter_kind, generation, source_version,
132
+ observed_hwm, committed_hwm, continuation_json, parser_version, state, last_error
133
+ FROM conversation_sources WHERE canonical_session_id=? ORDER BY source_id
134
+ `).all(canonicalId);
135
+ const memberQuery = db.prepare(`
136
+ SELECT member_id, locator_hash, locator_basename, fingerprint, member_role,
137
+ generation, byte_cursor, partial_line, observed_size, observed_mtime_ms, committed_hwm
138
+ FROM conversation_source_members WHERE source_id=? ORDER BY member_id
139
+ `);
140
+ kernelSources = sourceRows.map((row) => ({
141
+ sourceId: row.source_id,
142
+ provider: row.provider,
143
+ adapter: row.adapter_kind,
144
+ writer: 'conversation-commit-kernel',
145
+ generation: Number(row.generation || 0),
146
+ sourceVersion: Number(row.source_version || 0),
147
+ observedHwm: (() => { try { return JSON.parse(row.observed_hwm || '{}'); } catch { return {}; } })(),
148
+ committedHwm: (() => { try { return JSON.parse(row.committed_hwm || '{}'); } catch { return {}; } })(),
149
+ continuationPending: !!row.continuation_json,
150
+ parserVersion: Number(row.parser_version || 0),
151
+ state: row.state,
152
+ lastError: row.last_error || '',
153
+ members: memberQuery.all(row.source_id).map((member) => ({
154
+ memberId: member.member_id,
155
+ locatorHash: member.locator_hash,
156
+ locatorBasename: member.locator_basename,
157
+ fingerprint: member.fingerprint,
158
+ role: member.member_role,
159
+ generation: Number(member.generation || 0),
160
+ byteCursor: Number(member.byte_cursor || 0),
161
+ observedSize: Number(member.observed_size || 0),
162
+ observedMtimeMs: Number(member.observed_mtime_ms || 0),
163
+ partialLinePending: !!member.partial_line,
164
+ committedHwm: (() => { try { return JSON.parse(member.committed_hwm || '{}'); } catch { return {}; } })(),
165
+ })),
166
+ }));
167
+ projection = db.prepare('SELECT * FROM conversation_projection_state WHERE ctm_session_id=?').get(canonicalId) || null;
168
+ migration = db.prepare('SELECT * FROM conversation_migration_state WHERE provider=?').get('provider-source-enrollment') || null;
169
+ rangeProtocol = require('./conversation-page-v3')
170
+ .readConversationV3Diagnostics(db, canonicalId);
171
+ rangeProtocol.metrics = require('./conversation-range-metrics').snapshot(canonicalId);
172
+ } catch {}
173
+ const sourceComplete = (source) => {
174
+ if (!source || source.state !== 'active' || source.continuationPending) return false;
175
+ if (JSON.stringify(source.observedHwm || {}) !== JSON.stringify(source.committedHwm || {})) return false;
176
+ if (source.adapter !== 'append-log' && source.adapter !== 'compound-log') return true;
177
+ const currentMembers = source.members.filter((member) => member.generation === source.generation);
178
+ return currentMembers.length > 0 && currentMembers.every((member) => (
179
+ !member.partialLinePending && member.byteCursor >= member.observedSize
180
+ ));
181
+ };
182
+ let aliasPartitions = [];
183
+ try {
184
+ // One predicate: the adoption module owns "which agent ids hold a stranded v2 partition".
185
+ aliasPartitions = _deps.listSelfLinkedConversationPartitions(db, _deps.dbModule.getDomainDb('core'), { limit: 100 })
186
+ .map((p) => ({ agentSessionId: p.agentSessionId, ownerCtmSessionId: p.ownerCtmSessionId, rowCount: p.placements }));
187
+ } catch {}
188
+ let detectedProvider = '';
189
+ try {
190
+ const canonicalId = resolution?.canonicalSessionId || id;
191
+ // ctm_sessions + agent_sessions are both core.
192
+ detectedProvider = String(_deps.dbModule.getDomainDb('core').prepare(`
193
+ SELECT provider FROM ctm_sessions WHERE id=?
194
+ UNION ALL
195
+ SELECT provider FROM agent_sessions WHERE ctm_session_id=? OR agent_session_id=?
196
+ LIMIT 1
197
+ `).get(canonicalId, canonicalId, id)?.provider || '').trim().toLowerCase();
198
+ } catch {}
199
+ // S-19: pass the SAME adapterKind the runtime ingest path would derive
200
+ // (providerAdapterKind) rather than leaving adapterKind blank — a blank
201
+ // adapterKind makes historySourceSupport accept ANY registered adapter for
202
+ // the provider, which can report "supported" for a provider/adapter
203
+ // combination the runtime path would actually reject, making this
204
+ // diagnostic disagree with reality.
205
+ const sourceSupport = kernelSources.length > 0
206
+ ? _deps.historySourceSupport(kernelSources[0].provider, kernelSources[0].adapter)
207
+ : (detectedProvider
208
+ ? _deps.historySourceSupport(detectedProvider, _deps.providerAdapterKind(detectedProvider))
209
+ : { provider: '', status: 'history_source_unclassified', supported: false });
210
+ const sourceSetVersion = kernelSources.reduce((total, source) => total + Number(source.sourceVersion || 0), 0);
211
+ const migrationComplete = !migration || !!migration.completed_at;
212
+ const projectionComplete = !!projection
213
+ && projection.state === 'ready'
214
+ && Number(projection.source_set_version || 0) === sourceSetVersion
215
+ && kernelSources.length > 0
216
+ && kernelSources.every(sourceComplete)
217
+ && migrationComplete
218
+ && aliasPartitions.length === 0;
219
+ return {
220
+ ok: true,
221
+ generatedAt: Date.now(),
222
+ requestedId: id,
223
+ canonicalSessionId: resolution?.canonicalSessionId || id,
224
+ sources,
225
+ transcriptFiles,
226
+ totalLagBytes: transcriptFiles.reduce((n, row) => n + Number(row.lagBytes || 0), 0),
227
+ rowBackfillCursor,
228
+ convergence: {
229
+ main: typeof _deps.getConversationImportConvergenceStats === 'function'
230
+ ? _deps.getConversationImportConvergenceStats(id)
231
+ : null,
232
+ worker: null,
233
+ },
234
+ worker,
235
+ watcherRoots: _deps._jsonlWatcher?.rootHealthSnapshot?.() || [],
236
+ render: {
237
+ rowCount: _deps._sessionMessageRowsHwm(resolution?.canonicalSessionId || id).rowCount,
238
+ projectionEpoch: Number(projection?.projection_epoch || 0),
239
+ latestRowHwm: Number(projection?.latest_row_hwm || 0),
240
+ },
241
+ providerSources: kernelSources,
242
+ historySource: sourceSupport,
243
+ projectionComplete,
244
+ projection,
245
+ migration,
246
+ rangeProtocol,
247
+ rowOwnership: {
248
+ writer: 'conversation-commit-kernel',
249
+ aliasPartitionCount: aliasPartitions.length,
250
+ aliasRows: aliasPartitions.reduce((total, row) => total + Number(row.rowCount || 0), 0),
251
+ aliasPartitions,
252
+ },
253
+ publicationDebt,
254
+ coopJobs: _deps._coopScheduler ? _deps._coopScheduler.statusReport() : [],
255
+ freshnessDebt: _deps._conversationFreshnessDebtSnapshot(),
256
+ permanentStaleTripwire: _conversationPermanentStaleSnapshot(),
257
+ };
258
+ }
259
+
260
+ function _conversationPermanentStaleSnapshot() {
261
+ const items = [];
262
+ for (const [sessionId, item] of _deps._conversationPermanentStale.entries()) {
263
+ items.push({
264
+ sessionId,
265
+ firstAt: item.firstAt || 0,
266
+ loggedAt: item.loggedAt || 0,
267
+ state: item.state || '',
268
+ count: item.count || 0,
269
+ renderableTailBytes: item.renderableTailBytes || 0,
270
+ evidence: item.evidence || null,
271
+ });
272
+ }
273
+ return { count: _deps._conversationPermanentStaleCount, active: items };
274
+ }
275
+
276
+ module.exports = {
277
+ configure,
278
+ _conversationFreshnessDiagnostics,
279
+ _conversationPermanentStaleSnapshot,
280
+ };
@@ -0,0 +1,261 @@
1
+ 'use strict';
2
+
3
+ // WP-5 (docs/shared-memory-every-machine-2026-10-31.html §5 D-3, §6.8): the per-origin change
4
+ // clock over the conversation store. Every inserted/corrected item gets one clock row carrying
5
+ // (origin_instance_id, origin_seq) — the compacted log lib/conversation-sync.js serves as a
6
+ // version-vector-addressed feed. `conversation_vv` is "seen through"; `conversation_local_seq`
7
+ // is this host's monotonic allocator. Text table untouched (the brief's DDL is additive).
8
+ //
9
+ // HELPERS ONLY — no DDL lives here. The three clock tables are declared by migration v61
10
+ // (lib/migrations/v61-conversation-item-clock.js, the sanctioned lib/migrations/** home), which
11
+ // lib/conversation-store-v2.js reaches through ensureConversationItemClockSchema so a store built
12
+ // outside the ladder (a bare fixture, a fresh boot) still gets them — the same shape
13
+ // lib/conversation-turn-index.js uses for v31's turn index. Keeping the DDL out of that store is
14
+ // what keeps conversation-store-v2.js under its ddl-outside-runner ratchet; keeping it out of HERE
15
+ // is what lets this module sit BELOW db.js without a require cycle.
16
+ //
17
+ // The replica RECEIVER's delete is NOT here: it lives beside purgeConversationV2 in
18
+ // lib/prompt-purge-v2.js, because it is the same "delete items by stable key + record the feed +
19
+ // rebuild the turn index" operation, and that module is already the pinned writer of the
20
+ // conversation item tables (tests/conversation-store-v2.test.js's writer gate). Keeping it there
21
+ // keeps this module DDL-free AND free of raw item-table writes.
22
+
23
+ // WP-5 §6.8: one seed page is at most this many items (the brief's default).
24
+ const CONVERSATION_SEED_PAGE_LIMIT = 5_000;
25
+
26
+ // The seed walk's resumable cursor lives in the host-local `settings` kv (never replicated, D-7).
27
+ const CONVERSATION_SEED_CURSOR_KEY = 'conversation_clock_seed.cursor';
28
+
29
+ // A process-level override for this CTM's instance id. Production leaves it null and the store
30
+ // reads `instance_identity` (the row db.js's boot mint writes); tests set it so a bare in-memory
31
+ // store has a deterministic origin without a boot sequence.
32
+ let _instanceIdOverride = null;
33
+
34
+ // The production seam for the same question: a resolver db.js registers at module scope (it is the
35
+ // one module that owns `getCurrentHostedInstanceIdStrict`, and its handle routing knows where the
36
+ // `instance_identity` row physically lives). Null until then, and '' is a valid answer.
37
+ let _instanceIdResolver = null;
38
+
39
+ function setConversationInstanceIdForTests(instanceId) {
40
+ _instanceIdOverride = instanceId ? String(instanceId).trim() : null;
41
+ }
42
+
43
+ // `fn` is a zero-arg function returning this CTM's instance id (or a falsy value); null clears it.
44
+ function setConversationInstanceIdResolver(fn) {
45
+ _instanceIdResolver = typeof fn === 'function' ? fn : null;
46
+ }
47
+
48
+ // This CTM's own instance id — the value that addresses everything this node ORIGINATES. Same
49
+ // source the rest of the firehose DB uses for `origin_instance_id` (db.js's boot mint writes the
50
+ // `instance_identity` row); '' means "this host, before the identity was known" (never shipped —
51
+ // D-3), and a caller with no such row can pin one with setConversationInstanceIdForTests.
52
+ //
53
+ // Deliberately NOT falling back to lib/instance-identity-access here: that module sits ABOVE db.js
54
+ // (it reads its identity through `require('../db')`), and db.js requires the conversation store —
55
+ // reaching for it would put this module back above db.js and close a dependency-lint cycle
56
+ // (lib/conversation-item-clock -> lib/instance-identity-access -> db.js -> lib/conversation-store-v2).
57
+ //
58
+ // So the fallback is a RESOLVER SEAM instead of an import. The clock's own tables are read from the
59
+ // same handle as the identity row, so a handle that can read one can read the other — but only on a
60
+ // single-file install. On a DOMAIN-SPLIT install the clock tables are firehose (task-manager.db)
61
+ // while `instance_identity` is core (core.db), so the same-handle read above finds no table and
62
+ // every origin would be ''. db.js (which sits ABOVE this module and already requires the store, so
63
+ // no new edge is created) registers `() => getCurrentHostedInstanceIdStrict()` — the identity
64
+ // accessor lib/instance-identity-access.js itself uses, routed through getDomainDb('core') — and
65
+ // this module calls it only when the same-handle read came up empty. Tests may set the override or
66
+ // the resolver; both are process-wide and must be restored in after().
67
+ function localConversationInstanceId(db) {
68
+ if (_instanceIdOverride) return _instanceIdOverride;
69
+ try {
70
+ const row = db.prepare('SELECT instance_id FROM instance_identity LIMIT 1').get();
71
+ const id = String(row?.instance_id || '').trim();
72
+ if (id) return id;
73
+ } catch { /* expected: a store without the instance_identity table (bare fixture) */ }
74
+ if (_instanceIdResolver) {
75
+ try {
76
+ const resolved = _instanceIdResolver();
77
+ // A non-string (an object, a number, undefined) is NOT an instance id — take nothing from it.
78
+ if (typeof resolved === 'string') {
79
+ const id = resolved.trim();
80
+ if (id) return id;
81
+ }
82
+ } catch { /* expected: identity not readable yet (pre-initDb, or no core handle) — origin stays '' */ }
83
+ }
84
+ return ''; // REPORT: no readable identity — items stay unaddressable (origin '') rather than mislabelled
85
+ }
86
+
87
+ function _tableExists(db, name) {
88
+ return !!db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name=?").get(name);
89
+ }
90
+
91
+ // Allocate `count` consecutive local seqs; seqs start at 1. Caller owns the transaction.
92
+ function _takeLocalSeqs(db, count) {
93
+ const row = db.prepare('SELECT next_seq FROM conversation_local_seq WHERE id=1').get();
94
+ const start = row && Number.isSafeInteger(Number(row.next_seq)) && Number(row.next_seq) > 0
95
+ ? Number(row.next_seq) : 1;
96
+ db.prepare(`
97
+ INSERT INTO conversation_local_seq(id, next_seq) VALUES (1, ?)
98
+ ON CONFLICT(id) DO UPDATE SET next_seq=excluded.next_seq
99
+ `).run(start + count);
100
+ return start;
101
+ }
102
+
103
+ // "Seen through": monotonic per origin, exactly like the brain's _bumpVv.
104
+ function _bumpConversationVv(db, originInstanceId, seq) {
105
+ const origin = String(originInstanceId || '').trim();
106
+ const value = Number(seq);
107
+ if (!origin || !Number.isSafeInteger(value) || value <= 0) return;
108
+ db.prepare(`
109
+ INSERT INTO conversation_vv(origin_instance_id, max_seq) VALUES (?, ?)
110
+ ON CONFLICT(origin_instance_id) DO UPDATE SET max_seq=MAX(max_seq, excluded.max_seq)
111
+ `).run(origin, value);
112
+ }
113
+
114
+ function _stampConversationClock(db, { stableKey, sessionId, originInstanceId, originSeq, nowMs, deleted }) {
115
+ db.prepare(`
116
+ INSERT INTO conversation_item_clock
117
+ (stable_key, session_id, origin_instance_id, origin_seq, updated_at_ms, deleted)
118
+ VALUES (?,?,?,?,?,?)
119
+ ON CONFLICT(stable_key) DO UPDATE SET
120
+ session_id=excluded.session_id,
121
+ origin_instance_id=excluded.origin_instance_id,
122
+ origin_seq=excluded.origin_seq,
123
+ updated_at_ms=excluded.updated_at_ms,
124
+ deleted=excluded.deleted
125
+ `).run(String(stableKey), String(sessionId), String(originInstanceId || ''),
126
+ Number(originSeq) || 0, Number(nowMs) || 0, deleted ? 1 : 0);
127
+ }
128
+
129
+ // The receiver's tombstone clock row: the sender's (origin, origin_seq) with deleted=1, so the
130
+ // delete stays addressable in its origin's stream and relays onward (D-3). No local seq is spent.
131
+ function stampIncomingConversationClockV2(db, { stableKey, sessionId, origin, originSeq, nowMs = Date.now() } = {}) {
132
+ const key = String(stableKey || '').trim();
133
+ const originId = String(origin || '').trim();
134
+ const seq = Number(originSeq);
135
+ if (!key || !originId || !Number.isSafeInteger(seq) || seq <= 0) return false;
136
+ _stampConversationClock(db, {
137
+ stableKey: key, sessionId, originInstanceId: originId, originSeq: seq, nowMs, deleted: true,
138
+ });
139
+ _bumpConversationVv(db, originId, seq);
140
+ return true;
141
+ }
142
+
143
+ function _readConversationVv(db) {
144
+ const vector = {};
145
+ for (const row of db.prepare('SELECT origin_instance_id, max_seq FROM conversation_vv ORDER BY origin_instance_id ASC').all()) {
146
+ vector[String(row.origin_instance_id)] = Number(row.max_seq) || 0;
147
+ }
148
+ return vector;
149
+ }
150
+
151
+ // The tombstone half of a purge: a purged key must keep an addressable clock row (deleted=1)
152
+ // under THIS host's origin so peers learn to delete it. Local seqs, local vv bump, one row per key.
153
+ function stampConversationTombstonesV2(db, { sessionId, stableKeys = [], nowMs = Date.now() } = {}) {
154
+ const keys = [...new Set((Array.isArray(stableKeys) ? stableKeys : []).map((k) => String(k)).filter(Boolean))];
155
+ if (!keys.length) return 0;
156
+ const localId = localConversationInstanceId(db);
157
+ // No identity, no stamping (the same rule the ingest path applies — lib/conversation-store-v2.js
158
+ // skips `!origin`): a row at origin '' is unaddressable AND permanently so, because nothing ever
159
+ // revisits a key that already has a clock row. Spend no seq, write no row, say so.
160
+ if (!localId) return 0;
161
+ let start = 1;
162
+ db.transaction(() => {
163
+ start = _takeLocalSeqs(db, keys.length);
164
+ keys.forEach((stableKey, index) => {
165
+ _stampConversationClock(db, {
166
+ stableKey, sessionId, originInstanceId: localId, originSeq: start + index, nowMs, deleted: true,
167
+ });
168
+ });
169
+ _bumpConversationVv(db, localId, start + keys.length - 1);
170
+ })();
171
+ return keys.length;
172
+ }
173
+
174
+ function conversationSeedState(db) {
175
+ try {
176
+ const row = db.prepare('SELECT value FROM settings WHERE key=?').get(CONVERSATION_SEED_CURSOR_KEY);
177
+ if (!row || row.value == null) return { done: false, afterItemId: 0 };
178
+ const parsed = JSON.parse(String(row.value));
179
+ return { done: parsed?.done === true, afterItemId: Number(parsed?.afterItemId) || 0 };
180
+ } catch {
181
+ return { done: false, afterItemId: 0 }; // expected: no cursor yet (or a bare fixture without `settings`)
182
+ }
183
+ }
184
+
185
+ function _writeConversationSeedState(db, state) {
186
+ db.prepare(`
187
+ INSERT INTO settings(key, value) VALUES (?, ?)
188
+ ON CONFLICT(key) DO UPDATE SET value=excluded.value
189
+ `).run(CONVERSATION_SEED_CURSOR_KEY, JSON.stringify(state));
190
+ }
191
+
192
+ // One bounded, resumable page of the one-time seed for items that predate the clock. Stamps a
193
+ // clock row at THIS host's origin (local seq) for every item that has none, writes NO outbox row
194
+ // (seeding is not a user-visible change — test (g)), and advances the item_id cursor. Never boot
195
+ // work: the hub/member round drives it until done.
196
+ function seedConversationClockPage(db, { limit = CONVERSATION_SEED_PAGE_LIMIT } = {}) {
197
+ if (!_tableExists(db, 'conversation_item_clock') || !_tableExists(db, 'conversation_text_items_v2')) {
198
+ return { seeded: 0, done: true, afterItemId: 0 };
199
+ }
200
+ const budget = Math.max(1, Math.min(CONVERSATION_SEED_PAGE_LIMIT, Number(limit) || CONVERSATION_SEED_PAGE_LIMIT));
201
+ const state = conversationSeedState(db);
202
+ if (state.done) return { seeded: 0, done: true, afterItemId: state.afterItemId };
203
+ const localId = localConversationInstanceId(db);
204
+ // No readable identity ⇒ stamp NOTHING: not the rows, not the cursor. Seeding at origin '' would
205
+ // take seqs and write clock rows for all N items, and the walk never revisits a key that already
206
+ // has one — so a single premature page would make the whole store permanently unaddressable
207
+ // (the live domain-split symptom: 16,482 items, zero clock rows, nothing on the feed). Returning
208
+ // done:false without opening a transaction leaves the cursor untouched, so the very next call
209
+ // after the identity becomes readable seeds the same items at the REAL origin.
210
+ if (!localId) return { seeded: 0, done: false, afterItemId: state.afterItemId };
211
+ const nowMs = Date.now();
212
+ let seeded = 0;
213
+ let afterItemId = state.afterItemId;
214
+ db.transaction(() => {
215
+ const rows = db.prepare(`
216
+ SELECT i.item_id, i.stable_key, i.session_id
217
+ FROM conversation_text_items_v2 i
218
+ LEFT JOIN conversation_item_clock c ON c.stable_key = i.stable_key
219
+ WHERE i.item_id > ? AND c.stable_key IS NULL
220
+ ORDER BY i.item_id ASC
221
+ LIMIT ?
222
+ `).all(afterItemId, budget);
223
+ if (rows.length) {
224
+ const start = _takeLocalSeqs(db, rows.length);
225
+ rows.forEach((row, index) => {
226
+ _stampConversationClock(db, {
227
+ stableKey: row.stable_key, sessionId: row.session_id,
228
+ originInstanceId: localId, originSeq: start + index, nowMs, deleted: false,
229
+ });
230
+ });
231
+ _bumpConversationVv(db, localId, start + rows.length - 1);
232
+ seeded = rows.length;
233
+ afterItemId = Number(rows[rows.length - 1].item_id);
234
+ }
235
+ // More work remains when this page was full or a later item still lacks a clock.
236
+ const pending = db.prepare(`
237
+ SELECT 1 AS hit FROM conversation_text_items_v2 i
238
+ LEFT JOIN conversation_item_clock c ON c.stable_key = i.stable_key
239
+ WHERE i.item_id > ? AND c.stable_key IS NULL LIMIT 1
240
+ `).get(afterItemId);
241
+ _writeConversationSeedState(db, { done: !pending, afterItemId });
242
+ })();
243
+ return { seeded, done: conversationSeedState(db).done, afterItemId };
244
+ }
245
+
246
+ module.exports = {
247
+ CONVERSATION_SEED_PAGE_LIMIT,
248
+ setConversationInstanceIdForTests,
249
+ setConversationInstanceIdResolver,
250
+ localConversationInstanceId,
251
+ readConversationClockVector: _readConversationVv,
252
+ bumpConversationVv: _bumpConversationVv,
253
+ stampIncomingConversationClockV2,
254
+ stampConversationTombstonesV2,
255
+ conversationSeedState,
256
+ seedConversationClockPage,
257
+ // Internal stamping primitives the conversation store's writer calls inside its own transaction.
258
+ _takeLocalSeqs,
259
+ _stampConversationClock,
260
+ _bumpConversationVv,
261
+ };
@@ -93,6 +93,11 @@ const PROVIDER_ADAPTERS = Object.freeze({
93
93
  'claude-desktop': Object.freeze(['snapshot']),
94
94
  cursor: Object.freeze(['database-snapshot']),
95
95
  opencode: Object.freeze(['database-snapshot']),
96
+ // S-25 (docs/deepseek-harness-acp-agent-2026-10-28.html, WP-3 after OQ-2): the DeepSeek Harness's
97
+ // CTM-owned transcript (lib/acp/dsh-transcript.js) is Claude-shaped JSONL, so its history ingest
98
+ // rides the same compound-log lane as claude. Without this entry providerAdapterKind('dsh') is ''
99
+ // and isLogAdapterProvider() rejects the file before it can be parsed.
100
+ dsh: Object.freeze(['compound-log']),
96
101
  });
97
102
 
98
103
  function _flagEnabled(name) {
@@ -17,6 +17,12 @@ const {
17
17
  const DEFAULT_READ_LIMIT = 500;
18
18
  const MAX_READ_LIMIT = 2_000;
19
19
 
20
+ // WP-5 §6.8: the clock's tables are migration v61's; its helpers are lib/conversation-item-clock.js.
21
+ const {
22
+ localConversationInstanceId, _takeLocalSeqs, _stampConversationClock, _bumpConversationVv, seedConversationClockPage,
23
+ } = require('./conversation-item-clock');
24
+ const { ensureConversationItemClockSchema } = require('./migrations/v61-conversation-item-clock');
25
+
20
26
  // These triggers keep the external-content FTS index in sync; table rebuilds recreate them transactionally (v25 migration).
21
27
  const CONVERSATION_FTS_TRIGGERS_DDL = `
22
28
  CREATE TRIGGER IF NOT EXISTS conversation_text_v2_ai
@@ -169,6 +175,8 @@ function ensureConversationStoreV2(db) {
169
175
 
170
176
  ${CONVERSATION_FTS_TRIGGERS_DDL}
171
177
  `);
178
+ // WP-5 §6.8: reached here too, so a store built outside the ladder still has the clock tables.
179
+ ensureConversationItemClockSchema({ getDb: () => db });
172
180
  ensureTurnIndexSchema(db);
173
181
  const textColumns = new Set(db.prepare('PRAGMA table_info(conversation_text_items_v2)').all().map((row) => row.name));
174
182
  if (!textColumns.has('source_event_digest')) {
@@ -436,6 +444,8 @@ function partitionReplacedRemovals(removals, admittedIdentities) {
436
444
  return { removals: removals.filter((r) => !isReplaced(r)), replaced: removals.filter(isReplaced) };
437
445
  }
438
446
 
447
+ // The receiver's delete (deleteConversationItemsByStableKeyV2) moved to lib/prompt-purge-v2.js.
448
+
439
449
  function commitConversationBatchV2(db, batch = {}) {
440
450
  if (!db) throw new TypeError('db is required');
441
451
  if (!_tableExists(db, 'conversation_text_items_v2')
@@ -788,6 +798,38 @@ function commitConversationBatchV2(db, batch = {}) {
788
798
  outboxChanges += 1;
789
799
  }
790
800
 
801
+ // WP-5 §6.8: stamp the per-origin clock for every live/tombstoned key this batch changed. The
802
+ // ordinary writer stamps THIS host's origin with fresh local seqs; the receiver path
803
+ // (`batch.replication = { origin, originSeqByKey }`) keeps the SENDER's origin/seq instead, so a
804
+ // re-served row stays addressable in its origin's stream and this node never re-authors it (no echo).
805
+ if (changed.size) {
806
+ const replication = batch.replication && typeof batch.replication === 'object' ? batch.replication : null;
807
+ const originSeqByKey = replication && replication.originSeqByKey && typeof replication.originSeqByKey === 'object'
808
+ ? replication.originSeqByKey : null;
809
+ const keys = [...changed.keys()];
810
+ const localId = localConversationInstanceId(db);
811
+ const localStart = replication ? 0 : _takeLocalSeqs(db, keys.length);
812
+ const ceiling = new Map(); // origin -> highest seq stamped by this batch
813
+ keys.forEach((stableKey, index) => {
814
+ const change = changed.get(stableKey);
815
+ const incoming = originSeqByKey ? Number(originSeqByKey[stableKey]) : NaN;
816
+ const replicated = !!replication && Number.isSafeInteger(incoming) && incoming > 0;
817
+ // A replication batch keeps only the sender's origin/seq; a key with no incoming seq is a
818
+ // local divergence this node already owns, so it is left to its own writer rather than
819
+ // re-authored here under a fabricated origin.
820
+ if (replication && !replicated) return;
821
+ const origin = replicated ? String(replication.origin || '') : localId;
822
+ const seq = replicated ? incoming : localStart + index;
823
+ if (!origin || !(seq > 0)) return;
824
+ _stampConversationClock(db, {
825
+ stableKey, sessionId: change.sessionId, originInstanceId: origin,
826
+ originSeq: seq, nowMs, deleted: change.kind === 'deleted',
827
+ });
828
+ ceiling.set(origin, Math.max(ceiling.get(origin) || 0, seq));
829
+ });
830
+ for (const [origin, seq] of ceiling) _bumpConversationVv(db, origin, seq);
831
+ }
832
+
791
833
  const generationSessionIds = new Set(items.map((entry) => entry.item.sessionId));
792
834
  for (const removal of removals) generationSessionIds.add(removal.sessionId);
793
835
  if (snapshotSessionId) generationSessionIds.add(snapshotSessionId);
@@ -1043,4 +1085,6 @@ module.exports = {
1043
1085
  readConversationItemsV2,
1044
1086
  searchConversationItemsV2,
1045
1087
  verifyConversationFtsV2,
1088
+ // WP-5 §6.8: re-exported for callers that still reach the seed through the store (lib/memory-sync.js).
1089
+ seedConversationClockPage,
1046
1090
  };