@sema-agent/server 7.141.0 → 7.143.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 (341) hide show
  1. package/MIGRATION.md +657 -0
  2. package/USAGE.md +102 -30
  3. package/dist/adoption/plan.js +22 -0
  4. package/dist/approval-ask-audit-store.d.ts +61 -43
  5. package/dist/approval-ask-audit-store.js +69 -44
  6. package/dist/approval-ask-machine.d.ts +15 -7
  7. package/dist/approval-ask-machine.js +10 -4
  8. package/dist/approval-card.d.ts +126 -27
  9. package/dist/approval-card.js +103 -23
  10. package/dist/approval-crash-convergence.d.ts +17 -7
  11. package/dist/approval-crash-convergence.js +94 -22
  12. package/dist/approval-deny-reasons.d.ts +34 -30
  13. package/dist/approval-deny-reasons.js +21 -6
  14. package/dist/approval-policy-settlement.d.ts +1 -1
  15. package/dist/approval-queue-kind.d.ts +27 -0
  16. package/dist/approval-queue-kind.js +6 -0
  17. package/dist/approval-reconciler.d.ts +41 -9
  18. package/dist/approval-reconciler.js +45 -42
  19. package/dist/audit.js +4 -2
  20. package/dist/auth-bridge.d.ts +9 -6
  21. package/dist/auth-bridge.js +9 -3
  22. package/dist/boot/adoption.js +2 -1
  23. package/dist/boot/budget-tracing.d.ts +17 -1
  24. package/dist/boot/budget-tracing.js +10 -6
  25. package/dist/boot/device-lane.d.ts +1 -1
  26. package/dist/boot/execution-env.d.ts +24 -4
  27. package/dist/boot/execution-env.js +26 -23
  28. package/dist/boot/execution-lane.js +2 -1
  29. package/dist/boot/exit-boundary.js +5 -4
  30. package/dist/boot/governance-seams.d.ts +26 -41
  31. package/dist/boot/governance-seams.js +61 -28
  32. package/dist/boot/late-binds.d.ts +7 -4
  33. package/dist/boot/late-binds.js +3 -1
  34. package/dist/boot/leader.js +2 -4
  35. package/dist/boot/memory-consolidation.d.ts +0 -8
  36. package/dist/boot/memory-consolidation.js +5 -4
  37. package/dist/boot/parked-revive-gate.js +2 -1
  38. package/dist/boot/permission-rules-audit.d.ts +0 -28
  39. package/dist/boot/permission-rules-audit.js +2 -1
  40. package/dist/boot/read-deny-anchor-audit.js +2 -1
  41. package/dist/boot/reapers.js +9 -7
  42. package/dist/boot/resolve-spec.d.ts +1 -1
  43. package/dist/boot/resolve-spec.js +19 -10
  44. package/dist/boot/retention-lane.js +5 -3
  45. package/dist/boot/runner-deps.d.ts +10 -7
  46. package/dist/boot/runner-deps.js +20 -29
  47. package/dist/boot/runtime-caps.js +3 -2
  48. package/dist/boot/session-faces.js +4 -3
  49. package/dist/boot/shutdown.d.ts +9 -0
  50. package/dist/boot/shutdown.js +19 -4
  51. package/dist/boot/stage-02-web-admin-pull.js +3 -0
  52. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  53. package/dist/boot/stage-03-store-backend.js +1 -2
  54. package/dist/boot/stage-04-stores.d.ts +5 -2
  55. package/dist/boot/stage-04-stores.js +6 -7
  56. package/dist/boot/stage-05-execution-env.d.ts +6 -3
  57. package/dist/boot/stage-05-execution-env.js +8 -6
  58. package/dist/boot/stage-06-runners.d.ts +6 -3
  59. package/dist/boot/stage-06-runners.js +3 -4
  60. package/dist/boot/stage-07-capability-layer.d.ts +6 -3
  61. package/dist/boot/stage-07-capability-layer.js +7 -2
  62. package/dist/boot/stage-08-reapers.d.ts +6 -3
  63. package/dist/boot/stage-08-reapers.js +3 -2
  64. package/dist/boot/stage-09-leader.d.ts +6 -3
  65. package/dist/boot/stage-10-http-server.d.ts +6 -3
  66. package/dist/boot/stage-10-http-server.js +14 -5
  67. package/dist/boot/stores.d.ts +5 -2
  68. package/dist/boot/stores.js +10 -9
  69. package/dist/boot/web-admin.d.ts +5 -1
  70. package/dist/boot/web-admin.js +48 -36
  71. package/dist/boot/webfetch-summarize-lane.js +2 -1
  72. package/dist/boot/workflow-orchestration.js +3 -2
  73. package/dist/capabilities/builtin-tools.d.ts +2 -1
  74. package/dist/capabilities/builtin-tools.js +2 -4
  75. package/dist/capabilities/composite-members.d.ts +2 -1
  76. package/dist/capabilities/composite-members.js +2 -1
  77. package/dist/capabilities/hands-lane.d.ts +9 -39
  78. package/dist/capabilities/hands-lane.js +8 -13
  79. package/dist/capabilities/mcp-probe.d.ts +3 -2
  80. package/dist/capabilities/scenarios.d.ts +11 -1
  81. package/dist/capabilities/scenarios.js +1 -0
  82. package/dist/capabilities/skills.d.ts +1 -17
  83. package/dist/capabilities/skills.js +0 -8
  84. package/dist/capability-facts.d.ts +31 -7
  85. package/dist/capability-facts.js +27 -4
  86. package/dist/card-void.d.ts +6 -9
  87. package/dist/config-catalog.js +2 -1
  88. package/dist/config-dir-trust.js +58 -29
  89. package/dist/config-invariants.d.ts +7 -1
  90. package/dist/config-invariants.js +7 -0
  91. package/dist/config-provider.d.ts +10 -0
  92. package/dist/config-provider.js +15 -4
  93. package/dist/config-root-migration.d.ts +13 -0
  94. package/dist/config-root-migration.js +99 -0
  95. package/dist/config-types.d.ts +19 -8
  96. package/dist/config.d.ts +10 -3
  97. package/dist/config.js +18 -4
  98. package/dist/delegated-session-owner.d.ts +5 -3
  99. package/dist/delegated-session-owner.js +1 -1
  100. package/dist/device-ws-protocol.d.ts +1 -0
  101. package/dist/device-ws-protocol.js +2 -1
  102. package/dist/env-model-table-gate.d.ts +53 -0
  103. package/dist/env-model-table-gate.js +53 -0
  104. package/dist/execution-lane-caps.d.ts +2 -1
  105. package/dist/fleet/fleet-bus.d.ts +34 -55
  106. package/dist/fleet/fleet-bus.js +35 -100
  107. package/dist/fleet/fleet-reconciler.d.ts +4 -4
  108. package/dist/fleet/fleet-reconciler.js +1 -1
  109. package/dist/fleet/subagent-tail-bus.d.ts +14 -11
  110. package/dist/fleet/subagent-tail-bus.js +15 -28
  111. package/dist/hooks/hook-runner.d.ts +6 -0
  112. package/dist/hooks/hook-runner.js +58 -8
  113. package/dist/host-decision.d.ts +54 -20
  114. package/dist/host-decision.js +42 -14
  115. package/dist/http/admission.d.ts +1 -1
  116. package/dist/http/admission.js +7 -3
  117. package/dist/http/approval-sweeps.js +11 -8
  118. package/dist/http/caller-trust.d.ts +1 -1
  119. package/dist/http/dispatch.js +4 -2
  120. package/dist/http/durable-run-leg.js +2 -2
  121. package/dist/http/engine-refusal.d.ts +16 -0
  122. package/dist/http/engine-refusal.js +17 -0
  123. package/dist/http/execution-context.d.ts +2 -2
  124. package/dist/http/idempotency.d.ts +1 -1
  125. package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
  126. package/dist/http/memory-compliance-failure-reply.js +4 -6
  127. package/dist/http/owner-access.d.ts +11 -0
  128. package/dist/http/owner-access.js +13 -0
  129. package/dist/http/principal-gate.d.ts +3 -1
  130. package/dist/http/principal-gate.js +17 -8
  131. package/dist/http/resume-legs.d.ts +21 -7
  132. package/dist/http/resume-legs.js +76 -58
  133. package/dist/http/resume-restatement.d.ts +39 -0
  134. package/dist/http/resume-restatement.js +25 -0
  135. package/dist/http/route-ctx.d.ts +35 -10
  136. package/dist/http/route-ctx.js +1 -1
  137. package/dist/http/route-table.js +2 -0
  138. package/dist/http/routes/approvals-assistant.d.ts +9 -1
  139. package/dist/http/routes/approvals-assistant.js +142 -31
  140. package/dist/http/routes/attachments.js +18 -0
  141. package/dist/http/routes/capabilities.js +16 -4
  142. package/dist/http/routes/memory-policy.d.ts +2 -2
  143. package/dist/http/routes/memory-policy.js +27 -7
  144. package/dist/http/routes/notify-wake.js +23 -25
  145. package/dist/http/routes/rules.js +48 -13
  146. package/dist/http/routes/runs.js +12 -11
  147. package/dist/http/routes/session-memory-sync.d.ts +91 -0
  148. package/dist/http/routes/session-memory-sync.js +174 -0
  149. package/dist/http/routes/session-sync.js +13 -20
  150. package/dist/http/routes/sessions-list.d.ts +2 -1
  151. package/dist/http/routes/sessions.d.ts +2 -2
  152. package/dist/http/routes/sessions.js +22 -23
  153. package/dist/http/routes/tasks.js +34 -54
  154. package/dist/http/run-read-face.d.ts +7 -0
  155. package/dist/http/run-read-face.js +9 -3
  156. package/dist/http/send.d.ts +5 -0
  157. package/dist/http/send.js +9 -2
  158. package/dist/http/server.d.ts +27 -15
  159. package/dist/http/server.js +4 -6
  160. package/dist/http/stored-body-replay.js +15 -4
  161. package/dist/http/submit-replay.d.ts +4 -3
  162. package/dist/http/submit-replay.js +2 -2
  163. package/dist/http/sync-submit-body.d.ts +21 -4
  164. package/dist/http/sync-submit-body.js +13 -0
  165. package/dist/http/wire-types.d.ts +17 -7
  166. package/dist/identity-source.d.ts +21 -2
  167. package/dist/identity-source.js +6 -0
  168. package/dist/leader/leader.js +5 -2
  169. package/dist/leader/wire.d.ts +7 -1
  170. package/dist/leader/wire.js +6 -5
  171. package/dist/leg-facts.d.ts +37 -0
  172. package/dist/leg-facts.js +15 -0
  173. package/dist/memory-bundle-engine.d.ts +1 -4
  174. package/dist/memory-bundle-engine.js +2 -2
  175. package/dist/memory-incident-sink.d.ts +19 -6
  176. package/dist/memory-incident-sink.js +8 -4
  177. package/dist/memory-operator-faces.d.ts +30 -66
  178. package/dist/memory-operator-faces.js +17 -88
  179. package/dist/memory-scope-stores.d.ts +38 -40
  180. package/dist/memory-scope-stores.js +51 -36
  181. package/dist/memory-scope.d.ts +0 -9
  182. package/dist/memory-scope.js +0 -9
  183. package/dist/memory-sync-client.d.ts +21 -21
  184. package/dist/memory-sync-client.js +62 -43
  185. package/dist/memory-sync-identity.d.ts +24 -0
  186. package/dist/memory-sync-identity.js +57 -0
  187. package/dist/memory-sync.d.ts +27 -5
  188. package/dist/memory-sync.js +29 -7
  189. package/dist/model-plane-face.d.ts +13 -7
  190. package/dist/model-plane-face.js +2 -1
  191. package/dist/observability/fail-open.d.ts +47 -14
  192. package/dist/observability/fail-open.js +37 -11
  193. package/dist/observability/run-terminal.d.ts +92 -34
  194. package/dist/observability/run-terminal.js +171 -162
  195. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
  196. package/dist/orchestration/workflow-completion-inbox.js +0 -12
  197. package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
  198. package/dist/orchestration/workflow-park-decision.d.ts +8 -3
  199. package/dist/orchestration/workflow-park-decision.js +5 -3
  200. package/dist/org-delivery-gate.d.ts +11 -0
  201. package/dist/org-delivery-gate.js +19 -1
  202. package/dist/parked-decide.d.ts +13 -9
  203. package/dist/parked-decide.js +7 -7
  204. package/dist/parked-revive-surface.js +1 -1
  205. package/dist/peer-inbound-face.d.ts +127 -0
  206. package/dist/peer-inbound-face.js +158 -0
  207. package/dist/permission-rule-list.d.ts +13 -9
  208. package/dist/permission-rule-list.js +7 -3
  209. package/dist/plugins/approval-ask-store-file.d.ts +14 -4
  210. package/dist/plugins/approval-ask-store-file.js +64 -11
  211. package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
  212. package/dist/plugins/approval-ask-store-memory.js +17 -14
  213. package/dist/plugins/approval-ask-store-sql.d.ts +70 -23
  214. package/dist/plugins/approval-ask-store-sql.js +79 -30
  215. package/dist/plugins/checkpoint-store-sql.d.ts +4 -4
  216. package/dist/plugins/checkpoint-store-sql.js +9 -7
  217. package/dist/plugins/file-history-store-sql.d.ts +24 -18
  218. package/dist/plugins/file-history-store-sql.js +24 -19
  219. package/dist/plugins/file-run-store.d.ts +35 -1
  220. package/dist/plugins/file-run-store.js +108 -9
  221. package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
  222. package/dist/plugins/imported-layer-root-retirement.js +96 -0
  223. package/dist/plugins/local-checkpoint-store.d.ts +1 -1
  224. package/dist/plugins/local-checkpoint-store.js +2 -2
  225. package/dist/plugins/local-session-store.d.ts +42 -9
  226. package/dist/plugins/local-session-store.js +83 -33
  227. package/dist/plugins/local-task-attachment-store.d.ts +12 -2
  228. package/dist/plugins/local-task-attachment-store.js +67 -43
  229. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
  230. package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
  231. package/dist/plugins/mailbox-store-sql.d.ts +12 -8
  232. package/dist/plugins/mailbox-store-sql.js +76 -7
  233. package/dist/plugins/memory-key-guards.d.ts +3 -3
  234. package/dist/plugins/memory-run-store.d.ts +6 -1
  235. package/dist/plugins/memory-run-store.js +11 -1
  236. package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
  237. package/dist/plugins/memory-sync-store-pg.js +21 -0
  238. package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
  239. package/dist/plugins/memory-sync-store-tidb.js +13 -1
  240. package/dist/plugins/one-time-migrations.d.ts +58 -2
  241. package/dist/plugins/one-time-migrations.js +161 -4
  242. package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
  243. package/dist/plugins/org-delivery-quota-store.js +2 -12
  244. package/dist/plugins/park-commit-watch.d.ts +1 -1
  245. package/dist/plugins/permission-rule-store-file.d.ts +10 -1
  246. package/dist/plugins/permission-rule-store-file.js +15 -2
  247. package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
  248. package/dist/plugins/permission-rule-store-sql.js +35 -2
  249. package/dist/plugins/remote-env-device.d.ts +8 -11
  250. package/dist/plugins/remote-env-device.js +6 -3
  251. package/dist/plugins/remote-env-e2b.d.ts +23 -4
  252. package/dist/plugins/remote-env-e2b.js +111 -28
  253. package/dist/plugins/remote-env-k8s.d.ts +61 -22
  254. package/dist/plugins/remote-env-k8s.js +133 -33
  255. package/dist/plugins/remote-env-local-docker.d.ts +15 -3
  256. package/dist/plugins/remote-env-local-docker.js +40 -12
  257. package/dist/plugins/retention-store-sql.d.ts +2 -2
  258. package/dist/plugins/run-store-sql.d.ts +9 -1
  259. package/dist/plugins/run-store-sql.js +9 -1
  260. package/dist/plugins/sandbox-read-floor.d.ts +5 -7
  261. package/dist/plugins/sandbox-read-floor.js +2 -7
  262. package/dist/plugins/sql-errors.d.ts +10 -1
  263. package/dist/plugins/sql-errors.js +13 -0
  264. package/dist/plugins/store-backend.d.ts +33 -35
  265. package/dist/plugins/store-backend.js +10 -1
  266. package/dist/plugins/store-contracts.d.ts +50 -1
  267. package/dist/plugins/store-contracts.js +6 -0
  268. package/dist/plugins/task-attachment-store.d.ts +112 -14
  269. package/dist/plugins/task-attachment-store.js +207 -29
  270. package/dist/plugins/tool-result-store-sql.d.ts +9 -8
  271. package/dist/plugins/tool-result-store-sql.js +23 -2
  272. package/dist/plugins/wiring-section-codec.d.ts +32 -0
  273. package/dist/plugins/wiring-section-codec.js +55 -0
  274. package/dist/plugins/workspace-fill.d.ts +60 -0
  275. package/dist/plugins/workspace-fill.js +106 -0
  276. package/dist/project-bundle.d.ts +38 -0
  277. package/dist/project-bundle.js +609 -0
  278. package/dist/rule-entry-list.d.ts +3 -2
  279. package/dist/rule-entry-list.js +5 -1
  280. package/dist/rules-consent.d.ts +28 -5
  281. package/dist/rules-consent.js +40 -28
  282. package/dist/run-local.js +11 -13
  283. package/dist/runs.d.ts +12 -8
  284. package/dist/runs.js +6 -8
  285. package/dist/runtime-governance.d.ts +1 -1
  286. package/dist/sandbox-egress-policy.d.ts +4 -1
  287. package/dist/sandbox-egress-policy.js +3 -1
  288. package/dist/sandbox-git-plane.d.ts +31 -12
  289. package/dist/sandbox-git-plane.js +24 -4
  290. package/dist/security.d.ts +9 -0
  291. package/dist/security.js +8 -0
  292. package/dist/server-secret-env.d.ts +4 -0
  293. package/dist/session-error-wire.d.ts +36 -0
  294. package/dist/session-error-wire.js +13 -0
  295. package/dist/session-incarnation.d.ts +1 -1
  296. package/dist/session-notify-door.d.ts +106 -0
  297. package/dist/session-notify-door.js +93 -0
  298. package/dist/session-sync.d.ts +9 -14
  299. package/dist/session-sync.js +5 -5
  300. package/dist/session-workspace.d.ts +3 -13
  301. package/dist/session-workspace.js +0 -9
  302. package/dist/standing-answer-grant.d.ts +5 -0
  303. package/dist/standing-answer-grant.js +10 -0
  304. package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
  305. package/dist/stores-sql/session-policy-store-sql.js +3 -13
  306. package/dist/task-mcp.d.ts +1 -1
  307. package/dist/task-settings.d.ts +21 -10
  308. package/dist/task-settings.js +46 -13
  309. package/dist/terminal.d.ts +39 -19
  310. package/dist/terminal.js +65 -22
  311. package/dist/tool-approval.d.ts +56 -37
  312. package/dist/tool-approval.js +78 -71
  313. package/dist/trace/core-keyset-guard.d.ts +134 -14
  314. package/dist/trace/engine-notice-wire.d.ts +9 -3
  315. package/dist/trace/engine-notice-wire.js +7 -3
  316. package/dist/trace/exit-seat.d.ts +9 -2
  317. package/dist/trace/exit-seat.js +1 -0
  318. package/dist/trace/ledger-sink.d.ts +10 -6
  319. package/dist/trace/ledger-sink.js +2 -2
  320. package/dist/trace/model-segment.d.ts +55 -25
  321. package/dist/trace/model-segment.js +101 -33
  322. package/dist/trace/project.d.ts +25 -5
  323. package/dist/trace/project.js +22 -0
  324. package/dist/trace/redact.d.ts +61 -9
  325. package/dist/trace/redact.js +1490 -468
  326. package/dist/trace/self-minted-wire.d.ts +745 -24
  327. package/dist/trace/self-minted-wire.js +239 -9
  328. package/dist/trace/wire-projection-faces.d.ts +2 -2
  329. package/dist/trace/wire-projection-faces.js +2 -2
  330. package/dist/verifier-pause-card.d.ts +33 -5
  331. package/dist/verifier-pause-card.js +15 -10
  332. package/dist/web-admin-client/apply-effective.d.ts +12 -16
  333. package/dist/web-admin-client/apply-effective.js +109 -9
  334. package/dist/web-admin-client/effective-keys.js +2 -0
  335. package/dist/web-admin-client/types.d.ts +4 -0
  336. package/dist/workspace-space.d.ts +19 -3
  337. package/dist/workspace-space.js +8 -4
  338. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
  339. package/package.json +3 -2
  340. package/wire-changes/server@7.142.0.json +639 -0
  341. package/wire-changes/server@7.143.0.json +1167 -0
@@ -4,7 +4,7 @@ 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
+ import { createSessionWorkspaceRecorder, sessionWorkspaceStoreOf } from "../session-workspace.js";
8
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";
9
9
  import { HttpError, decodeCheckpointScope, CHECKPOINT_PUBLIC_SCOPE } from "../security.js";
10
10
  import { graftParkToolCallId, parkToolCallId, TurnAnchorCapture, HEARTBEAT_MS, markChildrenStoppedByUserOnAbort, voidHeldParkCard } from "../runs.js";
@@ -15,7 +15,7 @@ import { isTerminalRunStatus } from "../plugins/store-contracts.js";
15
15
  import { readTurnActivityMs, recordTurnActivity } from "../turn-activity.js";
16
16
  import { recordResumeResourceWindow } from "../resource-window.js";
17
17
  import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKeyOf, NotifiedKeys } from "../orchestration/workflow-completion-inbox.js";
18
- import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals, isFleetAgentTerminalNotification } from "../fleet/fleet-bus.js";
18
+ import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals } from "../fleet/fleet-bus.js";
19
19
  import { defaultSubagentTailBus } from "../fleet/subagent-tail-bus.js";
20
20
  import { currentApprovalGateToken, currentGateFacesOf, sightsCurrentGate } from "../approval-gate-currency.js";
21
21
  import { approverFacingArgs, createApprovalCardEmitter, declaredApprovalFrameFamilies, parkRowStandingAnswerFacts, resolveApprovalLeg, resolveStreamApprovalGate, standingAnswerDurablyRecordable } from "../tool-approval.js";
@@ -25,9 +25,9 @@ import { serviceVersion } from "../service-version.js";
25
25
  import { TERMINAL_PARK_GATE_KINDS } from "../plugins/checkpoint-store-sql.js";
26
26
  import { withPrincipal } from "../observability/principal-context.js";
27
27
  import { withModelReachScope } from "../model-reach-scope.js";
28
- import { runSkillsOf } from "../capabilities/skills.js";
28
+ import { legFactsOf } from "../leg-facts.js";
29
29
  import { createInstructionSelectionLeg } from "../instruction-selection.js";
30
- 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";
30
+ import { modelTextEventData, appendParkRow, 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
31
  import { redactSecrets } from "../trace/redact.js";
32
32
  import { buildRunObjectivePreview } from "../user-authored-text.js";
33
33
  import { createForwardAppendFailedNote, createLedgerSink, createSerialLedgerAppend } from "../trace/ledger-sink.js";
@@ -57,9 +57,11 @@ import { readResumeCtx, resumeCtxCorruptAnswer, resumeCtxUnsealableAnswer } from
57
57
  import { buildCheckpointVersionKeys, resumeBlockedByPolicyAnswer, resumeRefusalWithCard, sealCheckpointCtx, storedBodyReplayAnswer, storedBodyReplayLogFields, withPermissionModeRewritten } from "./checkpoint-ctx.js";
58
58
  import { refusalBody, resumeRefusalFacts } from "./refusal-body.js";
59
59
  import { storedBodyReplayRefusal } from "./stored-body-replay.js";
60
+ import { restateResumeCtx } from "./resume-restatement.js";
60
61
  import { httpErrorRefusal } from "./send.js";
61
62
  import { createRunAcceptance } from "../run-acceptance.js";
62
63
  import { fieldConflictFacts } from "../field-conflict.js";
64
+ import { createSessionNotifyDoor } from "../session-notify-door.js";
63
65
  function legMayHaveReopenedCheckpoint(r) {
64
66
  return r.terminal.kind === "failed" && nestedPauseOf(r.terminal) === undefined;
65
67
  }
@@ -107,6 +109,8 @@ const CHECKPOINT_ERROR_DISPOSITION = {
107
109
  "checkpoint.reopened_concurrently": "retriable",
108
110
  "resume.parent_constraint_missing": "retriable",
109
111
  "resume.parent_constraint_mismatch": "retriable",
112
+ "resume.composition_mismatch": "retriable",
113
+ "checkpoint.void_unpin_failed": "terminal",
110
114
  "resume.constraint_rejected": "retriable",
111
115
  "resume.constraint_unprojectable": "retriable",
112
116
  "resume.usage_window_exhausted": "retriable",
@@ -230,14 +234,19 @@ export function checkpointRefusalAnswer(e, at) {
230
234
  }),
231
235
  }, at.retriable);
232
236
  }
237
+ export function decidedActionOf(binding) {
238
+ const { boundCallId, boundInputHash } = binding;
239
+ const missingKeys = [...(typeof boundCallId === "string" && boundCallId.length > 0 ? [] : ["boundCallId"]), ...(typeof boundInputHash === "string" && boundInputHash.length > 0 ? [] : ["boundInputHash"])];
240
+ return missingKeys.length === 0 ? { action: { boundCallId: boundCallId, boundInputHash: boundInputHash } } : { missingKeys };
241
+ }
233
242
  export function createResumeLegs(ctx) {
234
243
  const { deps, runnerFor, idemCache, inflightRuns, preemptableRuns, steerableRuns, wakeParkMints, counters, readJson, readRawBody, rateLimited, quotaExceeded, ownerQuotaDenied, leaseDenied, ownerLeaseDenied, usageWindowDenied, safeDecode, runOwnerOk, sessionOwnerOk, runSessionAcceptOk, prepareSpec, finalizeTaskResult, ownerCostQuotaDenied, ownerFleetLeaseDenied, usageWindowDenialFor } = ctx;
235
244
  const ctxOpening = (sessionId) => ({ sessionId, opener: deps.checkpointCtxSealing });
236
245
  const resumeFleetScope = (req, auth) => req ? (gatedPrincipal(req, deps.config) ?? "default") : (auth.principal ?? "default");
237
- async function resumeCheckpoint(sessionId, decision, reason, hostDecision, req, answer, binding, onResumeCommitted, acceptEarly, decider) {
246
+ async function resumeCheckpoint(sessionId, decision, reason, hostDecision, req, answer, binding, onResumeCommitted, acceptEarly, decider, restatement) {
238
247
  const cs = deps.checkpointStore;
239
248
  const token = await currentApprovalGateToken(cs, sessionId);
240
- if (binding?.checkpointToken && !sightsCurrentGate({ face: "checkpointToken", value: binding.checkpointToken }, token ? { checkpointToken: token } : null)) {
249
+ if (binding.checkpointToken && !sightsCurrentGate({ face: "checkpointToken", value: binding.checkpointToken }, token ? { checkpointToken: token } : null)) {
241
250
  let seenUnreadable = false;
242
251
  const seen = await cs.get(binding.checkpointToken).catch((e) => {
243
252
  seenUnreadable = true;
@@ -326,20 +335,23 @@ export function createResumeLegs(ctx) {
326
335
  }),
327
336
  };
328
337
  }
329
- if (req !== undefined && !binding?.checkpointToken && !binding?.boundCallId) {
338
+ const decided = decidedActionOf(binding);
339
+ if (decided.action === undefined) {
330
340
  return {
331
341
  status: 400,
332
342
  body: refusalBody({
333
343
  errorCode: "decide_requires_binding",
334
- message: "decide requires the decision-action binding — echo checkpointToken and/or boundCallId from the pending approval (GET /v1/approvals)",
344
+ message: "decide requires the decision-action binding — echo boundCallId and boundInputHash exactly as the pending approval you are deciding shows them (GET /v1/approvals), so a decision on a view that has since been replaced is refused instead of landing on the gate that replaced it",
335
345
  facts: {
336
346
  bindingEnforced: true,
347
+ missingKeys: decided.missingKeys,
337
348
  },
338
349
  }),
339
350
  };
340
351
  }
352
+ const action = decided.action;
341
353
  const s57RowCallId = cp.pendingAction.kind === "tool_approval" ? cp.pendingAction.toolCallId : undefined;
342
- if (binding?.boundCallId !== undefined && s57RowCallId && binding.boundCallId !== s57RowCallId) {
354
+ if (s57RowCallId && action.boundCallId !== s57RowCallId) {
343
355
  let s57CurrentPending;
344
356
  if (decider !== undefined && cp.status === "pending" && cp.sessionId === sessionId && cp.pendingAction.kind === "tool_approval") {
345
357
  s57CurrentPending = {
@@ -400,8 +412,9 @@ export function createResumeLegs(ctx) {
400
412
  const parkedReq = {
401
413
  token, scope: cp.scope, sessionId: cp.sessionId, pendingAction: cp.pendingAction,
402
414
  decision, hostDecision, ...(reason !== undefined ? { reason } : {}),
403
- ...(binding !== undefined ? { binding: (({ checkpointToken: _staleGuardOnly, ...rest }) => rest)(binding) } : {}),
415
+ binding: { ...(({ checkpointToken: _staleGuardOnly, ...rest }) => rest)(binding), ...action },
404
416
  ...(answer !== undefined ? { answer } : {}),
417
+ ...(restatement !== undefined ? { restatement } : {}),
405
418
  ...(boundGrant ? { grantRemember: (rootSessionId) => boundGrant(rootSessionId) } : {}),
406
419
  };
407
420
  if (origin?.kind === "background" && parkedAgentStore !== undefined && parkedSurface !== undefined) {
@@ -458,7 +471,7 @@ export function createResumeLegs(ctx) {
458
471
  if (decisions === undefined || runStore === undefined) {
459
472
  return { status: 501, body: refusalBody({ errorCode: "capability.run_store_required", message: "delivering this decision requires a durable run store (DB_BACKEND=mysql|pg|local)" }) };
460
473
  }
461
- const fingerprint = parkDecisionFingerprint(plan.outcome);
474
+ const fingerprint = parkDecisionFingerprint(plan.outcome, restatement);
462
475
  const liveReceiptOf = async (held) => {
463
476
  if (held === null || held.fingerprint !== fingerprint)
464
477
  return undefined;
@@ -488,8 +501,8 @@ export function createResumeLegs(ctx) {
488
501
  .catch(() => undefined);
489
502
  const admittedPayer = decodeCheckpointScope(cp.scope);
490
503
  const out = hostToken
491
- ? await resumeWake(plan.hostSessionId, plan.message, decider?.principal, req, acceptEarly, delivery, admittedPayer)
492
- : await startFreshHostTurn(plan.hostSessionId, plan.message, admittedPayer, req, delivery, plan.runId);
504
+ ? await resumeWake(plan.hostSessionId, plan.message, decider?.principal, req, acceptEarly, delivery, admittedPayer, restatement)
505
+ : await startFreshHostTurn(plan.hostSessionId, plan.message, admittedPayer, req, delivery, plan.runId, restatement);
493
506
  if (recordFailure !== undefined)
494
507
  throw recordFailure.err;
495
508
  if (acceptedTaskIdOf(out) === undefined)
@@ -502,9 +515,10 @@ export function createResumeLegs(ctx) {
502
515
  return resumeCtxCorruptAnswer(ctxRead0.where);
503
516
  if (ctxRead0.kind === "unsealable")
504
517
  return resumeCtxUnsealableAnswer(ctxRead0);
505
- const ctx = ctxRead0.kind === "ok" ? ctxRead0.ctx : null;
506
- if (!ctx)
518
+ const storedCtx = ctxRead0.kind === "ok" ? ctxRead0.ctx : null;
519
+ if (!storedCtx)
507
520
  return { status: 409, body: refusalBody({ errorCode: "conflict.resume_context_unavailable", message: "resume context missing — cannot rebuild task config" }) };
521
+ const ctx = restateResumeCtx(storedCtx, restatement);
508
522
  const auth = { sessionId: cp.sessionId, principal: decodeCheckpointScope(cp.scope), memoryScope: ctx.memoryScope };
509
523
  const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
510
524
  if (!resolved.ok)
@@ -520,21 +534,19 @@ export function createResumeLegs(ctx) {
520
534
  }
521
535
  const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
522
536
  const pa = cp.pendingAction;
523
- const persistedCallId = pa.kind === "tool_approval" ? pa.toolCallId : "";
524
- const persistedHash = pa.kind === "tool_approval" ? (pa.boundInputHash ?? "") : "";
525
537
  const outcome = {
526
538
  gate: "policy_ask",
527
- boundCallId: binding?.boundCallId ?? persistedCallId,
528
- boundInputHash: binding?.boundInputHash ?? persistedHash,
539
+ boundCallId: action.boundCallId,
540
+ boundInputHash: action.boundInputHash,
529
541
  decision: decision === "approve" ? "allow" : "deny",
530
- ...(decision === "approve" && !isEngineQuestionRow(pa) && binding?.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}),
542
+ ...(decision === "approve" && !isEngineQuestionRow(pa) && binding.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}),
531
543
  ...(reason ? { reason } : {}),
532
- ...(binding?.feedback !== undefined ? { feedback: binding.feedback } : {}),
544
+ ...(binding.feedback !== undefined ? { feedback: binding.feedback } : {}),
533
545
  ...(answer !== undefined ? { answer } : {}),
534
546
  hostDecision,
535
547
  };
536
548
  const verifyRounds = verifyRoundsFromBody(ctx.body);
537
- const driven = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, 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 } : {}) });
549
+ const driven = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner: resolved.runner, legFacts: resolved.legFacts, 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 } : {}) });
538
550
  noteLateSettleIfAccepted(driven);
539
551
  return driven;
540
552
  }
@@ -547,14 +559,17 @@ export function createResumeLegs(ctx) {
547
559
  const resolveResumeSpec = async (ctx, req, auth, lease) => {
548
560
  const engineNotices = [];
549
561
  const execution = await resolveExecutionContext(deps, { kind: "continuation", root: auth.sessionId, principal: auth.principal });
550
- const spec = stampSpecRoot(await deps.resolveSpec({ ...ctx.body, ...ONE_SHOT_SUBMIT_STRIP }, req, auth, {
562
+ const resolved = await deps.resolveSpec({ ...ctx.body, ...ONE_SHOT_SUBMIT_STRIP }, req, auth, {
551
563
  leg: "resume",
552
564
  onNotice: (n) => engineNotices.push(n),
553
565
  ...(ctx.unattendedLeg === true ? { unattendedLeg: true } : {}),
554
566
  lease,
555
567
  execution,
556
- }), execution);
557
- return { spec, engineNotices, execution };
568
+ });
569
+ const legFacts = legFactsOf(resolved);
570
+ const runner = runnerFor(resolved);
571
+ const spec = stampSpecRoot(resolved, execution);
572
+ return { spec, runner, legFacts, engineNotices, execution };
558
573
  };
559
574
  const refuseStoredBodyReplay = (sessionId, refusal) => {
560
575
  deps.logger?.warn?.("resume_refused_stored_body", { sessionId, ...storedBodyReplayLogFields(refusal) });
@@ -566,8 +581,8 @@ export function createResumeLegs(ctx) {
566
581
  return { ok: false, answer: refuseStoredBodyReplay(auth.sessionId, replay) };
567
582
  const lease = deps.peerDesk.lease("resume");
568
583
  try {
569
- const { spec, engineNotices, execution } = await resolveResumeSpec(ctx, req, auth, lease);
570
- return { ok: true, spec, engineNotices, execution, peerLease: lease };
584
+ const { spec, runner, legFacts, engineNotices, execution } = await resolveResumeSpec(ctx, req, auth, lease);
585
+ return { ok: true, spec, runner, legFacts, engineNotices, execution, peerLease: lease };
571
586
  }
572
587
  catch (e) {
573
588
  lease.release();
@@ -603,7 +618,7 @@ export function createResumeLegs(ctx) {
603
618
  const reparkStatus = outcome.gate === "plan_review" ? "needs_review" : "suspended";
604
619
  const commitResumeCtx = () => Promise.resolve().then(() => deps.checkpointStore.putCtx(resumeCtx.sessionId, sealCheckpointCtx({ ...resumeCtx.ctx, writerVersion: serviceVersion() }, deps.checkpointCtxSealing, resumeCtx.sessionId))).catch((e) => {
605
620
  deps.metrics?.inc("resume_ctx_not_persisted_total");
606
- deps.logger?.warn?.("resume_ctx_not_persisted", { sessionId: resumeCtx.sessionId, gate: outcome.gate, error: errorText(e), note: "this continuation runs with the body it was given; the durable rebuild input still holds the PREVIOUS body, so the NEXT continuation of this session rebuilds from that one (never wider than this leg's)" });
621
+ deps.logger?.warn?.("resume_ctx_not_persisted", { sessionId: resumeCtx.sessionId, gate: outcome.gate, error: errorText(e), note: "this continuation runs with the body it was given; the durable rebuild input still holds the PREVIOUS body, so the NEXT continuation of this session rebuilds from that one — its permission mode is never wider than this leg's, but if this leg restated its MCP / A2A peer tables (mcpServers / a2aPeers on the resume request), a later continuation that does not restate them runs with the previous tables again" });
607
622
  });
608
623
  const legKey = createHash("sha256").update(String(token)).digest("hex");
609
624
  const streamApprovalOn = resolveStreamApprovalGate({
@@ -777,7 +792,7 @@ export function createResumeLegs(ctx) {
777
792
  let unregisterEngineNotice;
778
793
  try {
779
794
  const instructionLeg = createInstructionSelectionLeg();
780
- const legWiringSections = () => ({ instructions: instructionLeg.segment(), skills: runSkillsOf(taskConfig) });
795
+ const legWiringSections = () => ({ instructions: instructionLeg.segment(), skills: args.legFacts?.skills });
781
796
  result = await instructionLeg.run(sessionId, () => withModelReachScope({ sessionId, taskId }, () => withPrincipal(principal, async () => {
782
797
  const resumeNotifiedKeys = new NotifiedKeys();
783
798
  if (deps.runStore && taskId) {
@@ -832,9 +847,8 @@ export function createResumeLegs(ctx) {
832
847
  if (defaultSubagentTailBus.hasSubscribers(n.task_id)) {
833
848
  defaultSubagentTailBus.publish(n.task_id, { type: "task_settled", taskId: n.task_id, status: n.status, ...(typeof n.seq === "number" ? { seq: n.seq } : {}), ...(n.summary ? { summary: redactSecrets(n.summary) } : {}) });
834
849
  }
835
- const hadRow = isFleetAgentTerminalNotification(n) ? (fleetPub?.onChildTerminal(n.sessionId ?? n.task_id, n.status, n.task_id, n.toolUseId) ?? false) : false;
836
850
  const parked = !resumeLegLive && Boolean(deps.workflowCompletionInbox && sessionId);
837
- deps.logger?.info?.("task_notification_observed", { route: "resume-verify", taskId: n.task_id, taskType: n.task_type, status: n.status, hadFleetRow: hadRow, legLive: resumeLegLive, parkedDurable: parked });
851
+ deps.logger?.info?.("task_notification_observed", { route: "resume-verify", taskId: n.task_id, taskType: n.task_type, status: n.status, legLive: resumeLegLive, parkedDurable: parked });
838
852
  if (parked) {
839
853
  void deps.workflowCompletionInbox.enqueue(taskNotificationInboxEntry(sessionId, principal ?? null, n, Date.now(), taskId, opts?.priority)).catch((err) => deps.logger?.warn?.("park_enqueue_failed", { route: "resume-verify", taskId: n.task_id, err: err instanceof Error ? err.message : String(err) }));
840
854
  }
@@ -856,7 +870,7 @@ export function createResumeLegs(ctx) {
856
870
  resumeLegLive = true;
857
871
  const vrEngine = await resumeWithVerification(legRunner, token, outcome, { ...resumeTaskConfig, signal: cancelCtrl.signal, preemptSignal: preemptCtrl.signal }, resumeObjective, verifyRounds, verifyInternals);
858
872
  const vrCause = cancelCtrl.cause();
859
- await voidVerifierPauseCard(vrEngine, deps.checkpointStore);
873
+ await voidVerifierPauseCard(vrEngine, legRunner);
860
874
  const vrJudged = atHostBoundary(vrEngine, sessionId);
861
875
  if (vrJudged.terminal.kind === "paused")
862
876
  heldPark = vrJudged;
@@ -876,9 +890,8 @@ export function createResumeLegs(ctx) {
876
890
  const ap = vAppend;
877
891
  await appendPromptManifest(ap, deps.promptManifests, taskId);
878
892
  if (reSuspended || vrReopened) {
879
- await appendModelUsageDelta(ap, deps.modelUsage, taskId);
880
893
  const vrParkCallId = reSuspended ? await parkToolCallId(vr, deps.checkpointStore) : undefined;
881
- await ap(reParkEvent ?? reparkStatus, parkEventData({ terminal: vrPaused, ...(vrParkCallId !== undefined ? { toolCallId: vrParkCallId } : {}) }, vrReopened ? (failureCodeOf(vr.terminal) ?? null) : undefined));
894
+ await appendParkRow(ap, { modelUsage: deps.modelUsage, taskId }, reParkEvent ?? reparkStatus, { terminal: vrPaused, ...(vrParkCallId !== undefined ? { toolCallId: vrParkCallId } : {}) }, vrReopened ? (failureCodeOf(vr.terminal) ?? null) : undefined);
882
895
  }
883
896
  else {
884
897
  safe = await attachModelUsage(safe, { append: ap, getEvents: (id, a) => rs2.getEvents(id, a), modelUsage: deps.modelUsage, taskId });
@@ -940,7 +953,7 @@ export function createResumeLegs(ctx) {
940
953
  const driveResume = async () => {
941
954
  resumeLegLive = true;
942
955
  const tailContentMode = resumeTaskConfig.forwardSubagentEvents === true ? "on" : "progress_only";
943
- const resumeWorkspace = createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), legSessionWitnessOf(resumeTaskConfig));
956
+ const resumeWorkspace = createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), args.legFacts?.sessionWitness);
944
957
  const stream = await legRunner.resumeStream(token, outcome, { ...resumeTaskConfig, signal: cancelCtrl.signal, preemptSignal: preemptCtrl.signal }, {
945
958
  ...launchInternals,
946
959
  onForwardEvent: (e) => {
@@ -977,9 +990,8 @@ export function createResumeLegs(ctx) {
977
990
  if (defaultSubagentTailBus.hasSubscribers(n.task_id)) {
978
991
  defaultSubagentTailBus.publish(n.task_id, { type: "task_settled", taskId: n.task_id, status: n.status, ...(typeof n.seq === "number" ? { seq: n.seq } : {}), ...(n.summary ? { summary: redactSecrets(n.summary) } : {}) });
979
992
  }
980
- const hadRow = isFleetAgentTerminalNotification(n) ? (fleetPub?.onChildTerminal(n.sessionId ?? n.task_id, n.status, n.task_id, n.toolUseId) ?? false) : false;
981
993
  const parked = !resumeLegLive && Boolean(deps.workflowCompletionInbox && sessionId);
982
- deps.logger?.info?.("task_notification_observed", { route: "resume", taskId: n.task_id, taskType: n.task_type, status: n.status, hadFleetRow: hadRow, legLive: resumeLegLive, parkedDurable: parked });
994
+ deps.logger?.info?.("task_notification_observed", { route: "resume", taskId: n.task_id, taskType: n.task_type, status: n.status, legLive: resumeLegLive, parkedDurable: parked });
983
995
  if (parked) {
984
996
  void deps.workflowCompletionInbox.enqueue(taskNotificationInboxEntry(sessionId, principal ?? null, n, Date.now(), taskId, opts?.priority)).catch((err) => deps.logger?.warn?.("park_enqueue_failed", { route: "resume", taskId: n.task_id, err: err instanceof Error ? err.message : String(err) }));
985
997
  }
@@ -1141,21 +1153,18 @@ export function createResumeLegs(ctx) {
1141
1153
  heldPark = r;
1142
1154
  const rPark = r.terminal.kind === "paused" ? outwardPlane(r.terminal).status : undefined;
1143
1155
  if (rPark === "suspended") {
1144
- await append("suspended", parkEventData(await graftParkToolCallId(r, deps.checkpointStore)));
1145
- await appendModelUsageDelta(append, deps.modelUsage, taskId);
1156
+ await appendParkRow(append, { modelUsage: deps.modelUsage, taskId }, "suspended", await graftParkToolCallId(r, deps.checkpointStore));
1146
1157
  return r;
1147
1158
  }
1148
1159
  if (rPark === "needs_review") {
1149
- await append("needs_review", parkEventData(r));
1150
- await appendModelUsageDelta(append, deps.modelUsage, taskId);
1160
+ await appendParkRow(append, { modelUsage: deps.modelUsage, taskId }, "needs_review", r);
1151
1161
  return r;
1152
1162
  }
1153
1163
  const settledLeg = await reopenedAfterLeg(r, causeAtDone !== undefined);
1154
1164
  if (settledLeg.reopened) {
1155
1165
  reopenConfirmedPark = true;
1156
1166
  try {
1157
- await append(reparkStatus, parkEventData(r, failureCodeOf(r.terminal) ?? null));
1158
- await appendModelUsageDelta(append, deps.modelUsage, taskId);
1167
+ await appendParkRow(append, { modelUsage: deps.modelUsage, taskId }, reparkStatus, r, failureCodeOf(r.terminal) ?? null);
1159
1168
  }
1160
1169
  catch {
1161
1170
  }
@@ -1311,7 +1320,7 @@ export function createResumeLegs(ctx) {
1311
1320
  const owner = decodeCheckpointScope(scope ?? CHECKPOINT_PUBLIC_SCOPE);
1312
1321
  return owner === undefined || owner === decider.principal;
1313
1322
  }
1314
- async function resumePreempted(sessionId, req, acceptEarly, decider) {
1323
+ async function resumePreempted(sessionId, req, acceptEarly, decider, restatement) {
1315
1324
  const cs = deps.checkpointStore;
1316
1325
  const RESUMABLE_GATE_KIND = "resource_limit";
1317
1326
  const preemptBinding = { gateKinds: [RESUMABLE_GATE_KIND] };
@@ -1361,7 +1370,7 @@ export function createResumeLegs(ctx) {
1361
1370
  return resumeCtxUnsealableAnswer(ctxRead);
1362
1371
  if (ctxRead.kind === "absent")
1363
1372
  return { status: 409, body: refusalBody({ errorCode: "conflict.resume_context_unavailable", message: "resume context missing — cannot rebuild task config" }) };
1364
- const ctx = ctxRead.ctx;
1373
+ const ctx = restateResumeCtx(ctxRead.ctx, restatement);
1365
1374
  const auth = { sessionId: cp.sessionId, principal: decodeCheckpointScope(cp.scope), memoryScope: ctx.memoryScope };
1366
1375
  const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
1367
1376
  if (!resolved.ok)
@@ -1371,13 +1380,13 @@ export function createResumeLegs(ctx) {
1371
1380
  const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
1372
1381
  const verifyRounds = verifyRoundsFromBody(ctx.body);
1373
1382
  const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
1374
- return await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, 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 } : {}) });
1383
+ return await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner: resolved.runner, legFacts: resolved.legFacts, 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 } : {}) });
1375
1384
  }
1376
1385
  finally {
1377
1386
  resolved.peerLease.release();
1378
1387
  }
1379
1388
  }
1380
- async function startFreshHostTurn(sessionId, objective, principal, req, workflowDecision, runId) {
1389
+ async function startFreshHostTurn(sessionId, objective, principal, req, workflowDecision, runId, restatement) {
1381
1390
  const cs = deps.checkpointStore;
1382
1391
  if (!deps.runStore) {
1383
1392
  return { status: 501, body: refusalBody({ errorCode: "capability.run_store_required", message: "delivering this decision requires a durable run store (DB_BACKEND=mysql|pg|local)" }) };
@@ -1387,8 +1396,8 @@ export function createResumeLegs(ctx) {
1387
1396
  return resumeCtxCorruptAnswer(ctxRead.where);
1388
1397
  if (ctxRead.kind === "unsealable")
1389
1398
  return resumeCtxUnsealableAnswer(ctxRead);
1390
- const ctx = ctxRead.kind === "ok" ? ctxRead.ctx : null;
1391
- if (!ctx) {
1399
+ const storedCtx = ctxRead.kind === "ok" ? ctxRead.ctx : null;
1400
+ if (!storedCtx) {
1392
1401
  return {
1393
1402
  status: 409,
1394
1403
  body: refusalBody({
@@ -1401,6 +1410,7 @@ export function createResumeLegs(ctx) {
1401
1410
  }),
1402
1411
  };
1403
1412
  }
1413
+ const ctx = restateResumeCtx(storedCtx, restatement);
1404
1414
  const windowDenial = await usageWindowDenialFor(principal || GLOBAL_USAGE_KEY);
1405
1415
  if (windowDenial)
1406
1416
  return { status: windowDenial.status, body: windowDenial.body };
@@ -1412,7 +1422,7 @@ export function createResumeLegs(ctx) {
1412
1422
  const { spec, engineNotices } = resolved;
1413
1423
  const hostSpec = { ...spec, objective };
1414
1424
  const out = await mintAndDriveDurableRun(routeCtxBase, deps.runStore, {
1415
- prepared: { spec: hostSpec, runner: runnerFor(hostSpec), auth, body: ctx.body, acceptance: createRunAcceptance({}, { objective }), peerLease: resolved.peerLease, execution: resolved.execution, ...(engineNotices.length > 0 ? { engineNotices } : {}) },
1425
+ prepared: { spec: hostSpec, runner: resolved.runner, legFacts: resolved.legFacts, auth, body: ctx.body, acceptance: createRunAcceptance({}, { objective }), peerLease: resolved.peerLease, execution: resolved.execution, ...(engineNotices.length > 0 ? { engineNotices } : {}) },
1416
1426
  fleetScope: resumeFleetScope(req, auth),
1417
1427
  elicitOwner: principal ?? null,
1418
1428
  source: "workflow_parked_decide",
@@ -1431,7 +1441,7 @@ export function createResumeLegs(ctx) {
1431
1441
  resolved.peerLease.release();
1432
1442
  }
1433
1443
  }
1434
- async function resumeWake(sessionId, message, caller, req, acceptEarly, workflowDecision, ownerLeaseAdmittedFor) {
1444
+ async function resumeWake(sessionId, message, caller, req, acceptEarly, workflowDecision, ownerLeaseAdmittedFor, restatement) {
1435
1445
  const cs = deps.checkpointStore;
1436
1446
  const wakeBinding = { gateKinds: TERMINAL_PARK_GATE_KINDS, pick: "oldest" };
1437
1447
  const token = (await cs.findPendingTokenBySession(sessionId, undefined, wakeBinding)) ?? (await cs.findPendingTokenBySession(sessionId));
@@ -1488,7 +1498,7 @@ export function createResumeLegs(ctx) {
1488
1498
  return resumeCtxUnsealableAnswer(ctxRead);
1489
1499
  if (ctxRead.kind === "absent")
1490
1500
  return { status: 409, body: refusalBody({ errorCode: "conflict.resume_context_unavailable", message: "resume context missing — cannot rebuild task config" }) };
1491
- const ctx = ctxRead.ctx;
1501
+ const ctx = restateResumeCtx(ctxRead.ctx, restatement);
1492
1502
  const auth = { sessionId: cp.sessionId, principal: decodeCheckpointScope(cp.scope), memoryScope: ctx.memoryScope };
1493
1503
  const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
1494
1504
  if (!resolved.ok)
@@ -1499,7 +1509,8 @@ export function createResumeLegs(ctx) {
1499
1509
  return await driveResumeIntoRunLog({
1500
1510
  peerLease: resolved.peerLease,
1501
1511
  execution: resolved.execution,
1502
- runner: runnerFor(spec),
1512
+ runner: resolved.runner,
1513
+ legFacts: resolved.legFacts,
1503
1514
  token,
1504
1515
  sessionId: cp.sessionId,
1505
1516
  principal: auth.principal,
@@ -1599,8 +1610,9 @@ export function createResumeLegs(ctx) {
1599
1610
  return refuse(refuseStoredBodyReplay(sessionId, replay));
1600
1611
  return { ok: true, prepared: { sessionId, token, cp, ctx: ctxRead.ctx } };
1601
1612
  }
1602
- async function drivePlanReview(prepared, decision, editedPlan, reason, hostDecision, req, acceptEarly, permissionModeAfter) {
1603
- const { sessionId, token, cp, ctx } = prepared;
1613
+ async function drivePlanReview(prepared, decision, editedPlan, reason, hostDecision, req, acceptEarly, permissionModeAfter, restatement) {
1614
+ const { sessionId, token, cp } = prepared;
1615
+ const ctx = restateResumeCtx(prepared.ctx, restatement);
1604
1616
  if ((await deps.checkpointStore.findPendingTokenBySession(sessionId, undefined, { gateKinds: ["plan_review"] })) !== token)
1605
1617
  return notResumableAnswer();
1606
1618
  const auth = { sessionId: cp.sessionId, principal: decodeCheckpointScope(cp.scope), memoryScope: ctx.memoryScope };
@@ -1625,20 +1637,26 @@ export function createResumeLegs(ctx) {
1625
1637
  hostDecision,
1626
1638
  };
1627
1639
  const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
1628
- const out = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, 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 } : {}) });
1640
+ const out = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner: resolved.runner, legFacts: resolved.legFacts, 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 } : {}) });
1629
1641
  return out;
1630
1642
  }
1631
1643
  finally {
1632
1644
  resolved.peerLease.release();
1633
1645
  }
1634
1646
  }
1647
+ const sessionNotifyDoor = createSessionNotifyDoor({
1648
+ activeTaskIdOf: async (sessionId) => deps.runStore?.getActiveTaskId?.(sessionId),
1649
+ liveRuns: steerableRuns,
1650
+ inbox: deps.workflowCompletionInbox,
1651
+ headOf: headReadOf(deps.sessionStorage),
1652
+ });
1635
1653
  const routeCtxBase = {
1636
1654
  deps,
1637
1655
  registry: { idemCache, inflightRuns, preemptableRuns, steerableRuns, wakeParkMints, counters },
1638
1656
  helpers: { readJson, readRawBody, rateLimited, quotaExceeded, ownerQuotaDenied, leaseDenied, ownerLeaseDenied, usageWindowDenied, safeDecode, runOwnerOk, sessionOwnerOk, runSessionAcceptOk },
1639
1657
  local: { images: createImagesLocal(deps), sessions: createSessionsLocal(), sessionSync: createSessionSyncLocal(), capabilities: createCapabilitiesLocal() },
1640
- legs: { prepareSpec, finalizeTaskResult, resumeCheckpoint, driveResumeIntoRunLog, resumePreempted, resumeWake, preparePlanReview, drivePlanReview },
1658
+ legs: { prepareSpec, finalizeTaskResult, resumeCheckpoint, driveResumeIntoRunLog, resumePreempted, resumeWake, preparePlanReview, drivePlanReview, sessionNotify: sessionNotifyDoor },
1641
1659
  };
1642
- return { routeCtxBase, resumeCheckpoint, driveResumeIntoRunLog, driveResumeLeg, mayDiscloseRowError, resumePreempted, startFreshHostTurn, resumeWake, preparePlanReview, drivePlanReview };
1660
+ return { routeCtxBase, resumeCheckpoint, driveResumeIntoRunLog, driveResumeLeg, mayDiscloseRowError, resumePreempted, startFreshHostTurn, resumeWake, preparePlanReview, drivePlanReview, sessionNotifyDoor };
1643
1661
  }
1644
1662
  //# sourceMappingURL=resume-legs.js.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 续跑请求的**重述键** —— 「我此刻的对端表」随续跑请求一起说出来(唯一属主)。
3
+ *
4
+ * ## 律(一条)
5
+ * 续跑请求体可带 {@link RESUME_RESTATABLE_KEYS} 里的键(今天两只:`mcpServers` / `a2aPeers`),键名与值形 = 提交体(`POST /v1/tasks`)的同一键:
6
+ * · **在场**(值不是 `undefined` / `null`)⇒ 先过提交腿**同一只**判官(`assertRequestMcpEntries` / `assertRequestA2aEntries`;坏形 = 与提交腿同码同句的
7
+ * 400,判在续跑腿任何状态改动之前),再**取代**续跑重建输入(`checkpoint_ctx` 体)里的那一键:本次重建读它,续跑赢下 CAS 之后随重建输入一起写回
8
+ * (`DriveResumeArgs.resumeCtx` 那一只写点)⇒ 之后的续跑在没有新重述时重放的也是它;
9
+ * · **缺席**(或 `null`,与提交体「缺席或 `null` = 没声明」同一读法)⇒ 存量体那一键原样重放(冻结读法)。
10
+ * 重建之后的路与存量体逐字同一条(`resolveSpec` 的续跑腿:部署锁、闸、部署保留名、合并、对端座登记、用户面通告),所以一份重述在本部署上能挂上什么,
11
+ * 与它作为一次新提交能挂上什么是同一个答案;引擎从 `ResumeTaskConfig.mcp` / `.a2a`(与 `TaskSpec` 同键)收到的就是这张表。
12
+ *
13
+ * ## 不在本仓判的
14
+ * 「停驻快照里那一只调用的目标台还在不在当前表里」是引擎续跑准入的判(引擎 7.61.0 起三码各答各形,以 core 为准:工具不在了 ⇒ `resume.tool_unavailable`、同名而已不是批准时那一只 ⇒ `resume.tool_contract_mismatch`(两者重开检查点)、还是那一只而面或声明变了 ⇒ `resume.target_moved`(否决);本服务逐字过境)—— 本服务只负责把当前表送到,不自判、不预拒。
15
+ *
16
+ * ## 为什么是一张闭表
17
+ * 与提交腿的一次性动作那张闭表(`resume-legs.ts` 的 `ONE_SHOT_SUBMIT_KEYS`:重建时剥掉)对称 —— 那张说「哪些提交键不随重建走」,这张说「哪些提交键由续跑请求重述」。
18
+ * 加一键 = 改这条律本身:判官表 {@link RESTATEMENT_JUDGES} 缺行即编译红,接收它的续跑门各自在键闭集里声明它。
19
+ */
20
+ import type { TaskRequestBody } from "./wire-types.js";
21
+ import type { CheckpointCtx } from "./route-ctx.js";
22
+ /** 续跑请求可重述的提交键(闭集;`satisfies` 钉在提交体的具名键上 —— 写一个提交体上没有的词 = 编译红)。 */
23
+ export declare const RESUME_RESTATABLE_KEYS: readonly ["a2aPeers", "mcpServers"];
24
+ export type ResumeRestatableKey = (typeof RESUME_RESTATABLE_KEYS)[number];
25
+ /** 一次续跑请求读出的重述(只含在场的键;读者 {@link readResumeRestatement},用者 {@link restateResumeCtx})。 */
26
+ export type ResumeRestatement = {
27
+ readonly [K in ResumeRestatableKey]?: TaskRequestBody[K];
28
+ };
29
+ /**
30
+ * 从一份续跑请求体里读出重述:在场的键逐一过判官,全部过 ⇒ 交回只含在场键的重述;一键都不在 ⇒ `undefined`(冻结读法)。
31
+ * 判官的拒原样抛出(调用方是路由,`HttpError` 由分发器按提交腿同一只渲染器落 wire)。体不是对象 ⇒ `undefined`(体形由各门自己的根形门答)。
32
+ */
33
+ export declare function readResumeRestatement(body: unknown): ResumeRestatement | undefined;
34
+ /**
35
+ * 把重述盖进续跑重建输入:在场的键取代体里的同名键,其余位(记忆域 / 无人值守标 / 读法记号 / 写者版本)原样随行。`undefined` ⇒ 原 ctx 原样(同一个对象)。
36
+ * 各续跑腿在读出 ctx 的那一拍调一次,之后重建(`resolveResumeSpecOrBlocked`)与写回(`resumeCtx`)读的都是这一份。
37
+ */
38
+ export declare function restateResumeCtx(ctx: CheckpointCtx, restatement: ResumeRestatement | undefined): CheckpointCtx;
39
+ //# sourceMappingURL=resume-restatement.d.ts.map
@@ -0,0 +1,25 @@
1
+ import { assertRequestMcpEntries } from "../task-mcp.js";
2
+ import { assertRequestA2aEntries } from "../task-a2a.js";
3
+ export const RESUME_RESTATABLE_KEYS = ["a2aPeers", "mcpServers"];
4
+ const RESTATEMENT_JUDGES = {
5
+ a2aPeers: assertRequestA2aEntries,
6
+ mcpServers: assertRequestMcpEntries,
7
+ };
8
+ export function readResumeRestatement(body) {
9
+ if (body === null || typeof body !== "object" || Array.isArray(body))
10
+ return undefined;
11
+ const raw = body;
12
+ let out;
13
+ for (const key of RESUME_RESTATABLE_KEYS) {
14
+ const value = Object.hasOwn(raw, key) ? raw[key] : undefined;
15
+ if (value === undefined || value === null)
16
+ continue;
17
+ RESTATEMENT_JUDGES[key](value);
18
+ (out ??= {})[key] = value;
19
+ }
20
+ return out;
21
+ }
22
+ export function restateResumeCtx(ctx, restatement) {
23
+ return restatement === undefined ? ctx : { ...ctx, body: { ...ctx.body, ...restatement } };
24
+ }
25
+ //# sourceMappingURL=resume-restatement.js.map