create-walle 0.10.1 → 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 (341) hide show
  1. package/README.md +4 -0
  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 +6 -4
  6. package/package.json +1 -1
  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/claude-hook.js +7 -3
  11. package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
  12. package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
  13. package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
  14. package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
  15. package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
  16. package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
  17. package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
  18. package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
  19. package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
  20. package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
  21. package/template/coding-task-manager/db.js +705 -286
  22. package/template/coding-task-manager/git-utils.js +44 -0
  23. package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
  24. package/template/coding-task-manager/lib/agent-presets.js +15 -0
  25. package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
  26. package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
  27. package/template/coding-task-manager/lib/api/host-stats.js +98 -0
  28. package/template/coding-task-manager/lib/api/ingress.js +35 -12
  29. package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
  30. package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
  31. package/template/coding-task-manager/lib/api/machines.js +461 -0
  32. package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
  33. package/template/coding-task-manager/lib/api/providers.js +53 -6
  34. package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
  35. package/template/coding-task-manager/lib/api/sessions.js +160 -8
  36. package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
  37. package/template/coding-task-manager/lib/api/worktrees.js +38 -37
  38. package/template/coding-task-manager/lib/approval-drift.js +16 -1
  39. package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
  40. package/template/coding-task-manager/lib/approval-scope.js +68 -4
  41. package/template/coding-task-manager/lib/auth-context.js +32 -2
  42. package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
  43. package/template/coding-task-manager/lib/auth-rules.js +186 -45
  44. package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
  45. package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
  46. package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
  47. package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
  48. package/template/coding-task-manager/lib/claude-session-title.js +6 -30
  49. package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
  50. package/template/coding-task-manager/lib/client-diag-handler.js +5 -0
  51. package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
  52. package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
  53. package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
  54. package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
  55. package/template/coding-task-manager/lib/codex-paths.js +2 -1
  56. package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
  57. package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
  58. package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
  59. package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
  60. package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
  61. package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
  62. package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
  63. package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
  64. package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
  65. package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
  66. package/template/coding-task-manager/lib/db-domains.js +21 -2
  67. package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
  68. package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
  69. package/template/coding-task-manager/lib/feature-manifest.js +1 -1
  70. package/template/coding-task-manager/lib/fs-watcher.js +3 -2
  71. package/template/coding-task-manager/lib/harness-history-transition.js +3 -3
  72. package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
  73. package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
  74. package/template/coding-task-manager/lib/headless-term-service.js +55 -17
  75. package/template/coding-task-manager/lib/host-control-dial.js +167 -0
  76. package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
  77. package/template/coding-task-manager/lib/host-handoff.js +51 -13
  78. package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
  79. package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
  80. package/template/coding-task-manager/lib/host-stats.js +328 -0
  81. package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
  82. package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
  83. package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
  84. package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
  85. package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
  86. package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
  87. package/template/coding-task-manager/lib/instance-manifest.js +13 -1
  88. package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
  89. package/template/coding-task-manager/lib/launch-model-override.js +160 -1
  90. package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
  91. package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
  92. package/template/coding-task-manager/lib/lead-model-switch.js +3 -2
  93. package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
  94. package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
  95. package/template/coding-task-manager/lib/login-tripwire.js +1 -0
  96. package/template/coding-task-manager/lib/machine-pairing.js +238 -0
  97. package/template/coding-task-manager/lib/machine-pool.js +409 -0
  98. package/template/coding-task-manager/lib/machine-registry.js +749 -0
  99. package/template/coding-task-manager/lib/machine-self.js +66 -0
  100. package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +52 -4
  101. package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
  102. package/template/coding-task-manager/lib/media-journal.js +84 -27
  103. package/template/coding-task-manager/lib/media-store-options.js +43 -15
  104. package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
  105. package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
  106. package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
  107. package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
  108. package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
  109. package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
  110. package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
  111. package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
  112. package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
  113. package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
  114. package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
  115. package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
  116. package/template/coding-task-manager/lib/native-history-control.js +2 -2
  117. package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
  118. package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
  119. package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
  120. package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
  121. package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
  122. package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
  123. package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
  124. package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
  125. package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
  126. package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
  127. package/template/coding-task-manager/lib/read-pool-client.js +5 -2
  128. package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
  129. package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
  130. package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
  131. package/template/coding-task-manager/lib/remote-command-context.js +12 -0
  132. package/template/coding-task-manager/lib/remote-command-runtime.js +13 -1
  133. package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
  134. package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
  135. package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
  136. package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
  137. package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
  138. package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
  139. package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
  140. package/template/coding-task-manager/lib/restart-preflight.js +9 -2
  141. package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
  142. package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
  143. package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
  144. package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
  145. package/template/coding-task-manager/lib/resume-cwd.js +13 -0
  146. package/template/coding-task-manager/lib/resume-from-store.js +12 -1
  147. package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
  148. package/template/coding-task-manager/lib/resume-preflight.js +21 -16
  149. package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
  150. package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
  151. package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
  152. package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
  153. package/template/coding-task-manager/lib/root-prompt-admission.js +33 -2
  154. package/template/coding-task-manager/lib/root-prompt-flow.js +167 -33
  155. package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
  156. package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
  157. package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
  158. package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
  159. package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
  160. package/template/coding-task-manager/lib/session-create/identity.js +20 -1
  161. package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
  162. package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
  163. package/template/coding-task-manager/lib/session-create/provider-process.js +34 -37
  164. package/template/coding-task-manager/lib/session-create/response.js +30 -12
  165. package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
  166. package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
  167. package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
  168. package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
  169. package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
  170. package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
  171. package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
  172. package/template/coding-task-manager/lib/session-host-manager.js +152 -206
  173. package/template/coding-task-manager/lib/session-jobs.js +17 -9
  174. package/template/coding-task-manager/lib/session-lifecycle.js +18 -0
  175. package/template/coding-task-manager/lib/session-model-action-preconditions.js +9 -0
  176. package/template/coding-task-manager/lib/session-resource-sampler.js +19 -9
  177. package/template/coding-task-manager/lib/session-standup.js +67 -4
  178. package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
  179. package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
  180. package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
  181. package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
  182. package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
  183. package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
  184. package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
  185. package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
  186. package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
  187. package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
  188. package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
  189. package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
  190. package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
  191. package/template/coding-task-manager/lib/transcript-link.js +77 -0
  192. package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
  193. package/template/coding-task-manager/lib/transcript-source.js +8 -3
  194. package/template/coding-task-manager/lib/transcript-store.js +40 -0
  195. package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
  196. package/template/coding-task-manager/lib/typing-interaction-trace.js +92 -0
  197. package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
  198. package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
  199. package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
  200. package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
  201. package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
  202. package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
  203. package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
  204. package/template/coding-task-manager/lib/ws-router.js +68 -1
  205. package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
  206. package/template/coding-task-manager/oauth-proxy.js +99 -55
  207. package/template/coding-task-manager/package-lock.json +24 -0
  208. package/template/coding-task-manager/package.json +3 -0
  209. package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
  210. package/template/coding-task-manager/providers/codex-mcp.js +14 -5
  211. package/template/coding-task-manager/public/css/app.css +279 -1
  212. package/template/coding-task-manager/public/css/reviews.css +4 -0
  213. package/template/coding-task-manager/public/index.html +294 -223
  214. package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
  215. package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
  216. package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
  217. package/template/coding-task-manager/public/js/background-work.js +13 -7
  218. package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
  219. package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
  220. package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
  221. package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
  222. package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
  223. package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
  224. package/template/coding-task-manager/public/js/history-scroller.js +187 -9
  225. package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
  226. package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
  227. package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
  228. package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -8
  229. package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
  230. package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
  231. package/template/coding-task-manager/public/js/reviews.js +7 -3
  232. package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
  233. package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
  234. package/template/coding-task-manager/public/js/row-join.js +4 -2
  235. package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
  236. package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
  237. package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
  238. package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
  239. package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
  240. package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
  241. package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
  242. package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
  243. package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
  244. package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
  245. package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
  246. package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
  247. package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
  248. package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -1
  249. package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
  250. package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
  251. package/template/coding-task-manager/public/js/walle-session.js +30 -7
  252. package/template/coding-task-manager/public/m/app.css +226 -8
  253. package/template/coding-task-manager/public/m/app.js +502 -9
  254. package/template/coding-task-manager/public/m/index.html +38 -1
  255. package/template/coding-task-manager/public/m/machines.js +1313 -0
  256. package/template/coding-task-manager/public/m/pool-failover.js +391 -0
  257. package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
  258. package/template/coding-task-manager/public/m/sw.js +5 -0
  259. package/template/coding-task-manager/queue-engine.js +13 -0
  260. package/template/coding-task-manager/server/approvals.js +5 -6
  261. package/template/coding-task-manager/server/boot.js +136 -17
  262. package/template/coding-task-manager/server.js +902 -239
  263. package/template/coding-task-manager/session-integrity.js +7 -9
  264. package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
  265. package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
  266. package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
  267. package/template/coding-task-manager/workers/session-host-process.js +14 -3
  268. package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
  269. package/template/coding-task-manager/workers/worktree-worker.js +34 -0
  270. package/template/package-lock.json +2 -2
  271. package/template/package.json +1 -1
  272. package/template/scripts/conversation-storage-v2-migration.js +78 -11
  273. package/template/shared/conversation-storage-v2-contract.js +42 -6
  274. package/template/shared/fixtures/worker-status-payloads.json +392 -0
  275. package/template/shared/git-remote-key.js +83 -0
  276. package/template/shared/host-identity.js +98 -2
  277. package/template/shared/owner-write-safety.js +135 -0
  278. package/template/shared/public-runtime.js +13 -5
  279. package/template/shared/release-schema.json +3 -2
  280. package/template/shared/report-citations.js +14 -0
  281. package/template/shared/sqlite-write-lock.js +361 -223
  282. package/template/shared/storage/contract.js +35 -3
  283. package/template/wall-e/agent.js +21 -0
  284. package/template/wall-e/api-walle.js +5 -0
  285. package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
  286. package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
  287. package/template/wall-e/brain/helper-rules-schema.js +129 -0
  288. package/template/wall-e/brain/migrations.js +51 -22
  289. package/template/wall-e/brain/model-deployment-facts.js +31 -1
  290. package/template/wall-e/brain/owner-call-whitelist.js +16 -0
  291. package/template/wall-e/brain/schema-ensures.js +22 -0
  292. package/template/wall-e/brain.js +1 -1
  293. package/template/wall-e/coding/journal-dispatcher.js +51 -0
  294. package/template/wall-e/coding/session-journal.js +28 -40
  295. package/template/wall-e/coding-orchestrator.js +23 -26
  296. package/template/wall-e/http/auth.js +18 -1
  297. package/template/wall-e/http/blog-views-api.js +318 -0
  298. package/template/wall-e/http/helper-rules-api.js +321 -0
  299. package/template/wall-e/http/model-proxy-providers.js +3 -1
  300. package/template/wall-e/http/telemetry-api.js +12 -0
  301. package/template/wall-e/lib/blog-view-policy.js +88 -0
  302. package/template/wall-e/lib/blog-view-store.js +169 -0
  303. package/template/wall-e/lib/client-config-lock.js +2 -1
  304. package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
  305. package/template/wall-e/lib/error-kinds.js +10 -1
  306. package/template/wall-e/lib/feature-manifest.js +1 -1
  307. package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
  308. package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
  309. package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
  310. package/template/wall-e/lib/helper-rules/grade.js +277 -0
  311. package/template/wall-e/lib/helper-rules/label.js +247 -0
  312. package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
  313. package/template/wall-e/lib/helper-rules/store.js +667 -0
  314. package/template/wall-e/lib/mcp-integration.js +5 -6
  315. package/template/wall-e/lib/runtime-worker-pool.js +1 -0
  316. package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
  317. package/template/wall-e/lib/telemetry-db-schema.js +37 -0
  318. package/template/wall-e/lib/telemetry-process-client.js +76 -1
  319. package/template/wall-e/llm/default-fallback.js +4 -0
  320. package/template/wall-e/llm/model-catalog.js +13 -4
  321. package/template/wall-e/llm/model-roles.js +6 -0
  322. package/template/wall-e/llm/portkey-http.js +150 -0
  323. package/template/wall-e/llm/portkey-sync.js +15 -145
  324. package/template/wall-e/llm/worker-mcp-routing.js +61 -0
  325. package/template/wall-e/llm/worker-route.js +43 -1
  326. package/template/wall-e/loops/brain-custom-writes.js +45 -0
  327. package/template/wall-e/mcp-protocol-contract.js +41 -1
  328. package/template/wall-e/mcp-server.js +13 -2
  329. package/template/wall-e/mcp-worker-schemas.js +20 -2
  330. package/template/wall-e/memory/ctm-context-client.js +25 -5
  331. package/template/wall-e/shared/release-schema.json +3 -2
  332. package/template/wall-e/shared/sqlite-write-lock.js +361 -223
  333. package/template/wall-e/shared/storage/contract.js +35 -3
  334. package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
  335. package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
  336. package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
  337. package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
  338. package/template/wall-e/tools/local-tools.js +6 -4
  339. package/template/wall-e/workers/brain-owner-worker.js +9 -0
  340. package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
  341. package/template/wall-e/workers/telemetry-worker.js +8 -0
@@ -26,6 +26,13 @@ const PROJECT_TRUST_ENV = 'CTM_CODEX_PROJECT_TRUST';
26
26
  const HTTP_TRANSPORT_ENV = 'CTM_CODEX_HTTP_TRANSPORT';
27
27
  const HTTP_TRANSPORT_PROVIDER_ID = 'ctm-openai-https';
28
28
 
29
+ // WP-2 (lead-cost-routing-round1-2026-10-21.html §5 D-6): a Codex LEAD calls Wall-E's MCP tools
30
+ // as direct function calls instead of invoking them from inside a code-mode `exec` script, so a
31
+ // long `walle_worker_wait` is a real client-side MCP call the client can hold. The key lives
32
+ // under `[features.code_mode]` (`features.code_mode.direct_only_tool_namespaces`, verified on
33
+ // codex-cli 0.162.1). Codex WORKERS never carry it -- they are denied walle_worker_wait anyway.
34
+ const CODEX_LEAD_DIRECT_TOOL_ARGS = Object.freeze(['-c', 'features.code_mode.direct_only_tool_namespaces=["mcp__wall_e"]']);
35
+
29
36
  function isCodexCommand(cmd) {
30
37
  return path.basename(String(cmd || '')).toLowerCase() === 'codex';
31
38
  }
@@ -527,6 +534,20 @@ function applyCodexHttpTransportOverride(args, options = {}) {
527
534
  };
528
535
  }
529
536
 
537
+ // WP-2 (D-6): the lead-only direct-tool namespace, its own prepareCodexLaunch step so it does not
538
+ // depend on the HTTP-transport flag (off by default). A LEAD is the launch that reaches
539
+ // prepareCodexLaunch with no model_provider override: every Codex worker already carries one
540
+ // (codexWorkerProviderArgs, resolve-launch-params.js), while a routed lead gets its override later
541
+ // in provider-process.js's argsTransform. Idempotent: a pair already present is never doubled.
542
+ function applyCodexLeadDirectToolArgs(args) {
543
+ const originalArgs = Array.isArray(args) ? args.slice() : [];
544
+ if (argsContainCodexModelProviderOverride(originalArgs)) return { args: originalArgs, added: false, skipped: 'worker_provider_override' };
545
+ if (originalArgs.some((value) => String(value).startsWith('features.code_mode.direct_only_tool_namespaces='))) {
546
+ return { args: originalArgs, added: false, skipped: 'already_configured' };
547
+ }
548
+ return { args: [...CODEX_LEAD_DIRECT_TOOL_ARGS, ...originalArgs], added: true };
549
+ }
550
+
530
551
  function argsContainProjectTrustOverride(args, projectPath) {
531
552
  const resolved = path.resolve(String(projectPath || '').trim());
532
553
  const quoted = JSON.stringify(resolved);
@@ -842,7 +863,10 @@ function prepareCodexLaunch(options = {}) {
842
863
  // in this branch.
843
864
  const _cfgStartedAt = Date.now();
844
865
  const projectTrustReport = applyProjectTrustOverride(args, options);
845
- const transportReport = applyCodexHttpTransportOverride(projectTrustReport.args, options);
866
+ // WP-2 (D-6): the lead step runs BEFORE the transport step -- the transport override is itself a
867
+ // model_provider block, and only a WORKER's override (present before the launch plan) means skip.
868
+ const leadDirectReport = applyCodexLeadDirectToolArgs(projectTrustReport.args);
869
+ const transportReport = applyCodexHttpTransportOverride(leadDirectReport.args, options);
846
870
  const missingEnvReport = applyMissingMcpEnvOverrides(transportReport.args, options);
847
871
  const learnedMcpReport = applyLearnedMcpFailureOverrides(missingEnvReport.args, options);
848
872
  const cfgMs = Date.now() - _cfgStartedAt;
@@ -856,7 +880,7 @@ function prepareCodexLaunch(options = {}) {
856
880
  learned: learnedMcpReport,
857
881
  };
858
882
  return {
859
- args: mcpReport.args, skillReport, mcpReport, projectTrustReport, transportReport,
883
+ args: mcpReport.args, skillReport, mcpReport, projectTrustReport, transportReport, leadDirectReport,
860
884
  timings: { skillWalkMs, cfgMs },
861
885
  };
862
886
  }
@@ -962,6 +986,8 @@ module.exports = {
962
986
  MCP_FAILURE_TTL_MS,
963
987
  QUARANTINE_TTL_STARTUP_MS,
964
988
  MCP_READINESS_PROBE_TIMEOUT_MS,
989
+ CODEX_LEAD_DIRECT_TOOL_ARGS,
990
+ applyCodexLeadDirectToolArgs,
965
991
  applyLearnedMcpFailureOverrides,
966
992
  applyMissingMcpEnvOverrides,
967
993
  applyCodexHttpTransportOverride,
@@ -980,6 +1006,7 @@ module.exports = {
980
1006
  argsContainCodexModelProviderOverride,
981
1007
  applyCodexHttpTransportOverride,
982
1008
  applyMissingMcpEnvOverrides,
1009
+ CODEX_LEAD_DIRECT_TOOL_ARGS,
983
1010
  applyProjectTrustOverride,
984
1011
  argsContainProjectTrustOverride,
985
1012
  codexHttpTransportConfigArgs,
@@ -97,15 +97,16 @@ async function prepareCodexLink(payload, db, assertLive = () => {}) {
97
97
  assertLive();
98
98
  const resumeId = thread?.id || payload.threadId;
99
99
  if (!resumeId) return { status, thread, known, resolved: null, modelTruth: null };
100
- // WP-1 (nightly-followups 2026-10-17): findCodexSessionFiles(..., { indexOnly: true }) answers only
101
- // from the in-memory rollout index or the Codex state-DB row, and this op path never built that
102
- // index -- so a missing/unreadable state_5.sqlite left a link IDENTITY-ONLY while the rollout file
103
- // sat right there (server persists jsonl_path='' and never attaches the stream). Build/refresh the
104
- // async index here first, exactly as lib/session-file-resolver.js does before its own indexOnly
105
- // lookups. No synchronous directory walk: that walk was removed on purpose (commit 84cf35c69).
106
- await history.ensureCodexRolloutIndex(payload.homeDir);
100
+ // The verified native state path already has precedence in findCodexSessionFiles. It does not
101
+ // depend on a global index refresh. Missing/mismatched native state still needs the async index
102
+ // recovery: an index-only miss must not leave a discoverable rollout linked as identity-only.
103
+ let rolloutPath = history.findCodexStateRolloutPath(resumeId, payload.homeDir);
104
+ if (!rolloutPath || !history.codexRolloutFileMatchesThread(rolloutPath, resumeId)) {
105
+ await history.ensureCodexRolloutIndex(payload.homeDir);
106
+ assertLive();
107
+ rolloutPath = history.findCodexSessionFiles(resumeId, null, payload.homeDir, { indexOnly: true })[0] || '';
108
+ }
107
109
  assertLive();
108
- const rolloutPath = history.findCodexSessionFiles(resumeId, null, payload.homeDir, { indexOnly: true })[0] || '';
109
110
  const observation = await observeCodexRollout(rolloutPath, db, assertLive);
110
111
  assertLive();
111
112
  const agentSessionId = history.codexRolloutIdFromPath(rolloutPath) || resumeId;
@@ -26,6 +26,7 @@ const fs = require('fs');
26
26
  const path = require('path');
27
27
  const os = require('os');
28
28
  const crypto = require('crypto');
29
+ const { isWritableOnlyByOwner } = require('../../shared/owner-write-safety');
29
30
 
30
31
  function homeBase(homeDir) {
31
32
  return homeDir || process.env.HOME || process.env.USERPROFILE || os.homedir() || '';
@@ -77,7 +78,7 @@ function resolveCodexSessionsRoot(options = {}) {
77
78
  out.refusalCode = 'wrong-owner';
78
79
  return out;
79
80
  }
80
- if ((Number(stat.mode) & 0o022) !== 0) {
81
+ if (!isWritableOnlyByOwner(stat)) {
81
82
  out.validationStatus = 'refused';
82
83
  out.refusalCode = 'unsafe-permissions';
83
84
  return out;
@@ -288,18 +288,6 @@ function isGenericCodingSessionLabel(label, agentType = 'codex') {
288
288
  || lower === 'session';
289
289
  }
290
290
 
291
- function shouldApplyCodexAutoTitle({ session, existingTitle } = {}) {
292
- if (existingTitle && existingTitle.userRenamed) return false;
293
- for (const candidate of [session?.label, existingTitle?.title]) {
294
- const text = normalizeTitleText(candidate);
295
- if (text && !/^Codex:\s*/i.test(text) && !isGenericCodingSessionLabel(text, 'codex')) return false;
296
- }
297
- const title = normalizeTitleText(existingTitle?.title || session?.label || '');
298
- if (!title) return true;
299
- if (/^Codex:\s*/i.test(title) && !isGenericCodingSessionLabel(title, 'codex')) return true;
300
- return isGenericCodingSessionLabel(title, 'codex');
301
- }
302
-
303
291
  function resolveModelToRegistry(modelName) {
304
292
  if (!modelName) return null;
305
293
  let provider = null;
@@ -561,11 +549,23 @@ function createCodingAgentModelSync({
561
549
  if (!modelStateRuntime) _persistSessionModel(session, model);
562
550
  changed = true;
563
551
  }
564
- if (agentType === 'codex' && !session._codexTitleSynced) {
552
+ if (agentType === 'codex') {
565
553
  const existingTitle = titlesById.get(session.id) || null;
566
- if (existingTitle && existingTitle.userRenamed) {
567
- session._codexTitleSynced = true;
568
- } else if (!shouldApplyCodexAutoTitle({ session, existingTitle })) {
554
+ // WP-4/D-10: the thread's OWN name (threads.name) is read on EVERY tick — there is no
555
+ // one-shot `_codexTitleSynced` latch any more, and no title-vs-label precedence test that
556
+ // could let a CTM title block the name (S-22). applyProviderTitle owns the tier rules: it
557
+ // re-asserts a drifted tier-1 (user-renamed) row outward, skips a row already carrying this
558
+ // exact name, and writes the agent name over an older tier-2/tier-3 title.
559
+ const agentName = session._claudeSessionId ? getCodexThreadAgentName(session._claudeSessionId) : '';
560
+ if (agentName) {
561
+ const outcome = applyProviderTitle({ db: dbModule, sessionId: session.id, provider: 'codex', agentName }); // not a dbModule method — no dispatchOwnerMutation
562
+ if (outcome.applied === 'agent') {
563
+ session.label = `Codex: ${agentName}`;
564
+ changed = true;
565
+ }
566
+ } else {
567
+ // No thread name at all: the CTM live label is the only signal left, so it repairs a
568
+ // stale auto-title. Never a tier-2 (`provider_title`) row, never the user's own name.
569
569
  const liveLabel = normalizeTitleText(session.label);
570
570
  if (liveLabel
571
571
  && !isGenericCodingSessionLabel(liveLabel, 'codex')
@@ -573,16 +573,6 @@ function createCodingAgentModelSync({
573
573
  dispatchOwnerMutation(dbModule, 'setSessionTitleNew', [session.id, liveLabel, false], 'coding-agent title');
574
574
  changed = true;
575
575
  }
576
- session._codexTitleSynced = true;
577
- } else {
578
- // Requires the exact Codex thread id — cwd/spawn-time matching is unsafe for periodic refresh.
579
- const agentName = session._claudeSessionId ? getCodexThreadAgentName(session._claudeSessionId) : '';
580
- if (agentName) {
581
- session.label = `Codex: ${agentName}`;
582
- session._codexTitleSynced = true;
583
- applyProviderTitle({ db: dbModule, sessionId: session.id, provider: 'codex', agentName }); // not a dbModule method — no dispatchOwnerMutation
584
- changed = true;
585
- }
586
576
  }
587
577
  }
588
578
  }
@@ -688,7 +678,7 @@ function createCodingAgentModelSync({
688
678
  if (agentType === 'gemini' && !modelStateRuntime) {
689
679
  context.result = { id: session.id, modelName: _modelArgValue(session.args) };
690
680
  } else {
691
- const item = { id: session.id, agentType, directory: session.cwd || (session.meta && session.meta.cwd) || '', knownSourceRevision: agentType === 'opencode' ? modelSyncState.knownSourceRevision(session.id) : '', claudeJsonlPath, codexThreadId: agentType === 'codex' ? (session._providerResumeId || session._claudeSessionId || '') : (session._claudeSessionId || session._providerResumeId || null), wantCodexTitle: agentType === 'codex' && session._codexTitleSynced !== true && !!(session._providerResumeId || session._claudeSessionId) };
681
+ const item = { id: session.id, agentType, directory: session.cwd || (session.meta && session.meta.cwd) || '', knownSourceRevision: agentType === 'opencode' ? modelSyncState.knownSourceRevision(session.id) : '', claudeJsonlPath, codexThreadId: agentType === 'codex' ? (session._providerResumeId || session._claudeSessionId || '') : (session._claudeSessionId || session._providerResumeId || null), wantCodexTitle: agentType === 'codex' && !!(session._providerResumeId || session._claudeSessionId) }; // WP-4/D-10: no one-shot latch gates the name read
692
682
  if (modelStateRuntime) {
693
683
  Object.assign(item, { owner: context.ownerSnapshot, providerSessionId: context.ownerSnapshot.providerSessionId, processGeneration: context.ownerSnapshot.processGeneration, providerEnv: modelProviderEnv(session), geminiTranscriptPath: session._geminiTranscriptPath || '' });
694
684
  // The pre-await half of the source binding, and the prior checkpoint this request may carry.
@@ -758,7 +748,7 @@ function createCodingAgentModelSync({
758
748
  && (session.model_id !== model.model_id || session.model_provider !== model.model_provider);
759
749
  if (agentType === 'claude' && model) claudeResolved += 1; if (modelChanged && session.model_id && String(session.model_source || '') === 'db:restore') repairedStamps += 1; // I-6: ONLY a stamp still carrying the pre-apply db:restore provenance is a repair; a mid-session /model switch on a live-sourced row is a normal change
760
750
  const truthChanged = _claudeTruthNeedsApply(session, truth);
761
- const needsTitleDecision = agentType === 'codex' && session._codexTitleSynced !== true;
751
+ const needsTitleDecision = agentType === 'codex'; // WP-4/D-10: a title decision is taken on every probe, never once
762
752
  // Codex: the effort of the rollout's latest turn_context (observed, never requested).
763
753
  const codexEffortChanged = agentType === 'codex' && result.modelEffort !== undefined
764
754
  && String(session.model_effort || '') !== String(result.modelEffort || '');
@@ -853,7 +843,9 @@ function createCodingAgentModelSync({
853
843
  changed = true;
854
844
  }
855
845
  }
856
- if (entry.titleSynced) session._codexTitleSynced = true;
846
+ // entry.titleSynced is the batch's "the title decision ran" receipt (the completion cache
847
+ // below and the durable applier's latch both consume it); the session no longer carries a
848
+ // one-shot `_codexTitleSynced` gate of its own.
857
849
  const complete = (!context.intent.modelId || entry.modelPersisted)
858
850
  && (agentType !== 'codex' || entry.titleSynced);
859
851
  if (complete) modelSyncState.cacheCompletedContext(context);
@@ -942,5 +934,4 @@ module.exports = {
942
934
  opencodeDataDbPath,
943
935
  isGenericCodingSessionLabel,
944
936
  resolveModelToRegistry,
945
- shouldApplyCodexAutoTitle,
946
937
  };
@@ -3,9 +3,28 @@
3
3
  // Pure decoders for native provider evidence. These functions deliberately do no discovery or I/O.
4
4
  const SYNTHETIC = '<synthetic>';
5
5
  const { CLAUDE_ALIASES } = require('./claude-model-selection-vocabulary');
6
+ const { WORKER_MODEL_ALIAS } = require('./model-proxy/lead-worker-picks');
6
7
  const ALIASES = new Set([...CLAUDE_ALIASES, 'default']);
7
8
  const GEMINI_ALIASES = new Set(['auto', 'default', 'pro', 'flash', 'flash-lite']);
8
9
 
10
+ /*
11
+ * The ONE reserved delegate alias (WORKER_MODEL_ALIAS in lib/model-proxy/lead-worker-picks.js). It names
12
+ * what a lead's SUBAGENTS ask the proxy for -- never a model a session's own CLI runs -- so it is
13
+ * refused by VALUE (trimmed, case-insensitive) before any producer can hand it to the ledger as a
14
+ * lead fact. Normal CLI aliases and policies keep their existing behavior.
15
+ *
16
+ * The value is normalised through the SAME one marker rule `modelClass` applies below:
17
+ * The reserved alias with `[1m]` is wearing the session's context marker, not a different
18
+ * model, so it can never be a lead fact either. Exactly one marker, and no blacklist of lookalikes
19
+ * (lookalikes, `claude-opus-5-5[1m]` and every real id keep their existing behavior).
20
+ */
21
+ function isReservedWorkerModel(value) {
22
+ if (typeof value !== 'string') return false;
23
+ const folded = value.trim().toLowerCase();
24
+ const base = folded.endsWith('[1m]') ? folded.slice(0, -4) : folded;
25
+ return base === WORKER_MODEL_ALIAS;
26
+ }
27
+
9
28
  function bounded(value, required = false) {
10
29
  if (typeof value !== 'string') return null;
11
30
  const valueTrimmed = value.trim();
@@ -46,6 +65,7 @@ function emit(out, args) { const item = observation(...args); if (item) out.push
46
65
  function modelClass(raw) {
47
66
  const name = bounded(raw, true);
48
67
  if (!name) return null;
68
+ if (isReservedWorkerModel(name)) return null;
49
69
  const suffix = name.toLowerCase().endsWith('[1m]') ? '[1m]' : '';
50
70
  const base = suffix ? name.slice(0, -4) : name;
51
71
  const folded = base.toLowerCase();
@@ -165,7 +185,9 @@ function codexSettingsCandidate(owner, rec, index, resumeId) {
165
185
  if (rec.type !== 'event_msg' || p.type !== 'thread_settings_applied' || !p.thread_id ||
166
186
  (p.thread_id !== owner.providerSessionId && p.thread_id !== resumeId) || !p.thread_settings) return null;
167
187
  const model = bounded(p.thread_settings.model, true);
168
- if (!model) return null;
188
+ // Codex carries the same reserved alias in its thread settings and turn contexts when a lead's
189
+ // subagents are routed through the proxy; neither can be the lead's own model (AC-0d).
190
+ if (!model || isReservedWorkerModel(model)) return null;
169
191
  const ordinal = Number.isSafeInteger(rec.ordinal) && rec.ordinal >= 0 ? String(rec.ordinal) : null;
170
192
  return { at: time(rec.timestamp), index, value: model, effort: p.thread_settings.reasoning_effort ?? null,
171
193
  sourceRevision: ordinal, source: 'codex:thread-settings' };
@@ -186,6 +208,7 @@ function codexTurnContextCandidate(owner, rec, index, resumeId) {
186
208
  if (!(rec.type === 'turn_context' || (rec.type === 'event_msg' && p.type === 'turn_context'))) return null;
187
209
  const model = bounded(p.model ?? p.model_id, true);
188
210
  const turnId = p.turn_id == null ? null : String(p.turn_id);
211
+ if (isReservedWorkerModel(model)) return null;
189
212
  return { at: time(rec.timestamp), index, payload: p, model, turnId };
190
213
  }
191
214
 
@@ -297,4 +320,6 @@ module.exports = { claudeModelObservations, claudeHookModelObservations, codexMo
297
320
  laterRank: later, isCodexRelatedRecord, codexThreadMatches,
298
321
  claudeIdentityCandidate, claudeTurnCandidate, claudeIdentityObservations, claudeTurnObservations,
299
322
  codexSettingsCandidate, codexSettingsObservations, codexTurnContextCandidate, codexTerminalCandidate,
300
- codexTurnObservations };
323
+ codexTurnObservations,
324
+ // WP-0: the one shared "is this the reserved delegate alias?" predicate (see the doc comment above).
325
+ isReservedWorkerModel };
@@ -1,11 +1,16 @@
1
1
  'use strict';
2
2
 
3
+ const { isReservedWorkerModel } = require('./coding-session-model-adapters');
4
+
3
5
  const PRIORITY = Object.freeze({ resolved: 3, lastCompletedTurn: 2, selection: 1 });
4
6
  const MODEL_RESULT_PAGE_SIZE = 8;
5
7
  const MAX_MODEL_RESULT_BYTES = 1024 * 1024;
6
8
 
7
9
  function concrete(fact, allowNullKind) {
8
10
  return !!fact && typeof fact.value === 'string' && fact.value.trim() !== '' && Buffer.byteLength(fact.value.trim(), 'utf8') <= 256 && !fact.value.includes('<synthetic>') && Number.isFinite(fact.observedAtMs) && fact.observedAtMs >= 0 &&
11
+ // WP-0 (AC-0c): a historical row may still HOLD the reserved alias (it is kept for audit), but it
12
+ // is never a compatibility model -- the real selection/turn wins by the existing precedence below.
13
+ !isReservedWorkerModel(fact.value) &&
9
14
  (fact.selectionKind === 'concrete' || (allowNullKind && fact.selectionKind === null));
10
15
  }
11
16
 
@@ -1470,7 +1470,7 @@ function createDurableModelResultApplier({ modelStateRuntime, isCurrent, isOwner
1470
1470
  context.capturedSignature = refreshSignature(context.session, context.agentType);
1471
1471
  if (context.agentType === 'opencode' && context.result.sourceRevision) context.nextSourceRevision = String(context.result.sourceRevision);
1472
1472
  cacheCompleted(context);
1473
- if (context.agentType === 'codex' && context.session._codexTitleSynced !== true) {
1473
+ if (context.agentType === 'codex') { // WP-4/D-10: the thread name is decided on every completed probe, never once
1474
1474
  context.needsTitleDecision = true;
1475
1475
  intents.push({ id: context.session.id, agentType: 'codex', generation, capturedSignature: context.capturedSignature,
1476
1476
  agentSessionId: context.ownerSnapshot.providerSessionId, liveLabel: normalizeTitle(context.session.label),
@@ -1488,7 +1488,6 @@ function createDurableModelResultApplier({ modelStateRuntime, isCurrent, isOwner
1488
1488
  const entry = byId.get(String(context.session.id));
1489
1489
  if (!entry || Number(entry.generation) !== generation || entry.capturedSignature !== context.capturedSignature) continue;
1490
1490
  if (entry.titleApplied && entry.title && entry.titleKind !== 'live') { const label = `Codex: ${entry.title}`; if (context.session.label !== label) { context.session.label = label; titleChanged = true; } }
1491
- if (entry.titleSynced) context.session._codexTitleSynced = true;
1492
1491
  if (entry.titleSynced) cacheCompleted(context);
1493
1492
  }
1494
1493
  if (titleChanged && typeof broadcastSessionList === 'function') broadcastSessionList();
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { isReservedWorkerModel } = require('./coding-session-model-adapters');
4
+
3
5
  const SOURCE_GROUPS = {
4
6
  claude: {
5
7
  selection: ['hook:PostModelSwitch', 'hook:SessionStart', 'transcript:identity', 'db:restore'],
@@ -54,6 +56,14 @@ function validateObservation(input) {
54
56
  if (fields.outcome !== 'completed' || fields.value === null || fields.selectionKind !== 'concrete') return null;
55
57
  }
56
58
  if (fields.kind === 'selection' && ['alias', 'policy'].includes(fields.selectionKind) && fields.value === null) return null;
59
+ /*
60
+ * WP-0 (AC-0b): the reserved delegate alias is refused by VALUE for every kind, whatever
61
+ * selectionKind a caller claims for it -- a lead session's own model can never be what its
62
+ * subagents ask the proxy for. `validFact`/`validPrior` deliberately stay permissive, so a row
63
+ * already persisted with the alias still loads (the projection skips the fact; history is never
64
+ * rewritten or dropped).
65
+ */
66
+ if (isReservedWorkerModel(fields.value)) return null;
57
67
  return { ...fields, processGeneration: input.processGeneration, observedAtMs: input.observedAtMs };
58
68
  }
59
69
 
@@ -127,7 +127,6 @@ function createCodingSessionModelSyncState({
127
127
  String(session?.model_source || ''),
128
128
  Number(session?.model_observed_at || 0),
129
129
  String(session?.label || ''),
130
- session?._codexTitleSynced === true,
131
130
  String(session?._claudeSessionId || session?.agentSessionId || ''),
132
131
  /*
133
132
  * Corrective finding 10: the PURE provider-source inputs a checkpoint's offsets are relative to.
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const path = require('path');
3
4
  const { ANCHOR_PREFIX, cursorAnchorGuard } = require('./source-checkpoint');
4
5
 
5
6
  // WP-1 (design D-3/D-4): the conversation cursor is an anchor guard and nothing else.
@@ -77,13 +78,22 @@ function commitConversationBatchAndTranscriptCursor(db, options) {
77
78
  OR transcript_files.status IS NOT 'ok'
78
79
  OR transcript_files.last_error IS NOT ''
79
80
  `);
81
+ // A row's `ctm_session_id` changing under this upsert used to be silent -- one committed import
82
+ // re-keys the file to a different owner (a re-import of the same rollout under another session)
83
+ // with nothing in the log to say so. Read the prior owner inside the transaction, before the write.
84
+ const readPriorOwner = db.prepare('SELECT ctm_session_id FROM transcript_files WHERE jsonl_path = ?');
80
85
  return db.transaction(() => {
86
+ const priorOwner = readPriorOwner.get(options.filePath);
81
87
  const committed = options.commitBatch(db, options.batch);
82
88
  // WP-1 (S-3b): the guard is stored as-is; the manifest receipt binding is deleted with
83
89
  // the whole-prefix proof it fenced.
84
90
  upsert.run(options.filePath, options.agentSessionId, options.ctmSessionId, options.provider,
85
91
  String(options.stat.dev ?? ''), String(options.stat.ino ?? ''), Number(options.stat.size || 0),
86
92
  Number(options.stat.mtimeMs || 0), options.offset, options.parserVersion, options.guard);
93
+ // One line, ids only (truncated). The basename, never the full path, and never any content.
94
+ const prior = priorOwner ? String(priorOwner.ctm_session_id || '') : '';
95
+ const next = String(options.ctmSessionId || '');
96
+ if (priorOwner && prior !== next) console.log(`[transcript-owner] cursor commit changed owner ${path.basename(String(options.filePath || ''))}: ${prior.slice(0, 8)} -> ${next.slice(0, 8)}`);
87
97
  return committed;
88
98
  })();
89
99
  }
@@ -456,7 +456,14 @@ function resolveCreateLaunchParams(ctx) {
456
456
  // alias because startup_tasks still stores that legacy column.
457
457
  const requestedTitle = String(msg.title || msg.label || '').replace(/^Resume:\s*/i, '').trim().slice(0, 120);
458
458
  const walleResumeRequest = msg.resumeWalle === true && !msg._isRestore;
459
- const hasExplicitClientTitle = !msg._isRestore && !walleResumeRequest && !!requestedTitle;
459
+ // D-1: every resume sender echoes the row's own DISPLAYED title back (`label`/`title`), and
460
+ // an echoed label is not user intent — so a resume never yields a tier-1 (user) name.
461
+ // D-13/WP-5: a CTM-composed label (`Shell:`, `Folder:`, `Code Review:`, a review session, a
462
+ // best-of attempt, the Claude Desktop fork) declares itself with `titleIntent:'default'`, so it is
463
+ // written at tier 3 like any other echo. An absent titleIntent keeps today's semantics (an old
464
+ // client causes no regression), and the New Session modal's typed label still lands tier 1.
465
+ const hasExplicitClientTitle = !msg._isRestore && !walleResumeRequest && !isResumeLaunch
466
+ && msg.titleIntent !== 'default' && !!requestedTitle;
460
467
  let title = requestedTitle;
461
468
  if (!title) {
462
469
  const agentName = cmd.includes('claude') ? 'Claude Code'
@@ -91,8 +91,9 @@ function ctmLifecycleJournalPath({ env = process.env, configDir = null, instance
91
91
  return path.join(resolveEffectiveDataDir({ env, configDir }), 'logs', fileName);
92
92
  }
93
93
 
94
- function appendCtmBootLine({ pid = process.pid, env = process.env, configDir = null, instanceTag = null, port = null } = {}) {
94
+ function appendCtmBootLine({ pid = process.pid, env = process.env, configDir = null, instanceTag = null, port = null, enteredAtServer = false } = {}) {
95
95
  _reportLaunchdProcessTypeOnBoot(env);
96
+ _reportBootEntryOnBoot(env, { enteredAtServer });
96
97
  return appendLifecycleLine(ctmLifecycleJournalPath({ env, configDir, instanceTag, port }), {
97
98
  ts: new Date().toISOString(),
98
99
  event: 'ctm-boot',
@@ -127,10 +128,25 @@ function _reportLaunchdProcessTypeOnBoot(env = process.env) {
127
128
  } catch { /* expected: a boot-time advisory must never block boot; the plist may be unreadable on a hardened install */ }
128
129
  }
129
130
 
131
+ // WP-2 (clock-free r6 OQ-6): report-only boot check for the OTHER install drift — a launchd-managed
132
+ // CTM whose plist still points at server.js directly, so bin/ctm-service-entry.js's conversation-storage
133
+ // boot gate never ran. Rather than diff the plist (a second source of truth, and one that can't tell a
134
+ // wrapper that execs the entry from a real bypass — D-2), the caller reports the RUNTIME fact
135
+ // `require.main === module`. Warns once per boot so the drift can't stay silent for a month; never blocks
136
+ // boot, never invokes launchctl, never reads or writes the plist. Only the real launchd-managed primary
137
+ // is checked — a /ctm-dev instance (CTM_MANAGED_BY_LAUNCHD unset/'0') or non-darwin host has no plist.
138
+ function _reportBootEntryOnBoot(env = process.env, { enteredAtServer = false, platform = process.platform, warn = console.warn } = {}) {
139
+ if (!enteredAtServer || env.CTM_MANAGED_BY_LAUNCHD !== '1' || platform !== 'darwin') return;
140
+ try {
141
+ warn('[launchd] CTM was started at server.js, so the conversation-storage boot gate did not run; re-run bin/install-service.sh or npx create-walle to enter through bin/ctm-service-entry.js');
142
+ } catch { /* expected: a boot-time advisory must never block boot */ }
143
+ }
144
+
130
145
  module.exports = {
131
146
  resolvePrimaryDataDir,
132
147
  resolveEffectiveDataDir,
133
148
  isPrimaryInstance,
134
149
  ctmLifecycleJournalPath,
135
150
  appendCtmBootLine,
151
+ _reportBootEntryOnBoot,
136
152
  };
@@ -93,6 +93,13 @@ const TABLE_DOMAINS = Object.freeze({
93
93
  // WP-3 (§6.4 S-12): where a shipped transcript landed on THIS instance. Same domain as
94
94
  // agent_sessions (the identity row it is written alongside) so one handle serves the consumer.
95
95
  sync_transcript_replicas: 'core',
96
+ // WP-0 (remote-machine-hub-sessions-2026-10-22.html §6.1): the hub machine registry.
97
+ machines: 'core',
98
+ // WP-1 (machine-pool-picker-pairing-dashboard-2026-10-24.html §6.1, D-4/D-6/D-11): the machine
99
+ // pool's own tables, same domain as `machines` — one 'core' handle serves the whole feature.
100
+ host_samples: 'core',
101
+ machine_self: 'core',
102
+ machine_pairing_offers: 'core',
96
103
  // Legacy pre-v1 predecessors of ctm_sessions/agent_sessions/session_index.
97
104
  // Superseded but their CREATE TABLE IF NOT EXISTS guards remain for
98
105
  // fresh-v0 / mid-migration databases. Same domain as their successors
@@ -193,6 +193,26 @@ const CTM_WRITE_OPS = Object.freeze([
193
193
  'deleteChain', 'deleteCtmSession', 'deleteFolder', 'deleteHook', 'deleteImage',
194
194
  'deletePermissionRule', 'deletePrompt', 'deleteReview', 'deleteReviewComment',
195
195
  'deleteSessionAnalysis', 'deleteStaleAnalyses', 'deleteTemplate',
196
+ // WP-2 (docs/remote-machine-hub-sessions-2026-10-22.html §6.1/§8, deferred from WP-0): the hub
197
+ // machine-registry writes. `machines` is domain 'core' (lib/db-domain-tables.js), and each op's
198
+ // OP_META row in shared/storage/contract.js carries the same tag — Gate 2c (CTM_WRITE_OPS →
199
+ // OP_META kind:'write' + domain) and Gate 2c-inventory (a domain-tagged write op outside this
200
+ // list) are exactly the two assertions that require the pair to land together.
201
+ 'upsertMachineRow', 'recordMachineProbe', 'deleteMachineRow',
202
+ // WP-1 (machine-pool-picker-pairing-dashboard-2026-10-24.html §6.1, D-11): the 60 s host-sample
203
+ // write, on the same `core` handle as the machines rows above; its OP_META row in
204
+ // shared/storage/contract.js carries the matching kind:'write' + domain + tables:['host_samples'].
205
+ 'recordHostSample',
206
+ // WP-2a (machine-pool-picker-pairing-dashboard-2026-10-24.html §6.1, D-4/P-5/P-6): the
207
+ // machine-owned settings write, the P-5 roster replacement (one transaction: upsert listed,
208
+ // delete unlisted, never self) and the leave() sweep. Each OP_META row in shared/storage/contract.js
209
+ // carries the matching kind:'write' + domain:'core'.
210
+ 'setMachineSelf', 'replaceRosterMachines', 'deleteAllMachineRows',
211
+ // WP-3 (machine-pool-picker-pairing-dashboard-2026-10-24.html §6.3, D-6/D-9): the pairing-offer
212
+ // writes — mint, single-use redeem, and the 5-wrong-redeem burn. `machine_pairing_offers` is
213
+ // classified 'core' in lib/db-domain-tables.js and each op's OP_META row in
214
+ // shared/storage/contract.js carries the matching kind:'write' + domain + tables.
215
+ 'insertPairingOffer', 'markPairingOfferRedeemed', 'burnLivePairingOffers',
196
216
  'deleteWorkspace', 'detachPromotedProviderChildSessions', 'duplicatePrompt',
197
217
  'enqueueSyncOutbox', 'flushSessionDiagnostics', 'flushSessionMetadataUpdates', 'heartbeatStartupTasks', 'incrementApprovalRuleMatch',
198
218
  'markStartupTaskExited', 'markStartupTaskUserPromptInput', 'markSyncOutboxDeliveredThrough', 'recordSyncOutboxServed',
@@ -205,7 +225,7 @@ const CTM_WRITE_OPS = Object.freeze([
205
225
  'supersedeHeldApprovalDecision', 'expireStaleHeldApprovalDecision', 'resolveApprovalDecision', 'claimWallePermissionResolution', 'commitWallePermissionResolution', 'expireOpenWallePermissions', 'restorePromptVersion', 'reviveStartupTask',
206
226
  'saveApprovalAiRefinementRule', 'saveApprovalRescuePattern', 'saveImage',
207
227
  'setAlwaysAsk', 'setPermRuleExceptions', 'setPromptParent',
208
- 'setScrollbackIdentity', 'setSessionStar', 'setSessionTitleMirror', 'setSessionTitleStatusNew',
228
+ 'setScrollbackIdentity', 'setSessionStar', 'setSessionTitleMirror', 'setSessionTitleStatusNew', 'applyAgentTitleBackfillRows',
209
229
  'setSetting', 'startAnalysisRun', 'toggleApprovalRule', 'toggleAutoApproval',
210
230
  'toggleHook', 'trackPromptUsage', 'transferSessionOwnership', 'updateChain',
211
231
  'updateCodingSessionModel', 'updateFolder', 'updateHarvestState',
@@ -256,7 +276,6 @@ const CTM_WRITE_OPS = Object.freeze([
256
276
  'recordSyncPeerConflict', 'updateStartupTaskTitle', 'updateStartupTaskClaudeSession',
257
277
  'updateStartupTaskAttentionDismissal', 'updateStartupTaskLifecycle',
258
278
  'markStartupTaskParked', 'prepareScrollbackForSession', 'upsertAgentSessionIdentity',
259
- 'promoteStartupTaskTitleIfUserNamed', 'repairSessionTitlesFromStartupTasks',
260
279
  'repairCodexRolloutAgentIdentities', 'cleanupOrphanScrollbackIdentities',
261
280
  ].concat(require('../../shared/storage/ctm-domain-operation-contract').WORKSPACE_ACTIVITY_OWNER_WRITE_OPS));
262
281
 
@@ -124,6 +124,13 @@ const RAW_DB_OWNER_OPS = {
124
124
  updatePromptEffectiveness: { expectedMs: 5000, resumable: false },
125
125
  applySafeRelinkRepairs: { expectedMs: 1000, resumable: false },
126
126
  recoverSessionIntegrity: { expectedMs: 1000, resumable: false },
127
+ // WP-3 (worker-transcript-link-derived-not-discovered-2026-10-25.html §5 D-5): one bounded,
128
+ // idempotent boot pass that fills agent_sessions.jsonl_path for Claude rows whose transcript is
129
+ // already at the derived path. `expectedMs` is a budget HINT, not a deadline: the dispatch
130
+ // deadline is max(interactive floor 60s, expectedMs*8) (lib/db-owner-op-deadline.js), and the op
131
+ // is additionally bounded by payload.limit (<=500 rows). Not resumable: the caller is a
132
+ // fire-and-forget boot hook with no redrive, and a redrive could only re-run a no-op.
133
+ linkDerivedClaudeTranscripts: { expectedMs: 2000, resumable: false },
127
134
  backfillSessionMessagesAsync: { expectedMs: 500, resumable: false },
128
135
  runContentRowsBackfillSweep: { expectedMs: 500, resumable: false },
129
136
  deleteStaleSessionAnalysesFromArtifact: {
@@ -39,6 +39,7 @@ const SCHEMA_SOURCE_FILES = Object.freeze([
39
39
  'lib/migrations/v52-coding-session-launch-generations.js',
40
40
  'lib/migrations/v53-session-model-intent.js',
41
41
  'lib/migrations/v54-session-lead-model.js',
42
+ 'lib/migrations/v56-host-samples-and-machine-pool.js',
42
43
  'lib/migrations/v29-usage-accounting.js', 'lib/migrations/v30-usage-reporting.js', 'lib/migrations/v36-conversation-projection-deletes.js',
43
44
  '../shared/usage-store.js', '../shared/usage-reporting-schema.js',
44
45
  'lib/delete-ctm-session-saga.js',
@@ -1557,7 +1557,7 @@ const FEATURES = [
1557
1557
  // no polarity/tunable/config pattern matched; 1 site(s); first: db.js:4416
1558
1558
  { id: "ctm_ctm_sqlite_synchronous", env: "CTM_SQLITE_SYNCHRONOUS", owner: "ctm-core-team", stage: "ops", defaultOn: true, since: "2026-08-24", expires: null, note: "unclassified raw read; needs manual triage" },
1559
1559
  // numeric-tunable suffix/read shape; 1 site(s); first: db.js:4373
1560
- { id: "ctm_ctm_sqlite_write_lock_stale_ms", env: "CTM_SQLITE_WRITE_LOCK_STALE_MS", owner: "ctm-core-team", stage: "ops", tunable: true, default: 0, since: "2026-08-24", expires: null, note: "numeric tunable" },
1560
+ { id: "ctm_ctm_sqlite_write_lock_stale_ms", env: "CTM_SQLITE_WRITE_LOCK_STALE_MS", owner: "ctm-core-team", stage: "removed", defaultOn: false, since: "2026-08-24", expires: null, note: "retired 2026-10-23 (fsevents-churn WP-1, docs/fsevents-churn-kernel-write-lock-2026-10-23.html D-4): the SQLite write lock is a kernel lock on a .mutex lock DB released by the OS when its holder dies, so stale-claim recovery and its age knob were deleted; no read of this name survives." },
1561
1561
  // !== '0' comparison found; 1 site(s); first: server.js:448
1562
1562
  { id: "ctm_ctm_stale_grid_embargo", env: "CTM_STALE_GRID_EMBARGO", owner: "ctm-core-team", stage: "stable", defaultOn: true, since: "2026-08-24", expires: null },
1563
1563
  // !== '0' comparison found; 1 site(s); first: server.js:19764
@@ -4,6 +4,7 @@ const path = require('path');
4
4
  const EventEmitter = require('events');
5
5
  const { namedInterval, runSync, wrap } = require('./perf-tracker');
6
6
  const envFlags = require('./env-flags');
7
+ const { isWritableOnlyByOwner } = require('../../shared/owner-write-safety');
7
8
 
8
9
  // Design doc mainloop-composer-freeze-2026-08-20.html §5 D-1, §6, §9 S-1/S-4. The 60s
9
10
  // scan tick and the attach/reattach directory walk ran completely unwrapped, so the
@@ -103,7 +104,7 @@ function resolveRoot(root) {
103
104
  result.refusalCode = 'wrong-owner';
104
105
  return result;
105
106
  }
106
- if ((Number(targetStat.mode) & 0o022) !== 0) {
107
+ if (!isWritableOnlyByOwner(targetStat)) {
107
108
  result.validationStatus = 'refused';
108
109
  result.refusalCode = 'unsafe-permissions';
109
110
  return result;
@@ -159,7 +160,7 @@ async function resolveRootAsync(root) {
159
160
  result.refusalCode = 'wrong-owner';
160
161
  return result;
161
162
  }
162
- if ((Number(targetStat.mode) & 0o022) !== 0) {
163
+ if (!isWritableOnlyByOwner(targetStat)) {
163
164
  result.validationStatus = 'refused';
164
165
  result.refusalCode = 'unsafe-permissions';
165
166
  return result;
@@ -4,7 +4,7 @@ const NATIVE_ORIGINS = new Set(['native-codex', 'native-claude', 'native-opencod
4
4
  const KNOWN_ORIGINS = new Set([...NATIVE_ORIGINS, 'routed-proxy', 'portable-transcript']);
5
5
  // S-3: the adapter/schema ids and the version membership test come from the one qualified table.
6
6
  const { CODEX_CONTROL_ADAPTER, CODEX_COMPACTION_SCHEMA_RECEIPT, CODEX_PRE_TURN_COMPACTION_SCHEMA,
7
- isQualifiedCodexVersion } = require('./codex-harness-qualification');
7
+ isQualifiedCodexVersion, isNonElevatedCyberAccessProgram } = require('./codex-harness-qualification');
8
8
  // S-4: the ONE portable-kind set. `native-media` is a message whose only non-text content parts are
9
9
  // input_image parts (D-2); it is portable only to a Codex target, which is the planner's job below.
10
10
  const PORTABLE_HISTORY_KINDS = new Set(['text', 'tool-pair', 'native-world-state', 'native-lifecycle', 'native-media']);
@@ -48,8 +48,8 @@ function inspectTransition({ sourceRecipe, targetRecipe, snapshot, signal } = {}
48
48
  if (!sourceCheckpoint) return refuse('source_checkpoint_unknown');
49
49
  if (codexHistorySource && sourceProviderId !== targetProviderId
50
50
  && (!qualifiedCodexHistorySource
51
- || sourceRecipe.cyberAccessProgram !== null
52
- || snapshot.previousSettings?.cyberAccessProgram !== null
51
+ || !isNonElevatedCyberAccessProgram(sourceRecipe.cyberAccessProgram)
52
+ || !isNonElevatedCyberAccessProgram(snapshot.previousSettings?.cyberAccessProgram)
53
53
  || targetRecipe.harness !== 'codex-cli' || !isQualifiedCodexVersion(targetRecipe.harnessVersion))) {
54
54
  return refuse('native_fork_adapter_unqualified', { sourceCheckpoint });
55
55
  }