create-walle 0.10.2 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (488) hide show
  1. package/README.md +3 -1
  2. package/lib/release-schema.json +2 -2
  3. package/lib/runtime-closure-policy.json +8 -7
  4. package/package.json +1 -1
  5. package/template/coding-task-manager/api-prompts.js +45 -7
  6. package/template/coding-task-manager/bin/claude-hook.js +55 -1
  7. package/template/coding-task-manager/bin/ctm-relay-client.js +35 -12
  8. package/template/coding-task-manager/bin/land.js +2069 -0
  9. package/template/coding-task-manager/bin/memory-census.js +4 -2
  10. package/template/coding-task-manager/bin/memory-sync-verify.js +151 -0
  11. package/template/coding-task-manager/bin/probe-refusal-scope.js +530 -0
  12. package/template/coding-task-manager/db.js +156 -32
  13. package/template/coding-task-manager/lib/acp/acp-client.js +383 -0
  14. package/template/coding-task-manager/lib/acp/dsh-context-truth.js +176 -0
  15. package/template/coding-task-manager/lib/acp/dsh-launch-model.js +302 -0
  16. package/template/coding-task-manager/lib/acp/dsh-mcp-servers.js +194 -0
  17. package/template/coding-task-manager/lib/acp/dsh-prompt-lane.js +616 -0
  18. package/template/coding-task-manager/lib/acp/dsh-route-patch.js +308 -0
  19. package/template/coding-task-manager/lib/acp/dsh-session-runtime.js +522 -0
  20. package/template/coding-task-manager/lib/acp/dsh-transcript.js +395 -0
  21. package/template/coding-task-manager/lib/acp/dsh-usage-log.js +162 -0
  22. package/template/coding-task-manager/lib/acp/ndjson-stdio-transport.js +225 -0
  23. package/template/coding-task-manager/lib/adopted-host-redial.js +47 -11
  24. package/template/coding-task-manager/lib/adopted-launch-environment.js +123 -0
  25. package/template/coding-task-manager/lib/agent-auto-update-runtime.js +0 -3
  26. package/template/coding-task-manager/lib/agent-auto-update.js +26 -10
  27. package/template/coding-task-manager/lib/agent-bundle/build.js +657 -0
  28. package/template/coding-task-manager/lib/agent-bundle/codex-install.js +558 -0
  29. package/template/coding-task-manager/lib/agent-bundle/drift.js +120 -0
  30. package/template/coding-task-manager/lib/agent-bundle/gc.js +522 -0
  31. package/template/coding-task-manager/lib/agent-bundle/inventory.js +346 -0
  32. package/template/coding-task-manager/lib/agent-bundle/push.js +717 -0
  33. package/template/coding-task-manager/lib/agent-bundle/skill-transfer.js +724 -0
  34. package/template/coding-task-manager/lib/agent-bundle/spawn.js +119 -0
  35. package/template/coding-task-manager/lib/agent-bundle/store.js +568 -0
  36. package/template/coding-task-manager/lib/agent-capabilities.js +142 -12
  37. package/template/coding-task-manager/lib/agent-cli-cache.js +30 -5
  38. package/template/coding-task-manager/lib/agent-definitions.js +19 -0
  39. package/template/coding-task-manager/lib/agent-hooks-codex-toml.js +28 -16
  40. package/template/coding-task-manager/lib/agent-hooks-codex-workspace.js +9 -1
  41. package/template/coding-task-manager/lib/agent-hooks-installer.js +23 -8
  42. package/template/coding-task-manager/lib/agent-hooks-prune.js +37 -11
  43. package/template/coding-task-manager/lib/agent-hooks-shim.js +105 -0
  44. package/template/coding-task-manager/lib/agent-presets.js +84 -1
  45. package/template/coding-task-manager/lib/agent-upgrade-jobs.js +12 -1
  46. package/template/coding-task-manager/lib/agent-version-service.js +74 -11
  47. package/template/coding-task-manager/lib/all-sessions-query.js +6 -2
  48. package/template/coding-task-manager/lib/api/agent-bundles.js +436 -0
  49. package/template/coding-task-manager/lib/api/backup-retention.js +83 -0
  50. package/template/coding-task-manager/lib/api/conversation-sync-routes.js +124 -0
  51. package/template/coding-task-manager/lib/api/diagnostics.js +549 -69
  52. package/template/coding-task-manager/lib/api/fleet.js +118 -0
  53. package/template/coding-task-manager/lib/api/hub-bridge.js +243 -0
  54. package/template/coding-task-manager/lib/api/ingress.js +9 -1
  55. package/template/coding-task-manager/lib/api/landing.js +403 -0
  56. package/template/coding-task-manager/lib/api/machines.js +691 -2
  57. package/template/coding-task-manager/lib/api/memory-sync-routes.js +335 -0
  58. package/template/coding-task-manager/lib/api/misc-ops.js +8 -3
  59. package/template/coding-task-manager/lib/api/remote-sessions.js +1326 -0
  60. package/template/coding-task-manager/lib/api/session-attach.js +623 -0
  61. package/template/coding-task-manager/lib/api/session-messages.js +1384 -0
  62. package/template/coding-task-manager/lib/api/sessions.js +77 -51
  63. package/template/coding-task-manager/lib/api/setup-network.js +544 -16
  64. package/template/coding-task-manager/lib/api/setup-wizard-handlers.js +884 -0
  65. package/template/coding-task-manager/lib/api/setup.js +829 -10
  66. package/template/coding-task-manager/lib/api/walle-bridge.js +9 -1
  67. package/template/coding-task-manager/lib/attachment-reconciler-wiring.js +5 -2
  68. package/template/coding-task-manager/lib/auth-rate-limit.js +23 -0
  69. package/template/coding-task-manager/lib/auth-rules.js +292 -21
  70. package/template/coding-task-manager/lib/background-stop.js +369 -0
  71. package/template/coding-task-manager/lib/best-of-attempts.js +4 -1
  72. package/template/coding-task-manager/lib/best-of-launch-plan.js +52 -0
  73. package/template/coding-task-manager/lib/box-keep-awake.js +89 -0
  74. package/template/coding-task-manager/lib/broadcast-reason-stats.js +152 -0
  75. package/template/coding-task-manager/lib/broadcast-serialize.js +5 -0
  76. package/template/coding-task-manager/lib/build-info.js +4 -2
  77. package/template/coding-task-manager/lib/claude-model-truth.js +13 -2
  78. package/template/coding-task-manager/lib/claude-transcript-terminal-renderer.js +17 -13
  79. package/template/coding-task-manager/lib/client-diag-handler.js +64 -2
  80. package/template/coding-task-manager/lib/codex-app-server-client.js +14 -16
  81. package/template/coding-task-manager/lib/codex-configuration-history.js +55 -0
  82. package/template/coding-task-manager/lib/codex-harness-qualification.js +43 -20
  83. package/template/coding-task-manager/lib/codex-rollout-history.js +743 -0
  84. package/template/coding-task-manager/lib/coding-agent-models.js +27 -12
  85. package/template/coding-task-manager/lib/coding-cli-skill-installer.js +44 -14
  86. package/template/coding-task-manager/lib/coding-session-model-adapters.js +43 -2
  87. package/template/coding-task-manager/lib/coding-session-model-owner.js +1 -1
  88. package/template/coding-task-manager/lib/coding-session-model-public.js +7 -1
  89. package/template/coding-task-manager/lib/coding-session-model-runtime.js +23 -4
  90. package/template/coding-task-manager/lib/coding-session-model-scan.js +31 -0
  91. package/template/coding-task-manager/lib/coding-session-model-state.js +7 -0
  92. package/template/coding-task-manager/lib/conversation-freshness-diagnostics.js +280 -0
  93. package/template/coding-task-manager/lib/conversation-item-clock.js +261 -0
  94. package/template/coding-task-manager/lib/conversation-source-registry.js +5 -0
  95. package/template/coding-task-manager/lib/conversation-store-v2.js +44 -0
  96. package/template/coding-task-manager/lib/conversation-sync.js +355 -0
  97. package/template/coding-task-manager/lib/create/resolve-launch-params.js +96 -12
  98. package/template/coding-task-manager/lib/create/worker-role-profile.js +4 -4
  99. package/template/coding-task-manager/lib/create-intent-lease.js +51 -0
  100. package/template/coding-task-manager/lib/ctm-session-context-api.js +97 -6
  101. package/template/coding-task-manager/lib/db-domain-tables.js +1 -0
  102. package/template/coding-task-manager/lib/db-domains.js +1 -0
  103. package/template/coding-task-manager/lib/db-owner-dispatch-probe.js +32 -0
  104. package/template/coding-task-manager/lib/db-owner-request-counts.js +178 -0
  105. package/template/coding-task-manager/lib/db-owner-worker-client.js +68 -14
  106. package/template/coding-task-manager/lib/db-schema-source-files.js +5 -0
  107. package/template/coding-task-manager/lib/deferred-restore-attempt.js +6 -2
  108. package/template/coding-task-manager/lib/feature-manifest.js +4 -0
  109. package/template/coding-task-manager/lib/fleet-conversation-route.js +97 -0
  110. package/template/coding-task-manager/lib/fleet-fanout.js +78 -0
  111. package/template/coding-task-manager/lib/fleet-hub.js +762 -0
  112. package/template/coding-task-manager/lib/fleet-origin-follower.js +252 -0
  113. package/template/coding-task-manager/lib/fleet-resolver-effects.js +147 -0
  114. package/template/coding-task-manager/lib/fleet-resolver-tick.js +148 -0
  115. package/template/coding-task-manager/lib/fleet-resolver.js +454 -0
  116. package/template/coding-task-manager/lib/fleet-session-list-routes.js +114 -0
  117. package/template/coding-task-manager/lib/fleet-session-lists.js +672 -0
  118. package/template/coding-task-manager/lib/fleet-update.js +798 -0
  119. package/template/coding-task-manager/lib/fs-watcher-root-watch.js +141 -0
  120. package/template/coding-task-manager/lib/fs-watcher.js +58 -42
  121. package/template/coding-task-manager/lib/harness-history-transition.js +50 -9
  122. package/template/coding-task-manager/lib/headless-term-service.js +84 -8
  123. package/template/coding-task-manager/lib/hermetic-agent-launch-guard.js +10 -0
  124. package/template/coding-task-manager/lib/history-transition-read-op.js +175 -8
  125. package/template/coding-task-manager/lib/host-cpu-categories.js +310 -0
  126. package/template/coding-task-manager/lib/host-fseventsd-sampler.js +399 -0
  127. package/template/coding-task-manager/lib/host-handoff.js +16 -19
  128. package/template/coding-task-manager/lib/host-stats.js +150 -3
  129. package/template/coding-task-manager/lib/hosted-sync-worker.js +43 -320
  130. package/template/coding-task-manager/lib/hub-bridge-access.js +798 -0
  131. package/template/coding-task-manager/lib/hub-bridge-box.js +409 -0
  132. package/template/coding-task-manager/lib/hub-bridge-mcp.js +380 -0
  133. package/template/coding-task-manager/lib/hub-bridge-mesh.js +313 -0
  134. package/template/coding-task-manager/lib/hub-bridge-ops.js +721 -0
  135. package/template/coding-task-manager/lib/hub-bridge.js +398 -0
  136. package/template/coding-task-manager/lib/idle-notify.js +491 -0
  137. package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +8 -0
  138. package/template/coding-task-manager/lib/instance-manifest.js +5 -1
  139. package/template/coding-task-manager/lib/instance-sync-status.js +18 -8
  140. package/template/coding-task-manager/lib/landing/agent-rule.txt +1 -0
  141. package/template/coding-task-manager/lib/landing/batch-runner.js +366 -0
  142. package/template/coding-task-manager/lib/landing/config.js +536 -0
  143. package/template/coding-task-manager/lib/landing/ctm-view.js +256 -0
  144. package/template/coding-task-manager/lib/landing/gate.js +360 -0
  145. package/template/coding-task-manager/lib/landing/git.js +344 -0
  146. package/template/coding-task-manager/lib/landing/lease.js +247 -0
  147. package/template/coding-task-manager/lib/landing/merge-delta.js +380 -0
  148. package/template/coding-task-manager/lib/landing/proof.js +223 -0
  149. package/template/coding-task-manager/lib/landing/queue.js +998 -0
  150. package/template/coding-task-manager/lib/landing/radar.js +489 -0
  151. package/template/coding-task-manager/lib/landing/resolve-cli.js +424 -0
  152. package/template/coding-task-manager/lib/landing/state.js +263 -0
  153. package/template/coding-task-manager/lib/landing/stop.js +49 -0
  154. package/template/coding-task-manager/lib/landing/sync-cli.js +475 -0
  155. package/template/coding-task-manager/lib/landing/sync.js +456 -0
  156. package/template/coding-task-manager/lib/landing/train.js +885 -0
  157. package/template/coding-task-manager/lib/landing/window.js +57 -0
  158. package/template/coding-task-manager/lib/launch-environment.js +121 -0
  159. package/template/coding-task-manager/lib/launch-model-override.js +36 -10
  160. package/template/coding-task-manager/lib/launch-plan-pool.js +2 -1
  161. package/template/coding-task-manager/lib/launch-plan-warm-cache.js +6 -0
  162. package/template/coding-task-manager/lib/lead-model-observer.js +57 -1
  163. package/template/coding-task-manager/lib/lead-model-options.js +160 -3
  164. package/template/coding-task-manager/lib/lead-model-restore-reconciliation.js +106 -24
  165. package/template/coding-task-manager/lib/lead-model-switch-runtime.js +352 -68
  166. package/template/coding-task-manager/lib/lead-model-switch.js +114 -10
  167. package/template/coding-task-manager/lib/lead-model-transition-runtime.js +14 -2
  168. package/template/coding-task-manager/lib/lead-model-transition-store.js +24 -6
  169. package/template/coding-task-manager/lib/lead-route-preflight.js +179 -0
  170. package/template/coding-task-manager/lib/lead-switch-history-mode.js +110 -0
  171. package/template/coding-task-manager/lib/lead-wire-agent.js +7 -0
  172. package/template/coding-task-manager/lib/lifecycle-wake-experiment.js +9 -2
  173. package/template/coding-task-manager/lib/live-defer-announce.js +45 -0
  174. package/template/coding-task-manager/lib/machine-registry.js +750 -5
  175. package/template/coding-task-manager/lib/macos-capabilities.js +32 -15
  176. package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +433 -53
  177. package/template/coding-task-manager/lib/mainloop-observability.js +14 -9
  178. package/template/coding-task-manager/lib/media-draft-owner.js +16 -3
  179. package/template/coding-task-manager/lib/memory-join.js +337 -0
  180. package/template/coding-task-manager/lib/memory-sync-verify.js +393 -0
  181. package/template/coding-task-manager/lib/memory-sync.js +565 -0
  182. package/template/coding-task-manager/lib/migrations/v57-delegate-pref-mirror-opencode.js +68 -0
  183. package/template/coding-task-manager/lib/migrations/v58-subagent-launch-native-subagents.js +42 -0
  184. package/template/coding-task-manager/lib/migrations/v59-coding-session-model-state-dsh.js +73 -0
  185. package/template/coding-task-manager/lib/migrations/v60-delegate-pref-mirror-dsh.js +78 -0
  186. package/template/coding-task-manager/lib/migrations/v61-conversation-item-clock.js +71 -0
  187. package/template/coding-task-manager/lib/model-availability.js +727 -0
  188. package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +4 -6
  189. package/template/coding-task-manager/lib/model-host-receipt.js +6 -3
  190. package/template/coding-task-manager/lib/model-id-rule.js +19 -0
  191. package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
  192. package/template/coding-task-manager/lib/model-proxy/auto-mode-review.js +110 -23
  193. package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
  194. package/template/coding-task-manager/lib/model-proxy/generation-probe.js +60 -17
  195. package/template/coding-task-manager/lib/model-proxy/historical-tool-declarations.js +37 -0
  196. package/template/coding-task-manager/lib/model-proxy/lead-request-validation.js +1 -0
  197. package/template/coding-task-manager/lib/model-proxy/lead-token-admin.js +130 -0
  198. package/template/coding-task-manager/lib/model-proxy/refusal-scope.js +151 -0
  199. package/template/coding-task-manager/lib/model-proxy/request-budget-store.js +11 -2
  200. package/template/coding-task-manager/lib/model-proxy/tokens.js +69 -5
  201. package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
  202. package/template/coding-task-manager/lib/native-agent-model-args.js +25 -22
  203. package/template/coding-task-manager/lib/native-history-control.js +6 -4
  204. package/template/coding-task-manager/lib/native-lead-settings-client.js +44 -4
  205. package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +173 -36
  206. package/template/coding-task-manager/lib/online-backup-worker-client.js +2 -0
  207. package/template/coding-task-manager/lib/opencode-cli.js +480 -0
  208. package/template/coding-task-manager/lib/opencode-launch-model.js +471 -0
  209. package/template/coding-task-manager/lib/opencode-v1-plugin/model-carrier.mjs +35 -0
  210. package/template/coding-task-manager/lib/opencode-v2-plugin/server.js +118 -0
  211. package/template/coding-task-manager/lib/owner-action-manifest-data.json +1 -1
  212. package/template/coding-task-manager/lib/park-composer-draft.js +54 -0
  213. package/template/coding-task-manager/lib/park-fresh-relaunch.js +41 -10
  214. package/template/coding-task-manager/lib/perf-phase-trace.js +72 -0
  215. package/template/coding-task-manager/lib/perf-summary.js +7 -0
  216. package/template/coding-task-manager/lib/perf-tracker.js +63 -2
  217. package/template/coding-task-manager/lib/project-config.js +7 -0
  218. package/template/coding-task-manager/lib/prompt-purge-v2.js +52 -1
  219. package/template/coding-task-manager/lib/provider-login-broker.js +72 -15
  220. package/template/coding-task-manager/lib/provider-login-tab.js +10 -2
  221. package/template/coding-task-manager/lib/read-pool-client.js +89 -2
  222. package/template/coding-task-manager/lib/read-pool-worker-handle.js +29 -4
  223. package/template/coding-task-manager/lib/recent-catalog-query.js +15 -0
  224. package/template/coding-task-manager/lib/recent-session-catalog-response.js +67 -10
  225. package/template/coding-task-manager/lib/recovery-evidence.js +26 -11
  226. package/template/coding-task-manager/lib/relay-client.js +57 -3
  227. package/template/coding-task-manager/lib/relink-audit.js +34 -5
  228. package/template/coding-task-manager/lib/remote-machine-catalog.js +321 -26
  229. package/template/coding-task-manager/lib/remote-machine-create.js +576 -36
  230. package/template/coding-task-manager/lib/remote-machine-link.js +546 -59
  231. package/template/coding-task-manager/lib/remote-machine-proxy.js +143 -9
  232. package/template/coding-task-manager/lib/remote-session-forward.js +65 -7
  233. package/template/coding-task-manager/lib/remote-terminal-target.js +9 -2
  234. package/template/coding-task-manager/lib/restart-guard.js +18 -6
  235. package/template/coding-task-manager/lib/restore-seed-modes.js +87 -0
  236. package/template/coding-task-manager/lib/restored-scrollback-hydration-runtime.js +22 -2
  237. package/template/coding-task-manager/lib/resume-admission.js +17 -3
  238. package/template/coding-task-manager/lib/review-repo-registry.js +58 -19
  239. package/template/coding-task-manager/lib/root-delivery-runtime.js +2 -2
  240. package/template/coding-task-manager/lib/root-prompt-flow.js +1 -1
  241. package/template/coding-task-manager/lib/runtime-contract.js +3 -1
  242. package/template/coding-task-manager/lib/schema-indexes.js +1 -0
  243. package/template/coding-task-manager/lib/session-context-locator.js +742 -0
  244. package/template/coding-task-manager/lib/session-create/attachment.js +2 -2
  245. package/template/coding-task-manager/lib/session-create/create-phases.js +118 -0
  246. package/template/coding-task-manager/lib/session-create/delegate-worker.js +86 -16
  247. package/template/coding-task-manager/lib/session-create/dsh-session.js +930 -0
  248. package/template/coding-task-manager/lib/session-create/lead-route-launch.js +186 -13
  249. package/template/coding-task-manager/lib/session-create/native-lead-lifetime.js +55 -3
  250. package/template/coding-task-manager/lib/session-create/opencode-lead-provider.js +50 -0
  251. package/template/coding-task-manager/lib/session-create/prepared.js +162 -38
  252. package/template/coding-task-manager/lib/session-create/provider-process.js +160 -28
  253. package/template/coding-task-manager/lib/session-create/response.js +7 -7
  254. package/template/coding-task-manager/lib/session-create/structured-session.js +27 -0
  255. package/template/coding-task-manager/lib/session-create/subagent-pick-table.js +3 -1
  256. package/template/coding-task-manager/lib/session-create/subagent-pick.js +458 -9
  257. package/template/coding-task-manager/lib/session-create/transcript.js +1 -1
  258. package/template/coding-task-manager/lib/session-create/worker-budget-setup.js +21 -2
  259. package/template/coding-task-manager/lib/session-create/worker-continuation.js +7 -1
  260. package/template/coding-task-manager/lib/session-create/worker-launch-sandbox.js +39 -10
  261. package/template/coding-task-manager/lib/session-create/worker-observability.js +2 -2
  262. package/template/coding-task-manager/lib/session-empty.js +13 -10
  263. package/template/coding-task-manager/lib/session-host-manager.js +60 -0
  264. package/template/coding-task-manager/lib/session-jobs.js +3 -1
  265. package/template/coding-task-manager/lib/session-lifecycle.js +10 -4
  266. package/template/coding-task-manager/lib/session-model-action-preconditions.js +6 -2
  267. package/template/coding-task-manager/lib/session-model-intent-contract.js +11 -8
  268. package/template/coding-task-manager/lib/session-park.js +738 -0
  269. package/template/coding-task-manager/lib/session-path-grant.js +13 -4
  270. package/template/coding-task-manager/lib/session-status-ledger.js +106 -4
  271. package/template/coding-task-manager/lib/session-transport.js +17 -0
  272. package/template/coding-task-manager/lib/session-workspace-projection.js +54 -5
  273. package/template/coding-task-manager/lib/session-workspace-tracking-runtime.js +213 -1
  274. package/template/coding-task-manager/lib/skill-autocomplete-query.js +120 -3
  275. package/template/coding-task-manager/lib/skill-autocomplete.js +15 -1
  276. package/template/coding-task-manager/lib/sqlite-file-set.js +39 -0
  277. package/template/coding-task-manager/lib/standup-search-adapter.js +16 -2
  278. package/template/coding-task-manager/lib/state-sync/client-ledger.js +12 -0
  279. package/template/coding-task-manager/lib/state-sync/frame-emitter.js +319 -100
  280. package/template/coding-task-manager/lib/storage/coding-session-model-store.js +4 -1
  281. package/template/coding-task-manager/lib/storage/delegate-pref-mirror-store.js +32 -9
  282. package/template/coding-task-manager/lib/structured-session-boot-sweep.js +235 -0
  283. package/template/coding-task-manager/lib/submission-ack.js +90 -2
  284. package/template/coding-task-manager/lib/systemd-scope.js +115 -0
  285. package/template/coding-task-manager/lib/telemetry-receiver.js +39 -0
  286. package/template/coding-task-manager/lib/terminal-attach-geometry.js +985 -0
  287. package/template/coding-task-manager/lib/terminal-bootstrap.js +30 -0
  288. package/template/coding-task-manager/lib/terminal-draft-operation.js +357 -0
  289. package/template/coding-task-manager/lib/terminal-input-admission.js +17 -1
  290. package/template/coding-task-manager/lib/terminal-input-prepared.js +563 -0
  291. package/template/coding-task-manager/lib/transcript-cache-temps.js +171 -0
  292. package/template/coding-task-manager/lib/transcript-frame-cache.js +8 -3
  293. package/template/coding-task-manager/lib/transcript-source.js +36 -4
  294. package/template/coding-task-manager/lib/transcript-store.js +9 -0
  295. package/template/coding-task-manager/lib/typing-interaction-trace.js +106 -3
  296. package/template/coding-task-manager/lib/usage-ledger/backfill.js +40 -5
  297. package/template/coding-task-manager/lib/usage-ledger/client.js +4 -1
  298. package/template/coding-task-manager/lib/usage-ledger/dsh-parse.js +152 -0
  299. package/template/coding-task-manager/lib/usage-ledger/dsh-read.js +73 -0
  300. package/template/coding-task-manager/lib/usage-ledger/ingest.js +34 -6
  301. package/template/coding-task-manager/lib/usage-ledger/live.js +35 -8
  302. package/template/coding-task-manager/lib/usage-ledger/read.js +29 -20
  303. package/template/coding-task-manager/lib/usage-ledger/schema.js +61 -1
  304. package/template/coding-task-manager/lib/usage-ledger/task-coordinator.js +4 -2
  305. package/template/coding-task-manager/lib/wake-skip-reasons.js +1 -0
  306. package/template/coding-task-manager/lib/walle/turn.js +1 -1
  307. package/template/coding-task-manager/lib/walle-history-serve.js +838 -0
  308. package/template/coding-task-manager/lib/walle-kill-authority.js +2 -2
  309. package/template/coding-task-manager/lib/walle-log-rotation.js +164 -1
  310. package/template/coding-task-manager/lib/walle-mcp-auto-config.js +56 -2
  311. package/template/coding-task-manager/lib/walle-row-history.js +495 -0
  312. package/template/coding-task-manager/lib/walle-supervisor.js +33 -14
  313. package/template/coding-task-manager/lib/watch-worker-client.js +203 -0
  314. package/template/coding-task-manager/lib/worker-terminal-output.js +5 -2
  315. package/template/coding-task-manager/lib/ws/hub-bridge.js +35 -0
  316. package/template/coding-task-manager/lib/ws/lifecycle.js +6 -11
  317. package/template/coding-task-manager/lib/ws/misc.js +1 -1
  318. package/template/coding-task-manager/lib/ws/state-sync.js +106 -4
  319. package/template/coding-task-manager/lib/ws/terminal-attach.js +91 -0
  320. package/template/coding-task-manager/oauth-proxy.js +112 -115
  321. package/template/coding-task-manager/package-lock.json +10 -94
  322. package/template/coding-task-manager/package.json +4 -3
  323. package/template/coding-task-manager/protocol/message-table.json +10 -0
  324. package/template/coding-task-manager/protocol/messages.js +10 -0
  325. package/template/coding-task-manager/protocol/ws-schema.json +20 -0
  326. package/template/coding-task-manager/protocol/ws-schema.md +2 -0
  327. package/template/coding-task-manager/public/css/app.css +170 -0
  328. package/template/coding-task-manager/public/css/walle-session.css +4 -0
  329. package/template/coding-task-manager/public/index.html +473 -243
  330. package/template/coding-task-manager/public/js/agent-command.js +86 -0
  331. package/template/coding-task-manager/public/js/app/backups-panel.js +111 -5
  332. package/template/coding-task-manager/public/js/app/coding-agent-upgrade.js +103 -4
  333. package/template/coding-task-manager/public/js/app/machines-page.js +1328 -8
  334. package/template/coding-task-manager/public/js/app/models-tab.js +113 -38
  335. package/template/coding-task-manager/public/js/app/restart-banner.js +53 -0
  336. package/template/coding-task-manager/public/js/app/worktrees-panel.js +184 -2
  337. package/template/coding-task-manager/public/js/background-work.js +196 -27
  338. package/template/coding-task-manager/public/js/coding-session-model-presentation.js +138 -10
  339. package/template/coding-task-manager/public/js/core/active-session-groups.js +179 -0
  340. package/template/coding-task-manager/public/js/core/pending-create.js +238 -0
  341. package/template/coding-task-manager/public/js/core/recent-machine-source.js +228 -0
  342. package/template/coding-task-manager/public/js/core/session-commands.js +180 -14
  343. package/template/coding-task-manager/public/js/dashboard-client-function-order.json +8 -0
  344. package/template/coding-task-manager/public/js/document-review-links.js +9 -1
  345. package/template/coding-task-manager/public/js/file-resolution-client.js +52 -1
  346. package/template/coding-task-manager/public/js/history-app-seam.js +22 -2
  347. package/template/coding-task-manager/public/js/machine-pool-shared.js +558 -3
  348. package/template/coding-task-manager/public/js/message-renderer.js +4 -3
  349. package/template/coding-task-manager/public/js/model-picker.js +3 -1
  350. package/template/coding-task-manager/public/js/native-subagent-review.js +15 -2
  351. package/template/coding-task-manager/public/js/new-session-agent-grid.js +346 -0
  352. package/template/coding-task-manager/public/js/pasted-content.js +236 -0
  353. package/template/coding-task-manager/public/js/pe-private-content-lifetime.js +39 -7
  354. package/template/coding-task-manager/public/js/private-model-lifetime.js +6 -2
  355. package/template/coding-task-manager/public/js/prompts.js +11 -10
  356. package/template/coding-task-manager/public/js/protocol.js +10 -0
  357. package/template/coding-task-manager/public/js/restart-banner-policy.js +29 -1
  358. package/template/coding-task-manager/public/js/session-model-picker.js +447 -57
  359. package/template/coding-task-manager/public/js/session-search-utils.js +18 -2
  360. package/template/coding-task-manager/public/js/session-usage-view.js +2 -1
  361. package/template/coding-task-manager/public/js/session-workspace-tracking.js +51 -1
  362. package/template/coding-task-manager/public/js/state-sync-client.js +10 -1
  363. package/template/coding-task-manager/public/js/stream-view.js +6 -5
  364. package/template/coding-task-manager/public/js/terminal/conv-only-session.js +287 -0
  365. package/template/coding-task-manager/public/js/terminal/runtime-09.js +2 -0
  366. package/template/coding-task-manager/public/js/terminal/runtime-10.js +5 -5
  367. package/template/coding-task-manager/public/js/terminal/runtime-12.js +8 -1
  368. package/template/coding-task-manager/public/js/terminal/runtime-16.js +4 -0
  369. package/template/coding-task-manager/public/js/terminal/runtime-20.js +1 -1
  370. package/template/coding-task-manager/public/js/terminal-attachment-draft.js +67 -13
  371. package/template/coding-task-manager/public/js/terminal-image-orchestration.js +52 -6
  372. package/template/coding-task-manager/public/js/terminal-wheel.js +23 -3
  373. package/template/coding-task-manager/public/js/walle/chat-conversation.js +4 -4
  374. package/template/coding-task-manager/public/js/walle.js +6 -0
  375. package/template/coding-task-manager/public/js/ws/live-dispatch.js +10 -0
  376. package/template/coding-task-manager/public/m/app.css +140 -0
  377. package/template/coding-task-manager/public/m/app.js +507 -68
  378. package/template/coding-task-manager/public/m/index.html +17 -0
  379. package/template/coding-task-manager/public/m/machines.js +838 -4
  380. package/template/coding-task-manager/public/m/private-api.js +31 -1
  381. package/template/coding-task-manager/public/usage.html +1 -0
  382. package/template/coding-task-manager/scripts/dev-route-fixture/synthetic-route-upstream.js +104 -0
  383. package/template/coding-task-manager/scripts/dev-route-fixture.js +339 -0
  384. package/template/coding-task-manager/scripts/opencode-lead-route-probe.js +195 -0
  385. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/fake-anthropic.js +168 -0
  386. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/probe-plugin/server.js +95 -0
  387. package/template/coding-task-manager/scripts/opencode-v2-contract-probe.js +673 -0
  388. package/template/coding-task-manager/server.js +1950 -11679
  389. package/template/coding-task-manager/session-integrity.js +64 -4
  390. package/template/coding-task-manager/workers/db-owner-worker.js +19 -2
  391. package/template/coding-task-manager/workers/online-backup-worker.js +1 -0
  392. package/template/coding-task-manager/workers/read-pool-model-collector.js +51 -3
  393. package/template/coding-task-manager/workers/read-pool-worker.js +76 -6
  394. package/template/coding-task-manager/workers/session-host-pool-process.js +6 -6
  395. package/template/coding-task-manager/workers/session-host-process.js +5 -5
  396. package/template/coding-task-manager/workers/watch-worker.js +105 -0
  397. package/template/coding-task-manager/workers/worktree-worker.js +168 -33
  398. package/template/ctm-relay/lib/protocol.js +14 -1
  399. package/template/package-lock.json +2 -2
  400. package/template/package.json +1 -1
  401. package/template/shared/backup-retention.js +82 -0
  402. package/template/shared/conversation-admission.js +2 -0
  403. package/template/shared/conversation-provenance.js +3 -7
  404. package/template/shared/conversation-storage-v2-contract.js +5 -0
  405. package/template/shared/linked-worktree.js +51 -0
  406. package/template/shared/macos-fda-target.js +57 -0
  407. package/template/shared/orphan-parents.js +55 -0
  408. package/template/shared/release-schema.json +2 -2
  409. package/template/shared/storage/contract.js +3 -0
  410. package/template/wall-e/adapters/imessage.js +12 -0
  411. package/template/wall-e/agent.js +71 -4
  412. package/template/wall-e/api-walle.js +21 -1
  413. package/template/wall-e/bin/train-gemma-e4b-tooluse.js +2 -2
  414. package/template/wall-e/bin/walle-mcp-stdio.js +5 -5
  415. package/template/wall-e/brain/brain-join.js +859 -0
  416. package/template/wall-e/brain/brain-sync-membership.js +20 -0
  417. package/template/wall-e/brain/brain-sync-store.js +131 -77
  418. package/template/wall-e/brain/brain-sync-v2-schema.js +203 -0
  419. package/template/wall-e/brain/brain-sync-v2.js +578 -0
  420. package/template/wall-e/brain/delegate-model-prefs-store.js +13 -4
  421. package/template/wall-e/brain/deterministic-id.js +51 -0
  422. package/template/wall-e/brain/memories.js +2 -2
  423. package/template/wall-e/brain/migrations.js +40 -6
  424. package/template/wall-e/brain/model-identity-migration.js +1 -1
  425. package/template/wall-e/brain/owner-call-whitelist.js +23 -7
  426. package/template/wall-e/brain/schema.js +45 -85
  427. package/template/wall-e/brain.js +171 -35
  428. package/template/wall-e/chat.js +3 -3
  429. package/template/wall-e/coding/agent-shell-env.js +7 -2
  430. package/template/wall-e/coding/prompt-bundle.js +66 -21
  431. package/template/wall-e/config/main-loop-exemptions.json +2 -2
  432. package/template/wall-e/http/admin-api.js +37 -0
  433. package/template/wall-e/http/gws-api.js +4 -0
  434. package/template/wall-e/http/helper-rules-api.js +7 -1
  435. package/template/wall-e/http/model-admin.js +8 -1
  436. package/template/wall-e/http/model-delegate-pref-admin.js +3 -3
  437. package/template/wall-e/http/model-proxy-providers.js +174 -1
  438. package/template/wall-e/http/model-route-health.js +157 -0
  439. package/template/wall-e/http/sync-api.js +278 -464
  440. package/template/wall-e/jobs/job-runner.js +28 -1
  441. package/template/wall-e/lib/brain-owner-op-priority.js +9 -1
  442. package/template/wall-e/lib/ctm-data-dir.js +26 -0
  443. package/template/wall-e/lib/derivation-home.js +147 -0
  444. package/template/wall-e/lib/helper-rules/evaluate.js +50 -9
  445. package/template/wall-e/lib/helper-rules/grade.js +51 -8
  446. package/template/wall-e/lib/helper-rules/lead-call-hook.js +38 -5
  447. package/template/wall-e/lib/helper-rules/store.js +4 -2
  448. package/template/wall-e/lib/landing-mcp-tools.js +170 -0
  449. package/template/wall-e/lib/mcp-client-config.js +133 -14
  450. package/template/wall-e/lib/mcp-gateway-migrate.js +28 -64
  451. package/template/wall-e/lib/mcp-integration.js +58 -13
  452. package/template/wall-e/lib/parent-death.js +7 -1
  453. package/template/wall-e/lib/scheduler-worker-jobs.js +6 -4
  454. package/template/wall-e/llm/delegate-lead-prefs.js +16 -1
  455. package/template/wall-e/llm/delegate-vendor-default.js +12 -5
  456. package/template/wall-e/llm/model-roles.js +1 -1
  457. package/template/wall-e/llm/native-delegate-selection.js +56 -8
  458. package/template/wall-e/llm/worker-delegate-args.js +72 -7
  459. package/template/wall-e/llm/worker-mcp-routing.js +66 -17
  460. package/template/wall-e/loops/brain-custom-writes.js +19 -0
  461. package/template/wall-e/loops/ingest.js +17 -1
  462. package/template/wall-e/loops/think.js +19 -4
  463. package/template/wall-e/mcp-contract.js +222 -6
  464. package/template/wall-e/mcp-protocol-contract.js +40 -5
  465. package/template/wall-e/mcp-server.js +128 -29
  466. package/template/wall-e/mcp-worker-schemas.js +5 -5
  467. package/template/wall-e/memory/ctm-context-client.js +85 -0
  468. package/template/wall-e/memory/ctm-session-context.js +9 -3
  469. package/template/wall-e/memory/hub-bridge-client.js +388 -0
  470. package/template/wall-e/memory/replica-origin.js +56 -0
  471. package/template/wall-e/memory/session-pool.js +135 -0
  472. package/template/wall-e/runtime/live-capabilities.js +8 -3
  473. package/template/wall-e/server.js +4 -2
  474. package/template/wall-e/shared/release-schema.json +2 -2
  475. package/template/wall-e/shared/sqlite-file-set.js +39 -0
  476. package/template/wall-e/shared/storage/contract.js +3 -0
  477. package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
  478. package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +7 -1
  479. package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +4 -4
  480. package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +6 -6
  481. package/template/wall-e/skills/_templates/fleet-sync/VERSION +1 -0
  482. package/template/wall-e/skills/_templates/fleet-sync/released-sha256.json +16 -0
  483. package/template/wall-e/skills/_templates/fleet-sync/templates/claude/SKILL.md +64 -0
  484. package/template/wall-e/skills/_templates/fleet-sync/templates/codex/SKILL.md +64 -0
  485. package/template/wall-e/tools/chrome-automation.js +6 -0
  486. package/template/wall-e/training/setup-cuda-train-env.sh +2 -2
  487. package/template/wall-e/workers/brain-owner-worker.js +18 -4
  488. package/template/wall-e/workers/mcp-gateway-process.js +5 -5
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { registerApiRoutes } = require('../api-router');
4
+ const remoteMachineCatalog = require('../remote-machine-catalog');
4
5
 
5
6
  let _deps = null;
6
7
 
@@ -107,9 +108,16 @@ function _maybeNotifyDelegatePrefMutation(req, res, url) {
107
108
  });
108
109
  }
109
110
 
110
- function handleProxy(req, res, url) {
111
+ async function handleProxy(req, res, url) {
111
112
  _maybeNotifyProviderMutation(req, res, url);
112
113
  _maybeNotifyDelegatePrefMutation(req, res, url);
114
+ // WP-3 read + WP-1 writes (docs/remote-session-delegate-pick-write-forward-2026-10-30.html): a
115
+ // box-owned session's delegate pick is read from — and its per-session / per-agent writes are
116
+ // stored on — the box that owns it.
117
+ if (url && (url.pathname === '/api/models/delegate-prefs' || DELEGATE_PREF_SCOPE_RE.test(url.pathname))) {
118
+ const id = String(url.searchParams.get('ctm_session_id') || '');
119
+ if (id && await remoteMachineCatalog.forwardDelegatePrefsRequest(req, res, id)) return undefined;
120
+ }
113
121
  return _deps.walleClient.proxyHttp(req, res, {
114
122
  port: _deps.wallePort,
115
123
  unavailableContext: () => _deps.getWalleSupervisorStatus(),
@@ -226,7 +226,10 @@ function createAuthorityReportReconcilerDispatch(deps = {}) {
226
226
  // caller that only cares about the diagnostic-only shape (WP-5's own tests) still works
227
227
  // unmodified.
228
228
  executeAttachmentTeardown = () => {},
229
- // Route-dead rung: asks the client to re-run its own gated bootstrap request.
229
+ // Route-dead rung: asks the client to re-run its own gated bootstrap request. A bootstrap is
230
+ // lease-neutral (server.js:40958-40966: a ROUTE RESET, not a departure -- geometry lease,
231
+ // primary role and measured dims stay intact), so holding the lease is NOT part of the
232
+ // route-dead predicate; `leaseOwnerMatches` is only threaded through for the diagnostic.
230
233
  rebootstrapRoute = () => ({ sent: false }),
231
234
  now = () => Date.now(),
232
235
  } = deps;
@@ -243,7 +246,7 @@ function createAuthorityReportReconcilerDispatch(deps = {}) {
243
246
  function routeRebootstrapStep({ ws, sessionId, details, clientIdStr, leaseOwnerMatches, ptyAlive, lockedSinceMs }) {
244
247
  const key = _keyFor(clientIdStr, sessionId);
245
248
  const routeDead = details?.blocker === 'route_unavailable' && details?.routeLive === false
246
- && ptyAlive === true && leaseOwnerMatches === true;
249
+ && ptyAlive === true;
247
250
  if (!routeDead) { routeEpisodes.delete(key); return null; }
248
251
  const t = now();
249
252
  for (const [k, e] of routeEpisodes) if (t - e.lastReportAt >= ROUTE_EPISODE_TTL_MS) routeEpisodes.delete(k);
@@ -5,6 +5,15 @@
5
5
  // low-level limiter behind the rule tables (and their consumers) for a one-string comparison.
6
6
  const PEER_CONTROL_SCOPE = 'peer-control';
7
7
 
8
+ // WP-1 (docs/remote-relay-ack-rate-limit-typing-delay-2026-10-28.html §5 D-2, §9 S-2): the one
9
+ // rate kind that is NOT a bucket. A rule row carrying `rateKind: 'credit'` declares a message that
10
+ // is the sender's PERMISSION to keep sending (an SSH-style window/ack credit, RFC 4254 §5.2), so
11
+ // charging it to a token bucket stalls the sender instead of protecting the box. Only the WS `ack`
12
+ // row carries it today. `_rateLimitDecision` short-circuits this kind to `{ ok: true }`, so this
13
+ // module deliberately HAS NO `credit` bucket and `AuthRateLimiter.check('credit', …)` is never
14
+ // reached (see server.js `_rateLimitDecision`).
15
+ const RATE_KIND_CREDIT = 'credit';
16
+
8
17
  const DEFAULT_LIMITS = Object.freeze({
9
18
  // Remote/mobile page bootstrap fans out across settings, sessions, standup,
10
19
  // auth state, WebSocket setup, and cached refresh probes. Keep read traffic
@@ -22,6 +31,13 @@ const DEFAULT_LIMITS = Object.freeze({
22
31
  // authenticated `peer-control` principal (see rateKindForRule below); every other caller keeps
23
32
  // the exact bucket it had before.
24
33
  peer: { refillPerMinute: 600, burst: 120 },
34
+ // receipt (WP-1, docs/remote-relay-ack-rate-limit-typing-delay-2026-10-28.html §5 D-3): the
35
+ // diagnostic frame receipts (`frame-receipt`). They are NOT credit — each one can persist a
36
+ // `maybePersistFrameApplyReceipt` row — but refusing one loses telemetry ONLY, so they get their
37
+ // own bucket instead of sharing the hub-wide `default` one, which is what let 153 relayed
38
+ // receipts in 33 min compete with the acks of the same principal. 3× the `default` refill
39
+ // because a frame carries up to 2 receipts versus 1 ack (§1c); burst 300 ≈ 5 s of 60 fps output.
40
+ receipt: { refillPerMinute: 1800, burst: 300 },
25
41
  // machine_pair (WP-3, docs/machine-pool-picker-pairing-dashboard-2026-10-24.html §6.3/D-13): the
26
42
  // PRE-AUTH POST /api/machine-pairing/join. `sync`'s own bucket. It is the ONLY bucket selected by
27
43
  // route rather than by principal: the join has no authenticated caller yet (the request carries the
@@ -168,6 +184,12 @@ class AuthRateLimiter {
168
184
  */
169
185
  function rateKindForRule(rule, pathname = '', auth = null) {
170
186
  if (pathname === '/api/auth/begin-step-up') return 'step_up';
187
+ // WP-1 (§5 D-2/D-3, §9 S-1): a rule that declares its own kind wins over the mutation-scope
188
+ // cascade below — `credit` (never charged; the caller short-circuits) and `receipt` (its own
189
+ // bucket). Checked BEFORE the `!rule.mutation → 'default'` line so a relayed read-shaped message
190
+ // is no longer dumped into the hub-wide `default` bucket keyed by the single hub principal (the
191
+ // root cause: 190 acks refused in 33 min). No HTTP rule carries `rateKind`, so HTTP is unchanged.
192
+ if (rule?.rateKind === RATE_KIND_CREDIT || rule?.rateKind === 'receipt') return rule.rateKind;
171
193
  if (!rule?.mutation) return 'default';
172
194
  const scopes = auth && auth.scopes;
173
195
  const isPeerControl = scopes instanceof Set
@@ -183,6 +205,7 @@ module.exports = {
183
205
  DEFAULT_FAILED_AUTH,
184
206
  DEFAULT_LIMITS,
185
207
  IP_LOCK_AUTH_FAILURE_CODES,
208
+ RATE_KIND_CREDIT,
186
209
  normalizeAuthFailureCode,
187
210
  normalizeIpLockKey,
188
211
  rateKindForRule,
@@ -47,8 +47,17 @@ const WS_AUTH_RULES = Object.freeze({
47
47
  // State-sync render protocol: clients acknowledge frames, request bounded
48
48
  // keyframes, and report visible sessions. These only affect that viewer's
49
49
  // stream/backpressure state, not agent execution or persisted session data.
50
- ack: peerControl('read', false, 'never'),
51
- 'frame-receipt': peerControl('read', false, 'never'),
50
+ //
51
+ // WP-1 (docs/remote-relay-ack-rate-limit-typing-delay-2026-10-28.html §5 D-2/D-3, §9 S-3): an
52
+ // `ack` is the flow-control CREDIT for a frame this box itself sent (it is a no-op unless
53
+ // `seq === inFlightSeq`), so it is never charged to a token bucket — refusing it stalls the
54
+ // sender, which is how 190 relayed acks were refused in 33 min on the Spark box and each
55
+ // refusal waited out the fixed 3 s lost-ack sweep. `frame-receipt` is diagnostics + a DB
56
+ // write (`maybePersistFrameApplyReceipt`), so it keeps a bucket, but its OWN (`receipt`), so
57
+ // receipt overflow can never starve acks or `input`. Both rows otherwise keep their §6.2
58
+ // tuple (read / no mutation / never step-up) — `rateKind` is additive.
59
+ ack: peerControl('read', false, 'never', { rateKind: 'credit' }),
60
+ 'frame-receipt': peerControl('read', false, 'never', { rateKind: 'receipt' }),
52
61
  'keyframe-req': peerControl('read', false, 'never'),
53
62
  'restore-applied': rule('read', false, 'never'),
54
63
  // D-2/WP-2 verdict/adopt round-trip ack — same viewer-local render-protocol
@@ -62,7 +71,7 @@ const WS_AUTH_RULES = Object.freeze({
62
71
  'terminal-bootstrap': peerControl('read', false, 'never'),
63
72
  'terminal-bootstrap-ack': peerControl('read', false, 'never'),
64
73
  'session-inventory': rule('read', false, 'never'),
65
- 'terminal-geometry-claim-v2': rule('read', false, 'never'),
74
+ 'terminal-geometry-claim-v2': peerControl('read', false, 'never'),
66
75
  'secondary-snapshot-retry': rule('read', false, 'never'),
67
76
  // Wake paint acknowledgement closes the viewer-local wake timing span. It
68
77
  // carries no PTY input and does not mutate durable session state.
@@ -129,6 +138,13 @@ const WS_AUTH_RULES = Object.freeze({
129
138
  'update-session-cwd': rule('admin', true, 'remote'),
130
139
  'session-surface-preference': rule('admin', true, 'remote'),
131
140
  'model-change': peerControl('admin', true, 'remote'),
141
+ // WP-0 (docs/remote-session-hub-bridge-2026-10-30.html §5 R-2, §6.1, §8 WP-0): the two frames a
142
+ // BOX receives on the socket the HUB dialled — the hub's own identity handshake and its reply to a
143
+ // box `hub-bridge-request`. Read scope, non-mutation, never step-up: they carry no command, only
144
+ // routing. `peerControl` is what admits them: an ordinary device/admin socket is refused, so only
145
+ // the hub's CONTROL link can register itself for the box -> hub lane.
146
+ 'hub-bridge-hello': peerControl('read', false, 'never'),
147
+ 'hub-bridge-response': peerControl('read', false, 'never'),
132
148
  });
133
149
 
134
150
  const HTTP_AUTH_RULES = Object.freeze([
@@ -174,11 +190,17 @@ const HTTP_AUTH_RULES = Object.freeze([
174
190
  // image-draft family a hub forwards for a MIRROR session. Only the `peerControl` flag is added —
175
191
  // scope, mutation and step-up are unchanged for every other caller — exactly like the hub §6.2 rows.
176
192
  regex('GET', /^\/api\/sessions\/[^/]+\/image-drafts(?:\/[^/]+\/content)?$/, 'read', false, 'never', { peerControl: true }),
177
- regex('GET', /^\/api\/sessions\/[^/]+\/native-subagents\/[^/]+\/messages$/, 'read', false, 'never'),
193
+ // WP-1 (docs/remote-session-child-transcript-model-truth-and-restart-2026-10-27.html §5 D-2, §8
194
+ // WP-1, §9 S-6): the child transcript and the native runtime live on the BOX that owns a mirror
195
+ // session, so the review read is forwarded over the peer bearer. Flag only — scope/mutation/step-up
196
+ // are byte-for-byte what every other caller is evaluated against.
197
+ regex('GET', /^\/api\/sessions\/[^/]+\/native-subagents\/[^/]+\/messages$/, 'read', false, 'never', { peerControl: true }),
178
198
  // WP-0 (docs/exited-worker-transcript-view-2026-10-17.html §6c): a routed worker's own read-only
179
199
  // transcript page. Same posture as its native sibling -- GET, read scope, non-mutation, never
180
200
  // step-up. Worker lifecycle (resume/kill/retire) stays on its own stronger rules.
181
- regex('GET', /^\/api\/sessions\/[^/]+\/worker-transcript\/messages$/, 'read', false, 'never'),
201
+ // WP-1 (docs/remote-session-child-transcript-model-truth-and-restart-2026-10-27.html §5 D-2): a
202
+ // BOX-owned lead's routed-worker transcript is read on the box too, over the same peer bearer.
203
+ regex('GET', /^\/api\/sessions\/[^/]+\/worker-transcript\/messages$/, 'read', false, 'never', { peerControl: true }),
182
204
  regex('POST', /^\/api\/sessions\/[^/]+\/image-drafts$/, 'respond', true, 'remote', { peerControl: true }),
183
205
  regex('PUT', /^\/api\/sessions\/[^/]+\/image-drafts\/[^/]+$/, 'respond', true, 'remote', { peerControl: true }),
184
206
  regex('DELETE', /^\/api\/sessions\/[^/]+\/image-drafts$/, 'respond', true, 'remote', { peerControl: true }),
@@ -215,6 +237,41 @@ const HTTP_AUTH_RULES = Object.freeze([
215
237
  exact('GET', '/api/machines', 'read', false, 'never'),
216
238
  exact('POST', '/api/machines', 'admin', true, 'remote'),
217
239
  regex('POST', /^\/api\/machines\/[^/]+\/remove$/, 'admin', true, 'remote'),
240
+ // WP-8 (docs/remote-agent-skills-bundles-2026-10-25.html §5 D-12/D-13, §6.5, AC-8a..AC-8d): the
241
+ // ONE-SKILL exchange, hub side. Import WRITES into the hub user's own skill root (D-12: an explicit,
242
+ // reviewed act, with a backup) and retire moves the box's copy aside (D-13) — so both are the same
243
+ // admin + step-up remote tuple as POST /api/machines, NOT loopbackOnly (a phone reaches a member
244
+ // through the hub's ?machine= proxy), and NOT peerControl (the peer bearer is for machine-to-machine
245
+ // calls; these are hub-local user acts — pinning it false is what keeps
246
+ // tests/peer-control-auth.test.js's exact set honest). The exclude-plugins row edits one hub-side
247
+ // file's list for this machine, so it carries the same tuple.
248
+ regex('POST', /^\/api\/machines\/[^/]+\/skills\/(?:import|retire)$/, 'admin', true, 'remote'),
249
+ regex('PUT', /^\/api\/machines\/[^/]+\/skills\/exclude-plugins$/, 'admin', true, 'remote'),
250
+ // WP-4 (docs/remote-box-model-access-2026-10-26.html §6.4): the HUB end of "Remove from <box>" —
251
+ // it deletes rows on ANOTHER machine (which is exactly why the hub must not do it locally), so it
252
+ // is the same admin + step-up remote tuple as its neighbours and NOT peerControl: the peer bearer
253
+ // is for machine-to-machine calls, and this is a hub-local user act (the human did the passkey
254
+ // ceremony on the hub; tests/peer-control-auth.test.js pins the unflagged set). The regex is
255
+ // byte-identical to lib/api/machines.js's registration.
256
+ regex('POST', /^\/api\/machines\/[^/]+\/models\/remove$/, 'admin', true, 'remote'),
257
+ // WP-5 (docs/remote-box-model-access-2026-10-26.html §5.1 R-5/R-6, §6.4): the HUB end of "Use on
258
+ // <box>" — it moves ONE route's credential to ANOTHER machine, so it is the same admin + step-up
259
+ // remote tuple as the remove row above and NOT peerControl (the human did the passkey ceremony on
260
+ // the hub, and the peer bearer is for machine-to-machine calls). The regex is byte-identical to
261
+ // lib/api/machines.js's registration.
262
+ regex('POST', /^\/api\/machines\/[^/]+\/models\/copy$/, 'admin', true, 'remote'),
263
+ // …and the list it is driven by: read-only (nothing is written on either machine, no key is
264
+ // returned — the hub's own list already strips them), so no ceremony, exactly like the skills
265
+ // preview row above. Same regex spelling as the registration.
266
+ regex('GET', /^\/api\/machines\/[^/]+\/models\/copyable$/, 'admin', false, 'never'),
267
+ // WP-9 (docs/remote-agent-skills-bundles-2026-10-25.html §9 S-9, AC-9b): the REVIEW dialog's diff
268
+ // source — the box's copy of one skill and the hub's own, read side by side. It WRITES nothing on
269
+ // either side (mutation false) and needs no ceremony (stepUp 'never'), but it does read both
270
+ // machines' skill trees into a response the browser renders, so it is not a plain `read` scope: the
271
+ // same admin shape as its neighbours, minus the step-up. NOT peerControl — the peer bearer is for
272
+ // machine-to-machine calls, and the dialog is a hub-local user act (tests/peer-control-auth.test.js
273
+ // pins the unflagged set). The regex is byte-identical to lib/api/machines.js's registration.
274
+ regex('GET', /^\/api\/machines\/[^/]+\/skills\/preview$/, 'admin', false, 'never'),
218
275
  // WP-3 (machine-pool-picker-pairing-dashboard-2026-10-24.html §6.3, D-13, §9 S-16): the MEMBER
219
276
  // side of pairing — this machine joins a pool by redeeming the box's code. It mints nothing and
220
277
  // reads nothing back, but it adopts a shared secret and rewrites this member's roster, so it is
@@ -233,6 +290,19 @@ const HTTP_AUTH_RULES = Object.freeze([
233
290
  // bearer — peerControl: true. Guest/user scope is `read`/never on GET (nothing here is a secret)
234
291
  // and admin + step-up remote on POST. lib/api/machine-pool.js refuses a non-peer on the pool rows.
235
292
  exact('GET', '/api/machine-self', 'read', false, 'never', { peerControl: true }),
293
+ // WP-0 (docs/fleet-auto-update-pooled-machines-2026-10-26.html §6, §8 WP-0, §9 S-4): this
294
+ // machine's own checkout status (channel/branch/clean + the restart guard's blocking count). A hub
295
+ // reads it to decide whether the box may be updated, so the row must admit the peer bearer —
296
+ // peerControl: true. Read scope, no step-up, NOT loopbackOnly: the payload is a git branch name and
297
+ // a count, and the caller is a paired machine. Non-mutating, so no step-up substitution is in play
298
+ // (nothing here writes).
299
+ exact('GET', '/api/fleet/status', 'read', false, 'never', { peerControl: true }),
300
+ // WP-1 (docs/fleet-auto-update-pooled-machines-2026-10-26.html §6, §8 WP-1, §9 S-6): the hub PUSHES
301
+ // one fast-forward bundle (D-3) for this box to apply (D-4). The most powerful write in the fleet —
302
+ // it moves a git ref and spawns the detached apply helper — so it is `admin` + step-up 'remote',
303
+ // exactly like every other peerControl MUTATION row (auth-stepup-matrix.test.js pins that a human
304
+ // admin still needs a passkey for it); the paired-machine peer bearer is the intended caller.
305
+ exact('POST', '/api/fleet/bundle', 'admin', true, 'remote', { peerControl: true }),
236
306
  exact('POST', '/api/machine-self', 'admin', true, 'remote', { peerControl: true }),
237
307
  // WP-2a D-13/S-27: the pool routes. There is no dedicated "peer-only" rule mechanism in this
238
308
  // codebase (peerControl ADDS the peer bearer to the row's normal reach), so the roster/rotate rows
@@ -249,6 +319,65 @@ const HTTP_AUTH_RULES = Object.freeze([
249
319
  // and the payload is hardware counters, not secrets. peerControl: true is the one reach delta this
250
320
  // WP adds (tests/peer-control-auth.test.js pins it).
251
321
  exact('GET', '/api/host/stats', 'read', false, 'never', { peerControl: true }),
322
+ // WP-0 (docs/remote-session-hub-bridge-2026-10-30.html §6.2, §8 WP-0): the BOX-side hub-bridge
323
+ // lane. The caller is a LOCAL box process (Wall-E / the agent) reaching the box CTM over loopback,
324
+ // so both rows are `loopbackOnly` and carry NO peerControl — a paired hub must never read this
325
+ // box's link status or drive the lane through the peer bearer; it already owns the CONTROL socket
326
+ // this reports. `status` is a read (role + the connected hubs' display names, nothing secret);
327
+ // `call` is admin + step-up remote like any other privileged local action. Bridge FAILURES are
328
+ // data with HTTP 200 (lib/api/hub-bridge.js), so the row never has to express them.
329
+ exact('GET', '/api/hub-bridge/status', 'read', false, 'never', { loopbackOnly: true }),
330
+ exact('POST', '/api/hub-bridge/call', 'admin', true, 'never', { loopbackOnly: true }),
331
+ // WP-2 (docs/remote-session-hub-bridge-2026-10-30.html §5 R-4/R-5/R-9/R-11, §6.2, §8 WP-2): the
332
+ // HUB-side access surface — grants, pending denies, the trust policy and the audit tail.
333
+ // Every row is a USER-principal act: `admin` + step-up 'remote' and, critically, NO peerControl.
334
+ // authorize() therefore refuses the box's peer bearer with insufficient_scope (the peer credential
335
+ // cannot perform the passkey ceremony), which is R-4's whole point: a box agent can never mint
336
+ // itself a grant, and R-11's policy can never be rewritten by the machine it governs.
337
+ exact('GET', '/api/hub-bridge/grants', 'admin', false, 'remote'),
338
+ exact('POST', '/api/hub-bridge/grants', 'admin', true, 'remote'),
339
+ exact('DELETE', '/api/hub-bridge/grants', 'admin', true, 'remote'),
340
+ regex('POST', /^\/api\/hub-bridge\/pending\/[^/]+\/deny$/, 'admin', true, 'remote'),
341
+ exact('GET', '/api/hub-bridge/trust', 'admin', false, 'remote'),
342
+ exact('PUT', '/api/hub-bridge/trust', 'admin', true, 'remote'),
343
+ exact('GET', '/api/hub-bridge/audit', 'admin', false, 'remote'),
344
+ // WP-2 (docs/remote-agent-skills-bundles-2026-10-25.html §5 D-1/D-2/D-5, §6.2, §6.3): the box-side
345
+ // bundle ingress — the hub pushes its skills to the machine that will run a forwarded session.
346
+ // POST /api/agent-bundles/missing the "what do you already hold" probe
347
+ // POST /api/agent-bundles/blobs a batch of blobs in one request (WP-4/§6.2, D-6)
348
+ // PUT /api/agent-bundles/blobs/<sha256> one content-addressed blob
349
+ // PUT /api/agent-bundles/manifests/<treeHash> the tree hash + entry list
350
+ // All four are machine-to-machine: the caller is the paired hub's peer bearer, and the box keys
351
+ // every bundle by the AUTHENTICATED peer identity (req.ctmAuth.peerInstanceId), never by a body
352
+ // field — see lib/api/agent-bundles.js. `admin` + step-up 'remote' is the tuple a human admin token
353
+ // still needs (they write files outside ~/.claude under the box's data dir), and it is exactly the
354
+ // posture of the peer-forwarded image-draft PUT rows above; the peer bearer itself is admitted by
355
+ // the `peerControl` flag, which authorize() evaluates in full WITHOUT the passkey step-up a machine
356
+ // credential cannot perform (proved through real HTTP in
357
+ // tests-integration/agent-bundles-route.test.js). Explicit rows are load-bearing: a route with no
358
+ // rule is 403 auth_rule_missing, so these must land with the registrations in server.js.
359
+ exact('POST', '/api/agent-bundles/missing', 'admin', true, 'remote', { peerControl: true }),
360
+ // WP-4 (docs/remote-skills-hub-peer-identity-2026-10-26.html §5 D-6/D-7, §6.2): the batch upload
361
+ // leg. Same tuple as the per-blob row below — it writes the same store, one blob at a time, so it
362
+ // is the same risk class, just fewer requests (the peer bucket is per-hub and shared with the live
363
+ // relay; D-7).
364
+ exact('POST', '/api/agent-bundles/blobs', 'admin', true, 'remote', { peerControl: true }),
365
+ regex('PUT', /^\/api\/agent-bundles\/blobs\/[0-9a-f]{64}$/, 'admin', true, 'remote', { peerControl: true }),
366
+ regex('PUT', /^\/api\/agent-bundles\/manifests\/[^/]+$/, 'admin', true, 'remote', { peerControl: true }),
367
+ // WP-7 (docs/remote-agent-skills-bundles-2026-10-25.html §5 D-11, §6.2, §9 AC-7a/AC-7d): the
368
+ // RETURN path of the same exchange — the hub reads what the box already holds so it can classify
369
+ // it (never copy). A READ: `mutation: false` / step-up 'never' (like the image-draft GET row), but
370
+ // ADMIN scope rather than `read` — it lists the box user's skill roots, and the box keys the reported
371
+ // `base` by the AUTHENTICATED caller (req.ctmAuth.peerInstanceId), so nothing but the paired hub's
372
+ // peer bearer (or a human admin) is meant to reach it.
373
+ exact('GET', '/api/agent-skills/inventory', 'admin', false, 'never', { peerControl: true }),
374
+ // WP-8 (§5 D-12/D-13, §6.2): the BOX side of the one-skill exchange. `export` ships one item's
375
+ // BYTES and `retire` MOVES that item aside on this box — both are machine-to-machine, keyed by
376
+ // req.ctmAuth.peerInstanceId (lib/api/agent-bundles.js), never by a body field. `export` is a READ
377
+ // (same tuple as the inventory row above); `retire` MOVES a folder, so it is a mutation the peer
378
+ // performs without a passkey ceremony (reviewed in tests/auth-stepup-matrix.test.js).
379
+ exact('GET', '/api/agent-skills/export', 'admin', false, 'never', { peerControl: true }),
380
+ exact('POST', '/api/agent-skills/retire', 'admin', true, 'remote', { peerControl: true }),
252
381
  exact('GET', '/api/setup/network/microsoft-dev-tunnel/probe', 'admin', false, 'never'),
253
382
  // Go-Live wizard read view (design doc §Bootstrap & Auth): same posture as
254
383
  // GET /api/setup/network — admin scope, no step-up, remote-readable. The
@@ -268,7 +397,9 @@ const HTTP_AUTH_RULES = Object.freeze([
268
397
  // unchanged, from anywhere.
269
398
  regex('POST', /^\/api\/setup\//, 'admin', true, 'remote', { bootstrapLocal: true }),
270
399
 
271
- exact('GET', '/api/models/available-agents', 'read', false, 'never'),
400
+ // WP-13b (deepseek-harness-acp-agent-2026-10-28 D-15): a hub reads its box's agent presence here
401
+ // (lib/machine-registry.js keeps only the dsh boolean).
402
+ exact('GET', '/api/models/available-agents', 'read', false, 'never', { peerControl: true }),
272
403
  exact('GET', '/api/models/agent-versions', 'read', false, 'never'),
273
404
  exact('GET', '/api/models/agent-versions/plan', 'read', false, 'never'),
274
405
  exact('GET', '/api/models/agent-versions/upgrade-jobs', 'admin', false, 'never'),
@@ -277,10 +408,41 @@ const HTTP_AUTH_RULES = Object.freeze([
277
408
  exact('POST', '/api/models/agent-versions/auto-update', 'admin', false, 'never'),
278
409
  exact('POST', '/api/models/agent-versions/check', 'read', false, 'never'),
279
410
  exact('POST', '/api/models/agent-versions/upgrade', 'admin', true, 'remote'),
411
+ // WP-1 (docs/remote-box-model-access-2026-10-26.html §6.1, §5.3 D-2/D-3): the BOX answers what it
412
+ // can serve, to the paired hub that asks with the peer bearer — a peer READ, copied from the
413
+ // /api/agent-skills/inventory row's style (admin scope: it enumerates this machine's route rows,
414
+ // which are configuration, not a browser surface). MUST stay ABOVE the /^\/api\/models/ catch-all
415
+ // below: `getHttpAuthRule` returns the FIRST match, and the catch-all carries no peerControl.
416
+ exact('GET', '/api/models/availability', 'admin', false, 'never', { peerControl: true }),
417
+ // WP-4 (docs/remote-box-model-access-2026-10-26.html §6.4): the BOX end of "Remove from <box>" —
418
+ // the paired hub asks THIS machine to delete its own route rows. A MUTATION, and the same tuple as
419
+ // POST /api/agent-skills/retire: admin + step-up remote with peerControl, because the caller is the
420
+ // hub's peer bearer (the human did the step-up on the hub route; tests/auth-stepup-matrix.test.js's
421
+ // REVIEWED_PEER_CONTROL_WITHOUT_STEPUP carries the reason). MUST stay ABOVE the /^\/api\/models/
422
+ // catch-all below for the same first-match reason as the availability row.
423
+ exact('POST', '/api/models/remove', 'admin', true, 'remote', { peerControl: true }),
424
+ // WP-5 (docs/remote-box-model-access-2026-10-26.html §5.1 R-5/R-6, §6.4): the BOX end of "Use on
425
+ // <box>" — the paired hub asks THIS machine to write ONE route the hub holds. Same tuple as the
426
+ // remove row above and for the same reason: the caller is the hub's peer bearer (the human did the
427
+ // step-up on the hub route; tests/auth-stepup-matrix.test.js's REVIEWED_PEER_CONTROL_WITHOUT_STEPUP
428
+ // carries the reason). This is the one peer row whose body carries a credential — ONE route's key,
429
+ // by the user's explicit click (R-5), never a bulk export (R-6). MUST stay ABOVE the
430
+ // /^\/api\/models/ catch-all below for the same first-match reason as the rows above it.
431
+ exact('POST', '/api/models/import', 'admin', true, 'remote', { peerControl: true }),
432
+ // WP-3 (docs/remote-session-child-transcript-model-truth-and-restart-2026-10-27.html §5 D-4, §8
433
+ // WP-3): the Delegate pane of a BOX-owned session reads the BOX's own delegate ladder, so the hub
434
+ // asks that machine over the peer bearer. A plain peer READ — read scope, no mutation, no step-up;
435
+ // `peerControl: true` is the only addition, exactly like the /api/models/availability row above.
436
+ // MUST stay ABOVE the /^\/api\/models/ catch-all below: `getHttpAuthRule` returns the FIRST match,
437
+ // and the catch-all carries no peerControl.
438
+ exact('GET', '/api/models/delegate-prefs', 'read', false, 'never', { peerControl: true }),
280
439
  regex('GET', /^\/api\/models(?:\/|$)/, 'read', false, 'never'),
281
440
  // Delegate model prefs (session / per-agent default scope rows): same class as the other model-config writes.
282
- exact('PUT', '/api/models/delegate-prefs', 'admin', true, 'remote'),
283
- regex('DELETE', /^\/api\/models\/delegate-prefs\/[^/]+$/, 'admin', true, 'remote'),
441
+ // WP-1 (docs/remote-session-delegate-pick-write-forward-2026-10-30.html D-1/D-2/D-7): the hub
442
+ // forwards a write for a BOX-owned session to the box that owns it over the peer bearer, exactly
443
+ // like the read row above; scope/mutation/step-up are unchanged (`peerControl` is the only addition).
444
+ exact('PUT', '/api/models/delegate-prefs', 'admin', true, 'remote', { peerControl: true }),
445
+ regex('DELETE', /^\/api\/models\/delegate-prefs\/[^/]+$/, 'admin', true, 'remote', { peerControl: true }),
284
446
  exact('PUT', '/api/models/workflows', 'admin', true, 'remote'),
285
447
  regex('DELETE', /^\/api\/models\/workflows\/[^/]+$/, 'admin', true, 'remote'),
286
448
  exact('POST', '/api/models/workflows/import', 'admin', true, 'remote'),
@@ -310,7 +472,10 @@ const HTTP_AUTH_RULES = Object.freeze([
310
472
  exact('GET', '/api/sessions/standup', 'read', false, 'never'),
311
473
  exact('GET', '/api/sessions/git-status', 'read', false, 'never'),
312
474
  exact('GET', '/api/session/prompts', 'read', false, 'never'),
313
- exact('GET', '/api/session/messages', 'read', false, 'never'),
475
+ // WP-13 (deepseek-harness-acp-agent-2026-10-28 D-25): the hub forwards a box-owned session's Conv
476
+ // read here (lib/remote-session-forward.js), and with a box selected the Recent review reads it too
477
+ // (docs/recent-sessions-follow-computer-filter-2026-10-31.html §5 D-6), so the box grants it to the peer bearer.
478
+ exact('GET', '/api/session/messages', 'read', false, 'never', { peerControl: true }),
314
479
  exact('GET', '/api/session/message-content', 'read', false, 'never'),
315
480
  exact('GET', '/api/session/runtime-diagnostics', 'read', false, 'never'),
316
481
  exact('GET', '/api/diagnostics/client-health/ping', 'read', false, 'never'),
@@ -318,6 +483,9 @@ const HTTP_AUTH_RULES = Object.freeze([
318
483
  exact('GET', '/api/diagnostics/lifecycle', 'read', false, 'never'),
319
484
  exact('GET', '/api/diagnostics/session-resources', 'read', false, 'never'),
320
485
  exact('GET', '/api/diagnostics/uploads', 'read', false, 'never'),
486
+ // WP-3 (box-idle-sleep-remote-typing-freezes-2026-11-01.html §8 WP-3): the frame-receipt exit
487
+ // counters readout -- read-only observation, exact same shape as the uploads row above.
488
+ exact('GET', '/api/diagnostics/receipt-exits', 'read', false, 'never'),
321
489
  exact('GET', '/api/diagnostics/submissions', 'read', false, 'never'),
322
490
  exact('GET', '/api/diagnostics/perf-summary', 'read', false, 'never'),
323
491
  exact('POST', '/api/diagnostics/client-health', 'read', false, 'never'),
@@ -328,10 +496,18 @@ const HTTP_AUTH_RULES = Object.freeze([
328
496
  exact('GET', '/api/session/export', 'read', false, 'never'),
329
497
  exact('GET', '/api/debug/clients', 'read', false, 'never', { loopbackOnly: true }),
330
498
  exact('GET', '/api/session/prompts', 'read', false, 'never'),
331
- exact('POST', '/api/session/image-refs', 'respond', true, 'never'),
499
+ // WP-1 (docs/composer-image-chip-stuck-submission-recovery-2026-10-30.html §5 R-1, §6, §9): the
500
+ // image-ref recording call is session-scoped in its path and forwarded to the box that owns a
501
+ // MIRROR session (the draft lives there), so the row gains peerControl. Scope/mutation/step-up are
502
+ // unchanged — respond + no step-up for every other caller. The singular /api/session/image-refs
503
+ // row is REMOVED, not aliased; that path now falls to the /api/session/ catch-all below.
504
+ regex('POST', /^\/api\/sessions\/[^/]+\/image-refs$/, 'respond', true, 'never', { peerControl: true }),
332
505
  exact('GET', '/api/sessions/integrity', 'read', false, 'never'),
333
506
  exact('GET', '/api/sessions/relink-audit', 'read', false, 'never'),
334
- exact('GET', '/api/sessions/search', 'read', false, 'never'),
507
+ // WP-0 (docs/recent-sessions-follow-computer-filter-2026-10-31.html §5 D-6, §6): with a box
508
+ // selected the Recent search runs ON that box, over the same peer leg as /api/recent-sessions
509
+ // above. Flag only — `read`/never is what every other caller already had.
510
+ exact('GET', '/api/sessions/search', 'read', false, 'never', { peerControl: true }),
335
511
  exact('GET', '/api/sessions/search-status', 'read', false, 'never'),
336
512
  exact('GET', '/api/sessions/analysis', 'read', false, 'never'),
337
513
  exact('GET', '/api/stream/status', 'read', false, 'never'),
@@ -349,20 +525,52 @@ const HTTP_AUTH_RULES = Object.freeze([
349
525
  // mirrored box session. Previously had NO rule (loopback-only in practice) — the explicit read row
350
526
  // is what makes it reachable for the peer bearer; scope read / no step-up / no mutation.
351
527
  regex('GET', /^\/api\/sessions\/[^/]+\/transcripts$/, 'read', false, 'never', { peerControl: true }),
528
+ // WP-1 (docs/remote-session-history-reads-and-box-status-hooks-2026-10-26.html WP-1 / D-2): the three
529
+ // terminal-history reads the hub forwards to the box for a BOX-owned (mirror) session — the paged
530
+ // scrollback archive, the rendered rollout-history window, and the painted-row store. Previously had
531
+ // NO rule (loopback-only in practice), so a forwarded read died on the box as a bare 403; the explicit
532
+ // read row is what makes them reachable for the peer bearer. Scope read / no mutation / no step-up,
533
+ // the §6.2 read class. SINGULAR `/api/session/` — they are registered as
534
+ // `/^\/api\/session\/([^/]+)\/(scrollback|history-window|painted-rows)$/` in lib/api/sessions.js.
535
+ regex('GET', /^\/api\/session\/[^/]+\/(?:history-window|scrollback|painted-rows)$/, 'read', false, 'never', { peerControl: true }),
352
536
  // Lead-model switch (picker design WP-2): same class as the WS 'model-change' it replaces for
353
- // Claude/Codex tabs (admin + step-up); reading the request state is a plain read.
354
- regex('POST', /^\/api\/sessions\/[^/]+\/lead-model$/, 'admin', true, 'remote'),
355
- regex('GET', /^\/api\/sessions\/[^/]+\/lead-model\/(?:request|options)$/, 'read', false, 'never'),
356
- regex('DELETE', /^\/api\/sessions\/[^/]+\/lead-model\/request$/, 'admin', true, 'remote'),
537
+ // Claude/Codex tabs (admin + step-up); reading the request state is a plain read. WP-2
538
+ // (docs/remote-box-model-access-2026-10-26.html §6.3, §5.1 R-4): the hub forwards all four
539
+ // lead-model calls of a MIRROR session to the box that owns it, over the same peer bearer the
540
+ // lifecycle rows above use — so the three rows gain the flag and keep their scope/mutation/stepUp
541
+ // exactly as they were.
542
+ regex('POST', /^\/api\/sessions\/[^/]+\/lead-model$/, 'admin', true, 'remote', { peerControl: true }),
543
+ regex('GET', /^\/api\/sessions\/[^/]+\/lead-model\/(?:request|options)$/, 'read', false, 'never', { peerControl: true }),
544
+ regex('DELETE', /^\/api\/sessions\/[^/]+\/lead-model\/request$/, 'admin', true, 'remote', { peerControl: true }),
357
545
  regex('POST', /^\/api\/sessions\/[^/]+\/workflow-(?:match|route|outcome)$/, 'respond', true, 'never'),
358
546
  exact('POST', '/api/sessions/ai-search', 'read', false, 'never'),
359
547
  exact('POST', '/api/sessions/analyze', 'read', false, 'never'),
360
548
  exact('POST', '/api/sessions/resume', 'create', true, 'remote'),
549
+ // WP-2 (docs/external-causality-kill-session-loss-2026-10-27.html §6, §8 WP-2): the dead adopted
550
+ // host's "Resume N sessions" control. Same class as the resume POST beside it — it starts PTYs.
551
+ exact('POST', '/api/sessions/resume-deferred', 'create', true, 'remote'),
361
552
  exact('POST', '/api/sessions/attach', 'create', true, 'remote'),
362
553
  exact('POST', '/api/sessions/repoint', 'admin', true, 'remote'),
363
- exact('POST', '/api/sessions/rename', 'respond', true, 'never'),
364
- exact('POST', '/api/sessions/workers/retire', 'respond', true, 'never'),
365
- regex('POST', /^\/api\/sessions\/[^/]+\/native-subagents\/clear$/, 'respond', true, 'never'),
554
+ // WP-1 (docs/remote-session-rename-forward-and-empty-rows-2026-10-30.html §5 D-1, §9 S-4): a
555
+ // BOX-owned session's rename is forwarded to the box's own route on the peer bearer, so the box
556
+ // row must declare the flag (scope/mutation/step-up unchanged for every other caller).
557
+ exact('POST', '/api/sessions/rename', 'respond', true, 'never', { peerControl: true }),
558
+ // WP-1 (docs/remote-session-rename-forward-and-empty-rows-2026-10-30.html §5 D-1, §9 S-4):
559
+ // POST /api/session/star had NO row and fell to the singular catch-all below
560
+ // (regex('POST', /^\/api\/session\//, 'admin', true, 'remote')). It is declared explicitly — with
561
+ // that catch-all's own admin/step-up posture plus the flag — because a BOX-owned session's star is
562
+ // forwarded to the box's own route on the peer bearer. The catch-all itself stays unflagged.
563
+ exact('POST', '/api/session/star', 'admin', true, 'remote', { peerControl: true }),
564
+ // WP-1 (docs/remote-session-child-transcript-model-truth-and-restart-2026-10-27.html §5 D-2/D-3, §8
565
+ // WP-1/AC-1h, §9 S-6/S-15): the sidebar's "Clear N finished" retires a BOX-owned lead's finished
566
+ // workers on the box that holds those worker_sessions rows, and the native clear cutoff writes the
567
+ // box's own runtime. Unlike the per-session forwards above, the retire row is a COLLECTION route
568
+ // whose ids arrive in the BODY (lib/api/sessions.js forwards it keyed on the parsed body via
569
+ // remoteMachineCatalog.forwardWorkersRetireRequest) — hence its presence here without a
570
+ // FORWARDED_SESSION_ROUTES member in lib/remote-session-forward.js. Flag only: scope/mutation/
571
+ // step-up are unchanged for every other caller.
572
+ exact('POST', '/api/sessions/workers/retire', 'respond', true, 'never', { peerControl: true }),
573
+ regex('POST', /^\/api\/sessions\/[^/]+\/native-subagents\/clear$/, 'respond', true, 'never', { peerControl: true }),
366
574
  // usage-ledger read model (WP-4 §6d): the session usage page and its raw call page are
367
575
  // plain reads of <dataDir>/usage.db. POST /api/usage/backfill starts a local, idempotent
368
576
  // re-ingest of transcripts already on this host — it writes only CTM's own usage.db, sends
@@ -393,13 +601,48 @@ const HTTP_AUTH_RULES = Object.freeze([
393
601
  exact('POST', '/api/sync/apply', 'sync', true, 'never'),
394
602
  exact('POST', '/api/sync/purge', 'sync', true, 'never'),
395
603
  exact('POST', '/api/sync/resync', 'sync', true, 'never'),
604
+ // WP-3 (docs/shared-memory-every-machine-2026-10-31.html §5 D-9/D-12, §6.6): the box-side v2 brain
605
+ // replica front routes (lib/api/memory-sync-routes.js). The hub dials a member's CTM with the pool
606
+ // credential (scopes sync + peer-control, lib/auth-context.js) and the member forwards to its own
607
+ // loopback Wall-E. Scope `sync`, no step-up — the same machine-to-machine class as the /api/sync/*
608
+ // rows above, and like them NOT peerControl-flagged (sync scope already authorizes the hub). MUST stay ABOVE the /^\/api\/sync\// catch-alls (there is no generic
609
+ // /api/sync/ catch-all today, but the four literals are declared here, next to their siblings).
610
+ exact('GET', '/api/sync/brain/v2/vector', 'sync', false, 'never'),
611
+ exact('POST', '/api/sync/brain/v2/changes', 'sync', true, 'never'),
612
+ exact('POST', '/api/sync/brain/v2/apply', 'sync', true, 'never'),
613
+ exact('GET', '/api/sync/brain/v2/digest', 'sync', false, 'never'),
614
+ // WP-4 (docs/shared-memory-every-machine-2026-10-31.html §5 D-6, §6.7): the JOIN family. The hub
615
+ // ships its consistent snapshot to a member that has never taken its origin, in 4 MiB chunks the
616
+ // member CTM assembles on its own disk. Same machine-to-machine class as the four rows above —
617
+ // scope `sync`, no step-up, NOT peerControl-flagged — so the same pool credential the hub already
618
+ // dials `/api/sync/brain/v2/*` with carries it. The two POSTs are reviewed in
619
+ // tests/auth-stepup-matrix.test.js alongside their brain/v2 siblings.
620
+ exact('POST', '/api/sync/brain/v2/join/chunk', 'sync', true, 'never'),
621
+ exact('GET', '/api/sync/brain/v2/join/transfer', 'sync', false, 'never'),
622
+ exact('POST', '/api/sync/brain/v2/join/import', 'sync', true, 'never'),
623
+ exact('GET', '/api/sync/brain/v2/join/status', 'sync', false, 'never'),
624
+ // WP-5 (docs/shared-memory-every-machine-2026-10-31.html §5 D-3, §6.8): the conversation-history
625
+ // feed (lib/api/conversation-sync-routes.js). Unlike the brain/v2 family these are served by CTM
626
+ // itself — transcription history lives in task-manager.db, so there is no Wall-E hop — but they
627
+ // are the same machine-to-machine class: scope `sync`, no step-up, NOT peerControl-flagged, so
628
+ // the pool credential the hub already dials `/api/sync/brain/v2/*` with carries them. The POSTs
629
+ // are reviewed in tests/auth-stepup-matrix.test.js alongside their brain/v2 siblings.
630
+ exact('GET', '/api/sync/conversation/v2/vector', 'sync', false, 'never'),
631
+ exact('POST', '/api/sync/conversation/v2/changes', 'sync', true, 'never'),
632
+ exact('POST', '/api/sync/conversation/v2/apply', 'sync', true, 'never'),
396
633
  regex('POST', /^\/api\/sync\/handoff\/[^/]+\/(?:offer|accept|cancel)$/, 'admin', true, 'remote'),
397
634
  exact('POST', '/api/instance/funnel/toggle', 'admin', true, 'remote'),
398
635
  regex('POST', /^\/api\/sessions\//, 'admin', true, 'remote'),
399
636
  regex('POST', /^\/api\/session\//, 'admin', true, 'remote'),
400
637
  exact('DELETE', '/api/session', 'admin', true, 'remote'),
401
638
 
402
- regex('GET', /^\/api\/ctm\/session-memory\/(?:health|search|context)$/, 'read', false, 'never'),
639
+ // WP-2 (docs/cross-machine-session-context-2026-10-31.html §6.2, §5 R-8): the hub forwards a
640
+ // single-session context read (and, in WP-4, a pool search) to the member that OWNS the session,
641
+ // over the same peer-bearer leg as every row above — so those two GETs admit the peer bearer.
642
+ // `health` reports THIS machine's own tables and is deliberately NOT flagged: the combined regex
643
+ // is SPLIT, not widened. Scope/mutation/step-up are unchanged for every other caller.
644
+ regex('GET', /^\/api\/ctm\/session-memory\/(?:search|context)$/, 'read', false, 'never', { peerControl: true }),
645
+ exact('GET', '/api/ctm/session-memory/health', 'read', false, 'never'),
403
646
  regex('GET', /^\/api\/sessions\/[^/]+\/messages\/range$/, 'read', false, 'never'),
404
647
  exact('POST', '/api/ctm/session-memory/context-pack', 'read', false, 'never'),
405
648
  // WP-0 conversation change feed (one-transcript-ingestor §6.1): subscriber reads
@@ -456,6 +699,28 @@ const HTTP_AUTH_RULES = Object.freeze([
456
699
  regex('POST', /^\/api\/worktrees\//, 'admin', true, 'remote'),
457
700
  regex('DELETE', /^\/api\/worktrees\//, 'admin', true, 'remote'),
458
701
 
702
+ // WP-3 (docs/local-landing-queue-multi-session-integration-2026-10-26.html §6.3/§8 WP-3): the
703
+ // landing-queue surface. All three rows are LOOPBACK-ONLY, deliberately — the landing queue is
704
+ // per-repository state on THIS host reachable only by a local child process (`bin/land.js`), so
705
+ // there is no remote or hub leg to serve, and `{ loopbackOnly: true }` is the strictest posture
706
+ // available (authorize() answers 403 `loopback_only` for every non-loopback caller regardless of
707
+ // scope). Reading the queue is a plain read; `run` starts the local runner and `submit` enqueues
708
+ // this session's branch, so both are `write`. Step-up is unreachable on a loopback caller
709
+ // (authorize() only demands it for non-loopback requests), so 'never' is the honest column.
710
+ exact('GET', '/api/landing/status', 'read', false, 'never', { loopbackOnly: true }),
711
+ exact('POST', '/api/landing/run', 'write', false, 'never', { loopbackOnly: true }),
712
+ exact('POST', '/api/landing/submit', 'write', false, 'never', { loopbackOnly: true }),
713
+
714
+ // WP-4 (docs/fleet-session-lists-hub-search-2026-11-01.html §6.3, §9 S-13/S-14/S-15): the PE
715
+ // "Search conversations" list and its single-conversation view are read on the BOX that owns the
716
+ // rows, over the same `?machine=` + peer-bearer leg as /api/recent-sessions (:471) and
717
+ // /api/sessions/search (:510) — hence `peerControl: true` and nothing else: scope/step-up are
718
+ // exactly what the broad `/api/conversations` read regex below gives every other caller. Declared
719
+ // here, BEFORE that regex, so the peer flag is on the row the matcher returns first. The `:id`
720
+ // shape is the spelling api-prompts.js matches (`/^\/api\/conversations\/[a-f0-9-]+$/`).
721
+ exact('GET', '/api/conversations', 'read', false, 'never', { peerControl: true }),
722
+ regex('GET', /^\/api\/conversations\/[a-f0-9-]+$/, 'read', false, 'never', { peerControl: true }),
723
+
459
724
  regex('GET', /^\/api\/(?:prompts?|folders|images|chains|permissions|conversations|templates|session-prompts|settings|hotkey|backups|tool-permissions|auto-approvals|approval-rules|approval-decisions|approval-escalations|approval\/blocklist|hooks\/status|queues|queue-linked-prompts|queue-draft|harvest|autocomplete|palette|ghost-complete|similar|patterns|copilot|prompt-quality|prompt-executions|prompt-execution-(?:pairs|sessions)|frequent-questions|session-trajectory|skills\/(?:autocomplete|resolve-intent))(?:\/|$)/, 'read', false, 'never'),
460
725
  exact('GET', '/api/runtime/approvals', 'read', false, 'never'),
461
726
  exact('GET', '/api/runtime/registry', 'read', false, 'never'),
@@ -495,6 +760,10 @@ const HTTP_AUTH_RULES = Object.freeze([
495
760
  regex('DELETE', /^\/api\/feedback(?:\/|$)/, 'admin', true, 'remote'),
496
761
 
497
762
  exact('GET', '/api/storage/conversation-migration/status', 'read', false, 'never'),
763
+ // Backup retention setting (docs/backup-retention-days-setting-2026-10-31.html §6): reading the
764
+ // window is a read; changing it alters what the next backup deletes, so it is an admin write.
765
+ exact('GET', '/api/storage/backup-retention', 'read', false, 'never'),
766
+ exact('PUT', '/api/storage/backup-retention', 'admin', true, 'remote'),
498
767
  exact('GET', '/api/wall-e/memories/search', 'read', false, 'never'),
499
768
  exact('GET', '/api/wall-e/prompt-purge/legacy-migration', 'admin', false, 'remote'),
500
769
  exact('POST', '/api/wall-e/prompt-purge/legacy-migration-intents', 'admin', true, 'remote'),
@@ -534,8 +803,10 @@ function rule(scope, mutation, stepUp, extra = {}) {
534
803
  // distinct flag rather than a scope union so `scope` (and everything that reads it — the
535
804
  // step-up matrix, the owner manifest, /api/auth/rules consumers) keeps its existing meaning;
536
805
  // authorize() consults the flag directly.
537
- function peerControl(scope, mutation, stepUp) {
538
- return rule(scope, mutation, stepUp, { peerControl: true });
806
+ // WP-1 (§9 S-4): `extra` passes through so a peer-control row can carry the same additive flags
807
+ // (`rateKind`) an ordinary `rule(...)` row can, without a second constructor.
808
+ function peerControl(scope, mutation, stepUp, extra = {}) {
809
+ return rule(scope, mutation, stepUp, { ...extra, peerControl: true });
539
810
  }
540
811
 
541
812
  function exact(method, path, scope, mutation, stepUp, extra = {}) {