@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
@@ -23,6 +23,8 @@ export interface LeaderCtx {
23
23
  toolResultStore: ToolResultStoreFull | undefined;
24
24
  sessionStore: ReturnType<typeof createSessionStore>;
25
25
  checkpointStore: CheckpointStoreFull | undefined;
26
+ /** S-1907:停驻行凭据的封签器(与 HTTP 面 `ServiceDeps.checkpointCtxSealing` 同一只;起服第 6 段已对「店在、它不在」拒启)。必填键,值可为 undefined。 */
27
+ checkpointCtxSealing: import("../http/checkpoint-ctx.js").CheckpointCtxSealing | undefined;
26
28
  /** [ref] 件B/C/D([ref],codex R2-F1):部署治理三座席 —— leader 车道的每一只 Runner 都要带上它,
27
29
  * 否则开了 leader 端点的部署就有一条在部署治理**之外**的执行面(合规否决/锁都够不着)。 */
28
30
  governanceSeams: import("./governance-seams.js").GovernanceSeams;
@@ -1,4 +1,5 @@
1
1
  import { createLeaderEndpoint } from "../leader/endpoint.js";
2
+ import { createLeaderRunVisibility } from "../http/owner-access.js";
2
3
  import { createLeaderRunner } from "../leader/wire.js";
3
4
  import { buildDeploymentPostureSeats } from "./runner-deps.js";
4
5
  import { hasApprovalListIntent } from "../approval.js";
@@ -21,7 +22,7 @@ export function assertLeaderDurableStore(leaderEnabled, hasLeaderRunStore) {
21
22
  "(#193 车4 件2 capability gate; the DB_BACKEND literal check in config.ts is the intent half of the same rule)");
22
23
  }
23
24
  export function createLeaderFace(ctx) {
24
- const { config, logger, brain, pricing, executionEnvFactory, toolResultStore, sessionStore, checkpointStore, governanceSeams } = ctx;
25
+ const { config, logger, brain, pricing, executionEnvFactory, toolResultStore, sessionStore, checkpointStore, checkpointCtxSealing, governanceSeams } = ctx;
25
26
  const leaderMinio = process.env.MINIO_ENDPOINT && process.env.MINIO_ACCESS_KEY && process.env.MINIO_SECRET_KEY
26
27
  ? {
27
28
  s3: {
@@ -73,6 +74,7 @@ export function createLeaderFace(ctx) {
73
74
  durable: () => hasApprovalListIntent(config)
74
75
  ? {
75
76
  checkpointStore,
77
+ ctxSealer: checkpointCtxSealing,
76
78
  requireApproval: config.approvalRequire,
77
79
  deny: config.approvalDeny,
78
80
  autoBudget: config.approvalAutoBudget,
@@ -86,6 +88,7 @@ export function createLeaderFace(ctx) {
86
88
  logger,
87
89
  requiredFields: ["objective", "durableRemote", "testCmd", "seedCmd", "baseSha"],
88
90
  ...(leaderRunStore ? { store: leaderRunStore } : {}),
91
+ ownerVisible: createLeaderRunVisibility(config),
89
92
  })
90
93
  : undefined;
91
94
  if (leaderEndpoint)
@@ -1,5 +1,5 @@
1
1
  import { resolve } from "node:path";
2
- import { executionLaneCaps, executionLaneOf } from "../execution-lane-caps.js";
2
+ import { executionLaneCaps, executionLaneOf, laneWiresExecutionEnv } from "../execution-lane-caps.js";
3
3
  export function effectiveMemoryPersistenceCapable(config) {
4
4
  if (config.memoryPersistenceCapable !== undefined)
5
5
  return config.memoryPersistenceCapable;
@@ -11,7 +11,7 @@ export function buildMemoryBoundaryLaneFacts(config, processCwd) {
11
11
  return {
12
12
  lane,
13
13
  hostSemanticsLane: caps.hostFilePlane === "supported",
14
- coreRemoteExecutionEnv: caps.coreRemoteExecutionEnv === "supported",
14
+ coreRemoteExecutionEnv: laneWiresExecutionEnv(lane),
15
15
  containmentRoots: lane === "in-process" ? [processCwd] : [],
16
16
  };
17
17
  }
@@ -298,9 +298,9 @@ export declare function judgeConsolidationValve(input: ConsolidationValveInput):
298
298
  *
299
299
  * consolidation 要后端自带引擎控制面归属 ⇒ 今天只有 file 记忆后端满足 ⇒ 本仓只在**单用户**形
300
300
  * (`REQUIRE_PRINCIPAL !== true`)上装配记忆引擎 —— 而那种部署的 `OPERATOR_PRINCIPALS` 通常是**空的**。
301
- * 空名单下 `explicitOperatorOk` 对任何身份恒假(那是它与 `isOperator` 刻意分家的地方:空名单绝不等于
302
- * 「人人都是 operator」),于是:阀门开着、启动成功、两口挂着、**每一次调用 403**,能力位诚实地报
303
- * `false` —— 唯独运维不知道为什么,而他刚刚显式拧了一根写着 "on" 的旋钮。
301
+ * 没有运维名册(名单空且没有单用户声明 `OPERATOR_SINGLE_USER`)时 `explicitOperatorOk` 对任何身份恒假(「谁是 operator」的唯一读法:空名单绝不等于
302
+ * 「人人都是 operator」),于是:阀门开着、启动成功、两口挂着、**每一次调用 501 `capability.operator_principals_required`**(运维面同一只拒发口;403 只留给名单非空而你不在名单上),
303
+ * 能力位诚实地报 `false` —— 唯独运维不知道为什么,而他刚刚显式拧了一根写着 "on" 的旋钮。
304
304
  *
305
305
  * ## 为什么是 warn 而不是拒启(与 D1 的三条拒启臂**刻意不同档**)
306
306
  *
@@ -322,7 +322,8 @@ export declare function judgeConsolidationValve(input: ConsolidationValveInput):
322
322
  export declare function buildConsolidationValveAudit(input: {
323
323
  /** 阀门判决({@link resolveConsolidationValve} 的 `enabled` + `source`)。 */
324
324
  valve: Pick<ConsolidationValve, "enabled" | "source">;
325
- operatorPrincipals: readonly string[];
325
+ /** 这台部署有没有运维名册(`operatorRosterPresent`:名单非空 ∨ 单用户声明)—— 判据不在本函数里另写一份。 */
326
+ operatorRosterPresent: boolean;
326
327
  /** 这台部署配了任何一把 service 凭证吗(`config.authToken` 或 `config.authTokens` 非空)。 */
327
328
  hasServiceAuth: boolean;
328
329
  /** 本地开发的显式逃生口(`ALLOW_UNAUTHED_WRITES=true`)。 */
@@ -1,5 +1,6 @@
1
1
  import { redactSecrets } from "../trace/redact.js";
2
2
  import { recordFailOpen } from "../observability/fail-open.js";
3
+ import { buildOperatorRosterWayOut } from "../http/principal-gate.js";
3
4
  import { memoryMountRootOf } from "../memory-scope.js";
4
5
  import { executionLaneHomeDir } from "../execution-lane-caps.js";
5
6
  import { DEFAULT_MODEL_REF, resolveMainModel } from "../model-select.js";
@@ -266,15 +267,15 @@ export function buildConsolidationValveAudit(input) {
266
267
  if (!input.valve.enabled || input.valve.source !== "explicit")
267
268
  return { warnings: [] };
268
269
  const warnings = [];
269
- if (input.operatorPrincipals.length === 0) {
270
+ if (!input.operatorRosterPresent) {
270
271
  warnings.push({
271
272
  tag: "memory_consolidation_valve_unreachable",
272
273
  detail: "MEMORY_CONSOLIDATION_DRIVER=on armed the consolidation valve and both admin endpoints are mounted, but " +
273
- "OPERATOR_PRINCIPALS is EMPTY — an empty operator list means NO ONE is an operator (it deliberately does " +
274
- "not mean 'everyone'), so POST /v1/admin/memory/consolidation/run and GET /v1/admin/memory/consolidation " +
275
- "answer 403 auth.operator_only to every caller and capabilities.memoryConsolidationDriver reports false. " +
276
- "Set OPERATOR_PRINCIPALS to the principal(s) allowed to drive consolidation, and send that principal in " +
277
- "the configured principal header. (Not a startup refusal: OPERATOR_PRINCIPALS is shared by every operator " +
274
+ "this worker has no operator: OPERATOR_PRINCIPALS is EMPTY and OPERATOR_SINGLE_USER is not set — an empty operator list means NO ONE " +
275
+ "is an operator (it deliberately does not mean 'everyone'), so POST /v1/admin/memory/consolidation/run and GET /v1/admin/memory/consolidation " +
276
+ "answer 501 capability.operator_principals_required to every caller and capabilities.memoryConsolidationDriver reports false. " +
277
+ `To fix: ${buildOperatorRosterWayOut()}. With OPERATOR_PRINCIPALS, callers must send a listed principal in the configured principal header; a single-user declaration needs no principal. ` +
278
+ "(Not a startup refusal: the operator roster is shared by every operator " +
278
279
  "endpoint on this worker, so one valve must not decide whether the whole worker starts.)",
279
280
  });
280
281
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * [ref] §10.2 —— 跨主体投递门的**装配点**(门本体与规则在 `src/org-delivery-gate.ts`)。
3
+ *
4
+ * 挂载规则(一条):**部署声明了 principal 收件箱的消费方 ⟺ 门在座**。声明 = `RunnerDeps.principalInboxConsumer`
5
+ * (由 `PRINCIPAL_INBOX_ASSISTANT` 铸,`boot/runner-deps.ts`);门要的四件 —— 消费方、耐久 mailbox、org 成员目录、配额店 ——
6
+ * 是这条声明的**前提**,不是可选项:声明在而任一件缺 ⇒ **拒启**,拒句点名缺哪件。不存在「声明了但门没挂」的静默半态:
7
+ * 那一形下收件箱有消费方却没有任何合法的写入方,运维以为跨主体投递开着,wire 上它恒 501。
8
+ *
9
+ * 消费方取自**同一个** `RunnerDeps` 对象(`principalInboxConsumerOf(runnerDeps)`),不从 config 再读一遍(core 契约原句:
10
+ * 「over the same RunnerDeps the deployment runs its legs with」)。
11
+ */
12
+ import { type MailboxStore, type OrgDeliveryGate, type RunnerDeps } from "@sema-agent/core";
13
+ import type { OrgMemoryDirectory } from "../org-memory-admission.js";
14
+ import type { StoreBackend } from "../plugins/store-backend.js";
15
+ import type { Logger } from "../observability/logger.js";
16
+ export interface OrgDeliveryMountInput {
17
+ /** 主 Runner 的那一份 `RunnerDeps`(消费方声明从它读)。 */
18
+ readonly runnerDeps: Pick<RunnerDeps, "principalInboxConsumer">;
19
+ /** 记忆准入 / memory-policy / 共享记忆读面共用的那一个目录实例(`boot/org-memory.ts`)。 */
20
+ readonly directory: OrgMemoryDirectory | undefined;
21
+ /** 与引擎 `RunnerDeps.mailboxStore` 同一只店。 */
22
+ readonly mailboxStore: MailboxStore | undefined;
23
+ readonly backend: Pick<StoreBackend, "orgDeliveryQuota"> | undefined;
24
+ readonly logger: Pick<Logger, "info">;
25
+ }
26
+ /** 门在座 ⇒ 门;部署没声明消费方 ⇒ `undefined`;声明了而前提缺 ⇒ 抛(拒启)。 */
27
+ export declare function mountOrgDeliveryGate(input: OrgDeliveryMountInput): OrgDeliveryGate | undefined;
28
+ //# sourceMappingURL=org-delivery.d.ts.map
@@ -0,0 +1,20 @@
1
+ import { principalInboxConsumerOf } from "@sema-agent/core";
2
+ import { createOrgDeliveryGate } from "../org-delivery-gate.js";
3
+ export function mountOrgDeliveryGate(input) {
4
+ const consumer = principalInboxConsumerOf(input.runnerDeps);
5
+ if (consumer.kind === "none")
6
+ return undefined;
7
+ const { mailboxStore, directory, backend } = input;
8
+ if (mailboxStore === undefined || directory === undefined || backend === undefined) {
9
+ const missing = [
10
+ ...(mailboxStore === undefined ? ["a durable mailbox store (DB_BACKEND=mysql|pg|local)"] : []),
11
+ ...(directory === undefined ? ["an organization membership directory (a web-admin center, or MEMORY_ORG_DIRECTORY_JSON)"] : []),
12
+ ...(backend === undefined ? ["a store backend for the delivery quota (DB_BACKEND=mysql|pg|local)"] : []),
13
+ ];
14
+ throw new Error(`PRINCIPAL_INBOX_ASSISTANT declares a principal-inbox consumer, so this deployment must mount the organization delivery gate — but it lacks ${missing.join("; ")}. ` +
15
+ `Refusing to boot rather than run with a declared inbox that nothing may legitimately write to; provide the missing pieces or unset PRINCIPAL_INBOX_ASSISTANT.`);
16
+ }
17
+ input.logger.info("org_delivery_gate_mounted", { consumer: consumer.kind });
18
+ return createOrgDeliveryGate({ directory, mailbox: mailboxStore, quota: backend.orgDeliveryQuota(), consumer });
19
+ }
20
+ //# sourceMappingURL=org-delivery.js.map
@@ -1,9 +1,9 @@
1
- import { compileReadDeny, readDenyPatternRun } from "@sema-agent/core";
1
+ import { compileReadDeny, readDenyRowAnchor } from "@sema-agent/core";
2
2
  import { echoCallerText } from "../caller-text-echo.js";
3
3
  export const READ_DENY_AUDIT_MAX_NAMED_ROWS = 20;
4
4
  const NAMED_ROW_ECHO_CHARS = 200;
5
5
  function isAnchoredCanonicalRow(canonical) {
6
- return readDenyPatternRun(canonical).homeAnchored || canonical.startsWith("/");
6
+ return readDenyRowAnchor(canonical) !== "none";
7
7
  }
8
8
  export function auditReadDenyAnchoring(ctx) {
9
9
  if (ctx.rows === undefined || ctx.rows.length === 0)
@@ -25,6 +25,7 @@ import type { FileHistoryErasureFace } from "../file-history-capture.js";
25
25
  import type { ApprovalNonceStore, CheckpointStoreFull, CostQuotaStore, ImageBake, RateLimiterStore, ServiceWorkflowJournalStore, StoreBackend, ToolResultStoreFull } from "../plugins/store-backend.js";
26
26
  import type { ToolApprovalCoordinator } from "../tool-approval.js";
27
27
  import type { ParkCommitWatch } from "../plugins/park-commit-watch.js";
28
+ import { type AuditRotationPort } from "../approval-ask-retention.js";
28
29
  /** [ref] / [ref]§五(sema-comms `audits/failopen-governance-176.md` §7 "Z 类 1 条"):default consecutive-failure
29
30
  * count before a reaper leg's swallowed error gets a `warn` line. The ~15 `.catch(() => undefined)` sites
30
31
  * below are correct in DIRECTION (a hiccuping periodic sweep must never crash the whole tick loop — one bad
@@ -108,6 +109,8 @@ export interface ReapersCtx {
108
109
  * 受理的最后一刻),所以存量是「到达率 × TTL」而不是历史总量,清扫无需分批。无 backend 的 env-only
109
110
  * 部署 ⇒ undefined ⇒ 本腿零调用(那种部署也没有 durable 审批门)。 */
110
111
  approvalNonceStore: ApprovalNonceStore | undefined;
112
+ /** local 车道的审批审计账(装配三合取见 `boot/coordinators.ts`;SQL 车道 / 审批关着 ⇒ undefined)—— 本 tick 只用它的**留存轮转**一手。 */
113
+ approvalAskAudit: AuditRotationPort | undefined;
111
114
  /** 晚绑(server 造出来才有)——见文件头「位置即契约」①。 */
112
115
  getRunDenySweep: () => ((now: number) => Promise<void>) | undefined;
113
116
  }
@@ -4,6 +4,7 @@ import { CostQuota } from "../observability/cost-quota.js";
4
4
  import { isAdoptionQuiescing, trackMaintenanceLeg } from "../adoption/quiesce.js";
5
5
  import { createApprovalReconciler } from "../approval-reconciler.js";
6
6
  import { createE2bOrphanSandboxProvider, reclaimOrphanE2bSandboxes, E2B_ORPHAN_GRACE_MS } from "../plugins/e2b-orphan-reclaim.js";
7
+ import { APPROVAL_ASK_RETENTION_PASS_MS, runApprovalAskRetentionPass } from "../approval-ask-retention.js";
7
8
  export const REAPER_FAILURE_WARN_THRESHOLD = 5;
8
9
  export function createThrottledReaperCatch(name, logger, threshold = REAPER_FAILURE_WARN_THRESHOLD) {
9
10
  let streak = 0;
@@ -56,7 +57,7 @@ export function createPlacementAwareReapSessions(deps) {
56
57
  };
57
58
  }
58
59
  export function startReapers(ctx) {
59
- const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, parkCommits, rateLimiter, costQuota, toolResultStore, fileHistoryErasure, taskAttachmentStore, imageBakes, worktreeReap, workflowNotifyGate, workflowRecoverOpts, workflowJournalStore, sqlWorkflowRunStore, workflowNotifyJournal, rosterStore, backgroundAgentStore, mailboxStore, toolApproval, permissionRuleStores, approvalNonceStore, getRunDenySweep, userInputLedger, } = ctx;
60
+ const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, parkCommits, rateLimiter, costQuota, toolResultStore, fileHistoryErasure, taskAttachmentStore, imageBakes, worktreeReap, workflowNotifyGate, workflowRecoverOpts, workflowJournalStore, sqlWorkflowRunStore, workflowNotifyJournal, rosterStore, backgroundAgentStore, mailboxStore, toolApproval, permissionRuleStores, approvalNonceStore, getRunDenySweep, userInputLedger, approvalAskAudit, } = ctx;
60
61
  const leg = (p) => {
61
62
  if (p !== undefined)
62
63
  trackMaintenanceLeg(p);
@@ -101,6 +102,17 @@ export function startReapers(ctx) {
101
102
  const leaderRunStaleGuard = createThrottledReaperCatch("leader_run_reap_stale", logger);
102
103
  const leaderRunStore = config.leaderEnabled ? backend?.leaderRun?.() : undefined;
103
104
  const scratchpadSweepStaleGuard = createThrottledReaperCatch("scratchpad_sweep_stale", logger);
105
+ const approvalAskRetentionMs = config.approvalAskRetentionMs;
106
+ const approvalAskRetentionGuard = createThrottledReaperCatch("approval_ask_retention", logger);
107
+ let approvalAskRetentionLastRunMs = Number.NEGATIVE_INFINITY;
108
+ let approvalAskRetentionInFlight = false;
109
+ logger.info("approval_ask_retention", {
110
+ windowMs: approvalAskRetentionMs,
111
+ ledgers: { asks: backend !== undefined, audit: approvalAskAudit !== undefined },
112
+ note: approvalAskRetentionMs > 0
113
+ ? "settled approval asks quiet for longer than windowMs are deleted whole from the approval ledgers on the maintenance tick (at most once an hour); unsettled asks, and every ask hanging off something that can still move (a running / parked run or delegated child, by run id or session), are never aged out. APPROVAL_ASK_RETENTION_MS=0 keeps everything."
114
+ : "APPROVAL_ASK_RETENTION_MS=0 — the approval ledgers are kept forever (nothing is aged out).",
115
+ });
104
116
  const approvalReconcileGuard = createThrottledReaperCatch("approval_reconcile", logger);
105
117
  const approvalSuspendedPollGuard = createThrottledReaperCatch("approval_suspended_poll", logger);
106
118
  let approvalSuspendedPollInFlight = false;
@@ -325,6 +337,14 @@ export function startReapers(ctx) {
325
337
  if (permissionRuleStores?.reapExpired === undefined)
326
338
  permissionRuleReapInFlight = false;
327
339
  }
340
+ if (approvalAskRetentionMs > 0 && runStore !== undefined && !approvalAskRetentionInFlight && Date.now() - approvalAskRetentionLastRunMs >= APPROVAL_ASK_RETENTION_PASS_MS && (backend !== undefined || approvalAskAudit !== undefined)) {
341
+ approvalAskRetentionInFlight = true;
342
+ approvalAskRetentionLastRunMs = Date.now();
343
+ leg(Promise.resolve()
344
+ .then(() => runApprovalAskRetentionPass({ askStore: backend?.approvalAsk(), audit: approvalAskAudit, runs: runStore, backgroundAgents: backgroundAgentStore, checkpoints: backend?.checkpointReadView(), cutoffMs: Date.now() - approvalAskRetentionMs, logger, metrics }))
345
+ .then(() => approvalAskRetentionGuard.onSuccess(), approvalAskRetentionGuard.onError)
346
+ .finally(() => (approvalAskRetentionInFlight = false)));
347
+ }
328
348
  if (config.scratchpadSweepTtlMs > 0) {
329
349
  leg(sweepStaleScratchpads(config.localDataRoot ?? localRoot, { olderThanMs: config.scratchpadSweepTtlMs })
330
350
  .then((removed) => {
@@ -16,6 +16,7 @@ import type { StoreBackend } from "../plugins/store-backend.js";
16
16
  import { type TaskAttachmentStore } from "../plugins/task-attachment-store.js";
17
17
  import { type createPrincipalEntitlementsClient } from "../runtime-caps-resolver.js";
18
18
  import { type OwnerAwareSessionStore } from "../security.js";
19
+ import type { MemorySyncRunner } from "../memory-sync-client.js";
19
20
  import type { RunnerDepsOnAsk } from "./runner-deps.js";
20
21
  type PrincipalCaps = ReturnType<typeof createPrincipalEntitlementsClient>;
21
22
  /** `resolveSpec` 原先从 `main()` 闭包里拿到的全部 boot 局部量。 */
@@ -56,6 +57,8 @@ export interface ResolveSpecCtx {
56
57
  backend: MemoryBackend;
57
58
  root: string;
58
59
  } | undefined;
60
+ /** S-640:记忆同步腿(开 `MEMORY_SYNC_*` 且记忆引擎接线时在场)—— 项目层准备一步把本任务的项目层交给它跟踪(`memory-project-layer.ts`)。 */
61
+ memorySyncRunner: MemorySyncRunner | undefined;
59
62
  durableEnabled: boolean;
60
63
  /** [ref] ([ref] 案二):活体 AskUserQuestion 面(QuestionCoordinator 的判决探针切面)。在场(=
61
64
  * ASK_QUESTION_ENABLED)时 durable question 门按活流上下文分腿、spec 不再 stamp QUESTION_AWAITS_RESUME
@@ -1,11 +1,11 @@
1
1
  import { realpathSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import { NodeExecutionEnv, QUESTION_AWAITS_RESUME, WRITE_EXEMPT_DIR_COVERS_ROOT_CODE, deriveAskEffective, expandTiers, modePolicyOf, resolveAskSeamForm } from "@sema-agent/core";
3
+ import { NodeExecutionEnv, QUESTION_AWAITS_RESUME, deriveAskEffective, expandTiers, modePolicyOf, resolveAskSeamForm } from "@sema-agent/core";
4
4
  import { cappedCeiling } from "../budget.js";
5
5
  import { recordFailOpen } from "../observability/fail-open.js";
6
6
  import { SessionEnvironmentSelection, selectEnvironmentTool } from "../capabilities/select-environment-tool.js";
7
7
  import { sendUserFileTool } from "../capabilities/send-user-file-tool.js";
8
- import { buildPromptSeats, createScenarioGate, mergeUserSkills, selectScenario } from "../capabilities/scenarios.js";
8
+ import { buildExcludeToolsSeat, buildPromptSeats, createScenarioGate, mergeUserSkills, selectScenario } from "../capabilities/scenarios.js";
9
9
  import { stampHandsLane, toolPolicyForHands } from "../capabilities/hands-lane.js";
10
10
  import { applyLongtailDefer } from "../capabilities/tool-defer.js";
11
11
  import { assertGuardPatternsUsable, buildApprovalGrantNotice, buildOnlySensitiveBaselineWarning, createApprovalBaselinePolicy, createDeploymentGovernanceInputs } from "../deployment-governance.js";
@@ -17,7 +17,7 @@ import { HOST_POSTURE_REFUSED_CODE, taskInheritEnvRefusal, taskWriteFaceRefusal
17
17
  import { headerStr } from "../http/principal-gate.js";
18
18
  import { explicitOperatorOk } from "../http/server.js";
19
19
  import { isAtMentionable, matchCatalogModel, modelSupportsImages, refusedCatalogEntry, resolveTaskModel, selectableCatalog, terminalCatalogName } from "../model-select.js";
20
- import { modelUnavailableMessage } from "../model-entry-refusal.js";
20
+ import { echoModelRef, modelUnavailableMessage } from "../model-entry-refusal.js";
21
21
  import { PerTaskImageRegistry, resolveSandboxImageRef } from "../per-task-image.js";
22
22
  import { isRemoteScratchpadLane, remoteScratchpadDirFor } from "../plugins/remote-scratchpad.js";
23
23
  import { bindAttachmentsForTask } from "../plugins/task-attachment-store.js";
@@ -27,7 +27,9 @@ import { tightenGoverned } from "../governance-overrides.js";
27
27
  import { gateExecutionLane } from "../runtime-caps-resolver.js";
28
28
  import { applyRuntimeGovernance } from "../runtime-governance.js";
29
29
  import { HttpError, createCodedHttpError, encodeCheckpointScope } from "../security.js";
30
- import { memoryProjectKeyFor, memorySpecForRequest } from "../memory-scope.js";
30
+ import { sessionFaceReadOf } from "../session-incarnation.js";
31
+ import { memorySpecForRequest } from "../memory-scope.js";
32
+ import { createMemoryProjectLayers } from "../memory-project-layer.js";
31
33
  import { inheritEnvFieldIssue, singleMemberOffFieldIssue } from "../request-value-closure.js";
32
34
  import { a2aForScenario, mcpForScenario } from "../web-admin-client/facade.js";
33
35
  import { normalizeAttachments, normalizeResilience, normalizeResumeAtMode, normalizeSuggestNextPrompts, promptProfileFromBody, resolveTaskLimits, retainBackgroundProcessesFromBody, taskAgentsSpecFragment, toolMaterializeStrategyFromBody, allowToolsSpecFragment, toolNameListFromBody } from "../spec-fields.js";
@@ -37,17 +39,21 @@ import { assertRequestA2aUnlocked, resolveRequestA2a } from "../task-a2a.js";
37
39
  import { assertRequestMcpEntries, assertRequestMcpUnlocked, resolveRequestMcp } from "../task-mcp.js";
38
40
  import { storedToolAxesRereadM19 } from "../stored-request-tool-axes-m19.js";
39
41
  import { storedHooksRereadM20 } from "../stored-request-hooks-m20.js";
40
- import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, REQUEST_SETTINGS_REFUSAL_PREFIX, acceptAppendSystemPrompt, applyTaskSettings, effectivePermissionMode, effectiveThinking, parseTaskSettings, taskHooksHonored, settingsPermissionBucketIssue, withPermissionMode } from "../task-settings.js";
42
+ import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, REQUEST_SETTINGS_REFUSAL_PREFIX, SETTINGS_RULE_REFUSAL_CODE, SettingsRuleRefusalError, acceptAppendSystemPrompt, applyTaskSettings, createWorkflowAskPolicy, effectivePermissionMode, effectiveThinking, parseTaskSettings, taskHooksHonored, settingsPermissionBucketIssue } from "../task-settings.js";
43
+ import { tightenOnlySeatIssue } from "../tighten-only-seats.js";
44
+ import { entryProblemsFacts } from "../entry-problems.js";
41
45
  import { inertToolListEntryOf } from "../rule-entry-list.js";
42
46
  import { TENANCY_WALL_CLOCK_BASE_SEC, enableForkFromBody, normalizeRetainSubagentSessions, selfOrchestrationFromBody } from "../task-workflow.js";
43
47
  import { redactSecrets } from "../trace/redact.js";
44
48
  import { DeferredSandboxPathEnv, isSandboxPathAdjudicationLane, sandboxPathEnvSlots } from "./deferred-sandbox-path-env.js";
45
- import { executionLaneCaps, executionLaneHomeDir, executionLaneOf } from "../execution-lane-caps.js";
49
+ import { executionLaneHomeDir, executionLaneOf, laneWiresExecutionEnv } from "../execution-lane-caps.js";
46
50
  import { effectiveMemoryPersistenceCapable } from "./memory-boundary.js";
47
51
  import { withUnattendedLeg } from "../unattended-permission-mode.js";
52
+ import { fieldConflictFacts } from "../field-conflict.js";
48
53
  export function createResolveSpec(ctx) {
49
- const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, fenceSessionOwner, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore, checkpointStore, imageIndex, perTaskImage, sessionEnvSelection, liveQuestionFace, approverSeat, lockedKeys, } = ctx;
54
+ const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, fenceSessionOwner, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, memorySyncRunner, durableEnabled, approvalExemptionStore, checkpointStore, imageIndex, perTaskImage, sessionEnvSelection, liveQuestionFace, approverSeat, lockedKeys, } = ctx;
50
55
  const scenarioGate = createScenarioGate({ config, scenarios, principalCaps, logger }, "enforce");
56
+ const readSessionFace = sessionFaceReadOf(ownerAware);
51
57
  assertGuardPatternsUsable(config);
52
58
  const onlySensitiveBaseline = buildOnlySensitiveBaselineWarning(config, {
53
59
  approvalSeat: durableEnabled ? "durable" : "absent",
@@ -59,6 +65,7 @@ export function createResolveSpec(ctx) {
59
65
  const sessionCwd = auth?.sessionId ? effectiveHostWorkspace(perSessionCwd.get(auth.sessionId), {}) : undefined;
60
66
  return sessionCwd ?? (config.remoteExec === undefined ? process.cwd() : undefined);
61
67
  };
68
+ const memoryProjectLayers = createMemoryProjectLayers({ backend: memoryEngine?.backend, syncRunner: memorySyncRunner, log: logger });
62
69
  if (onlySensitiveBaseline)
63
70
  logger.warn(onlySensitiveBaseline.event, onlySensitiveBaseline.fields);
64
71
  const approvalGrantNotice = buildApprovalGrantNotice(config);
@@ -81,7 +88,7 @@ export function createResolveSpec(ctx) {
81
88
  cwdHonored: cwdHonored(config),
82
89
  });
83
90
  if (conflict) {
84
- throw new HttpError(400, `cwd "${conflict.cwd.asSpelled}" is inside this session's scratchpad "${conflict.scratchpadDir.asSpelled}" — the scratchpad is the fs-write gate's EXEMPT directory, so a task rooted there would auto-approve every write under its own root and the engine refuses to build the gate at all (config.write_exempt_dir_covers_root). Point cwd at the project directory instead (or send no cwd and let the session keep the one it has): this session registers the cwd you send, so a task that happens not to mount the write gate would still leave every LATER task on this session rooted in the exemption. A workflow that really is meant to write without prompts says so with a knob that means it (a permission mode, an open write face) and still keeps its root outside the scratchpad — those knobs do not lift this refusal, because the conflict is between two fields of this request, not a permission level.`, { code: "request.field_conflict", extra: { cwd: conflict.cwd, scratchpadDir: conflict.scratchpadDir } });
91
+ throw new HttpError(400, `cwd "${conflict.cwd.asSpelled}" is inside this session's scratchpad "${conflict.scratchpadDir.asSpelled}" — the scratchpad is the fs-write gate's EXEMPT directory, so a task rooted there would auto-approve every write under its own root and the engine refuses to build the gate at all (config.write_exempt_dir_covers_root). Point cwd at the project directory instead (or send no cwd and let the session keep the one it has): this session registers the cwd you send, so a task that happens not to mount the write gate would still leave every LATER task on this session rooted in the exemption. A workflow that really is meant to write without prompts says so with a knob that means it (a permission mode, an open write face) and still keeps its root outside the scratchpad — those knobs do not lift this refusal, because the conflict is between two fields of this request, not a permission level.`, { code: "request.field_conflict", extra: { ...fieldConflictFacts("scratchpad_root", body.scratchpadDir === conflict.scratchpadDir.asSpelled ? ["cwd", "scratchpadDir"] : ["cwd"]), cwd: conflict.cwd, scratchpadDir: conflict.scratchpadDir } });
85
92
  }
86
93
  }
87
94
  const offFieldIssue = singleMemberOffFieldIssue(body);
@@ -109,6 +116,11 @@ export function createResolveSpec(ctx) {
109
116
  if (bucketIssue)
110
117
  throw new HttpError(400, bucketIssue.message, { code: "request.field_invalid", extra: bucketIssue.fields });
111
118
  }
119
+ {
120
+ const seatIssue = tightenOnlySeatIssue(body.settings);
121
+ if (seatIssue)
122
+ throw new HttpError(400, seatIssue.message, { code: "request.field_invalid", extra: seatIssue.fields });
123
+ }
112
124
  {
113
125
  const replay = opts?.leg === "resume";
114
126
  const inertList = inertToolListEntryOf(body, replay ? ["deny"] : undefined);
@@ -136,8 +148,9 @@ export function createResolveSpec(ctx) {
136
148
  }
137
149
  const lane = bindSettingsCwdEnvAndModel(body, auth, gated, opts);
138
150
  const anchors = await resolveHistoryAnchors(body, auth);
139
- const spec = assembleSpecLiteral(body, auth, req, opts, { ...gated, ...lane, ...anchors }, effMode);
140
- const folded = await foldGovernanceAndSettings(body, auth, spec, gated, effMode);
151
+ const projectKey = memoryEngine ? await memoryProjectLayers.prepare(config, auth?.memoryScope, realTaskRootOf(auth)) : undefined;
152
+ const spec = assembleSpecLiteral(body, auth, req, opts, { ...gated, ...lane, ...anchors, projectKey }, effMode);
153
+ const folded = await foldGovernanceAndSettings(body, auth, spec, gated);
141
154
  const final = await applyImageFactsAndRouting(body, auth, folded.governed, {
142
155
  scenarioName: gated.scenarioName,
143
156
  scratchpadDir: folded.scratchpadDir,
@@ -149,7 +162,7 @@ export function createResolveSpec(ctx) {
149
162
  const gateScenarioAndAppend = async (body, auth, opts) => {
150
163
  const scenarioName = await scenarioGate(auth?.principal, body.scenario);
151
164
  gateExecutionLane(await principalCaps?.executionRuling(auth?.principal), executionLaneOf(config.remoteExec?.provider), logger);
152
- const cap = selectScenario(scenarios, scenarioName)(body, auth?.principal, auth?.sessionId !== undefined ? { sessionId: auth.sessionId } : {});
165
+ const cap = selectScenario(scenarios, scenarioName)(body, auth?.principal, auth?.sessionId !== undefined ? { sessionId: auth.sessionId, delegationRoot: { sessionId: auth.sessionId, incarnation: (await readSessionFace?.(auth.sessionId))?.incarnation ?? null } } : {});
153
166
  const acceptedAppend = acceptAppendSystemPrompt(body.appendSystemPrompt, (detail) => logger.warn("append_system_prompt_dropped", { detail, sessionId: auth?.sessionId ?? null }));
154
167
  const objective = typeof body.objective === "string" ? body.objective : "";
155
168
  const parsedSettings = parseTaskSettings(body.settings, opts?.leg === "fresh" || !taskHooksHonored(config) ? {} : { storedHooksReread: storedHooksRereadM20(new Date().toISOString().slice(0, 10)) });
@@ -274,22 +287,22 @@ export function createResolveSpec(ctx) {
274
287
  if (picked.unavailable !== undefined) {
275
288
  const { requested, name, refusal, source } = picked.unavailable;
276
289
  if (opts?.leg === "fresh") {
277
- throw new HttpError(400, modelUnavailableMessage(source === "mention" ? "@-mention" : "model", requested.slice(0, 120), name, refusal), { code: "request.model_unavailable" });
290
+ throw new HttpError(400, modelUnavailableMessage(source === "mention" ? "@-mention" : "model", requested, name, refusal), { code: "request.model_unavailable" });
278
291
  }
279
292
  metrics.inc("task_model_unavailable_fallback_total");
280
- logger.warn("task_model_unavailable_fallback", { requested: requested.slice(0, 120), name, code: refusal.code, source, fallback: picked.model, sessionId: auth?.sessionId ?? null });
293
+ logger.warn("task_model_unavailable_fallback", { requested: echoModelRef(requested), name, code: refusal.code, source, fallback: picked.model, sessionId: auth?.sessionId ?? null });
281
294
  }
282
295
  if (picked.notAllowed !== undefined) {
283
296
  const { requested, resolved, source } = picked.notAllowed;
284
297
  if (opts?.leg === "fresh") {
285
- throw new HttpError(400, `model "${requested.slice(0, 120)}" is not @-mentionable on this deployment (it resolves to catalog model "${resolved}") — which models can be @-mentioned is configured by the operator (models.atMention)`, { code: "request.model_not_allowed" });
298
+ throw new HttpError(400, `model "${echoModelRef(requested)}" is not @-mentionable on this deployment (it resolves to catalog model "${resolved}") — which models can be @-mentioned is configured by the operator (models.atMention)`, { code: "request.model_not_allowed" });
286
299
  }
287
300
  metrics.inc("task_model_not_allowlisted_resume_total");
288
- logger.warn("task_model_not_allowlisted_resume", { requested: requested.slice(0, 120), resolved, source, sessionId: auth?.sessionId ?? null, note: "resumed leg keeps running the model it was started on — the allowlist gates fresh picks only" });
301
+ logger.warn("task_model_not_allowlisted_resume", { requested: echoModelRef(requested), resolved, source, sessionId: auth?.sessionId ?? null, note: "resumed leg keeps running the model it was started on — the allowlist gates fresh picks only" });
289
302
  }
290
303
  if (picked.unknownExplicit !== undefined) {
291
304
  metrics.inc("task_model_unknown_fallback_total");
292
- logger.warn("task_model_unknown_fallback", { requested: picked.unknownExplicit.slice(0, 120), fallback: picked.model, sessionId: auth?.sessionId ?? null });
305
+ logger.warn("task_model_unknown_fallback", { requested: echoModelRef(picked.unknownExplicit), fallback: picked.model, sessionId: auth?.sessionId ?? null });
293
306
  }
294
307
  if (Array.isArray(body.images) && body.images.length > 0 && !modelSupportsImages(wireCatalog[picked.model])) {
295
308
  metrics.inc("images_omitted_total", { model: picked.model });
@@ -338,7 +351,7 @@ export function createResolveSpec(ctx) {
338
351
  return deriveAskEffective(askForm.form, "unresolved") === "human_reachable";
339
352
  };
340
353
  const assembleSpecLiteral = (body, auth, req, opts, parts, effMode) => {
341
- const { scenarioName, cap, hands, acceptedAppend, parsedSettings, attachmentNotice, taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked, resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes, } = parts;
354
+ const { scenarioName, cap, hands, acceptedAppend, parsedSettings, attachmentNotice, taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked, resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes, projectKey, } = parts;
342
355
  const storedToolAxes = opts?.leg === "fresh" ? undefined : storedToolAxesRereadM19(new Date().toISOString().slice(0, 10));
343
356
  const spec = {
344
357
  objective: attachmentNotice ? `${picked.cleanedObjective}\n\n${attachmentNotice}` : picked.cleanedObjective,
@@ -380,7 +393,7 @@ export function createResolveSpec(ctx) {
380
393
  ? { retainBackgroundProcesses: true }
381
394
  : {}),
382
395
  ...(body.excludeAllTools === true ? { excludeAllTools: true } : {}),
383
- ...(() => { const v = toolNameListFromBody(body.excludeTools); return v ? { excludeTools: v } : {}; })(),
396
+ ...buildExcludeToolsSeat(cap.excludeTools, toolNameListFromBody(body.excludeTools)),
384
397
  ...allowToolsSpecFragment(body.allowTools),
385
398
  ...(() => { const v = toolNameListFromBody(body.deferTools); return v ? { deferTools: v } : {}; })(),
386
399
  ...(() => { const v = promptProfileFromBody(body.promptProfile); return v ? { promptProfile: v } : {}; })(),
@@ -389,7 +402,7 @@ export function createResolveSpec(ctx) {
389
402
  ...(declaresInteractivePosture(body, req, opts) ? { interactionPosture: "interactive" } : {}),
390
403
  ...(body.approvalReach !== undefined ? { approvalReach: body.approvalReach } : {}),
391
404
  ...(typeof body.oneShot === "boolean" ? { oneShot: body.oneShot } : {}),
392
- resilience: normalizeResilience(body.resilience, explicitOperatorOk(auth?.principal, config.operatorPrincipals)),
405
+ resilience: normalizeResilience(body.resilience, explicitOperatorOk(auth?.principal, config)),
393
406
  finalVerification: cap.finalVerification === true || body.finalVerification === true ? true : undefined,
394
407
  attachments: normalizeAttachments(body.attachments),
395
408
  ...(taskHooks ? { mods: [taskHooks] } : {}),
@@ -400,23 +413,23 @@ export function createResolveSpec(ctx) {
400
413
  const cm = matchCatalogModel(body.compactionModel, wireCatalog, config.modelRefusals);
401
414
  const refusedCm = cm === undefined ? refusedCatalogEntry(body.compactionModel, config.modelRefusals) : undefined;
402
415
  if (refusedCm !== undefined && opts?.leg === "fresh") {
403
- throw new HttpError(400, modelUnavailableMessage("compactionModel", body.compactionModel.slice(0, 120), refusedCm.name, refusedCm.refusal), { code: "request.model_unavailable" });
416
+ throw new HttpError(400, modelUnavailableMessage("compactionModel", body.compactionModel, refusedCm.name, refusedCm.refusal), { code: "request.model_unavailable" });
404
417
  }
405
418
  if (cm === undefined) {
406
419
  if (opts?.leg === "fresh") {
407
- throw new HttpError(400, `unknown compactionModel "${body.compactionModel.slice(0, 120)}" — not in the configured catalog (name, tier word, or id; a catalog refresh may have removed it mid-request)`);
420
+ throw new HttpError(400, `unknown compactionModel "${echoModelRef(body.compactionModel)}" — not in the configured catalog (name, tier word, or id; a catalog refresh may have removed it mid-request)`);
408
421
  }
409
422
  metrics.inc("task_model_unknown_fallback_total");
410
- logger.warn("compaction_model_unknown_fallback", { requested: body.compactionModel.slice(0, 120), sessionId: auth?.sessionId ?? null });
423
+ logger.warn("compaction_model_unknown_fallback", { requested: echoModelRef(body.compactionModel), sessionId: auth?.sessionId ?? null });
411
424
  return {};
412
425
  }
413
426
  if (!isAtMentionable(cm, wireCatalog, config.atMention, config.modelRefusals)) {
414
427
  const terminal = terminalCatalogName(cm, wireCatalog, config.modelRefusals) ?? cm;
415
428
  if (opts?.leg === "fresh") {
416
- throw new HttpError(400, `compactionModel "${body.compactionModel.slice(0, 120)}" is not @-mentionable on this deployment (it resolves to catalog model "${terminal}") — which models can be @-mentioned is configured by the operator (models.atMention)`, { code: "request.model_not_allowed" });
429
+ throw new HttpError(400, `compactionModel "${echoModelRef(body.compactionModel)}" is not @-mentionable on this deployment (it resolves to catalog model "${terminal}") — which models can be @-mentioned is configured by the operator (models.atMention)`, { code: "request.model_not_allowed" });
417
430
  }
418
431
  metrics.inc("task_model_not_allowlisted_resume_total");
419
- logger.warn("task_model_not_allowlisted_resume", { requested: body.compactionModel.slice(0, 120), resolved: terminal, source: "compaction", sessionId: auth?.sessionId ?? null, note: "resumed leg keeps the compaction model it was started with — the allowlist gates fresh picks only" });
432
+ logger.warn("task_model_not_allowlisted_resume", { requested: echoModelRef(body.compactionModel), resolved: terminal, source: "compaction", sessionId: auth?.sessionId ?? null, note: "resumed leg keeps the compaction model it was started with — the allowlist gates fresh picks only" });
420
433
  }
421
434
  return { compactionModel: cm };
422
435
  })()),
@@ -459,7 +472,7 @@ export function createResolveSpec(ctx) {
459
472
  })(),
460
473
  ...(config.requirePrincipal !== true ? { backgroundScope: "session" } : {}),
461
474
  memory: memoryEngine
462
- ? memorySpecForRequest(auth?.memoryScope, memoryProjectKeyFor(config, auth?.memoryScope, realTaskRootOf(auth)), body.memoryWrite, s4DefaultScopes, { multiTenant: config.requirePrincipal === true }, { memory: body.memory, memoryCapture: body.memoryCapture })
475
+ ? memorySpecForRequest(auth?.memoryScope, projectKey, body.memoryWrite, s4DefaultScopes, { multiTenant: config.requirePrincipal === true }, { memory: body.memory, memoryCapture: body.memoryCapture })
463
476
  : undefined,
464
477
  ...((v) => (v !== undefined ? { memoryPersistenceCapable: v } : {}))(effectiveMemoryPersistenceCapable(config)),
465
478
  tools: ((base) => {
@@ -505,7 +518,7 @@ export function createResolveSpec(ctx) {
505
518
  };
506
519
  return spec;
507
520
  };
508
- const foldGovernanceAndSettings = async (body, auth, spec, gated, effMode) => {
521
+ const foldGovernanceAndSettings = async (body, auth, spec, gated) => {
509
522
  const { acceptedAppend, parsedSettings } = gated;
510
523
  const hostSemanticsLane = !isSandboxPathAdjudicationLane(config.remoteExec?.provider);
511
524
  const laneHomeBase = () => {
@@ -533,7 +546,7 @@ export function createResolveSpec(ctx) {
533
546
  };
534
547
  const governedBase = applyRuntimeGovernance(spec, createDeploymentGovernanceInputs(config, pathAdjudication));
535
548
  let governed = governedBase;
536
- let effectiveSettings = effMode ? withPermissionMode(parsedSettings.settings, effMode) : parsedSettings.settings;
549
+ let effectiveSettings = parsedSettings.settings;
537
550
  if (effectiveSettings?.outputStyle && acceptedAppend && acceptedAppend.length + 2 + effectiveSettings.outputStyle.length > MAX_SETTINGS_OUTPUT_STYLE_CHARS) {
538
551
  logger.warn("output_style_dropped", { detail: `combined append carriers exceed the ${MAX_SETTINGS_OUTPUT_STYLE_CHARS} cap (rider ${acceptedAppend.length} + style ${effectiveSettings.outputStyle.length}) — style dropped (pre-cap stored body on a resume leg?)`, sessionId: auth?.sessionId ?? null });
539
552
  const { outputStyle: _dropped2, ...rest2 } = effectiveSettings;
@@ -549,65 +562,31 @@ export function createResolveSpec(ctx) {
549
562
  ? await ensureScratchpadDir(config.localDataRoot ?? localRoot, auth.sessionId, (msg, meta) => logger.warn(msg, { ...(meta ?? {}), sessionId: auth.sessionId }))
550
563
  : undefined);
551
564
  if (effectiveSettings) {
552
- const gateCommon = {
553
- ...(approvalExemptionStore && auth?.sessionId
554
- ? {
555
- isExempt: async (toolName) => {
556
- const hit = await approvalExemptionStore.has(auth.sessionId, toolName);
557
- if (hit)
558
- logger.info("fs_write_gate_exempted", { toolName, sessionId: auth.sessionId });
559
- return hit;
560
- },
561
- }
562
- : {}),
565
+ const ruleBases = {
566
+ ...(pathAdjudication.taskRoot !== undefined ? { taskRoot: pathAdjudication.taskRoot } : {}),
567
+ ...(pathAdjudication.taskHome !== undefined ? { taskHome: pathAdjudication.taskHome } : {}),
563
568
  };
564
- const fsWriteGate = hostSemanticsLane
565
- ? {
566
- env: pathAdjudication.env,
567
- ...(pathAdjudication.cwd !== undefined ? { cwd: pathAdjudication.cwd } : {}),
568
- ...(pathAdjudication.taskRoot !== undefined ? { taskRoot: pathAdjudication.taskRoot } : {}),
569
- ...(pathAdjudication.taskHome !== undefined ? { taskHome: pathAdjudication.taskHome } : {}),
570
- ...(scratchpadDir ? { scratchpadDir } : {}),
571
- ...gateCommon,
572
- }
573
- :
574
- (() => {
575
- const sandboxScratchpadDir = isRemoteScratchpadLane(config.remoteExec?.provider) ? remoteScratchpadDirFor(auth?.sessionId) : undefined;
576
- return {
577
- env: pathAdjudication.env,
578
- ...(pathAdjudication.taskHome !== undefined ? { taskHome: pathAdjudication.taskHome } : {}),
579
- ...gateCommon,
580
- ...(sandboxScratchpadDir ? { scratchpadDir: sandboxScratchpadDir } : {}),
581
- ...(gateCommon.isExempt
582
- ? {
583
- isExempt: (toolName, canonicalPath) => canonicalPath.startsWith("/") ? gateCommon.isExempt(toolName) : false,
584
- }
585
- : {}),
586
- };
587
- })();
588
- const workflowGate = approvalExemptionStore && auth?.sessionId
589
- ? {
590
- isExempt: async (toolName) => {
591
- const hit = await approvalExemptionStore.has(auth.sessionId, toolName);
592
- if (hit)
593
- logger.info("workflow_gate_exempted", { toolName, sessionId: auth.sessionId });
594
- return hit;
595
- },
596
- }
597
- : undefined;
598
569
  try {
599
- governed = applyTaskSettings(governedBase, effectiveSettings, fsWriteGate, workflowGate);
570
+ governed = applyTaskSettings(governedBase, effectiveSettings, ruleBases);
600
571
  }
601
572
  catch (e) {
602
- if (e.code === WRITE_EXEMPT_DIR_COVERS_ROOT_CODE) {
603
- throw new HttpError(400, e.message, {
604
- code: "request.field_conflict",
605
- ...(e.detail !== undefined ? { extra: { writeExemptDirCoversRoot: e.detail } } : {}),
606
- });
607
- }
573
+ if (e instanceof SettingsRuleRefusalError)
574
+ throw new HttpError(422, `${REQUEST_SETTINGS_REFUSAL_PREFIX}${e.message}`, { code: SETTINGS_RULE_REFUSAL_CODE, extra: { ...entryProblemsFacts(e.problems) } });
608
575
  throw new HttpError(422, `${REQUEST_SETTINGS_REFUSAL_PREFIX}${e.message}`);
609
576
  }
610
577
  }
578
+ if (governed.selfOrchestration === true) {
579
+ governed = tightenGoverned(governed, {
580
+ toolPolicy: createWorkflowAskPolicy(approvalExemptionStore && auth?.sessionId
581
+ ? async (toolName) => {
582
+ const hit = await approvalExemptionStore.has(auth.sessionId, toolName);
583
+ if (hit)
584
+ logger.info("workflow_gate_exempted", { toolName, sessionId: auth.sessionId });
585
+ return hit;
586
+ }
587
+ : undefined),
588
+ });
589
+ }
611
590
  return { governed, scratchpadDir, hostSemanticsLane };
612
591
  };
613
592
  const applyImageFactsAndRouting = async (body, auth, governed, folded) => {
@@ -631,7 +610,7 @@ export function createResolveSpec(ctx) {
631
610
  const resolved = await resolveSandboxImageRef({
632
611
  profile: taskImageProfile,
633
612
  ...(capsNeeded && capsNeeded.length > 0 ? { capabilitiesNeeded: capsNeeded } : {}),
634
- viewer: { operator: explicitOperatorOk(auth.principal, config.operatorPrincipals), tenantId: auth.principal ?? null },
613
+ viewer: { operator: explicitOperatorOk(auth.principal, config), tenantId: auth.principal ?? null },
635
614
  index: imageIndex,
636
615
  });
637
616
  if (!resolved.ok)
@@ -662,7 +641,7 @@ export function createResolveSpec(ctx) {
662
641
  const isolatedExecEnv = isIsolatedExecEnv(config.remoteExec?.provider, config.remoteExec?.provider === "k8s" ? config.remoteExec.runtimeClass : undefined);
663
642
  const decision = routeServiceTask({
664
643
  isolatedExecEnv,
665
- hasExecutionEnv: executionLaneCaps(executionLaneOf(config.remoteExec?.provider)).coreRemoteExecutionEnv === "supported",
644
+ hasExecutionEnv: laneWiresExecutionEnv(executionLaneOf(config.remoteExec?.provider)),
666
645
  ...(config.autonomy ? { autonomy: config.autonomy } : {}),
667
646
  });
668
647
  logger.info("orchestration_routed", { mode: decision.mode, reason: decision.reason, sessionId: auth?.sessionId ?? null });