create-walle 0.10.0 → 0.10.2

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 (381) hide show
  1. package/README.md +88 -41
  2. package/lib/owner-write-safety.js +135 -0
  3. package/lib/public-runtime.js +13 -5
  4. package/lib/release-schema.json +3 -2
  5. package/lib/runtime-closure-policy.json +7 -5
  6. package/package.json +10 -4
  7. package/template/bin/deps-doctor.js +1 -1
  8. package/template/bin/node-bin.sh +11 -0
  9. package/template/coding-task-manager/api-prompts.js +10 -22
  10. package/template/coding-task-manager/bin/capture-codex-rollout-records.js +417 -0
  11. package/template/coding-task-manager/bin/census-codex-lead-history.js +325 -0
  12. package/template/coding-task-manager/bin/claude-hook.js +7 -3
  13. package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
  14. package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
  15. package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
  16. package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
  17. package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
  18. package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
  19. package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
  20. package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
  21. package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
  22. package/template/coding-task-manager/bin/seam-replay-codex.js +301 -0
  23. package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
  24. package/template/coding-task-manager/db.js +705 -286
  25. package/template/coding-task-manager/git-utils.js +44 -0
  26. package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
  27. package/template/coding-task-manager/lib/agent-presets.js +15 -0
  28. package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
  29. package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
  30. package/template/coding-task-manager/lib/api/host-stats.js +98 -0
  31. package/template/coding-task-manager/lib/api/ingress.js +35 -12
  32. package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
  33. package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
  34. package/template/coding-task-manager/lib/api/machines.js +461 -0
  35. package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
  36. package/template/coding-task-manager/lib/api/providers.js +53 -6
  37. package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
  38. package/template/coding-task-manager/lib/api/sessions.js +160 -8
  39. package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
  40. package/template/coding-task-manager/lib/api/worktrees.js +38 -37
  41. package/template/coding-task-manager/lib/approval-drift.js +16 -1
  42. package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
  43. package/template/coding-task-manager/lib/approval-scope.js +68 -4
  44. package/template/coding-task-manager/lib/auth-context.js +32 -2
  45. package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
  46. package/template/coding-task-manager/lib/auth-rules.js +186 -45
  47. package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
  48. package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
  49. package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
  50. package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
  51. package/template/coding-task-manager/lib/claude-session-title.js +6 -30
  52. package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
  53. package/template/coding-task-manager/lib/client-diag-handler.js +25 -0
  54. package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
  55. package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
  56. package/template/coding-task-manager/lib/codex-history-terminal-renderer.js +33 -33
  57. package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
  58. package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
  59. package/template/coding-task-manager/lib/codex-local-links.js +267 -0
  60. package/template/coding-task-manager/lib/codex-markdown-lists.js +160 -0
  61. package/template/coding-task-manager/lib/codex-native-history-prefix.js +4 -0
  62. package/template/coding-task-manager/lib/codex-paths.js +2 -1
  63. package/template/coding-task-manager/lib/codex-source-handoff.js +186 -0
  64. package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
  65. package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
  66. package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
  67. package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
  68. package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
  69. package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
  70. package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
  71. package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
  72. package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
  73. package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
  74. package/template/coding-task-manager/lib/db-domains.js +21 -2
  75. package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
  76. package/template/coding-task-manager/lib/db-owner-worker-client.js +22 -0
  77. package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
  78. package/template/coding-task-manager/lib/feature-manifest.js +1 -3
  79. package/template/coding-task-manager/lib/fs-watcher.js +3 -2
  80. package/template/coding-task-manager/lib/harness-history-transition.js +41 -14
  81. package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
  82. package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
  83. package/template/coding-task-manager/lib/headless-term-service.js +60 -23
  84. package/template/coding-task-manager/lib/history-transition-read-op.js +179 -23
  85. package/template/coding-task-manager/lib/host-control-dial.js +167 -0
  86. package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
  87. package/template/coding-task-manager/lib/host-handoff.js +51 -13
  88. package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
  89. package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
  90. package/template/coding-task-manager/lib/host-stats.js +328 -0
  91. package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
  92. package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
  93. package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
  94. package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
  95. package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
  96. package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
  97. package/template/coding-task-manager/lib/instance-manifest.js +13 -1
  98. package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
  99. package/template/coding-task-manager/lib/kernel/diag-log.js +12 -0
  100. package/template/coding-task-manager/lib/launch-model-override.js +160 -1
  101. package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
  102. package/template/coding-task-manager/lib/lead-model-observer.js +17 -2
  103. package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
  104. package/template/coding-task-manager/lib/lead-model-switch.js +11 -2
  105. package/template/coding-task-manager/lib/lead-model-transition-runtime.js +42 -4
  106. package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
  107. package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
  108. package/template/coding-task-manager/lib/login-tripwire.js +18 -0
  109. package/template/coding-task-manager/lib/machine-pairing.js +238 -0
  110. package/template/coding-task-manager/lib/machine-pool.js +409 -0
  111. package/template/coding-task-manager/lib/machine-registry.js +749 -0
  112. package/template/coding-task-manager/lib/machine-self.js +66 -0
  113. package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +56 -4
  114. package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
  115. package/template/coding-task-manager/lib/media-journal.js +84 -27
  116. package/template/coding-task-manager/lib/media-store-options.js +43 -15
  117. package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
  118. package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
  119. package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +16 -3
  120. package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
  121. package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
  122. package/template/coding-task-manager/lib/model-proxy/collaboration-codec.js +94 -0
  123. package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
  124. package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
  125. package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
  126. package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
  127. package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
  128. package/template/coding-task-manager/lib/model-proxy/responses-face.js +24 -2
  129. package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
  130. package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
  131. package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
  132. package/template/coding-task-manager/lib/native-history-control.js +62 -14
  133. package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
  134. package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
  135. package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
  136. package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
  137. package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
  138. package/template/coding-task-manager/lib/prompt-admission-trace.js +69 -0
  139. package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
  140. package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
  141. package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
  142. package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
  143. package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
  144. package/template/coding-task-manager/lib/raw-history-block.js +3 -1
  145. package/template/coding-task-manager/lib/read-pool-client.js +36 -24
  146. package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
  147. package/template/coding-task-manager/lib/read-pool-telemetry.js +14 -5
  148. package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
  149. package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
  150. package/template/coding-task-manager/lib/remote-command-context.js +12 -0
  151. package/template/coding-task-manager/lib/remote-command-runtime.js +18 -5
  152. package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
  153. package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
  154. package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
  155. package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
  156. package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
  157. package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
  158. package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
  159. package/template/coding-task-manager/lib/restart-preflight.js +9 -2
  160. package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
  161. package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
  162. package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
  163. package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
  164. package/template/coding-task-manager/lib/resume-cwd.js +13 -0
  165. package/template/coding-task-manager/lib/resume-from-store.js +12 -1
  166. package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
  167. package/template/coding-task-manager/lib/resume-preflight.js +21 -16
  168. package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
  169. package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
  170. package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
  171. package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
  172. package/template/coding-task-manager/lib/root-prompt-admission.js +43 -11
  173. package/template/coding-task-manager/lib/root-prompt-flow.js +175 -38
  174. package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
  175. package/template/coding-task-manager/lib/server-memory-sampler-runtime.js +10 -0
  176. package/template/coding-task-manager/lib/server-memory-sampler.js +41 -2
  177. package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
  178. package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
  179. package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
  180. package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
  181. package/template/coding-task-manager/lib/session-create/identity.js +20 -1
  182. package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
  183. package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
  184. package/template/coding-task-manager/lib/session-create/provider-process.js +38 -39
  185. package/template/coding-task-manager/lib/session-create/response.js +30 -12
  186. package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
  187. package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
  188. package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
  189. package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
  190. package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
  191. package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
  192. package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
  193. package/template/coding-task-manager/lib/session-host-manager.js +152 -206
  194. package/template/coding-task-manager/lib/session-jobs.js +17 -9
  195. package/template/coding-task-manager/lib/session-lifecycle.js +20 -50
  196. package/template/coding-task-manager/lib/session-model-action-preconditions.js +68 -3
  197. package/template/coding-task-manager/lib/session-resource-sampler.js +67 -9
  198. package/template/coding-task-manager/lib/session-standup.js +67 -4
  199. package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
  200. package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
  201. package/template/coding-task-manager/lib/session-status.js +2 -2
  202. package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
  203. package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
  204. package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
  205. package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
  206. package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
  207. package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
  208. package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
  209. package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
  210. package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
  211. package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
  212. package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
  213. package/template/coding-task-manager/lib/transcript-link.js +77 -0
  214. package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
  215. package/template/coding-task-manager/lib/transcript-source.js +8 -3
  216. package/template/coding-task-manager/lib/transcript-store.js +40 -0
  217. package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
  218. package/template/coding-task-manager/lib/typing-interaction-trace.js +136 -2
  219. package/template/coding-task-manager/lib/typing-worker-stages.js +208 -1
  220. package/template/coding-task-manager/lib/usage-ledger/claude-parse.js +53 -2
  221. package/template/coding-task-manager/lib/usage-ledger/ingest.js +13 -4
  222. package/template/coding-task-manager/lib/usage-ledger/read.js +14 -0
  223. package/template/coding-task-manager/lib/usage-ledger/schema.js +49 -1
  224. package/template/coding-task-manager/lib/usage-ledger/store.js +337 -6
  225. package/template/coding-task-manager/lib/usage-ledger/task-read.js +123 -5
  226. package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
  227. package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
  228. package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
  229. package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
  230. package/template/coding-task-manager/lib/ws/input.js +1 -0
  231. package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
  232. package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
  233. package/template/coding-task-manager/lib/ws-router.js +68 -1
  234. package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
  235. package/template/coding-task-manager/oauth-proxy.js +99 -55
  236. package/template/coding-task-manager/package-lock.json +24 -0
  237. package/template/coding-task-manager/package.json +3 -0
  238. package/template/coding-task-manager/protocol/message-table.json +0 -10
  239. package/template/coding-task-manager/protocol/messages.js +0 -10
  240. package/template/coding-task-manager/protocol/ws-schema.json +0 -20
  241. package/template/coding-task-manager/protocol/ws-schema.md +0 -2
  242. package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
  243. package/template/coding-task-manager/providers/codex-mcp.js +14 -5
  244. package/template/coding-task-manager/public/css/app.css +279 -2
  245. package/template/coding-task-manager/public/css/reviews.css +4 -0
  246. package/template/coding-task-manager/public/index.html +297 -240
  247. package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
  248. package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
  249. package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
  250. package/template/coding-task-manager/public/js/background-work.js +13 -7
  251. package/template/coding-task-manager/public/js/client-health-core.js +81 -0
  252. package/template/coding-task-manager/public/js/client-health-main.js +61 -0
  253. package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
  254. package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
  255. package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
  256. package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
  257. package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
  258. package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
  259. package/template/coding-task-manager/public/js/history-scroller.js +187 -9
  260. package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
  261. package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
  262. package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
  263. package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -4
  264. package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
  265. package/template/coding-task-manager/public/js/protocol.js +0 -10
  266. package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
  267. package/template/coding-task-manager/public/js/reviews.js +7 -3
  268. package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
  269. package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
  270. package/template/coding-task-manager/public/js/row-join.js +18 -3
  271. package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
  272. package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
  273. package/template/coding-task-manager/public/js/session-usage-view.js +1 -0
  274. package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
  275. package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
  276. package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
  277. package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
  278. package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
  279. package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
  280. package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
  281. package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
  282. package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
  283. package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
  284. package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
  285. package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -3
  286. package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
  287. package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
  288. package/template/coding-task-manager/public/js/walle-session.js +30 -7
  289. package/template/coding-task-manager/public/m/app.css +226 -8
  290. package/template/coding-task-manager/public/m/app.js +502 -9
  291. package/template/coding-task-manager/public/m/index.html +38 -1
  292. package/template/coding-task-manager/public/m/machines.js +1313 -0
  293. package/template/coding-task-manager/public/m/pool-failover.js +391 -0
  294. package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
  295. package/template/coding-task-manager/public/m/sw.js +5 -0
  296. package/template/coding-task-manager/queue-engine.js +13 -0
  297. package/template/coding-task-manager/server/approvals.js +5 -6
  298. package/template/coding-task-manager/server/boot.js +136 -17
  299. package/template/coding-task-manager/server.js +964 -425
  300. package/template/coding-task-manager/session-integrity.js +7 -9
  301. package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
  302. package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
  303. package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
  304. package/template/coding-task-manager/workers/session-host-process.js +14 -3
  305. package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
  306. package/template/coding-task-manager/workers/worktree-worker.js +34 -0
  307. package/template/package-lock.json +2 -2
  308. package/template/package.json +1 -1
  309. package/template/scripts/conversation-storage-v2-migration.js +78 -11
  310. package/template/shared/conversation-storage-v2-contract.js +42 -6
  311. package/template/shared/fixtures/worker-status-payloads.json +392 -0
  312. package/template/shared/git-remote-key.js +83 -0
  313. package/template/shared/host-identity.js +98 -2
  314. package/template/shared/owner-write-safety.js +135 -0
  315. package/template/shared/public-runtime.js +13 -5
  316. package/template/shared/release-schema.json +3 -2
  317. package/template/shared/report-citations.js +14 -0
  318. package/template/shared/sqlite-write-lock.js +361 -223
  319. package/template/shared/storage/contract.js +35 -3
  320. package/template/wall-e/agent.js +21 -0
  321. package/template/wall-e/api-walle.js +5 -0
  322. package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
  323. package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
  324. package/template/wall-e/brain/helper-rules-schema.js +129 -0
  325. package/template/wall-e/brain/migrations.js +51 -22
  326. package/template/wall-e/brain/model-deployment-facts.js +31 -1
  327. package/template/wall-e/brain/owner-call-whitelist.js +16 -0
  328. package/template/wall-e/brain/schema-ensures.js +22 -0
  329. package/template/wall-e/brain.js +1 -1
  330. package/template/wall-e/coding/host-capabilities.js +2 -2
  331. package/template/wall-e/coding/journal-dispatcher.js +51 -0
  332. package/template/wall-e/coding/session-journal.js +28 -40
  333. package/template/wall-e/coding-orchestrator.js +23 -26
  334. package/template/wall-e/fly.toml +1 -1
  335. package/template/wall-e/http/auth.js +18 -1
  336. package/template/wall-e/http/blog-views-api.js +318 -0
  337. package/template/wall-e/http/helper-rules-api.js +321 -0
  338. package/template/wall-e/http/model-proxy-providers.js +3 -1
  339. package/template/wall-e/http/telemetry-api.js +12 -0
  340. package/template/wall-e/lib/blog-view-policy.js +88 -0
  341. package/template/wall-e/lib/blog-view-store.js +169 -0
  342. package/template/wall-e/lib/client-config-lock.js +2 -1
  343. package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
  344. package/template/wall-e/lib/error-kinds.js +10 -1
  345. package/template/wall-e/lib/feature-manifest.js +1 -1
  346. package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
  347. package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
  348. package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
  349. package/template/wall-e/lib/helper-rules/grade.js +277 -0
  350. package/template/wall-e/lib/helper-rules/label.js +247 -0
  351. package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
  352. package/template/wall-e/lib/helper-rules/store.js +667 -0
  353. package/template/wall-e/lib/mcp-integration.js +5 -6
  354. package/template/wall-e/lib/runtime-worker-pool.js +1 -0
  355. package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
  356. package/template/wall-e/lib/telemetry-db-schema.js +37 -0
  357. package/template/wall-e/lib/telemetry-process-client.js +76 -1
  358. package/template/wall-e/llm/default-fallback.js +4 -0
  359. package/template/wall-e/llm/model-catalog.js +13 -4
  360. package/template/wall-e/llm/model-roles.js +6 -0
  361. package/template/wall-e/llm/portkey-http.js +150 -0
  362. package/template/wall-e/llm/portkey-sync.js +15 -145
  363. package/template/wall-e/llm/worker-mcp-routing.js +61 -0
  364. package/template/wall-e/llm/worker-route.js +43 -1
  365. package/template/wall-e/loops/brain-custom-writes.js +45 -0
  366. package/template/wall-e/mcp-protocol-contract.js +41 -1
  367. package/template/wall-e/mcp-server.js +13 -2
  368. package/template/wall-e/mcp-worker-schemas.js +20 -2
  369. package/template/wall-e/memory/ctm-context-client.js +25 -5
  370. package/template/wall-e/shared/release-schema.json +3 -2
  371. package/template/wall-e/shared/sqlite-write-lock.js +361 -223
  372. package/template/wall-e/shared/storage/contract.js +35 -3
  373. package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
  374. package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
  375. package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
  376. package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
  377. package/template/wall-e/tools/local-tools.js +12 -5
  378. package/template/wall-e/workers/brain-owner-worker.js +9 -0
  379. package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
  380. package/template/wall-e/workers/telemetry-worker.js +8 -0
  381. package/template/coding-task-manager/lib/giant-freeze-park.js +0 -31
@@ -10,7 +10,8 @@ const {
10
10
  createRootDeliveryRuntime, getRootDeliveryJobLifetime, isRootDeliveryJobLifetimeCurrent,
11
11
  } = require('./root-delivery-runtime');
12
12
  const { ROOT_PROMPT_ACTION } = require('./remote-command-purpose');
13
- const { selectRootDeliveryAttempt } = require('./root-delivery-selection');
13
+ const { selectRootDeliveryAttempt, selectRootDeliveryRecovery } = require('./root-delivery-selection');
14
+ const promptAdmissionTrace = require('./prompt-admission-trace');
14
15
 
15
16
  const TERMINAL_STATUSES = new Set([
16
17
  'sent', 'accepted_by_terminal', 'durable_user_message_seen', 'response_started', 'queued_by_agent',
@@ -18,6 +19,49 @@ const TERMINAL_STATUSES = new Set([
18
19
  const PREFLIGHT_RETRYABLE = new Set([
19
20
  'session_input_in_flight', 'session_resume_not_ready', 'command_deferred_until_idle',
20
21
  ]);
22
+ const PREFLIGHT_USER_ACTION = new Set(['session_not_live', 'session_waiting_for_approval']);
23
+ // WP-0 (queue-delivery-recovery): one wording per recovery action, so the persisted
24
+ // row, the broadcast frame and the direct reply cannot describe the same verdict
25
+ // differently. Both describe the preserved prompt and the action the user owns;
26
+ // neither claims the prompt was not sent while its effect is unknown.
27
+ const RESEND_MESSAGE = 'Your prompt is saved and was not sent. Choose Resend to try again.';
28
+ const REVIEW_MESSAGE = 'CTM could not safely confirm this desktop delivery. Review the submission before resending.';
29
+ const SAFE_DIAGNOSTIC_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$/u;
30
+
31
+ function safeDiagnosticId(value) {
32
+ return typeof value === 'string' && SAFE_DIAGNOSTIC_ID_RE.test(value) ? value : '';
33
+ }
34
+
35
+ // WP-0: what a cached (restart-surviving) parent row plus its scoped delivery
36
+ // receipts prove about the prompt, and the exact action the user owns. Delegates
37
+ // the proof rules to root-delivery-selection so read evidence and classification
38
+ // cannot drift; anything uncertified stays `unknown`/`review`.
39
+ function classifyReplayRecovery(snapshot) {
40
+ const verdict = selectRootDeliveryRecovery(snapshot);
41
+ if (verdict.deliveryState === 'sent') {
42
+ const recorded = String(snapshot?.parent?.status || '');
43
+ return Object.freeze({
44
+ recoveryAction: verdict.recoveryAction, deliveryState: verdict.deliveryState,
45
+ reason: '', // Canonical Root confirmation stores 'sent' for provider_transcript_match.
46
+ terminalStatus: recorded === 'sent' ? 'durable_user_message_seen' : recorded,
47
+ });
48
+ }
49
+ if (verdict.recoveryAction === 'resend') {
50
+ // The certified no-effect proof names the exact earlier blocker; keep that
51
+ // specific reason instead of flattening it to the generic refusal code.
52
+ const blocker = snapshot?.latest?.result?.result?.delivery_evidence?.blocker;
53
+ const specific = typeof blocker === 'string'
54
+ && (PREFLIGHT_RETRYABLE.has(blocker) || PREFLIGHT_USER_ACTION.has(blocker)) ? blocker : '';
55
+ return Object.freeze({
56
+ recoveryAction: verdict.recoveryAction, deliveryState: verdict.deliveryState,
57
+ reason: specific, terminalStatus: '',
58
+ });
59
+ }
60
+ return Object.freeze({
61
+ recoveryAction: verdict.recoveryAction, deliveryState: verdict.deliveryState,
62
+ reason: '', terminalStatus: '',
63
+ });
64
+ }
21
65
  const SAFE_DIAGNOSTIC_ERROR_KINDS = new Set(['ReferenceError', 'TypeError', 'RangeError', 'SqliteError', 'Error']);
22
66
  const SAFE_DIAGNOSTIC_SOURCE_FILES = new Set([
23
67
  'root-prompt-admission.js', 'remote-relay-store.js', 'server.js', 'main-db-census.js',
@@ -49,6 +93,7 @@ function safeResult(response, publicId, sessionId, fallbackSource = 'unknown') {
49
93
  reason: mapped.reason,
50
94
  source: mapped.source,
51
95
  retryable: mapped.retryable,
96
+ recoveryAction: mapped.recoveryAction,
52
97
  ...(mapped.message ? { message: mapped.message } : {}),
53
98
  ...(detail.duplicate === true || response?.duplicate === true ? { duplicate: true } : {}),
54
99
  ...(detail.retrying === true || response?.retrying === true ? { retrying: true } : {}),
@@ -68,6 +113,7 @@ function safeResult(response, publicId, sessionId, fallbackSource = 'unknown') {
68
113
  reason: mapped.reason,
69
114
  source: mapped.source,
70
115
  retryable: mapped.retryable,
116
+ recoveryAction: mapped.recoveryAction,
71
117
  ...(mapped.message ? { message: mapped.message } : {}),
72
118
  ...(Number.isInteger(httpStatus) && httpStatus >= 400 && httpStatus <= 599 ? { httpStatus } : {}),
73
119
  };
@@ -94,6 +140,11 @@ function createRootPromptFlow(deps = {}) {
94
140
  const observerLifetimes = new WeakMap();
95
141
  const sessionDrains = new WeakMap();
96
142
  const httpRequestScopes = new WeakMap();
143
+ // WP-0: the normalized session/client-message correlation for the operation
144
+ // currently running on a captured scope, so every diagnostic that scope emits
145
+ // (admission, driver, delivery stage, replay recovery) can be joined to the one
146
+ // user-visible submission. Both values are bounded ids, never receipt ids.
147
+ const scopeCorrelation = new WeakMap();
97
148
 
98
149
  function registryFor(db) {
99
150
  let registry = registries.get(db);
@@ -120,6 +171,9 @@ function createRootPromptFlow(deps = {}) {
120
171
  function reportFailure(scope, phase, code, details = {}) {
121
172
  if (!scope?.isCurrent()) return;
122
173
  const event = { category: 'root-prompt-flow', phase, code };
174
+ const correlation = scopeCorrelation.get(scope);
175
+ if (correlation?.sessionId) event.sessionId = correlation.sessionId;
176
+ if (correlation?.clientMessageId) event.clientMessageId = correlation.clientMessageId;
123
177
  for (const key of ['returnedRecordConfirmed', 'canonicalRecordConfirmed', 'recordFieldsMatch']) {
124
178
  if (typeof details[key] === 'boolean') event[key] = details[key];
125
179
  }
@@ -182,6 +236,11 @@ function createRootPromptFlow(deps = {}) {
182
236
  },
183
237
  isDeliveryCurrent: (_handle, metadata) => scope.isCurrent() === true && now() < metadata.expiresAt,
184
238
  now,
239
+ // WP-0 criterion 6: the driver reports the exact rejected handoff stage
240
+ // (delivery_snapshot / delivery_text / delivery_selection / delivery_dispatch /
241
+ // admission_metadata) with a static code. reportFailure bounds the event and
242
+ // swallows a throwing sink, so diagnostics can never change an outcome.
243
+ reportDiagnostic: (event) => reportFailure(scope, event?.phase, event?.code, {}),
185
244
  });
186
245
  }
187
246
 
@@ -230,14 +289,18 @@ function createRootPromptFlow(deps = {}) {
230
289
  {
231
290
  retire(registry, job);
232
291
  if (job.scope.isCurrent()) {
292
+ // WP-0 criterion 7: the certificate is gone without a completion proof,
293
+ // so the effect of this prompt is UNKNOWN. Say so, and keep the
294
+ // conservative review action rather than claiming nothing was sent.
295
+ const expired = code === 'root_delivery_expired';
233
296
  try {
234
297
  await storeStatus(job.sessionId, job.receiptId, 'needs_attention', {
235
- reason: code === 'root_delivery_expired'
236
- ? code : 'root_job_unresolved',
298
+ reason: expired ? code : 'root_job_unresolved',
237
299
  retryable: false,
238
- message: code === 'root_delivery_expired'
239
- ? 'The desktop delivery permission expired. Resend this prompt to try again.'
240
- : 'CTM could not safely confirm this desktop delivery. Review the submission and resend if needed.',
300
+ recoveryAction: 'review',
301
+ message: expired
302
+ ? 'The desktop delivery permission expired before CTM could confirm this delivery. Review the submission before resending.'
303
+ : REVIEW_MESSAGE,
241
304
  source: job.source,
242
305
  });
243
306
  } catch { reportFailure(job.scope, 'publish_unresolved', 'status_write_failed'); }
@@ -321,6 +384,11 @@ function createRootPromptFlow(deps = {}) {
321
384
  const scope = operationScope || commandRuntime.captureRootPromptCoordinator();
322
385
  if (!scope || !requestCurrent(scope, current)) return denial('remote_command_auth_unavailable');
323
386
  const publicId = agentSessionKernel.normalizeClientMessageId(options.clientMessageId);
387
+ // WP-0: correlate every diagnostic this operation emits with its normalized
388
+ // session/client-message identity (bounded ids only -- never a receipt id).
389
+ scopeCorrelation.set(scope, {
390
+ sessionId: safeDiagnosticId(sessionId), clientMessageId: safeDiagnosticId(publicId),
391
+ });
324
392
  const authState = { auth: null, namespace: null };
325
393
  const freshContext = transportKind === 'ws'
326
394
  ? (socket, namespace) => commandRuntime.freshRootPromptContext(socket, namespace)
@@ -351,7 +419,7 @@ function createRootPromptFlow(deps = {}) {
351
419
  const admission = makeAdmission({ scope, current, freshContext, authState, sessionId, text, options });
352
420
  let admitted;
353
421
  try {
354
- admitted = await admission.submit(client, sessionId, text, options);
422
+ admitted = await promptAdmissionTrace.time('admission', () => admission.submit(client, sessionId, text, options));
355
423
  } catch {
356
424
  admitted = { response: denial('remote_command_unresolved'), admission: null };
357
425
  }
@@ -383,6 +451,15 @@ function createRootPromptFlow(deps = {}) {
383
451
  driver, writeActive: true, autoPending: true, inFlight: false, lastResult: null,
384
452
  };
385
453
  registry.set(receiptId, job);
454
+ } else {
455
+ // WP-0 criterion 4: a committed admission whose delivery facade cannot be
456
+ // registered is a typed handoff failure, never a silent acceptance. The
457
+ // committed historical record is left exactly as it is.
458
+ reportFailure(scope, 'driver_registration', 'root_driver_registration_unavailable');
459
+ admitted = { ...admitted, response: { ...denial('root_driver_registration_unavailable', 503),
460
+ recoveryAction: 'resend',
461
+ message: 'CTM saved your prompt but could not start delivery. Resend to try again.',
462
+ } };
386
463
  }
387
464
  }
388
465
  if (job) {
@@ -392,37 +469,86 @@ function createRootPromptFlow(deps = {}) {
392
469
  void firstDrive.catch(() => reportFailure(scope, 'drive', 'unexpected_failure'));
393
470
  }
394
471
  } else if (admitted?.response?.ok === true) {
395
- // A cached parent is not a process-local write marker. Never adopt it after restart.
472
+ // A cached parent is not a process-local write marker. Never adopt it after
473
+ // restart, and never answer with its cached acceptance: a reply is truthful
474
+ // only when this process holds the job, or when a scoped read proves what
475
+ // actually happened to the prompt.
396
476
  let context = null;
477
+ let contextFailed = false;
397
478
  try { context = await freshContext(client, null); }
398
- catch { reportFailure(scope, 'drive', 'unexpected_failure'); }
399
- if (context?.ok && requestCurrent(scope, current)) {
400
- const receiptId = remoteCommandStore.remoteCommandReceiptId(context.namespace.namespaceHash, publicId);
401
- const resident = registry.get(receiptId);
402
- let requestedIntentHash = '';
479
+ catch { contextFailed = true; }
480
+ if (!contextFailed && (!context?.ok || !requestCurrent(scope, current))) contextFailed = true;
481
+ if (contextFailed) {
482
+ // WP-0 criterion 4: no current authority and no proof -- refuse, never
483
+ // fall through to the cached `received`/`accepted` response.
484
+ reportFailure(scope, 'replay_recovery', 'root_replay_context_unavailable');
485
+ return denial(context?.code || 'remote_command_auth_unavailable', context?.status || 503);
486
+ }
487
+ const receiptId = remoteCommandStore.remoteCommandReceiptId(context.namespace.namespaceHash, publicId);
488
+ const resident = registry.get(receiptId);
489
+ let requestedIntentHash = '';
490
+ try {
491
+ const intentHandle = rootPromptIntent.captureRootPromptIntent({
492
+ sessionId, text, source: options.source, attachments: options.attachments,
493
+ }, { maxPromptBytes });
494
+ requestedIntentHash = intentHandle.body.intent_hash;
495
+ } catch { requestedIntentHash = ''; reportFailure(scope, 'replay_recovery', 'root_replay_intent_unavailable'); }
496
+ const residentProof = resident && getCommittedRootAdmission(resident.admissionHandle);
497
+ if (resident?.writeActive && now() < resident.expiresAt && resident.scope.isCurrent()
498
+ && residentProof?.selector?.sessionId === sessionId
499
+ && residentProof.selector.namespaceHash === context.namespace.namespaceHash
500
+ && residentProof.selector.intentHash === requestedIntentHash) {
501
+ // A same-id manual retry with a live local job keeps the existing child
502
+ // selection semantics; no read evidence is consulted for it.
503
+ job = resident;
504
+ const retry = driveJob(registry, resident, false);
505
+ void retry.catch(() => reportFailure(scope, 'drive', 'unexpected_failure'));
506
+ } else {
507
+ // WP-0 criterion 3: the delivery permission is gone (restart, lost
508
+ // registry). Ask the scoped store what the prompt's own receipts prove --
509
+ // authenticated namespace + session + command id + a freshly captured
510
+ // intent hash -- and recheck the request scope after every await.
511
+ let snapshot = null;
512
+ let readFailed = false;
403
513
  try {
404
- const intentHandle = rootPromptIntent.captureRootPromptIntent({
405
- sessionId, text, source: options.source, attachments: options.attachments,
406
- }, { maxPromptBytes });
407
- requestedIntentHash = intentHandle.body.intent_hash;
408
- } catch { requestedIntentHash = ''; reportFailure(scope, 'drive', 'unexpected_failure'); }
409
- const residentProof = resident && getCommittedRootAdmission(resident.admissionHandle);
410
- if (resident?.writeActive && now() < resident.expiresAt && resident.scope.isCurrent()
411
- && residentProof?.selector?.sessionId === sessionId
412
- && residentProof.selector.namespaceHash === context.namespace.namespaceHash
413
- && residentProof.selector.intentHash === requestedIntentHash) {
414
- job = resident;
415
- const retry = driveJob(registry, resident, false);
416
- void retry.catch(() => reportFailure(scope, 'drive', 'unexpected_failure'));
514
+ snapshot = await runReadPoolOp('getLatestRootJobDeliveryReceipt', {
515
+ dbPath: scope.dbPath,
516
+ selector: {
517
+ namespaceHash: context.namespace.namespaceHash, commandId: publicId,
518
+ instanceId: scope.instanceId, sessionId, intentHash: requestedIntentHash,
519
+ },
520
+ }, { telemetryReason: 'root-prompt-replay-recovery' });
521
+ } catch { readFailed = true; }
522
+ if (!requestCurrent(scope, current)) return denial('remote_command_auth_unavailable');
523
+ if (readFailed) reportFailure(scope, 'replay_recovery', 'root_delivery_replay_unavailable');
524
+ const proof = classifyReplayRecovery(readFailed ? null : snapshot);
525
+ if (proof.deliveryState === 'sent') {
526
+ // Read evidence proves the prompt was already delivered: report the
527
+ // recorded sent signal as a duplicate. No new delivery, no new
528
+ // authority, and the preserved row is not downgraded.
529
+ admitted = { ...admitted, response: {
530
+ ok: true, status: proof.terminalStatus, duplicate: true,
531
+ source: options.source || 'web',
532
+ } };
417
533
  } else {
534
+ const action = proof.recoveryAction === 'resend' ? 'resend' : 'review';
535
+ const status = action === 'resend' ? 'needs_attention' : 'blocked';
536
+ const details = {
537
+ reason: proof.reason || 'root_job_unresolved', retryable: false,
538
+ recoveryAction: action,
539
+ message: action === 'resend' ? RESEND_MESSAGE : REVIEW_MESSAGE,
540
+ source: options.source || 'web',
541
+ };
542
+ reportFailure(scope, 'replay_recovery', 'root_job_unresolved');
418
543
  try {
419
- await storeStatus(sessionId, receiptId, 'needs_attention', {
420
- reason: 'root_job_unresolved', retryable: false,
421
- message: 'The original desktop delivery permission is unavailable. Resend this prompt to try again.',
422
- source: options.source || 'web',
423
- });
544
+ await storeStatus(sessionId, receiptId, status, details);
424
545
  } catch { reportFailure(scope, 'proof_loss_status', 'status_write_failed'); }
425
- admitted = { ...admitted, response: denial('root_job_unresolved', 409) };
546
+ if (!requestCurrent(scope, current)) return denial('remote_command_auth_unavailable');
547
+ admitted = { ...admitted, response: {
548
+ ok: false, status, code: 'root_job_unresolved', httpStatus: 409,
549
+ reason: details.reason, message: details.message, retryable: false,
550
+ recoveryAction: action, source: details.source,
551
+ } };
426
552
  }
427
553
  }
428
554
  }
@@ -445,6 +571,7 @@ function createRootPromptFlow(deps = {}) {
445
571
  type: 'submit-prompt-status', id: sessionId, clientMessageId: publicId,
446
572
  status: safe.status, signal: safe.signal, reason: safe.reason, source: safe.source,
447
573
  code: safe.code || '', retryable: safe.retryable === true,
574
+ recoveryAction: safe.recoveryAction || 'none',
448
575
  ...(safe.message ? { message: safe.message } : {}),
449
576
  };
450
577
  try { sendWsJson(client, frame); } catch { reportFailure(scope, 'status_reply', 'socket_write_failed'); }
@@ -456,8 +583,9 @@ function createRootPromptFlow(deps = {}) {
456
583
  function submitWs(ws, sessionId, text, options = {}) {
457
584
  const authReference = ws?.auth;
458
585
  const current = () => ws?.readyState === 1 && ws?.auth === authReference;
459
- return submit({ client: ws, sessionId, text, options, transportKind: 'ws',
460
- current, req: null, url: null });
586
+ return promptAdmissionTrace.run({ sessionId, source: options.source, transport: 'ws', receivedAt: options.wsReceivedAt },
587
+ () => submit({ client: ws, sessionId, text, options, transportKind: 'ws',
588
+ current, req: null, url: null }));
461
589
  }
462
590
 
463
591
  function submitHttp(req, url, sessionId, options = {}) {
@@ -470,8 +598,9 @@ function createRootPromptFlow(deps = {}) {
470
598
  || url?.pathname !== state.url.pathname || url?.search !== state.url.search) {
471
599
  return Promise.resolve(denial('invalid_request', 400));
472
600
  }
473
- return submit({ client: req, sessionId, text: options.text, options,
474
- transportKind: 'http', req, url: state.url, current: state.current, operationScope: state.scope });
601
+ return promptAdmissionTrace.run({ sessionId, source: options.source, transport: 'http' },
602
+ () => submit({ client: req, sessionId, text: options.text, options,
603
+ transportKind: 'http', req, url: state.url, current: state.current, operationScope: state.scope }));
475
604
  }
476
605
 
477
606
  function captureHttpScope(req, url, response) {
@@ -503,6 +632,7 @@ function createRootPromptFlow(deps = {}) {
503
632
  const scope = capturedScope || commandRuntime.captureRootPromptCoordinator();
504
633
  if (!scope || (databaseHandle && scope.databaseHandle !== databaseHandle)
505
634
  || (instanceId && scope.instanceId !== instanceId) || !scope.isCurrent()) return 0;
635
+ scopeCorrelation.set(scope, { sessionId: safeDiagnosticId(sessionId) });
506
636
  let rows;
507
637
  try { rows = remoteRelayStore.listRemoteSubmissions(scope.databaseHandle, { sessionId, limit: 200 }); }
508
638
  catch { return 0; }
@@ -524,7 +654,12 @@ function createRootPromptFlow(deps = {}) {
524
654
  if (!scope.isCurrent()) break;
525
655
  const details = {
526
656
  reason: 'root_job_unresolved', retryable: false,
527
- message: 'The original desktop delivery permission is unavailable. Resend this prompt to try again.',
657
+ // WP-0 criterion 7: a missing process-local marker is not proof that the
658
+ // prompt was never sent (a restart can lose the marker after delivery).
659
+ // Only a scoped no-effect certificate would justify "resend"; none is
660
+ // reachable from a bare durable row, so the action is review.
661
+ recoveryAction: 'review',
662
+ message: REVIEW_MESSAGE,
528
663
  source: row.result?.source || 'web',
529
664
  };
530
665
  try {
@@ -548,6 +683,7 @@ function createRootPromptFlow(deps = {}) {
548
683
  if (!id) return { driven: 0, escalated: 0 };
549
684
  const scope = commandRuntime.captureRootPromptCoordinator();
550
685
  if (!scope || !scope.isCurrent()) return { driven: 0, escalated: 0 };
686
+ scopeCorrelation.set(scope, { sessionId: safeDiagnosticId(id) });
551
687
  const registry = registryFor(scope.databaseHandle);
552
688
  const inFlight = sessionDrains.get(scope.databaseHandle) || new Set();
553
689
  if (!sessionDrains.has(scope.databaseHandle)) sessionDrains.set(scope.databaseHandle, inFlight);
@@ -566,7 +702,8 @@ function createRootPromptFlow(deps = {}) {
566
702
  try {
567
703
  await storeStatus(job.sessionId, job.receiptId, 'needs_attention', {
568
704
  reason: 'root_delivery_expired', retryable: false,
569
- message: 'The desktop delivery permission expired. Resend this prompt to try again.',
705
+ recoveryAction: 'review',
706
+ message: 'The desktop delivery permission expired before CTM could confirm this delivery. Review the submission before resending.',
570
707
  });
571
708
  } catch { reportFailure(job.scope, 'expiry_status', 'status_write_failed'); }
572
709
  continue;
@@ -103,6 +103,8 @@ function createScrollbackArchive(options = {}) {
103
103
  const flushMs = options.flushMs !== undefined && Number.isFinite(Number(options.flushMs))
104
104
  ? Number(options.flushMs)
105
105
  : ARCHIVE_FLUSH_MS;
106
+ // Test seam, like `now`: a test drives ticks itself instead of waiting on the wall clock.
107
+ const scheduleInterval = typeof options.setInterval === 'function' ? options.setInterval : setInterval;
106
108
  const pendingMaxRows = Math.max(1, Number(options.pendingMaxRows) || ARCHIVE_PENDING_MAX_ROWS);
107
109
  const pendingMaxBytes = Math.max(1, Number(options.pendingMaxBytes) || ARCHIVE_PENDING_MAX_BYTES);
108
110
  const blockBytes = Math.max(1, Number(options.blockBytes) || DEFAULT_BLOCK_BYTES);
@@ -525,12 +527,12 @@ function createScrollbackArchive(options = {}) {
525
527
 
526
528
  function _scheduleTimer() {
527
529
  if (timer || flushMs <= 0) return;
528
- timer = setInterval(() => {
530
+ const tick = () => {
529
531
  // A slow async tick skips re-entry; the next tick resumes round-robin order.
530
- if (tickInFlight) return;
532
+ if (tickInFlight) return null;
531
533
  tickInFlight = true;
532
534
  const ids = Array.from(sessions.keys());
533
- (async () => {
535
+ return (async () => {
534
536
  // 1) Write buffered appends for every session -- cheap, one appendFile
535
537
  // per session's active bucket, no gzip involved.
536
538
  for (const id of ids) {
@@ -561,7 +563,8 @@ function createScrollbackArchive(options = {}) {
561
563
  })()
562
564
  .catch(() => { /* expected: the background timer tick itself must never throw -- every step inside already catches its own failures; this is the final backstop */ })
563
565
  .finally(() => { tickInFlight = false; });
564
- }, flushMs);
566
+ };
567
+ timer = scheduleInterval(tick, flushMs);
565
568
  if (typeof timer.unref === 'function') timer.unref();
566
569
  }
567
570
 
@@ -46,6 +46,13 @@ function startServerMemorySamplerRuntime(options = {}) {
46
46
  // WP-0b (§5 D-2): () => [{ owner, memory }] over the read-pool / db-owner worker clients.
47
47
  // Forwarded verbatim; absent -> the sampler's own () => [] default keeps workers[] empty.
48
48
  workersSource,
49
+ // WP-A P-2 (freeze-probes): () => the work in flight at sample time (read-pool ops, db-owner
50
+ // pending ops, recent main-loop spans). Forwarded verbatim; absent -> the sampler's () => null
51
+ // default keeps the row's `inFlight` null.
52
+ inFlightSource,
53
+ // WP-A P-3 (freeze-probes): { sampleFootprintRegions(pid) } for the main pid -- the categorized
54
+ // `/usr/bin/footprint` read. Forwarded verbatim; absent -> main.regions stays null.
55
+ regionSampler,
49
56
  samplerOptions,
50
57
  } = options;
51
58
  // WP-4 (design doc §5 D-5, §8 WP-4): reuse the SAME 'mirrors-report' IPC round trip
@@ -62,6 +69,9 @@ function startServerMemorySamplerRuntime(options = {}) {
62
69
  mirrorsSampler,
63
70
  // Explicit workersSource wins; otherwise a workersSource carried in samplerOptions (test seam).
64
71
  workersSource: typeof workersSource === 'function' ? workersSource : samplerOptions?.workersSource,
72
+ // WP-A P-2/P-3: forwarded the same way, so server.js's one call site wires all three probes.
73
+ inFlightSource: typeof inFlightSource === 'function' ? inFlightSource : samplerOptions?.inFlightSource,
74
+ regionSampler: regionSampler || samplerOptions?.regionSampler || null,
65
75
  listProcesses: () => serverProcessList({ sessionHostManager, desktopIndex, errorSink }),
66
76
  buildLedgerInput: () => ({
67
77
  processMemory: process.memoryUsage(),
@@ -135,6 +135,15 @@ function createServerMemorySampler(options = {}) {
135
135
  // liveDecoders } }] in raw bytes -- read from the read-pool/db-owner worker clients. Omitted ->
136
136
  // workers[] is empty and workersTotal sums are 0 (never fabricated from nothing).
137
137
  workersSource = () => [],
138
+ // WP-A P-2 (freeze-probes): () => any JSON-safe value describing the work in flight when the row
139
+ // was taken (read-pool ops, db-owner pending ops, recent main-loop spans). Stored verbatim on the
140
+ // row as `inFlight`; a throw or an absent source yields null ("unknown"), never a lost row.
141
+ inFlightSource = () => null,
142
+ // WP-A P-3 (freeze-probes): optional { sampleFootprintRegions(pid): Promise<{ totalMB, top }|null> }
143
+ // -- the CATEGORIZED `/usr/bin/footprint` read (lib/session-resource-sampler.js), a fresh spawn per
144
+ // call rather than the TTL-cached sampleFootprints() summary, so the region that just grew is
145
+ // named. Omitted -> main.regions stays null, never fabricated.
146
+ regionSampler = null,
138
147
  now = () => Date.now(),
139
148
  // Injectable so a test isn't forced to monkey-patch the process-global console (which
140
149
  // would race other concurrently-running tests in the same file).
@@ -199,6 +208,17 @@ function createServerMemorySampler(options = {}) {
199
208
  };
200
209
  }
201
210
 
211
+ // WP-A P-2: the in-flight snapshot for this row. A broken/absent source reports null rather than
212
+ // failing the tick (same disposition as readWorkerMemory above).
213
+ function readInFlight() {
214
+ try {
215
+ return (typeof inFlightSource === 'function' ? inFlightSource() : null) ?? null;
216
+ } catch {
217
+ /* expected: the read-pool/db-owner clients can be mid-restart; "unknown in flight" beats a lost row */
218
+ return null;
219
+ }
220
+ }
221
+
202
222
  async function sampleProcessesRss(pids) {
203
223
  if (!pids.length) return new Map();
204
224
  const psCommand = platform === 'darwin' ? '/bin/ps' : 'ps';
@@ -261,6 +281,18 @@ function createServerMemorySampler(options = {}) {
261
281
  const mu = process.memoryUsage();
262
282
  const mainProc = procs.find((p) => p.role === 'main') || null;
263
283
  const poolProc = procs.find((p) => p.role === 'session-host-pool') || null;
284
+ // WP-A P-3: the MAIN process' categorized footprint regions -- the only read that can NAME the
285
+ // category behind a step (the 4<->9 GB swing is entirely "Malloc Large"). `null` (never
286
+ // fabricated) when unwired, when the main pid is unknown, or when the read failed.
287
+ let regions = null;
288
+ if (regionSampler && typeof regionSampler.sampleFootprintRegions === 'function' && mainProc && mainProc.pid) {
289
+ try {
290
+ regions = (await regionSampler.sampleFootprintRegions(mainProc.pid)) ?? null;
291
+ } catch {
292
+ /* expected: /usr/bin/footprint can be missing, denied or killed; the row must still record */
293
+ regions = null;
294
+ }
295
+ }
264
296
  const main = {
265
297
  heapUsedMB: roundMB(mu.heapUsed),
266
298
  externalMB: roundMB(mu.external),
@@ -273,6 +305,8 @@ function createServerMemorySampler(options = {}) {
273
305
  footprintMB: mainProc ? mainProc.physFootprintMB : null,
274
306
  // WP-0b (§5 D-2): main-thread's OWN live zstd contexts (workers report theirs separately).
275
307
  liveDecoders: liveDecoderCount(),
308
+ // WP-A P-3: categorized footprint regions of this same pid (null when unwired/unsampled).
309
+ regions,
276
310
  };
277
311
  // WP-0b (§5 D-2, §9 S-9): per-worker heap/external/arrayBuffers + live decoder count, summed
278
312
  // into workersTotal so the row explains what the main isolate's process.memoryUsage() cannot.
@@ -338,7 +372,10 @@ function createServerMemorySampler(options = {}) {
338
372
  }
339
373
  const ledger = compactLedgerSubset(fullLedger);
340
374
 
341
- const sample = { schemaVersion: SCHEMA_VERSION, reason, procs, main, poolHost, ledger, workers, workersTotal };
375
+ // WP-A P-2: the work in flight at sample time, so a step in rss/footprint can be read against
376
+ // what was running when it happened (`null` = unknown/not wired).
377
+ const inFlight = readInFlight();
378
+ const sample = { schemaVersion: SCHEMA_VERSION, reason, procs, main, poolHost, ledger, workers, workersTotal, inFlight };
342
379
  if (typeof record === 'function') {
343
380
  try { record('server-memory', sample); } catch { /* expected: a broken diagnostic sink must not break the sampler loop itself */ }
344
381
  }
@@ -363,13 +400,15 @@ function createServerMemorySampler(options = {}) {
363
400
  // WP-0b (§5 D-2, §9 S-9): run an extra sample whenever main RSS stepped >= minStepMB since the
364
401
  // last recorded row. Never throws; returns the sample or null when skipped (no prior sample,
365
402
  // caller rss unavailable, below threshold, an unrepresentable prior rss, or a sample in flight).
403
+ // WP-A P-3: the default threshold is 768 MB, not 2048 -- the live 2026-10-21 measurement showed the
404
+ // server's real steps are ~970 MB of "Malloc Large", which the old 2048 default silently skipped.
366
405
  async function sampleIfStep(options = {}) {
367
406
  try {
368
407
  const opts = options && typeof options === 'object' ? options : {};
369
408
  const target = Number(opts.rssMB);
370
409
  if (!Number.isFinite(target)) return null;
371
410
  if (!_lastMain || !Number.isFinite(Number(_lastMain.rssMB))) return null;
372
- const threshold = Number.isFinite(Number(opts.minStepMB)) ? Number(opts.minStepMB) : 2048;
411
+ const threshold = Number.isFinite(Number(opts.minStepMB)) ? Number(opts.minStepMB) : 768;
373
412
  if (Math.abs(target - Number(_lastMain.rssMB)) < threshold) return null;
374
413
  return await sampleOnce({ reason: 'rss-step', rssMB: target });
375
414
  } catch {
@@ -322,6 +322,8 @@ function loadCodingJournalOutcomes(sessionIds, options = {}) {
322
322
  archived_at, consolidated_at, extraction_status
323
323
  FROM memories INDEXED BY idx_memories_session_summary
324
324
  WHERE archived_at IS NULL
325
+ AND source IN ('walle-coding', 'walle-diary')
326
+ AND memory_type IN ('coding_journal', 'coding_journal_segment', 'agent_diary')
325
327
  AND source = 'walle-coding'
326
328
  AND memory_type = 'coding_journal'
327
329
  AND subject IN (${placeholders})