@sema-agent/core 7.5.2 → 7.6.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 (85) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/agents/cascade.d.ts +2 -2
  3. package/dist/agents/cascade.js +12 -10
  4. package/dist/agents/repair-loop.d.ts +5 -3
  5. package/dist/agents/repair-loop.js +13 -15
  6. package/dist/agents/subagent.d.ts +24 -42
  7. package/dist/agents/subagent.js +119 -105
  8. package/dist/agents/suspend-guard.d.ts +31 -19
  9. package/dist/agents/suspend-guard.js +14 -8
  10. package/dist/agents/teacher.js +9 -9
  11. package/dist/agents/team.d.ts +4 -3
  12. package/dist/agents/team.js +10 -8
  13. package/dist/agents/verify.d.ts +3 -3
  14. package/dist/agents/verify.js +17 -17
  15. package/dist/core/a2a.js +2 -1
  16. package/dist/core/ask-origin.d.ts +60 -7
  17. package/dist/core/ask-origin.js +26 -1
  18. package/dist/core/checkpoint-store.d.ts +78 -76
  19. package/dist/core/checkpoint-store.js +17 -1
  20. package/dist/core/gate-outcome.d.ts +189 -0
  21. package/dist/core/gate-outcome.js +70 -0
  22. package/dist/core/hooks.d.ts +18 -92
  23. package/dist/core/hooks.js +88 -85
  24. package/dist/core/mcp-failure.d.ts +104 -0
  25. package/dist/core/mcp-failure.js +128 -0
  26. package/dist/core/mcp.d.ts +21 -77
  27. package/dist/core/mcp.js +76 -150
  28. package/dist/core/pause-registry.d.ts +131 -0
  29. package/dist/core/pause-registry.js +27 -0
  30. package/dist/core/runner/assemble-result.d.ts +32 -41
  31. package/dist/core/runner/assemble-result.js +55 -74
  32. package/dist/core/runner/contracts.d.ts +46 -64
  33. package/dist/core/runner/denial-limit-arms.d.ts +1 -1
  34. package/dist/core/runner/denial-limit-arms.js +3 -3
  35. package/dist/core/runner/gate-exit.d.ts +74 -0
  36. package/dist/core/runner/gate-exit.js +55 -0
  37. package/dist/core/runner/park-commit.d.ts +17 -23
  38. package/dist/core/runner/park-commit.js +14 -15
  39. package/dist/core/runner/prepare-ask-lane.d.ts +0 -3
  40. package/dist/core/runner/prepare-ask-lane.js +3 -5
  41. package/dist/core/runner/prepare-boundary-parks.d.ts +3 -6
  42. package/dist/core/runner/prepare-boundary-parks.js +3 -3
  43. package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
  44. package/dist/core/runner/prepare-gate-stations.d.ts +4 -7
  45. package/dist/core/runner/prepare-gate-stations.js +29 -54
  46. package/dist/core/runner/prepare-inherited-gate.js +1 -1
  47. package/dist/core/runner/prepare-memory.d.ts +44 -26
  48. package/dist/core/runner/prepare-park-ask.d.ts +2 -4
  49. package/dist/core/runner/prepare-park-ask.js +5 -5
  50. package/dist/core/runner/prepare-task.js +8 -9
  51. package/dist/core/runner/prepare-wiring-manifest.d.ts +7 -15
  52. package/dist/core/runner/prepare-wiring-manifest.js +9 -10
  53. package/dist/core/runner/runtask.d.ts +16 -31
  54. package/dist/core/runner/runtask.js +109 -120
  55. package/dist/core/runner/terminal-projection.d.ts +22 -0
  56. package/dist/core/runner/terminal-projection.js +28 -0
  57. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +4 -1
  58. package/dist/core/store-contracts/checkpoint-store-contract.js +8 -2
  59. package/dist/core/terminal-cause.d.ts +137 -0
  60. package/dist/core/terminal-cause.js +9 -0
  61. package/dist/core/tool-policy.d.ts +43 -139
  62. package/dist/core/tool-policy.js +79 -112
  63. package/dist/core/types.d.ts +67 -164
  64. package/dist/core/wiring-manifest.d.ts +6 -3
  65. package/dist/core/workflow-journal-store.js +3 -4
  66. package/dist/engine/harness/agent-harness.d.ts +1 -1
  67. package/dist/index.d.ts +10 -7
  68. package/dist/index.js +8 -5
  69. package/dist/orchestration/builtin-workflows.d.ts +2 -2
  70. package/dist/orchestration/builtin-workflows.js +1 -1
  71. package/dist/orchestration/goal.js +8 -7
  72. package/dist/orchestration/run-spec.js +5 -3
  73. package/dist/orchestration/run-workflow-tool.d.ts +1 -1
  74. package/dist/orchestration/run-workflow-tool.js +4 -4
  75. package/dist/orchestration/workflow-governance.d.ts +4 -4
  76. package/dist/orchestration/workflow-governance.js +4 -2
  77. package/dist/orchestration/workflow-primitives.d.ts +1 -1
  78. package/dist/orchestration/workflow-primitives.js +1 -1
  79. package/dist/orchestration/workflow.d.ts +11 -0
  80. package/dist/orchestration/workflow.js +64 -39
  81. package/dist/prompts/supervisor.d.ts +1 -1
  82. package/dist/prompts/supervisor.js +3 -3
  83. package/dist/scenarios/scenario-registry.js +1 -1
  84. package/package.json +3 -1
  85. package/test/export-surface.snapshot.json +74 -22
@@ -7,26 +7,25 @@ export function sanitizedTtlMs(ttlMs) {
7
7
  return Number.isFinite(ttlMs) && ttlMs > 0 ? ttlMs : DEFAULT_RESOURCE_TTL_MS;
8
8
  }
9
9
  export function gatedCallIdOf(p) {
10
- if (p.suspendRef.token !== undefined)
11
- return p.suspendRef.gatedCallId;
12
- if (p.reviewRef.token !== undefined)
13
- return p.reviewRef.gatedCallId;
14
- return undefined;
10
+ return p.pausedRef.current?.gatedCallId;
15
11
  }
16
12
  export function parkContaminationMarker(refs) {
17
- if (refs.suspendRef.token === undefined && refs.reviewRef.token === undefined)
13
+ if (refs.pausedRef.current === undefined)
18
14
  return undefined;
19
15
  const gatedCallId = gatedCallIdOf(refs);
20
16
  return { code: "gate.parked", ...(gatedCallId !== undefined ? { gatedCallId } : {}) };
21
17
  }
22
18
  export function publishCommittedSuspend(refs, token, gate, scope, remoteHandle, checkpointId, pendingAction) {
23
- const ref = gate.kind === "needs_review" || gate.kind === "plan_review" ? refs.reviewRef : refs.suspendRef;
24
- ref.token = token;
25
- if (checkpointId !== undefined)
26
- ref.checkpointId = checkpointId;
27
- ref.gate = gate;
28
- ref.gatedCallId = pendingAction?.kind === "tool_approval" ? pendingAction.toolCallId : undefined;
29
- if (remoteHandle !== undefined)
30
- ref.restoreMode = remoteHandle.restoreMode === "park_only" ? "park_only" : "snapshot";
31
- ref.scope = scope;
19
+ const pause = {
20
+ cause: {
21
+ kind: "paused",
22
+ gate,
23
+ token,
24
+ ...(checkpointId !== undefined ? { checkpointId } : {}),
25
+ ...(remoteHandle !== undefined ? { restoreMode: remoteHandle.restoreMode === "park_only" ? "park_only" : "snapshot" } : {}),
26
+ },
27
+ scope,
28
+ ...(pendingAction?.kind === "tool_approval" ? { gatedCallId: pendingAction.toolCallId } : {}),
29
+ };
30
+ refs.pausedRef.current = pause;
32
31
  }
@@ -60,9 +60,6 @@ export interface PrepareAskLaneInput {
60
60
  * synchronous resolve that a person actually judged (count / totalWaitMs / gates push); runtask adds the durable
61
61
  * resume latency. */
62
62
  humanReviewRef: Prepared["humanReviewRef"];
63
- /** borrowed-mutable — the bare-human-rejection sideband. Writer here: a `settledBy:"human"` deny with no note
64
- * (`add`); the gate station judges and sweeps it. */
65
- humanBareRejections: Set<string>;
66
63
  /** borrowed-readonly — the injectable wall clock every human-time observable reads (`Prepared.now`). */
67
64
  now: () => number;
68
65
  /** borrowed-readonly — the policy-chain phase's rule-offer factory (the suggestion members the ask mint threads). */
@@ -55,7 +55,7 @@ function resolveApprovalPreview(tools, toolName, args) {
55
55
  }
56
56
  }
57
57
  export function prepareAskLane(input) {
58
- const { gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, humanBareRejections, now, ruleOffersOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash } = input;
58
+ const { gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash } = input;
59
59
  if (!gateMachineryActive)
60
60
  return { askLane: undefined };
61
61
  const composedCallSignal = (callSignal) => composeCallSignal(abortController.signal, callSignal);
@@ -77,6 +77,7 @@ export function prepareAskLane(input) {
77
77
  `(no live approver reachable, or a durable-park mandate applies), and no durable approval park is ` +
78
78
  `available — denied fail-closed (the inherited constraint stands).`,
79
79
  decisionReason: "mode",
80
+ settlement: { kind: "approver_unavailable", who: { party: "none" }, when: now() },
80
81
  approverUnavailable: true,
81
82
  };
82
83
  }
@@ -104,7 +105,7 @@ export function prepareAskLane(input) {
104
105
  ...(decision.action === "ask" && decision.ruleEvidence !== undefined ? { ruleEvidence: decision.ruleEvidence } : {}),
105
106
  }, onAsk, composedCallSignal(callSignal), lateAskSettlementObserver({ toolName: req.toolName, toolCallId: req.toolCallId, sessionId, runId, ...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}), onNotice: deps.onNotice, onError: deps.onError }));
106
107
  const waitMs = Math.max(0, now() - t0);
107
- if (resolved.approverUnavailable !== true && resolved.resolution !== "task_aborted") {
108
+ if (resolved.approverUnavailable !== true && resolved.settlement?.kind !== "task_aborted") {
108
109
  humanReviewRef.count += 1;
109
110
  humanReviewRef.totalWaitMs += waitMs;
110
111
  const toolArg = primaryActivityArg(req.args);
@@ -116,9 +117,6 @@ export function prepareAskLane(input) {
116
117
  ...(toolArg !== undefined ? { toolArg } : {}),
117
118
  });
118
119
  }
119
- if (resolved.action === "deny" && resolved.settledBy === "human" && resolved.humanRefusalNote !== true) {
120
- humanBareRejections.add(req.toolCallId);
121
- }
122
120
  return resolved;
123
121
  };
124
122
  const notifyPermissionDenied = createDenyObserverNotifier(hooks, hookTimeoutMs, abortController.signal, notifyOwnHookCrash);
@@ -78,12 +78,9 @@ export interface PrepareBoundaryParksInput {
78
78
  f012CheckpointState: () => boolean;
79
79
  /** borrowed-readonly — see `faceCheckpointState`. */
80
80
  orgAdmissionCheckpointState: () => boolean;
81
- /** borrowed-mutable — the durable-suspend holder (`Prepared.suspendRef`). Writer here: the commit-side publication of a
82
- * committed resource row. */
83
- suspendRef: Prepared["suspendRef"];
84
- /** borrowed-mutable — the review holder (`Prepared.reviewRef`). Writer here: the commit-side publication of a committed
85
- * plan_review row. */
86
- reviewRef: Prepared["reviewRef"];
81
+ /** borrowed-mutable — the run's committed-pause holder (`Prepared.pausedRef`). Writer here: the commit-side publication
82
+ * of a committed resource / platform / plan-review checkpoint. */
83
+ pausedRef: Prepared["pausedRef"];
87
84
  /** borrowed-mutable — the run-scoped remote-lifecycle failure log. Writer here: a refused `suspendVM` (`push`). */
88
85
  remoteEnvFailures: Prepared["remoteEnvFailures"];
89
86
  /** borrowed-readonly — the wiring-manifest phase's task-axis predicate (opt-in ∧ durable infra): exposes `suspendForResource`. */
@@ -5,7 +5,7 @@ import { checkpointScopeOf } from "./checkpoint-scope.js";
5
5
  import { DEFAULT_RESOURCE_TTL_MS, publishCommittedSuspend, sanitizedTtlMs, USAGE_WINDOW_REAP_MARGIN_MS } from "./park-commit.js";
6
6
  import { remoteEnvFailureNote } from "./remote-env-retry.js";
7
7
  export function prepareBoundaryParks(input) {
8
- const { saga, spec, checkpointStore, abortController, harness, session, sessions, sessionId, deps, priorLedger, maxSlices, maxSuspends, resourceTotal, priorSuspendCount, suspendChainBase, humanReviewRef, liveSpendRef, now, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, suspendRef, reviewRef, remoteEnvFailures, resourceSuspendEligible, durableSuspendInfraReady, incompleteSuspendAdapter } = input;
8
+ const { saga, spec, checkpointStore, abortController, harness, session, sessions, sessionId, deps, priorLedger, maxSlices, maxSuspends, resourceTotal, priorSuspendCount, suspendChainBase, humanReviewRef, liveSpendRef, now, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, pausedRef, remoteEnvFailures, resourceSuspendEligible, durableSuspendInfraReady, incompleteSuspendAdapter } = input;
9
9
  if (saga === undefined)
10
10
  return { suspendForResource: undefined, suspendForPlatformLimit: undefined, suspendForReview: undefined };
11
11
  const { inFlightSpendMicroUsd, serializeCheckpointState, commitSuspendSaga, suspendLoopCapHit, suspendableEnv, parkOnlyRemoteEnv, parkOnlyHandle } = saga;
@@ -67,7 +67,7 @@ export function prepareBoundaryParks(input) {
67
67
  };
68
68
  if ((await commitSuspendSaga(token, cp, suspendableEnv, remoteHandle)).tag !== "committed")
69
69
  return false;
70
- publishCommittedSuspend({ suspendRef, reviewRef }, token, gate, scope, remoteHandle, cp.checkpointId, cp.pendingAction);
70
+ publishCommittedSuspend({ pausedRef }, token, gate, scope, remoteHandle, cp.checkpointId, cp.pendingAction);
71
71
  try {
72
72
  await sessions.pin?.(sessionId);
73
73
  }
@@ -153,7 +153,7 @@ export function prepareBoundaryParks(input) {
153
153
  };
154
154
  if ((await commitSuspendSaga(token, cp, suspendableEnv, remoteHandle)).tag !== "committed")
155
155
  return false;
156
- publishCommittedSuspend({ suspendRef, reviewRef }, token, gate, scope, remoteHandle, cp.checkpointId, cp.pendingAction);
156
+ publishCommittedSuspend({ pausedRef }, token, gate, scope, remoteHandle, cp.checkpointId, cp.pendingAction);
157
157
  try {
158
158
  await sessions.pin?.(sessionId);
159
159
  }
@@ -244,7 +244,7 @@ export async function prepareCapsAndWorkflow(input) {
244
244
  },
245
245
  ...(spec.handsReadOnly === true ? { parentHandsReadOnly: true } : {}), ...(spec.interactiveTools === false ? { parentInteractiveTools: false } : {}),
246
246
  onNotice: deps.onNotice,
247
- parentCheckpointStoreDisabled: spec.checkpointStore === null,
247
+ parentCheckpointStoreDisabled: spec.checkpointStore === "disabled",
248
248
  parentCenterArtifactDigest: () => input.centerAdoption()?.artifact.artifactDigest,
249
249
  parentCenterSourceRevision: () => input.centerAdoption()?.sourceRevision,
250
250
  ...(forwardEvent ? { forwardEvent } : {}),
@@ -27,7 +27,7 @@ import type { AskClass } from "../ask-class.js";
27
27
  import type { AutoModeDecider, AutoModeDenialTracker } from "../auto-mode.js";
28
28
  import { type ComplianceCapability } from "../compliance.js";
29
29
  import { type HookEnvCapabilities, type HookInvocationIdentity, type Hooks } from "../hooks.js";
30
- import { type ToolPolicy } from "../tool-policy.js";
30
+ import type { ToolPolicy } from "../tool-policy.js";
31
31
  import type { RunnerDeps, TaskSpec, ToolEffect } from "../types.js";
32
32
  import type { CwdRef } from "../../tools/fs/fs-shared.js";
33
33
  import type { AskLane, IrreversibilityTier, ParkAsk, Prepared, ReversibilityProbes } from "./contracts.js";
@@ -74,9 +74,6 @@ export interface PrepareGateStationsInput {
74
74
  blockedToolCalls: Set<string>;
75
75
  /** borrowed-mutable — the duplicate-frame ask-grant record. Writer here: the head-of-evaluation and lifecycle-end `delete`. */
76
76
  inheritedAskGrants: Map<string, unknown>;
77
- /** borrowed-mutable — the bare-human-rejection sideband. Writer here: the head-of-evaluation `delete` and the lifecycle
78
- * sweep whose `delete` IS the read the boundary judgment consumes. */
79
- humanBareRejections: Set<string>;
80
77
  /** borrowed-mutable — the inherited-unavailable marker set. Writer here: the lifecycle-end `delete`; `has` is handed to
81
78
  * the gate as the read-only `isMarkedUnresolvable`. */
82
79
  inheritedUnavailableAsks: Set<string>;
@@ -94,9 +91,9 @@ export interface PrepareGateStationsInput {
94
91
  /** borrowed-mutable — PreToolUse `additionalContext` per call id. Writers here: the `tool_call` station's stash (`set`, only
95
92
  * for calls that will execute) and the `tool_result` station's one-shot drain (`delete`). */
96
93
  preToolContexts: Map<string, string[]>;
97
- /** borrowed-mutable — the settlement sideband (`Prepared.approvalSettlement`). Writer here: the ONE screened `set` per
98
- * gate outcome; the frame mint reads and deletes. */
99
- approvalSettlement: Prepared["approvalSettlement"];
94
+ /** borrowed-mutable — the gate-outcome sideband (`Prepared.gateOutcomes`). Writer here: the single screened write per
95
+ * gated call (the two short-circuits and the gate's terminal exits); the frame mint reads and deletes. */
96
+ gateOutcomes: Prepared["gateOutcomes"];
100
97
  /** borrowed-mutable — the turn halt fact (`Prepared.batchHaltRef`). Writer here: the bare-rejection boundary (`current`). */
101
98
  batchHaltRef: Prepared["batchHaltRef"];
102
99
  /** borrowed-readonly — whether blocked/suspended ids are tracked at all (the post-tool callbacks exist). */
@@ -2,54 +2,29 @@ import { SEND_MESSAGE_TOOL_NAME } from "../../agents/send-message-tool.js";
2
2
  import { complianceCallDenial } from "../compliance.js";
3
3
  import { cloneObserverInput, formatHookFeedback, hookSeatExpiredError, runHookSeat, runToolGate } from "../hooks.js";
4
4
  import { PRESENT_PLAN_TOOL_NAME } from "../present-plan-tool.js";
5
- import { isApprovalSettledBy, isAskDenyResolution, screenApproverAttribution } from "../tool-policy.js";
5
+ import { screenGateOutcome } from "../gate-outcome.js";
6
+ import { directDeny } from "./gate-exit.js";
6
7
  import { emitTrace } from "../trace.js";
7
8
  import { createWriteProtectionCheck } from "../write-protect.js";
8
9
  import { PATH_CONFINABLE_WRITE_TOOLS } from "./session-rule-policy.js";
9
- function screenGateSettlement(result, settling) {
10
- const defects = [];
11
- const reportedBy = result.settledBy;
12
- let settledBy;
13
- if (reportedBy !== undefined) {
14
- if (!isApprovalSettledBy(reportedBy) || (!settling && reportedBy !== "human")) {
15
- defects.push(`a tool-gate settlement reported settledBy "${String(reportedBy)}" on ${settling ? "a blocked" : "an executing"} call — ` +
16
- `it is one of "human" / "timeout" / "aborted", and only "human" can be the source of a call that runs; the frame carries no source`);
17
- }
18
- else
19
- settledBy = reportedBy;
20
- }
21
- const attribution = screenApproverAttribution(result.approver);
22
- if (attribution.defect !== undefined) {
23
- defects.push(`a tool-gate settlement reported an attribution this engine refuses: ${attribution.defect}; the frame carries no approver`);
24
- }
25
- const reportedResolution = result.resolution;
26
- let resolution;
27
- if (reportedResolution !== undefined) {
28
- if (!isAskDenyResolution(reportedResolution) || !settling) {
29
- defects.push(`a tool-gate settlement reported a deny resolution "${String(reportedResolution)}" on ${settling ? "a blocked" : "an executing"} call — ` +
30
- `it is one of the closed ask-deny vocabulary and only a BLOCKED call can carry one; the frame carries no resolution`);
31
- }
32
- else
33
- resolution = reportedResolution;
34
- }
35
- const reportedAutoDenied = result.autoDenied;
36
- let autoDenied;
37
- if (reportedAutoDenied === true) {
38
- if (!settling)
39
- defects.push("a tool-gate settlement reported autoDenied on an executing call — only a BLOCKED call can carry the marker; the frame carries none");
40
- else
41
- autoDenied = true;
10
+ function screenGateResult(result) {
11
+ if (result.suspend !== undefined)
12
+ return { defects: [] };
13
+ const gate = result.gate;
14
+ if (gate === undefined)
15
+ return { defects: ["a tool-gate result carried no outcome record on a terminal exit — every terminal exit mints one; the frame carries none"] };
16
+ const defects = screenGateOutcome(gate);
17
+ const blocked = result.block === true;
18
+ if ((gate.disposition.kind === "denied") !== blocked) {
19
+ defects.push(`a tool-gate result's outcome reads "${gate.disposition.kind}" on ${blocked ? "a blocked" : "an executing"} call — the two faces of one verdict disagree; the frame carries no outcome`);
42
20
  }
43
- const record = {
44
- ...(settledBy !== undefined ? { settledBy } : {}),
45
- ...(attribution.approver !== undefined ? { approver: attribution.approver } : {}),
46
- ...(resolution !== undefined ? { resolution } : {}),
47
- ...(autoDenied !== undefined ? { autoDenied } : {}),
48
- };
49
- return { ...(settledBy !== undefined || attribution.approver !== undefined || resolution !== undefined || autoDenied !== undefined ? { record } : {}), defects };
21
+ return defects.length > 0 ? { defects } : { gate, defects };
50
22
  }
51
23
  function maybeHumanRejectionHalt(input) {
52
- if (!input.bare || input.settledBy !== "human" || input.isDelegatedChild)
24
+ const d = input.gate?.disposition;
25
+ const s = input.gate?.settlement;
26
+ const bare = d?.kind === "denied" && d.deniedBy === "ask_resolution" && s?.kind === "human_refused" && s.note === undefined;
27
+ if (!bare || input.isDelegatedChild)
53
28
  return undefined;
54
29
  return {
55
30
  reason: `This tool call was NOT executed: the user rejected the "${input.toolName}" tool call in the same ` +
@@ -64,7 +39,7 @@ function maybeHumanRejectionHalt(input) {
64
39
  };
65
40
  }
66
41
  export function prepareGateStations(input) {
67
- const { askLane, parkAsk, tools, toolEffects, deps, toolCallGateArmedRef, effectivePolicy, hooks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, humanBareRejections, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, approvalSettlement, batchHaltRef, blockedTracked, hookIdentity, reminderMark, planModeRef, hostTaskId, sessionId, ownGatePreToolUse, hookTimeoutMs, handsCwdRef, hookEnvFace, irreversibilityTier, reversibilityProbes, abortController, shellGatedBash, shellGatedMonitor, autoModeDecider, autoModeDenialTracking, stopForDenialLimit, permissionRuleLane, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, notifyOwnHookCrash } = input;
42
+ const { askLane, parkAsk, tools, toolEffects, deps, toolCallGateArmedRef, effectivePolicy, hooks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, gateOutcomes, batchHaltRef, blockedTracked, hookIdentity, reminderMark, planModeRef, hostTaskId, sessionId, ownGatePreToolUse, hookTimeoutMs, handsCwdRef, hookEnvFace, irreversibilityTier, reversibilityProbes, abortController, shellGatedBash, shellGatedMonitor, autoModeDecider, autoModeDenialTracking, stopForDenialLimit, permissionRuleLane, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, notifyOwnHookCrash } = input;
68
43
  if (askLane !== undefined && parkAsk !== undefined) {
69
44
  const { adjudicate, resolveAskBound, notifyPermissionDenied, notifyHookError } = askLane;
70
45
  const { resolveContentAsk, suspendAsk } = parkAsk;
@@ -87,14 +62,15 @@ export function prepareGateStations(input) {
87
62
  harness.on("tool_call", async (e) => {
88
63
  blockedToolCalls.delete(e.toolCallId);
89
64
  inheritedAskGrants.delete(e.toolCallId);
90
- humanBareRejections.delete(e.toolCallId);
91
65
  {
92
66
  const complianceDeny = complianceCallDenial(complianceDenies, e.toolName);
93
67
  if (complianceDeny !== undefined) {
94
68
  if (blockedTracked)
95
69
  blockedToolCalls.add(e.toolCallId);
70
+ const gate = directDeny("compliance");
71
+ gateOutcomes.set(e.toolCallId, gate);
96
72
  if (notifyPermissionDenied) {
97
- await notifyPermissionDenied({ toolName: e.toolName, input: cloneObserverInput(e.input), toolCallId: e.toolCallId, reason: complianceDeny, source: "safety", identity: hookIdentity });
73
+ await notifyPermissionDenied({ toolName: e.toolName, input: cloneObserverInput(e.input), toolCallId: e.toolCallId, reason: complianceDeny, gate, identity: hookIdentity });
98
74
  }
99
75
  return { block: true, reason: formatHookFeedback(complianceDeny, reminderMark), preToolContext: [] };
100
76
  }
@@ -104,8 +80,10 @@ export function prepareGateStations(input) {
104
80
  blockedToolCalls.add(e.toolCallId);
105
81
  const planDenyReason = `Plan mode is active — "${e.toolName}" is a write/mutating tool and is read-only-blocked. ` +
106
82
  `Research with read-only tools, then call ${PRESENT_PLAN_TOOL_NAME} with your plan to get it approved before acting.`;
83
+ const gate = directDeny("plan_mode");
84
+ gateOutcomes.set(e.toolCallId, gate);
107
85
  if (notifyPermissionDenied) {
108
- await notifyPermissionDenied({ toolName: e.toolName, input: cloneObserverInput(e.input), toolCallId: e.toolCallId, reason: planDenyReason, source: "planMode", identity: hookIdentity });
86
+ await notifyPermissionDenied({ toolName: e.toolName, input: cloneObserverInput(e.input), toolCallId: e.toolCallId, reason: planDenyReason, gate, identity: hookIdentity });
109
87
  }
110
88
  return {
111
89
  block: true,
@@ -114,7 +92,6 @@ export function prepareGateStations(input) {
114
92
  };
115
93
  }
116
94
  let result;
117
- let humanBareRejection = false;
118
95
  try {
119
96
  result = await runToolGate({
120
97
  onNotifyError: (f) => emitTrace(deps.tracer, () => ({ kind: "observer.notify_failed", version: 1, taskId: hostTaskId, site: f.site, message: f.error.message, ts: Date.now() })),
@@ -190,7 +167,6 @@ export function prepareGateStations(input) {
190
167
  inheritedUnavailableAsks.delete(e.toolCallId);
191
168
  inheritedAskGrants.delete(e.toolCallId);
192
169
  foldAskClasses.delete(e.toolCallId);
193
- humanBareRejection = humanBareRejections.delete(e.toolCallId);
194
170
  }
195
171
  const ancestorAdmitted = ancestorSandboxAdmissions.get(e.toolCallId);
196
172
  ancestorSandboxAdmissions.delete(e.toolCallId);
@@ -204,15 +180,14 @@ export function prepareGateStations(input) {
204
180
  if (blockedTracked && (result.block || result.suspend)) {
205
181
  blockedToolCalls.add(e.toolCallId);
206
182
  }
207
- const settlement = screenGateSettlement(result, result.block === true);
208
- for (const defect of settlement.defects)
183
+ const screened = screenGateResult(result);
184
+ for (const defect of screened.defects)
209
185
  deps.onError?.(new Error(defect), { phase: "config", sessionId });
210
- if (settlement.record !== undefined)
211
- approvalSettlement.set(e.toolCallId, settlement.record);
186
+ if (screened.gate !== undefined)
187
+ gateOutcomes.set(e.toolCallId, screened.gate);
212
188
  if (result.block) {
213
189
  const haltRemaining = maybeHumanRejectionHalt({
214
- bare: humanBareRejection,
215
- settledBy: result.settledBy,
190
+ gate: screened.gate,
216
191
  isDelegatedChild: delegation.isDelegatedChild === true,
217
192
  toolName: e.toolName,
218
193
  toolCallId: e.toolCallId,
@@ -221,7 +221,7 @@ export function prepareInheritedGate(input) {
221
221
  delegationSettlement: delegationSettlementForChildren,
222
222
  ...(autoModeDecider ? { autoModeReview: { decider: autoModeDecider } } : {}),
223
223
  ...(spec.durableApproval !== undefined ? { durableApprovalForChildren: { ...spec.durableApproval } } : {}),
224
- ...(spec.checkpointStore === null ? { checkpointStoreDisabledForChildren: true } : {}),
224
+ ...(spec.checkpointStore === "disabled" ? { checkpointStoreDisabledForChildren: true } : {}),
225
225
  taskId: hostTaskId,
226
226
  ...(internals?.parentTaskId !== undefined ? { parentTaskId: internals.parentTaskId } : {}),
227
227
  ...(internals?.parentSessionId !== undefined ? { parentSessionId: internals.parentSessionId } : {}),
@@ -2,15 +2,29 @@ import type { BeforeWriteHook, EffectiveMemoryScopes, RunnerDeps, TaskSpec, Tool
2
2
  import { type CaptureEntitlementInput, type MemoryCapturePosture } from "./memory-capture-optout.js";
3
3
  import type { Prepared } from "./contracts.js";
4
4
  export interface PrepareMemoryInput {
5
+ /** borrowed-readonly — the REBOUND spec. Read: `memory` (the scope declaration this phase
6
+ * normalizes) and `principal` (the org-admission subject). Never mutated. */
5
7
  spec: TaskSpec;
8
+ /** borrowed-readonly — the deployment seams this phase reads: the two operator lanes (`onError`,
9
+ * `onNotice`), the memory planes (`memoryBackend`, `memoryStore`, `memoryEngineDir`, `rootPath`,
10
+ * `deploymentMemoryScopes`, `memoryScopeAdmission`), `memoryCaptureRecordStore`,
11
+ * `memoryConsolidation`, `runtimeCapsResolver` and `onMemoryHarvestReport`. Receivers preserved
12
+ * (`deps.onError?.(…)`). */
6
13
  deps: RunnerDeps;
14
+ /** borrowed-readonly — the acquired session's id: the engine session's key, the operator lines'
15
+ * context, and the capture record's subject. */
7
16
  sessionId: string;
17
+ /** borrowed-readonly — the resolved task root: the containment boundary every derived memory dir
18
+ * is checked against, and the repo-root fallback when `deps.rootPath` is unset. */
8
19
  taskRootPath: string;
20
+ /** borrowed-mutable — the caller's write-gate cell, and THIS phase is its writer: it installs the
21
+ * memory write gate into `.current` (the module header's one out-param effect). Identity is the
22
+ * contract — the caller's hands/read-face seat reads this exact cell. */
9
23
  memoryWriteGateRef: {
10
24
  current?: BeforeWriteHook;
11
25
  };
12
26
  /**
13
- * #181-F5 whether a tool NAMED `Write` (the tool the CC `# Memory` instruction names) is on the
27
+ * borrowed-readonly — #181-F5: whether a tool NAMED `Write` (the tool the CC `# Memory` instruction names) is on the
14
28
  * ASSEMBLED roster this run, not excluded, AND can actually REACH the host-side memory root:
15
29
  * prepare-task's `tools.some(t => t.name === "Write") && !exclude.includes("Write")` plus the
16
30
  * remote-env conjunct (a hand-band Write on a remote ExecutionEnv writes the sandbox filesystem,
@@ -22,12 +36,12 @@ export interface PrepareMemoryInput {
22
36
  * its roster (or cannot reach the store); the RB-276 index seed follows the same gate.
23
37
  */
24
38
  writeToolsMounted: boolean;
25
- /** design/319 (A ticket) the run's reminder provenance mark: the memory engine's announcement
39
+ /** borrowed-readonly — design/319 (A ticket): the run's reminder provenance mark: the memory engine's announcement
26
40
  * block is an engine-authored `<system-reminder>`, so its open tag must carry the same mark the
27
41
  * system-prompt declaration names. Threaded into every `engine.inject` call this phase builds. */
28
42
  reminderMark: string;
29
43
  /**
30
- * The session-wide persistence verdict: `TaskSpec.memoryPersistenceCapable` (the deployment's own
44
+ * borrowed-readonly — the session-wide persistence verdict: `TaskSpec.memoryPersistenceCapable` (the deployment's own
31
45
  * statement — the only honest channel for a custom memory writer persisting through its closure,
32
46
  * which no inference can see) when set, else the KNOWN-store-path inference: a mounted,
33
47
  * non-excluded file-write tool (Write/Edit/NotebookEdit) or a write-capable shell. A generic
@@ -37,7 +51,7 @@ export interface PrepareMemoryInput {
37
51
  */
38
52
  rosterCanPersist: boolean;
39
53
  /**
40
- * The raw `TaskSpec.memoryPersistenceCapable` DECLARATION, kept separate from the composed
54
+ * borrowed-readonly — the raw `TaskSpec.memoryPersistenceCapable` DECLARATION, kept separate from the composed
41
55
  * {@link rosterCanPersist} verdict because the two drive different arms:
42
56
  * - `true` (declared) RETRACTS the engine's own read-only notice — the deployment vouches for a
43
57
  * persistence channel the engine cannot see (a custom writer persisting through its closure),
@@ -52,14 +66,14 @@ export interface PrepareMemoryInput {
52
66
  */
53
67
  memoryPersistenceDeclared?: boolean;
54
68
  /**
55
- * design/336 §13-3 the memory-provenance master switch, screened at the config doors
69
+ * borrowed-readonly — design/336 §13-3: the memory-provenance master switch, screened at the config doors
56
70
  * (`config.memory_provenance`, exact spellings, absent folded to `"carry"`). Every engine this
57
71
  * phase constructs runs under it, and the pollution notices/tool wording state the mode-true
58
72
  * behavior off it. See {@link RunnerDeps.memoryProvenance}.
59
73
  */
60
74
  memoryProvenance: "off" | "carry";
61
75
  /**
62
- * design/178 ②-1 whether the `memory_search`/`memory_get` pair PASSED its early mount conjuncts
76
+ * borrowed-readonly — design/178 ②-1: whether the `memory_search`/`memory_get` pair PASSED its early mount conjuncts
63
77
  * (exclusion + name occupancy, decided in prepare-task BEFORE this phase). True ⇒ this phase builds
64
78
  * the pair's ToolSpecs ({@link PrepareMemoryResult.memoryTools}) and the injection's instruction
65
79
  * teaches the retrieval discipline; false ⇒ neither happens, so the teaching and the roster agree
@@ -68,29 +82,22 @@ export interface PrepareMemoryInput {
68
82
  */
69
83
  memorySearchToolsPlanned: boolean;
70
84
  /**
71
- * Org-memory admission context (ruled 2026-08-05), assembled by prepare-task:
72
- * - `orgMemoryDenied`/`complianceDegraded`: the compliance capability `org_memory_mount` verdict
73
- * for this principal (the veto covers the request-origin plane);
74
- * - `parentAdmittedOrgScopes`: the delegation chain's FROZEN admitted org set — `undefined` for a
75
- * top-level task; for a delegated child the caller passes the fail-closed empty set when the
76
- * chain carries no verdict (an older-shape chain must not read as "unconstrained").
77
- */
78
- /**
79
- * design/383 §3.1 — the SCREENED capture posture (prepare-config-doors; absent deps seat folded
80
- * to `"open"`) plus whether the deployment DECLARED one at all (the once-per-process "switch in
81
- * use, no policy configured" operator line fires only on the undeclared arm).
85
+ * borrowed-readonly design/383 §3.1: the SCREENED capture posture (prepare-config-doors; an
86
+ * absent deps seat folded to `"open"`).
82
87
  */
83
88
  memoryCapturePolicy?: MemoryCapturePosture;
89
+ /** borrowed-readonly — whether the deployment DECLARED a posture at all: the once-per-process
90
+ * "switch in use, no policy configured" operator line fires only on the undeclared arm. */
84
91
  memoryCapturePolicyDeclared?: boolean;
85
92
  /**
86
- * design/383 §3.1 the per-principal entitlement as resolved by prepare-task's ONE caps resolve
93
+ * borrowed-readonly — design/383 §3.1: the per-principal entitlement as resolved by prepare-task's ONE caps resolve
87
94
  * (`value` = `runtimeCaps.allowMemoryOptOut` when boolean; `faulted` = the resolve threw or the
88
95
  * member was non-boolean — per the member's F2 fault-transit contract a fault must never arrive
89
96
  * as a coined explicit value). Consumed by the adjudicator on every ingress of this prepare.
90
97
  */
91
98
  captureEntitlement?: CaptureEntitlementInput;
92
99
  /**
93
- * design/383 §2.1b the carrier-absence verdict, judged by prepare-task from the DECLARED
100
+ * borrowed-readonly — design/383 §2.1b: the carrier-absence verdict, judged by prepare-task from the DECLARED
94
101
  * deployment shape: a remote-execution deployment whose control plane does not follow the run
95
102
  * (the per-run sandbox / stateless-replica form) with no
96
103
  * {@link RunnerDeps.memoryCaptureRecordStore} supplied. TRUE + a `capture:"off"` declaration ⇒
@@ -99,7 +106,7 @@ export interface PrepareMemoryInput {
99
106
  */
100
107
  captureCarrierUnsupported?: boolean;
101
108
  /**
102
- * design/383 §2.5 the IMMEDIATE spawner's session id (trusted internals seat, filled by the
109
+ * borrowed-readonly — design/383 §2.5: the IMMEDIATE spawner's session id (trusted internals seat, filled by the
103
110
  * delegation lanes; absent on top-level runs). The record-query leg of the delegation floor: a
104
111
  * child's harvest legs also read the PARENT's opt-out record off the shared write-plane control
105
112
  * store, so a parent whose opt-out landed AFTER this child spawned (the mid-run flip) still gets
@@ -112,7 +119,7 @@ export interface PrepareMemoryInput {
112
119
  */
113
120
  parentSessionId?: string;
114
121
  /**
115
- * design/383 §2.5 the delegation FLOOR bit off the trusted internals chain
122
+ * borrowed-readonly — design/383 §2.5: the delegation FLOOR bit off the trusted internals chain
116
123
  * (`internals.memoryCaptureFloor === true`): the spawning session was opted out at spawn time.
117
124
  * A floored leg runs opted-out WITHOUT re-adjudication (the parent's granted opt-out tightens
118
125
  * the tree; re-asking could only loosen) and mints its own one-way record (reason names the
@@ -120,7 +127,7 @@ export interface PrepareMemoryInput {
120
127
  */
121
128
  captureFloor?: boolean;
122
129
  /**
123
- * design/383 §2.5 (rescan post-6.0.0-RC) the floor seat's THIRD state off the same trusted
130
+ * borrowed-readonly — design/383 §2.5 (rescan post-6.0.0-RC): the floor seat's THIRD state off the same trusted
124
131
  * chain: the spawning session's capture state was INDETERMINATE at spawn time (its record store
125
132
  * faulted at the getter read). This leg resolves it against the live record query (see
126
133
  * `armCaptureOptOut`): ancestor record found ⇒ floor; still faulting ⇒ this session runs
@@ -129,7 +136,7 @@ export interface PrepareMemoryInput {
129
136
  */
130
137
  captureFloorIndeterminate?: boolean;
131
138
  /**
132
- * design/383 §2.5 (rescan post-6.0.0-RC) the HOST-SIDE FORK lane: the session this one was
139
+ * borrowed-readonly — design/383 §2.5 (rescan post-6.0.0-RC): the HOST-SIDE FORK lane: the session this one was
133
140
  * forked FROM (`SessionMetadata.forkedFrom`, read by prepare-task off the acquired session). A
134
141
  * fork byte-copies the source's committed transcript, so the source's standing opt-out governs
135
142
  * the copy: record found at prepare ⇒ the floor arm (mint, reason naming the fork, no
@@ -138,22 +145,33 @@ export interface PrepareMemoryInput {
138
145
  * record-query walk, so a source that flips WHILE the fork runs suppresses it live.
139
146
  */
140
147
  captureForkOrigin?: string;
141
- /** design/383 §2.5 (rescan, codex adversarial round) the fork-lineage read itself FAULTED
148
+ /** borrowed-readonly — design/383 §2.5 (rescan, codex adversarial round): the fork-lineage read itself FAULTED
142
149
  * (session metadata unreadable): whether this session forks an opted-out source is unknowable,
143
150
  * so the capture arm runs INDETERMINATE (suppress fail-closed, disclose, mint nothing) — a
144
151
  * metadata outage must not read as "no lineage" (读错不许伪装 clean). */
145
152
  captureLineageFault?: boolean;
146
- /** design/383 §2.5 (codex review adopted) the SPAWNING session's write-plane control dir
153
+ /** borrowed-readonly — design/383 §2.5 (codex review adopted): the SPAWNING session's write-plane control dir
147
154
  * (trusted internals chain), so the record-query leg reaches a parent on a DIFFERENT memory
148
155
  * plane (project-writing parent, personal-writing child). Absent ⇒ same-plane query only. */
149
156
  parentCaptureQueryDir?: string;
150
- /** design/383 §2.5 (codex round 3) the full ancestor chain's capture coordinates off the
157
+ /** borrowed-readonly — design/383 §2.5 (codex round 3): the full ancestor chain's capture coordinates off the
151
158
  * trusted internals seat; the harvest closure walks every row (deduped with the parent seat),
152
159
  * so a mid-run flip anywhere up the tree suppresses this in-flight descendant. */
153
160
  captureAncestors?: ReadonlyArray<{
154
161
  sessionId: string;
155
162
  controlDir?: string;
156
163
  }>;
164
+ /**
165
+ * borrowed-readonly — the org-memory admission context (ruled 2026-08-05), assembled by
166
+ * prepare-task:
167
+ * - `orgMemoryDenied`/`complianceDegraded`: the compliance capability `org_memory_mount` verdict
168
+ * for this principal (the veto covers the request-origin plane);
169
+ * - `parentAdmittedOrgScopes`: the delegation chain's FROZEN admitted org set — `undefined` for a
170
+ * top-level task; for a delegated child the caller passes the fail-closed empty set when the
171
+ * chain carries no verdict (an older-shape chain must not read as "unconstrained");
172
+ * - `priorOwnVerdict`/`governedProvenance`: the session freeze and the monotonic governance bit.
173
+ * Read as a whole into the admission call; never mutated.
174
+ */
157
175
  admissionCtx: {
158
176
  orgMemoryDenied: boolean;
159
177
  complianceDegraded: boolean;
@@ -142,10 +142,8 @@ export interface PrepareParkAskInput {
142
142
  };
143
143
  /** borrowed-mutable — the built harness. Writer here: `abort()` (release the gate, then stop the loop). */
144
144
  harness: Pick<AgentHarness, "abort">;
145
- /** borrowed-mutable — the durable-suspend holder (`Prepared.suspendRef`). Writer here: the commit-side publication. */
146
- suspendRef: Prepared["suspendRef"];
147
- /** borrowed-readonly — the review holder; handed to the commit-side discriminant, which never writes it for these kinds. */
148
- reviewRef: Prepared["reviewRef"];
145
+ /** borrowed-mutable — the run's committed-pause holder (`Prepared.pausedRef`). Writer here: the commit-side publication. */
146
+ pausedRef: Prepared["pausedRef"];
149
147
  }
150
148
  export interface PrepareParkAskResult {
151
149
  /** owned — the two closures as ONE value, or undefined exactly when the ask lane (and so the saga) is absent. */
@@ -4,6 +4,7 @@ import { ASK_USER_QUESTION_TOOL_NAME, classifyQuestionOutcome, validateAskQuesti
4
4
  import { hasBackgroundShell, sweepBackgroundShells } from "../background-shell.js";
5
5
  import { boundInputHashOf } from "../canonical-json.js";
6
6
  import { BINDING_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, encodeAtFidelity, F012_CHECKPOINT_VERSION, FACE_CHECKPOINT_VERSION, mintCheckpointId, mintCheckpointToken, ORG_ADMISSION_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, resolveDeclaredFidelity, samePlainValue, TOKEN_CHECKPOINT_VERSION, } from "../checkpoint-store.js";
7
+ import { pauseOf } from "../pause-registry.js";
7
8
  import { askCarryRowMembers } from "../hooks.js";
8
9
  import { defaultTaskRegistry } from "../task-registry.js";
9
10
  import { isLiveApproverSeat, carriesBidiControls, describeThrown, refuseOutOfContractDecision, tryCloneArgs } from "../tool-policy.js";
@@ -20,7 +21,7 @@ class ParkRefusal extends Error {
20
21
  }
21
22
  }
22
23
  export function prepareParkAsk(input) {
23
- const { askLane, saga, spec, deps, sessionId, checkpointStore, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedBash, shellGatedMonitor, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, now, humanReviewRef, abortController, harness, suspendRef, reviewRef } = input;
24
+ const { askLane, saga, spec, deps, sessionId, checkpointStore, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedBash, shellGatedMonitor, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, now, humanReviewRef, abortController, harness, pausedRef } = input;
24
25
  if (askLane === undefined || saga === undefined)
25
26
  return { parkAsk: undefined };
26
27
  const { composedCallSignal, approvalPreviewOf } = askLane;
@@ -272,8 +273,7 @@ export function prepareParkAsk(input) {
272
273
  scope,
273
274
  sessionId,
274
275
  leafId,
275
- gate,
276
- pendingAction: {
276
+ ...pauseOf(gate, {
277
277
  kind: "tool_approval",
278
278
  toolCallId: req.toolCallId,
279
279
  toolName: req.toolName,
@@ -301,7 +301,7 @@ export function prepareParkAsk(input) {
301
301
  boundInputHash: boundInputHashOf(parkedArgs),
302
302
  batchToolCallIds,
303
303
  completedCallIds,
304
- },
304
+ }),
305
305
  state: checkpointState,
306
306
  deadline: ttlMs !== undefined
307
307
  ? mintedAt + ttlMs
@@ -348,7 +348,7 @@ export function prepareParkAsk(input) {
348
348
  }
349
349
  return { parkFailed: committed.reason };
350
350
  }
351
- publishCommittedSuspend({ suspendRef, reviewRef }, token, gate, cp.scope, remoteHandle, cp.checkpointId, cp.pendingAction);
351
+ publishCommittedSuspend({ pausedRef }, token, gate, cp.scope, remoteHandle, cp.checkpointId, cp.pendingAction);
352
352
  try {
353
353
  await sessions.pin?.(sessionId);
354
354
  }