@sema-agent/server 7.135.0 → 7.137.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 (342) hide show
  1. package/MIGRATION.md +237 -2
  2. package/USAGE.md +146 -41
  3. package/deploy/sema-up/README.md +15 -1
  4. package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
  5. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
  6. package/deploy/sema-up/chart/values.yaml +1 -1
  7. package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
  8. package/dist/approval-card.d.ts +60 -4
  9. package/dist/approval-card.js +18 -1
  10. package/dist/approval-content-kind.d.ts +7 -0
  11. package/dist/approval-content-kind.js +8 -1
  12. package/dist/approval-gate-currency.d.ts +48 -6
  13. package/dist/approval-gate-currency.js +16 -9
  14. package/dist/approval-hmac.d.ts +13 -1
  15. package/dist/approval-hmac.js +1 -1
  16. package/dist/approval.js +3 -3
  17. package/dist/auth-bridge.d.ts +34 -5
  18. package/dist/auth-bridge.js +22 -5
  19. package/dist/boot/budget-tracing.d.ts +1 -2
  20. package/dist/boot/budget-tracing.js +2 -2
  21. package/dist/boot/execution-env.d.ts +24 -1
  22. package/dist/boot/execution-env.js +69 -6
  23. package/dist/boot/org-memory.js +1 -1
  24. package/dist/boot/reapers.d.ts +3 -0
  25. package/dist/boot/reapers.js +15 -1
  26. package/dist/boot/resolve-spec.d.ts +4 -0
  27. package/dist/boot/resolve-spec.js +24 -22
  28. package/dist/boot/runner-deps.js +4 -2
  29. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  30. package/dist/boot/stage-04-stores.d.ts +2 -2
  31. package/dist/boot/stage-05-execution-env.d.ts +4 -2
  32. package/dist/boot/stage-05-execution-env.js +11 -2
  33. package/dist/boot/stage-06-runners.d.ts +4 -2
  34. package/dist/boot/stage-06-runners.js +5 -1
  35. package/dist/boot/stage-07-capability-layer.d.ts +5 -2
  36. package/dist/boot/stage-07-capability-layer.js +1 -1
  37. package/dist/boot/stage-08-reapers.d.ts +5 -2
  38. package/dist/boot/stage-08-reapers.js +2 -1
  39. package/dist/boot/stage-09-leader.d.ts +5 -2
  40. package/dist/boot/stage-10-http-server.d.ts +5 -2
  41. package/dist/boot/stage-10-http-server.js +3 -2
  42. package/dist/boot/stores.d.ts +1 -1
  43. package/dist/boot/stores.js +2 -3
  44. package/dist/boot/web-admin.js +10 -17
  45. package/dist/brain.js +12 -3
  46. package/dist/broker/broker.d.ts +89 -0
  47. package/dist/broker/broker.js +287 -0
  48. package/dist/broker/constants.d.ts +39 -0
  49. package/dist/broker/constants.js +15 -0
  50. package/dist/broker/http1.d.ts +111 -0
  51. package/dist/broker/http1.js +256 -0
  52. package/dist/broker/lease-book.d.ts +87 -0
  53. package/dist/broker/lease-book.js +142 -0
  54. package/dist/broker/lease-file.d.ts +60 -0
  55. package/dist/broker/lease-file.js +127 -0
  56. package/dist/broker/main.d.ts +2 -0
  57. package/dist/broker/main.js +20 -0
  58. package/dist/budget.d.ts +3 -3
  59. package/dist/budget.js +4 -0
  60. package/dist/capabilities/composite-members.d.ts +2 -1
  61. package/dist/capabilities/composite-members.js +2 -1
  62. package/dist/capabilities/engine-capabilities.js +1 -0
  63. package/dist/capabilities/mcp-probe.d.ts +5 -4
  64. package/dist/capabilities/scenarios.d.ts +23 -8
  65. package/dist/capabilities/scenarios.js +13 -8
  66. package/dist/capabilities/skills.d.ts +28 -5
  67. package/dist/capabilities/skills.js +8 -0
  68. package/dist/capability-facts.d.ts +3 -7
  69. package/dist/capability-facts.js +3 -5
  70. package/dist/center-credential-renewer.js +5 -1
  71. package/dist/center-credential.d.ts +18 -4
  72. package/dist/center-credential.js +18 -3
  73. package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
  74. package/dist/checkpoint-ctx-seal-m28.js +1 -1
  75. package/dist/checkpoint-identity.d.ts +3 -3
  76. package/dist/config-catalog.js +21 -16
  77. package/dist/config-d-migration.js +1 -1
  78. package/dist/config-invariants.d.ts +1 -1
  79. package/dist/config-invariants.js +8 -0
  80. package/dist/config-lkg.d.ts +0 -38
  81. package/dist/config-lkg.js +1 -83
  82. package/dist/config-types.d.ts +21 -4
  83. package/dist/config.d.ts +1 -1
  84. package/dist/config.js +60 -16
  85. package/dist/deployment-governance.d.ts +2 -2
  86. package/dist/deployment-governance.js +7 -9
  87. package/dist/deployment-shape.d.ts +1 -1
  88. package/dist/device-ws-protocol.d.ts +1 -0
  89. package/dist/device-ws-protocol.js +2 -1
  90. package/dist/elicitation.d.ts +8 -7
  91. package/dist/elicitation.js +9 -8
  92. package/dist/file-history-disclosure.d.ts +8 -4
  93. package/dist/file-history-disclosure.js +24 -6
  94. package/dist/fleet-client.d.ts +32 -1
  95. package/dist/fleet-client.js +24 -4
  96. package/dist/fleet-lease.d.ts +7 -3
  97. package/dist/fleet-lease.js +31 -23
  98. package/dist/hooks/classic-stations.d.ts +11 -54
  99. package/dist/hooks/hook-llm.js +14 -8
  100. package/dist/hooks/hook-runner.d.ts +4 -4
  101. package/dist/hooks/hook-runner.js +2 -2
  102. package/dist/http/admission.js +10 -7
  103. package/dist/http/approval-sweeps.js +4 -3
  104. package/dist/http/caller-trust.d.ts +2 -1
  105. package/dist/http/caller-trust.js +1 -3
  106. package/dist/http/checkpoint-ctx.d.ts +76 -16
  107. package/dist/http/checkpoint-ctx.js +45 -1
  108. package/dist/http/dispatch.js +24 -19
  109. package/dist/http/durable-run-leg.d.ts +5 -1
  110. package/dist/http/durable-run-leg.js +1 -1
  111. package/dist/http/health-self-report.d.ts +2 -2
  112. package/dist/http/mcp-remote-text.d.ts +5 -0
  113. package/dist/http/mcp-remote-text.js +7 -0
  114. package/dist/http/principal-gate.d.ts +15 -10
  115. package/dist/http/principal-gate.js +48 -9
  116. package/dist/http/resume-ctx-read.d.ts +2 -16
  117. package/dist/http/resume-ctx-read.js +2 -3
  118. package/dist/http/resume-legs.d.ts +2 -20
  119. package/dist/http/resume-legs.js +52 -38
  120. package/dist/http/route-ctx.d.ts +8 -2
  121. package/dist/http/routes/approvals-assistant.d.ts +0 -2
  122. package/dist/http/routes/approvals-assistant.js +65 -16
  123. package/dist/http/routes/capabilities.js +11 -1
  124. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  125. package/dist/http/routes/mcp-reconnect.js +5 -7
  126. package/dist/http/routes/runs.js +4 -3
  127. package/dist/http/routes/session-sync.js +70 -12
  128. package/dist/http/routes/sessions.js +20 -15
  129. package/dist/http/routes/tasks.js +8 -6
  130. package/dist/http/server.d.ts +4 -0
  131. package/dist/http/stored-body-replay.d.ts +3 -3
  132. package/dist/http/stored-body-replay.js +6 -1
  133. package/dist/http/submit-ctx.js +1 -1
  134. package/dist/http/wire-types.d.ts +57 -30
  135. package/dist/identity-source.d.ts +65 -0
  136. package/dist/identity-source.js +45 -0
  137. package/dist/index.d.ts +1 -0
  138. package/dist/index.js +1 -0
  139. package/dist/memory-store-refusal.d.ts +3 -3
  140. package/dist/model-entry-refusal.d.ts +2 -0
  141. package/dist/model-entry-refusal.js +11 -0
  142. package/dist/model-route-gap.d.ts +49 -4
  143. package/dist/model-route-gap.js +34 -1
  144. package/dist/model-select.d.ts +6 -17
  145. package/dist/model-select.js +0 -3
  146. package/dist/namespaced-rule-name.d.ts +1 -1
  147. package/dist/object-store-buckets.d.ts +13 -0
  148. package/dist/object-store-buckets.js +3 -0
  149. package/dist/observability/fail-open.d.ts +19 -7
  150. package/dist/observability/fail-open.js +19 -7
  151. package/dist/observability/metrics.js +2 -2
  152. package/dist/observability/principal-context.d.ts +4 -1
  153. package/dist/observability/principal-context.js +6 -1
  154. package/dist/observability/run-terminal.js +1 -0
  155. package/dist/operator-ask.d.ts +2 -2
  156. package/dist/org-delivery-gate.js +1 -1
  157. package/dist/org-memory-admission.d.ts +2 -2
  158. package/dist/org-memory-admission.js +39 -2
  159. package/dist/parked-decide.d.ts +4 -3
  160. package/dist/parked-decide.js +29 -9
  161. package/dist/peer-directory.d.ts +2 -1
  162. package/dist/peer-directory.js +7 -5
  163. package/dist/permission-rule-list.d.ts +2 -2
  164. package/dist/plugins/approval-ask-store-sql.d.ts +8 -0
  165. package/dist/plugins/approval-ask-store-sql.js +3 -0
  166. package/dist/plugins/blob-backend.js +2 -1
  167. package/dist/plugins/checkpoint-index-columns.d.ts +50 -1
  168. package/dist/plugins/checkpoint-index-columns.js +28 -0
  169. package/dist/plugins/checkpoint-store-sql.d.ts +46 -12
  170. package/dist/plugins/checkpoint-store-sql.js +64 -35
  171. package/dist/plugins/file-history-store-sql.d.ts +6 -0
  172. package/dist/plugins/file-history-store-sql.js +37 -37
  173. package/dist/plugins/file-run-store.js +8 -2
  174. package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
  175. package/dist/plugins/k8s-exec-protocol.js +116 -28
  176. package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
  177. package/dist/plugins/k8s-pod-delete-failure.js +17 -0
  178. package/dist/plugins/k8s-pod-reaper.d.ts +112 -0
  179. package/dist/plugins/k8s-pod-reaper.js +122 -0
  180. package/dist/plugins/local-checkpoint-store.d.ts +3 -6
  181. package/dist/plugins/local-checkpoint-store.js +7 -6
  182. package/dist/plugins/memory-run-store.js +2 -0
  183. package/dist/plugins/one-time-migrations.d.ts +49 -37
  184. package/dist/plugins/one-time-migrations.js +87 -128
  185. package/dist/plugins/permission-rule-store-file.js +2 -2
  186. package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
  187. package/dist/plugins/permission-rule-store-sql.js +16 -17
  188. package/dist/plugins/pg-pool.js +4 -0
  189. package/dist/plugins/pg-session-storage.js +2 -2
  190. package/dist/plugins/remote-env-adb.d.ts +3 -0
  191. package/dist/plugins/remote-env-adb.js +1 -0
  192. package/dist/plugins/remote-env-device.d.ts +3 -0
  193. package/dist/plugins/remote-env-device.js +4 -0
  194. package/dist/plugins/remote-env-e2b.d.ts +3 -0
  195. package/dist/plugins/remote-env-e2b.js +1 -0
  196. package/dist/plugins/remote-env-file-error.d.ts +8 -1
  197. package/dist/plugins/remote-env-file-error.js +7 -1
  198. package/dist/plugins/remote-env-host.d.ts +7 -1
  199. package/dist/plugins/remote-env-host.js +7 -1
  200. package/dist/plugins/remote-env-k8s.d.ts +154 -14
  201. package/dist/plugins/remote-env-k8s.js +300 -21
  202. package/dist/plugins/remote-env-local-docker.d.ts +3 -0
  203. package/dist/plugins/remote-env-local-docker.js +1 -0
  204. package/dist/plugins/remote-env-ssh.d.ts +3 -0
  205. package/dist/plugins/remote-env-ssh.js +1 -0
  206. package/dist/plugins/run-store-sql.js +10 -4
  207. package/dist/plugins/s3-answer.d.ts +15 -0
  208. package/dist/plugins/s3-answer.js +5 -0
  209. package/dist/plugins/session-ownership.d.ts +17 -3
  210. package/dist/plugins/session-ownership.js +19 -5
  211. package/dist/plugins/snapshot-bucket-presence.d.ts +39 -4
  212. package/dist/plugins/snapshot-bucket-presence.js +35 -7
  213. package/dist/plugins/sql-errors.d.ts +60 -0
  214. package/dist/plugins/sql-errors.js +64 -1
  215. package/dist/plugins/store-contracts.d.ts +10 -1
  216. package/dist/plugins/store-fault.d.ts +4 -0
  217. package/dist/plugins/store-fault.js +10 -0
  218. package/dist/plugins/tidb-pool.js +8 -1
  219. package/dist/plugins/tidb-session-store.js +2 -2
  220. package/dist/plugins/web-search.d.ts +1 -1
  221. package/dist/plugins/web-search.js +2 -2
  222. package/dist/request-declaration-refusal.d.ts +94 -0
  223. package/dist/request-declaration-refusal.js +78 -0
  224. package/dist/request-image-urls.d.ts +6 -0
  225. package/dist/request-image-urls.js +27 -0
  226. package/dist/request-key-closure.d.ts +5 -0
  227. package/dist/request-key-closure.js +5 -2
  228. package/dist/request-value-closure.d.ts +31 -2
  229. package/dist/request-value-closure.js +7 -1
  230. package/dist/rule-entry-list.d.ts +3 -2
  231. package/dist/rule-entry-list.js +2 -2
  232. package/dist/rules-consent.js +7 -4
  233. package/dist/run-local.d.ts +2 -2
  234. package/dist/runs.js +2 -1
  235. package/dist/runtime-caps-resolver.js +1 -1
  236. package/dist/runtime-governance.d.ts +5 -5
  237. package/dist/sandbox-git-lease.d.ts +49 -0
  238. package/dist/sandbox-git-lease.js +60 -0
  239. package/dist/sandbox-git-plane.d.ts +84 -0
  240. package/dist/sandbox-git-plane.js +105 -0
  241. package/dist/sandbox-pkg-source.d.ts +28 -1
  242. package/dist/sandbox-pkg-source.js +1 -2
  243. package/dist/sealed-key.d.ts +19 -0
  244. package/dist/sealed-key.js +47 -4
  245. package/dist/security.d.ts +16 -4
  246. package/dist/security.js +8 -3
  247. package/dist/server-secret-env.d.ts +6 -0
  248. package/dist/server-secret-env.js +14 -0
  249. package/dist/session-error-wire.d.ts +14 -6
  250. package/dist/session-error-wire.js +2 -1
  251. package/dist/session-incarnation.d.ts +16 -5
  252. package/dist/session-incarnation.js +7 -4
  253. package/dist/session-policy-wire.d.ts +1 -1
  254. package/dist/session-policy-wire.js +2 -2
  255. package/dist/session-row.d.ts +3 -17
  256. package/dist/session-row.js +4 -0
  257. package/dist/session-sync.d.ts +15 -3
  258. package/dist/session-sync.js +5 -2
  259. package/dist/spec-fields.d.ts +43 -13
  260. package/dist/spec-fields.js +33 -12
  261. package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
  262. package/dist/stored-request-prompt-profile-m30.js +25 -0
  263. package/dist/task-a2a.d.ts +52 -81
  264. package/dist/task-a2a.js +219 -89
  265. package/dist/task-mcp.d.ts +7 -15
  266. package/dist/task-mcp.js +16 -51
  267. package/dist/task-settings.d.ts +2 -2
  268. package/dist/tool-approval.d.ts +35 -12
  269. package/dist/tool-approval.js +59 -39
  270. package/dist/tool-rule-names.d.ts +5 -0
  271. package/dist/trace/core-keyset-guard.d.ts +5 -5
  272. package/dist/trace/engine-notice-wire.d.ts +1 -1
  273. package/dist/trace/engine-notice-wire.js +2 -0
  274. package/dist/trace/exit-seat.js +37 -13
  275. package/dist/trace/ledger-sink.d.ts +4 -5
  276. package/dist/trace/ledger-sink.js +3 -7
  277. package/dist/trace/project.d.ts +37 -3
  278. package/dist/trace/project.js +20 -6
  279. package/dist/trace/redact.d.ts +40 -12
  280. package/dist/trace/redact.js +332 -128
  281. package/dist/trace/self-minted-wire.d.ts +641 -0
  282. package/dist/trace/self-minted-wire.js +201 -0
  283. package/dist/trace/wire-projection-faces.d.ts +5 -3
  284. package/dist/trace/wire-projection-faces.js +7 -3
  285. package/dist/url-credential-refusal.d.ts +52 -0
  286. package/dist/url-credential-refusal.js +14 -0
  287. package/dist/url-refusal.d.ts +13 -4
  288. package/dist/url-refusal.js +8 -2
  289. package/dist/web-admin-client/apply-effective.js +0 -1
  290. package/dist/web-admin-client/center-request.d.ts +20 -2
  291. package/dist/web-admin-client/center-request.js +40 -5
  292. package/dist/web-admin-client/http-client.js +6 -6
  293. package/dist/web-admin-client/types.d.ts +5 -5
  294. package/dist/workspace-space.d.ts +27 -0
  295. package/dist/workspace-space.js +26 -0
  296. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
  297. package/package.json +4 -3
  298. package/scripts/drain-check-local.mjs +2 -1
  299. package/scripts/drain-check.mysql.sql +3 -1
  300. package/scripts/drain-check.pg.sql +3 -1
  301. package/skills/schedule.md +1 -1
  302. package/wire-changes/server@7.104.0.json +134 -0
  303. package/wire-changes/server@7.105.0.json +53 -0
  304. package/wire-changes/server@7.106.0.json +475 -0
  305. package/wire-changes/server@7.107.0.json +64 -0
  306. package/wire-changes/server@7.108.0.json +153 -0
  307. package/wire-changes/server@7.109.0.json +46 -0
  308. package/wire-changes/server@7.110.0.json +90 -0
  309. package/wire-changes/server@7.111.0.json +86 -0
  310. package/wire-changes/server@7.112.0.json +60 -0
  311. package/wire-changes/server@7.113.0.json +26 -0
  312. package/wire-changes/server@7.114.0.json +26 -0
  313. package/wire-changes/server@7.115.0.json +97 -0
  314. package/wire-changes/server@7.116.0.json +218 -0
  315. package/wire-changes/server@7.116.1.json +26 -0
  316. package/wire-changes/server@7.117.0.json +65 -0
  317. package/wire-changes/server@7.118.0.json +129 -0
  318. package/wire-changes/server@7.119.0.json +65 -0
  319. package/wire-changes/server@7.120.0.json +89 -0
  320. package/wire-changes/server@7.121.0.json +219 -0
  321. package/wire-changes/server@7.122.0.json +54 -0
  322. package/wire-changes/server@7.123.0.json +26 -0
  323. package/wire-changes/server@7.124.0.json +336 -0
  324. package/wire-changes/server@7.124.1.json +26 -0
  325. package/wire-changes/server@7.125.0.json +111 -0
  326. package/wire-changes/server@7.126.0.json +285 -0
  327. package/wire-changes/server@7.127.0.json +77 -0
  328. package/wire-changes/server@7.127.1.json +26 -0
  329. package/wire-changes/server@7.127.2.json +53 -0
  330. package/wire-changes/server@7.128.0.json +26 -0
  331. package/wire-changes/server@7.129.0.json +106 -0
  332. package/wire-changes/server@7.129.1.json +26 -0
  333. package/wire-changes/server@7.130.0.json +26 -0
  334. package/wire-changes/server@7.131.0.json +118 -0
  335. package/wire-changes/server@7.132.0.json +226 -0
  336. package/wire-changes/server@7.133.0.json +1155 -0
  337. package/wire-changes/server@7.134.0.json +107 -0
  338. package/wire-changes/server@7.135.0.json +174 -0
  339. package/wire-changes/server@7.136.0.json +448 -0
  340. package/wire-changes/server@7.137.0.json +825 -0
  341. package/dist/url-credential.d.ts +0 -52
  342. package/dist/url-credential.js +0 -49
@@ -3,7 +3,7 @@ import { redactHead, redactLedgerEventForRead } from "../../observability/run-te
3
3
  import { z } from "zod";
4
4
  import { uuidv7, mintCheckpointToken, CheckpointError, policyCannotAnswer, validatePendingSteer, TASK_OUTPUT_REPLAY_KINDS, isSystemInjectionPriority } from "@sema-agent/core";
5
5
  import { isTerminalRunStatus, isParkedRunStatus, runProvenElsewhere } from "../../plugins/store-contracts.js";
6
- import { askRowCarriesOwner } from "../../plugins/approval-ask-store-sql.js";
6
+ import { askOwnerAdmits, askRowCarriesOwner } from "../../plugins/approval-ask-store-sql.js";
7
7
  import { LIVE_RUN_GATE_KINDS, TERMINAL_PARK_GATE_KINDS } from "../../plugins/checkpoint-store-sql.js";
8
8
  import { redactSecrets } from "../../trace/redact.js";
9
9
  import { isUuidV7, encodeCheckpointScope } from "../../security.js";
@@ -22,7 +22,7 @@ import { invalidJsonError, sendJson, sendError, sendHttpError, sseHeaders } from
22
22
  import { mintCancelledResult } from "../../run-cancel-context.js";
23
23
  import { acceptedInputKindOf } from "../../user-input-ledger.js";
24
24
  import { INJECTION_TIERS } from "../../trace/injection-tier.js";
25
- import { headerStr, gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal } from "../principal-gate.js";
25
+ import { headerStr, gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, runIdentityOf } from "../principal-gate.js";
26
26
  import { ActorAssertionWire } from "@sema-agent/settings-schema";
27
27
  import * as facts from "../../capability-facts.js";
28
28
  import { assertNever } from "../route-ctx.js";
@@ -1345,7 +1345,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1345
1345
  askNotFound();
1346
1346
  return;
1347
1347
  }
1348
- const ownerOk = row0.owner === null || (principal !== undefined && row0.owner === principal);
1348
+ const ownerOk = askOwnerAdmits(row0.owner, principal);
1349
1349
  const operatorOk = explicitOperatorOk(principal, deps.config);
1350
1350
  if (!ownerOk && !operatorOk) {
1351
1351
  askNotFound();
@@ -1603,6 +1603,7 @@ export async function createDurableRun(req, res, ctx, prepared, idem) {
1603
1603
  fleetScope: submitter ?? "default",
1604
1604
  elicitOwner: submitter ?? null,
1605
1605
  source,
1606
+ identity: runIdentityOf(req, deps.config, prepared.auth?.principal ?? null),
1606
1607
  });
1607
1608
  return out.existing ? await replayOfExistingRun(out.existing, caller, "durable", deps, runStore) : out;
1608
1609
  });
@@ -8,6 +8,7 @@ import { classifySyncRelationshipByIds, SyncConflictError } from "../../session-
8
8
  import { isUuidShape, legacyUnownedSessionOk, sessionOwnerCellOf } from "../../security.js";
9
9
  import { sendJson, sendError, sendSessionError, sendSessionPolicyError, logRequestError, msg } from "../send.js";
10
10
  import { buildDisplaySafeUrl } from "../../trace/redact.js";
11
+ import { storeFaultClassOf } from "../../plugins/store-fault.js";
11
12
  import { fleetViewOf, gatedPrincipal, explicitOperatorOk, sendUnauthorized, sessionCallerOf } from "../principal-gate.js";
12
13
  const SYNC_BLOB_MAX_BYTES = 64 * 1024 * 1024;
13
14
  const SYNC_NDJSON_LINE_MAX_BYTES = 8 * 1024 * 1024;
@@ -60,7 +61,15 @@ export async function handleSessionSync(req, res, match, ctx) {
60
61
  const mayTouch = face !== undefined && (scope.fleetWide || face.owner === scope.gateOwner || legacyUnownedSessionOk(deps.config, sessionCallerOf(req, deps), await sessionOwnerCellOf(sessionStorage, sessionId, face.owner)));
61
62
  return { face, mayPull: mayTouch, mayPush: face === undefined || mayTouch };
62
63
  };
63
- const gate = await judgeSessionGate();
64
+ let gate;
65
+ try {
66
+ gate = await judgeSessionGate();
67
+ }
68
+ catch (e) {
69
+ if (isPullPort(match.decl.id) && sendPullUnreadable(req, res, deps.logger, e))
70
+ return;
71
+ throw e;
72
+ }
64
73
  const gateFace = gate.face;
65
74
  const owner = gateFace === undefined ? undefined : gateFace.owner;
66
75
  const sendSessionAbsent = () => sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
@@ -96,7 +105,7 @@ export async function handleSessionSync(req, res, match, ctx) {
96
105
  out = await exportSessionManifest(sessionId, backend, historyStore);
97
106
  }
98
107
  catch (e) {
99
- if (sendSessionPolicyError(res, e) || sendFileHistoryUnreadable(res, e))
108
+ if (sendSessionPolicyError(res, e) || sendPullUnreadable(req, res, deps.logger, e))
100
109
  return;
101
110
  throw e;
102
111
  }
@@ -120,7 +129,15 @@ export async function handleSessionSync(req, res, match, ctx) {
120
129
  }
121
130
  afterSeq = n;
122
131
  }
123
- const it = await sessionStorage.exportEntriesStream(sessionId, afterSeq === undefined ? undefined : { afterSeq });
132
+ let it;
133
+ try {
134
+ it = await sessionStorage.exportEntriesStream(sessionId, afterSeq === undefined ? undefined : { afterSeq });
135
+ }
136
+ catch (e) {
137
+ if (sendPullUnreadable(req, res, deps.logger, e))
138
+ return;
139
+ throw e;
140
+ }
124
141
  if (it === null) {
125
142
  sendSessionAbsent();
126
143
  return;
@@ -167,7 +184,7 @@ export async function handleSessionSync(req, res, match, ctx) {
167
184
  envelope = await exportedFileHistory(fs, sessionId);
168
185
  }
169
186
  catch (e) {
170
- if (sendFileHistoryUnreadable(res, e))
187
+ if (sendPullUnreadable(req, res, deps.logger, e))
171
188
  return;
172
189
  throw e;
173
190
  }
@@ -176,7 +193,15 @@ export async function handleSessionSync(req, res, match, ctx) {
176
193
  sendError(res, 404, "not_found.blob", "blob not found");
177
194
  return;
178
195
  }
179
- const bytes = await fs.getBlob(hash);
196
+ let bytes;
197
+ try {
198
+ bytes = await fs.getBlob(hash);
199
+ }
200
+ catch (e) {
201
+ if (sendPullUnreadable(req, res, deps.logger, e))
202
+ return;
203
+ throw e;
204
+ }
180
205
  if (!bytes) {
181
206
  sendError(res, 404, "not_found.blob", "blob not found");
182
207
  return;
@@ -569,13 +594,46 @@ export async function handleSessionSync(req, res, match, ctx) {
569
594
  }
570
595
  }
571
596
  }
572
- function sendFileHistoryUnreadable(res, e) {
573
- if (!(e instanceof FileHistoryUnreadableError))
574
- return false;
575
- const permanence = e.failure.permanence;
576
- const advice = permanence === "transient" ? "the history store judged the fault transient: retry later" : permanence === "terminal" ? "the history store judged the fault permanent: retrying will not help until the store is repaired" : "the history store did not judge whether retrying can help";
577
- sendError(res, 503, "state.file_history_unreadable", `this session's file history cannot be read whole (${e.failure.code}), so nothing was exported — ${advice}`, permanence === undefined ? undefined : { permanence });
578
- return true;
597
+ function isPullPort(id) {
598
+ switch (id) {
599
+ case "session-sync-manifest":
600
+ case "session-sync-entries":
601
+ case "session-sync-history-blob":
602
+ return true;
603
+ case "session-sync-plan":
604
+ case "session-sync-import":
605
+ case "session-sync-import-entries":
606
+ case "session-sync-blob-put":
607
+ return false;
608
+ default:
609
+ return assertNever(id);
610
+ }
611
+ }
612
+ function sendPullUnreadable(req, res, logger, e) {
613
+ if (e instanceof FileHistoryUnreadableError) {
614
+ const permanence = e.failure.permanence;
615
+ const advice = permanence === "transient" ? "the history store judged the fault transient: retry later" : permanence === "terminal" ? "the history store judged the fault permanent: retrying will not help until the store is repaired" : "the history store did not judge whether retrying can help";
616
+ sendError(res, 503, "state.file_history_unreadable", `this session's file history cannot be read whole (${e.failure.code}), so nothing was exported — ${advice}`, permanence === undefined ? undefined : { permanence });
617
+ return true;
618
+ }
619
+ const fault = storeFaultClassOf(e);
620
+ switch (fault) {
621
+ case "connection":
622
+ logRequestError(logger, req, e);
623
+ sendError(res, 503, "state.file_history_unreadable", "this session's stored state could not be read right now (the store connection failed), so nothing was exported — retry later", { permanence: "transient" });
624
+ return true;
625
+ case "deployment":
626
+ logRequestError(logger, req, e);
627
+ sendError(res, 503, "state.file_history_unreadable", "this session's stored state cannot be read: the store does not match what this deployment requires (a table is missing or the database account lacks a privilege), so nothing was exported — retrying will not help until an operator repairs the store", { permanence: "terminal" });
628
+ return true;
629
+ case "corrupt":
630
+ case "unclassified":
631
+ return false;
632
+ default: {
633
+ const unhandled = fault;
634
+ throw new Error(`store fault class without a session-sync pull-port answer: ${String(unhandled)}`);
635
+ }
636
+ }
579
637
  }
580
638
  function sendMissingBlob(res) {
581
639
  sendError(res, 422, "missing_blob", "missing blob; PUT all referenced blobs before import");
@@ -3,6 +3,7 @@ import { a2aForScenario, mcpForScenario } from "../../web-admin-client/facade.js
3
3
  import { HttpError, isUuidShape, legacyUnownedSessionOk, sessionOwnerCellOf } from "../../security.js";
4
4
  import { windowMessages, truncateMessageBlobs, redactSessionViewForRead } from "../../audit.js";
5
5
  import { redactSecrets } from "../../trace/redact.js";
6
+ import { redactMcpRemoteText } from "../mcp-remote-text.js";
6
7
  import { recordFailOpen } from "../../observability/fail-open.js";
7
8
  import { MCP_DIAL_DEADLINE_MS, raceDeadline } from "../mcp-dial-deadline.js";
8
9
  import { sentMemoryComplianceFailure } from "../memory-compliance-failure-reply.js";
@@ -10,7 +11,7 @@ import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, MAX_SETTINGS_ENV_VARS, MAX_SETTINGS_EN
10
11
  import { readWritableSessionPermissionRules } from "../../session-policy-wire.js";
11
12
  import { sendJson, sendError, sendSessionError, sendSessionPolicyError, sseHeaders, httpErrorBody } from "../send.js";
12
13
  import { fleetViewOf, gatedPrincipal, explicitOperatorOk, sessionCallerOf, sessionOwnerReadable, sendPrincipalRefusal, sendUnauthorized } from "../principal-gate.js";
13
- import { headReadOf, sessionFaceOfHead } from "../../session-incarnation.js";
14
+ import { headReadOf, leafOfAdmittedHead, sessionFaceOfHead } from "../../session-incarnation.js";
14
15
  import { runRowReadableOnSessionFace } from "../owner-access.js";
15
16
  import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
16
17
  import * as facts from "../../capability-facts.js";
@@ -185,7 +186,7 @@ export async function handleSessions(req, res, match, ctx) {
185
186
  status: s.status,
186
187
  ...(s.serverInfo ? { serverInfo: s.serverInfo } : {}),
187
188
  ...(s.toolNames ? { toolNames: s.toolNames } : {}),
188
- ...(s.error ? { error: redactSecrets(String(s.error)).slice(0, 200) } : {}),
189
+ ...(s.error ? { error: redactMcpRemoteText(String(s.error)) } : {}),
189
190
  })),
190
191
  };
191
192
  }
@@ -272,7 +273,7 @@ export async function handleSessions(req, res, match, ctx) {
272
273
  }
273
274
  if (!sessionOwnerOk(req, res, await sessionOwnerCellOf(deps.sessionStorage, headSession, head.owner)))
274
275
  return;
275
- const leafId = head.leafId;
276
+ const leafId = leafOfAdmittedHead(head);
276
277
  const etag = `"${leafId ?? "empty"}"`;
277
278
  if (req.headers["if-none-match"] === etag) {
278
279
  res.writeHead(304, { etag }).end();
@@ -290,7 +291,8 @@ export async function handleSessions(req, res, match, ctx) {
290
291
  sendError(res, 501, "capability.session_store_required", "session events require a durable session store (DB_BACKEND=mysql|pg|local)");
291
292
  return;
292
293
  }
293
- const readOwner = async (id) => (await evFact.sessionStorage.headOf(id))?.owner;
294
+ const readHead = (id) => evFact.sessionStorage.headOf(id);
295
+ const readOwner = async (id) => (await readHead(id))?.owner;
294
296
  const watch = evFact.watch;
295
297
  const evSession = safeDecode(match.params.sessionId);
296
298
  if (evSession === null) {
@@ -326,13 +328,13 @@ export async function handleSessions(req, res, match, ctx) {
326
328
  return;
327
329
  }
328
330
  sse.sseOwnerLookups++;
329
- const cellP = readOwner(evSession).then((o) => (o === undefined ? undefined : sessionOwnerCellOf(evFact.sessionStorage, evSession, o)));
330
- void cellP.catch(() => undefined).then(() => { sse.sseOwnerLookups--; });
331
+ const admissionP = readHead(evSession).then(async (head) => (head === undefined ? undefined : { head, cell: await sessionOwnerCellOf(evFact.sessionStorage, evSession, head.owner) }));
332
+ void admissionP.catch(() => undefined).then(() => { sse.sseOwnerLookups--; });
331
333
  let stallTimer;
332
- let cell;
334
+ let admission;
333
335
  try {
334
- cell = await Promise.race([
335
- cellP,
336
+ admission = await Promise.race([
337
+ admissionP,
336
338
  new Promise((r) => { stallTimer = setTimeout(() => r("__stall__"), stallBound); stallTimer.unref?.(); }),
337
339
  ]);
338
340
  }
@@ -342,22 +344,23 @@ export async function handleSessions(req, res, match, ctx) {
342
344
  }
343
345
  if (closed)
344
346
  return;
345
- if (cell === "__stall__") {
347
+ if (admission === "__stall__") {
346
348
  cleanup();
347
349
  res.setHeader("retry-after", "5");
348
350
  sendError(res, 503, "state.sse_owner_lookup_stalled", "session-events owner lookup stalled — retry");
349
351
  return;
350
352
  }
351
- if (cell === undefined) {
353
+ if (admission === undefined) {
352
354
  cleanup();
353
355
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
354
356
  return;
355
357
  }
356
- if (!sessionOwnerOk(req, res, cell)) {
358
+ if (!sessionOwnerOk(req, res, admission.cell)) {
357
359
  cleanup();
358
360
  return;
359
361
  }
360
- const owner = cell.owner;
362
+ leafOfAdmittedHead(admission.head);
363
+ const owner = admission.cell.owner;
361
364
  const q = new URLSearchParams(match.search);
362
365
  const lastLeafId = q.get("lastLeafId");
363
366
  let first = true;
@@ -656,13 +659,15 @@ export async function handleSessions(req, res, match, ctx) {
656
659
  }
657
660
  const store = rowFact.sessionStorage;
658
661
  const sessionId = match.params.sessionId;
659
- const face = sessionFaceOfHead(sessionId, await store.headOf(sessionId));
660
- if (face === undefined) {
662
+ const head = await store.headOf(sessionId);
663
+ if (head === undefined) {
661
664
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
662
665
  return;
663
666
  }
667
+ const face = sessionFaceOfHead(sessionId, head);
664
668
  if (!sessionOwnerOk(req, res, await sessionOwnerCellOf(store, sessionId, face.owner)))
665
669
  return;
670
+ leafOfAdmittedHead(head);
666
671
  const read = readSessionRowPatch(await readJson(req));
667
672
  if ("problem" in read) {
668
673
  sendError(res, 400, read.problem.code, read.problem.message);
@@ -25,7 +25,7 @@ import { approvalPreambleReplays, createApprovalCardEmitter, declaredApprovalFra
25
25
  import { buildActiveRunConflict, isActiveRunConflictBody, toDoneFrameResult } from "../active-run-conflict.js";
26
26
  import { commitPlacement, devicePlacementErrorBody } from "../device-placement.js";
27
27
  import { commitSessionInheritEnv } from "../session-inherit-env.js";
28
- import { headerStr, gatedPrincipal, explicitOperatorOk } from "../principal-gate.js";
28
+ import { headerStr, gatedPrincipal, explicitOperatorOk, runIdentityOf } from "../principal-gate.js";
29
29
  import { failOpenTagForDroppedFrame, recordFailOpen } from "../../observability/fail-open.js";
30
30
  import { buildSyncSubmitBody } from "../sync-submit-body.js";
31
31
  import { assertNever } from "../route-ctx.js";
@@ -33,6 +33,7 @@ import * as facts from "../../capability-facts.js";
33
33
  import { persistSubmitCtx } from "../submit-ctx.js";
34
34
  import { serviceVersion } from "../../service-version.js";
35
35
  import { withModelReachScope } from "../../model-reach-scope.js";
36
+ import { runSkillsOf } from "../../capabilities/skills.js";
36
37
  import { createInstructionSelectionLeg } from "../../instruction-selection.js";
37
38
  import { fieldConflictFacts } from "../../field-conflict.js";
38
39
  import { refusalBody } from "../refusal-body.js";
@@ -166,6 +167,7 @@ export async function handleTasks(req, res, match, ctx) {
166
167
  const wiringOperatorFace = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config);
167
168
  let wiringReceipt;
168
169
  const instructionLeg = createInstructionSelectionLeg();
170
+ const legWiringSections = () => ({ instructions: instructionLeg.segment(), skills: runSkillsOf(prepared.spec) });
169
171
  const withRunReceipt = (out) => wiringReceipt !== undefined ? { ...out, wiringManifest: wiringReceipt } : out;
170
172
  if (liveStream) {
171
173
  if (prepared.verify || prepared.cascade) {
@@ -298,7 +300,7 @@ export async function handleTasks(req, res, match, ctx) {
298
300
  };
299
301
  if (deps.runStore && prepared.spec.sessionId) {
300
302
  const tid = earlyDurableTid ?? uuidv7();
301
- const created = await deps.runStore.createRun(tid, prepared.spec.sessionId, principal ?? null, deps.instanceId ?? "default", { ...runMeta(prepared, source), idem: idem ?? null });
303
+ const created = await deps.runStore.createRun(tid, prepared.spec.sessionId, principal ?? null, deps.instanceId ?? "default", { ...runMeta(prepared, source), identity: runIdentityOf(req, deps.config, principal ?? null), idem: idem ?? null });
302
304
  if (created.ok)
303
305
  clearTurnActivity(tid);
304
306
  if (created.ok)
@@ -338,7 +340,7 @@ export async function handleTasks(req, res, match, ctx) {
338
340
  if (durableTaskId && deps.runStore) {
339
341
  const rs = deps.runStore;
340
342
  const tid = durableTaskId;
341
- ledgerSink = createLedgerSink({ appendEvent: (seq, type, data) => rs.appendEvent(tid, seq, type, data), persistThinking: deps.config.traceThinking, onActivity: (kind, statusData) => recordTurnActivity(tid, kind, statusData), instructionsSegment: instructionLeg.segment });
343
+ ledgerSink = createLedgerSink({ appendEvent: (seq, type, data) => rs.appendEvent(tid, seq, type, data), persistThinking: deps.config.traceThinking, onActivity: (kind, statusData) => recordTurnActivity(tid, kind, statusData), legSections: legWiringSections });
342
344
  usageKey = tid;
343
345
  deps.modelUsage?.register(tid);
344
346
  const owner = principal ?? null;
@@ -589,7 +591,7 @@ export async function handleTasks(req, res, match, ctx) {
589
591
  sseData(res, { type: "compaction_started", ...compactionStartedEventData(ev) });
590
592
  }
591
593
  else if (ev.type === "wiring_manifest") {
592
- const wiringFace = wiringManifestFaceEventData(ev, wiringOperatorFace, instructionLeg.segment());
594
+ const wiringFace = wiringManifestFaceEventData(ev, wiringOperatorFace, legWiringSections());
593
595
  wiringReceipt ??= wiringFace;
594
596
  sseData(res, { type: "wiring_manifest", ...wiringFace });
595
597
  }
@@ -890,7 +892,7 @@ export async function handleTasks(req, res, match, ctx) {
890
892
  let durableHeartbeat;
891
893
  if (deps.runStore && prepared.spec.sessionId) {
892
894
  const tid = uuidv7();
893
- const created = await deps.runStore.createRun(tid, prepared.spec.sessionId, principal ?? null, deps.instanceId ?? "default", { ...runMeta(prepared, source), idem: idem ?? null });
895
+ const created = await deps.runStore.createRun(tid, prepared.spec.sessionId, principal ?? null, deps.instanceId ?? "default", { ...runMeta(prepared, source), identity: runIdentityOf(req, deps.config, principal ?? null), idem: idem ?? null });
894
896
  if (created.ok)
895
897
  clearTurnActivity(tid);
896
898
  if (created.ok)
@@ -937,7 +939,7 @@ export async function handleTasks(req, res, match, ctx) {
937
939
  const observeSyncLegEvent = (ev) => {
938
940
  if (ev.type !== "wiring_manifest" || wiringReceipt !== undefined)
939
941
  return;
940
- wiringReceipt = wiringManifestFaceEventData(ev, wiringOperatorFace, instructionLeg.segment());
942
+ wiringReceipt = wiringManifestFaceEventData(ev, wiringOperatorFace, legWiringSections());
941
943
  };
942
944
  let result;
943
945
  counters.uncountedBillableInflight++;
@@ -695,6 +695,10 @@ export interface ServiceDeploymentDeps {
695
695
  /** [ref] ②:caps `centerWiring` 的读面(`capabilities/center-wiring.ts` `createCenterWiringReader`;入参 = 请求的已验 principal)。
696
696
  * 缺席 = 没接中心(或测试夹具)⇒ 键整个缺席。 */
697
697
  centerWiring?: (principal: string | undefined) => import("../capabilities/center-wiring.js").CenterWiring;
698
+ /** The member git-credential plane's one reading (`sandbox-git-plane.ts`; stage 5 computes it once — config premises + the boot's secret
699
+ * seat answer + the static patch judge). Caps `credentialPlane.sandboxGit` projects it as is. Absent = not built by the composition root
700
+ * (a fixture) ⇒ the same judge on config alone, the seat counted as not asked. */
701
+ sandboxGitPlane?: import("../sandbox-git-plane.js").SandboxGitPlane;
698
702
  /**
699
703
  * Graceful drain — shared mutable state between main.ts (flips `draining` on SIGTERM) and this server:
700
704
  * • while `draining`, NEW model-running submissions (the billable submit paths) get 503 + Retry-After, so an
@@ -1,7 +1,7 @@
1
1
  /**
2
- * 「这条停驻行的持久化体在本版上能否重放」—— **唯一**判据(三问一只;五个问点同调:续跑驱动段 `resume-legs.ts` `resolveResumeSpecOrBlocked`、
2
+ * 「这条停驻行的持久化体在本版上能否重放」—— **唯一**判据(四问一只;五个问点同调:续跑驱动段 `resume-legs.ts` `resolveResumeSpecOrBlocked`、
3
3
  * plan_review 的 prepare 段、SLA 拒扫腿的跳过臂 `approval-sweeps.ts`、终态 run 的 steer 铸唤醒卡之前 `routes/runs.ts`;`resolveSpec` 本身留作提交腿的拒点)。
4
- * 三问的规则、记号、拒句与删除条件的属主 = `http/checkpoint-ctx.ts` 顶注;答复 = 那里的 `storedBodyReplayAnswer`。
4
+ * 四问的规则、记号、拒句与删除条件的属主 = `http/checkpoint-ctx.ts` 顶注;答复 = 那里的 `storedBodyReplayAnswer`。
5
5
  *
6
6
  * 为什么判据住在这里而不是 `checkpoint-ctx.ts`:第三问要读体的**生效模式词**(`task-settings.ts` `storedBodyPermissionMode`,请求设置的解析层)与本部署此刻的
7
7
  * **入口地板**(`runtime-governance.ts` `autonomyModeFloor`)—— 这两只属主带着配置层的包外依赖;`checkpoint-ctx.ts` 被随包的本地排空脚本经编译产物 import,
@@ -28,7 +28,7 @@ export type StoredReplayDeployment = LaneHomeDeployment & {
28
28
  readonly autonomy?: Autonomy | undefined;
29
29
  };
30
30
  /**
31
- * 三问一只判据:不能重放 ⇒ 返回拒的那条规则;能 ⇒ `undefined`。顺序:allow 读法记号 → 请求设置里的条目表(**与拒点同序**:桶门〔形 / 空串 / 超帽〕→ 工具名清单读成空〔**只问限制方向**:放行方向的存量条目读成空,续跑照旧、只留一行运维 warn〕→ deny / ask 的名字层 + 规则文法)→ 模式词读法记号(几问同中时答先中的那一问 ——
31
+ * 四问一只判据:不能重放 ⇒ 返回拒的那条规则;能 ⇒ `undefined`。顺序:allow 读法记号 → 请求设置里的条目表(**与拒点同序**:桶门〔形 / 空串 / 超帽〕→ 工具名清单读成空〔**只问限制方向**:放行方向的存量条目读成空,续跑照旧、只留一行运维 warn〕→ deny / ask 的名字层 + 规则文法)→ 模式词读法记号 → 体里的退役请求键(几问同中时答先中的那一问 ——
32
32
  * 任一问中都不重放,句子只需一句)。`deployment` = 本部署**此刻**的 `config`(活 config:热改即生效):`autonomy` 的地板由它的唯一属主算,`~/` 形规则的 home 由 `executionLaneHomeDir` 算,问点都不自己算。
33
33
  */
34
34
  export declare function storedBodyReplayRefusal(ctx: CheckpointCtx, deployment: StoredReplayDeployment): StoredBodyReplayRefusal | undefined;
@@ -4,13 +4,15 @@ import { entryProblemsFacts } from "../entry-problems.js";
4
4
  import { autonomyModeFloor, entryPermissionMode } from "../runtime-governance.js";
5
5
  import { inertToolListEntryOf, replayInertEntry } from "../rule-entry-list.js";
6
6
  import { executionLaneHomeDir } from "../execution-lane-caps.js";
7
- import { allowListReadingEraOf, allowListReadingUnstated, permissionModeReadingStated } from "./checkpoint-ctx.js";
7
+ import { migrationWindowEnd } from "../plugins/one-time-migrations.js";
8
+ import { allowListReadingEraOf, allowListReadingUnstated, permissionModeReadingStated, retiredRequestKeyOf } from "./checkpoint-ctx.js";
8
9
  export function permissionModeReadingUnstated(ctx, floor) {
9
10
  if (floor === undefined || permissionModeReadingStated(ctx))
10
11
  return undefined;
11
12
  const stored = storedBodyPermissionMode(ctx.body);
12
13
  return entryPermissionMode(stored, floor).effective === stored ? undefined : { stored, floor };
13
14
  }
15
+ const RETIRED_KEY_REWRITE_MIGRATION = { promptProfile: "M30" };
14
16
  const BUCKET_GATE_CODE = "request.field_invalid";
15
17
  function storedPermissions(body) {
16
18
  const permissions = body?.settings?.permissions;
@@ -52,6 +54,9 @@ export function storedBodyReplayRefusal(ctx, deployment) {
52
54
  const mode = permissionModeReadingUnstated(ctx, autonomyModeFloor(deployment.autonomy));
53
55
  if (mode !== undefined)
54
56
  return { kind: "permission_mode_reading", ...mode, ...writer };
57
+ const retiredKey = retiredRequestKeyOf(ctx.body);
58
+ if (retiredKey !== undefined)
59
+ return { kind: "retired_request_key", key: retiredKey, rewriteWindowEnd: migrationWindowEnd(RETIRED_KEY_REWRITE_MIGRATION[retiredKey]), ...writer };
55
60
  return undefined;
56
61
  }
57
62
  //# sourceMappingURL=stored-body-replay.js.map
@@ -8,7 +8,7 @@ function unsealableRefusal(e) {
8
8
  status: 409,
9
9
  body: refusalBody({
10
10
  errorCode: "conflict.checkpoint_ctx_unsealable",
11
- message: "this deployment cannot store this task's credentials (MCP / A2A headers or env values, settings.env, settings.webSearch.apiKey, http hook headers, or command hook plugin options) for resuming it: they are kept only sealed, and this server has no sealed-key store — nothing was run; ask whoever operates this deployment to give the service a writable sealed-key directory (<data root>/sealed-key/), or submit the task without those credentials",
11
+ message: "this deployment cannot store this task's credentials (static request headers, the command lines and environment values given to MCP stdio servers and command hooks, settings.env, or settings.webSearch.apiKey) for resuming it: they are kept only sealed, and this server has no sealed-key store — nothing was run; ask whoever operates this deployment to give the service a writable sealed-key directory (<data root>/sealed-key/), or submit the task without those credentials",
12
12
  facts: { field: e.field, reason: e.reason },
13
13
  }),
14
14
  };
@@ -11,6 +11,31 @@ import type { RequestMcpServerSpec } from "../mcp-assertion-header.js";
11
11
  import type { wiringManifestFaceEventData } from "../trace/project.js";
12
12
  import type { buildSyncSubmitBody } from "./sync-submit-body.js";
13
13
  import type { EntryProblem } from "../entry-problems.js";
14
+ /**
15
+ * 请求面上的一条技能 = core 的 `SkillSpec` 去掉 `mods`(core 7.56.0 [ref] 的技能座扩展注册:带 `register` 函数的代码对象,不是 wire 数据)。
16
+ * 带 `mods` 的请求技能受理门 400(`http/admission.ts` 的 `validateUserSkills`);本服务不编技能 hooks(能力位 `mods.skill_seat` 恒假)。
17
+ * 键集仍由 core 本体派生([ref]:core 加键,本型同批跟上;删 `mods` 是唯一的一处减法)。
18
+ */
19
+ export type RequestSkill = Omit<SkillSpec, "mods">;
20
+ /**
21
+ * `TaskRequestBody.attachments` 的子键集。本类型是这十个键在导出类型面上的**唯一**声明处;受理门(`http/admission.ts`)与重放翻译口
22
+ * (`spec-fields.ts` 的 `normalizeAttachments`)读 `spec-fields.ts` 的 `ATTACHMENT_KEY_KINDS` 那一张表,表与本接口互为差集门
23
+ * (`_GuardAttachmentKeys*`,漏一边 ⇒ tsc 红)。加 / 删一个键:本接口、那张表、`normalizeAttachments` 的逐键赋值三处同批改。
24
+ */
25
+ export interface TaskRequestAttachments {
26
+ todoReminder?: boolean;
27
+ todoReminderMode?: "baseline" | "off";
28
+ changedFiles?: boolean | {
29
+ maxFiles?: number;
30
+ };
31
+ budgetUsd?: true;
32
+ backgroundTasks?: boolean;
33
+ toolsDelta?: boolean;
34
+ mcpInstructions?: true;
35
+ agentListing?: boolean;
36
+ skillsListing?: boolean;
37
+ mcpUnavailable?: boolean;
38
+ }
14
39
  export interface TaskRequestBody {
15
40
  objective: string;
16
41
  sessionId?: string;
@@ -114,20 +139,20 @@ export interface TaskRequestBody {
114
139
  jobId?: string;
115
140
  /** Personalization seam: the caller's OWN skills for this task, threaded into core's
116
141
  * `TaskSpec.skills`. Merged AFTER the scenario's skills with SCENARIO-WINS on a name clash (the security
117
- * baseline can never be shadowed by user content — see mergeUserSkills). User skills are user-authored
142
+ * baseline can never be shadowed by user content — see buildRunSkills). User skills are user-authored
118
143
  * content in the user's OWN principal-isolated task (self-harm surface, not privilege widening);
119
144
  * scenario/center skills remain the only trusted layer.
120
145
  *
121
146
  * 🔴 **类型 = core 的 `SkillSpec` 本体,不是它的手抄子集**([ref]):这里曾写死
122
147
  * `{ name; description; content }` —— core 闭集六位里的三位,而 `manifest` / `files` / `baseDir`
123
- * 三位在运行期一直是**收的**(受理门 `validateUserSkills` 不判未知键,`mergeUserSkills` 原样透传到
148
+ * 三位在运行期一直是**收的**(受理门 `validateUserSkills` 不判未知键,`buildRunSkills` 原样透传到
124
149
  * `TaskSpec.skills`)。一份会漂的手抄 = 声明面比真受理面**窄**,SDK 消费方按声明写代码就以为发不了,
125
150
  * 而 core 加键(7.20.0 [ref] 的 `baseDir`)时这里连红都不会红。改成 core 本体后,闭集由 tsc 看守。
126
151
  * ⚠️ 受理**判据**(形/尺寸)仍在 `validateUserSkills` + `spec-fields.ts` 的 `SKILL_FIELD_SHAPES`——
127
152
  * 类型说「哪些键存在」,门说「值合不合法」,两者不是一件事。
128
153
  * (旧注里的「Caps: ≤10 skills, content ≤32KB each」两条帽早已随 [ref] / core 1.293 退役,一并纠正:
129
154
  * 今天只剩 `content ≤ 1 MiB` 这一条 core 加载门孪生。) */
130
- skills?: SkillSpec[];
155
+ skills?: RequestSkill[];
131
156
  /** §7 P0.5 (用户按需选像): the sandbox image PROFILE this task wants (e.g.
132
157
  * "code-full" / "code-python"). An INTENT, never a digest — the service resolves it to a published digest with
133
158
  * the caller's principal (fail-closed visibility re-admit) and applies it per-pod. Only supported on the k8s
@@ -247,19 +272,7 @@ export interface TaskRequestBody {
247
272
  * boolean 透传(core DEFAULT-ON,explicit false 才关);budgetUsd/mcpInstructions 只认 literal true;
248
273
  * limits 三个 opt-out 只认 literal false(normalizer 同判)。 */
249
274
  /** core 7.39.0 [ref]:`planModeReminder` 退役(硬破坏,零别名)—— 提交即 400 点名退役;plan 姿态由引擎从 `permissionMode:"plan"` 自己陈述。 */
250
- attachments?: {
251
- todoReminder?: boolean;
252
- todoReminderMode?: "baseline" | "off";
253
- changedFiles?: boolean | {
254
- maxFiles?: number;
255
- };
256
- budgetUsd?: true;
257
- backgroundTasks?: boolean;
258
- toolsDelta?: boolean;
259
- mcpInstructions?: true;
260
- agentListing?: boolean;
261
- skillsListing?: boolean;
262
- };
275
+ attachments?: TaskRequestAttachments;
263
276
  /** C1 (core 1.219, subagent viewing pane): opt-in — forward a delegated child's live CONTENT events
264
277
  * (text_delta/text_end/reasoning_delta/tool_start/tool_end, each stamped `parentToolCallId`) onto this run's stream/durable
265
278
  * log, so a shell can render the child's transcript live ("enter 看详情"). Default OFF = progress-only (prior
@@ -337,9 +350,13 @@ export interface TaskRequestBody {
337
350
  /** [ref]② (core 1.314): [ref] 延迟披露清单(占位上 wire,ToolSearch 激活)——cli「Workflow 默认开
338
351
  * 不暴露」的承载位。同 excludeTools 的校验/继承姿势。 */
339
352
  deferTools?: string[];
340
- /** [ref]/[ref] (core 1.328 R2): 提示词双形轴——simple(CC 212 短形,引擎缺省)| classic(长形,可按
341
- * 任务/模型试分)。纯呈现轴无租户门;枚举 fail-loud at submit;缺省不挂键。 */
342
- promptProfile?: "simple" | "classic";
353
+ /** core 7.56.0([ref]):提示词形的**唯一**任务开关 —— `true` 加 `lean_prompt` 特征(短形)、`false` 去掉它(长的 classic 形)、
354
+ * 缺省 = 模型目录条目自己的声明(引擎缺省 lean)。只动这一个特征,不碰其余特征;原样透传进 `TaskSpec.promptLean`,随引擎铸的每个子代走。
355
+ * 纯呈现轴无租户门;非布尔 400 fail-loud at submit;缺省不挂键。
356
+ * 退役键 `promptProfile`(7.136.x 及以前的 `"simple" | "classic"`)整键删、零别名:fresh 提交体仍带它 ⇒ 键闭集门 400 `request.body_shape`
357
+ * (`unknownKeys:["promptProfile"]`);迁移 = `"classic"` ⇒ `promptLean: false`,`"simple"` ⇒ 不带键。续跑重放不过那道门:盘上 7.136.x 体里的旧键由一次性迁移 M30 在起服时按同一张映射原地改写(`stored-request-prompt-profile-m30.ts`;M30 · 窗口见 `plugins/one-time-migrations.ts` 登记表),
358
+ * 改写不到的残留行续跑 409(`http/stored-body-replay.ts` 第四问)—— 续跑腿不读旧键。 */
359
+ promptLean?: boolean;
343
360
  /** [ref]②(core 5.14.0 座已在,`TaskSpec.toolMaterializeStrategy`):deferred 工具在**激活之后**怎么给
344
361
  * 模型供 schema。`static` = 占位符形不变(激活只改可调用性,广告的 schema 仍是空对象);`swap` = 激活
345
362
  * 后下一轮把占位符换成真 schema。
@@ -352,7 +369,7 @@ export interface TaskRequestBody {
352
369
  * core 把 `"static"` 重新定性为「a strict explicit opt-in」)。本注上一版还写着 `?? "static"`,照它推
353
370
  * 「不挂键 ⇒ 落 static」会反。缺省词的属主是 core,本仓不复述第二份——要确认取值去读 core 的
354
371
  * `prepare-task` 与其 CHANGELOG。
355
- * 缺省不挂键(交给 core 的 env/缺省链);未知词 400 fail-loud(与 promptProfile/permissionMode 同姿势 ——
372
+ * 缺省不挂键(交给 core 的 env/缺省链);未知词 400 fail-loud(与 permissionMode 同姿势 ——
356
373
  * 静默折缺省会让调用方以为切了策略却没切)。 */
357
374
  toolMaterializeStrategy?: "static" | "swap";
358
375
  /** R4 (CC parity): the LIGHT top-level per-turn permission-mode intent (CC `permissionMode`). The shell sends
@@ -363,7 +380,7 @@ export interface TaskRequestBody {
363
380
  * `deniedBy:"mode"`); none can subtract from deployment/operator policy or the request's own deny / ask rules (tightenTaskSpec
364
381
  * deny-wins). The top-level word wins over `settings.permissions.defaultMode` (the heavier bundle) — one precedence, read in one place.
365
382
  * [ref]-②: CLOSED enum on the wire — an unknown word 400s at submit (`request.field_invalid`, sibling of
366
- * promptProfile) instead of silently coercing to `default`; resume replay of a stored body stays lenient
383
+ * toolMaterializeStrategy) instead of silently coercing to `default`; resume replay of a stored body stays lenient
367
384
  * (coercePermissionMode).
368
385
  * 🔴 型与闭集的属主是 core 的 `PermissionMode` / `PERMISSION_MODES`(受理腿 `isPermissionMode` 与三句 400 文案同读那一份)—— 本仓不持词表。 */
369
386
  permissionMode?: PermissionMode;
@@ -432,7 +449,7 @@ export interface TaskRequestBody {
432
449
  cwd?: string;
433
450
  /**
434
451
  * [ref](7.106.0,core [ref] [ref] ②)—— 模型驱动的 host shell **继承多少用户环境**,由调用方按请求声明。
435
- * 闭集两词(词表外 ⇒ 400 `request.field_invalid`,两腿同判,判据属主 `request-value-closure.ts` 的 `inheritEnvFieldIssue`):
452
+ * 闭集两词(词表外 ⇒ 400 `request.field_invalid` + 机读位 `field: "inheritEnv"` / `reason`〔`unknown_word` | `not_a_string`〕,两腿同判,判据与机读位的属主 `request-value-closure.ts` 的 `inheritEnvFieldIssue`):
436
453
  * · `"all"` —— 整份用户环境**减本服务自有凭据名**(配置目录 secret 名 / 名单型旋钮名 / 模型条目 `apiKeyEnv`,起服向引擎声明一次,判在引擎;7.129.0 起,CC 交互形);只在**单用户**部署兑现,射程 = 写容纳面那一只
437
454
  * 部署形表行 `taskHostPostureDeclarations`(`deployment-shape.ts`)⇒ 托管部署(`REQUIRE_PRINCIPAL=true`)响亮拒
438
455
  * 422 `request.host_posture_refused`;
@@ -440,7 +457,7 @@ export interface TaskRequestBody {
440
457
  * **缺席 = 缺省清洗**:不带键的请求把本会话的绑定清掉(不继承上一条请求的声明 —— 这一位是「本条请求要什么」,
441
458
  * 粘到下一条上就是替一个没说话的请求放宽)。名单形(`string[]`)**不上 wire**(那是嵌入方构造执行环境的选项)。
442
459
  * 🔒 **只有 host 车道有消费点**:别的车道(e2b / k8s / local-docker / ssh / adb / device / in-process)带 `"all"` ⇒
443
- * 400 `request.field_invalid`「applies to the host lane only」,不静默忽略、不映射到别的车道的 env 名单;`"scrub"` 在那些车道上照受理(无消费点,无害)。
460
+ * 400 `request.field_invalid`(`reason: lane_not_host`)「applies to the host lane only」,不静默忽略、不映射到别的车道的 env 名单;`"scrub"` 在那些车道上照受理(无消费点,无害)。
444
461
  * Rides the persisted body onto resume legs:重放照射程与车道重判(部署由单用户改托管后 revive ⇒ 同一只拒,
445
462
  * resume-legs 折成 `409 resume_blocked_by_policy`)。
446
463
  */
@@ -541,12 +558,14 @@ export interface TaskRequestBody {
541
558
  * 声明被接收、server 照常挂载但不带断言头,并有一行运维 info `mcp_assertion_header_not_sent { server }`;发送随引擎座。 */
542
559
  mcpServers?: RequestMcpServerSpec[];
543
560
  /** [DESIGN-269 车1] Caller-supplied per-request A2A peers (remote agents this task may call), aligned to
544
- * core `A2aServerSpec`. 🔒 honored on a SINGLE-USER deployment that has neither locked the `a2a` key nor
545
- * had `a2a_peers` denied by its compliance posture (task-a2a.ts `a2aInjectionHonored`, the same three-veto
561
+ * core `A2aServerSpec`. 🔒 honored on a SINGLE-USER deployment (task-a2a.ts `a2aInjectionHonored`, the same
546
562
  * predicate `capabilities.a2aInjection` advertises) — the requester is the super-admin of their OWN worker,
547
563
  * on ANY execution lane (an A2A call is a plain outbound HTTPS request from the worker, so the lane where
548
564
  * tool calls run is irrelevant); IGNORED on multi-tenant (a tenant can't point the shared worker at an
549
- * agent of their choosing). A locked deployment refuses the whole request instead: 400 `config.locked_key`.
565
+ * agent of their choosing). A2A has no operator lock and no compliance capability today. A new submission
566
+ * with a malformed list or entry is refused 400 (`assertRequestA2aEntries`: not an array / over the 32-entry
567
+ * cap / an entry that is not an object / a key outside {@link A2A_PEER_ENTRY_KEYS} / a key whose value is
568
+ * unusable / a url or cardUrl carrying a credential) — the same refusal shape as `mcpServers`, whatever the lane.
550
569
  * 🔴 Every skill a peer advertises mounts `egress:true` + `effect:"write"` (core's ruling) — declaring a
551
570
  * peer is declaring an outbound WRITE channel, not a data source. Validated + gated downstream; the
552
571
  * center/config baseline wins on a name clash (the peer name IS the tool namespace). */
@@ -584,12 +603,20 @@ export type DecideBinding = {
584
603
  * mints carry it verbatim when present — the engine owns what counts as written (blank = nothing) and judges it again pre-CAS. */
585
604
  feedback?: string;
586
605
  };
587
- /** [ref]([ref]④→[ref] 坐标轮换判定):409 `approval_stale` 拒体上的 additive 机读指路 ——
606
+ /** 409 `approval_stale` 拒体的 additive 机读指路 `currentPending`:**本会话此刻在这道门上待决的那道门**的回显坐标 = 这道门的决断体回显的那几位
607
+ * (一条规则,两道决断门各一形):`/decide` ⇒ {@link DecideStaleCurrentPending};计划审阅([ref])⇒ {@link PlanReviewStaleCurrentPending}。
608
+ * 🔴 恒**不含** checkpointToken(resume 凭证从不外发);只在当前门在场、属这道门的门型、且已过属主门的域内铸 —— 否则键缺席(不造键)。 */
609
+ export type ApprovalStaleCurrentPending = DecideStaleCurrentPending | PlanReviewStaleCurrentPending;
610
+ /** [ref]:计划审阅门的回显坐标 = 门身份 `checkpointId`(过信任边界的那个值;当前门说不出身份 ⇒ 整个 `currentPending` 缺席)。 */
611
+ export type PlanReviewStaleCurrentPending = {
612
+ /** 当前待决 plan_review 门的非秘密身份 —— 壳据此重取那道门的计划给人看,再带它决。 */
613
+ checkpointId: string;
614
+ };
615
+ /** [ref]([ref]④→[ref] 坐标轮换判定):`/decide` 那一形 ——
588
616
  * **本会话当前 pending** 的 D-1 回显坐标,让持旧坐标的壳一跳重定位(免重拉列表)。
589
617
  * 键名/键形与 GET /v1/approvals 的 pending 行逐字同名(壳复用同一解析)。
590
- * 🔴 恒**不含** checkpointToken(runs.ts §12-C:resume 凭证从不外发);只在当前 pending **在场**、
591
- * 属 tool_approval、且已过路由级 owner 门的域内铸 —— 无 pending / 非工具门 / 读失败 ⇒ 键缺席(不造键)。 */
592
- export type ApprovalStaleCurrentPending = {
618
+ * 只在当前 pending 属 tool_approval 时铸 —— 无 pending / 非工具门 / 读失败 ⇒ 键缺席(不造键)。 */
619
+ export type DecideStaleCurrentPending = {
593
620
  /** 当前 pending 被门住的工具名(与 pending 行的 `toolName` 同源同值)。 */
594
621
  toolName: string;
595
622
  /** 当前 pending 的 `pendingAction.toolCallId` —— 壳重定位后 decide 时回显的 D-1 锚。 */