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
@@ -25,6 +25,18 @@ function mergePendingInteractionIds(existing, incoming, limit = PENDING_IDS_LIMI
25
25
  return merged.slice(-limit);
26
26
  }
27
27
 
28
+ // WP-4 (R-7, clock-free-tests-followups-r3-2026-10-24.html §5 R-7, §6 WP-4): keep the per-id
29
+ // inputSeq map to exactly the ids `pending` still carries, oldest dropped first, capped at
30
+ // `limit` -- the same "keep the most recent N" policy mergePendingInteractionIds applies to the
31
+ // id list itself, so the two can never drift apart.
32
+ function prunePendingInputSeqs(byId, pending, limit = PENDING_IDS_LIMIT) {
33
+ for (const id of Array.from(byId.keys())) {
34
+ if (!pending.includes(id)) byId.delete(id);
35
+ }
36
+ while (byId.size > limit) byId.delete(byId.keys().next().value);
37
+ return byId;
38
+ }
39
+
28
40
  // Post ONE 'typing-stage' message covering every id currently pending for this session -- the
29
41
  // STAGES store's note() (lib/typing-interaction-trace.js) fans it out per-interactionId and is
30
42
  // idempotent per (interactionId, stage), so calling this more than once for the same boundary is
@@ -38,4 +50,199 @@ function noteWorkerTypingStage(postTransport, sessionId, interactionIds, stage,
38
50
  });
39
51
  }
40
52
 
41
- module.exports = { mergePendingInteractionIds, noteWorkerTypingStage, PENDING_IDS_LIMIT };
53
+ // --- WP-3 shadow echo matchers -----------------------------------------------------------
54
+ // Design doc: composer-freeze-followups-load-sigstop-attribution-2026-10-20.html §5 D-C2
55
+ // (two per-key matchers, shadow-only, OPTIONAL stages) and §1.3 (most existing stages are
56
+ // "first X after the key", not that key's echo -- e.g. pty-output lands 0-3 ms after
57
+ // pty-written in 14 of 18 retained slow rows, which no agent CLI can do).
58
+ //
59
+ // Prior art, both rules copied as-is:
60
+ // - echo-bytes = VS Code terminal typeahead's rule: the predicted char is "eaten" out of
61
+ // the incoming BYTE STREAM once SGR/escape sequences are skipped
62
+ // (terminalTypeAheadAddon.ts, `input.eatChar(this._char)`).
63
+ // - echo-cell = mosh's rule: a prediction is confirmed only when "a letter we hypothesized
64
+ // to appear in a particular cell did appear there" (mosh paper, USENIX ATC'12).
65
+ //
66
+ // Both stamps are per-key (ONE interactionId), shadow-only: nothing reads them as truth and
67
+ // no existing stage changes meaning (that decision is WP-5, on WP-4's numbers, per D-C4).
68
+ const ECHO_PREDICTION_CAP = 24;
69
+ // D-C2: a prediction that neither matcher confirmed within this window is dropped -- the CLI
70
+ // may echo arbitrarily late, but a stale prediction can only ever produce a false positive
71
+ // against a later, unrelated redraw.
72
+ const ECHO_PREDICTION_TTL_MS = 10_000;
73
+
74
+ // One grapheme, at most 4 UTF-8 bytes, no C0 control / ESC / DEL -- the D-C2 input class that
75
+ // can be predicted at all. This is also what server.js uses to decide whether a keystroke
76
+ // carries an `echo` payload; it lives here so server.js stays at its file-size ratchet.
77
+ const _echoSegmenter = new Intl.Segmenter();
78
+ function isSingleGraphemeEcho(data) {
79
+ if (typeof data !== 'string' || !data) return false;
80
+ if (Buffer.byteLength(data, 'utf8') > 4) return false;
81
+ if (/[\x00-\x1f\x7f]/.test(data)) return false;
82
+ let count = 0;
83
+ for (const _segment of _echoSegmenter.segment(data)) {
84
+ count += 1;
85
+ if (count > 1) return false;
86
+ }
87
+ return count === 1;
88
+ }
89
+
90
+ // D-C2: the byte matcher must look at what the CLI actually printed, not at the escape
91
+ // sequences around it. Strip CSI (`ESC [ ... final`), OSC (`ESC ] ... BEL | ESC \`) and any
92
+ // other two-byte `ESC x`, leaving only the printable text.
93
+ function stripEscapeSequences(text) {
94
+ const source = String(text ?? '');
95
+ let out = '';
96
+ let index = 0;
97
+ while (index < source.length) {
98
+ if (source[index] !== '\x1b') {
99
+ out += source[index];
100
+ index += 1;
101
+ continue;
102
+ }
103
+ const next = source[index + 1];
104
+ if (next === '[') {
105
+ let end = index + 2;
106
+ // ECMA-48 CSI: parameter/intermediate bytes are 0x20-0x3f, the final byte is 0x40-0x7e.
107
+ while (end < source.length) {
108
+ const code = source.charCodeAt(end);
109
+ if (code >= 0x40 && code <= 0x7e) break;
110
+ end += 1;
111
+ }
112
+ index = end + 1;
113
+ } else if (next === ']') {
114
+ let end = index + 2;
115
+ while (end < source.length && source[end] !== '\x07'
116
+ && !(source[end] === '\x1b' && source[end + 1] === '\\')) {
117
+ end += 1;
118
+ }
119
+ if (end >= source.length) index = source.length;
120
+ else index = source[end] === '\x07' ? end + 1 : end + 2;
121
+ } else if (next === undefined) {
122
+ index = source.length;
123
+ } else {
124
+ index += 2;
125
+ }
126
+ }
127
+ return out;
128
+ }
129
+
130
+ // D-C2, called from the 'note-input' handler (headless-term-service.js). Merges the incoming
131
+ // interactionIds exactly like the inline block it replaces, then -- when the keystroke carries
132
+ // a single-grapheme `echo` -- records where the CLI's echo SHOULD land from here: the cursor
133
+ // cell of the mirror at this instant, in the buffer that is active at this instant.
134
+ function armEchoPrediction(entry, msg) {
135
+ if (!entry || !entry.state || !msg) return;
136
+ if (Array.isArray(msg.interactionIds) && msg.interactionIds.length) {
137
+ entry.state.pendingTypingInteractionIds = mergePendingInteractionIds(
138
+ entry.state.pendingTypingInteractionIds, msg.interactionIds,
139
+ );
140
+ entry.state.typingIdsAwaitingFeed = true;
141
+ // WP-4 (R-7): remember each pending id's OWN inputSeq here, so emitSettled can tell "the
142
+ // offered frame did not yet contain this key's echo" apart from "worker->main delivery or
143
+ // main-thread queueing" (the (i)/(ii) split design r3 §1.4 says today's stamps cannot make).
144
+ // Earliest seq wins for an id seen twice; the Math.max(0, ...) normalization is the same one
145
+ // headless-term-service.js's 'note-input' handler applies to msg.inputSeq.
146
+ const inputSeq = Math.max(0, Number(msg.inputSeq) || 0);
147
+ const seqById = entry.state.pendingTypingInputSeqById instanceof Map
148
+ ? entry.state.pendingTypingInputSeqById
149
+ : new Map();
150
+ for (const rawId of msg.interactionIds) {
151
+ const id = String(rawId);
152
+ if (!seqById.has(id) || inputSeq < seqById.get(id)) seqById.set(id, inputSeq);
153
+ }
154
+ entry.state.pendingTypingInputSeqById = prunePendingInputSeqs(
155
+ seqById, entry.state.pendingTypingInteractionIds,
156
+ );
157
+ }
158
+ const echo = msg.echo;
159
+ if (!echo || !echo.interactionId || typeof echo.char !== 'string' || !echo.char) return;
160
+ const buf = entry.term?.buffer?.active;
161
+ if (!buf) return;
162
+ if (!Array.isArray(entry.state.echoPredictions)) entry.state.echoPredictions = [];
163
+ const predictions = entry.state.echoPredictions;
164
+ predictions.push({
165
+ interactionId: String(echo.interactionId),
166
+ char: echo.char,
167
+ row: buf.baseY + buf.cursorY,
168
+ col: buf.cursorX,
169
+ bufferType: buf.type,
170
+ armedAt: Date.now(),
171
+ bytes: false,
172
+ cell: false,
173
+ });
174
+ // D-C2 bound: never more than 24 pending, oldest dropped first.
175
+ while (predictions.length > ECHO_PREDICTION_CAP) predictions.shift();
176
+ return predictions;
177
+ }
178
+
179
+ // D-C2, called once per applied NON-seed feed (headless-term-service.js's feed onApplied).
180
+ // Each matcher stamps AT MOST ONCE per prediction, for that prediction's single id only --
181
+ // never the session's whole pending set (that is the R1/R2 misattribution this shadows).
182
+ function matchEchoPredictions(postTransport, sessionId, entry, data, now = Date.now()) {
183
+ const predictions = entry?.state?.echoPredictions;
184
+ if (!Array.isArray(predictions) || !predictions.length) return;
185
+ const text = stripEscapeSequences(data);
186
+ const buf = entry.term?.buffer?.active;
187
+ const kept = [];
188
+ for (const prediction of predictions) {
189
+ if (!prediction.bytes && prediction.char && text.includes(prediction.char)) {
190
+ prediction.bytes = true;
191
+ noteWorkerTypingStage(postTransport, sessionId, [prediction.interactionId], 'echo-bytes');
192
+ }
193
+ if (!prediction.cell && buf && buf.type === prediction.bufferType) {
194
+ const line = buf.getLine(prediction.row);
195
+ if (line?.getCell(prediction.col)?.getChars() === prediction.char) {
196
+ prediction.cell = true;
197
+ noteWorkerTypingStage(postTransport, sessionId, [prediction.interactionId], 'echo-cell');
198
+ }
199
+ }
200
+ // D-C2: drop when both matchers hit, or past the 10 s window.
201
+ if (prediction.bytes && prediction.cell) continue;
202
+ if (now - prediction.armedAt > ECHO_PREDICTION_TTL_MS) continue;
203
+ kept.push(prediction);
204
+ }
205
+ entry.state.echoPredictions = kept;
206
+ }
207
+
208
+ // WP-4 (R-7), called from headless-term-service.js's emitSettled ONLY after
209
+ // _stateSyncEmitter.onMirrorUpdated returned `sent` -- the frame that just shipped is the first
210
+ // one that could carry these keys' echoes, so stamp `frame-posted` for exactly the pending ids
211
+ // the frame's `echoedThroughSeq` already covers (recorded inputSeq >= 1 AND <= offeredEchoSeq).
212
+ // An id with NO recorded seq is treated as echoed, which preserves the pre-WP-4 blanket clear.
213
+ // Returns the ids that remain un-echoed (recorded seq > offeredEchoSeq) so the caller can keep
214
+ // only those pending -- that is what makes `emit-offered -> frame-posted` readable as "the
215
+ // offered frame DID contain this key's echo" versus "the frame lacked it" instead of collapsing
216
+ // both into one delivery gap.
217
+ function noteFramePostedForEchoed(postTransport, sessionId, entry, offeredEchoSeq) {
218
+ const pending = Array.isArray(entry?.state?.pendingTypingInteractionIds)
219
+ ? entry.state.pendingTypingInteractionIds
220
+ : [];
221
+ const seqById = entry?.state?.pendingTypingInputSeqById;
222
+ const covering = Math.max(0, Number(offeredEchoSeq) || 0);
223
+ const echoedIds = [];
224
+ const remaining = [];
225
+ for (const rawId of pending) {
226
+ const id = String(rawId);
227
+ const seq = seqById instanceof Map && seqById.has(id) ? Number(seqById.get(id)) : 0;
228
+ if (seq > covering) remaining.push(id);
229
+ else echoedIds.push(id);
230
+ }
231
+ noteWorkerTypingStage(postTransport, sessionId, echoedIds, 'frame-posted', { offeredEchoSeq: covering });
232
+ // The echoed ids are delivered; only the un-echoed ones stay pending (and keep their seq).
233
+ if (seqById instanceof Map) {
234
+ for (const id of echoedIds) seqById.delete(id);
235
+ }
236
+ return remaining;
237
+ }
238
+
239
+ module.exports = {
240
+ mergePendingInteractionIds,
241
+ noteWorkerTypingStage,
242
+ noteFramePostedForEchoed,
243
+ PENDING_IDS_LIMIT,
244
+ isSingleGraphemeEcho,
245
+ armEchoPrediction,
246
+ matchEchoPredictions,
247
+ ECHO_PREDICTION_CAP,
248
+ };
@@ -267,6 +267,37 @@ function createClaudeFileParser({ sessionId, agentId = '', state = null } = {})
267
267
  // it just emitted (the store's primary key dedups across passes as well).
268
268
  const seenAliases = new Set();
269
269
 
270
+ // The vendor ids of the rows THIS slice saw (WP-3, design §5 D-8). A re-read from 0 no
271
+ // longer deletes the file's prior facts up front (D-7); instead the store sweeps, at EOF,
272
+ // only the prior facts whose vendor id the new reading OBSERVED and no longer re-emits.
273
+ // So this is the evidence half of that rule: every id that proves a source row is still
274
+ // in the file, whether or not this reading turned it into a fact.
275
+ //
276
+ // * responses -- the provider message id of every assistant record (with or without
277
+ // usage: a record the reading no longer admits is exactly one whose call must go);
278
+ // * prompts -- the id of every row the parser ACCEPTS as a prompt row, and only
279
+ // those rows. Later rows of the same turn (a tool_result `user` row, for instance)
280
+ // carry the same promptId, so collecting the id off every record would "observe" a
281
+ // prompt whose OWN row the vendor cut -- and the sweep would then delete the prompt
282
+ // fact and its aliases. Observation happens in the prompt-recording path alone;
283
+ // * toolUses -- every tool_use block id, which is the vendor id of a spawn, an edge
284
+ // and an attempt alike.
285
+ //
286
+ // De-duplicated within the slice (a Set), and NOT persisted in the checkpoint: it
287
+ // describes one slice's reading, never a resume position.
288
+ const observedResponses = new Set();
289
+ const observedPrompts = new Set();
290
+ const observedToolUses = new Set();
291
+
292
+ function observeToolUses(content) {
293
+ if (!Array.isArray(content)) return;
294
+ for (const block of content) {
295
+ if (!block || block.type !== 'tool_use') continue;
296
+ if (typeof block.id !== 'string' || block.id === '') continue;
297
+ observedToolUses.add(block.id);
298
+ }
299
+ }
300
+
270
301
  function recordCall(row) {
271
302
  const existing = indexByKey.get(row.call_key);
272
303
  if (existing === undefined) {
@@ -315,11 +346,14 @@ function createClaudeFileParser({ sessionId, agentId = '', state = null } = {})
315
346
  if (record.type === 'assistant') {
316
347
  const message = record.message;
317
348
  const usage = message && message.usage;
349
+ const responseId = responseIdOf(message);
350
+ if (responseId !== '') observedResponses.add(responseId);
351
+ observeToolUses(message && message.content);
318
352
  // Admission: a usage object and a nonempty response id. A requestId is NOT required (it
319
353
  // is absent in every one of the six historical glm-5-3 transcripts, which is what the
320
354
  // old rule discarded), and no prefix is required on the id.
321
355
  if (usage && typeof usage === 'object'
322
- && responseIdOf(message) !== ''
356
+ && responseId !== ''
323
357
  && nonEmptyText(message.model) !== '<synthetic>') {
324
358
  const promptId = agentId === '' ? persisted.current_prompt_id : null;
325
359
  recordCall(callRowFor(record, offset, { sessionId, agentId, promptId }));
@@ -440,6 +474,10 @@ function createClaudeFileParser({ sessionId, agentId = '', state = null } = {})
440
474
  // other silently.
441
475
  const promptId = nonEmptyText(entry.promptId) || nonEmptyText(entry.uuid);
442
476
  if (!promptId) return;
477
+ // The row is accepted as a prompt, so its id proves THIS record's own row is present
478
+ // (WP-3 D-8). Recorded here, and nowhere else: an id carried by a later row of the same
479
+ // turn would observe a prompt whose own row the vendor removed.
480
+ observedPrompts.add(promptId);
443
481
  const digest = providerMessageDigestFor(nonEmptyText(entry.uuid)) || null;
444
482
  // Every persisted prompt row is where attribution goes next -- a human task, or the
445
483
  // `/clear` / `/compact` boundary that broke the previous turn. A boundary therefore gets
@@ -478,7 +516,17 @@ function createClaudeFileParser({ sessionId, agentId = '', state = null } = {})
478
516
  }
479
517
 
480
518
  function drain() {
481
- const out = { calls, prompts, aliases, spawns, delegations, attempts, reported, state: persisted };
519
+ const out = {
520
+ calls, prompts, aliases, spawns, delegations, attempts, reported,
521
+ // The ids this slice observed (WP-3 D-8). Never persisted: they describe one slice's
522
+ // reading, and the store clears its own copy of them at EOF.
523
+ observed: {
524
+ responses: [...observedResponses],
525
+ prompts: [...observedPrompts],
526
+ toolUses: [...observedToolUses],
527
+ },
528
+ state: persisted,
529
+ };
482
530
  calls = [];
483
531
  prompts = [];
484
532
  aliases = [];
@@ -489,6 +537,9 @@ function createClaudeFileParser({ sessionId, agentId = '', state = null } = {})
489
537
  indexByKey.clear();
490
538
  seenAliases.clear();
491
539
  seenPrompts.clear();
540
+ observedResponses.clear();
541
+ observedPrompts.clear();
542
+ observedToolUses.clear();
492
543
  return out;
493
544
  }
494
545
 
@@ -205,10 +205,13 @@ function createUsageIngestor({ store, sliceBytes = DEFAULT_SLICE_BYTES, pricer =
205
205
  let firstBatch = true;
206
206
  let done = false;
207
207
  let remaining = maxBytes;
208
- // WP-8b: when a file RESETS to offset 0 (its checkpoint was discarded by a
209
- // parser_version or head change) the store must first delete the facts this file
210
- // wrote under the old reading, else stale rows double-count. The flag rides the
211
- // first slice only: a brand-new file (no row) never resets, and the re-read's later
208
+ // WP-8b/WP-3: when a file RESETS to offset 0 (its checkpoint was discarded by a
209
+ // parser_version or head change) the store must reconcile the facts this file wrote
210
+ // under the old reading. For a CODEX file that stays today's eager delete (WP-8b). For
211
+ // a CLAUDE file it is a SNAPSHOT instead (WP-3 D-7): the vendor rewrites a compacted
212
+ // transcript, so the new reading sees fewer rows than the reading that wrote those
213
+ // facts, and deleting them would destroy usage nothing can re-create. The flag rides
214
+ // the first slice only: a brand-new file (no row) never resets, and the re-read's later
212
215
  // slices append to the facts the first slice just re-created.
213
216
  const resetOnFirstBatch = !!row && offset === 0;
214
217
 
@@ -257,6 +260,12 @@ function createUsageIngestor({ store, sliceBytes = DEFAULT_SLICE_BYTES, pricer =
257
260
  reported: out.reported,
258
261
  checkpoint,
259
262
  reset: firstBatch && resetOnFirstBatch,
263
+ // The ids this slice OBSERVED (WP-3 D-8) and whether this slice reached EOF. The
264
+ // store uses them only for a Claude file: a prior fact whose vendor id was seen
265
+ // but which the new reading no longer emits is swept at EOF, while one whose row
266
+ // the vendor deleted is kept. Both are ignored for Codex (D-10).
267
+ observed: out.observed || null,
268
+ final: checkpoint.status === 'current',
260
269
  price,
261
270
  });
262
271
  calls += upserted.callsWritten;
@@ -506,6 +506,11 @@ function resolveScope(coreDb, ctmSessionId) {
506
506
  delegatedCtmSessions.push(childId);
507
507
  workers.push({
508
508
  ctm_session_id: childId,
509
+ // WP-2: the CTM session whose OWN turn launched this worker -- the BFS node whose children are
510
+ // being read. The launch-time fallback (task-read.js) may only charge a worker to the scope
511
+ // ROOT's canonical turns, so a worker launched by another worker (a nested delegation) is
512
+ // excluded by comparing this field against the scope's own CTM session id.
513
+ parent_ctm_session_id: String(current.ctmId),
509
514
  generation: Number.isInteger(child.generation) && child.generation >= 1 ? child.generation : null,
510
515
  generation_ends_ms: generationEndsMs(child.generation, child.runtime_json),
511
516
  launches: workerLaunches(child, childId),
@@ -708,6 +713,10 @@ function availabilityOf(ledgerDb) {
708
713
  // v5: the native local turn of a prompt, beside its event-derived identity. A ledger
709
714
  // written before the column reads it as an explicit UNAVAILABLE fact, never a throw.
710
715
  prompt_native_turn_id: prompts.has('native_turn_id'),
716
+ // D-3 (WP-1): whether a prompt row still carries its SOURCE file. A prompt written before the
717
+ // column existed reads as an explicit `source_less` fact on the page; the raw file id itself is
718
+ // internal plumbing and never crosses this boundary.
719
+ prompt_source_file: prompts.has('source_file_id'),
711
720
  prompt_aliases: hasAll(aliases, ['prompt_id', 'provider_message_digest']),
712
721
  revision: tableColumns(ledgerDb, 'usage_ledger_meta').has('value'),
713
722
  };
@@ -986,6 +995,7 @@ function readLedgerSession(ledgerDb, scope, options = {}) {
986
995
  if (available.source_event_digest) promptColumns.push('source_event_digest');
987
996
  if (available.prompt_content_fingerprint) promptColumns.push('content_fingerprint');
988
997
  if (available.prompt_native_turn_id) promptColumns.push('native_turn_id');
998
+ if (available.prompt_source_file) promptColumns.push('source_file_id');
989
999
  const promptSizeColumns = available.prompt_metadata
990
1000
  ? ", CASE WHEN text IS NULL THEN 0 ELSE length(CAST(text AS BLOB)) END AS text_bytes, CASE WHEN text IS NULL THEN 0 ELSE length(text) END AS text_chars"
991
1001
  : ', 0 AS text_bytes, 0 AS text_chars';
@@ -1106,6 +1116,10 @@ function readLedgerSession(ledgerDb, scope, options = {}) {
1106
1116
  source_event_digest: available.source_event_digest ? row.source_event_digest ?? null : null,
1107
1117
  content_fingerprint: available.prompt_content_fingerprint ? row.content_fingerprint ?? null : null,
1108
1118
  native_turn_id: available.prompt_native_turn_id ? row.native_turn_id ?? null : null,
1119
+ // D-3: `true` only when the column EXISTS and the row's value is NULL. Without the column
1120
+ // the read cannot prove the prompt is sourceless, so it reports `false` ("cannot prove") and
1121
+ // the prompt is never matched by time.
1122
+ source_less: available.prompt_source_file ? row.source_file_id == null : false,
1109
1123
  kind: available.prompt_metadata ? (row.kind ?? null) : null,
1110
1124
  text: fetched ? overviewTextFor.get(key) : null,
1111
1125
  text_truncated: available.prompt_metadata ? row.text_truncated === 1 || row.text_truncated === true : null,
@@ -15,7 +15,7 @@
15
15
 
16
16
  const { createMigrationRunner, pragmaVersionStore } = require('../../../shared/db-migration-runner');
17
17
 
18
- const USAGE_LEDGER_SCHEMA_VERSION = 7;
18
+ const USAGE_LEDGER_SCHEMA_VERSION = 8;
19
19
 
20
20
  // The complete v1 schema, in one place. Each statement is idempotent
21
21
  // (IF NOT EXISTS) so a re-run of the baseline against a partially-created file
@@ -302,6 +302,52 @@ function createV7(db) {
302
302
  `);
303
303
  }
304
304
 
305
+ // v8 (usage-vendor-rewrite WP-3, design §5 D-7/D-8): the non-destructive re-read scratch
306
+ // state for CLAUDE files. Claude Code rewrites a large transcript after compaction -- it
307
+ // removes every row before the last compact boundary and renames a new file over the old
308
+ // path -- so a re-read from 0 sees FEWER rows than the reading that wrote the ledger's
309
+ // facts. Until this version the reset deleted the file's facts up front, which destroyed
310
+ // real, already-recorded usage (the measured incident: 4.5 days of one lead session's calls
311
+ // and every launch receipt). The two tables here make the re-read a snapshot refresh
312
+ // instead of a retraction (D-7) while keeping today's safety for a fact whose row IS still
313
+ // present but which the new reading no longer emits (D-8):
314
+ //
315
+ // * usage_reread_prior -- the keys of the file's prior facts, snapshotted on the first
316
+ // slice of a re-read instead of deleting them. `fact_key` is the JSON array of the
317
+ // fact's primary-key values in PK column order, so it is comparable as text and
318
+ // rebuildable in SQL (json_array) and in JS (JSON.stringify) identically. `vendor_id`
319
+ // is the provider id a fact can be matched against what the new reading OBSERVED;
320
+ // NULL means the identity is an older form nothing can match (swept at EOF, which is
321
+ // exactly today's behaviour for a stale key).
322
+ // * usage_reread_seen -- the vendor ids the re-read actually SAW, in three kinds:
323
+ // 'response' (an assistant message.id), 'prompt' (the id of a row the parser accepted as a
324
+ // prompt row -- never a later row of the same turn, which carries the same promptId) and
325
+ // 'tool_use' (a tool_use block id).
326
+ //
327
+ // Both are per-file scratch: they are cleared for the file in the same transaction as the
328
+ // slice that reaches EOF. They are bounded by that file's own fact count. Codex files never
329
+ // write here -- they keep the eager reset delete (D-10).
330
+ //
331
+ // It is a pure CREATE TABLE step (no data rewrite), so the migration is inherently re-run
332
+ // safe and idempotent.
333
+ function createV8(db) {
334
+ db.exec(`
335
+ CREATE TABLE IF NOT EXISTS usage_reread_prior (
336
+ file_id INTEGER NOT NULL,
337
+ kind TEXT NOT NULL CHECK(kind IN ('call','prompt','alias','spawn','delegation','attempt')),
338
+ fact_key TEXT NOT NULL, -- JSON array of the fact's primary-key values, in PK column order
339
+ vendor_id TEXT, -- NULL = not derivable (older identity form) -> swept at EOF
340
+ PRIMARY KEY(file_id, kind, fact_key)
341
+ ) WITHOUT ROWID;
342
+ CREATE TABLE IF NOT EXISTS usage_reread_seen (
343
+ file_id INTEGER NOT NULL,
344
+ kind TEXT NOT NULL CHECK(kind IN ('response','prompt','tool_use')),
345
+ vendor_id TEXT NOT NULL,
346
+ PRIMARY KEY(file_id, kind, vendor_id)
347
+ ) WITHOUT ROWID;
348
+ `);
349
+ }
350
+
305
351
  // Built lazily on first use so merely requiring this module has no side effects
306
352
  // (no module-level runner construction, no DDL, no env reads).
307
353
  let _runner = null;
@@ -323,6 +369,7 @@ function runner() {
323
369
  5: { up: createV5, label: 'v5 prompt native turn id' },
324
370
  6: { up: createV6, label: 'v6 delegation edges' },
325
371
  7: { up: createV7, label: 'v7 delegation launch attempts' },
372
+ 8: { up: createV8, label: 'v8 claude re-read snapshot' },
326
373
  },
327
374
  baseline: (db) => {
328
375
  createV1(db);
@@ -332,6 +379,7 @@ function runner() {
332
379
  createV5(db);
333
380
  createV6(db);
334
381
  createV7(db);
382
+ createV8(db);
335
383
  },
336
384
  versionStore: pragmaVersionStore(),
337
385
  });