@sema-agent/server 7.136.0 → 7.138.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 (327) hide show
  1. package/MIGRATION.md +501 -139
  2. package/README.md +1 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +149 -34
  5. package/deploy/sema-up/README.md +14 -0
  6. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
  7. package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
  8. package/dist/approval-card.d.ts +21 -14
  9. package/dist/approval-card.js +1 -0
  10. package/dist/approval-content-kind.d.ts +6 -0
  11. package/dist/approval-content-kind.js +7 -0
  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/audit.js +1 -0
  18. package/dist/auth-bridge.js +2 -2
  19. package/dist/background-agent-name.d.ts +5 -0
  20. package/dist/background-agent-name.js +5 -0
  21. package/dist/boot/budget-tracing.d.ts +1 -12
  22. package/dist/boot/deployment-mods.d.ts +46 -16
  23. package/dist/boot/deployment-mods.js +82 -6
  24. package/dist/boot/execution-env.d.ts +24 -1
  25. package/dist/boot/execution-env.js +69 -6
  26. package/dist/boot/governance-seams.d.ts +10 -17
  27. package/dist/boot/governance-seams.js +5 -17
  28. package/dist/boot/leader.d.ts +3 -0
  29. package/dist/boot/leader.js +1 -0
  30. package/dist/boot/org-delivery.js +15 -2
  31. package/dist/boot/reapers.d.ts +3 -0
  32. package/dist/boot/reapers.js +15 -1
  33. package/dist/boot/resolve-spec.d.ts +7 -0
  34. package/dist/boot/resolve-spec.js +36 -26
  35. package/dist/boot/retention-lane.d.ts +11 -5
  36. package/dist/boot/retention-lane.js +2 -2
  37. package/dist/boot/runner-deps.d.ts +7 -3
  38. package/dist/boot/runner-deps.js +1 -0
  39. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  40. package/dist/boot/stage-04-stores.d.ts +2 -13
  41. package/dist/boot/stage-05-execution-env.d.ts +6 -13
  42. package/dist/boot/stage-05-execution-env.js +17 -5
  43. package/dist/boot/stage-06-runners.d.ts +6 -13
  44. package/dist/boot/stage-06-runners.js +10 -3
  45. package/dist/boot/stage-07-capability-layer.d.ts +7 -13
  46. package/dist/boot/stage-07-capability-layer.js +3 -3
  47. package/dist/boot/stage-08-reapers.d.ts +7 -13
  48. package/dist/boot/stage-08-reapers.js +2 -1
  49. package/dist/boot/stage-09-leader.d.ts +7 -13
  50. package/dist/boot/stage-09-leader.js +2 -2
  51. package/dist/boot/stage-10-http-server.d.ts +7 -13
  52. package/dist/boot/stage-10-http-server.js +6 -3
  53. package/dist/boot/stores.d.ts +1 -1
  54. package/dist/boot/web-admin.d.ts +5 -2
  55. package/dist/boot/web-admin.js +3 -3
  56. package/dist/brain.js +5 -5
  57. package/dist/broker/broker.d.ts +89 -0
  58. package/dist/broker/broker.js +287 -0
  59. package/dist/broker/constants.d.ts +39 -0
  60. package/dist/broker/constants.js +15 -0
  61. package/dist/broker/http1.d.ts +111 -0
  62. package/dist/broker/http1.js +256 -0
  63. package/dist/broker/lease-book.d.ts +87 -0
  64. package/dist/broker/lease-book.js +142 -0
  65. package/dist/broker/lease-file.d.ts +60 -0
  66. package/dist/broker/lease-file.js +127 -0
  67. package/dist/broker/main.d.ts +2 -0
  68. package/dist/broker/main.js +20 -0
  69. package/dist/budget.d.ts +17 -15
  70. package/dist/budget.js +2 -2
  71. package/dist/capabilities/composite-members.d.ts +2 -1
  72. package/dist/capabilities/composite-members.js +2 -1
  73. package/dist/capabilities/engine-capabilities.js +1 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -11
  75. package/dist/capabilities/mcp-probe.js +44 -5
  76. package/dist/capabilities/scenarios.d.ts +23 -8
  77. package/dist/capabilities/scenarios.js +13 -8
  78. package/dist/capabilities/skills.d.ts +28 -5
  79. package/dist/capabilities/skills.js +8 -0
  80. package/dist/capability-facts.d.ts +6 -0
  81. package/dist/capability-facts.js +5 -0
  82. package/dist/center-credential-renewer.js +5 -1
  83. package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
  84. package/dist/checkpoint-ctx-seal-m28.js +1 -1
  85. package/dist/checkpoint-identity.d.ts +13 -6
  86. package/dist/config-catalog.js +16 -7
  87. package/dist/config-types.d.ts +24 -7
  88. package/dist/config.d.ts +1 -1
  89. package/dist/config.js +42 -13
  90. package/dist/deployment-governance.d.ts +2 -2
  91. package/dist/deployment-governance.js +7 -9
  92. package/dist/deployment-shape.d.ts +6 -6
  93. package/dist/device-ws-protocol.d.ts +1 -0
  94. package/dist/device-ws-protocol.js +2 -1
  95. package/dist/file-history-disclosure.d.ts +4 -2
  96. package/dist/file-history-disclosure.js +2 -0
  97. package/dist/gate-settlement.d.ts +71 -0
  98. package/dist/gate-settlement.js +40 -0
  99. package/dist/hooks/classic-stations.d.ts +12 -54
  100. package/dist/hooks/classic-stations.js +1 -0
  101. package/dist/hooks/command-spawn.d.ts +2 -2
  102. package/dist/hooks/hook-runner.js +14 -14
  103. package/dist/http/admission.js +14 -9
  104. package/dist/http/approval-sweeps.js +4 -3
  105. package/dist/http/caller-trust.d.ts +2 -1
  106. package/dist/http/caller-trust.js +1 -3
  107. package/dist/http/checkpoint-ctx.d.ts +48 -7
  108. package/dist/http/checkpoint-ctx.js +40 -0
  109. package/dist/http/dispatch.d.ts +4 -0
  110. package/dist/http/dispatch.js +18 -10
  111. package/dist/http/durable-run-leg.d.ts +5 -1
  112. package/dist/http/durable-run-leg.js +5 -3
  113. package/dist/http/health-self-report.d.ts +2 -2
  114. package/dist/http/memory-compliance-failure-reply.js +3 -0
  115. package/dist/http/principal-gate.d.ts +15 -10
  116. package/dist/http/principal-gate.js +48 -9
  117. package/dist/http/resume-legs.d.ts +7 -31
  118. package/dist/http/resume-legs.js +185 -126
  119. package/dist/http/route-ctx.d.ts +38 -53
  120. package/dist/http/route-ctx.js +2 -5
  121. package/dist/http/routes/a2a-serve.js +10 -4
  122. package/dist/http/routes/agents-roster.d.ts +1 -1
  123. package/dist/http/routes/agents-roster.js +5 -1
  124. package/dist/http/routes/approvals-assistant.js +24 -10
  125. package/dist/http/routes/capabilities.js +23 -11
  126. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  127. package/dist/http/routes/mcp-reconnect.js +7 -7
  128. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  129. package/dist/http/routes/memory-origin.d.ts +1 -1
  130. package/dist/http/routes/rules.js +3 -3
  131. package/dist/http/routes/runs.js +13 -8
  132. package/dist/http/routes/session-sync.js +42 -6
  133. package/dist/http/routes/sessions.js +6 -3
  134. package/dist/http/routes/side-query.js +2 -3
  135. package/dist/http/routes/tasks.js +794 -780
  136. package/dist/http/server.d.ts +35 -25
  137. package/dist/http/stored-body-replay.d.ts +3 -3
  138. package/dist/http/stored-body-replay.js +6 -1
  139. package/dist/http/wire-types.d.ts +66 -33
  140. package/dist/identity-source.d.ts +65 -0
  141. package/dist/identity-source.js +45 -0
  142. package/dist/index.d.ts +2 -0
  143. package/dist/index.js +1 -0
  144. package/dist/leader/wire.d.ts +7 -0
  145. package/dist/leader/wire.js +5 -4
  146. package/dist/mcp-assertion-header.d.ts +51 -40
  147. package/dist/mcp-assertion-header.js +10 -11
  148. package/dist/mcp-authorization-face.d.ts +27 -0
  149. package/dist/mcp-authorization-face.js +15 -0
  150. package/dist/memory-operator-faces.d.ts +13 -4
  151. package/dist/memory-operator-faces.js +1 -17
  152. package/dist/memory-store-refusal.d.ts +3 -3
  153. package/dist/memory-sync-client.js +72 -57
  154. package/dist/memory-sync.d.ts +1 -1
  155. package/dist/model-entry-refusal.d.ts +2 -0
  156. package/dist/model-entry-refusal.js +11 -0
  157. package/dist/model-route-gap.d.ts +6 -22
  158. package/dist/model-route-gap.js +7 -5
  159. package/dist/model-select.d.ts +6 -17
  160. package/dist/model-select.js +0 -3
  161. package/dist/mods-declaration.d.ts +110 -0
  162. package/dist/mods-declaration.js +109 -0
  163. package/dist/namespaced-rule-name.d.ts +1 -1
  164. package/dist/observability/err-text.d.ts +5 -0
  165. package/dist/observability/err-text.js +9 -0
  166. package/dist/observability/fail-open.d.ts +17 -1
  167. package/dist/observability/fail-open.js +17 -1
  168. package/dist/observability/metrics.js +1 -1
  169. package/dist/observability/run-terminal.js +1 -0
  170. package/dist/observability/secret-env-scrub.d.ts +1 -1
  171. package/dist/observability/secret-env-scrub.js +1 -1
  172. package/dist/operator-ask.d.ts +2 -2
  173. package/dist/org-delivery-gate.js +1 -1
  174. package/dist/org-memory-admission.d.ts +2 -2
  175. package/dist/org-memory-admission.js +39 -2
  176. package/dist/parked-decide.d.ts +15 -2
  177. package/dist/parked-decide.js +17 -10
  178. package/dist/peer-directory.js +2 -0
  179. package/dist/peer-seat.d.ts +150 -0
  180. package/dist/peer-seat.js +239 -0
  181. package/dist/permission-rule-list.d.ts +2 -2
  182. package/dist/permission-rule-vocab.d.ts +7 -7
  183. package/dist/permission-rule-vocab.js +3 -3
  184. package/dist/plain-string-record.d.ts +38 -0
  185. package/dist/plain-string-record.js +38 -0
  186. package/dist/plugins/background-agent-store-sql.js +6 -3
  187. package/dist/plugins/caching-session-store.d.ts +5 -0
  188. package/dist/plugins/caching-session-store.js +6 -0
  189. package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
  190. package/dist/plugins/checkpoint-store-sql.js +14 -14
  191. package/dist/plugins/file-history-store-sql.js +10 -16
  192. package/dist/plugins/file-run-store.js +8 -2
  193. package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
  194. package/dist/plugins/k8s-exec-protocol.js +116 -28
  195. package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
  196. package/dist/plugins/k8s-pod-delete-failure.js +17 -0
  197. package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
  198. package/dist/plugins/k8s-pod-reaper.js +122 -0
  199. package/dist/plugins/local-checkpoint-store.d.ts +4 -17
  200. package/dist/plugins/local-checkpoint-store.js +3 -4
  201. package/dist/plugins/local-session-store.d.ts +66 -27
  202. package/dist/plugins/local-session-store.js +60 -28
  203. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  204. package/dist/plugins/mailbox-store-sql.js +103 -15
  205. package/dist/plugins/memory-run-store.js +2 -0
  206. package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
  207. package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
  208. package/dist/plugins/one-time-migrations.d.ts +34 -12
  209. package/dist/plugins/one-time-migrations.js +51 -9
  210. package/dist/plugins/permission-rule-store-file.js +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
  212. package/dist/plugins/permission-rule-store-sql.js +37 -30
  213. package/dist/plugins/pg-pool.js +4 -0
  214. package/dist/plugins/pg-session-storage.d.ts +10 -2
  215. package/dist/plugins/pg-session-storage.js +20 -7
  216. package/dist/plugins/remote-env-adb.d.ts +6 -1
  217. package/dist/plugins/remote-env-adb.js +2 -1
  218. package/dist/plugins/remote-env-device.d.ts +6 -1
  219. package/dist/plugins/remote-env-device.js +5 -1
  220. package/dist/plugins/remote-env-e2b.d.ts +5 -0
  221. package/dist/plugins/remote-env-e2b.js +2 -1
  222. package/dist/plugins/remote-env-file-error.d.ts +8 -1
  223. package/dist/plugins/remote-env-file-error.js +7 -1
  224. package/dist/plugins/remote-env-host.d.ts +10 -2
  225. package/dist/plugins/remote-env-host.js +8 -2
  226. package/dist/plugins/remote-env-k8s.d.ts +140 -11
  227. package/dist/plugins/remote-env-k8s.js +277 -15
  228. package/dist/plugins/remote-env-local-docker.d.ts +5 -0
  229. package/dist/plugins/remote-env-local-docker.js +2 -1
  230. package/dist/plugins/remote-env-ssh.d.ts +6 -1
  231. package/dist/plugins/remote-env-ssh.js +2 -1
  232. package/dist/plugins/retention-store-sql.d.ts +14 -2
  233. package/dist/plugins/retention-store-sql.js +6 -0
  234. package/dist/plugins/run-store-sql.js +10 -4
  235. package/dist/plugins/session-fork.d.ts +10 -13
  236. package/dist/plugins/session-fork.js +5 -25
  237. package/dist/plugins/session-ownership.d.ts +24 -3
  238. package/dist/plugins/session-ownership.js +24 -5
  239. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  240. package/dist/plugins/session-workspace-cell.js +38 -0
  241. package/dist/plugins/sql-errors.d.ts +23 -2
  242. package/dist/plugins/sql-errors.js +15 -0
  243. package/dist/plugins/store-backend.js +7 -7
  244. package/dist/plugins/store-contracts.d.ts +10 -1
  245. package/dist/plugins/store-fault.d.ts +2 -2
  246. package/dist/plugins/store-fault.js +4 -2
  247. package/dist/plugins/tidb-pool.js +13 -0
  248. package/dist/plugins/tidb-session-store.d.ts +17 -2
  249. package/dist/plugins/tidb-session-store.js +18 -7
  250. package/dist/plugins/tool-result-store-sql.d.ts +13 -6
  251. package/dist/plugins/tool-result-store-sql.js +8 -7
  252. package/dist/plugins/worktree-isolation.d.ts +3 -2
  253. package/dist/plugins/worktree-isolation.js +1 -7
  254. package/dist/project-identity.d.ts +1 -14
  255. package/dist/project-identity.js +0 -4
  256. package/dist/request-key-closure.js +1 -1
  257. package/dist/request-value-closure.d.ts +31 -2
  258. package/dist/request-value-closure.js +7 -1
  259. package/dist/rule-entry-list.d.ts +3 -2
  260. package/dist/rule-entry-list.js +2 -2
  261. package/dist/rules-consent.js +12 -7
  262. package/dist/run-local.d.ts +2 -2
  263. package/dist/run-local.js +12 -6
  264. package/dist/runs.d.ts +7 -1
  265. package/dist/runs.js +8 -2
  266. package/dist/runtime-governance.d.ts +5 -5
  267. package/dist/sandbox-git-lease.d.ts +49 -0
  268. package/dist/sandbox-git-lease.js +60 -0
  269. package/dist/sandbox-git-plane.d.ts +84 -0
  270. package/dist/sandbox-git-plane.js +105 -0
  271. package/dist/security.d.ts +16 -4
  272. package/dist/security.js +8 -3
  273. package/dist/server-secret-env.d.ts +12 -3
  274. package/dist/server-secret-env.js +18 -2
  275. package/dist/session-error-wire.d.ts +14 -6
  276. package/dist/session-error-wire.js +2 -1
  277. package/dist/session-incarnation.d.ts +4 -5
  278. package/dist/session-incarnation.js +2 -2
  279. package/dist/session-policy-wire.d.ts +1 -1
  280. package/dist/session-policy-wire.js +2 -2
  281. package/dist/session-sync.d.ts +1 -1
  282. package/dist/session-workspace.d.ts +130 -0
  283. package/dist/session-workspace.js +83 -0
  284. package/dist/spec-fields.d.ts +44 -14
  285. package/dist/spec-fields.js +33 -12
  286. package/dist/standing-answer-grant.d.ts +2 -13
  287. package/dist/standing-answer-grant.js +0 -7
  288. package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
  289. package/dist/stored-request-prompt-profile-m30.js +25 -0
  290. package/dist/task-a2a.d.ts +44 -14
  291. package/dist/task-a2a.js +46 -20
  292. package/dist/task-mcp.d.ts +34 -21
  293. package/dist/task-mcp.js +46 -22
  294. package/dist/task-settings.d.ts +2 -2
  295. package/dist/tool-approval.d.ts +43 -9
  296. package/dist/tool-approval.js +57 -15
  297. package/dist/tool-rule-names.d.ts +5 -0
  298. package/dist/trace/core-keyset-guard.d.ts +34 -19
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +4 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +5 -2
  303. package/dist/trace/extension-call-face.d.ts +33 -0
  304. package/dist/trace/extension-call-face.js +39 -0
  305. package/dist/trace/ledger-sink.d.ts +4 -5
  306. package/dist/trace/ledger-sink.js +3 -7
  307. package/dist/trace/project.d.ts +62 -10
  308. package/dist/trace/project.js +49 -9
  309. package/dist/trace/redact.d.ts +18 -6
  310. package/dist/trace/redact.js +154 -60
  311. package/dist/trace/self-minted-wire.d.ts +500 -7
  312. package/dist/trace/self-minted-wire.js +182 -1
  313. package/dist/trace/wire-projection-faces.d.ts +7 -5
  314. package/dist/trace/wire-projection-faces.js +9 -4
  315. package/dist/user-authored-text.d.ts +2 -2
  316. package/dist/user-authored-text.js +16 -1
  317. package/dist/web-admin-client/apply-effective.js +0 -1
  318. package/dist/web-admin-client/center-request.d.ts +23 -4
  319. package/dist/web-admin-client/center-request.js +42 -8
  320. package/dist/web-admin-client/http-client.js +6 -6
  321. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  322. package/dist/web-admin-client/skills-mcp.js +31 -18
  323. package/dist/web-admin-client/types.d.ts +10 -5
  324. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
  325. package/package.json +3 -3
  326. package/wire-changes/server@7.137.0.json +825 -0
  327. package/wire-changes/server@7.138.0.json +446 -0
@@ -4,12 +4,13 @@ import { uuidv7, resumeWithVerification, CheckpointError, defaultTaskRegistry, t
4
4
  import { decideParkedAgent, denyWorkflowParkForked, denyWorkflowParksUnreadable, findParkOrigin, heldWorkflowParkDecisions, planWorkflowParkedDecide } from "../parked-decide.js";
5
5
  import { parkDecisionFingerprint } from "../orchestration/workflow-park-decision.js";
6
6
  import { headReadOf } from "../session-incarnation.js";
7
+ import { createSessionWorkspaceRecorder, legSessionWitnessOf, sessionWorkspaceStoreOf } from "../session-workspace.js";
7
8
  const DELIVERY_NOT_RECORDED = "workflow park decide: this delivery no longer holds the host session (its claim was released) — the decision was not recorded and this delivery was not started";
8
9
  const headUnavailable = async (sessionId) => {
9
10
  throw new Error(`parked decide cannot verify which occupant session ${sessionId} belongs to: this deployment's session store has no head read (headOf; every built-in store has one) — refusing rather than resuming unverified`);
10
11
  };
11
12
  import { HttpError, decodeCheckpointScope, CHECKPOINT_PUBLIC_SCOPE } from "../security.js";
12
- import { parkToolCallId, TurnAnchorCapture, HEARTBEAT_MS, markChildrenStoppedByUserOnAbort } from "../runs.js";
13
+ import { graftParkToolCallId, parkToolCallId, TurnAnchorCapture, HEARTBEAT_MS, markChildrenStoppedByUserOnAbort } from "../runs.js";
13
14
  import { failureCodeOf, nestedPauseOf, sealResultForExit, outwardPlane } from "../terminal.js";
14
15
  import { buildCancelledLedgerRow, createRunAbort, mintCancelledResult } from "../run-cancel-context.js";
15
16
  import { isTerminalRunStatus } from "../plugins/store-contracts.js";
@@ -18,16 +19,17 @@ import { recordResumeResourceWindow } from "../resource-window.js";
18
19
  import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKeyOf, NotifiedKeys } from "../orchestration/workflow-completion-inbox.js";
19
20
  import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals, isFleetAgentTerminalNotification } from "../fleet/fleet-bus.js";
20
21
  import { defaultSubagentTailBus } from "../fleet/subagent-tail-bus.js";
21
- import { currentApprovalGateToken } from "../approval-gate-currency.js";
22
- import { createApprovalCardEmitter, declaredApprovalFrameFamilies, parkRowStandingAnswerFacts, resolveApprovalLeg, resolveStreamApprovalGate, standingAnswerDurablyRecordable } from "../tool-approval.js";
22
+ import { currentApprovalGateToken, currentGateFacesOf, sightsCurrentGate } from "../approval-gate-currency.js";
23
+ import { approverFacingArgs, createApprovalCardEmitter, declaredApprovalFrameFamilies, parkRowStandingAnswerFacts, resolveApprovalLeg, resolveStreamApprovalGate, standingAnswerDurablyRecordable } from "../tool-approval.js";
23
24
  import { buildCheckpointAnchorHash } from "../approval-ask-audit-store.js";
24
25
  import { APPROVAL_ENDING_CAUSES } from "../approval-deny-reasons.js";
25
26
  import { serviceVersion } from "../service-version.js";
26
27
  import { TERMINAL_PARK_GATE_KINDS } from "../plugins/checkpoint-store-sql.js";
27
28
  import { withPrincipal } from "../observability/principal-context.js";
28
29
  import { withModelReachScope } from "../model-reach-scope.js";
30
+ import { runSkillsOf } from "../capabilities/skills.js";
29
31
  import { createInstructionSelectionLeg } from "../instruction-selection.js";
30
- import { modelTextEventData, turnEndEventData, contextUsageEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "../trace/project.js";
32
+ import { modelTextEventData, parkEventData, turnEndEventData, contextUsageEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "../trace/project.js";
31
33
  import { redactSecrets } from "../trace/redact.js";
32
34
  import { buildRunObjectivePreview } from "../user-authored-text.js";
33
35
  import { createForwardAppendFailedNote, createLedgerSink, createSerialLedgerAppend } from "../trace/ledger-sink.js";
@@ -37,17 +39,20 @@ import { errorText } from "../observability/err-text.js";
37
39
  import { recordFailOpen } from "../observability/fail-open.js";
38
40
  import { verifyRoundsFromBody } from "./verify-rounds.js";
39
41
  import { planReviewDecisionExitsPlan, storedBodyPermissionMode } from "../task-settings.js";
40
- import { acceptedResumingReceipt, acceptedTaskIdOf, buildHostLegOutcome } from "./route-ctx.js";
42
+ import { acceptedResumingReceipt, acceptedTaskIdOf } from "./route-ctx.js";
43
+ import { heldFor } from "../peer-seat.js";
44
+ import { NO_SETTLEMENT_EVIDENCE, buildSettlementEvidence, decisionCommittedOf } from "../gate-settlement.js";
45
+ import { durableRowIdentity } from "../checkpoint-identity.js";
41
46
  import { mintAndDriveDurableRun } from "./durable-run-leg.js";
42
47
  import { createSessionsLocal } from "./routes/sessions.js";
43
48
  import { createSessionSyncLocal } from "./routes/session-sync.js";
44
49
  import { createImagesLocal } from "./routes/images.js";
45
50
  import { createCapabilitiesLocal } from "./routes/capabilities.js";
46
- import { gatedPrincipal, explicitOperatorOk } from "./principal-gate.js";
51
+ import { gatedPrincipal, explicitOperatorOk, runIdentityOf } from "./principal-gate.js";
47
52
  import { buildActiveRunConflict, resumeEntryForGate } from "./active-run-conflict.js";
48
53
  import { commitPlacement, devicePlacementErrorBody } from "./device-placement.js";
49
54
  import { commitSessionInheritEnv } from "./session-inherit-env.js";
50
- import { ASK_USER_QUESTION_TOOL_NAME, isApprovalGateKind } from "../approval-content-kind.js";
55
+ import { ASK_USER_QUESTION_TOOL_NAME, isApprovalGateKind, isEngineQuestionRow } from "../approval-content-kind.js";
51
56
  import { deploymentListAsks } from "../approval.js";
52
57
  import { readResumeCtx, resumeCtxCorruptAnswer, resumeCtxUnsealableAnswer } from "./resume-ctx-read.js";
53
58
  import { buildCheckpointVersionKeys, resumeBlockedByPolicyAnswer, resumeRefusalWithCard, sealCheckpointCtx, storedBodyReplayAnswer, storedBodyReplayLogFields, withPermissionModeRewritten } from "./checkpoint-ctx.js";
@@ -74,11 +79,14 @@ const WORKER_SWAP_REDEEMABLE = {
74
79
  ledger_event_unknown: true,
75
80
  real_approval_damaged: false,
76
81
  real_approval_forged: false,
82
+ tool_identity_missing: true,
83
+ bound_input_hash_missing: false,
77
84
  requirements_damaged: false,
78
85
  read_face_damaged: false,
79
86
  read_face_forged: false,
80
87
  write_face_damaged: false,
81
88
  skill_grants_damaged: false,
89
+ skill_scopes_damaged: false,
82
90
  constraint_chain_missing: false,
83
91
  hands_coordinates_damaged: false,
84
92
  installation_record_absent: true,
@@ -111,6 +119,7 @@ const CHECKPOINT_ERROR_DISPOSITION = {
111
119
  "resume.principal_mismatch": "retriable",
112
120
  "resume.placement_mismatch": "retriable",
113
121
  "resume.preflight_rejected": "retriable",
122
+ "resume.holder_superseded": "retriable",
114
123
  "wake.gate_pending": "retriable",
115
124
  "wake.nothing_to_deliver": "retriable",
116
125
  "checkpoint.config_refused": "retriable",
@@ -122,9 +131,9 @@ const CHECKPOINT_ERROR_DISPOSITION = {
122
131
  "checkpoint.gate_mismatch": "terminal",
123
132
  "checkpoint.reopen_failed": "terminal",
124
133
  "checkpoint.cwd_conflicts_restore": "terminal",
134
+ "steering.duplicate_input_id": "retriable",
125
135
  "checkpoint.already_exists": "terminal",
126
136
  "checkpoint.execution_outcome_conflict": "terminal",
127
- "steering.duplicate_input_id": "terminal",
128
137
  "steering.invalid_content": "terminal",
129
138
  "steering.queue_full": "terminal",
130
139
  };
@@ -156,6 +165,10 @@ const CHECKPOINT_ERROR_FIELD_ROLE = {
156
165
  hostDecision: "outcome_cell",
157
166
  approver: "outcome_cell",
158
167
  feedback: "outcome_cell",
168
+ outcome: "outcome_cell",
169
+ updatedInput: "outcome_cell",
170
+ decision: "outcome_cell",
171
+ reason: "outcome_cell",
159
172
  taskConfig: "config",
160
173
  deps: "config",
161
174
  inheritedGate: "config",
@@ -183,6 +196,26 @@ function decisionRefusalCauseOf(e, gate) {
183
196
  function notResumableAnswer() {
184
197
  return { status: 409, body: refusalBody({ errorCode: "conflict.not_resumable", message: "run is not in a resumable (suspended) state (already resumed, decided, or expired)" }) };
185
198
  }
199
+ function approvalStaleAnswer(facts) {
200
+ return {
201
+ status: 409,
202
+ body: refusalBody({
203
+ errorCode: "approval_stale",
204
+ message: "the approval you are deciding is no longer current (already resolved or superseded since you viewed it)",
205
+ facts: {
206
+ ...(facts.terminal !== undefined ? { terminal: facts.terminal } : {}),
207
+ ...(facts.currentPending !== undefined ? { currentPending: facts.currentPending } : {}),
208
+ },
209
+ }),
210
+ };
211
+ }
212
+ function acceptableFormFacts(detail) {
213
+ const rewritten = detail !== null && typeof detail === "object" ? detail.editRewritten : undefined;
214
+ if (rewritten === null || typeof rewritten !== "object" || !Object.hasOwn(rewritten, "acceptableForm"))
215
+ return {};
216
+ const shown = approverFacingArgs(rewritten.acceptableForm);
217
+ return shown === undefined ? {} : { acceptableForm: shown };
218
+ }
186
219
  export function checkpointRefusalAnswer(e, at) {
187
220
  const refusalCause = e.code === "checkpoint.invalid_outcome" ? decisionRefusalCauseOf(e, at.gate) : undefined;
188
221
  const detail = e.detail;
@@ -198,6 +231,7 @@ export function checkpointRefusalAnswer(e, at) {
198
231
  ? { retryAfterSec: Math.max(1, Math.ceil(detail.retryAfterMs / 1000)) }
199
232
  : {}),
200
233
  ...at.versionKeys,
234
+ ...(e.code === "resume.constraint_rejected" ? acceptableFormFacts(detail) : {}),
201
235
  },
202
236
  }),
203
237
  }, at.retriable);
@@ -209,7 +243,7 @@ export function createResumeLegs(ctx) {
209
243
  async function resumeCheckpoint(sessionId, decision, reason, hostDecision, req, answer, binding, onResumeCommitted, acceptEarly, decider) {
210
244
  const cs = deps.checkpointStore;
211
245
  const token = await currentApprovalGateToken(cs, sessionId);
212
- if (binding?.checkpointToken && binding.checkpointToken !== token) {
246
+ if (binding?.checkpointToken && !sightsCurrentGate({ face: "checkpointToken", value: binding.checkpointToken }, token ? { checkpointToken: token } : null)) {
213
247
  let seenUnreadable = false;
214
248
  const seen = await cs.get(binding.checkpointToken).catch((e) => {
215
249
  seenUnreadable = true;
@@ -245,17 +279,7 @@ export function createResumeLegs(ctx) {
245
279
  };
246
280
  }
247
281
  }
248
- return {
249
- status: 409,
250
- body: refusalBody({
251
- errorCode: "approval_stale",
252
- message: "the approval you are deciding is no longer current (already resolved or superseded since you viewed it)",
253
- facts: {
254
- ...(attributable ? { terminal: "resolved" } : {}),
255
- ...(currentPending ? { currentPending } : {}),
256
- },
257
- }),
258
- };
282
+ return approvalStaleAnswer({ ...(attributable ? { terminal: "resolved" } : {}), ...(currentPending ? { currentPending } : {}) });
259
283
  }
260
284
  if (!token) {
261
285
  deps.logger?.info?.("approval_decide_no_pending", { sessionId });
@@ -330,16 +354,7 @@ export function createResumeLegs(ctx) {
330
354
  ...(cp.pendingAction.boundInputHash ? { boundInputHash: cp.pendingAction.boundInputHash } : {}),
331
355
  };
332
356
  }
333
- return {
334
- status: 409,
335
- body: refusalBody({
336
- errorCode: "approval_stale",
337
- message: "the approval you are deciding is no longer current (already resolved or superseded since you viewed it)",
338
- facts: {
339
- ...(s57CurrentPending ? { currentPending: s57CurrentPending } : {}),
340
- },
341
- }),
342
- };
357
+ return approvalStaleAnswer(s57CurrentPending ? { currentPending: s57CurrentPending } : {});
343
358
  }
344
359
  const paForGrant = cp.pendingAction.kind === "tool_approval" ? cp.pendingAction : undefined;
345
360
  const rememberableTool = paForGrant !== undefined &&
@@ -360,9 +375,7 @@ export function createResumeLegs(ctx) {
360
375
  }
361
376
  : undefined;
362
377
  const noteLateSettleIfAccepted = (out) => {
363
- if (lateSettleSink === undefined || lateSettleAnchor === undefined || out.status !== 200)
364
- return;
365
- if (out.body?.errorCode === "cancelled" && out.decisionCommitted !== true)
378
+ if (lateSettleSink === undefined || lateSettleAnchor === undefined || !decisionCommittedOf(out))
366
379
  return;
367
380
  try {
368
381
  lateSettleSink.recordLateSettle({ ...lateSettleAnchor, outcome: decision === "approve" ? "allowed" : "denied", decidedBy: hostDecision.decidedBy, ...(hostDecision.approver !== undefined ? { approver: hostDecision.approver } : {}), settledAtMs: Date.now() });
@@ -378,6 +391,7 @@ export function createResumeLegs(ctx) {
378
391
  if (parkedForkLeaseDenial)
379
392
  return parkedForkLeaseDenial;
380
393
  const ownerLeaseAdmittedHere = req !== undefined;
394
+ const captureSelectedGate = () => durableRowIdentity("decision-receipt", cp.checkpointId, token);
381
395
  if (req !== undefined) {
382
396
  const parkedAgentStore = deps.backgroundAgentStore;
383
397
  const parkedSurface = deps.parkedReviveSurface;
@@ -407,7 +421,7 @@ export function createResumeLegs(ctx) {
407
421
  ...(deps.parkedReviveInheritedGate ? { rebuildInheritedGate: deps.parkedReviveInheritedGate } : {}),
408
422
  ...(deps.toolApproval ? { approverSeatFor: windowZeroSeatOf(deps.toolApproval) } : {}),
409
423
  ...(deps.logger ? { warn: parkWarn } : {}),
410
- }, parkedReq, { handle: origin.handle, row: origin.row }));
424
+ }, { ...parkedReq, selectedGate: captureSelectedGate() }, { handle: origin.handle, row: origin.row }));
411
425
  void ctxPromise.catch(() => { });
412
426
  noteLateSettleIfAccepted(parked);
413
427
  return parked;
@@ -435,7 +449,7 @@ export function createResumeLegs(ctx) {
435
449
  if (held === null || held.fingerprint !== fingerprint)
436
450
  return undefined;
437
451
  const run = await runStore.getRun(held.deliveredTaskId);
438
- return run != null && !isTerminalRunStatus(run.status) ? acceptedResumingReceipt(held.deliveredTaskId, held.hostSessionId) : undefined;
452
+ return run != null && !isTerminalRunStatus(run.status) ? acceptedResumingReceipt(held.deliveredTaskId, held.hostSessionId, NO_SETTLEMENT_EVIDENCE) : undefined;
439
453
  };
440
454
  const replay = await liveReceiptOf(await decisions.get(token));
441
455
  if (replay !== undefined)
@@ -481,42 +495,48 @@ export function createResumeLegs(ctx) {
481
495
  const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
482
496
  if (!resolved.ok)
483
497
  return resolved.answer;
484
- const { spec, engineNotices } = resolved;
485
- const pendingTool = cp.pendingAction.toolName;
486
- if (decision === "approve" && pendingTool === ASK_USER_QUESTION_TOOL_NAME && !answer) {
487
- return { status: 400, body: refusalBody({ errorCode: "request.field_conflict", message: "pending action is AskUserQuestion — approve must carry body.answer ({ answers: [{ header, selected: string[], note? }] })", facts: { ...fieldConflictFacts("ask_answer", ["decision", "answer"]) } }) };
498
+ try {
499
+ const { spec, engineNotices } = resolved;
500
+ const pendingTool = cp.pendingAction.toolName;
501
+ if (decision === "approve" && pendingTool === ASK_USER_QUESTION_TOOL_NAME && !answer) {
502
+ return { status: 400, body: refusalBody({ errorCode: "request.field_conflict", message: "pending action is AskUserQuestion — approve must carry body.answer ({ answers: [{ header, selected: string[], note? }] })", facts: { ...fieldConflictFacts("ask_answer", ["decision", "answer"]) } }) };
503
+ }
504
+ if (answer && (decision !== "approve" || pendingTool !== ASK_USER_QUESTION_TOOL_NAME)) {
505
+ return { status: 400, body: refusalBody({ errorCode: "request.field_conflict", message: `body.answer is only valid when approving a pending AskUserQuestion (decision: "${decision}", pending: "${pendingTool ?? "unknown"}")`, facts: { ...fieldConflictFacts("ask_answer", ["answer", "decision"]) } }) };
506
+ }
507
+ const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
508
+ const pa = cp.pendingAction;
509
+ const persistedCallId = pa.kind === "tool_approval" ? pa.toolCallId : "";
510
+ const persistedHash = pa.kind === "tool_approval" ? (pa.boundInputHash ?? "") : "";
511
+ const outcome = {
512
+ gate: "policy_ask",
513
+ boundCallId: binding?.boundCallId ?? persistedCallId,
514
+ boundInputHash: binding?.boundInputHash ?? persistedHash,
515
+ decision: decision === "approve" ? "allow" : "deny",
516
+ ...(decision === "approve" && !isEngineQuestionRow(pa) && binding?.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}),
517
+ ...(reason ? { reason } : {}),
518
+ ...(binding?.feedback !== undefined ? { feedback: binding.feedback } : {}),
519
+ ...(answer !== undefined ? { answer } : {}),
520
+ hostDecision,
521
+ };
522
+ const verifyRounds = verifyRoundsFromBody(ctx.body);
523
+ const driven = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, commitment: { kind: "gate_resolved", ...captureSelectedGate() }, verifyRounds, resumeCtx: { sessionId, ctx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(boundGrant ? { onResumeCommitted: boundGrant } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}), ...(ownerLeaseAdmittedHere ? { ownerLeaseAdmitted: true } : {}) });
524
+ noteLateSettleIfAccepted(driven);
525
+ return driven;
488
526
  }
489
- if (answer && (decision !== "approve" || pendingTool !== ASK_USER_QUESTION_TOOL_NAME)) {
490
- return { status: 400, body: refusalBody({ errorCode: "request.field_conflict", message: `body.answer is only valid when approving a pending AskUserQuestion (decision: "${decision}", pending: "${pendingTool ?? "unknown"}")`, facts: { ...fieldConflictFacts("ask_answer", ["answer", "decision"]) } }) };
527
+ finally {
528
+ resolved.peerLease.release();
491
529
  }
492
- const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
493
- const pa = cp.pendingAction;
494
- const persistedCallId = pa.kind === "tool_approval" ? pa.toolCallId : "";
495
- const persistedHash = pa.kind === "tool_approval" ? (pa.boundInputHash ?? "") : "";
496
- const outcome = {
497
- gate: "policy_ask",
498
- boundCallId: binding?.boundCallId ?? persistedCallId,
499
- boundInputHash: binding?.boundInputHash ?? persistedHash,
500
- decision: decision === "approve" ? "allow" : "deny",
501
- ...(decision === "approve" && binding?.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}),
502
- ...(reason ? { reason } : {}),
503
- ...(binding?.feedback !== undefined ? { feedback: binding.feedback } : {}),
504
- ...(answer !== undefined ? { answer } : {}),
505
- hostDecision,
506
- };
507
- const verifyRounds = verifyRoundsFromBody(ctx.body);
508
- const driven = await driveResumeIntoRunLog({ runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, verifyRounds, resumeCtx: { sessionId, ctx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(boundGrant ? { onResumeCommitted: boundGrant } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}), ...(ownerLeaseAdmittedHere ? { ownerLeaseAdmitted: true } : {}) });
509
- noteLateSettleIfAccepted(driven);
510
- return driven;
511
530
  }
512
531
  const ONE_SHOT_SUBMIT_KEYS = ["resumeAt", "restoreFiles", "acceptPartialRestore", "rewindFilesTo", "rewindFiles", "userAttachments", "images"];
513
532
  const ONE_SHOT_SUBMIT_STRIP = Object.fromEntries(ONE_SHOT_SUBMIT_KEYS.map((k) => [k, undefined]));
514
- const resolveResumeSpec = async (ctx, req, auth) => {
533
+ const resolveResumeSpec = async (ctx, req, auth, lease) => {
515
534
  const engineNotices = [];
516
535
  const spec = await deps.resolveSpec({ ...ctx.body, ...ONE_SHOT_SUBMIT_STRIP }, req, auth, {
517
536
  leg: "resume",
518
537
  onNotice: (n) => engineNotices.push(n),
519
538
  ...(ctx.unattendedLeg === true ? { unattendedLeg: true } : {}),
539
+ lease,
520
540
  });
521
541
  return { spec, engineNotices };
522
542
  };
@@ -528,11 +548,13 @@ export function createResumeLegs(ctx) {
528
548
  const replay = storedBodyReplayRefusal(ctx, deps.config);
529
549
  if (replay !== undefined)
530
550
  return { ok: false, answer: refuseStoredBodyReplay(auth.sessionId, replay) };
551
+ const lease = deps.peerDesk.lease("resume");
531
552
  try {
532
- const { spec, engineNotices } = await resolveResumeSpec(ctx, req, auth);
533
- return { ok: true, spec, engineNotices };
553
+ const { spec, engineNotices } = await resolveResumeSpec(ctx, req, auth, lease);
554
+ return { ok: true, spec, engineNotices, peerLease: lease };
534
555
  }
535
556
  catch (e) {
557
+ lease.release();
536
558
  if (e instanceof HttpError) {
537
559
  return { ok: false, answer: resumeRefusalWithCard(resumeBlockedByPolicyAnswer(httpErrorRefusal(e)), true) };
538
560
  }
@@ -541,11 +563,11 @@ export function createResumeLegs(ctx) {
541
563
  };
542
564
  async function driveResumeIntoRunLog(args) {
543
565
  if (args.acceptEarly !== true)
544
- return await driveResumeLeg(args);
566
+ return await heldFor(args.peerLease, () => driveResumeLeg(args));
545
567
  let settleAccepted;
546
568
  let wasAccepted = false;
547
569
  const accepted = new Promise((resolve) => { settleAccepted = resolve; });
548
- const leg = driveResumeLeg(args, (receipt) => { wasAccepted = true; settleAccepted?.(receipt); });
570
+ const leg = heldFor(args.peerLease, () => driveResumeLeg(args, (receipt) => { wasAccepted = true; settleAccepted?.(receipt); }));
549
571
  void leg.then((out) => {
550
572
  if (wasAccepted && out.status >= 400) {
551
573
  deps.logger?.warn?.("resume_leg_failed_after_accept", { sessionId: args.sessionId, status: out.status, body: out.body });
@@ -599,6 +621,7 @@ export function createResumeLegs(ctx) {
599
621
  const freshId = uuidv7();
600
622
  const created = await deps.runStore.createRun(freshId, sessionId, principal ?? null, deps.instanceId ?? "default", {
601
623
  source: args.mintFreshRun.source,
624
+ identity: args.mintFreshRun.identity,
602
625
  objectivePreview: buildRunObjectivePreview(resumeObjective ?? ""),
603
626
  });
604
627
  if (created.existing) {
@@ -725,6 +748,7 @@ export function createResumeLegs(ctx) {
725
748
  let unregisterEngineNotice;
726
749
  try {
727
750
  const instructionLeg = createInstructionSelectionLeg();
751
+ const legWiringSections = () => ({ instructions: instructionLeg.segment(), skills: runSkillsOf(taskConfig) });
728
752
  result = await instructionLeg.run(sessionId, () => withModelReachScope({ sessionId, taskId }, () => withPrincipal(principal, async () => {
729
753
  const resumeNotifiedKeys = new NotifiedKeys();
730
754
  if (deps.runStore && taskId) {
@@ -748,7 +772,7 @@ export function createResumeLegs(ctx) {
748
772
  persistThinking: deps.config.traceThinking,
749
773
  notifiedKeys: resumeNotifiedKeys,
750
774
  ...(taskId ? { onActivity: () => recordTurnActivity(taskId) } : {}),
751
- instructionsSegment: instructionLeg.segment,
775
+ legSections: legWiringSections,
752
776
  });
753
777
  const vAppend = (type, data) => verifySink.append(type, data);
754
778
  cancelLedgerAppend = vAppend;
@@ -820,7 +844,7 @@ export function createResumeLegs(ctx) {
820
844
  if (reSuspended || vrReopened) {
821
845
  await appendModelUsageDelta(ap, deps.modelUsage, taskId);
822
846
  const vrParkCallId = vrNested !== undefined ? await parkToolCallId({ terminal: vrNested }, deps.checkpointStore) : undefined;
823
- await ap(reParkStatus ?? reparkStatus, { gate: vrNested?.gate ?? null, ...(vrParkCallId !== undefined ? { toolCallId: vrParkCallId } : {}), ...(vrReopened ? { reopened: failureCodeOf(vr.terminal) ?? null } : {}) });
847
+ await ap(reParkStatus ?? reparkStatus, parkEventData({ terminal: vrNested, ...(vrParkCallId !== undefined ? { toolCallId: vrParkCallId } : {}) }, vrReopened ? (failureCodeOf(vr.terminal) ?? null) : undefined));
824
848
  }
825
849
  else {
826
850
  safe = await attachModelUsage(safe, { append: ap, getEvents: (id, a) => rs2.getEvents(id, a), modelUsage: deps.modelUsage, taskId });
@@ -882,6 +906,7 @@ export function createResumeLegs(ctx) {
882
906
  const driveResume = async () => {
883
907
  resumeLegLive = true;
884
908
  const tailContentMode = resumeTaskConfig.forwardSubagentEvents === true ? "on" : "progress_only";
909
+ const resumeWorkspace = createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), legSessionWitnessOf(resumeTaskConfig));
885
910
  const stream = await legRunner.resumeStream(token, outcome, { ...resumeTaskConfig, signal: cancelCtrl.signal, preemptSignal: preemptCtrl.signal }, {
886
911
  ...launchInternals,
887
912
  onForwardEvent: (e) => {
@@ -944,12 +969,14 @@ export function createResumeLegs(ctx) {
944
969
  if (taskId)
945
970
  steerableRuns.set(taskId, stream);
946
971
  if (!taskId || !rs) {
972
+ for await (const ev of stream)
973
+ await resumeWorkspace.observe(ev);
947
974
  const rNoRow = await stream.result();
948
975
  if (await reopenedAfterLeg(rNoRow, cancelCtrl.cause() !== undefined))
949
976
  reopenConfirmedPark = true;
950
977
  return sealResultForExit(rNoRow);
951
978
  }
952
- onAccepted?.(acceptedResumingReceipt(taskId, sessionId));
979
+ onAccepted?.(acceptedResumingReceipt(taskId, sessionId, buildSettlementEvidence({ at: "engine_accepted", commitment: args.commitment })));
953
980
  let causeAtDone;
954
981
  for await (const ev of stream) {
955
982
  if (ev.type === "done")
@@ -957,6 +984,7 @@ export function createResumeLegs(ctx) {
957
984
  recordTurnActivity(taskId);
958
985
  fleetPub?.onEvent(ev);
959
986
  await deps.userInputLedger?.observeLegEvent(stream, ev);
987
+ await resumeWorkspace.observe(ev);
960
988
  await appendPromptManifest(append, deps.promptManifests, taskId);
961
989
  switch (ev.type) {
962
990
  case "text_delta":
@@ -1017,7 +1045,7 @@ export function createResumeLegs(ctx) {
1017
1045
  break;
1018
1046
  case "wiring_manifest":
1019
1047
  await flush();
1020
- await append("wiring_manifest", wiringManifestEventData(ev, instructionLeg.segment()));
1048
+ await append("wiring_manifest", wiringManifestEventData(ev, legWiringSections()));
1021
1049
  break;
1022
1050
  case "tool_roster_delta": {
1023
1051
  await flush();
@@ -1074,20 +1102,19 @@ export function createResumeLegs(ctx) {
1074
1102
  const r = causeAtDone !== undefined ? mintCancelledResult({ taskId, sessionId, startedAtMs: resumeLegStartedAt, message: "cancelled by user", engineResult: rEngine, cause: causeAtDone }) : rEngine;
1075
1103
  const rPark = r.terminal.kind === "paused" ? outwardPlane(r.terminal).status : undefined;
1076
1104
  if (rPark === "suspended") {
1077
- const parkCallId = await parkToolCallId(r, deps.checkpointStore);
1078
- await append("suspended", { gate: r.terminal.kind === "paused" ? r.terminal.gate : null, ...(parkCallId !== undefined ? { toolCallId: parkCallId } : {}) });
1105
+ await append("suspended", parkEventData(await graftParkToolCallId(r, deps.checkpointStore)));
1079
1106
  await appendModelUsageDelta(append, deps.modelUsage, taskId);
1080
1107
  return r;
1081
1108
  }
1082
1109
  if (rPark === "needs_review") {
1083
- await append("needs_review", { gate: r.terminal.kind === "paused" ? r.terminal.gate : null });
1110
+ await append("needs_review", parkEventData(r));
1084
1111
  await appendModelUsageDelta(append, deps.modelUsage, taskId);
1085
1112
  return r;
1086
1113
  }
1087
1114
  if (await reopenedAfterLeg(r, causeAtDone !== undefined)) {
1088
1115
  reopenConfirmedPark = true;
1089
1116
  try {
1090
- await append(reparkStatus, { gate: null, reopened: failureCodeOf(r.terminal) ?? null });
1117
+ await append(reparkStatus, parkEventData(r, failureCodeOf(r.terminal) ?? null));
1091
1118
  await appendModelUsageDelta(append, deps.modelUsage, taskId);
1092
1119
  }
1093
1120
  catch {
@@ -1215,13 +1242,13 @@ export function createResumeLegs(ctx) {
1215
1242
  settleFleet(checkpointReopened ? reparkStatus : resumePlane.status, fleetRunResiduals(sealed));
1216
1243
  return {
1217
1244
  status: 200,
1218
- decisionCommitted: true,
1219
1245
  body: {
1220
1246
  taskId, sessionId, status: resumePlane.status,
1221
1247
  bindingEnforced: true,
1222
1248
  ...(resumePlane.errorCode ? { errorCode: resumePlane.errorCode } : {}),
1223
1249
  ...(resumePlane.errorMessage ? { errorMessage: redactErrorMessage(resumePlane.errorMessage) ?? "" } : {}),
1224
1250
  ...(checkpointReopened ? { retriable: true } : {}),
1251
+ ...buildSettlementEvidence({ at: "engine_terminal", commitment: args.commitment }),
1225
1252
  },
1226
1253
  };
1227
1254
  }
@@ -1296,10 +1323,16 @@ export function createResumeLegs(ctx) {
1296
1323
  const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
1297
1324
  if (!resolved.ok)
1298
1325
  return resolved.answer;
1299
- const { spec, engineNotices } = resolved;
1300
- const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
1301
- const verifyRounds = verifyRoundsFromBody(ctx.body);
1302
- return driveResumeIntoRunLog({ runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome: { gate: "resource_limit", decision: "continue" }, verifyRounds, resumeCtx: { sessionId, ctx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}) });
1326
+ try {
1327
+ const { spec, engineNotices } = resolved;
1328
+ const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
1329
+ const verifyRounds = verifyRoundsFromBody(ctx.body);
1330
+ const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
1331
+ return await driveResumeIntoRunLog({ peerLease: resolved.peerLease, runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome: { gate: "resource_limit", decision: "continue" }, commitment: { kind: "gate_resolved", ...selectedGate }, verifyRounds, resumeCtx: { sessionId, ctx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}) });
1332
+ }
1333
+ finally {
1334
+ resolved.peerLease.release();
1335
+ }
1303
1336
  }
1304
1337
  async function startFreshHostTurn(sessionId, objective, principal, req, workflowDecision, runId) {
1305
1338
  const cs = deps.checkpointStore;
@@ -1332,22 +1365,28 @@ export function createResumeLegs(ctx) {
1332
1365
  const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
1333
1366
  if (!resolved.ok)
1334
1367
  return resolved.answer;
1335
- const { spec, engineNotices } = resolved;
1336
- const hostSpec = { ...spec, objective, sessionId };
1337
- const out = await mintAndDriveDurableRun(routeCtxBase, deps.runStore, {
1338
- prepared: { spec: hostSpec, runner: runnerFor(hostSpec), auth, body: ctx.body, acceptance: createRunAcceptance({}, { objective }), ...(engineNotices.length > 0 ? { engineNotices } : {}) },
1339
- fleetScope: resumeFleetScope(req, auth),
1340
- elicitOwner: principal ?? null,
1341
- source: "workflow_parked_decide",
1342
- workflowDecision,
1343
- });
1344
- if (out.existing) {
1345
- throw new Error(`decide host turn: createRun observed an existing row ${out.existing.taskId} for a freshly minted taskId (no idempotency key was sent)`);
1368
+ try {
1369
+ const { spec, engineNotices } = resolved;
1370
+ const hostSpec = { ...spec, objective, sessionId };
1371
+ const out = await mintAndDriveDurableRun(routeCtxBase, deps.runStore, {
1372
+ prepared: { spec: hostSpec, runner: runnerFor(hostSpec), auth, body: ctx.body, acceptance: createRunAcceptance({}, { objective }), peerLease: resolved.peerLease, ...(engineNotices.length > 0 ? { engineNotices } : {}) },
1373
+ fleetScope: resumeFleetScope(req, auth),
1374
+ elicitOwner: principal ?? null,
1375
+ source: "workflow_parked_decide",
1376
+ identity: runIdentityOf(req, deps.config, principal ?? null),
1377
+ workflowDecision,
1378
+ });
1379
+ if (out.existing) {
1380
+ throw new Error(`decide host turn: createRun observed an existing row ${out.existing.taskId} for a freshly minted taskId (no idempotency key was sent)`);
1381
+ }
1382
+ if (out.status !== 202)
1383
+ return { status: out.status, body: out.body };
1384
+ const minted = out.body;
1385
+ return acceptedResumingReceipt(minted.taskId, minted.sessionId, NO_SETTLEMENT_EVIDENCE);
1386
+ }
1387
+ finally {
1388
+ resolved.peerLease.release();
1346
1389
  }
1347
- if (out.status !== 202)
1348
- return { status: out.status, body: out.body };
1349
- const minted = out.body;
1350
- return acceptedResumingReceipt(minted.taskId, minted.sessionId);
1351
1390
  }
1352
1391
  async function resumeWake(sessionId, message, caller, req, acceptEarly, workflowDecision, ownerLeaseAdmittedFor) {
1353
1392
  const cs = deps.checkpointStore;
@@ -1411,28 +1450,35 @@ export function createResumeLegs(ctx) {
1411
1450
  const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
1412
1451
  if (!resolved.ok)
1413
1452
  return resolved.answer;
1414
- const { spec, engineNotices } = resolved;
1415
- const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
1416
- return buildHostLegOutcome(await driveResumeIntoRunLog({
1417
- runner: runnerFor(spec),
1418
- token,
1419
- sessionId: cp.sessionId,
1420
- principal: auth.principal,
1421
- fleetScope: resumeFleetScope(req, auth),
1422
- taskConfig,
1423
- resumeObjective,
1424
- outcome: { gate: "wake", ...(message !== undefined ? { message: { text: message, trusted } } : {}) },
1425
- verifyRounds: undefined,
1426
- resumeCtx: { sessionId, ctx },
1427
- mintFreshRun: { source: "wake" },
1428
- ...(workflowDecision !== undefined ? { workflowDecision } : {}),
1429
- ...(engineNotices.length > 0 ? { engineNotices } : {}),
1430
- ...(acceptEarly === true ? { acceptEarly: true } : {}),
1431
- ...(req !== undefined ? { callerInitiated: true } : {}),
1432
- ...(ownerLeaseAdmittedFor !== undefined && auth.principal === ownerLeaseAdmittedFor ? { ownerLeaseAdmitted: true } : {}),
1433
- }));
1453
+ try {
1454
+ const { spec, engineNotices } = resolved;
1455
+ const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
1456
+ return await driveResumeIntoRunLog({
1457
+ peerLease: resolved.peerLease,
1458
+ runner: runnerFor(spec),
1459
+ token,
1460
+ sessionId: cp.sessionId,
1461
+ principal: auth.principal,
1462
+ fleetScope: resumeFleetScope(req, auth),
1463
+ taskConfig,
1464
+ resumeObjective,
1465
+ outcome: { gate: "wake", ...(message !== undefined ? { message: { text: message, trusted } } : {}) },
1466
+ commitment: { kind: "delivered" },
1467
+ verifyRounds: undefined,
1468
+ resumeCtx: { sessionId, ctx },
1469
+ mintFreshRun: { source: "wake", identity: runIdentityOf(req, deps.config, auth.principal ?? null) },
1470
+ ...(workflowDecision !== undefined ? { workflowDecision } : {}),
1471
+ ...(engineNotices.length > 0 ? { engineNotices } : {}),
1472
+ ...(acceptEarly === true ? { acceptEarly: true } : {}),
1473
+ ...(req !== undefined ? { callerInitiated: true } : {}),
1474
+ ...(ownerLeaseAdmittedFor !== undefined && auth.principal === ownerLeaseAdmittedFor ? { ownerLeaseAdmitted: true } : {}),
1475
+ });
1476
+ }
1477
+ finally {
1478
+ resolved.peerLease.release();
1479
+ }
1434
1480
  }
1435
- async function preparePlanReview(sessionId, log, decider) {
1481
+ async function preparePlanReview(sessionId, log, decider, sighting) {
1436
1482
  const cs = deps.checkpointStore;
1437
1483
  const refuse = (answer) => ({ ok: false, answer });
1438
1484
  const log404 = (r) => deps.logger?.info?.("decide_404", {
@@ -1490,6 +1536,13 @@ export function createResumeLegs(ctx) {
1490
1536
  }),
1491
1537
  });
1492
1538
  }
1539
+ if (sighting !== undefined) {
1540
+ const current = currentGateFacesOf(token, cp);
1541
+ if (!sightsCurrentGate(sighting, current)) {
1542
+ const currentId = decider !== undefined && cp.status === "pending" ? current.checkpointId : undefined;
1543
+ return refuse(approvalStaleAnswer(currentId !== undefined ? { currentPending: { checkpointId: currentId } } : {}));
1544
+ }
1545
+ }
1493
1546
  const ctxRead = await readResumeCtx(cs.getCtx(sessionId), ctxOpening(sessionId));
1494
1547
  if (ctxRead.kind === "corrupt")
1495
1548
  return refuse(resumeCtxCorruptAnswer(ctxRead.where));
@@ -1516,18 +1569,24 @@ export function createResumeLegs(ctx) {
1516
1569
  const resolved = await resolveResumeSpecOrBlocked(rebuildCtx, req, auth);
1517
1570
  if (!resolved.ok)
1518
1571
  return resolved.answer;
1519
- const { spec, engineNotices } = resolved;
1520
- const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
1521
- const verifyRounds = verifyRoundsFromBody(ctx.body);
1522
- const outcome = {
1523
- gate: "plan_review",
1524
- decision,
1525
- ...(editedPlan !== undefined ? { editedPlan } : {}),
1526
- ...(reason ? { reason } : {}),
1527
- hostDecision,
1528
- };
1529
- const out = await driveResumeIntoRunLog({ runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, verifyRounds, resumeCtx: { sessionId, ctx: rebuildCtx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}) });
1530
- return out;
1572
+ try {
1573
+ const { spec, engineNotices } = resolved;
1574
+ const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
1575
+ const verifyRounds = verifyRoundsFromBody(ctx.body);
1576
+ const outcome = {
1577
+ gate: "plan_review",
1578
+ decision,
1579
+ ...(editedPlan !== undefined ? { editedPlan } : {}),
1580
+ ...(reason ? { reason } : {}),
1581
+ hostDecision,
1582
+ };
1583
+ const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
1584
+ const out = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, commitment: { kind: "gate_resolved", ...selectedGate }, verifyRounds, resumeCtx: { sessionId, ctx: rebuildCtx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}) });
1585
+ return out;
1586
+ }
1587
+ finally {
1588
+ resolved.peerLease.release();
1589
+ }
1531
1590
  }
1532
1591
  const routeCtxBase = {
1533
1592
  deps,