@sema-agent/server 7.131.0 → 7.133.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 (509) hide show
  1. package/MIGRATION.md +575 -0
  2. package/README.md +12 -9
  3. package/README.zh-CN.md +9 -6
  4. package/USAGE.md +326 -98
  5. package/deploy/sema-up/README.md +19 -1
  6. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
  7. package/deploy/sema-up/chart/templates/server.yaml +5 -2
  8. package/deploy/sema-up/stack/compose.yaml +3 -0
  9. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  10. package/dist/adoption/plan.d.ts +3 -2
  11. package/dist/adoption/plan.js +7 -5
  12. package/dist/adoption/runner.js +3 -10
  13. package/dist/adoption/sql.d.ts +3 -2
  14. package/dist/adoption/sql.js +3 -5
  15. package/dist/adoption/wire.d.ts +4 -1
  16. package/dist/adoption/wire.js +1 -0
  17. package/dist/approval-ask-audit-store.d.ts +31 -13
  18. package/dist/approval-ask-audit-store.js +272 -74
  19. package/dist/approval-ask-machine.d.ts +15 -0
  20. package/dist/approval-ask-machine.js +6 -0
  21. package/dist/approval-ask-retention.d.ts +136 -0
  22. package/dist/approval-ask-retention.js +102 -0
  23. package/dist/approval-card.d.ts +82 -20
  24. package/dist/approval-card.js +46 -16
  25. package/dist/approval-deny-reasons.d.ts +1 -1
  26. package/dist/approval.d.ts +9 -0
  27. package/dist/approval.js +24 -3
  28. package/dist/audit.d.ts +33 -19
  29. package/dist/audit.js +12 -16
  30. package/dist/auth-bridge.d.ts +4 -0
  31. package/dist/auth-bridge.js +10 -11
  32. package/dist/bake-runner/main.js +3 -2
  33. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  34. package/dist/boot/deployment-mods.d.ts +31 -0
  35. package/dist/boot/deployment-mods.js +26 -0
  36. package/dist/boot/execution-env.d.ts +1 -1
  37. package/dist/boot/execution-env.js +27 -12
  38. package/dist/boot/execution-lane.js +11 -0
  39. package/dist/boot/leader.js +2 -0
  40. package/dist/boot/memory-boundary.d.ts +2 -2
  41. package/dist/boot/memory-boundary.js +2 -2
  42. package/dist/boot/memory-consolidation.d.ts +5 -4
  43. package/dist/boot/memory-consolidation.js +7 -6
  44. package/dist/boot/org-delivery.d.ts +28 -0
  45. package/dist/boot/org-delivery.js +20 -0
  46. package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
  47. package/dist/boot/read-deny-anchor-audit.js +36 -0
  48. package/dist/boot/reapers.d.ts +3 -0
  49. package/dist/boot/reapers.js +21 -1
  50. package/dist/boot/resolve-spec.d.ts +4 -5
  51. package/dist/boot/resolve-spec.js +74 -123
  52. package/dist/boot/runner-deps.d.ts +19 -8
  53. package/dist/boot/runner-deps.js +15 -2
  54. package/dist/boot/session-faces.d.ts +2 -7
  55. package/dist/boot/session-faces.js +4 -2
  56. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  57. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  58. package/dist/boot/stage-03-store-backend.js +2 -2
  59. package/dist/boot/stage-04-stores.d.ts +1 -1
  60. package/dist/boot/stage-05-execution-env.d.ts +4 -4
  61. package/dist/boot/stage-05-execution-env.js +7 -10
  62. package/dist/boot/stage-06-runners.d.ts +4 -2
  63. package/dist/boot/stage-06-runners.js +11 -7
  64. package/dist/boot/stage-07-capability-layer.d.ts +4 -2
  65. package/dist/boot/stage-07-capability-layer.js +27 -6
  66. package/dist/boot/stage-08-reapers.d.ts +4 -2
  67. package/dist/boot/stage-08-reapers.js +2 -2
  68. package/dist/boot/stage-09-leader.d.ts +6 -9
  69. package/dist/boot/stage-10-http-server.d.ts +6 -9
  70. package/dist/boot/stage-10-http-server.js +7 -9
  71. package/dist/boot/stores.d.ts +1 -1
  72. package/dist/boot/stores.js +7 -8
  73. package/dist/boot/web-admin.d.ts +4 -3
  74. package/dist/boot/web-admin.js +186 -98
  75. package/dist/boot/workflow-orchestration.d.ts +2 -0
  76. package/dist/boot/workflow-orchestration.js +2 -1
  77. package/dist/brain.js +25 -25
  78. package/dist/breaker-key.d.ts +6 -0
  79. package/dist/breaker-key.js +29 -0
  80. package/dist/budget.js +5 -4
  81. package/dist/caller-text-echo.d.ts +23 -0
  82. package/dist/caller-text-echo.js +21 -0
  83. package/dist/capabilities/brand-identity.d.ts +26 -0
  84. package/dist/capabilities/brand-identity.js +27 -0
  85. package/dist/capabilities/center-plugins.d.ts +7 -0
  86. package/dist/capabilities/center-plugins.js +1 -1
  87. package/dist/capabilities/center-prompts.d.ts +32 -59
  88. package/dist/capabilities/center-prompts.js +18 -32
  89. package/dist/capabilities/composite-members.d.ts +1 -1
  90. package/dist/capabilities/composite-members.js +1 -1
  91. package/dist/capabilities/engine-capabilities.js +2 -1
  92. package/dist/capabilities/execution-lane.js +2 -2
  93. package/dist/capabilities/hands-lane.d.ts +30 -6
  94. package/dist/capabilities/hands-lane.js +11 -1
  95. package/dist/capabilities/mcp-probe.d.ts +48 -3
  96. package/dist/capabilities/mcp-probe.js +47 -135
  97. package/dist/capabilities/scenarios.d.ts +95 -45
  98. package/dist/capabilities/scenarios.js +53 -38
  99. package/dist/capabilities/skills.d.ts +19 -4
  100. package/dist/capabilities/skills.js +30 -10
  101. package/dist/capability-facts.d.ts +34 -4
  102. package/dist/capability-facts.js +28 -2
  103. package/dist/center-config-tier.d.ts +69 -0
  104. package/dist/center-config-tier.js +42 -0
  105. package/dist/checkpoint-identity.d.ts +16 -0
  106. package/dist/checkpoint-identity.js +19 -0
  107. package/dist/config-catalog.d.ts +17 -10
  108. package/dist/config-catalog.js +47 -32
  109. package/dist/config-d-migration.d.ts +3 -1
  110. package/dist/config-d-migration.js +2 -2
  111. package/dist/config-dir-trust.d.ts +114 -0
  112. package/dist/config-dir-trust.js +388 -0
  113. package/dist/config-invariants.d.ts +18 -5
  114. package/dist/config-invariants.js +35 -3
  115. package/dist/config-lkg.d.ts +9 -9
  116. package/dist/config-lkg.js +20 -4
  117. package/dist/config-provider.d.ts +9 -2
  118. package/dist/config-provider.js +18 -6
  119. package/dist/config-types.d.ts +75 -20
  120. package/dist/config-types.js +8 -0
  121. package/dist/config.d.ts +13 -0
  122. package/dist/config.js +137 -62
  123. package/dist/delegated-session-owner.d.ts +185 -0
  124. package/dist/delegated-session-owner.js +119 -0
  125. package/dist/device-protocol.d.ts +5 -3
  126. package/dist/device-protocol.js +1 -1
  127. package/dist/device-ws-hub.js +21 -2
  128. package/dist/device-ws-protocol.d.ts +70 -6
  129. package/dist/device-ws-protocol.js +50 -22
  130. package/dist/elicitation.js +3 -2
  131. package/dist/entry-problems.d.ts +34 -0
  132. package/dist/entry-problems.js +14 -0
  133. package/dist/env-name-allowlist-knobs.d.ts +12 -2
  134. package/dist/env-name-allowlist-knobs.js +5 -4
  135. package/dist/exec-bounds.d.ts +15 -3
  136. package/dist/exec-bounds.js +4 -0
  137. package/dist/execution-lane-caps.d.ts +56 -10
  138. package/dist/execution-lane-caps.js +50 -0
  139. package/dist/field-conflict.d.ts +43 -0
  140. package/dist/field-conflict.js +20 -0
  141. package/dist/fleet/fleet-bus.d.ts +80 -6
  142. package/dist/fleet/fleet-bus.js +41 -9
  143. package/dist/hooks/classic-stations.d.ts +91 -0
  144. package/dist/hooks/classic-stations.js +27 -0
  145. package/dist/hooks/command-spawn.d.ts +57 -0
  146. package/dist/hooks/command-spawn.js +139 -0
  147. package/dist/hooks/hook-llm.d.ts +8 -5
  148. package/dist/hooks/hook-llm.js +79 -36
  149. package/dist/hooks/hook-runner.d.ts +349 -95
  150. package/dist/hooks/hook-runner.js +855 -568
  151. package/dist/hooks/hook-source.d.ts +44 -0
  152. package/dist/hooks/hook-source.js +40 -0
  153. package/dist/http/active-run-conflict.d.ts +5 -13
  154. package/dist/http/active-run-conflict.js +17 -27
  155. package/dist/http/admission.d.ts +8 -2
  156. package/dist/http/admission.js +188 -101
  157. package/dist/http/approval-sweeps.js +99 -21
  158. package/dist/http/caller-trust.d.ts +77 -0
  159. package/dist/http/caller-trust.js +143 -0
  160. package/dist/http/checkpoint-ctx.d.ts +41 -24
  161. package/dist/http/checkpoint-ctx.js +23 -16
  162. package/dist/http/claimed-run.d.ts +14 -0
  163. package/dist/http/claimed-run.js +15 -0
  164. package/dist/http/device-placement.d.ts +2 -4
  165. package/dist/http/device-placement.js +7 -11
  166. package/dist/http/dispatch.d.ts +0 -4
  167. package/dist/http/dispatch.js +15 -13
  168. package/dist/http/durable-run-leg.d.ts +6 -33
  169. package/dist/http/durable-run-leg.js +36 -10
  170. package/dist/http/health-self-report.d.ts +7 -5
  171. package/dist/http/health-self-report.js +4 -18
  172. package/dist/http/owner-access.d.ts +56 -0
  173. package/dist/http/owner-access.js +42 -0
  174. package/dist/http/principal-gate.d.ts +70 -28
  175. package/dist/http/principal-gate.js +61 -15
  176. package/dist/http/readiness.d.ts +11 -5
  177. package/dist/http/readiness.js +10 -3
  178. package/dist/http/refusal-body.d.ts +21 -0
  179. package/dist/http/refusal-body.js +4 -0
  180. package/dist/http/request-guards.d.ts +43 -23
  181. package/dist/http/request-guards.js +53 -17
  182. package/dist/http/resume-ctx-read.d.ts +2 -5
  183. package/dist/http/resume-ctx-read.js +7 -4
  184. package/dist/http/resume-legs.d.ts +28 -4
  185. package/dist/http/resume-legs.js +169 -91
  186. package/dist/http/retired-service-deps.d.ts +43 -0
  187. package/dist/http/retired-service-deps.js +18 -0
  188. package/dist/http/route-ctx.d.ts +44 -28
  189. package/dist/http/route-ctx.js +4 -0
  190. package/dist/http/route-table.js +2 -0
  191. package/dist/http/routes/a2a-serve.js +3 -4
  192. package/dist/http/routes/admin-config-refresh.js +1 -1
  193. package/dist/http/routes/admin-drain.js +1 -1
  194. package/dist/http/routes/admin-memory-optout.js +5 -1
  195. package/dist/http/routes/adoption.js +2 -9
  196. package/dist/http/routes/approvals-assistant.js +49 -48
  197. package/dist/http/routes/background.js +3 -2
  198. package/dist/http/routes/capabilities.js +21 -5
  199. package/dist/http/routes/config-catalog.d.ts +3 -3
  200. package/dist/http/routes/config-catalog.js +1 -1
  201. package/dist/http/routes/devices.js +3 -17
  202. package/dist/http/routes/diagnostics.js +6 -2
  203. package/dist/http/routes/images.js +6 -7
  204. package/dist/http/routes/leader.js +1 -8
  205. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  206. package/dist/http/routes/mcp-reconnect.js +3 -2
  207. package/dist/http/routes/memory-bundle.js +1 -1
  208. package/dist/http/routes/memory-compliance.js +1 -1
  209. package/dist/http/routes/memory-consolidation.js +1 -1
  210. package/dist/http/routes/memory-origin.js +1 -1
  211. package/dist/http/routes/memory-policy.d.ts +1 -1
  212. package/dist/http/routes/memory-policy.js +3 -2
  213. package/dist/http/routes/notify-wake.js +8 -21
  214. package/dist/http/routes/observability.js +2 -2
  215. package/dist/http/routes/principal-inbox.d.ts +39 -0
  216. package/dist/http/routes/principal-inbox.js +76 -0
  217. package/dist/http/routes/retention-ops.js +2 -9
  218. package/dist/http/routes/rules.js +5 -18
  219. package/dist/http/routes/runs.d.ts +5 -0
  220. package/dist/http/routes/runs.js +34 -107
  221. package/dist/http/routes/session-sync.js +15 -26
  222. package/dist/http/routes/sessions.js +30 -40
  223. package/dist/http/routes/shared-memory.js +2 -13
  224. package/dist/http/routes/side-query.js +8 -7
  225. package/dist/http/routes/tasks.js +67 -21
  226. package/dist/http/routes/workflows.d.ts +351 -0
  227. package/dist/http/routes/workflows.js +153 -119
  228. package/dist/http/send.d.ts +33 -10
  229. package/dist/http/send.js +21 -4
  230. package/dist/http/server.d.ts +27 -18
  231. package/dist/http/server.js +34 -6
  232. package/dist/http/stored-body-replay.js +17 -4
  233. package/dist/http/submit-ctx.d.ts +25 -0
  234. package/dist/http/submit-ctx.js +40 -0
  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 +11 -8
  238. package/dist/index.d.ts +2 -2
  239. package/dist/index.js +1 -2
  240. package/dist/lane-home-probe.d.ts +112 -0
  241. package/dist/lane-home-probe.js +101 -0
  242. package/dist/leader/endpoint.d.ts +4 -1
  243. package/dist/leader/endpoint.js +11 -10
  244. package/dist/limit-refusal.d.ts +59 -0
  245. package/dist/limit-refusal.js +15 -0
  246. package/dist/main.js +1 -1
  247. package/dist/mcp-assertion-header.d.ts +32 -19
  248. package/dist/mcp-assertion-header.js +10 -9
  249. package/dist/mcp-tool-faces.d.ts +5 -0
  250. package/dist/mcp-tool-faces.js +6 -4
  251. package/dist/memory-project-layer.d.ts +37 -0
  252. package/dist/memory-project-layer.js +46 -0
  253. package/dist/memory-scope.d.ts +24 -17
  254. package/dist/memory-scope.js +24 -8
  255. package/dist/memory-sync-client.d.ts +27 -13
  256. package/dist/memory-sync-client.js +107 -18
  257. package/dist/model-entry-refusal.d.ts +9 -1
  258. package/dist/model-entry-refusal.js +6 -1
  259. package/dist/model-plane-face.d.ts +51 -0
  260. package/dist/model-plane-face.js +24 -0
  261. package/dist/model-provider.d.ts +44 -12
  262. package/dist/model-provider.js +21 -2
  263. package/dist/model-route-endpoint.d.ts +9 -12
  264. package/dist/model-route-endpoint.js +8 -11
  265. package/dist/model-route-env.d.ts +22 -0
  266. package/dist/model-route-env.js +2 -0
  267. package/dist/model-route-gap.d.ts +60 -30
  268. package/dist/model-route-gap.js +21 -15
  269. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  270. package/dist/observability/corrupt-read-seat.js +9 -0
  271. package/dist/observability/cost-taxonomy.d.ts +7 -7
  272. package/dist/observability/err-text.d.ts +6 -0
  273. package/dist/observability/err-text.js +18 -4
  274. package/dist/observability/fail-open.d.ts +76 -14
  275. package/dist/observability/fail-open.js +76 -14
  276. package/dist/observability/metrics.js +4 -1
  277. package/dist/observability/prompt-manifest.d.ts +33 -82
  278. package/dist/observability/prompt-manifest.js +122 -17
  279. package/dist/observability/run-terminal.js +14 -6
  280. package/dist/observability/secret-env-scrub.d.ts +13 -1
  281. package/dist/observability/secret-env-scrub.js +13 -1
  282. package/dist/observability/tool-trace.d.ts +16 -21
  283. package/dist/observability/tool-trace.js +58 -49
  284. package/dist/operator-ask.d.ts +10 -0
  285. package/dist/operator-ask.js +3 -0
  286. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  287. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  288. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  289. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  290. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  291. package/dist/orchestration/workflow-notify-journal.js +27 -34
  292. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  293. package/dist/orchestration/workflow-park-decision.js +118 -0
  294. package/dist/org-delivery-gate.d.ts +81 -0
  295. package/dist/org-delivery-gate.js +59 -0
  296. package/dist/panel-tool-names.d.ts +23 -0
  297. package/dist/panel-tool-names.js +8 -0
  298. package/dist/parked-decide.d.ts +39 -6
  299. package/dist/parked-decide.js +98 -51
  300. package/dist/parked-revive-surface.d.ts +9 -2
  301. package/dist/parked-revive-surface.js +11 -8
  302. package/dist/per-task-image.d.ts +7 -1
  303. package/dist/per-task-image.js +3 -3
  304. package/dist/permission-rule-list.d.ts +1 -1
  305. package/dist/permission-rule-list.js +2 -2
  306. package/dist/plain-string-record.d.ts +25 -0
  307. package/dist/plain-string-record.js +32 -0
  308. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  309. package/dist/plugins/approval-ask-store-file.js +21 -0
  310. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  311. package/dist/plugins/approval-ask-store-memory.js +34 -2
  312. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  313. package/dist/plugins/approval-ask-store-sql.js +37 -1
  314. package/dist/plugins/blob-backend.d.ts +83 -15
  315. package/dist/plugins/blob-backend.js +68 -15
  316. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  317. package/dist/plugins/breaker-state-sql.js +4 -4
  318. package/dist/plugins/caching-session-store.d.ts +3 -0
  319. package/dist/plugins/caching-session-store.js +3 -0
  320. package/dist/plugins/checkpoint-store-sql.d.ts +28 -4
  321. package/dist/plugins/checkpoint-store-sql.js +59 -28
  322. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  323. package/dist/plugins/file-history-store-sql.js +3 -1
  324. package/dist/plugins/file-run-store.d.ts +5 -13
  325. package/dist/plugins/file-run-store.js +9 -0
  326. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  327. package/dist/plugins/fork-routing-session-store.js +12 -1
  328. package/dist/plugins/host-platform.d.ts +2 -0
  329. package/dist/plugins/host-platform.js +2 -1
  330. package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
  331. package/dist/plugins/k8s-bg-scripts.js +22 -0
  332. package/dist/plugins/local-checkpoint-store.d.ts +2 -0
  333. package/dist/plugins/local-checkpoint-store.js +11 -3
  334. package/dist/plugins/local-session-store.d.ts +1 -1
  335. package/dist/plugins/local-session-store.js +1 -1
  336. package/dist/plugins/local-session-window.d.ts +39 -0
  337. package/dist/plugins/local-session-window.js +54 -0
  338. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  339. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  340. package/dist/plugins/mailbox-store-sql.js +77 -52
  341. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  342. package/dist/plugins/memory-run-store.d.ts +5 -13
  343. package/dist/plugins/memory-run-store.js +8 -0
  344. package/dist/plugins/one-time-migrations.d.ts +245 -93
  345. package/dist/plugins/one-time-migrations.js +668 -207
  346. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  347. package/dist/plugins/org-delivery-quota-store.js +228 -0
  348. package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
  349. package/dist/plugins/permission-rule-store-sql.js +4 -18
  350. package/dist/plugins/pg-pool.js +39 -7
  351. package/dist/plugins/pg-session-storage.d.ts +20 -8
  352. package/dist/plugins/pg-session-storage.js +34 -21
  353. package/dist/plugins/remote-env-adb.d.ts +12 -12
  354. package/dist/plugins/remote-env-adb.js +21 -6
  355. package/dist/plugins/remote-env-device.js +3 -0
  356. package/dist/plugins/remote-env-e2b.d.ts +1 -1
  357. package/dist/plugins/remote-env-e2b.js +21 -9
  358. package/dist/plugins/remote-env-host.d.ts +9 -9
  359. package/dist/plugins/remote-env-host.js +10 -32
  360. package/dist/plugins/remote-env-k8s.d.ts +103 -38
  361. package/dist/plugins/remote-env-k8s.js +288 -95
  362. package/dist/plugins/remote-env-local-docker.d.ts +27 -13
  363. package/dist/plugins/remote-env-local-docker.js +82 -11
  364. package/dist/plugins/remote-env-ssh.d.ts +21 -12
  365. package/dist/plugins/remote-env-ssh.js +117 -5
  366. package/dist/plugins/remote-shell.d.ts +0 -1
  367. package/dist/plugins/remote-shell.js +1 -2
  368. package/dist/plugins/retention-store-sql.js +6 -2
  369. package/dist/plugins/run-store-sql.d.ts +16 -14
  370. package/dist/plugins/run-store-sql.js +22 -2
  371. package/dist/plugins/schema-consistency.d.ts +54 -0
  372. package/dist/plugins/schema-consistency.js +52 -0
  373. package/dist/plugins/schema-indexes.js +2 -0
  374. package/dist/plugins/send-user-file.js +2 -2
  375. package/dist/plugins/session-epoch-anchor.d.ts +39 -0
  376. package/dist/plugins/session-epoch-anchor.js +22 -0
  377. package/dist/plugins/session-store.d.ts +18 -8
  378. package/dist/plugins/session-store.js +15 -4
  379. package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
  380. package/dist/plugins/shared-memory-store-sql.js +5 -16
  381. package/dist/plugins/sql-driver.d.ts +205 -1
  382. package/dist/plugins/sql-driver.js +325 -13
  383. package/dist/plugins/sql-errors.d.ts +64 -0
  384. package/dist/plugins/sql-errors.js +57 -0
  385. package/dist/plugins/store-backend.d.ts +36 -1
  386. package/dist/plugins/store-backend.js +42 -15
  387. package/dist/plugins/store-contracts.d.ts +42 -0
  388. package/dist/plugins/store-contracts.js +1 -0
  389. package/dist/plugins/tidb-pool.d.ts +6 -1
  390. package/dist/plugins/tidb-pool.js +44 -10
  391. package/dist/plugins/tidb-session-storage.d.ts +8 -11
  392. package/dist/plugins/tidb-session-storage.js +6 -16
  393. package/dist/plugins/tidb-session-store.d.ts +24 -4
  394. package/dist/plugins/tidb-session-store.js +29 -5
  395. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  396. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  397. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  398. package/dist/plugins/workflow-run-store-sql.js +50 -9
  399. package/dist/posture-source.d.ts +18 -10
  400. package/dist/posture-source.js +4 -1
  401. package/dist/project-identity.d.ts +45 -6
  402. package/dist/project-identity.js +162 -8
  403. package/dist/project-layer-key.d.ts +28 -0
  404. package/dist/project-layer-key.js +29 -0
  405. package/dist/prompts-domain-validate.d.ts +17 -61
  406. package/dist/prompts-domain-validate.js +9 -119
  407. package/dist/question.js +3 -2
  408. package/dist/read-deny-entry.d.ts +25 -0
  409. package/dist/read-deny-entry.js +12 -0
  410. package/dist/read-face-posture.d.ts +37 -11
  411. package/dist/read-face-posture.js +32 -3
  412. package/dist/request-key-closure.d.ts +9 -2
  413. package/dist/request-key-closure.js +11 -5
  414. package/dist/request-value-closure.d.ts +5 -0
  415. package/dist/request-value-closure.js +11 -3
  416. package/dist/rule-entry-list.d.ts +38 -11
  417. package/dist/rule-entry-list.js +106 -30
  418. package/dist/rules-consent.js +3 -4
  419. package/dist/run-acceptance.d.ts +19 -3
  420. package/dist/run-acceptance.js +13 -1
  421. package/dist/run-local.js +54 -24
  422. package/dist/runs.d.ts +15 -8
  423. package/dist/runs.js +35 -1
  424. package/dist/runtime-caps-resolver.d.ts +16 -6
  425. package/dist/runtime-caps-resolver.js +18 -5
  426. package/dist/sandbox-pkg-source.d.ts +19 -1
  427. package/dist/sandbox-pkg-source.js +29 -7
  428. package/dist/security.d.ts +87 -9
  429. package/dist/security.js +52 -9
  430. package/dist/server-secret-env.d.ts +44 -18
  431. package/dist/server-secret-env.js +49 -8
  432. package/dist/session-error-wire.d.ts +19 -2
  433. package/dist/session-error-wire.js +5 -1
  434. package/dist/session-incarnation.d.ts +15 -5
  435. package/dist/session-incarnation.js +16 -9
  436. package/dist/session-titled-frame.d.ts +33 -0
  437. package/dist/session-titled-frame.js +4 -0
  438. package/dist/session-titler.d.ts +9 -1
  439. package/dist/session-titler.js +27 -6
  440. package/dist/spec-fields.d.ts +28 -16
  441. package/dist/spec-fields.js +66 -54
  442. package/dist/sql-engine-posture.d.ts +31 -4
  443. package/dist/sql-engine-posture.js +36 -1
  444. package/dist/stored-request-tool-axes-m19.d.ts +19 -4
  445. package/dist/stored-request-tool-axes-m19.js +30 -2
  446. package/dist/task-a2a.d.ts +9 -1
  447. package/dist/task-a2a.js +73 -47
  448. package/dist/task-cwd.d.ts +1 -1
  449. package/dist/task-mcp.d.ts +46 -58
  450. package/dist/task-mcp.js +82 -107
  451. package/dist/task-settings.d.ts +95 -108
  452. package/dist/task-settings.js +77 -98
  453. package/dist/text-bidi.d.ts +1 -48
  454. package/dist/text-bidi.js +3 -5
  455. package/dist/tighten-only-seats.d.ts +150 -0
  456. package/dist/tighten-only-seats.js +196 -0
  457. package/dist/tool-approval.d.ts +304 -88
  458. package/dist/tool-approval.js +623 -239
  459. package/dist/trace/core-keyset-guard.d.ts +122 -20
  460. package/dist/trace/engine-notice-wire.d.ts +11 -3
  461. package/dist/trace/engine-notice-wire.js +8 -1
  462. package/dist/trace/exit-seat.d.ts +28 -0
  463. package/dist/trace/exit-seat.js +76 -0
  464. package/dist/trace/ledger-events.d.ts +6 -3
  465. package/dist/trace/ledger-sink.js +4 -1
  466. package/dist/trace/model-segment.js +1 -1
  467. package/dist/trace/project.d.ts +98 -17
  468. package/dist/trace/project.js +98 -50
  469. package/dist/trace/projection-table.d.ts +100 -0
  470. package/dist/trace/projection-table.js +130 -0
  471. package/dist/trace/redact.d.ts +54 -0
  472. package/dist/trace/redact.js +778 -152
  473. package/dist/trace/self-minted-wire.d.ts +345 -1
  474. package/dist/trace/self-minted-wire.js +117 -1
  475. package/dist/trace/wire-projection-faces.d.ts +377 -3
  476. package/dist/trace/wire-projection-faces.js +164 -1
  477. package/dist/url-refusal.js +2 -0
  478. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  479. package/dist/web-admin-client/apply-effective.js +56 -5
  480. package/dist/web-admin-client/candidate-gate.d.ts +6 -6
  481. package/dist/web-admin-client/candidate-gate.js +3 -3
  482. package/dist/web-admin-client/facade.d.ts +1 -1
  483. package/dist/web-admin-client/facade.js +1 -1
  484. package/dist/web-admin-client/http-client.js +0 -6
  485. package/dist/web-admin-client/read-face.js +5 -9
  486. package/dist/web-admin-client/read-warnings.d.ts +13 -0
  487. package/dist/web-admin-client/read-warnings.js +10 -0
  488. package/dist/web-admin-client/skills-mcp.d.ts +3 -0
  489. package/dist/web-admin-client/skills-mcp.js +11 -9
  490. package/dist/web-admin-client/types.d.ts +2 -3
  491. package/dist/workspace-cache.d.ts +35 -0
  492. package/dist/workspace-cache.js +36 -0
  493. package/dist/workspace-space.d.ts +3 -2
  494. package/dist/workspace-space.js +2 -0
  495. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +65 -10
  496. package/package.json +8 -4
  497. package/scripts/drain-check-local.mjs +34 -1
  498. package/scripts/drain-check.mysql.sql +30 -2
  499. package/scripts/drain-check.pg.sql +29 -2
  500. package/dist/capabilities/memory-notice.d.ts +0 -138
  501. package/dist/capabilities/memory-notice.js +0 -64
  502. package/dist/capabilities/prompt.d.ts +0 -17
  503. package/dist/capabilities/prompt.js +0 -6
  504. package/dist/mcp-content-origin.d.ts +0 -34
  505. package/dist/mcp-content-origin.js +0 -10
  506. package/dist/tool-axis-words.d.ts +0 -27
  507. package/dist/tool-axis-words.js +0 -9
  508. package/dist/wire-name-bound.d.ts +0 -14
  509. package/dist/wire-name-bound.js +0 -13
@@ -0,0 +1,43 @@
1
+ /**
2
+ * 已退役的 `ServiceDeps` 座 —— 「嵌入方照传旧键」的**唯一判据**(闭集表 + 一只判官)。
3
+ *
4
+ * 病:一个座退役后,类型上它不在了(TypeScript 嵌入方 tsc 红即通告),但类型之外的嵌入方(JS / `as` 硬转)照传旧键 ⇒ 值被装配无声丢掉,
5
+ * 「传了没用」是无声失效 —— 而旧键背后的那道门(受理口的墙、blob 的帽)仍在别处判着,调用方以为自己的值在生效。
6
+ *
7
+ * 律:退役的座在 `createHttpServer` 装配期**响亮拒**,不静默忽略。座的名字只登记在 {@link RETIRED_SERVICE_DEPS} 这一张表里(键 = 旧座名,
8
+ * 值 = 退役版本 + 出路),判官 {@link retiredServiceDepsRefusal} 扫一次摊平后的装配入参(`flattenServiceDeps` 之后:顶层键与各组成员同在,
9
+ * 旧座曾住在 `knobs` 组里,分组形与平铺形同判),命中 ⇒ 交回一句拒话,点名「键 · 退役版本 · 出路」,一次把所有命中的键说全。
10
+ *
11
+ * 「传了」= 自有键在场且值不是 `undefined`(条件装配写 `k: cond ? v : undefined` 的嵌入方什么都没传,不拒)。
12
+ * 一个座新退役时,在表里加一行(同一提交里 CHANGELOG / MIGRATION 的升级条点名它);窗口过后的删表行是单独的一步,不在这里留别名。
13
+ */
14
+ /** 一个退役座的登记:哪一版退的、嵌入方现在该怎么做。 */
15
+ export interface RetiredServiceDep {
16
+ /** 退役所在的版本(拒句里原样说出)。 */
17
+ readonly retiredIn: string;
18
+ /** 出路,接在「was retired in <版本> — 」之后的半句(英文,与起服拒的其余句子同口径)。 */
19
+ readonly wayOut: string;
20
+ }
21
+ /** 闭集:`ServiceDeps` 上已退役的座名。 */
22
+ export declare const RETIRED_SERVICE_DEPS: {
23
+ readonly sqlEngineFacts: {
24
+ readonly retiredIn: "7.132.0";
25
+ readonly wayOut: "replaced by sqlEngine — pass the SQL pool's engine reading as sqlEngine: `{ dialect: \"tidb\" | \"pg\", facts }` where `facts` is read live (a getter) and is null while the pool's connection setup has not succeeded, or leave both unset when there is no SQL store";
26
+ };
27
+ readonly snapshotBlobSqlCapBytes: {
28
+ readonly retiredIn: "7.132.0";
29
+ readonly wayOut: "the HTTP surface no longer holds a blob cap of its own — the SQL snapshot store judges the cap on the connection that executes the write; set SNAPSHOT_BLOB_SQL_MAX_BYTES for a fixed cap, and a self-built file-history store answers an oversized putBlob with `{ ok: false, error: { code \"blob_too_large_for_sql\", message, wallSource } }`";
30
+ };
31
+ readonly snapshotBlobSqlCap: {
32
+ readonly retiredIn: "7.133.0";
33
+ readonly wayOut: "the HTTP surface no longer holds a blob cap of its own — the SQL snapshot store judges the cap on the connection that executes the write; set SNAPSHOT_BLOB_SQL_MAX_BYTES for a fixed cap, and a self-built file-history store answers an oversized putBlob with `{ ok: false, error: { code \"blob_too_large_for_sql\", message, wallSource } }`";
34
+ };
35
+ };
36
+ /** 退役座名的闭集。 */
37
+ export type RetiredServiceDepName = keyof typeof RETIRED_SERVICE_DEPS;
38
+ /**
39
+ * 装配入参(已摊平)里有没有传已退役的座。没有 ⇒ `undefined`;有 ⇒ 一句拒话(按表序把所有命中的键说全:键、退役版本、出路)。
40
+ * 调用方原样抛出 —— 判官只判不抛,抛的位置(装配期)在 `createHttpServer`。
41
+ */
42
+ export declare function retiredServiceDepsRefusal(flatDeps: object): string | undefined;
43
+ //# sourceMappingURL=retired-service-deps.d.ts.map
@@ -0,0 +1,18 @@
1
+ const BLOB_CAP_WAY_OUT = "the HTTP surface no longer holds a blob cap of its own — the SQL snapshot store judges the cap on the connection that executes the write; set SNAPSHOT_BLOB_SQL_MAX_BYTES for a fixed cap, and a self-built file-history store answers an oversized putBlob with `{ ok: false, error: { code \"blob_too_large_for_sql\", message, wallSource } }`";
2
+ export const RETIRED_SERVICE_DEPS = {
3
+ sqlEngineFacts: {
4
+ retiredIn: "7.132.0",
5
+ wayOut: "replaced by sqlEngine — pass the SQL pool's engine reading as sqlEngine: `{ dialect: \"tidb\" | \"pg\", facts }` where `facts` is read live (a getter) and is null while the pool's connection setup has not succeeded, or leave both unset when there is no SQL store",
6
+ },
7
+ snapshotBlobSqlCapBytes: { retiredIn: "7.132.0", wayOut: BLOB_CAP_WAY_OUT },
8
+ snapshotBlobSqlCap: { retiredIn: "7.133.0", wayOut: BLOB_CAP_WAY_OUT },
9
+ };
10
+ const RETIRED_NAMES = Object.keys(RETIRED_SERVICE_DEPS);
11
+ export function retiredServiceDepsRefusal(flatDeps) {
12
+ const hits = RETIRED_NAMES.filter((name) => Object.hasOwn(flatDeps, name) && flatDeps[name] !== undefined);
13
+ if (hits.length === 0)
14
+ return undefined;
15
+ const said = hits.map((name) => `${name} was retired in ${RETIRED_SERVICE_DEPS[name].retiredIn} — ${RETIRED_SERVICE_DEPS[name].wayOut}`).join("; ");
16
+ return `createHttpServer: ${said}; refusing to start rather than silently ignore a retired ServiceDeps seat (the value would no longer do anything)`;
17
+ }
18
+ //# sourceMappingURL=retired-service-deps.js.map
@@ -16,6 +16,8 @@
16
16
  */
17
17
  import type { IncomingMessage, ServerResponse } from "node:http";
18
18
  import type { HostDecision } from "../host-decision.js";
19
+ import type { EntryProblem } from "../entry-problems.js";
20
+ import type { SessionOwnerCell } from "../security.js";
19
21
  import type { TaskStream, TaskSpec, TaskResult, QuestionAnswer, Checkpoint, CheckpointToken, ResumeOutcome, RunInternals, Runner, EngineNotice } from "@sema-agent/core";
20
22
  import type { FlatServiceDeps, RequestAuth } from "./server.js";
21
23
  import type { TaskRequestBody, DecideBinding } from "./wire-types.js";
@@ -75,8 +77,9 @@ export interface RouteHelpers {
75
77
  /** run 面的属主门(谓词 `runOwnerReadable`;非属主 ⇒ 404 `not_found.run` + 长文,与 run 读口的 unknown 臂同码同串,[ref])。 */
76
78
  runOwnerOk(req: IncomingMessage, res: ServerResponse, owner: string | null): boolean;
77
79
  /** 会话面的属主门(谓词 `sessionOwnerReadable`,S-1452:没有身份边界的部署不钉人,与会话列表同读;非属主 ⇒ 404 `not_found.session` +
78
- * {@link SESSION_NOT_FOUND_MESSAGE},与会话读口的 unknown 臂同码同串 —— G52 [ref] / S-989)。每一个按会话寻址的属主判都走它。 */
79
- sessionOwnerOk(req: IncomingMessage, res: ServerResponse, owner: string | null): boolean;
80
+ * {@link SESSION_NOT_FOUND_MESSAGE},与会话读口的 unknown 臂同码同串 —— G52 [ref] / S-989)。每一个按会话寻址的属主判都走它。
81
+ * `cell` = 调用点经 `security.ts` 的 `sessionOwnerCellOf` 读出的那一格(S-1770:无主的委派子代 placed 行只对 fleet 调用方放行,判据 `ownerlessRowOpen`)。 */
82
+ sessionOwnerOk(req: IncomingMessage, res: ServerResponse, cell: SessionOwnerCell): boolean;
80
83
  sessionOwnerScope(req: IncomingMessage): {
81
84
  fleetWide: boolean;
82
85
  gateOwner: string | null;
@@ -132,6 +135,12 @@ export interface PreparedTaskSubmission {
132
135
  * 装配跑在这条腿的通告口开张之前,所以铸点交不出去 —— 由腿在 `registerEngineNoticeLeg` 那一拍
133
136
  * 经 `pending` 一起投(投递单点仍是那一只注册助手,不新开第二条机制)。缺席 = 本次装配没铸下任何通告。 */
134
137
  engineNotices?: readonly EngineNotice[];
138
+ /**
139
+ * 受理时对**放行侧选择器清单**(根 `allowTools`、子代定义的 `allowTools`)的告知(`rule-entry-list.ts` 的 `allowSelectorWarningsOf`):受理了、没拒,但这几条条目什么也不放
140
+ * (引擎读不出,或名字不在名册)。三条提交腿在各自的受理应答里原样带成 `warnings`(同步腿 200 体 · 流式腿 `meta` 帧 · 异步腿 202 回执);缺席 = 没有话说。
141
+ * 判的是**这一次提交**的体:幂等重放从 run 记录答,不重判、不带。
142
+ */
143
+ warnings?: readonly EntryProblem[];
135
144
  /**
136
145
  * S-470(device lane 首绑写协议,design §4.3.2 两阶段 placement)—— **已校验、未写库**的 placement 意图。
137
146
  *
@@ -191,6 +200,28 @@ export interface CheckpointCtx {
191
200
  */
192
201
  writerVersion?: string;
193
202
  }
203
+ /**
204
+ * `/decide` 第三条车道交给宿主投递腿(wake:`DriveResumeArgs` / fresh:`DurableRunLegArgs`)的**一件**:这一跑在内存里带着的决定,
205
+ * 与开跑之前落行的那一笔。两位只能一起给 —— 型上拆不开:送出一条决定的那一跑,开跑之前一定已经把它落成行(律的属主 =
206
+ * `orchestration/workflow-park-decision.ts` 文件头「先落行、后开跑」)。
207
+ * 🔴 **TRUSTED**:绝不是 `TaskSpec` 字段、也绝不是工具参数(模型不能决定一次审批)。
208
+ */
209
+ export interface WorkflowDecisionDelivery {
210
+ /**
211
+ * 这一跑在内存里带着的那条决定(`RunInternals.workflowParkedResume` 的元素形,直接取 core 的那一位 —— 手抄一份结构等价的字面会让更宽的
212
+ * `token: string` 悄悄通过)。为什么要随腿带:起跑读者(`parked-decide.ts` 的 `heldWorkflowParkDecisions`)在落行**之前**读行(wake 腿的
213
+ * internals 在引擎的 pre-CAS 守卫之前就交进去了),读不到这一笔;读者把两者按 token 合并,同一张卡以它为准(与随后落的是同一条)。
214
+ */
215
+ readonly carried: NonNullable<RunInternals["workflowParkedResume"]>;
216
+ /**
217
+ * 落行:宿主会话的认领在手、这一跑再没有任何会变成拒绝的判定之后、**开跑之前**调一次,`taskId` = 这一跑(行上的 `deliveredTaskId`)。
218
+ * wake 腿挂在引擎的 `afterCheckpointResolve` 座(resolve CAS 赢下之后、续跑那一腿开跑之前);fresh 腿在建行、落点、续跑输入之后、起跑之前。
219
+ * 写在决定店所绑 run 店的认领栅栏里:`taskId` 那一拍已不持有宿主会话的认领(被收割 / 已归别人)⇒ 不写、抛。担保止于栅栏那一拍 —— 写提交之后
220
+ * 这一跑才失去认领(提交确认迟到 / 进程停顿),它照样开跑、带着这一份(引擎 checkpoint 先 resolve 者赢;店头注「不承诺的半句」)。
221
+ * 抛 ⇒ 这一跑不开、认领放掉、响亮 500(wake:引擎把抛原样带出 `resumeStream`,普通异常臂终结合成行;fresh:`releaseClaimedRun` 撤行)。
222
+ */
223
+ readonly commitBeforeLaunch: (taskId: string) => Promise<void>;
224
+ }
194
225
  /** B4①(命名化):`driveResumeIntoRunLog` 的入参形(resume 家族共用)——原为 9 成员内联匿名对象。 */
195
226
  export interface DriveResumeArgs {
196
227
  token: CheckpointToken;
@@ -265,27 +296,8 @@ export interface DriveResumeArgs {
265
296
  mintFreshRun?: {
266
297
  source: string;
267
298
  };
268
- /**
269
- * S-185 车CM —— **workflow 出身 park 的决定**,随本次续跑走 core 的可信 run 通道
270
- * (`RunInternals.workflowParkedResume`)。
271
- *
272
- * 为什么是这里、为什么是这个形:core 给部署方留的**唯一**通道就是它(d.ts 逐字:「A host that decided a
273
- * workflow child's parked checkpoint **launches the run that re-invokes** `Workflow({resumeFromRunId})`
274
- * with the decision here」)。宿主这一跑的模型再调一次 `Workflow({resumeFromRunId})` 时,工具的
275
- * `parkedResume` dep 只挑出 `runId` 命中这次 resume 源的条目,交给 `RunWorkflowOptions.parkedResume`,
276
- * 于是那个 parked ordinal 带着人的决定继续,而不是再 park 一次。
277
- *
278
- * 🔴 **TRUSTED**:它绝不是 `TaskSpec` 字段、也绝不是工具参数(模型不能决定一次审批)。唯一的铸点是
279
- * `/decide` 的第三条车道(判据属主 = `parked-decide.ts` 的 `planWorkflowParkedDecide` 顶注)。
280
- * 缺席 ⇒ 本位对这条腿是完整 no-op,与本批之前逐字相同。
281
- *
282
- * 🔴 **形不手抄:直接是 core 的那一位**(`NonNullable<RunInternals["workflowParkedResume"]>`)。手抄一份
283
- * 结构等价的字面(本位 7.73.0 及以前就是)会让 `token: string` / `inheritedGate: unknown` 这种**更宽**的
284
- * 形悄悄通过,再靠下游一个 `as NonNullable<RunInternals[...]>` 把它洗进 core 的 branded 位 —— 那个转型
285
- * 正是「边界必 schema、禁自铸」要挡的东西(裸 string 当赎回键传进去,编译期一个字都不响)。派生之后
286
- * core 改这一位(本版就把 `WorkflowParkedResume.outcome` 改成了可选)在本仓是**编译事件**,不是靠人去
287
- * 对表的一行注。 */
288
- workflowParkedResume?: NonNullable<RunInternals["workflowParkedResume"]>;
299
+ /** `/decide` 第三条车道交给本腿的那一件决定投递(语义属主 = {@link WorkflowDecisionDelivery} 顶注)。缺席 ⇒ 只摊决定行(其余四条 resume 腿恒缺席)。 */
300
+ workflowDecision?: WorkflowDecisionDelivery;
289
301
  /** [ref]([ref] Inkglow 案 → [ref]① 定谳):**200 受理语义**——调用方声明「我的消费方按 poll/SSE 跟
290
302
  * 终态,别让 HTTP 等模型往返」。在场为 `true` 时本腿在**受理点**(`resumeStream` 解析之后)立刻把
291
303
  * `200 {taskId, status:"resuming", bindingEnforced:true}` 交回调用方,模型腿(流迭代 + 行驱动)继续
@@ -435,11 +447,9 @@ export interface RouteLegs {
435
447
  /** [ref] 件 S-1:透传给 {@link DriveResumeArgs.acceptEarly}(200 受理语义)。HTTP `/wake` 腿传 `true`
436
448
  * —— 本腿走 `mintFreshRun`,受理体里的 `taskId` 因此是**新铸的**那个(壳的 poll 锚)。 */
437
449
  acceptEarly?: boolean,
438
- /** S-185 车CM:透传给 {@link DriveResumeArgs.workflowParkedResume}(语义与 TRUSTED 纪律的属主在那条
439
- * 顶注)。HTTP `/wake` 腿**不设**此位 —— 它是 `/decide` 第三条车道的专用席,而两条腿共用这一条驱动
440
- * 路径正是 `notify-wake.ts` 那条「wake 会烧模型,所以复用 resume 家族的同一条腿、不自建第二条驱动
441
- * 路径」的成文纪律。 */
442
- workflowParkedResume?: DriveResumeArgs["workflowParkedResume"]): Promise<HostLegOutcome>;
450
+ /** 透传给 {@link DriveResumeArgs.workflowDecision}。HTTP `/wake` 腿**不设**此位 —— 它是 `/decide` 第三条车道投递腿的专用席,
451
+ * 而两条腿共用这一条驱动路径正是 `notify-wake.ts` 那条「wake 会烧模型,所以复用 resume 家族的同一条腿」的成文纪律。 */
452
+ workflowDecision?: WorkflowDecisionDelivery): Promise<HostLegOutcome>;
443
453
  /**
444
454
  * assistant plan_review 三态腿的**纯读段**(S-609,7.97.0):选卡 → 属主轻读 → 载入 → 行级 scope → 门类 → 这条决断
445
455
  * 唯一的一次 ctx 读。任何一步拒 ⇒ `{ok:false, answer}`(不改任何状态;端点在消费一次性 nonce **之前**把它答出去);
@@ -722,6 +732,12 @@ export declare function acceptedResumingReceipt(taskId: string, sessionId: strin
722
732
  status: number;
723
733
  body: object;
724
734
  };
735
+ /** 一条腿的结局是不是一张「已受理」回执,是 ⇒ 回执上那一跑的 `taskId`(同一张回执的读法与 {@link acceptedResumingReceipt} 住在一起;
736
+ * `/decide` 的 workflow 车道据它把投递那一跑记在决定行上)。 */
737
+ export declare function acceptedTaskIdOf(out: {
738
+ status: number;
739
+ body: object;
740
+ }): string | undefined;
725
741
  export declare const RUN_NOT_FOUND_MESSAGE = "run not found \u2014 the id belongs to no run in this deployment's run store (a run from another server process, or an in-memory store that did not survive a restart, is not visible here)";
726
742
  /**
727
743
  * 会话资源面 404 的**唯一一句**(与 {@link RUN_NOT_FOUND_MESSAGE} 同一冻结纪律,常量锚在 `test/api-error-text-freeze.test.ts`)。
@@ -27,6 +27,10 @@ export function buildHostLegOutcome(out) {
27
27
  export function acceptedResumingReceipt(taskId, sessionId) {
28
28
  return { status: 200, body: { taskId, sessionId, status: "resuming", bindingEnforced: true } };
29
29
  }
30
+ export function acceptedTaskIdOf(out) {
31
+ const body = out.body;
32
+ return out.status === 200 && "taskId" in body && typeof body.taskId === "string" && body.taskId !== "" ? body.taskId : undefined;
33
+ }
30
34
  export const RUN_NOT_FOUND_MESSAGE = "run not found — the id belongs to no run in this deployment's run store (a run from another server process, or an in-memory store that did not survive a restart, is not visible here)";
31
35
  export const SESSION_NOT_FOUND_MESSAGE = "session not found";
32
36
  export function runNotFoundMessage(id) {
@@ -14,6 +14,7 @@ import { handleMemoryCompliance, MEMORY_COMPLIANCE_ROUTES } from "./routes/memor
14
14
  import { handleMemoryOrigin, MEMORY_ORIGIN_ROUTES } from "./routes/memory-origin.js";
15
15
  import { handleMemoryConsolidation, MEMORY_CONSOLIDATION_ROUTES } from "./routes/memory-consolidation.js";
16
16
  import { handleSharedMemory, SHARED_MEMORY_ROUTES } from "./routes/shared-memory.js";
17
+ import { handlePrincipalInbox, PRINCIPAL_INBOX_ROUTES } from "./routes/principal-inbox.js";
17
18
  import { handleRules, RULES_ROUTES } from "./routes/rules.js";
18
19
  import { handleSessionsList, SESSIONS_LIST_ROUTES } from "./routes/sessions-list.js";
19
20
  import { handleAgentRoster, AGENT_ROSTER_ROUTES } from "./routes/agents-roster.js";
@@ -71,6 +72,7 @@ export const ROUTES = [
71
72
  row({ handler: handleMemoryConsolidation, decls: MEMORY_CONSOLIDATION_ROUTES, position: "post-credential", label: "memory-consolidation" }),
72
73
  row({ handler: handleRules, decls: RULES_ROUTES, position: "post-credential", label: "rules" }),
73
74
  row({ handler: handleSharedMemory, decls: SHARED_MEMORY_ROUTES, position: "post-credential", label: "shared-memory" }),
75
+ row({ handler: handlePrincipalInbox, decls: PRINCIPAL_INBOX_ROUTES, position: "post-credential", label: "principal-inbox" }),
74
76
  row({ handler: handleSessionsList, decls: SESSIONS_LIST_ROUTES, position: "post-credential", label: "sessions-list" }),
75
77
  row({ handler: handleAgentRoster, decls: AGENT_ROSTER_ROUTES, position: "post-credential", label: "agent-roster" }),
76
78
  row({ handler: handleSessions, decls: SESSIONS_ROUTES, position: "post-credential", label: "sessions" }),
@@ -9,6 +9,7 @@ import { isActiveRunConflictBody } from "../active-run-conflict.js";
9
9
  import { sendJson, sendError } from "../send.js";
10
10
  import { admissionRefusalOf, readinessOf, sendBillableRefusal } from "../readiness.js";
11
11
  import { gatedPrincipal, sendPrincipalRefusal } from "../principal-gate.js";
12
+ import { readOwnedRun } from "../owner-access.js";
12
13
  import { assertNever } from "../route-ctx.js";
13
14
  import * as facts from "../../capability-facts.js";
14
15
  import { createDurableRun } from "./runs.js";
@@ -241,7 +242,7 @@ async function handleMessageSend({ req, res, ctx, params, serve, runStore }) {
241
242
  .update(contextId ?? "").update("\x1f")
242
243
  .update(skillId ?? "")
243
244
  .digest("hex");
244
- const submitter = caller.principal ?? undefined;
245
+ const submitter = gatedPrincipal(req, deps.config);
245
246
  const idem = { key: idemKeyOf(fingerprint, caller, "run"), bodyFingerprint: fingerprint };
246
247
  const body = {
247
248
  objective,
@@ -315,11 +316,9 @@ function durableIdempotencyTaskId(scope, messageId) {
315
316
  async function handleTasksGet({ req, ctx, params, runStore }) {
316
317
  const { deps } = ctx;
317
318
  const id = asNonEmptyString(params.id, "params.id", MAX_TASK_ID_CHARS);
318
- const run = await runStore.getRun(id);
319
+ const run = await readOwnedRun(deps.config, runStore, gatedPrincipal(req, deps.config), id, "owner");
319
320
  if (!run)
320
321
  throw new RpcError(A2A_TASK_NOT_FOUND, A2A_TASK_NOT_FOUND_MESSAGE);
321
- if (run.owner !== null && gatedPrincipal(req, deps.config) !== run.owner)
322
- throw new RpcError(A2A_TASK_NOT_FOUND, A2A_TASK_NOT_FOUND_MESSAGE);
323
322
  return taskFromRun(run, isStaleRun(run, deps.config.runStaleSec));
324
323
  }
325
324
  const A2A_METHODS = {
@@ -17,7 +17,7 @@ export async function handleAdminConfigRefresh(req, res, match, ctx) {
17
17
  sendOperatorPrincipalsRequired(res);
18
18
  return;
19
19
  }
20
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
20
+ if (!explicitOperatorOk(principal, deps.config)) {
21
21
  sendError(res, 403, "auth.operator_only", OPERATOR_ONLY_MESSAGE);
22
22
  return;
23
23
  }
@@ -21,7 +21,7 @@ export async function handleAdminDrain(req, res, match, ctx) {
21
21
  sendOperatorPrincipalsRequired(res);
22
22
  return;
23
23
  }
24
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
24
+ if (!explicitOperatorOk(principal, deps.config)) {
25
25
  sendError(res, 403, "auth.operator_only", OPERATOR_ONLY_MESSAGE);
26
26
  return;
27
27
  }
@@ -21,7 +21,7 @@ export async function handleMemoryOptOut(req, res, match, ctx) {
21
21
  sendOperatorPrincipalsRequired(res);
22
22
  return;
23
23
  }
24
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
24
+ if (!explicitOperatorOk(principal, deps.config)) {
25
25
  sendError(res, 403, "auth.operator_only", "memory opt-out grant administration is operator-only: the caller principal is not in OPERATOR_PRINCIPALS");
26
26
  return;
27
27
  }
@@ -52,6 +52,10 @@ export async function handleMemoryOptOut(req, res, match, ctx) {
52
52
  return;
53
53
  case "memory-optout-put-default":
54
54
  case "memory-optout-put-override":
55
+ if (operator === undefined) {
56
+ sendPrincipalRefusal(res, req, deps.config);
57
+ return;
58
+ }
55
59
  break;
56
60
  default:
57
61
  return assertNever(match.decl.id);
@@ -52,7 +52,7 @@ export async function handleAdoption(req, res, match, ctx) {
52
52
  sendOperatorPrincipalsRequired(res);
53
53
  return;
54
54
  }
55
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
55
+ if (!explicitOperatorOk(principal, deps.config)) {
56
56
  sendError(res, 403, "auth.operator_only", "adoption is an operator-only deployment action");
57
57
  return;
58
58
  }
@@ -86,14 +86,7 @@ export async function handleAdoption(req, res, match, ctx) {
86
86
  return;
87
87
  }
88
88
  case "adoption-submit": {
89
- let raw;
90
- try {
91
- raw = await readJson(req);
92
- }
93
- catch {
94
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
95
- return;
96
- }
89
+ const raw = await readJson(req);
97
90
  const parsed = AdoptionRequestSchema.safeParse(raw);
98
91
  if (!parsed.success) {
99
92
  sendError(res, 400, "request.body_shape", "invalid adoption body — expected {fromPrincipal, toPrincipal} as non-empty strings");
@@ -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";
@@ -15,7 +15,8 @@ import { buildRunName } from "../../fleet/fleet-bus.js";
15
15
  import { sleep } from "../sse-log.js";
16
16
  import { bindSseLifecycle } from "../sse-lifecycle.js";
17
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";
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";
@@ -23,8 +24,11 @@ import { sendResumeOutcome } from "../route-ctx.js";
23
24
  import { assertNever } from "../route-ctx.js";
24
25
  import * as facts from "../../capability-facts.js";
25
26
  import { 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
33
  "answer", "boundCallId", "boundInputHash", "checkpointToken", "decidedBy", "decision", "reason", "remember", "updatedInput",
30
34
  ];
@@ -268,18 +272,19 @@ 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;
283
288
  sendJson(res, 200, {
284
289
  pending: (await cs.listPending(scope)).map((r) => projectPendingForWire(r, deps.config)),
285
290
  serverNowMs: Date.now(),
@@ -300,17 +305,13 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
300
305
  sendError(res, 400, "request.path_malformed", "malformed id (invalid percent-encoding)");
301
306
  return;
302
307
  }
303
- const operators = deps.config.operatorPrincipals;
304
- const isExplicitOperator = explicitOperatorOk(principal, operators);
305
- if (!isExplicitOperator) {
308
+ if (!explicitOperatorOk(principal, deps.config)) {
306
309
  const owned = facts.sessionOwnership(deps);
307
310
  if (!owned.available) {
308
311
  sendError(res, 501, "capability.session_store_required", "approval exemptions require a session-store backend");
309
312
  return;
310
313
  }
311
- const ownerOf = owned.sessionStorage.ownerOf.bind(owned.sessionStorage);
312
- const owner = await ownerOf(exSessionId);
313
- if (owner === undefined || (owner !== null && owner !== principal)) {
314
+ if ((await readOwnedSession(deps, owned.sessionStorage, sessionCallerOf(req, deps), exSessionId, "owner")) === undefined) {
314
315
  sendError(res, 404, "not_found.session", "not found");
315
316
  return;
316
317
  }
@@ -329,13 +330,16 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
329
330
  return;
330
331
  }
331
332
  const revoked = await deps.approvalExemptionStore.revoke(exSessionId, exToolName);
332
- sendJson(res, revoked ? 200 : 404, revoked ? { revoked: true } : { error: "not found", errorCode: "not_found.exemption" });
333
+ if (revoked)
334
+ sendJson(res, 200, { revoked: true });
335
+ else
336
+ sendError(res, 404, "not_found.exemption", "not found");
333
337
  return;
334
338
  }
335
339
  }
336
340
  if (match.decl.id === "assistant-inbox") {
337
341
  const ownerParam = new URLSearchParams(match.search).get("owner") || undefined;
338
- const scope = operator && ownerParam ? ownerParam : (principal ?? "__none__");
342
+ const scope = operator && ownerParam ? ownerParam : ownScope;
339
343
  const summaries = await cs.listByScope(scope);
340
344
  const inbox = (await Promise.all(summaries.map(async (s) => {
341
345
  const ctxRead = await readResumeCtx(cs.getCtx(s.sessionId));
@@ -345,6 +349,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
345
349
  const input = s.toolInput != null ? redactedPreview(s.toolInput) : null;
346
350
  return {
347
351
  sessionId: s.sessionId,
352
+ ...durableRowIdentity("assistant-inbox", s.checkpointId, s.token),
348
353
  scope: s.scope,
349
354
  createdAt: s.createdAt,
350
355
  ...(s.gateKind !== undefined ? { gateKind: s.gateKind } : {}),
@@ -364,13 +369,14 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
364
369
  objective,
365
370
  input,
366
371
  };
367
- }))).sort((a, b) => (b.severity ?? 0) - (a.severity ?? 0) || (a.createdAt ?? 0) - (b.createdAt ?? 0));
372
+ })))
373
+ .sort((a, b) => (b.severity ?? 0) - (a.severity ?? 0) || (a.createdAt ?? 0) - (b.createdAt ?? 0));
368
374
  sendJson(res, 200, { inbox });
369
375
  return;
370
376
  }
371
377
  if (match.decl.id === "assistant-tasks") {
372
378
  const ownerParam = new URLSearchParams(match.search).get("owner") || undefined;
373
- const scope = operator && ownerParam ? ownerParam : (principal ?? "__none__");
379
+ const scope = operator && ownerParam ? ownerParam : ownScope;
374
380
  const ledger = facts.durableRuns(deps);
375
381
  if (!ledger.available) {
376
382
  sendJson(res, 200, { tasks: [] });
@@ -379,7 +385,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
379
385
  const runStore = ledger.runStore;
380
386
  const summaries = await cs.listByScope(scope);
381
387
  const byGate = new Map(summaries.map((s) => [s.sessionId, s]));
382
- const runs = await runStore.listRuns({ owner: scope, limit: 100 });
388
+ const runs = await runStore.listRuns({ owner: ownerOfCheckpointScope(scope), limit: 100 });
383
389
  const tasks = runs
384
390
  .filter((r) => r.status === "running" || isParkedRunStatus(r.status))
385
391
  .map((r) => {
@@ -416,17 +422,11 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
416
422
  return;
417
423
  }
418
424
  const taskId = match.params.taskId;
419
- const run = await runStore.getRun(taskId);
425
+ const run = await readOwnedRun(deps.config, runStore, principal, taskId, "owner_or_operator");
420
426
  if (!run) {
421
427
  sendError(res, 404, "not_found.run", "task not found");
422
428
  return;
423
429
  }
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
430
  if (run.status === "running") {
431
431
  const ownedHere = run.instanceId != null && run.instanceId === deps.instanceId;
432
432
  if (ownedHere && !preemptableRuns.has(taskId)) {
@@ -482,8 +482,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
482
482
  sendError(res, 404, "not_found.run", "task not found");
483
483
  return;
484
484
  }
485
- const operators = deps.config.operatorPrincipals;
486
- const explicitOperator = explicitOperatorOk(principal, operators);
485
+ const explicitOperator = explicitOperatorOk(principal, deps.config);
487
486
  if (!explicitOperator && run.owner !== null && run.owner !== principal) {
488
487
  sendError(res, 404, "not_found.run", "task not found");
489
488
  return;
@@ -520,7 +519,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
520
519
  }
521
520
  }
522
521
  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)");
522
+ sendError(res, 400, "request.field_conflict", "decision 'edit' requires a non-empty editedPlan (the operator's revised plan)", fieldConflictFacts("plan_edit", ["decision", "editedPlan"]));
524
523
  return;
525
524
  }
526
525
  const decidedByReading = readDecidedBy(body.decidedBy, deps.config.directDoorActive);
@@ -543,7 +542,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
543
542
  return;
544
543
  }
545
544
  if (decision !== "edit" && body.editedPlan !== undefined) {
546
- sendError(res, 400, "request.field_conflict", `editedPlan is only valid with decision 'edit' (got '${decision}')`);
545
+ sendError(res, 400, "request.field_conflict", `editedPlan is only valid with decision 'edit' (got '${decision}')`, fieldConflictFacts("plan_edit", ["editedPlan", "decision"]));
547
546
  return;
548
547
  }
549
548
  if (body.permissionModeAfter !== undefined && !isPlanApprovePermissionModeAfter(body.permissionModeAfter)) {
@@ -551,7 +550,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
551
550
  return;
552
551
  }
553
552
  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}')`);
553
+ 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
554
  return;
556
555
  }
557
556
  if (body.reason !== undefined && typeof body.reason !== "string") {
@@ -572,7 +571,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
572
571
  return;
573
572
  }
574
573
  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");
574
+ 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
575
  return;
577
576
  }
578
577
  }
@@ -611,8 +610,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
611
610
  deciderPrincipal = proof.principal;
612
611
  singleUse = proof.singleUse === undefined ? undefined : { proof: proof.singleUse, store };
613
612
  }
614
- const operators = deps.config.operatorPrincipals;
615
- const explicitOperator = explicitOperatorOk(deciderPrincipal, operators);
613
+ const explicitOperator = explicitOperatorOk(deciderPrincipal, deps.config);
616
614
  if (!explicitOperator && run.owner !== null && run.owner !== deciderPrincipal) {
617
615
  deps.logger?.info?.("decide_404", { reason: "owner-mismatch", taskId, principalPresent: principal !== undefined });
618
616
  sendError(res, 404, "not_found.run", "task not found");
@@ -626,7 +624,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
626
624
  if (body.permissionModeAfter !== undefined) {
627
625
  const storedCtx = plan.prepared.ctx;
628
626
  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");
627
+ 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
628
  return;
631
629
  }
632
630
  }
@@ -683,7 +681,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
683
681
  return;
684
682
  }
685
683
  if (decision !== "approve") {
686
- sendError(res, 400, "request.field_conflict", "remember requires decision 'approve'");
684
+ sendError(res, 400, "request.field_conflict", "remember requires decision 'approve'", fieldConflictFacts("remember_decision", ["remember", "decision"]));
687
685
  return;
688
686
  }
689
687
  if (deps.config.directDoorActive) {
@@ -770,8 +768,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
770
768
  }
771
769
  deciderPrincipal = proof.principal;
772
770
  }
773
- const operators = deps.config.operatorPrincipals;
774
- const explicitOperator = explicitOperatorOk(deciderPrincipal, operators);
771
+ const explicitOperator = explicitOperatorOk(deciderPrincipal, deps.config);
775
772
  if (!explicitOperator) {
776
773
  const cpScope = await cs
777
774
  .peekPendingScope(sessionId, { gateKinds: APPROVAL_GATE_KINDS })
@@ -895,23 +892,27 @@ export async function streamApprovals(req, res, cs, live, scope, governance, pol
895
892
  });
896
893
  let first = true;
897
894
  while (!closed) {
898
- let pending;
899
- let livePending;
895
+ let snapshot;
900
896
  try {
901
- pending = (await cs.listPending(scope)).map((r) => projectPendingForWire(r, governance));
902
- livePending = live ? live.listLivePending(scope) : [];
897
+ const pending = (await cs.listPending(scope)).map((r) => projectPendingForWire(r, governance));
898
+ snapshot = { pending, livePending: live ? live.listLivePending(scope) : [] };
903
899
  }
904
- catch {
900
+ catch (err) {
901
+ if (err instanceof StoreCorruptError) {
902
+ if (!res.writableEnded)
903
+ 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`);
904
+ break;
905
+ }
905
906
  if (!res.writableEnded)
906
- res.write(`event: heartbeat\ndata: ${JSON.stringify({ type: "heartbeat" })}\n\n`);
907
- await sleep(pollMs);
908
- continue;
907
+ 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
908
  }
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;
909
+ if (snapshot !== undefined) {
910
+ durableLane.tick(snapshot.pending);
911
+ liveLane.tick(snapshot.livePending);
912
+ if (first) {
913
+ res.write(`event: synced\ndata: ${JSON.stringify({ type: "synced", count: snapshot.pending.length })}\n\n`);
914
+ first = false;
915
+ }
915
916
  }
916
917
  if (Date.now() - start > SSE_MAX_STREAM_MS) {
917
918
  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) {