@sema-agent/server 7.148.0 → 7.150.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 (360) hide show
  1. package/MIGRATION.md +551 -9
  2. package/README.md +17 -2
  3. package/README.zh-CN.md +5 -1
  4. package/USAGE.md +126 -68
  5. package/dist/adoption/wire.d.ts +3 -3
  6. package/dist/approval-card.d.ts +33 -33
  7. package/dist/approval-gate-currency.d.ts +1 -1
  8. package/dist/approval-leg-origin.d.ts +33 -0
  9. package/dist/approval-leg-origin.js +4 -0
  10. package/dist/audit.d.ts +1 -1
  11. package/dist/audit.js +2 -2
  12. package/dist/auth-bridge.d.ts +9 -1
  13. package/dist/auth-bridge.js +4 -4
  14. package/dist/auth-keys.d.ts +10 -1
  15. package/dist/auth-keys.js +8 -0
  16. package/dist/background-session-reap.d.ts +1 -1
  17. package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
  18. package/dist/boot/deferred-sandbox-path-env.js +1 -2
  19. package/dist/boot/execution-env.js +10 -11
  20. package/dist/boot/execution-lane.d.ts +6 -4
  21. package/dist/boot/execution-lane.js +3 -1
  22. package/dist/boot/org-delivery.d.ts +3 -2
  23. package/dist/boot/parked-revive-gate.d.ts +5 -5
  24. package/dist/boot/parked-revive-gate.js +2 -3
  25. package/dist/boot/resolve-spec.d.ts +4 -5
  26. package/dist/boot/resolve-spec.js +66 -28
  27. package/dist/boot/retention-lane.d.ts +1 -1
  28. package/dist/boot/runner-deps.js +3 -1
  29. package/dist/boot/session-faces.js +21 -21
  30. package/dist/boot/stage-01-config.d.ts +1 -0
  31. package/dist/boot/stage-01-config.js +4 -3
  32. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
  33. package/dist/boot/stage-02-web-admin-pull.js +10 -2
  34. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  35. package/dist/boot/stage-03-store-backend.js +4 -4
  36. package/dist/boot/stage-04-stores.d.ts +1 -0
  37. package/dist/boot/stage-05-execution-env.d.ts +1 -0
  38. package/dist/boot/stage-06-runners.d.ts +2 -1
  39. package/dist/boot/stage-06-runners.js +1 -2
  40. package/dist/boot/stage-07-capability-layer.d.ts +2 -1
  41. package/dist/boot/stage-07-capability-layer.js +1 -1
  42. package/dist/boot/stage-08-reapers.d.ts +2 -1
  43. package/dist/boot/stage-09-leader.d.ts +2 -1
  44. package/dist/boot/stage-10-http-server.d.ts +35 -2
  45. package/dist/boot/stage-10-http-server.js +9 -4
  46. package/dist/boot/stores.d.ts +3 -0
  47. package/dist/boot/stores.js +22 -19
  48. package/dist/boot/web-admin.d.ts +1 -1
  49. package/dist/capabilities/tool-defer.d.ts +1 -1
  50. package/dist/capability-facts.d.ts +70 -60
  51. package/dist/capability-facts.js +45 -49
  52. package/dist/card-settle-stored-scope.d.ts +56 -0
  53. package/dist/card-settle-stored-scope.js +27 -0
  54. package/dist/card-void.d.ts +7 -12
  55. package/dist/card-void.js +2 -7
  56. package/dist/config-catalog.d.ts +12 -0
  57. package/dist/config-catalog.js +37 -33
  58. package/dist/config-invariants.d.ts +5 -4
  59. package/dist/config-invariants.js +4 -4
  60. package/dist/config-types.d.ts +49 -16
  61. package/dist/config.d.ts +6 -5
  62. package/dist/config.js +35 -24
  63. package/dist/context-window-notice.d.ts +31 -0
  64. package/dist/context-window-notice.js +28 -0
  65. package/dist/deployment-governance.d.ts +7 -28
  66. package/dist/deployment-governance.js +1 -14
  67. package/dist/deployment-shape.d.ts +20 -11
  68. package/dist/deployment-shape.js +1 -0
  69. package/dist/device-ws-hub.d.ts +1 -0
  70. package/dist/device-ws-hub.js +64 -28
  71. package/dist/device-ws-protocol.d.ts +20 -6
  72. package/dist/device-ws-protocol.js +9 -2
  73. package/dist/engine-identity.d.ts +7 -1
  74. package/dist/engine-identity.js +5 -0
  75. package/dist/env-name-allowlist-knobs.d.ts +6 -5
  76. package/dist/env-name-allowlist-knobs.js +5 -0
  77. package/dist/execution-lane-caps.d.ts +20 -5
  78. package/dist/execution-lane-caps.js +18 -4
  79. package/dist/field-conflict.d.ts +2 -2
  80. package/dist/fleet/engine-signal.d.ts +14 -1
  81. package/dist/fleet/engine-signal.js +5 -1
  82. package/dist/fleet/fleet-reconciler.d.ts +1 -1
  83. package/dist/fleet/serving-lease.d.ts +18 -3
  84. package/dist/fleet/serving-lease.js +81 -35
  85. package/dist/fleet-client.d.ts +13 -11
  86. package/dist/fleet-client.js +53 -33
  87. package/dist/history-anchor.js +1 -1
  88. package/dist/hitl-delivery.d.ts +1 -3
  89. package/dist/hitl-delivery.js +1 -1
  90. package/dist/hooks/command-spawn.d.ts +7 -2
  91. package/dist/hooks/command-spawn.js +13 -6
  92. package/dist/hooks/hook-runner.d.ts +5 -0
  93. package/dist/hooks/hook-runner.js +11 -7
  94. package/dist/http/active-run-conflict.d.ts +3 -7
  95. package/dist/http/active-run-conflict.js +2 -2
  96. package/dist/http/admission.js +5 -5
  97. package/dist/http/approval-sweeps.js +5 -3
  98. package/dist/http/caller-trust.d.ts +2 -2
  99. package/dist/http/caller-trust.js +3 -3
  100. package/dist/http/checkpoint-ctx.d.ts +18 -63
  101. package/dist/http/checkpoint-ctx.js +1 -24
  102. package/dist/http/claim-heartbeat.d.ts +6 -6
  103. package/dist/http/claim-heartbeat.js +6 -6
  104. package/dist/http/claimed-run.d.ts +16 -9
  105. package/dist/http/claimed-run.js +8 -0
  106. package/dist/http/dispatch.js +7 -5
  107. package/dist/http/durable-run-leg.d.ts +8 -1
  108. package/dist/http/durable-run-leg.js +34 -15
  109. package/dist/http/execution-context.d.ts +115 -14
  110. package/dist/http/execution-context.js +130 -40
  111. package/dist/http/owner-access.d.ts +246 -21
  112. package/dist/http/owner-access.js +186 -8
  113. package/dist/http/principal-gate.d.ts +18 -11
  114. package/dist/http/principal-gate.js +3 -1
  115. package/dist/http/readiness.d.ts +4 -2
  116. package/dist/http/resume-ctx-read.d.ts +14 -3
  117. package/dist/http/resume-ctx-read.js +24 -3
  118. package/dist/http/resume-legs.d.ts +35 -3
  119. package/dist/http/resume-legs.js +262 -106
  120. package/dist/http/route-ctx.d.ts +29 -11
  121. package/dist/http/routes/a2a-serve.js +17 -14
  122. package/dist/http/routes/approvals-assistant.d.ts +3 -2
  123. package/dist/http/routes/approvals-assistant.js +11 -11
  124. package/dist/http/routes/capabilities.js +5 -4
  125. package/dist/http/routes/config-catalog.d.ts +1 -1
  126. package/dist/http/routes/diagnostics.d.ts +3 -1
  127. package/dist/http/routes/diagnostics.js +30 -5
  128. package/dist/http/routes/mcp-reconnect.js +2 -2
  129. package/dist/http/routes/memory-origin.d.ts +1 -1
  130. package/dist/http/routes/notify-wake.js +2 -3
  131. package/dist/http/routes/principal-inbox.d.ts +3 -1
  132. package/dist/http/routes/principal-inbox.js +3 -2
  133. package/dist/http/routes/projects.d.ts +1 -0
  134. package/dist/http/routes/projects.js +5 -3
  135. package/dist/http/routes/retention-ops.d.ts +1 -1
  136. package/dist/http/routes/run-permission-mode.d.ts +1 -1
  137. package/dist/http/routes/run-permission-mode.js +2 -2
  138. package/dist/http/routes/runs.d.ts +1 -1
  139. package/dist/http/routes/runs.js +33 -37
  140. package/dist/http/routes/session-memory-sync.js +4 -5
  141. package/dist/http/routes/session-sync.d.ts +24 -5
  142. package/dist/http/routes/session-sync.js +45 -37
  143. package/dist/http/routes/sessions-list.d.ts +1 -1
  144. package/dist/http/routes/sessions.d.ts +1 -1
  145. package/dist/http/routes/sessions.js +18 -44
  146. package/dist/http/routes/tasks.js +136 -101
  147. package/dist/http/routes/trace-usage.js +14 -14
  148. package/dist/http/routes/workflows.d.ts +1 -0
  149. package/dist/http/routes/workflows.js +20 -38
  150. package/dist/http/server.d.ts +12 -9
  151. package/dist/http/server.js +35 -6
  152. package/dist/http/stored-body-replay.d.ts +3 -24
  153. package/dist/http/stored-body-replay.js +2 -12
  154. package/dist/http/submit-ctx.d.ts +2 -2
  155. package/dist/http/submit-ctx.js +5 -5
  156. package/dist/http/submit-replay.d.ts +15 -2
  157. package/dist/http/submit-replay.js +10 -4
  158. package/dist/http/wire-types.d.ts +6 -3
  159. package/dist/index.d.ts +3 -1
  160. package/dist/index.js +1 -0
  161. package/dist/leader/endpoint.js +9 -8
  162. package/dist/leg-facts.d.ts +13 -2
  163. package/dist/leg-facts.js +2 -0
  164. package/dist/local-store-declaration.d.ts +54 -0
  165. package/dist/local-store-declaration.js +59 -0
  166. package/dist/mcp-assertion-header.d.ts +1 -1
  167. package/dist/mcp-assertion-header.js +1 -1
  168. package/dist/mcp-authorization-face.d.ts +18 -14
  169. package/dist/mcp-authorization-face.js +3 -2
  170. package/dist/memory-project-layer.js +1 -1
  171. package/dist/memory-scope.d.ts +4 -4
  172. package/dist/memory-scope.js +4 -4
  173. package/dist/memory-store-refusal.d.ts +1 -1
  174. package/dist/memory-sync-client.js +2 -2
  175. package/dist/model-context-window.d.ts +50 -11
  176. package/dist/model-context-window.js +20 -1
  177. package/dist/model-entry-refusal.d.ts +5 -4
  178. package/dist/model-entry-refusal.js +17 -3
  179. package/dist/model-reach-scope.d.ts +2 -1
  180. package/dist/observability/corrupt-read-seat.d.ts +1 -1
  181. package/dist/observability/fail-open.d.ts +19 -7
  182. package/dist/observability/fail-open.js +19 -7
  183. package/dist/observability/logger.d.ts +7 -0
  184. package/dist/observability/logger.js +3 -1
  185. package/dist/observability/metrics.js +1 -1
  186. package/dist/observability/run-terminal.d.ts +1 -1
  187. package/dist/observability/run-terminal.js +1 -0
  188. package/dist/observability/secret-env-scrub.d.ts +1 -1
  189. package/dist/observability/secret-env-scrub.js +1 -1
  190. package/dist/org-delivery-gate.d.ts +31 -6
  191. package/dist/org-delivery-gate.js +7 -4
  192. package/dist/owner-faces.d.ts +30 -5
  193. package/dist/owner-faces.js +2 -0
  194. package/dist/park-row-commit.d.ts +67 -0
  195. package/dist/park-row-commit.js +76 -0
  196. package/dist/parked-decide.d.ts +9 -7
  197. package/dist/parked-decide.js +25 -6
  198. package/dist/peer-directory.d.ts +1 -1
  199. package/dist/peer-seat.d.ts +1 -1
  200. package/dist/peer-seat.js +52 -59
  201. package/dist/plugins/adoption-log-sql.d.ts +3 -3
  202. package/dist/plugins/adoption-log-sql.js +19 -19
  203. package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
  204. package/dist/plugins/approval-ask-store-sql.js +3 -5
  205. package/dist/plugins/approval-exemption-skill-cutoff.d.ts +64 -0
  206. package/dist/plugins/approval-exemption-skill-cutoff.js +122 -0
  207. package/dist/plugins/approval-exemption-skill-m46.d.ts +0 -6
  208. package/dist/plugins/approval-exemption-skill-m46.js +6 -10
  209. package/dist/plugins/approval-exemption-store.d.ts +26 -1
  210. package/dist/plugins/approval-exemption-store.js +28 -19
  211. package/dist/plugins/ensure-schema-lock-policy.d.ts +36 -3
  212. package/dist/plugins/ensure-schema-lock-policy.js +75 -9
  213. package/dist/plugins/exec-path-law.d.ts +34 -0
  214. package/dist/plugins/exec-path-law.js +13 -0
  215. package/dist/plugins/file-run-store.d.ts +22 -9
  216. package/dist/plugins/file-run-store.js +51 -23
  217. package/dist/plugins/local-checkpoint-store.d.ts +8 -1
  218. package/dist/plugins/local-checkpoint-store.js +5 -1
  219. package/dist/plugins/local-data-root-admission.d.ts +52 -0
  220. package/dist/plugins/local-data-root-admission.js +100 -0
  221. package/dist/plugins/local-engine-high-water.d.ts +28 -7
  222. package/dist/plugins/local-engine-high-water.js +27 -22
  223. package/dist/plugins/local-session-store.d.ts +134 -49
  224. package/dist/plugins/local-session-store.js +149 -108
  225. package/dist/plugins/memory-run-store.d.ts +14 -9
  226. package/dist/plugins/memory-run-store.js +48 -22
  227. package/dist/plugins/one-time-migration-marker.d.ts +19 -3
  228. package/dist/plugins/one-time-migration-marker.js +7 -1
  229. package/dist/plugins/one-time-migrations.d.ts +110 -59
  230. package/dist/plugins/one-time-migrations.js +224 -136
  231. package/dist/plugins/org-delivery-quota-store.d.ts +34 -11
  232. package/dist/plugins/org-delivery-quota-store.js +29 -14
  233. package/dist/plugins/permission-rule-store-sql.d.ts +1 -1
  234. package/dist/plugins/permission-rule-store-sql.js +5 -9
  235. package/dist/plugins/pg-pool.d.ts +1 -1
  236. package/dist/plugins/pg-pool.js +14 -12
  237. package/dist/plugins/posix-shell-fs.js +4 -2
  238. package/dist/plugins/remote-env-adb.js +3 -2
  239. package/dist/plugins/remote-env-device.d.ts +3 -2
  240. package/dist/plugins/remote-env-device.js +8 -6
  241. package/dist/plugins/remote-env-e2b.d.ts +4 -8
  242. package/dist/plugins/remote-env-e2b.js +21 -15
  243. package/dist/plugins/remote-env-host.d.ts +51 -10
  244. package/dist/plugins/remote-env-host.js +97 -31
  245. package/dist/plugins/remote-env-k8s.js +7 -4
  246. package/dist/plugins/remote-env-local-docker.d.ts +6 -3
  247. package/dist/plugins/remote-env-local-docker.js +11 -25
  248. package/dist/plugins/remote-env-ssh.js +4 -3
  249. package/dist/plugins/remote-shell.d.ts +3 -1
  250. package/dist/plugins/remote-shell.js +3 -3
  251. package/dist/plugins/replica-registration.d.ts +35 -0
  252. package/dist/plugins/replica-registration.js +48 -0
  253. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  254. package/dist/plugins/run-store-sql.d.ts +27 -8
  255. package/dist/plugins/run-store-sql.js +46 -18
  256. package/dist/plugins/scenario-prefix-switch-m42.d.ts +8 -12
  257. package/dist/plugins/scenario-prefix-switch-m42.js +9 -6
  258. package/dist/plugins/schema-consistency.d.ts +91 -5
  259. package/dist/plugins/schema-consistency.js +189 -7
  260. package/dist/plugins/schema-drift-sentence.d.ts +6 -5
  261. package/dist/plugins/schema-drift-sentence.js +13 -5
  262. package/dist/plugins/serving-requirement.d.ts +49 -0
  263. package/dist/plugins/serving-requirement.js +53 -0
  264. package/dist/plugins/session-placement.d.ts +5 -4
  265. package/dist/plugins/shell-sentinel-owner-m48.d.ts +22 -0
  266. package/dist/plugins/shell-sentinel-owner-m48.js +6 -0
  267. package/dist/plugins/stop-then-start-sentence.d.ts +55 -0
  268. package/dist/plugins/stop-then-start-sentence.js +51 -0
  269. package/dist/plugins/store-backend.d.ts +23 -9
  270. package/dist/plugins/store-backend.js +58 -24
  271. package/dist/plugins/store-contracts.d.ts +45 -5
  272. package/dist/plugins/store-contracts.js +19 -0
  273. package/dist/plugins/tidb-pool.d.ts +11 -6
  274. package/dist/plugins/tidb-pool.js +22 -12
  275. package/dist/plugins/workspace-custody.d.ts +44 -0
  276. package/dist/plugins/workspace-custody.js +47 -0
  277. package/dist/process-instance.d.ts +3 -0
  278. package/dist/process-instance.js +7 -0
  279. package/dist/project-context.d.ts +66 -0
  280. package/dist/project-context.js +70 -0
  281. package/dist/project-identity.d.ts +8 -7
  282. package/dist/project-identity.js +40 -17
  283. package/dist/project-layer-key.d.ts +13 -2
  284. package/dist/project-layer-key.js +9 -1
  285. package/dist/question.d.ts +9 -21
  286. package/dist/question.js +28 -19
  287. package/dist/read-deny-floor-notice.d.ts +36 -0
  288. package/dist/read-deny-floor-notice.js +40 -0
  289. package/dist/{plain-string-record.d.ts → request-declaration-disposition.d.ts} +9 -23
  290. package/dist/request-declaration-disposition.js +39 -0
  291. package/dist/run-cancel-card.d.ts +28 -0
  292. package/dist/run-cancel-card.js +20 -0
  293. package/dist/run-cancel-context.d.ts +10 -0
  294. package/dist/run-cancel-context.js +1 -0
  295. package/dist/run-local.js +28 -13
  296. package/dist/runs.d.ts +31 -7
  297. package/dist/runs.js +34 -16
  298. package/dist/security.d.ts +3 -3
  299. package/dist/server-secret-env.d.ts +34 -20
  300. package/dist/server-secret-env.js +61 -18
  301. package/dist/session-agent.d.ts +4 -12
  302. package/dist/session-agent.js +0 -6
  303. package/dist/session-children-retire.d.ts +6 -3
  304. package/dist/session-children-retire.js +2 -5
  305. package/dist/session-incarnation.d.ts +18 -4
  306. package/dist/session-incarnation.js +4 -1
  307. package/dist/session-notify-door.d.ts +4 -4
  308. package/dist/session-notify-door.js +5 -6
  309. package/dist/session-rules-seat.d.ts +4 -3
  310. package/dist/session-rules-seat.js +3 -11
  311. package/dist/session-sync.js +3 -3
  312. package/dist/session-workspace.d.ts +3 -3
  313. package/dist/store-admission.d.ts +33 -0
  314. package/dist/store-admission.js +49 -0
  315. package/dist/store-posture.d.ts +5 -0
  316. package/dist/store-posture.js +18 -1
  317. package/dist/stores-sql/checkpoint-store-sql.d.ts +22 -3
  318. package/dist/stores-sql/checkpoint-store-sql.js +109 -23
  319. package/dist/stores-sql/file-history-store-sql.d.ts +1 -1
  320. package/dist/stores-sql/file-history-store-sql.js +3 -5
  321. package/dist/stores-sql/retention-store-sql.d.ts +1 -1
  322. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  323. package/dist/stores-sql/tool-result-store-sql.js +4 -6
  324. package/dist/task-a2a.d.ts +3 -8
  325. package/dist/task-a2a.js +25 -27
  326. package/dist/task-cwd.d.ts +27 -10
  327. package/dist/task-cwd.js +3 -0
  328. package/dist/task-mcp.d.ts +3 -3
  329. package/dist/task-mcp.js +1 -1
  330. package/dist/task-settings.d.ts +13 -0
  331. package/dist/task-settings.js +14 -7
  332. package/dist/terminal.d.ts +2 -0
  333. package/dist/terminal.js +21 -6
  334. package/dist/tool-approval.d.ts +50 -41
  335. package/dist/tool-approval.js +96 -73
  336. package/dist/trace/engine-notice-wire.d.ts +38 -21
  337. package/dist/trace/engine-notice-wire.js +25 -4
  338. package/dist/trace/ledger-sink.d.ts +3 -1
  339. package/dist/trace/project.d.ts +8 -5
  340. package/dist/trace/project.js +11 -9
  341. package/dist/trace/projection-table.d.ts +33 -2
  342. package/dist/trace/redact.d.ts +12 -0
  343. package/dist/trace/redact.js +5 -1
  344. package/dist/trace/self-minted-wire.d.ts +268 -56
  345. package/dist/trace/self-minted-wire.js +110 -40
  346. package/dist/trace/tool-card.d.ts +3 -0
  347. package/dist/trace/tool-card.js +24 -0
  348. package/dist/trace/tool-output-media.d.ts +2 -1
  349. package/dist/unattended-permission-mode.d.ts +1 -1
  350. package/dist/web-admin-client/apply-effective.d.ts +1 -1
  351. package/dist/web-admin-client/apply-effective.js +22 -9
  352. package/dist/web-admin-client/effective-keys.d.ts +1 -1
  353. package/dist/web-admin-client/skills-mcp.d.ts +1 -1
  354. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -29
  355. package/docs/error-text-lexicon.json +317 -0
  356. package/package.json +4 -2
  357. package/scripts/embed-minimal.mjs +183 -0
  358. package/wire-changes/server@7.149.0.json +372 -0
  359. package/wire-changes/server@7.150.0.json +335 -0
  360. package/dist/plain-string-record.js +0 -70
@@ -5,24 +5,38 @@ import { recheckClaimBeforeLaunch, refusalAfterLostClaim, startClaimHeartbeat }
5
5
  import { heldFor } from "../peer-seat.js";
6
6
  import { fleetRunPublisher, fleetRunLabels, nameFleetRowOnDelivery } from "../fleet/fleet-bus.js";
7
7
  import { cascadeConfig, fillRunPreviewOnDelivery, runMeta } from "./run-meta.js";
8
+ import { approvalLegOriginOf } from "../approval-leg-origin.js";
8
9
  import { declaredApprovalFrameFamilies, resolveStreamApprovalGate } from "../tool-approval.js";
9
10
  import { buildActiveRunConflict } from "./active-run-conflict.js";
10
- import { commitExecutionContext } from "./execution-context.js";
11
+ import { commitExecutionContext, faultedAnswerOf } from "./execution-context.js";
11
12
  import { rootSessionAbsentAnswer } from "./execution-context.js";
12
13
  import { timeClaim } from "./claim-latency.js";
13
14
  import { commitSessionInheritEnv } from "./session-inherit-env.js";
14
15
  import { clearTurnActivity, readTurnActivityMs } from "../turn-activity.js";
15
16
  import { recordResourceWindow } from "../resource-window.js";
16
17
  import { persistSubmissionCtx, SUBMIT_CTX_CLAIM_LOST } from "./submit-ctx.js";
17
- import { releaseClaimedRun } from "./claimed-run.js";
18
- import { headReadOf } from "../session-incarnation.js";
18
+ import { withdrawClaimedRun } from "./claimed-run.js";
19
+ import { sessionFactsReadOf } from "./owner-access.js";
19
20
  import { createSessionWorkspaceRecorder, sessionWorkspaceStoreOf } from "../session-workspace.js";
20
21
  export async function mintAndDriveDurableRun(ctx, runStore, args) {
21
22
  const { deps } = ctx;
22
- const { inflightRuns, preemptableRuns, steerableRuns } = ctx.registry;
23
23
  const sessionId = args.prepared.spec.sessionId;
24
24
  const taskId = args.clientTaskId ?? uuidv7();
25
25
  const trustedInternals = await heldWorkflowParkDecisions(deps, sessionId, args.workflowDecision?.carried);
26
+ let legId;
27
+ try {
28
+ const claimed = await claimAndCommit(ctx, runStore, args, sessionId, taskId);
29
+ if (!("holdingLeg" in claimed))
30
+ return claimed;
31
+ legId = claimed.holdingLeg;
32
+ }
33
+ catch (e) {
34
+ return faultedAnswerOf(e, args.face.faulted);
35
+ }
36
+ return launchDurableRun(ctx, runStore, args, sessionId, taskId, trustedInternals, legId);
37
+ }
38
+ async function claimAndCommit(ctx, runStore, args, sessionId, taskId) {
39
+ const { deps } = ctx;
26
40
  const created = await timeClaim(deps.metrics, "run_claim", runStore.createRun(taskId, sessionId, args.prepared.auth?.subject ?? null, deps.instanceId ?? "default", { ...runMeta(args.prepared, args.source), identity: args.identity, idem: args.idem ?? null }));
27
41
  if (created.ok)
28
42
  clearTurnActivity(taskId);
@@ -40,11 +54,11 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
40
54
  const owner = args.prepared.auth?.subject ?? null;
41
55
  const stopPreLaunchHeartbeat = startClaimHeartbeat(runStore, taskId, owner, deps.metrics);
42
56
  try {
43
- const placementReject = await commitExecutionContext(deps, { kind: "run", runStore, taskId }, args.prepared.execution);
57
+ const placementReject = await commitExecutionContext(deps, { kind: "run", runStore, taskId, legId: created.legId }, args.prepared.execution);
44
58
  if (placementReject)
45
- return placementReject;
59
+ return args.face.refused(placementReject);
46
60
  if (deps.checkpointStore) {
47
- const ctxRefusal = await persistSubmissionCtx(deps.checkpointStore, deps, { runStore, taskId }, args.prepared);
61
+ const ctxRefusal = await persistSubmissionCtx(deps.checkpointStore, deps, { runStore, taskId, legId: created.legId }, args.prepared);
48
62
  if (ctxRefusal === SUBMIT_CTX_CLAIM_LOST)
49
63
  return await refusalAfterLostClaim(deps, runStore, sessionId, taskId);
50
64
  if (ctxRefusal)
@@ -55,13 +69,13 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
55
69
  await args.workflowDecision.commitBeforeLaunch(taskId);
56
70
  }
57
71
  catch (err) {
58
- await releaseClaimedRun(runStore, taskId, `the workflow decision this run delivers could not be recorded: ${err instanceof Error ? err.message : String(err)}`, (releaseErr, step) => {
72
+ await withdrawClaimedRun(runStore, taskId, created.legId, (releaseErr, step) => {
59
73
  deps.logger?.warn?.("workflow_decision_run_release_failed", { taskId, sessionId, step, err: releaseErr instanceof Error ? releaseErr.message : String(releaseErr) });
60
74
  });
61
75
  throw err;
62
76
  }
63
77
  }
64
- const lostClaim = await recheckClaimBeforeLaunch(deps, runStore, sessionId, taskId);
78
+ const lostClaim = await recheckClaimBeforeLaunch(deps, runStore, sessionId, taskId, created.legId);
65
79
  if (lostClaim !== undefined)
66
80
  return lostClaim;
67
81
  }
@@ -69,11 +83,16 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
69
83
  stopPreLaunchHeartbeat();
70
84
  }
71
85
  commitSessionInheritEnv(deps, args.prepared.spec.sessionId, args.prepared.body);
86
+ return { holdingLeg: created.legId };
87
+ }
88
+ function launchDurableRun(ctx, runStore, args, sessionId, taskId, trustedInternals, legId) {
89
+ const { deps } = ctx;
90
+ const { inflightRuns, preemptableRuns, steerableRuns } = ctx.registry;
72
91
  const anchorOwner = args.prepared.auth?.subject ?? null;
73
- const headOf = headReadOf(deps.sessionStorage);
74
- const captureTurnAnchor = deps.resumeAnchorStore && headOf
92
+ const sessionFactsOf = sessionFactsReadOf(deps.sessionStorage);
93
+ const captureTurnAnchor = deps.resumeAnchorStore && sessionFactsOf
75
94
  ? async (eventId) => {
76
- const leaf = (await headOf(sessionId))?.leafId;
95
+ const leaf = (await sessionFactsOf(sessionId))?.leafId;
77
96
  if (leaf)
78
97
  await deps.resumeAnchorStore.put(sessionId, eventId, leaf, anchorOwner);
79
98
  }
@@ -89,7 +108,7 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
89
108
  ...fleetRunLabels(args.prepared.acceptance.objectiveAtSubmit),
90
109
  });
91
110
  nameFleetRowOnDelivery(args.prepared.acceptance, fleetPub);
92
- void heldFor(args.prepared.peerLease, () => runInBackground(args.prepared.runner, args.prepared.spec, runStore, taskId, deps.metrics, args.prepared.auth?.subject, args.prepared.verify, args.prepared.cascade ? cascadeConfig(deps.config.cascadeLadder, args.prepared.spec.limits?.maxCostUsd) : undefined, deps.instrumentDegenerate, deps.planCacheProbe, deps.config.traceThinking, inflightRuns, preemptableRuns, steerableRuns, deps.modelUsage, deps.elicitation, args.elicitOwner, captureTurnAnchor, fleetPub, captureUserMessageAnchor, deps.question, deps.workflowCompletionInbox, deps.subagentSteerRegistry, (m, x) => deps.logger?.info?.(m, x), deps.sendUserFile, deps.promptManifests, deps.toolApproval
111
+ void heldFor(args.prepared.peerLease, () => runInBackground(args.prepared.runner, args.prepared.spec, runStore, taskId, { legId, runStaleSec: deps.config.runStaleSec }, deps.metrics, args.prepared.auth?.subject, args.prepared.verify, args.prepared.cascade ? cascadeConfig(deps.config.cascadeLadder, args.prepared.spec.limits?.maxCostUsd) : undefined, deps.instrumentDegenerate, deps.planCacheProbe, deps.config.traceThinking, inflightRuns, preemptableRuns, steerableRuns, deps.modelUsage, deps.elicitation, args.elicitOwner, captureTurnAnchor, fleetPub, captureUserMessageAnchor, deps.question, deps.workflowCompletionInbox, deps.subagentSteerRegistry, (m, x) => deps.logger?.info?.(m, x), deps.sendUserFile, deps.promptManifests, deps.toolApproval
93
112
  ? {
94
113
  coordinator: deps.toolApproval,
95
114
  streamApprovalOn: resolveStreamApprovalGate({
@@ -101,9 +120,9 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
101
120
  windowMs: deps.config.streamApproval?.windowMs,
102
121
  windowMarginMs: deps.config.streamAskWindowMarginMs,
103
122
  declaredFamilies: declaredApprovalFrameFamilies(args.prepared.body.settings),
104
- executionLane: args.prepared.execution.lane,
123
+ origin: approvalLegOriginOf(args.prepared.execution),
105
124
  }
106
- : undefined, deps.checkpointStore, args.prepared.engineNotices, trustedInternals, deps.userInputLedger, args.prepared.acceptance, createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), args.prepared.legFacts?.sessionWitness), args.prepared.legFacts?.skills));
125
+ : undefined, deps.checkpointStore, args.prepared.engineNotices, trustedInternals, deps.userInputLedger, args.prepared.acceptance, createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), args.prepared.legFacts?.sessionWitness), args.prepared.legFacts?.skills, args.prepared.legFacts?.registeredCwd));
107
126
  args.runSlot?.release();
108
127
  args.prepared.seat.markRecord();
109
128
  return { status: 202, body: { taskId, sessionId, status: "running", ...(args.prepared.warnings !== undefined ? { warnings: args.prepared.warnings } : {}) } };
@@ -1,5 +1,6 @@
1
1
  import type { IncomingMessage } from "node:http";
2
2
  import type { SessionHead, TaskSpec } from "@sema-agent/core";
3
+ import { HttpError } from "../security.js";
3
4
  import { type DeviceOwner, type DeviceStore } from "../device-store.js";
4
5
  import { type DeviceEnrollment, type DeviceRejection } from "../device-enrollment.js";
5
6
  import type { ServiceConfig } from "../config.js";
@@ -123,19 +124,30 @@ export type RootedTaskSpec = TaskSpec & {
123
124
  * 走到这里只能是擦型或 JS 形;拒在建任何行之前)。续跑家族照它自己的折叠律把这只拒答成 409 `resume_blocked_by_policy`(`blockedBy` = 这只码,
124
125
  * `http/resume-legs.ts` 的 `resolveResumeSpecOrBlocked`:装配期的每一只 `HttpError` 在续跑腿上都这么折),同样什么都没续。
125
126
  *
126
- * **根「必须已在」的唯一写者也是这里**(`requireExistingSession`;装配器不写它):根是宿主的 ⇒ 引擎取会话时不许「缺行即建」——
127
- * 解析器步 ① 读到过这一行(`occupant` 在场),或调用方自己要求了它(`requireExistingSession: true`;店不带执行席时这是唯一的来源)⇒ 盖 `true`:
128
- * 门与引擎取会话之间这一行被删(属主删除 / 受理前拒的撤回),引擎答 `resume.session_not_found`,不在原 id 上重建一只无主的空根。
129
- * **例外只有一条,来自引擎的派生形**:`cascade: true` 的提交不盖 —— 引擎派生每一级时只删 `sessionId`、其余字段照展开,带着这一位的级就成了
130
- * 「没有会话 id 却要求会话已在」,被引擎拒掉(每一级都跑不起来)。引擎把这一位随 `sessionId` 一并剥掉之后,cascade 也盖,这一条例外删去。
131
- * 没读到行、调用方也没要求 ⇒ 不盖(与引擎缺省同:没有宿主见过的根可护)。
127
+ * **根「必须已在」(`requireExistingSession`)的唯一写者也是这里**(装配器不写它),按调用方交来的 {@link RootUse} 穷举 —— 用法由**选引擎入口的那条腿**交
128
+ * (受理漏斗:与它交给提交腿的 `cascade` 同一个值;续跑重建:`session`;续跑的梯子臂:`ladder_host`),不从提交体再读一遍:
129
+ * · `session` —— 它是引擎在根上取会话时的「只接、不建」:解析器步 ① 读到过这一行(`occupant` 在场),或调用方自己要求了它(`requireExistingSession: true`;
130
+ * 店不带执行席时这是唯一的来源)⇒ 盖 `true`:门与引擎取会话之间这一行被删(属主删除 / 受理前拒的撤回),引擎答 `resume.session_not_found`,不在原 id 上重建一只
131
+ * 无主的空根;没读到行、调用方也没要求 ⇒ 不盖(只加不减:装配器交来的那一位原样留着);
132
+ * · `ladder_host` —— 引擎在梯子上不取根,没有可盖的取会话 ⇒ 盖出的 spec 上**没有**这一位(交来的 spec 带着也剥掉:续跑的梯子臂从重建的那一份再盖);
133
+ * 根在不在、门后被删由宿主判 —— 受理口的属主门(调用方要求了它而行不在 ⇒ 404)与执行起点的认领(带 run 店的部署:根行锁之后判在不在 / 放置提交判行在 ⇒ 404)。
132
134
  */
133
135
  export declare function stampSpecRoot(spec: ResolvedTaskSpec, ctx: ExecutionRoot, submission: SpecRootSubmission): RootedTaskSpec;
134
- /** {@link stampSpecRoot} 读的那两位提交事实(受理漏斗交这次的体;续跑家族交 checkpoint 上存的那一份体)。 */
135
- export interface SpecRootSubmission {
136
- readonly cascade?: unknown;
136
+ /**
137
+ * 引擎拿这次提交的根做什么(闭集;{@link stampSpecRoot} 按它穷举 —— 加一种用法 ⇒ 那只 `switch` 编译红):
138
+ * · `session` —— 引擎在根上取会话跑(单腿;验证门的实现腿与修复腿;续跑家族 —— 续跑、wake、宿主会话上新铸的一跑);
139
+ * · `ladder_host` —— 根是梯子的宿主(`cascade: true` 的组合入口):每一级在引擎为它现铸的会话里冷跑,引擎不取根;根只是这条梯子停驻卡的归属(组合腿的 `hostSessionId`)。
140
+ */
141
+ export type RootUse = "session" | "ladder_host";
142
+ /**
143
+ * {@link stampSpecRoot} 的第三参:选引擎入口的那条腿交来的用法;调用方「根必须已在」的要求只属于 `session` 用法(梯子上它由宿主的门与认领判,型上没有这一键)。
144
+ */
145
+ export type SpecRootSubmission = {
146
+ readonly use: "session";
137
147
  readonly requireExistingSession?: unknown;
138
- }
148
+ } | {
149
+ readonly use: "ladder_host";
150
+ };
139
151
  /**
140
152
  * run 店建行时根会话行已经不在(`CreateRunOutcome.sessionAbsent`:受理之后、认领之前会话被删)的**唯一**答复 ——
141
153
  * 四个建行点(同步 / 流式 / durable / wake)、解析期的「行不在 / 住客换了」与提交期的 `gone` 同答 404 `resume.session_not_found`,什么都没建、什么都没跑。
@@ -150,19 +162,100 @@ export interface ExecutionRefusal {
150
162
  readonly body: RefusalBody;
151
163
  }
152
164
  /**
153
- * 本次认领 —— 提交拒时要释放的东西。`run` = 四个建行点与续跑家族认领的 run 行(释放 = 终结 + 放认领 + 放幂等键,唯一写法 `releaseClaimedRun`);
154
- * `parked` = 停驻赎回的认领(释放 = 回滚认领;「会话不在」答那条腿既有的 `decide.not_parked`,不是提交腿的 404)。
165
+ * 本次认领 —— 提交没放行时要撤回的东西。撤回只有一张表({@link withdrawClaim}),按认领种类把认领撤回到**它取来时的样子**:
166
+ * · `run` = 本请求铸的行(四个建行点 / wake 的现建行 / workflow 决定在宿主会话上的新一跑;`legId` = 建行交回的持有腿):取来之前没有这一行 ⇒ 每一种收场都删掉它
167
+ * (唯一写法 `withdrawClaimedRun`:只认本腿持有的那一行,行仍在跑才删,认领与幂等键随行去;已被收割 / 终局 ⇒ 零删)—— 同一个 `taskId` / 同一把幂等键的重发是一次新提交;
168
+ * · `resumed` = 续跑家族 `markResuming` 认领的停驻行:取来之前它停在等一张待决的卡 ⇒ 放回停驻(`restore`:认领方的写法 = 停驻的唯一提交点 `park-row-commit.ts` 的 `commitParkRow`;
169
+ * 认领与幂等键留着,卡仍待决,同一个决定可以再发;认领窗里落下的取消由认领方按取消收场 —— 停驻态会让下一次认领重置取消旗)。
170
+ * 唯一的例外是 `gone`:店答出这条 run 的会话已经不在,它再也续不了 ⇒ 终结(同 `run` 那一只写法);
171
+ * · `parked` = 停驻赎回的认领:每一种收场都回滚认领。
172
+ * 答复不在认领上:写口交回店的拒答,各面经自己的 {@link ClaimFace} 答它。
155
173
  */
156
174
  export type ExecutionClaim = {
157
175
  readonly kind: "run";
158
176
  readonly runStore: RunStore;
159
177
  readonly taskId: string;
178
+ readonly legId: string;
179
+ } | {
180
+ readonly kind: "resumed";
181
+ readonly runStore: RunStore;
182
+ readonly taskId: string;
183
+ readonly restore: () => Promise<void>;
160
184
  } | {
161
185
  readonly kind: "parked";
162
186
  readonly taskId: string;
163
187
  readonly rollback: (why: string) => Promise<unknown>;
164
- readonly goneAnswer: ExecutionRefusal;
165
188
  };
189
+ /**
190
+ * 认领之后、交给引擎之前那一段没放行的收场 —— **唯一**的类别判定。规则一句:**店答出的拒是答案,店的故障不是**。判在 {@link commitExecutionContext} 的两只出口上
191
+ * (结构判:交回拒答 vs 抛,不读错误文案);续跑腿「提交放行之后、交给引擎之前」那一段的抛同属 `faulted`(`resume-legs.ts`,经同一张撤回表):
192
+ * · `gone` —— 店答出这条会话已经不在(行没了 / 住客换了,{@link isRootSessionGoneRefusal}):确定的答案,这条会话上什么都再也续不了;
193
+ * · `refused` —— 店答出这条会话此刻不能在本处执行(已放在别的车道、写者在别处、设备拒):确定的答案,但会话还在 —— 与认领之前解析器读出同一个事实是同一个命运;
194
+ * · `faulted` —— 店没答出来(故障 / 超时 / 程序错):证不出这条会话不能执行,不当答案用。答复只看(这一面 × 店有没有答出来):各面的瞬时答复({@link faultedAnswerOf}),
195
+ * 本服务自己的程序错照旧响亮 500。
196
+ */
197
+ export type CommitEnding = "gone" | "refused" | "faulted";
198
+ /**
199
+ * 提交点的拒答是不是「会话不在」那一只({@link rootSessionAbsentAnswer};唯一读者 —— 撤回表据它分 `gone` / `refused`,续跑家族与停驻赎回的 {@link ClaimFace} 据它决定那一只拒怎么答)。
200
+ * 只认这一只答复的码(与 {@link isRootSessionGoneError} 同一个判据,一个读拒答、一个读解析器的抛)。
201
+ */
202
+ export declare function isRootSessionGoneRefusal(refusal: ExecutionRefusal): boolean;
203
+ /**
204
+ * `faulted` 那一形的答复 —— 认领这一段(认领那一笔、认领之后的提交、续跑腿交给引擎之前的店往返、新提交起跑之前的店写)的一抛**只在这里**分两种:
205
+ * 店没答出来(判官的 `corrupt` / `connection` / `deployment` / `unclassified`)⇒ 这一面的瞬时答复(`answer`:新提交 {@link runStoreUnavailableAnswer} · 续跑家族
206
+ * `resume-ctx-read.ts` 的 `resumeClaimFaultAnswer` · 停驻赎回 `decide.store_unreachable`;每一面与它认领那一笔撞店故障同答);本服务自己的程序错(`defect`)⇒ 原样上抛,响亮成 500。
207
+ * 两种都不改撤回:认领已按 `faulted` 撤回(调用方在调本函数之前撤,或写口在抛之前撤)。判官加词而这里不表态 = 编译错。
208
+ * 设备注册簿那一次往返(设备店 / 准入链)也只经这里读:店没答出来 ⇒ 设备闭集的 {@link registryUnavailable},认领之前的准入与认领之后的首绑 / 再断言同答。
209
+ */
210
+ export declare function faultedAnswerOf<A>(e: unknown, answer: () => A): A;
211
+ /**
212
+ * 新提交(`POST /v1/tasks` 两腿、`POST /v1/runs` 与 A2A)撞店故障的**唯一**答复({@link SUBMISSION_CLAIM_FACE} 的 `faulted`)—— 503 `state.run_store_unavailable`:
213
+ * 认领之前那一次执行席读、认领那一笔(`createRun`)、认领之后的执行放置、续跑输入的写或起跑之前的认领复核,有一次店往返没答出来;本请求铸的行已撤回(删掉,认领与幂等键随行去),
214
+ * 什么都没起跑。稍后原样再发(同一个自带 `taskId` 也行);一直如此 ⇒ 请运维查库。句子不带店层 detail。🔴 形是给冻结门看的:`status: <三位数>, body: refusalBody({ errorCode: "<码>", message: "<整句双引号字面>"`,中间只许有空白。
215
+ */
216
+ export declare function runStoreUnavailableAnswer(): {
217
+ status: 503;
218
+ body: RefusalBody;
219
+ };
220
+ /**
221
+ * **一面的两只答法**(规则一句见文件头「一面一只答法」):这一面在认领之前那一读(解析器)、认领那一笔、认领之后每一笔、交给引擎之前的店往返上,
222
+ * 店答出的拒与店的故障各怎么答 —— 每一面只声明一次,各调用点只经它答,不各自选码:
223
+ * · `refused` —— 写口交回的店的拒答(会话不在 / 本处此刻不能执行)在这一面的答复:与这一面认领之前解析器读出同一个事实同一只答;
224
+ * · `faulted` —— 店没答出来在这一面的瞬时答复(经 {@link faultedAnswerOf} 读;本服务的程序错照旧上抛)。
225
+ * 三面:{@link SUBMISSION_CLAIM_FACE}(新提交)· {@link CONTINUATION_CLAIM_FACE}(续跑家族:决断 / `/resume` / `plan_review` / `/wake` / `/decide` 在宿主会话上起的新一跑)·
226
+ * 停驻赎回(`parked-decide.ts` 的 `parkedRedeemFace`,按子代句柄铸)。
227
+ */
228
+ export interface ClaimFace {
229
+ readonly refused: (refusal: ExecutionRefusal) => ExecutionRefusal;
230
+ readonly faulted: () => ExecutionRefusal;
231
+ }
232
+ /** 新提交这一面:店答出的拒原样答(认领之前解析器那一只 typed 拒同码同体);店没答出来 ⇒ {@link runStoreUnavailableAnswer}。 */
233
+ export declare const SUBMISSION_CLAIM_FACE: ClaimFace;
234
+ /**
235
+ * 续跑家族这一面:会话不在({@link isRootSessionGoneRefusal})⇒ 原答 404 `resume.session_not_found`;其余店答出的拒 ⇒ {@link cardWaitingRefusalAnswer}(与认领之前同一只折法);
236
+ * 店没答出来 ⇒ `resume-ctx-read.ts` 的 `resumeClaimFaultAnswer`(503 `state.resume_context_unreadable`,卡仍待决)。
237
+ */
238
+ export declare const CONTINUATION_CLAIM_FACE: ClaimFace;
239
+ /**
240
+ * 一只拒在「有一张卡仍在等」的那几面上的答复(续跑家族与停驻赎回;认领之前的解析器拒与认领之后写口交回的拒同经这里)—— 认领之前那一只折法
241
+ * (`checkpoint-ctx.ts` 的 `resumeAssemblyRefusalAnswer`:409 `resume_blocked_by_policy`,`blockedBy` = 原码,原事实随体;自报瞬时的拒原码原状态)+ `retriable`(卡仍待决)。
242
+ */
243
+ export declare function cardWaitingRefusalAnswer(refusal: ExecutionRefusal): ExecutionRefusal;
244
+ /** 一只拒答 → typed 拒(`HttpError`;体经 `httpErrorRefusal` 读回同一份:码、句、机读事实)。解析器的拒与提交门认领之前的拒只认这一种载体。 */
245
+ export declare function refusalHttpError(refusal: ExecutionRefusal): HttpError;
246
+ /**
247
+ * **认领之前那一读**在一面上的唯一读法(提交门 / 续跑家族的重建 / 停驻赎回同调唯一的解析器 {@link resolveExecutionContext}):解析器的拒(typed `HttpError`)是答案,
248
+ * 原样上抛给这一面自己的折法;店没答出来 ⇒ 抛这一面的瞬时答复(`face.faulted`,载体 {@link refusalHttpError} 外套 {@link ClaimFaultAnswer} —— 与这一面认领那一笔撞店故障同答,
249
+ * 续跑家族的折叠口认它、不折);本服务的程序错原样上抛(响亮 500)。认领之前没有认领可撤,状态零改动。
250
+ */
251
+ export declare function resolveBeforeClaim(deps: ExecutionContextDeps, entry: Extract<ExecutionEntry, {
252
+ readonly root: string;
253
+ }>, face: ClaimFace): Promise<RootedExecutionContext>;
254
+ /** {@link resolveBeforeClaim} 抛出的「店没答出来」答复(typed 拒;`answer` = 这一面的瞬时答复原体)。只有折叠口要认它(续跑家族不把它折成 409);提交门按 typed 拒原样答。 */
255
+ export declare class ClaimFaultAnswer extends HttpError {
256
+ readonly answer: ExecutionRefusal;
257
+ constructor(answer: ExecutionRefusal);
258
+ }
166
259
  /** {@link commitExecutionContext} 的依赖 —— 逐字取自 `ServiceDeps` 的同名键(同一只 deps 对象喂进来)。 */
167
260
  export interface ExecutionCommitDeps {
168
261
  readonly sessionStorage?: {
@@ -189,10 +282,18 @@ export declare function placementWriteDeadlineMs(runStaleSec: number | undefined
189
282
  export declare function devicePlacementErrorBody(rej: DeviceRejection): RefusalBody;
190
283
  /**
191
284
  * **认领之后的唯一写口**(四个 `createRun` 点、续跑家族 `markResuming` 之后、停驻赎回 `claimParkedAgent` 之后)。返回 `null` = 放行;
192
- * 否则本次认领已释放,调用方交回拒答。店故障 / 超时 ⇒ 释放后原样上抛(响亮,不当答案);设备意图那一支的注册簿故障答 {@link registryUnavailable}(设备闭集,同准入阶段)。
285
+ * 否则本次认领已按 {@link withdrawClaim} 撤回(店答出的拒 = `gone` / `refused`),调用方交回拒答。店故障 / 超时 ⇒ 认领按 `faulted` 撤回后原样上抛
286
+ * (响亮,不当答案:各调用方经 {@link faultedAnswerOf} 落自己这一面的瞬时码);设备意图那一支的注册簿往返(首绑 / 再断言)撞故障 ⇒ 交回设备闭集的 {@link registryUnavailable}
287
+ * (经 {@link faultedAnswerOf},与认领之前的准入同一只读法;程序错照旧上抛),执行席那一读撞故障与认领之前那一读同答(上抛)。
193
288
  *
194
289
  * 不变量(一句):**离开本函数的那一刻,这条会话(解析器那一位住客)的格就是这条执行的车道(device 车道:准入批准的那台设备);否则本次认领已释放、调用方拿到拒答。**
195
290
  * 它不说「此后不变」:认领持有期间根行住客与放置不被换绑 / 导入改动,那是各写者写事务内锁根行后读认领的保证(规则句),不在本函数重复判。
196
291
  */
197
292
  export declare function commitExecutionContext(deps: ExecutionCommitDeps, claim: ExecutionClaim, ctx: RootedExecutionContext): Promise<ExecutionRefusal | null>;
293
+ /**
294
+ * **撤回本次认领的唯一一张表**(规则与各种类的落点见 {@link ExecutionClaim};类别见 {@link CommitEnding})。两个调用处:{@link commitExecutionContext} 的两只出口,
295
+ * 与续跑腿「提交放行之后、交给引擎之前」那一段的抛(`resume-legs.ts`,`faulted`)。`ending` 只在 `resumed` 上分叉(会话不在 ⇒ 终结;其余 ⇒ 放回停驻),另两种认领取来时就只有一个去处。
296
+ * 认领之后的其余几笔(续跑输入、决定落行、起跑之前的复核)撤本请求铸的行用 `run` 那一臂的同一只写法(`withdrawClaimedRun`)。
297
+ */
298
+ export declare function withdrawClaim(deps: ExecutionCommitDeps, claim: ExecutionClaim, why: string, ending: CommitEnding): Promise<void>;
198
299
  //# sourceMappingURL=execution-context.d.ts.map
@@ -3,13 +3,16 @@ import { HttpError, createCodedHttpError, ssoVerifiedScope } from "../security.j
3
3
  import { gatedPerson } from "./principal-gate.js";
4
4
  import { DEVICE_ERROR_CODES, assertDeviceIdShape } from "../device-store.js";
5
5
  import { buildDeviceRejection } from "../device-enrollment.js";
6
- import { sameOccupant } from "../execution-placement.js";
6
+ import { SessionForkInProgressError, sameOccupant } from "../execution-placement.js";
7
7
  import { deployedExecutionLanes } from "../execution-lane-caps.js";
8
8
  import { gateExecutionLane } from "../runtime-caps-resolver.js";
9
- import { releaseClaimedRun } from "./claimed-run.js";
9
+ import { releaseClaimedRun, withdrawClaimedRun } from "./claimed-run.js";
10
10
  import { sessionIdRetiredFor } from "../deleted-session-ids.js";
11
11
  import { refusalBody } from "./refusal-body.js";
12
12
  import { timeClaim } from "./claim-latency.js";
13
+ import { storeFaultClassOf } from "../plugins/store-fault.js";
14
+ import { resumeClaimFaultAnswer } from "./resume-ctx-read.js";
15
+ import { resumeAssemblyRefusalAnswer, resumeRefusalWithCard } from "./checkpoint-ctx.js";
13
16
  export async function resolveExecutionContext(deps, entry) {
14
17
  const lanes = deployedExecutionLanes(deps.config);
15
18
  switch (entry.kind) {
@@ -70,8 +73,7 @@ function laneOf(root, cell, lanes) {
70
73
  }
71
74
  }
72
75
  function sessionMirrorError(root) {
73
- const answer = sessionMirrorAnswer(root);
74
- return createCodedHttpError(answer.status, answer.body.errorCode, answer.body.error, { forkPath: forkPathOf(root) });
76
+ return refusalHttpError(sessionMirrorAnswer(root));
75
77
  }
76
78
  export function forkPathOf(root) {
77
79
  return `/v1/sessions/${encodeURIComponent(root)}/fork`;
@@ -87,8 +89,7 @@ function sessionMirrorAnswer(root) {
87
89
  };
88
90
  }
89
91
  function rootSessionGoneError() {
90
- const absent = rootSessionAbsentAnswer();
91
- return createCodedHttpError(absent.status, absent.body.errorCode, absent.body.error);
92
+ return refusalHttpError(rootSessionAbsentAnswer());
92
93
  }
93
94
  export function isRootSessionGoneError(err) {
94
95
  return err instanceof HttpError && err.code === rootSessionAbsentAnswer().body.errorCode;
@@ -142,8 +143,8 @@ async function admitDevicePlacement(deps, entry, lane, seat, reading) {
142
143
  try {
143
144
  admitted = await deps.deviceEnrollment.admitSession({ rootSessionId: entry.root, placement: reading, requester: owner, ...(requestedDeviceId === undefined ? {} : { requestedDeviceId }) });
144
145
  }
145
- catch {
146
- throw asHttpError(registryUnavailable());
146
+ catch (e) {
147
+ throw asHttpError(faultedAnswerOf(e, registryUnavailable));
147
148
  }
148
149
  if (admitted.ok)
149
150
  return { rootSessionId: entry.root, occupant: reading.occupant, owner, admittedDeviceId: admitted.value.deviceId, firstBind: false };
@@ -153,8 +154,8 @@ async function admitDevicePlacement(deps, entry, lane, seat, reading) {
153
154
  try {
154
155
  view = await deps.deviceStore.readDeviceForAdmission(requestedDeviceId, owner);
155
156
  }
156
- catch {
157
- throw asHttpError(registryUnavailable());
157
+ catch (e) {
158
+ throw asHttpError(faultedAnswerOf(e, registryUnavailable));
158
159
  }
159
160
  if (!view)
160
161
  throw asHttpError(buildDeviceRejection(DEVICE_ERROR_CODES.NOT_FOUND, "device not found"));
@@ -169,8 +170,20 @@ export function stampSpecRoot(spec, ctx, submission) {
169
170
  if (named !== undefined && named !== ctx.root) {
170
171
  throw createCodedHttpError(400, "request.precondition_unmet", "the deployment's spec resolver named a session other than the one this submission was authorized for — a submission's root session comes only from the authorizer, so resolveSpec must not set sessionId (read opts.execution.root instead)");
171
172
  }
172
- const requireExisting = submission.cascade !== true && (ctx.occupant !== undefined || submission.requireExistingSession === true);
173
- return requireExisting ? { ...spec, sessionId: ctx.root, requireExistingSession: true } : { ...spec, sessionId: ctx.root };
173
+ switch (submission.use) {
174
+ case "session": {
175
+ const mustExist = ctx.occupant !== undefined || submission.requireExistingSession === true;
176
+ return mustExist ? { ...spec, sessionId: ctx.root, requireExistingSession: true } : { ...spec, sessionId: ctx.root };
177
+ }
178
+ case "ladder_host": {
179
+ const { requireExistingSession: _noAcquireOnALadder, ...ladderSpec } = spec;
180
+ return { ...ladderSpec, sessionId: ctx.root };
181
+ }
182
+ default: {
183
+ const unhandled = submission;
184
+ throw new Error(`stampSpecRoot: unhandled root use ${JSON.stringify(unhandled)}`);
185
+ }
186
+ }
174
187
  }
175
188
  export function rootSessionAbsentAnswer() {
176
189
  return {
@@ -181,6 +194,62 @@ export function rootSessionAbsentAnswer() {
181
194
  }),
182
195
  };
183
196
  }
197
+ export function isRootSessionGoneRefusal(refusal) {
198
+ return refusal.body.errorCode === rootSessionAbsentAnswer().body.errorCode;
199
+ }
200
+ export function faultedAnswerOf(e, answer) {
201
+ const fault = storeFaultClassOf(e);
202
+ switch (fault) {
203
+ case "corrupt":
204
+ case "connection":
205
+ case "deployment":
206
+ case "unclassified":
207
+ return answer();
208
+ case "defect":
209
+ throw e;
210
+ default: {
211
+ const unhandled = fault;
212
+ throw new Error(`faultedAnswerOf: the store-fault judge answered a class this reader does not place: ${String(unhandled)}`);
213
+ }
214
+ }
215
+ }
216
+ export function runStoreUnavailableAnswer() {
217
+ return {
218
+ status: 503,
219
+ body: refusalBody({ errorCode: "state.run_store_unavailable", message: "this task could not be recorded just now (the store did not answer), so nothing was started. Send it again later; if this keeps happening, ask whoever operates this deployment to check its database." }),
220
+ };
221
+ }
222
+ export const SUBMISSION_CLAIM_FACE = { refused: (refusal) => refusal, faulted: runStoreUnavailableAnswer };
223
+ export const CONTINUATION_CLAIM_FACE = {
224
+ refused: (refusal) => (isRootSessionGoneRefusal(refusal) ? refusal : cardWaitingRefusalAnswer(refusal)),
225
+ faulted: resumeClaimFaultAnswer,
226
+ };
227
+ export function cardWaitingRefusalAnswer(refusal) {
228
+ const { error, errorCode, ...facts } = refusal.body;
229
+ return resumeRefusalWithCard(resumeAssemblyRefusalAnswer(refusal.status, { errorCode, message: error, facts }), true);
230
+ }
231
+ export function refusalHttpError(refusal) {
232
+ const { error, errorCode, ...facts } = refusal.body;
233
+ return createCodedHttpError(refusal.status, errorCode, error, Object.keys(facts).length > 0 ? facts : undefined);
234
+ }
235
+ export async function resolveBeforeClaim(deps, entry, face) {
236
+ try {
237
+ return await resolveExecutionContext(deps, entry);
238
+ }
239
+ catch (e) {
240
+ if (e instanceof HttpError)
241
+ throw e;
242
+ throw new ClaimFaultAnswer(faultedAnswerOf(e, face.faulted));
243
+ }
244
+ }
245
+ export class ClaimFaultAnswer extends HttpError {
246
+ answer;
247
+ constructor(answer) {
248
+ const { error, errorCode: code, ...facts } = answer.body;
249
+ super(answer.status, error, Object.keys(facts).length > 0 ? { code, extra: facts } : { code });
250
+ this.answer = answer;
251
+ }
252
+ }
184
253
  export function placementWriteDeadlineMs(runStaleSec) {
185
254
  const stale = typeof runStaleSec === "number" && Number.isFinite(runStaleSec) && runStaleSec > 0 ? runStaleSec : RUN_STALE_SEC_DEFAULT;
186
255
  return Math.min(15_000, Math.max(1_000, Math.floor((stale * 1000) / 4)));
@@ -209,7 +278,7 @@ export async function commitExecutionContext(deps, claim, ctx) {
209
278
  return timeClaim(deps.metrics, "placement_commit", commitPlacement(deps, claim, ctx, seat, occupant));
210
279
  }
211
280
  async function commitPlacement(deps, claim, ctx, seat, occupant) {
212
- const release = (why) => releaseClaim(deps, claim, why);
281
+ const release = (why, ending) => withdrawClaim(deps, claim, why, ending);
213
282
  const deadlineMs = placementWriteDeadlineMs(deps.config?.runStaleSec);
214
283
  const withDeadline = async (work) => {
215
284
  let timer;
@@ -227,56 +296,64 @@ async function commitPlacement(deps, claim, ctx, seat, occupant) {
227
296
  clearTimeout(timer);
228
297
  }
229
298
  };
230
- const goneAnswer = () => (claim.kind === "parked" ? claim.goneAnswer : rootSessionAbsentAnswer());
231
299
  let refusal;
232
300
  try {
233
301
  refusal =
234
302
  ctx.device !== undefined
235
- ? await commitDevice(deps, seat, ctx.device, withDeadline, goneAnswer)
303
+ ? await commitDevice(deps, seat, ctx.device, withDeadline)
236
304
  : ctx.placement === "absent"
237
- ? await commitPlace(seat, ctx, occupant, withDeadline, goneAnswer)
238
- : await reassertWriter(seat, ctx, occupant, withDeadline, goneAnswer);
305
+ ? await commitPlace(seat, ctx, occupant, withDeadline)
306
+ : await reassertWriter(seat, ctx, occupant, withDeadline);
239
307
  }
240
308
  catch (err) {
241
- deps.logger?.warn("execution_placement_commit_failed", { root: ctx.root, lane: ctx.lane, placement: ctx.placement, deadlineMs, err: err instanceof Error ? err.message : String(err) });
242
- await release(`execution placement could not be committed: ${err instanceof Error ? err.message : String(err)}`);
243
- if (ctx.device !== undefined) {
244
- refusal = deviceRefusal(registryUnavailable());
309
+ if (err instanceof SessionForkInProgressError) {
310
+ refusal = { status: 409, body: refusalBody({ errorCode: err.code, message: err.message }) };
245
311
  deps.metrics?.inc("execution_placement_rejects_total", { errorCode: refusal.body.errorCode });
312
+ await release(`execution placement rejected: [${refusal.body.errorCode}] ${refusal.body.error}`, "refused");
246
313
  return refusal;
247
314
  }
315
+ deps.logger?.warn("execution_placement_commit_failed", { root: ctx.root, lane: ctx.lane, placement: ctx.placement, deadlineMs, err: err instanceof Error ? err.message : String(err) });
316
+ await release(`execution placement could not be committed: ${err instanceof Error ? err.message : String(err)}`, "faulted");
248
317
  throw err;
249
318
  }
250
319
  if (refusal === null)
251
320
  return null;
252
321
  deps.metrics?.inc("execution_placement_rejects_total", { errorCode: refusal.body.errorCode });
253
- await release(`execution placement rejected: [${refusal.body.errorCode}] ${refusal.body.error}`);
322
+ await release(`execution placement rejected: [${refusal.body.errorCode}] ${refusal.body.error}`, isRootSessionGoneRefusal(refusal) ? "gone" : "refused");
254
323
  return refusal;
255
324
  }
256
- async function releaseClaim(deps, claim, why) {
325
+ export async function withdrawClaim(deps, claim, why, ending) {
326
+ const loud = (taskId, step, err) => {
327
+ deps.logger?.warn("execution_placement_run_release_failed", { taskId, step, err: err instanceof Error ? err.message : String(err) });
328
+ deps.metrics?.inc("execution_placement_run_release_failed_total");
329
+ };
257
330
  switch (claim.kind) {
258
331
  case "run":
259
- await releaseClaimedRun(claim.runStore, claim.taskId, why, (err, step) => {
260
- deps.logger?.warn("execution_placement_run_release_failed", { taskId: claim.taskId, step, err: err instanceof Error ? err.message : String(err) });
261
- deps.metrics?.inc("execution_placement_run_release_failed_total");
262
- });
332
+ await withdrawClaimedRun(claim.runStore, claim.taskId, claim.legId, (err, step) => loud(claim.taskId, step, err));
333
+ return;
334
+ case "resumed":
335
+ if (ending !== "gone") {
336
+ await claim.restore();
337
+ return;
338
+ }
339
+ await releaseClaimedRun(claim.runStore, claim.taskId, why, (err, step) => loud(claim.taskId, step, err));
263
340
  return;
264
341
  case "parked":
265
342
  await claim.rollback(why);
266
343
  return;
267
344
  default: {
268
345
  const unhandled = claim;
269
- throw new Error(`commitExecutionContext: unknown claim ${JSON.stringify(unhandled)}`);
346
+ throw new Error(`withdrawClaim: unknown claim ${JSON.stringify(unhandled)}`);
270
347
  }
271
348
  }
272
349
  }
273
- async function commitPlace(seat, ctx, occupant, withDeadline, goneAnswer) {
350
+ async function commitPlace(seat, ctx, occupant, withDeadline) {
274
351
  if (ctx.lane === "device") {
275
352
  return deviceRefusal(buildDeviceRejection(DEVICE_ERROR_CODES.NOT_BOUND, "this session has no device binding — nothing was started"));
276
353
  }
277
- return placeOutcomeAnswer(ctx.root, await withDeadline(seat.place(ctx.root, occupant, { role: "writer", lane: ctx.lane })), goneAnswer);
354
+ return placeOutcomeAnswer(ctx.root, await withDeadline(seat.place(ctx.root, occupant, { role: "writer", lane: ctx.lane })));
278
355
  }
279
- function placeOutcomeAnswer(root, outcome, goneAnswer) {
356
+ function placeOutcomeAnswer(root, outcome) {
280
357
  switch (outcome.outcome) {
281
358
  case "placed":
282
359
  case "same":
@@ -286,17 +363,17 @@ function placeOutcomeAnswer(root, outcome, goneAnswer) {
286
363
  case "mirror":
287
364
  return sessionMirrorAnswer(root);
288
365
  case "gone":
289
- return goneAnswer();
366
+ return rootSessionAbsentAnswer();
290
367
  default: {
291
368
  const unhandled = outcome;
292
369
  throw new Error(`commitExecutionContext: no answer for ${JSON.stringify(unhandled)}`);
293
370
  }
294
371
  }
295
372
  }
296
- async function reassertWriter(seat, ctx, occupant, withDeadline, goneAnswer) {
373
+ async function reassertWriter(seat, ctx, occupant, withDeadline) {
297
374
  const now = await withDeadline(seat.read(ctx.root));
298
375
  if (now === undefined || !sameOccupant(now.occupant, occupant))
299
- return goneAnswer();
376
+ return rootSessionAbsentAnswer();
300
377
  const cell = now.cell;
301
378
  switch (cell.role) {
302
379
  case "writer":
@@ -312,20 +389,31 @@ async function reassertWriter(seat, ctx, occupant, withDeadline, goneAnswer) {
312
389
  }
313
390
  }
314
391
  }
315
- async function commitDevice(deps, seat, intent, withDeadline, goneAnswer) {
392
+ async function commitDevice(deps, seat, intent, withDeadline) {
316
393
  const enrollment = deps.deviceEnrollment;
317
394
  if (!enrollment) {
318
395
  throw new Error("commitExecutionContext: a device placement intent was minted without a DeviceEnrollment — assembly bug (both are read from the same ServiceDeps)");
319
396
  }
397
+ const registry = async (work) => {
398
+ try {
399
+ return { ok: true, value: await withDeadline(work) };
400
+ }
401
+ catch (e) {
402
+ return { ok: false, refusal: deviceRefusal(faultedAnswerOf(e, registryUnavailable)) };
403
+ }
404
+ };
320
405
  if (intent.firstBind) {
321
- const bound = await withDeadline(enrollment.bindPlacement({ rootSessionId: intent.rootSessionId, occupant: intent.occupant, deviceId: intent.admittedDeviceId, requester: intent.owner }));
406
+ const binding = await registry(enrollment.bindPlacement({ rootSessionId: intent.rootSessionId, occupant: intent.occupant, deviceId: intent.admittedDeviceId, requester: intent.owner }));
407
+ if (!binding.ok)
408
+ return binding.refusal;
409
+ const bound = binding.value;
322
410
  if (bound.ok)
323
411
  return null;
324
412
  if ("reject" in bound)
325
413
  return deviceRefusal(bound.reject);
326
414
  switch (bound.placement) {
327
415
  case "gone":
328
- return goneAnswer();
416
+ return rootSessionAbsentAnswer();
329
417
  case "mirror":
330
418
  return sessionMirrorAnswer(intent.rootSessionId);
331
419
  case "tree_bound":
@@ -338,8 +426,10 @@ async function commitDevice(deps, seat, intent, withDeadline, goneAnswer) {
338
426
  }
339
427
  const placement = await withDeadline(seat.read(intent.rootSessionId));
340
428
  if (placement === undefined || !sameOccupant(placement.occupant, intent.occupant))
341
- return goneAnswer();
342
- const readmitted = await withDeadline(enrollment.admitSession({ rootSessionId: intent.rootSessionId, placement, requester: intent.owner, requestedDeviceId: intent.admittedDeviceId }));
343
- return readmitted.ok ? null : deviceRefusal(readmitted.reject);
429
+ return rootSessionAbsentAnswer();
430
+ const readmission = await registry(enrollment.admitSession({ rootSessionId: intent.rootSessionId, placement, requester: intent.owner, requestedDeviceId: intent.admittedDeviceId }));
431
+ if (!readmission.ok)
432
+ return readmission.refusal;
433
+ return readmission.value.ok ? null : deviceRefusal(readmission.value.reject);
344
434
  }
345
435
  //# sourceMappingURL=execution-context.js.map