@sema-agent/server 7.132.0 → 7.134.0

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 (473) hide show
  1. package/MIGRATION.md +353 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +301 -64
  5. package/deploy/sema-up/README.md +35 -1
  6. package/deploy/sema-up/chart/Chart.yaml +1 -1
  7. package/deploy/sema-up/chart/templates/NOTES.txt +15 -0
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +129 -0
  9. package/deploy/sema-up/chart/templates/sealed-key.yaml +24 -0
  10. package/deploy/sema-up/chart/templates/server-v4pro.yaml +19 -2
  11. package/deploy/sema-up/chart/templates/server.yaml +19 -2
  12. package/deploy/sema-up/chart/values-full-single.yaml +5 -1
  13. package/deploy/sema-up/chart/values.yaml +34 -0
  14. package/deploy/sema-up/stack/compose.yaml +3 -0
  15. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  16. package/dist/adoption/plan.d.ts +3 -2
  17. package/dist/adoption/plan.js +7 -5
  18. package/dist/adoption/runner.js +3 -10
  19. package/dist/adoption/sql.d.ts +3 -2
  20. package/dist/adoption/sql.js +3 -5
  21. package/dist/adoption/wire.d.ts +4 -1
  22. package/dist/adoption/wire.js +1 -0
  23. package/dist/approval-ask-audit-store.d.ts +32 -14
  24. package/dist/approval-ask-audit-store.js +272 -74
  25. package/dist/approval-ask-machine.d.ts +15 -0
  26. package/dist/approval-ask-machine.js +6 -0
  27. package/dist/approval-ask-retention.d.ts +136 -0
  28. package/dist/approval-ask-retention.js +102 -0
  29. package/dist/approval-card.d.ts +83 -23
  30. package/dist/approval-card.js +45 -15
  31. package/dist/approval-content-kind.d.ts +5 -2
  32. package/dist/approval-content-kind.js +16 -3
  33. package/dist/approval-deny-reasons.d.ts +1 -1
  34. package/dist/approval-gate-currency.d.ts +72 -0
  35. package/dist/approval-gate-currency.js +94 -0
  36. package/dist/approval.d.ts +15 -0
  37. package/dist/approval.js +55 -17
  38. package/dist/audit.d.ts +27 -10
  39. package/dist/audit.js +12 -16
  40. package/dist/bake-runner/main.js +3 -2
  41. package/dist/boot/coordinators.d.ts +6 -1
  42. package/dist/boot/coordinators.js +6 -3
  43. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  44. package/dist/boot/execution-env.js +9 -7
  45. package/dist/boot/execution-lane.js +11 -0
  46. package/dist/boot/leader.d.ts +2 -0
  47. package/dist/boot/leader.js +4 -1
  48. package/dist/boot/memory-boundary.js +2 -2
  49. package/dist/boot/memory-consolidation.d.ts +5 -4
  50. package/dist/boot/memory-consolidation.js +7 -6
  51. package/dist/boot/org-delivery.d.ts +28 -0
  52. package/dist/boot/org-delivery.js +20 -0
  53. package/dist/boot/read-deny-anchor-audit.js +2 -2
  54. package/dist/boot/reapers.d.ts +3 -0
  55. package/dist/boot/reapers.js +21 -1
  56. package/dist/boot/resolve-spec.d.ts +3 -0
  57. package/dist/boot/resolve-spec.js +60 -81
  58. package/dist/boot/runner-deps.d.ts +18 -5
  59. package/dist/boot/runner-deps.js +10 -0
  60. package/dist/boot/session-faces.d.ts +1 -0
  61. package/dist/boot/session-faces.js +4 -2
  62. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  63. package/dist/boot/stage-06-runners.d.ts +6 -3
  64. package/dist/boot/stage-06-runners.js +20 -4
  65. package/dist/boot/stage-07-capability-layer.d.ts +4 -1
  66. package/dist/boot/stage-07-capability-layer.js +24 -3
  67. package/dist/boot/stage-08-reapers.d.ts +4 -1
  68. package/dist/boot/stage-08-reapers.js +2 -2
  69. package/dist/boot/stage-09-leader.d.ts +5 -1
  70. package/dist/boot/stage-09-leader.js +2 -2
  71. package/dist/boot/stage-10-http-server.d.ts +5 -1
  72. package/dist/boot/stage-10-http-server.js +6 -6
  73. package/dist/boot/stores.d.ts +8 -0
  74. package/dist/boot/stores.js +10 -14
  75. package/dist/boot/web-admin.d.ts +10 -0
  76. package/dist/boot/web-admin.js +162 -65
  77. package/dist/boot/workflow-orchestration.d.ts +2 -0
  78. package/dist/boot/workflow-orchestration.js +2 -1
  79. package/dist/brain.js +8 -3
  80. package/dist/breaker-key.d.ts +6 -0
  81. package/dist/breaker-key.js +29 -0
  82. package/dist/budget.js +5 -1
  83. package/dist/caller-text-echo.d.ts +11 -6
  84. package/dist/caller-text-echo.js +10 -12
  85. package/dist/canonical-json.d.ts +2 -41
  86. package/dist/canonical-json.js +2 -13
  87. package/dist/capabilities/center-plugins.d.ts +7 -0
  88. package/dist/capabilities/center-plugins.js +1 -1
  89. package/dist/capabilities/composite-members.d.ts +1 -1
  90. package/dist/capabilities/composite-members.js +1 -1
  91. package/dist/capabilities/execution-lane.js +2 -2
  92. package/dist/capabilities/hands-lane.d.ts +21 -0
  93. package/dist/capabilities/hands-lane.js +10 -0
  94. package/dist/capabilities/mcp-probe.d.ts +36 -4
  95. package/dist/capabilities/mcp-probe.js +29 -6
  96. package/dist/capabilities/scenarios.d.ts +63 -7
  97. package/dist/capabilities/scenarios.js +39 -7
  98. package/dist/capability-facts.d.ts +36 -4
  99. package/dist/capability-facts.js +30 -4
  100. package/dist/center-config-tier.d.ts +69 -0
  101. package/dist/center-config-tier.js +42 -0
  102. package/dist/checkpoint-ctx-seal-m28.d.ts +42 -0
  103. package/dist/checkpoint-ctx-seal-m28.js +19 -0
  104. package/dist/checkpoint-identity.d.ts +16 -0
  105. package/dist/checkpoint-identity.js +19 -0
  106. package/dist/config-catalog.d.ts +17 -10
  107. package/dist/config-catalog.js +43 -28
  108. package/dist/config-d-migration.d.ts +3 -1
  109. package/dist/config-d-migration.js +2 -2
  110. package/dist/config-dir-trust.d.ts +114 -0
  111. package/dist/config-dir-trust.js +388 -0
  112. package/dist/config-invariants.d.ts +18 -5
  113. package/dist/config-invariants.js +35 -3
  114. package/dist/config-provider.d.ts +6 -1
  115. package/dist/config-provider.js +6 -2
  116. package/dist/config-types.d.ts +71 -14
  117. package/dist/config-types.js +8 -0
  118. package/dist/config.d.ts +13 -0
  119. package/dist/config.js +121 -59
  120. package/dist/delegated-session-owner.d.ts +185 -0
  121. package/dist/delegated-session-owner.js +119 -0
  122. package/dist/device-protocol.d.ts +5 -3
  123. package/dist/device-protocol.js +1 -1
  124. package/dist/device-ws-hub.js +21 -2
  125. package/dist/device-ws-protocol.d.ts +70 -6
  126. package/dist/device-ws-protocol.js +50 -23
  127. package/dist/elicitation.js +3 -2
  128. package/dist/entry-problems.d.ts +34 -0
  129. package/dist/entry-problems.js +14 -0
  130. package/dist/execution-lane-caps.d.ts +49 -10
  131. package/dist/execution-lane-caps.js +43 -4
  132. package/dist/field-conflict.d.ts +44 -0
  133. package/dist/field-conflict.js +21 -0
  134. package/dist/file-history-disclosure.d.ts +34 -5
  135. package/dist/file-history-disclosure.js +2 -2
  136. package/dist/fleet/fleet-bus.d.ts +84 -6
  137. package/dist/fleet/fleet-bus.js +42 -9
  138. package/dist/hooks/classic-stations.d.ts +10 -5
  139. package/dist/hooks/classic-stations.js +4 -4
  140. package/dist/hooks/command-spawn.d.ts +57 -0
  141. package/dist/hooks/command-spawn.js +139 -0
  142. package/dist/hooks/hook-llm.js +2 -2
  143. package/dist/hooks/hook-runner.d.ts +127 -25
  144. package/dist/hooks/hook-runner.js +668 -287
  145. package/dist/hooks/hook-source.d.ts +44 -0
  146. package/dist/hooks/hook-source.js +40 -0
  147. package/dist/http/active-run-conflict.d.ts +5 -13
  148. package/dist/http/active-run-conflict.js +17 -27
  149. package/dist/http/admission.js +111 -60
  150. package/dist/http/approval-sweeps.js +58 -19
  151. package/dist/http/caller-trust.d.ts +77 -0
  152. package/dist/http/caller-trust.js +143 -0
  153. package/dist/http/checkpoint-ctx.d.ts +173 -18
  154. package/dist/http/checkpoint-ctx.js +171 -12
  155. package/dist/http/claimed-run.d.ts +4 -3
  156. package/dist/http/device-placement.d.ts +2 -4
  157. package/dist/http/device-placement.js +2 -1
  158. package/dist/http/dispatch.js +13 -7
  159. package/dist/http/durable-run-leg.d.ts +4 -32
  160. package/dist/http/durable-run-leg.js +37 -12
  161. package/dist/http/idempotency.d.ts +2 -2
  162. package/dist/http/idempotency.js +2 -2
  163. package/dist/http/owner-access.d.ts +56 -0
  164. package/dist/http/owner-access.js +42 -0
  165. package/dist/http/principal-gate.d.ts +78 -27
  166. package/dist/http/principal-gate.js +64 -14
  167. package/dist/http/readiness.d.ts +11 -5
  168. package/dist/http/readiness.js +10 -3
  169. package/dist/http/refusal-body.d.ts +12 -0
  170. package/dist/http/refusal-body.js +11 -0
  171. package/dist/http/request-guards.d.ts +16 -32
  172. package/dist/http/request-guards.js +31 -30
  173. package/dist/http/resume-ctx-read.d.ts +50 -6
  174. package/dist/http/resume-ctx-read.js +33 -7
  175. package/dist/http/resume-legs.d.ts +5 -5
  176. package/dist/http/resume-legs.js +163 -91
  177. package/dist/http/retired-service-deps.d.ts +43 -0
  178. package/dist/http/retired-service-deps.js +18 -0
  179. package/dist/http/route-ctx.d.ts +44 -37
  180. package/dist/http/route-ctx.js +4 -0
  181. package/dist/http/route-table.js +2 -0
  182. package/dist/http/routes/a2a-serve.js +3 -4
  183. package/dist/http/routes/admin-config-refresh.js +1 -1
  184. package/dist/http/routes/admin-drain.js +1 -1
  185. package/dist/http/routes/admin-memory-optout.js +5 -1
  186. package/dist/http/routes/adoption.js +2 -9
  187. package/dist/http/routes/agents-roster.js +2 -3
  188. package/dist/http/routes/approvals-assistant.js +91 -56
  189. package/dist/http/routes/background.js +3 -2
  190. package/dist/http/routes/capabilities.js +20 -4
  191. package/dist/http/routes/config-catalog.d.ts +3 -3
  192. package/dist/http/routes/config-catalog.js +1 -1
  193. package/dist/http/routes/devices.js +3 -17
  194. package/dist/http/routes/diagnostics.d.ts +3 -3
  195. package/dist/http/routes/diagnostics.js +6 -2
  196. package/dist/http/routes/fleet.js +4 -4
  197. package/dist/http/routes/images.js +6 -7
  198. package/dist/http/routes/leader.js +1 -8
  199. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  200. package/dist/http/routes/mcp-reconnect.js +3 -2
  201. package/dist/http/routes/memory-bundle.js +1 -1
  202. package/dist/http/routes/memory-compliance.js +1 -1
  203. package/dist/http/routes/memory-consolidation.js +1 -1
  204. package/dist/http/routes/memory-origin.d.ts +1 -1
  205. package/dist/http/routes/memory-origin.js +1 -1
  206. package/dist/http/routes/memory-policy.d.ts +1 -1
  207. package/dist/http/routes/memory-policy.js +3 -2
  208. package/dist/http/routes/notify-wake.js +8 -21
  209. package/dist/http/routes/observability.js +2 -2
  210. package/dist/http/routes/principal-inbox.d.ts +39 -0
  211. package/dist/http/routes/principal-inbox.js +76 -0
  212. package/dist/http/routes/retention-ops.js +2 -9
  213. package/dist/http/routes/rules.js +9 -22
  214. package/dist/http/routes/runs.d.ts +5 -0
  215. package/dist/http/routes/runs.js +63 -115
  216. package/dist/http/routes/session-sync.d.ts +3 -2
  217. package/dist/http/routes/session-sync.js +53 -48
  218. package/dist/http/routes/sessions-list.d.ts +1 -1
  219. package/dist/http/routes/sessions-list.js +3 -4
  220. package/dist/http/routes/sessions.js +33 -43
  221. package/dist/http/routes/side-query.js +6 -4
  222. package/dist/http/routes/tasks.js +71 -30
  223. package/dist/http/routes/trace-usage.js +7 -9
  224. package/dist/http/routes/workflows.d.ts +351 -0
  225. package/dist/http/routes/workflows.js +153 -119
  226. package/dist/http/run-declared-families.d.ts +16 -0
  227. package/dist/http/run-declared-families.js +12 -0
  228. package/dist/http/send.d.ts +24 -3
  229. package/dist/http/send.js +14 -2
  230. package/dist/http/server.d.ts +23 -18
  231. package/dist/http/server.js +20 -15
  232. package/dist/http/stored-body-replay.js +17 -4
  233. package/dist/http/submit-ctx.d.ts +4 -3
  234. package/dist/http/submit-ctx.js +23 -6
  235. package/dist/http/submit-replay.d.ts +4 -3
  236. package/dist/http/submit-replay.js +5 -4
  237. package/dist/http/wire-types.d.ts +17 -10
  238. package/dist/index.d.ts +3 -1
  239. package/dist/index.js +1 -1
  240. package/dist/lane-home-probe.d.ts +78 -9
  241. package/dist/lane-home-probe.js +78 -12
  242. package/dist/leader/endpoint.d.ts +4 -1
  243. package/dist/leader/endpoint.js +11 -10
  244. package/dist/leader/wire.d.ts +4 -0
  245. package/dist/leader/wire.js +8 -7
  246. package/dist/limit-refusal.d.ts +17 -5
  247. package/dist/limit-refusal.js +4 -1
  248. package/dist/main.js +1 -1
  249. package/dist/mcp-assertion-header.d.ts +31 -10
  250. package/dist/mcp-assertion-header.js +10 -3
  251. package/dist/memory-origin-fence.js +2 -2
  252. package/dist/memory-project-layer.d.ts +37 -0
  253. package/dist/memory-project-layer.js +46 -0
  254. package/dist/memory-scope.d.ts +23 -16
  255. package/dist/memory-scope.js +24 -8
  256. package/dist/memory-sync-client.d.ts +27 -13
  257. package/dist/memory-sync-client.js +107 -18
  258. package/dist/model-compat.d.ts +1 -1
  259. package/dist/model-entry-refusal.d.ts +9 -1
  260. package/dist/model-entry-refusal.js +6 -1
  261. package/dist/model-plane-face.d.ts +51 -0
  262. package/dist/model-plane-face.js +24 -0
  263. package/dist/model-provider.d.ts +5 -0
  264. package/dist/model-provider.js +4 -2
  265. package/dist/model-route-endpoint.d.ts +8 -11
  266. package/dist/model-route-endpoint.js +4 -7
  267. package/dist/model-route-env.d.ts +22 -0
  268. package/dist/model-route-env.js +2 -0
  269. package/dist/model-route-gap.d.ts +60 -30
  270. package/dist/model-route-gap.js +21 -15
  271. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  272. package/dist/observability/corrupt-read-seat.js +9 -0
  273. package/dist/observability/err-text.d.ts +6 -0
  274. package/dist/observability/err-text.js +18 -4
  275. package/dist/observability/fail-open.d.ts +35 -9
  276. package/dist/observability/fail-open.js +35 -9
  277. package/dist/observability/metrics.js +1 -0
  278. package/dist/observability/prompt-manifest.d.ts +22 -25
  279. package/dist/observability/prompt-manifest.js +54 -50
  280. package/dist/observability/tool-trace.js +9 -10
  281. package/dist/operator-ask.d.ts +10 -0
  282. package/dist/operator-ask.js +3 -0
  283. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  284. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  285. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  286. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  287. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  288. package/dist/orchestration/workflow-notify-journal.js +27 -34
  289. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  290. package/dist/orchestration/workflow-park-decision.js +119 -0
  291. package/dist/org-delivery-gate.d.ts +81 -0
  292. package/dist/org-delivery-gate.js +59 -0
  293. package/dist/panel-tool-names.d.ts +23 -0
  294. package/dist/panel-tool-names.js +8 -0
  295. package/dist/parked-decide.d.ts +43 -11
  296. package/dist/parked-decide.js +100 -51
  297. package/dist/parked-revive-surface.d.ts +9 -2
  298. package/dist/parked-revive-surface.js +11 -8
  299. package/dist/permission-rule-list.d.ts +1 -1
  300. package/dist/permission-rule-list.js +2 -2
  301. package/dist/permission-rule-vocab.d.ts +1 -23
  302. package/dist/permission-rule-vocab.js +0 -13
  303. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  304. package/dist/plugins/approval-ask-store-file.js +21 -0
  305. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  306. package/dist/plugins/approval-ask-store-memory.js +34 -2
  307. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  308. package/dist/plugins/approval-ask-store-sql.js +37 -1
  309. package/dist/plugins/approval-payload-fingerprint.d.ts +14 -6
  310. package/dist/plugins/approval-payload-fingerprint.js +1 -1
  311. package/dist/plugins/blob-backend.d.ts +38 -25
  312. package/dist/plugins/blob-backend.js +29 -19
  313. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  314. package/dist/plugins/breaker-state-sql.js +4 -4
  315. package/dist/plugins/caching-session-store.d.ts +4 -1
  316. package/dist/plugins/caching-session-store.js +7 -3
  317. package/dist/plugins/checkpoint-store-sql.d.ts +36 -1
  318. package/dist/plugins/checkpoint-store-sql.js +65 -3
  319. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  320. package/dist/plugins/file-history-store-sql.js +3 -1
  321. package/dist/plugins/file-run-store.d.ts +5 -13
  322. package/dist/plugins/file-run-store.js +9 -0
  323. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  324. package/dist/plugins/fork-routing-session-store.js +12 -1
  325. package/dist/plugins/host-platform.d.ts +2 -0
  326. package/dist/plugins/host-platform.js +2 -1
  327. package/dist/plugins/local-checkpoint-store.d.ts +15 -2
  328. package/dist/plugins/local-checkpoint-store.js +32 -1
  329. package/dist/plugins/local-session-store.d.ts +13 -10
  330. package/dist/plugins/local-session-store.js +23 -14
  331. package/dist/plugins/local-session-window.d.ts +45 -0
  332. package/dist/plugins/local-session-window.js +38 -0
  333. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  334. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  335. package/dist/plugins/mailbox-store-sql.js +77 -52
  336. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  337. package/dist/plugins/memory-run-store.d.ts +5 -13
  338. package/dist/plugins/memory-run-store.js +8 -0
  339. package/dist/plugins/one-time-migrations.d.ts +121 -5
  340. package/dist/plugins/one-time-migrations.js +332 -8
  341. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  342. package/dist/plugins/org-delivery-quota-store.js +228 -0
  343. package/dist/plugins/permission-rule-store-file.js +10 -6
  344. package/dist/plugins/permission-rule-store-sql.js +8 -8
  345. package/dist/plugins/pg-pool.js +39 -7
  346. package/dist/plugins/pg-session-storage.d.ts +18 -5
  347. package/dist/plugins/pg-session-storage.js +68 -23
  348. package/dist/plugins/remote-env-adb.d.ts +6 -12
  349. package/dist/plugins/remote-env-adb.js +12 -2
  350. package/dist/plugins/remote-env-device.d.ts +14 -7
  351. package/dist/plugins/remote-env-device.js +23 -15
  352. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  353. package/dist/plugins/remote-env-k8s.js +23 -5
  354. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  355. package/dist/plugins/remote-env-local-docker.js +12 -9
  356. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  357. package/dist/plugins/remote-env-ssh.js +17 -11
  358. package/dist/plugins/run-store-sql.d.ts +16 -14
  359. package/dist/plugins/run-store-sql.js +22 -2
  360. package/dist/plugins/schema-indexes.js +2 -0
  361. package/dist/plugins/send-user-file.js +2 -2
  362. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  363. package/dist/plugins/session-epoch-anchor.js +2 -3
  364. package/dist/plugins/session-ownership.d.ts +11 -0
  365. package/dist/plugins/session-ownership.js +11 -0
  366. package/dist/plugins/session-placement.d.ts +12 -14
  367. package/dist/plugins/session-placement.js +2 -15
  368. package/dist/plugins/session-store.d.ts +18 -8
  369. package/dist/plugins/session-store.js +15 -4
  370. package/dist/plugins/sql-driver.d.ts +74 -11
  371. package/dist/plugins/sql-driver.js +210 -12
  372. package/dist/plugins/sql-errors.d.ts +23 -0
  373. package/dist/plugins/sql-errors.js +21 -0
  374. package/dist/plugins/store-backend.d.ts +36 -1
  375. package/dist/plugins/store-backend.js +40 -14
  376. package/dist/plugins/store-contracts.d.ts +42 -0
  377. package/dist/plugins/store-contracts.js +1 -0
  378. package/dist/plugins/tidb-pool.d.ts +6 -1
  379. package/dist/plugins/tidb-pool.js +44 -10
  380. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  381. package/dist/plugins/tidb-session-storage.js +2 -2
  382. package/dist/plugins/tidb-session-store.d.ts +25 -5
  383. package/dist/plugins/tidb-session-store.js +67 -21
  384. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  385. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  386. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  387. package/dist/plugins/workflow-run-store-sql.js +50 -9
  388. package/dist/posture-source.d.ts +18 -10
  389. package/dist/posture-source.js +4 -1
  390. package/dist/project-identity.d.ts +45 -6
  391. package/dist/project-identity.js +162 -8
  392. package/dist/project-layer-key.d.ts +28 -0
  393. package/dist/project-layer-key.js +29 -0
  394. package/dist/question.js +3 -2
  395. package/dist/read-deny-entry.d.ts +25 -0
  396. package/dist/read-deny-entry.js +12 -0
  397. package/dist/read-face-posture.d.ts +37 -11
  398. package/dist/read-face-posture.js +32 -3
  399. package/dist/request-key-closure.d.ts +7 -0
  400. package/dist/request-key-closure.js +9 -1
  401. package/dist/request-tool-axes.d.ts +12 -0
  402. package/dist/request-tool-axes.js +20 -0
  403. package/dist/request-value-closure.d.ts +5 -0
  404. package/dist/request-value-closure.js +11 -3
  405. package/dist/rule-entry-list.d.ts +26 -2
  406. package/dist/rule-entry-list.js +72 -12
  407. package/dist/rules-consent.js +3 -4
  408. package/dist/run-acceptance.d.ts +19 -3
  409. package/dist/run-acceptance.js +13 -1
  410. package/dist/run-local.js +37 -6
  411. package/dist/runs.d.ts +12 -10
  412. package/dist/runs.js +25 -6
  413. package/dist/runtime-caps-resolver.d.ts +16 -6
  414. package/dist/runtime-caps-resolver.js +18 -5
  415. package/dist/sandbox-pkg-source.d.ts +19 -1
  416. package/dist/sandbox-pkg-source.js +29 -7
  417. package/dist/sealed-key.d.ts +32 -0
  418. package/dist/sealed-key.js +55 -1
  419. package/dist/security.d.ts +95 -15
  420. package/dist/security.js +52 -9
  421. package/dist/session-error-wire.d.ts +31 -7
  422. package/dist/session-error-wire.js +9 -2
  423. package/dist/session-sync-kernel.d.ts +37 -10
  424. package/dist/session-sync-kernel.js +10 -0
  425. package/dist/session-titled-frame.d.ts +33 -0
  426. package/dist/session-titled-frame.js +4 -0
  427. package/dist/session-titler.d.ts +9 -1
  428. package/dist/session-titler.js +15 -4
  429. package/dist/spec-fields.js +21 -2
  430. package/dist/sql-engine-posture.d.ts +3 -1
  431. package/dist/task-a2a.js +4 -3
  432. package/dist/task-cwd.d.ts +1 -1
  433. package/dist/task-mcp.d.ts +5 -5
  434. package/dist/task-mcp.js +27 -74
  435. package/dist/task-settings.d.ts +93 -88
  436. package/dist/task-settings.js +71 -63
  437. package/dist/text-bidi.d.ts +0 -4
  438. package/dist/text-bidi.js +1 -3
  439. package/dist/tighten-only-seats.d.ts +150 -0
  440. package/dist/tighten-only-seats.js +196 -0
  441. package/dist/tool-approval.d.ts +451 -136
  442. package/dist/tool-approval.js +733 -256
  443. package/dist/tool-rule-names.d.ts +6 -0
  444. package/dist/trace/core-keyset-guard.d.ts +108 -25
  445. package/dist/trace/exit-seat.d.ts +40 -0
  446. package/dist/trace/exit-seat.js +130 -0
  447. package/dist/trace/ledger-events.d.ts +6 -3
  448. package/dist/trace/project.d.ts +98 -13
  449. package/dist/trace/project.js +57 -32
  450. package/dist/trace/projection-table.d.ts +100 -0
  451. package/dist/trace/projection-table.js +130 -0
  452. package/dist/trace/redact.d.ts +57 -0
  453. package/dist/trace/redact.js +962 -168
  454. package/dist/trace/self-minted-wire.d.ts +349 -1
  455. package/dist/trace/self-minted-wire.js +118 -1
  456. package/dist/trace/wire-projection-faces.d.ts +304 -2
  457. package/dist/trace/wire-projection-faces.js +160 -13
  458. package/dist/url-refusal.js +2 -0
  459. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  460. package/dist/web-admin-client/apply-effective.js +56 -5
  461. package/dist/web-admin-client/facade.d.ts +1 -1
  462. package/dist/web-admin-client/facade.js +1 -1
  463. package/dist/web-admin-client/read-face.js +5 -9
  464. package/dist/web-admin-client/skills-mcp.d.ts +1 -1
  465. package/dist/web-admin-client/skills-mcp.js +6 -8
  466. package/dist/web-admin-client/types.d.ts +1 -1
  467. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  468. package/package.json +8 -4
  469. package/scripts/drain-check-local.mjs +34 -2
  470. package/scripts/drain-check.mysql.sql +20 -2
  471. package/scripts/drain-check.pg.sql +20 -2
  472. package/dist/mcp-tool-faces.d.ts +0 -69
  473. package/dist/mcp-tool-faces.js +0 -106
@@ -4,7 +4,7 @@ import { sameExecutionRecord } from "@sema-agent/core";
4
4
  import { DECIDED_REPLAY_SCAN_CAP, approvalPayloadFingerprint } from "../../plugins/checkpoint-store-sql.js";
5
5
  import { APPROVAL_GATE_KINDS, carriesDeploymentListQuestion, standingAnswerDurablyRecordable } from "../../tool-approval.js";
6
6
  import { isParkedRunStatus } from "../../plugins/store-contracts.js";
7
- import { principalFrom, decodeCheckpointScope, PRINCIPAL_TOKEN_HEADER, APPROVAL_MAC_HEADER, APPROVAL_MAC_KID_HEADER } from "../../security.js";
7
+ import { principalFrom, decodeCheckpointScope, ownerOfCheckpointScope, CHECKPOINT_PUBLIC_SCOPE, PRINCIPAL_TOKEN_HEADER, APPROVAL_MAC_HEADER, APPROVAL_MAC_KID_HEADER } from "../../security.js";
8
8
  import { editedPlanBinding, isWellFormedUnicode, verifyDirectDoorProof } from "../../principal-jwt.js";
9
9
  import { MAX_APPROVAL_REASON_CHARS, projectQuestionAnswer, questionAnswerFromProjection } from "../../approval-hmac.js";
10
10
  import { PLAN_APPROVE_PERMISSION_MODES_AFTER, isPlanApprovePermissionModeAfter, planReviewDecisionExitsPlan, storedBodyPermissionMode } from "../../task-settings.js";
@@ -14,22 +14,26 @@ import { redactRiskDescriptor } from "../../observability/run-terminal.js";
14
14
  import { buildRunName } from "../../fleet/fleet-bus.js";
15
15
  import { sleep } from "../sse-log.js";
16
16
  import { bindSseLifecycle } from "../sse-lifecycle.js";
17
- import { sendJson, sendError, sseHeaders, SSE_MAX_STREAM_MS, SSE_HEARTBEAT_IDLE_MS } from "../send.js";
18
- import { gatedPrincipal, explicitOperatorOk, isOperator, sendPrincipalRefusal } from "../principal-gate.js";
17
+ import { sendJson, sendError, sseHeaders, logRequestError, SSE_MAX_STREAM_MS, SSE_HEARTBEAT_IDLE_MS } from "../send.js";
18
+ import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sessionCallerOf } from "../principal-gate.js";
19
+ import { readOwnedRun, readOwnedSession } from "../owner-access.js";
19
20
  import { governanceOriginOf } from "../../runtime-governance.js";
20
21
  import { deploymentListAsks } from "../../approval.js";
21
22
  import { callGrantBindingOf, questionGrantBindingOf } from "../../standing-answer-grant.js";
22
23
  import { sendResumeOutcome } from "../route-ctx.js";
23
24
  import { assertNever } from "../route-ctx.js";
24
25
  import * as facts from "../../capability-facts.js";
25
- import { readResumeCtx } from "../resume-ctx-read.js";
26
+ import { KEEP_SEALED, readResumeCtx } from "../resume-ctx-read.js";
27
+ import { StoreCorruptError } from "../../plugins/sql-json-column.js";
26
28
  import { recordFailOpen } from "../../observability/fail-open.js";
29
+ import { durableRowIdentity } from "../../checkpoint-identity.js";
27
30
  import { MAX_KEY_ECHO, keyClosureClause, scanKeyClosure } from "../../request-key-closure.js";
31
+ import { fieldConflictFacts } from "../../field-conflict.js";
28
32
  const DECIDE_BODY_DECLARED_KEYS = [
29
- "answer", "boundCallId", "boundInputHash", "checkpointToken", "decidedBy", "decision", "reason", "remember", "updatedInput",
33
+ "answer", "boundCallId", "boundInputHash", "checkpointToken", "decidedBy", "decision", "feedback", "reason", "remember", "updatedInput",
30
34
  ];
31
35
  const DECIDE_PROOF_COVERED_KEYS = ["answer", "boundCallId", "boundInputHash", "decision", "reason"];
32
- const DECIDE_NOT_IN_PROOF_KEYS = ["checkpointToken", "decidedBy", "remember", "updatedInput"];
36
+ const DECIDE_NOT_IN_PROOF_KEYS = ["checkpointToken", "decidedBy", "feedback", "remember", "updatedInput"];
33
37
  const PLAN_REVIEW_BODY_DECLARED_KEYS = [
34
38
  "boundCallId", "decidedBy", "decision", "editedPlan", "permissionModeAfter", "reason",
35
39
  ];
@@ -268,20 +272,32 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
268
272
  }
269
273
  const cs = park.checkpointStore;
270
274
  const principal = gatedPrincipal(req, deps.config);
271
- const operator = isOperator(principal, deps.config.operatorPrincipals);
275
+ const operator = explicitOperatorOk(principal, deps.config);
276
+ const ownScope = principal ?? CHECKPOINT_PUBLIC_SCOPE;
272
277
  if (match.decl.id === "approvals-stream") {
273
278
  const scope = operator
274
279
  ? (new URLSearchParams(match.search).get("owner") ?? undefined)
275
- : (principal ?? "__none__");
280
+ : ownScope;
276
281
  await streamApprovals(req, res, cs, deps.toolApproval, scope, deps.config);
277
282
  return;
278
283
  }
279
284
  if (match.decl.id === "approvals-list") {
280
285
  const scope = operator
281
286
  ? (new URLSearchParams(match.search).get("owner") ?? undefined)
282
- : (principal ?? "__none__");
287
+ : ownScope;
288
+ let durableRows;
289
+ try {
290
+ durableRows = await cs.listPending(scope);
291
+ }
292
+ catch (err) {
293
+ if (!isApprovalsReadCorrupt(err))
294
+ throw err;
295
+ logRequestError(deps.logger, req, err);
296
+ sendError(res, 500, "approvals.read_corrupt", "a stored approval row cannot be read - retrying this request will fail the same way until an operator repairs or removes the row");
297
+ return;
298
+ }
283
299
  sendJson(res, 200, {
284
- pending: (await cs.listPending(scope)).map((r) => projectPendingForWire(r, deps.config)),
300
+ pending: durableRows.map((r) => projectPendingForWire(r, deps.config)),
285
301
  serverNowMs: Date.now(),
286
302
  ...(deps.toolApproval ? { livePending: deps.toolApproval.listLivePending(scope) } : {}),
287
303
  ...(deps.approvalAskAudit ? { crashConverged: deps.approvalAskAudit.listCrashConverged(scope) } : {}),
@@ -300,17 +316,13 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
300
316
  sendError(res, 400, "request.path_malformed", "malformed id (invalid percent-encoding)");
301
317
  return;
302
318
  }
303
- const operators = deps.config.operatorPrincipals;
304
- const isExplicitOperator = explicitOperatorOk(principal, operators);
305
- if (!isExplicitOperator) {
319
+ if (!explicitOperatorOk(principal, deps.config)) {
306
320
  const owned = facts.sessionOwnership(deps);
307
321
  if (!owned.available) {
308
322
  sendError(res, 501, "capability.session_store_required", "approval exemptions require a session-store backend");
309
323
  return;
310
324
  }
311
- const ownerOf = owned.sessionStorage.ownerOf.bind(owned.sessionStorage);
312
- const owner = await ownerOf(exSessionId);
313
- if (owner === undefined || (owner !== null && owner !== principal)) {
325
+ if ((await readOwnedSession(deps, owned.sessionStorage, sessionCallerOf(req, deps), exSessionId, "owner")) === undefined) {
314
326
  sendError(res, 404, "not_found.session", "not found");
315
327
  return;
316
328
  }
@@ -329,22 +341,28 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
329
341
  return;
330
342
  }
331
343
  const revoked = await deps.approvalExemptionStore.revoke(exSessionId, exToolName);
332
- sendJson(res, revoked ? 200 : 404, revoked ? { revoked: true } : { error: "not found", errorCode: "not_found.exemption" });
344
+ if (revoked)
345
+ sendJson(res, 200, { revoked: true });
346
+ else
347
+ sendError(res, 404, "not_found.exemption", "not found");
333
348
  return;
334
349
  }
335
350
  }
336
351
  if (match.decl.id === "assistant-inbox") {
337
352
  const ownerParam = new URLSearchParams(match.search).get("owner") || undefined;
338
- const scope = operator && ownerParam ? ownerParam : (principal ?? "__none__");
353
+ const scope = operator && ownerParam ? ownerParam : ownScope;
339
354
  const summaries = await cs.listByScope(scope);
340
355
  const inbox = (await Promise.all(summaries.map(async (s) => {
341
- const ctxRead = await readResumeCtx(cs.getCtx(s.sessionId));
356
+ const ctxRead = await readResumeCtx(cs.getCtx(s.sessionId), KEEP_SEALED);
342
357
  if (ctxRead.kind === "corrupt")
343
358
  recordFailOpen("server.assistant-inbox.objective-ctx-corrupt", ctxRead.where);
344
- const objective = ctxRead.kind === "ok" ? (ctxRead.ctx.body?.objective ?? null) : null;
359
+ const storedBody = ctxRead.kind === "ok" ? ctxRead.ctx.body : undefined;
360
+ const storedObjective = typeof storedBody === "object" && storedBody !== null ? storedBody.objective : undefined;
361
+ const objective = typeof storedObjective === "string" ? storedObjective : null;
345
362
  const input = s.toolInput != null ? redactedPreview(s.toolInput) : null;
346
363
  return {
347
364
  sessionId: s.sessionId,
365
+ ...durableRowIdentity("assistant-inbox", s.checkpointId, s.token),
348
366
  scope: s.scope,
349
367
  createdAt: s.createdAt,
350
368
  ...(s.gateKind !== undefined ? { gateKind: s.gateKind } : {}),
@@ -364,13 +382,14 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
364
382
  objective,
365
383
  input,
366
384
  };
367
- }))).sort((a, b) => (b.severity ?? 0) - (a.severity ?? 0) || (a.createdAt ?? 0) - (b.createdAt ?? 0));
385
+ })))
386
+ .sort((a, b) => (b.severity ?? 0) - (a.severity ?? 0) || (a.createdAt ?? 0) - (b.createdAt ?? 0));
368
387
  sendJson(res, 200, { inbox });
369
388
  return;
370
389
  }
371
390
  if (match.decl.id === "assistant-tasks") {
372
391
  const ownerParam = new URLSearchParams(match.search).get("owner") || undefined;
373
- const scope = operator && ownerParam ? ownerParam : (principal ?? "__none__");
392
+ const scope = operator && ownerParam ? ownerParam : ownScope;
374
393
  const ledger = facts.durableRuns(deps);
375
394
  if (!ledger.available) {
376
395
  sendJson(res, 200, { tasks: [] });
@@ -379,7 +398,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
379
398
  const runStore = ledger.runStore;
380
399
  const summaries = await cs.listByScope(scope);
381
400
  const byGate = new Map(summaries.map((s) => [s.sessionId, s]));
382
- const runs = await runStore.listRuns({ owner: scope, limit: 100 });
401
+ const runs = await runStore.listRuns({ owner: ownerOfCheckpointScope(scope), limit: 100 });
383
402
  const tasks = runs
384
403
  .filter((r) => r.status === "running" || isParkedRunStatus(r.status))
385
404
  .map((r) => {
@@ -416,17 +435,11 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
416
435
  return;
417
436
  }
418
437
  const taskId = match.params.taskId;
419
- const run = await runStore.getRun(taskId);
438
+ const run = await readOwnedRun(deps.config, runStore, principal, taskId, "owner_or_operator");
420
439
  if (!run) {
421
440
  sendError(res, 404, "not_found.run", "task not found");
422
441
  return;
423
442
  }
424
- const operators = deps.config.operatorPrincipals;
425
- const explicitOperator = explicitOperatorOk(principal, operators);
426
- if (!explicitOperator && run.owner !== null && run.owner !== principal) {
427
- sendError(res, 404, "not_found.run", "task not found");
428
- return;
429
- }
430
443
  if (run.status === "running") {
431
444
  const ownedHere = run.instanceId != null && run.instanceId === deps.instanceId;
432
445
  if (ownedHere && !preemptableRuns.has(taskId)) {
@@ -482,8 +495,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
482
495
  sendError(res, 404, "not_found.run", "task not found");
483
496
  return;
484
497
  }
485
- const operators = deps.config.operatorPrincipals;
486
- const explicitOperator = explicitOperatorOk(principal, operators);
498
+ const explicitOperator = explicitOperatorOk(principal, deps.config);
487
499
  if (!explicitOperator && run.owner !== null && run.owner !== principal) {
488
500
  sendError(res, 404, "not_found.run", "task not found");
489
501
  return;
@@ -520,7 +532,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
520
532
  }
521
533
  }
522
534
  if (decision === "edit" && (typeof body.editedPlan !== "string" || body.editedPlan.length === 0)) {
523
- sendError(res, 400, "request.field_conflict", "decision 'edit' requires a non-empty editedPlan (the operator's revised plan)");
535
+ sendError(res, 400, "request.field_conflict", "decision 'edit' requires a non-empty editedPlan (the operator's revised plan)", fieldConflictFacts("plan_edit", ["decision", "editedPlan"]));
524
536
  return;
525
537
  }
526
538
  const decidedByReading = readDecidedBy(body.decidedBy, deps.config.directDoorActive);
@@ -543,7 +555,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
543
555
  return;
544
556
  }
545
557
  if (decision !== "edit" && body.editedPlan !== undefined) {
546
- sendError(res, 400, "request.field_conflict", `editedPlan is only valid with decision 'edit' (got '${decision}')`);
558
+ sendError(res, 400, "request.field_conflict", `editedPlan is only valid with decision 'edit' (got '${decision}')`, fieldConflictFacts("plan_edit", ["editedPlan", "decision"]));
547
559
  return;
548
560
  }
549
561
  if (body.permissionModeAfter !== undefined && !isPlanApprovePermissionModeAfter(body.permissionModeAfter)) {
@@ -551,7 +563,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
551
563
  return;
552
564
  }
553
565
  if (!planReviewDecisionExitsPlan(decision) && body.permissionModeAfter !== undefined) {
554
- sendError(res, 400, "request.field_conflict", `permissionModeAfter is only valid with a decision that carries the plan out ('approve' or 'edit'; got '${decision}')`);
566
+ sendError(res, 400, "request.field_conflict", `permissionModeAfter is only valid with a decision that carries the plan out ('approve' or 'edit'; got '${decision}')`, fieldConflictFacts("plan_mode_after", ["permissionModeAfter", "decision"]));
555
567
  return;
556
568
  }
557
569
  if (body.reason !== undefined && typeof body.reason !== "string") {
@@ -572,7 +584,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
572
584
  return;
573
585
  }
574
586
  if (!deps.config.directDoorActive) {
575
- sendError(res, 400, "request.field_conflict", "boundCallId (the plan_review nonce) is only valid on a direct-door worker — a BFF worker carries no decision proof to bind it to");
587
+ sendError(res, 400, "request.field_conflict", "boundCallId (the plan_review nonce) is only valid on a direct-door worker — a BFF worker carries no decision proof to bind it to", fieldConflictFacts("bound_call_door", ["boundCallId"]));
576
588
  return;
577
589
  }
578
590
  }
@@ -611,8 +623,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
611
623
  deciderPrincipal = proof.principal;
612
624
  singleUse = proof.singleUse === undefined ? undefined : { proof: proof.singleUse, store };
613
625
  }
614
- const operators = deps.config.operatorPrincipals;
615
- const explicitOperator = explicitOperatorOk(deciderPrincipal, operators);
626
+ const explicitOperator = explicitOperatorOk(deciderPrincipal, deps.config);
616
627
  if (!explicitOperator && run.owner !== null && run.owner !== deciderPrincipal) {
617
628
  deps.logger?.info?.("decide_404", { reason: "owner-mismatch", taskId, principalPresent: principal !== undefined });
618
629
  sendError(res, 404, "not_found.run", "task not found");
@@ -626,7 +637,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
626
637
  if (body.permissionModeAfter !== undefined) {
627
638
  const storedCtx = plan.prepared.ctx;
628
639
  if (storedCtx.body !== undefined && storedBodyPermissionMode(storedCtx.body) !== "plan") {
629
- sendError(res, 400, "request.field_conflict", "permissionModeAfter does not apply to this task: it was not started in plan mode (its stored permission mode is not \"plan\"), so approving the plan returns it to the mode it was in before planning");
640
+ sendError(res, 400, "request.field_conflict", "permissionModeAfter does not apply to this task: it was not started in plan mode (its stored permission mode is not \"plan\"), so approving the plan returns it to the mode it was in before planning", fieldConflictFacts("plan_mode_after", ["permissionModeAfter"]));
630
641
  return;
631
642
  }
632
643
  }
@@ -657,7 +668,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
657
668
  const body = (await readJson(req));
658
669
  const decision = body?.decision === "approve" ? "approve" : body?.decision === "deny" ? "deny" : undefined;
659
670
  if (!decision) {
660
- sendError(res, 400, "request.body_shape", "body must be { decision: 'approve' | 'deny', reason?, answer?, checkpointToken?, boundCallId?, boundInputHash?, updatedInput?, remember?, decidedBy? }", retiredDecisionKeyFacts(body)?.extra);
671
+ sendError(res, 400, "request.body_shape", "body must be { decision: 'approve' | 'deny', reason?, answer?, checkpointToken?, boundCallId?, boundInputHash?, updatedInput?, remember?, decidedBy?, feedback? }", retiredDecisionKeyFacts(body)?.extra);
661
672
  return;
662
673
  }
663
674
  {
@@ -683,7 +694,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
683
694
  return;
684
695
  }
685
696
  if (decision !== "approve") {
686
- sendError(res, 400, "request.field_conflict", "remember requires decision 'approve'");
697
+ sendError(res, 400, "request.field_conflict", "remember requires decision 'approve'", fieldConflictFacts("remember_decision", ["remember", "decision"]));
687
698
  return;
688
699
  }
689
700
  if (deps.config.directDoorActive) {
@@ -721,6 +732,10 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
721
732
  return;
722
733
  }
723
734
  }
735
+ if (body.feedback !== undefined && typeof body.feedback !== "string") {
736
+ sendError(res, 400, "request.field_invalid", "feedback must be a string (the words the approving person wrote on the card; omit the key when there are none)");
737
+ return;
738
+ }
724
739
  if (deps.config.directDoorActive && body.updatedInput !== undefined) {
725
740
  sendError(res, 400, "updated_input_not_in_proof", "updatedInput is not supported on a direct-door worker (not covered by the decision proof)");
726
741
  return;
@@ -729,6 +744,10 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
729
744
  sendError(res, 400, "checkpoint_token_not_in_proof", "checkpointToken is not supported on a direct-door worker (not covered by the decision proof); bind the decision with boundCallId and boundInputHash instead");
730
745
  return;
731
746
  }
747
+ if (deps.config.directDoorActive && body.feedback !== undefined) {
748
+ sendError(res, 400, "feedback_not_in_proof", "feedback is not supported on a direct-door worker (not covered by the decision proof)");
749
+ return;
750
+ }
732
751
  const decidedByReading = readDecidedBy(body.decidedBy, deps.config.directDoorActive);
733
752
  switch (decidedByReading.kind) {
734
753
  case "not_in_proof":
@@ -745,11 +764,20 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
745
764
  }
746
765
  }
747
766
  const decidedBy = decidedByReading.decidedBy;
767
+ if (body.feedback !== undefined && decision !== "approve") {
768
+ sendError(res, 400, "request.field_conflict", "feedback is only valid with decision 'approve' — the words of a denial are its reason", fieldConflictFacts("approval_feedback", ["feedback", "decision"]));
769
+ return;
770
+ }
771
+ if (body.feedback !== undefined && decidedBy !== "person") {
772
+ sendError(res, 400, "request.field_conflict", "feedback is only valid on a person's decision — the agent reads it as the user's own words, which a policy decision cannot carry", fieldConflictFacts("approval_feedback", ["feedback", "decidedBy"]));
773
+ return;
774
+ }
748
775
  const binding = {
749
776
  checkpointToken: body.checkpointToken,
750
777
  boundCallId: body.boundCallId,
751
778
  boundInputHash: body.boundInputHash,
752
779
  updatedInput: body.updatedInput,
780
+ ...(typeof body.feedback === "string" ? { feedback: body.feedback } : {}),
753
781
  };
754
782
  let deciderPrincipal = principal;
755
783
  if (deps.config.directDoorActive) {
@@ -770,8 +798,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
770
798
  }
771
799
  deciderPrincipal = proof.principal;
772
800
  }
773
- const operators = deps.config.operatorPrincipals;
774
- const explicitOperator = explicitOperatorOk(deciderPrincipal, operators);
801
+ const explicitOperator = explicitOperatorOk(deciderPrincipal, deps.config);
775
802
  if (!explicitOperator) {
776
803
  const cpScope = await cs
777
804
  .peekPendingScope(sessionId, { gateKinds: APPROVAL_GATE_KINDS })
@@ -814,6 +841,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
814
841
  ...(decision === "approve" && binding.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}),
815
842
  ...(answer !== undefined ? { answer } : {}),
816
843
  ...((r) => (r !== undefined ? { reason: r } : {}))(decisionReasonOf(body)),
844
+ ...(binding.feedback !== undefined ? { feedback: binding.feedback } : {}),
817
845
  },
818
846
  deciderPrincipal,
819
847
  explicitOperator,
@@ -830,6 +858,9 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
830
858
  return assertNever(match.decl.id);
831
859
  }
832
860
  const APPROVALS_STREAM_POLL_MS = 3000;
861
+ function isApprovalsReadCorrupt(err) {
862
+ return err instanceof StoreCorruptError;
863
+ }
833
864
  function redactPendingDisclosures(row) {
834
865
  const rd = row.riskDescriptor;
835
866
  if (rd === null || rd === undefined)
@@ -895,23 +926,27 @@ export async function streamApprovals(req, res, cs, live, scope, governance, pol
895
926
  });
896
927
  let first = true;
897
928
  while (!closed) {
898
- let pending;
899
- let livePending;
929
+ let snapshot;
900
930
  try {
901
- pending = (await cs.listPending(scope)).map((r) => projectPendingForWire(r, governance));
902
- livePending = live ? live.listLivePending(scope) : [];
931
+ const pending = (await cs.listPending(scope)).map((r) => projectPendingForWire(r, governance));
932
+ snapshot = { pending, livePending: live ? live.listLivePending(scope) : [] };
903
933
  }
904
- catch {
934
+ catch (err) {
935
+ if (isApprovalsReadCorrupt(err)) {
936
+ if (!res.writableEnded)
937
+ res.write(`event: error\ndata: ${JSON.stringify({ type: "error", errorCode: "approvals.read_corrupt", message: "a stored approval row cannot be read - this stream is closing, and reconnecting will fail the same way until an operator repairs or removes the row" })}\n\n`);
938
+ break;
939
+ }
905
940
  if (!res.writableEnded)
906
- res.write(`event: heartbeat\ndata: ${JSON.stringify({ type: "heartbeat" })}\n\n`);
907
- await sleep(pollMs);
908
- continue;
941
+ res.write(`event: error\ndata: ${JSON.stringify({ type: "error", errorCode: "approvals.read_unavailable", message: "the approvals queue could not be read - this stream stays open and retries on its next poll; until a read succeeds, silence here does not mean nothing is pending" })}\n\n`);
909
942
  }
910
- durableLane.tick(pending);
911
- liveLane.tick(livePending);
912
- if (first) {
913
- res.write(`event: synced\ndata: ${JSON.stringify({ type: "synced", count: pending.length })}\n\n`);
914
- first = false;
943
+ if (snapshot !== undefined) {
944
+ durableLane.tick(snapshot.pending);
945
+ liveLane.tick(snapshot.livePending);
946
+ if (first) {
947
+ res.write(`event: synced\ndata: ${JSON.stringify({ type: "synced", count: snapshot.pending.length })}\n\n`);
948
+ first = false;
949
+ }
915
950
  }
916
951
  if (Date.now() - start > SSE_MAX_STREAM_MS) {
917
952
  res.write(`event: error\ndata: ${JSON.stringify({ type: "error", errorCode: "STREAM_MAX_DURATION", message: "approvals stream reached its 15-minute cap — reconnect to continue" })}\n\n`);
@@ -7,6 +7,7 @@ import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal } from "../pri
7
7
  import {} from "../route-ctx.js";
8
8
  import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
9
9
  import * as facts from "../../capability-facts.js";
10
+ import { sessionOwnerCellOf } from "../../security.js";
10
11
  const LIST_LIMIT = 500;
11
12
  export const DESCRIPTION_MAX = 500;
12
13
  const ROW_KEY_DISPOSITION = {
@@ -67,8 +68,8 @@ export async function handleBackground(req, res, match, ctx) {
67
68
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
68
69
  return;
69
70
  }
70
- const isOperator = explicitOperatorOk(principal, deps.config.operatorPrincipals);
71
- if (!isOperator && !ctx.helpers.sessionOwnerOk(req, res, owner))
71
+ const operator = explicitOperatorOk(principal, deps.config);
72
+ if (!operator && !ctx.helpers.sessionOwnerOk(req, res, await sessionOwnerCellOf(owned.sessionStorage, sessionId, owner)))
72
73
  return;
73
74
  const scope = owner ?? "default";
74
75
  switch (id) {
@@ -2,6 +2,8 @@ import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLev
2
2
  import { modelImageInput, modelReasoningDecl, isAtMentionable, selectableCatalog } from "../../model-select.js";
3
3
  import { buildDroppedEntriesWire } from "../../web-admin-client/read-warnings.js";
4
4
  import { buildCandidateRejectedWire } from "../../web-admin-client/candidate-gate.js";
5
+ import { buildModelPlaneFace } from "../../model-plane-face.js";
6
+ import { isRosterGateArmed } from "../../config.js";
5
7
  import { modelKeyPoisonOf, resolveModelApiKey } from "../../key-resolver.js";
6
8
  import { projectSealedKeyCapability } from "../../sealed-key.js";
7
9
  import { cwdHonored, deviceCwdHonored } from "../../task-cwd.js";
@@ -10,7 +12,7 @@ import { leaderEntryRefusal, leaderRunEntry } from "../../leader/run-entry.js";
10
12
  import { autonomyKeepsOpenWriteFace, autonomyModeFloor } from "../../runtime-governance.js";
11
13
  import { DEVICE_PROTOCOL_VERSION, DEVICE_WS_PATH } from "../../device-ws-protocol.js";
12
14
  import { a2aInjectionHonored } from "../../task-a2a.js";
13
- import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
15
+ import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, McpProbeMisaligned, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
14
16
  import { mcpForScenario } from "../../web-admin-client/facade.js";
15
17
  import { sendScenarioNotFound } from "../scenario-read-face.js";
16
18
  import { sendJson, sendError } from "../send.js";
@@ -21,6 +23,7 @@ import { projectWriteProtectionCapability } from "../../write-protection.js";
21
23
  import { projectStoreCapability } from "../../store-posture.js";
22
24
  import { projectWebSearchCapability } from "../../plugins/web-search.js";
23
25
  import { projectExecutionLaneCapability } from "../../capabilities/execution-lane.js";
26
+ import { MCP_ASSERTION_HEADER_SENT } from "../../mcp-assertion-header.js";
24
27
  import { gateCompositeMembers } from "../../capabilities/composite-members.js";
25
28
  import { projectApprovalsStreamLiveCapability } from "../../capabilities/approvals-push.js";
26
29
  import { workflowModelAllowlistFor } from "../../task-workflow.js";
@@ -29,6 +32,7 @@ import * as facts from "../../capability-facts.js";
29
32
  import { judgeAutoModeArming } from "../../auto-mode-face.js";
30
33
  import { coercePermissionModeStrict, PERMISSION_MODE_WORDS, taskHooksHonored } from "../../task-settings.js";
31
34
  import { gatedPrincipal, sendPrincipalRefusal } from "../principal-gate.js";
35
+ import { callerTrust } from "../caller-trust.js";
32
36
  function routePairingOf(deps, name, m) {
33
37
  if (modelKeyPoisonOf(name, deps.config.modelApiKeyEnv ?? {}, process.env, deps.config.modelApiKeys ?? {}) !== undefined)
34
38
  return "unknown";
@@ -72,12 +76,14 @@ export async function handleCapabilities(req, res, match, ctx) {
72
76
  if (autoModeFault !== undefined)
73
77
  deps.logger?.warn("auto_mode_face_resolver_fault", { fault: autoModeFault });
74
78
  const rulesLaneForCaller = facts.ruleLaneForCaller(deps, gatedPrincipal(req, deps.config)).available;
79
+ const streamApprovalFact = facts.streamApproval(deps);
75
80
  sendJson(res, 200, gateCompositeMembers({
76
81
  ...deps.capabilities,
77
82
  ...facts.engineCapabilityBits(),
78
83
  asyncRuns: facts.durableRuns(deps).available,
79
84
  artifacts: facts.durableRuns(deps).available,
80
85
  approvals: facts.checkpointPark(deps).available,
86
+ approvalReadRootGrant: facts.readRootGrant(deps).available,
81
87
  sessions: facts.sessionAuditView(deps).available,
82
88
  deviceExecutor: facts.deviceLane(deps).available
83
89
  ? { enabled: true, protocolVersion: DEVICE_PROTOCOL_VERSION, maxInflightPerDevice: deps.config.remoteExec?.provider === "device" ? (deps.config.remoteExec.maxInflightPerDevice ?? 4) : 4, wsPath: DEVICE_WS_PATH, management: facts.deviceManagement(deps).available }
@@ -100,6 +106,7 @@ export async function handleCapabilities(req, res, match, ctx) {
100
106
  mcpReconnect: facts.mcpReconnect(deps).available,
101
107
  background: { listFace: facts.sessionOwnership(deps).available, exitFaces: facts.sessionOwnership(deps).available },
102
108
  sharedMemory: facts.sharedMemoryRead(deps).available,
109
+ principalInboxDelivery: facts.principalInboxDelivery(deps).available,
103
110
  adoption: facts.adoption(deps).available,
104
111
  memoryBundle: facts.memoryBundle(deps).available,
105
112
  memoryCompliance: facts.memoryCompliance(deps).available,
@@ -124,8 +131,8 @@ export async function handleCapabilities(req, res, match, ctx) {
124
131
  scratchpadDir: true,
125
132
  subagentSteer: facts.subagentSteer(deps).available,
126
133
  subagentResume: facts.subagentSteer(deps).available,
127
- taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: cwdHonored(deps.config) || deviceCwdHonored(deps.config), hooks: taskHooksHonored(deps.config) },
128
- settings: { permissions: { allowGrant: true, allowLayer: true } },
134
+ taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: cwdHonored(deps.config) || deviceCwdHonored(deps.config), hooks: taskHooksHonored(deps.config), pluginHooks: taskHooksHonored(deps.config), managedHookGroups: taskHooksHonored(deps.config), tightenOnlySeats: true, approvalFrameFamilies: true },
135
+ settings: { permissions: { allowGrant: true, allowLayer: true, callerTrust: callerTrust(req, deps.config).trust } },
129
136
  permissionModeAuto: {
130
137
  accepted: true,
131
138
  classifierSeat: deps.autoModeFace?.seatMounted === true,
@@ -160,11 +167,13 @@ export async function handleCapabilities(req, res, match, ctx) {
160
167
  sessionInit: true,
161
168
  mcp: true,
162
169
  mcpProbe: true,
170
+ mcpAssertionHeaderSent: MCP_ASSERTION_HEADER_SENT,
163
171
  mcpElicitation: facts.elicitation(deps).available,
164
172
  askUserQuestion: facts.askUserQuestion(deps).available,
165
173
  toolApproval: facts.toolApproval(deps).available,
166
174
  approvalsStreamLive: projectApprovalsStreamLiveCapability(deps),
167
- streamApproval: facts.streamApproval(deps).available,
175
+ streamApproval: streamApprovalFact.available,
176
+ approvalFrameFamilies: [...facts.approvalFrameFamilies(streamApprovalFact)],
168
177
  approvalDecisionNote: true,
169
178
  approvalDecidedBy: true,
170
179
  permissionModes: [...PERMISSION_MODES],
@@ -273,6 +282,11 @@ export async function handleCapabilities(req, res, match, ctx) {
273
282
  defaultModel: { id: deps.config.model.id, ...(defaultName ? { name: defaultName } : {}) },
274
283
  droppedEntries: buildDroppedEntriesWire(deps.config.droppedCatalogEntries),
275
284
  ...(candidateRejection !== undefined ? { candidateRejected: buildCandidateRejectedWire(candidateRejection) } : {}),
285
+ modelPlane: buildModelPlaneFace(deps.config, {
286
+ envTableIsPlaceholder: isRosterGateArmed(deps.config.webAdmin),
287
+ candidateRejection,
288
+ modelRefusals: deps.modelRefusalsState?.(),
289
+ }),
276
290
  });
277
291
  return;
278
292
  }
@@ -330,6 +344,8 @@ async function answerMcpProbe(res, ctx, answer, outcome, declaredBy) {
330
344
  sendMcpProbeRefusal(res, ctx, buildMcpProbeIncompleteRefusal(err.boundMs), "failed", Math.ceil(err.boundMs / 1000));
331
345
  return;
332
346
  }
347
+ if (err instanceof McpProbeMisaligned)
348
+ throw err;
333
349
  if (declaredBy === "caller") {
334
350
  sendMcpProbeRefusal(res, ctx, buildMcpProbeDeclarationRefusal(), "failed");
335
351
  return;
@@ -9,9 +9,9 @@
9
9
  * 门序 = operator 面口径:身份 → 能力(事实 `configCatalog`,501)→ 授权 → 应答;billable=false,
10
10
  * 刻意不吃 drain / roster-pending 两道 503(排障读面在停机窗里恰恰要打得通)。
11
11
  *
12
- * 🔴 鉴权 = `explicitOperatorOk`(空名单=谁都不是)——设计稿 §0.5 点名**禁** `isOperator` 那个
13
- * 「空名单=人人都是」的 fail-open 谓词:本面是部署事实外泄口(env 在场性/后端形态/限额值),
14
- * 单用户形也不放宽。
12
+ * 🔴 鉴权 = `explicitOperatorOk`(「谁是 operator」的唯一读法:空名单 = 谁都不是)—— 设计稿 §0.5 点名禁「空名单 = 人人都是」的 fail-open 读法
13
+ * (S-1050 起整只删):本面是部署事实外泄口(env 在场性 / 后端形态 / 限额值)。单用户形只在部署方显式声明 `OPERATOR_SINGLE_USER=true`
14
+ * (每个调用方都是运维)时对调用方开。
15
15
  *
16
16
  * 🔴 旋钮 `CONFIG_CATALOG_ENABLED=false` / operator 名单空 ⇒ 501(事实 `configCatalog`,与能力位同一只函数):
17
17
  * 旋钮关 = `feature.config_catalog_disabled`(合规部署不想让部署事实上 wire 的表态;「去开旋钮」由码与句承担),
@@ -29,7 +29,7 @@ export async function handleConfigCatalog(req, res, match, ctx) {
29
29
  return assertNever(fact.why);
30
30
  }
31
31
  }
32
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
32
+ if (!explicitOperatorOk(principal, deps.config)) {
33
33
  sendError(res, 403, "auth.operator_only", OPERATOR_ONLY_MESSAGE);
34
34
  return;
35
35
  }
@@ -47,14 +47,7 @@ function bodyKeyIssue(body, accepted) {
47
47
  return `unknown key(s) in body: ${extra.join(", ")} — this endpoint accepts ${accepted.length === 0 ? "no body keys" : accepted.slice().sort().join(", ")} (a silently dropped key is a declaration that never existed)`;
48
48
  }
49
49
  async function readClosedBody(req, res, readJson, accepted) {
50
- let body;
51
- try {
52
- body = await readJson(req);
53
- }
54
- catch {
55
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
56
- return null;
57
- }
50
+ const body = await readJson(req);
58
51
  if (typeof body !== "object" || body === null || Array.isArray(body)) {
59
52
  sendError(res, 400, "request.body_shape", "body must be a JSON object");
60
53
  return null;
@@ -151,7 +144,7 @@ export async function handleDevices(req, res, match, ctx) {
151
144
  }
152
145
  }
153
146
  const { store, hub, enrollment, runStore } = lane;
154
- const operator = explicitOperatorOk(principal, deps.config.operatorPrincipals);
147
+ const operator = explicitOperatorOk(principal, deps.config);
155
148
  const domain = deviceOwnerDomainOf(req, deps.config);
156
149
  if (match.decl.id === "devices-list") {
157
150
  if (!operator && domain === undefined) {
@@ -277,14 +270,7 @@ export async function handleDevices(req, res, match, ctx) {
277
270
  sendDeviceNotFound(res);
278
271
  return;
279
272
  }
280
- let body;
281
- try {
282
- body = (await readJson(req));
283
- }
284
- catch {
285
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
286
- return;
287
- }
273
+ const body = (await readJson(req));
288
274
  if (typeof body !== "object" || body === null || typeof body.toDeviceId !== "string" || body.expectedRev === undefined) {
289
275
  sendError(res, 400, "request.body_shape", "body must be { toDeviceId: string, expectedRev: number } — expectedRev is the binding rev read from GET /v1/devices/sessions/{rootSessionId} (explicit prior state; two concurrent operators must not silently stomp each other)");
290
276
  return;
@@ -43,8 +43,8 @@ export interface ServerWiringGateInput {
43
43
  streamApprovalEnabled: boolean;
44
44
  /** 谓词自己的入参类型(结构形,不 import store 依赖树)—— 取型而非重述,两处不可能漂。 */
45
45
  backend: StreamApprovalGateInput["backend"];
46
- /** 在场性即事实;本面不取实例,故 `unknown` 足够(取窄型会把整棵 store 类型树拖进诊断域)。 */
47
- checkpointStore: unknown;
46
+ /** 谓词自己的入参类型(只收店的形,工厂方法过不了 tsc)—— 取型而非重述,与 `backend` 同理;在场性即事实,本面不读实例的内容。 */
47
+ checkpointStore: StreamApprovalGateInput["checkpointStore"];
48
48
  durableApproval: boolean;
49
49
  /** S-178:三个 posture 旋钮的**来源**,取自 config 上与值同处写的那一格(不在这里重判)。 */
50
50
  durableApprovalSource: PostureSource;
@@ -68,7 +68,7 @@ export interface StaticWiringAudit {
68
68
  export interface StaticWiringFacts {
69
69
  /** core `describeStaticWiring(deps, specTemplate)` 的产物。 */
70
70
  manifest: WiringManifest;
71
- /** 我方喂给 `resolveStreamApprovalGate` 的 `parkFacility` 实参(= checkpoint 店在场 ∧ DURABLE_APPROVAL)。 */
71
+ /** 我方喂给 `resolveStreamApprovalGate` 的 `checkpointStore` 实参的在场性(= checkpoint 店在场 ∧ DURABLE_APPROVAL)。 */
72
72
  parkFacility: boolean;
73
73
  /** store backend 的种类;`undefined` = env-only worker(无 backend)。 */
74
74
  backendKind: "mysql" | "pg" | "local" | undefined;
@@ -12,27 +12,31 @@ export function buildServerWiringGates(input) {
12
12
  toolApprovalEnabled: input.toolApprovalEnabled,
13
13
  streamApprovalEnabled: input.streamApprovalEnabled,
14
14
  backend: input.backend,
15
- parkFacility: input.checkpointStore !== undefined,
15
+ checkpointStore: input.checkpointStore,
16
16
  });
17
17
  const noCenterArm = (knob) => `this knob has no web-admin arm on this deployment — it is set by ${knob} on this machine, or derived from the deployment posture`;
18
+ const noLaneArm = (knob) => `this knob has no execution-lane default — ${knob} does not depend on which execution lane this deployment runs`;
18
19
  return {
19
20
  streamApproval: gate.active ? "active" : gate.reason,
20
21
  durableApproval: buildPostureKnobReading(input.durableApproval, {
21
22
  knob: "DURABLE_APPROVAL",
22
23
  source: input.durableApprovalSource,
23
24
  centerMeaning: noCenterArm("DURABLE_APPROVAL"),
25
+ laneMeaning: noLaneArm("DURABLE_APPROVAL"),
24
26
  postureMeaning: "derived from the single-user turnkey posture (REQUIRE_PRINCIPAL is not set) composed with a durable store being present: park/resume and the /v1/approvals routes are on by default — set DURABLE_APPROVAL=false to pin them off",
25
27
  }),
26
28
  streamAskWindowMs: buildPostureKnobReading(input.streamAskWindowMs, {
27
29
  knob: "STREAM_ASK_WINDOW_MS",
28
30
  source: input.streamAskWindowMsSource,
29
31
  centerMeaning: noCenterArm("STREAM_ASK_WINDOW_MS"),
32
+ laneMeaning: noLaneArm("STREAM_ASK_WINDOW_MS"),
30
33
  postureMeaning: "derived from the single-user turnkey posture (REQUIRE_PRINCIPAL is not set): an approval card waits 24h instead of 5 minutes, so stepping away does not settle the run unattended — set STREAM_ASK_WINDOW_MS to pin your own window",
31
34
  }),
32
35
  sessionAutoTitle: buildPostureKnobReading(input.sessionAutoTitle, {
33
36
  knob: "SESSION_AUTO_TITLE",
34
37
  source: input.sessionAutoTitleSource,
35
38
  centerMeaning: noCenterArm("SESSION_AUTO_TITLE"),
39
+ laneMeaning: noLaneArm("SESSION_AUTO_TITLE"),
36
40
  postureMeaning: "this knob has no posture arm — its default is the same on every deployment shape",
37
41
  }),
38
42
  checkpointStore: input.checkpointStore !== undefined,
@@ -93,7 +97,7 @@ export async function handleDiagnostics(req, res, match, ctx) {
93
97
  return;
94
98
  }
95
99
  const principal = gatedPrincipal(req, deps.config);
96
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
100
+ if (!explicitOperatorOk(principal, deps.config)) {
97
101
  sendError(res, 403, "auth.operator_only", "wiring diagnostics are operator-only on a multi-tenant worker");
98
102
  return;
99
103
  }