@sema-agent/core 7.53.0 → 7.54.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 (244) hide show
  1. package/CHANGELOG.md +277 -1
  2. package/LICENSE +3 -1
  3. package/dist/agents/peer-session-drain.d.ts +0 -1
  4. package/dist/agents/peer-session-drain.js +0 -2
  5. package/dist/agents/send-message-tool.js +3 -4
  6. package/dist/agents/subagent.d.ts +3 -5
  7. package/dist/agents/subagent.js +18 -11
  8. package/dist/agents/tool-filter.d.ts +7 -4
  9. package/dist/agents/tool-filter.js +7 -3
  10. package/dist/core/a2a.js +4 -2
  11. package/dist/core/allow-entry.d.ts +1 -0
  12. package/dist/core/allow-entry.js +1 -0
  13. package/dist/core/approval-object.d.ts +87 -0
  14. package/dist/core/approval-object.js +85 -0
  15. package/dist/core/arg-summary.d.ts +3 -2
  16. package/dist/core/arg-summary.js +17 -11
  17. package/dist/core/ask-origin.d.ts +43 -27
  18. package/dist/core/ask-origin.js +20 -11
  19. package/dist/core/ask-question.d.ts +0 -1
  20. package/dist/core/ask-question.js +4 -67
  21. package/dist/core/ask-unresolvable-notice.d.ts +3 -2
  22. package/dist/core/auto-compaction.d.ts +49 -50
  23. package/dist/core/auto-compaction.js +41 -51
  24. package/dist/core/auto-mode-prompt.d.ts +4 -2
  25. package/dist/core/auto-mode-prompt.js +4 -3
  26. package/dist/core/canonical-json.d.ts +69 -0
  27. package/dist/core/canonical-json.js +130 -8
  28. package/dist/core/checkpoint-requirements.d.ts +13 -7
  29. package/dist/core/checkpoint-requirements.js +4 -1
  30. package/dist/core/checkpoint-store.d.ts +33 -18
  31. package/dist/core/checkpoint-store.js +5 -4
  32. package/dist/core/child-clamp-seats.d.ts +45 -6
  33. package/dist/core/child-clamp-seats.js +56 -4
  34. package/dist/core/consolidate-scope.d.ts +1 -1
  35. package/dist/core/cross-boundary-taint.d.ts +213 -0
  36. package/dist/core/cross-boundary-taint.js +196 -0
  37. package/dist/core/decision-receipt.d.ts +44 -1
  38. package/dist/core/decision-receipt.js +16 -0
  39. package/dist/core/effective-path-target.d.ts +3 -0
  40. package/dist/core/effective-path-target.js +4 -0
  41. package/dist/core/engine-notice.d.ts +34 -2
  42. package/dist/core/engine-notice.js +17 -1
  43. package/dist/core/engine-storage-backend.d.ts +73 -0
  44. package/dist/core/engine-storage-backend.js +1 -0
  45. package/dist/core/file-history-store.d.ts +6 -2
  46. package/dist/core/file-history-store.js +1 -0
  47. package/dist/core/gate-fold.js +10 -2
  48. package/dist/core/gate-lanes.js +30 -21
  49. package/dist/core/gate-outcome.d.ts +7 -3
  50. package/dist/core/governance-codes.d.ts +7 -2
  51. package/dist/core/governance-codes.js +6 -0
  52. package/dist/core/hooks.d.ts +14 -14
  53. package/dist/core/hooks.js +1 -2
  54. package/dist/core/locked-config.d.ts +28 -1
  55. package/dist/core/locked-config.js +30 -3
  56. package/dist/core/lsp.d.ts +1 -1
  57. package/dist/core/mcp-server-spec.d.ts +66 -9
  58. package/dist/core/mcp-server-spec.js +52 -19
  59. package/dist/core/mcp.js +5 -4
  60. package/dist/core/memory-engine/engine.js +2 -1
  61. package/dist/core/memory-engine/export-bundle.d.ts +1 -1
  62. package/dist/core/memory-engine/export-bundle.js +1 -1
  63. package/dist/core/memory-engine/file-backend.d.ts +2 -6
  64. package/dist/core/memory-engine/file-backend.js +1 -12
  65. package/dist/core/memory.d.ts +3 -3
  66. package/dist/core/mode-policy.d.ts +13 -8
  67. package/dist/core/mode-policy.js +3 -2
  68. package/dist/core/mods/kernel/receive.d.ts +2 -1
  69. package/dist/core/mods/kernel/receive.js +7 -2
  70. package/dist/core/parent-spec-seat.d.ts +10 -13
  71. package/dist/core/parent-spec-seat.js +14 -6
  72. package/dist/core/pause-registry.d.ts +35 -1
  73. package/dist/core/pause-registry.js +10 -0
  74. package/dist/core/permission-rule-consent.d.ts +18 -5
  75. package/dist/core/permission-rule-consent.js +13 -8
  76. package/dist/core/permission-rule-model.d.ts +29 -6
  77. package/dist/core/permission-rule-model.js +6 -1
  78. package/dist/core/permission-rule-org.d.ts +37 -0
  79. package/dist/core/permission-rule-org.js +34 -42
  80. package/dist/core/permission-rule-session.js +2 -2
  81. package/dist/core/permission-rule-store.d.ts +8 -0
  82. package/dist/core/permission-rule-store.js +1 -0
  83. package/dist/core/permission-rule-sync.js +3 -2
  84. package/dist/core/read-only-shell.d.ts +1 -1
  85. package/dist/core/read-only-shell.js +30 -9
  86. package/dist/core/remote-env.d.ts +41 -1
  87. package/dist/core/remote-env.js +18 -0
  88. package/dist/core/resume-startup-cause.d.ts +18 -0
  89. package/dist/core/resume-startup-cause.js +12 -0
  90. package/dist/core/runner/approval-feedback.d.ts +46 -0
  91. package/dist/core/runner/approval-feedback.js +41 -0
  92. package/dist/core/runner/compaction-call-options.d.ts +3 -3
  93. package/dist/core/runner/compaction-call-options.js +2 -2
  94. package/dist/core/runner/contracts.d.ts +33 -41
  95. package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
  96. package/dist/core/runner/cross-boundary-lane.js +190 -0
  97. package/dist/core/runner/decide-continuation.d.ts +4 -4
  98. package/dist/core/runner/decide-continuation.js +3 -1
  99. package/dist/core/runner/gate-exit.d.ts +32 -12
  100. package/dist/core/runner/gate-exit.js +75 -33
  101. package/dist/core/runner/inherited-ask-grants.js +2 -2
  102. package/dist/core/runner/person-path-rows.d.ts +2 -2
  103. package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -4
  104. package/dist/core/runner/prepare-acquire-reconcile.js +3 -3
  105. package/dist/core/runner/prepare-ask-lane.js +3 -3
  106. package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
  107. package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
  108. package/dist/core/runner/prepare-config-doors.d.ts +12 -15
  109. package/dist/core/runner/prepare-config-doors.js +8 -3
  110. package/dist/core/runner/prepare-context-lane.js +6 -3
  111. package/dist/core/runner/prepare-delegation-surface.d.ts +3 -2
  112. package/dist/core/runner/prepare-delegation-surface.js +2 -3
  113. package/dist/core/runner/prepare-execution-env.d.ts +1 -2
  114. package/dist/core/runner/prepare-execution-env.js +2 -1
  115. package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
  116. package/dist/core/runner/prepare-gate-stations.js +4 -3
  117. package/dist/core/runner/prepare-hands-readface.d.ts +2 -2
  118. package/dist/core/runner/prepare-hands-readface.js +1 -1
  119. package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
  120. package/dist/core/runner/prepare-inherited-gate.js +1 -0
  121. package/dist/core/runner/prepare-park-ask.d.ts +1 -1
  122. package/dist/core/runner/prepare-park-ask.js +9 -3
  123. package/dist/core/runner/prepare-policy-chain.js +2 -7
  124. package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
  125. package/dist/core/runner/prepare-safety-scan.js +34 -27
  126. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
  127. package/dist/core/runner/prepare-suspend-saga.js +6 -2
  128. package/dist/core/runner/prepare-task.js +13 -10
  129. package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
  130. package/dist/core/runner/prepare-turn-wiring.js +14 -49
  131. package/dist/core/runner/prepare-wiring-manifest.d.ts +2 -2
  132. package/dist/core/runner/prepare-wiring-manifest.js +2 -2
  133. package/dist/core/runner/prepare-workspace-restore.js +2 -2
  134. package/dist/core/runner/resume-admission.js +9 -9
  135. package/dist/core/runner/resume-apply.js +4 -4
  136. package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
  137. package/dist/core/runner/resume-policy-outcome.js +18 -15
  138. package/dist/core/runner/resume-preflight.js +2 -2
  139. package/dist/core/runner/resume-review-outcome.js +3 -3
  140. package/dist/core/runner/run-leg.js +57 -33
  141. package/dist/core/runner/run-settle-and-teardown.js +2 -0
  142. package/dist/core/runner/run-terminal-adoption.js +15 -4
  143. package/dist/core/runner/session-file-state-replay.d.ts +5 -2
  144. package/dist/core/runner/session-file-state-replay.js +3 -2
  145. package/dist/core/runner/stream-steer-verb.js +2 -2
  146. package/dist/core/runner/tool-face-overlay.d.ts +24 -6
  147. package/dist/core/runner/tool-face-overlay.js +24 -15
  148. package/dist/core/runner-deps.d.ts +9 -9
  149. package/dist/core/session-store.d.ts +35 -16
  150. package/dist/core/session-store.js +20 -12
  151. package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
  152. package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
  153. package/dist/core/shell-wrapper-table.d.ts +5 -3
  154. package/dist/core/shell-wrapper-table.js +1 -1
  155. package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
  156. package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
  157. package/dist/core/store-contracts/session-store-contract.js +639 -0
  158. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
  159. package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
  160. package/dist/core/task-event.d.ts +6 -4
  161. package/dist/core/task-registry-agent.js +1 -0
  162. package/dist/core/task-registry-shared.d.ts +5 -0
  163. package/dist/core/task-registry.d.ts +7 -0
  164. package/dist/core/task-registry.js +17 -0
  165. package/dist/core/task-result.d.ts +1 -1
  166. package/dist/core/task-spec.d.ts +6 -6
  167. package/dist/core/tighten-task-spec.d.ts +6 -4
  168. package/dist/core/tighten-task-spec.js +2 -2
  169. package/dist/core/tool-catalog-entries.d.ts +1 -1
  170. package/dist/core/tool-catalog-entries.js +52 -52
  171. package/dist/core/tool-face-reader.d.ts +49 -0
  172. package/dist/core/tool-face-reader.js +94 -0
  173. package/dist/core/tool-face.d.ts +17 -8
  174. package/dist/core/tool-face.js +1 -0
  175. package/dist/core/tool-policy.d.ts +64 -23
  176. package/dist/core/tool-policy.js +62 -56
  177. package/dist/core/tool-roster.d.ts +46 -28
  178. package/dist/core/tool-roster.js +91 -14
  179. package/dist/core/tool-spec-members.js +2 -2
  180. package/dist/core/tool-spec.d.ts +20 -4
  181. package/dist/core/tools.js +2 -0
  182. package/dist/core/trace.d.ts +24 -2
  183. package/dist/core/types.d.ts +2 -2
  184. package/dist/core/types.js +1 -1
  185. package/dist/core/untrusted-text.d.ts +7 -0
  186. package/dist/core/untrusted-text.js +3 -8
  187. package/dist/core/user-attachment.d.ts +43 -0
  188. package/dist/core/user-attachment.js +92 -15
  189. package/dist/engine/compaction/compaction.d.ts +2 -2
  190. package/dist/engine/compaction/utils.d.ts +2 -2
  191. package/dist/engine/harness/types.d.ts +7 -4
  192. package/dist/engine/llm/types.d.ts +7 -2
  193. package/dist/engine/llm/types.js +2 -1
  194. package/dist/engine/session/repo-utils.d.ts +5 -0
  195. package/dist/engine/session/repo-utils.js +9 -0
  196. package/dist/engine/session/storage-base.js +2 -2
  197. package/dist/index.d.ts +23 -9
  198. package/dist/index.js +19 -8
  199. package/dist/internal/llm.d.ts +1 -1
  200. package/dist/internal/llm.js +1 -1
  201. package/dist/orchestration/run-workflow-tool.d.ts +3 -0
  202. package/dist/orchestration/run-workflow-tool.js +1 -0
  203. package/dist/orchestration/workflow-governance.d.ts +1 -1
  204. package/dist/orchestration/workflow.d.ts +3 -0
  205. package/dist/orchestration/workflow.js +2 -1
  206. package/dist/prompt-assembly/catalog/schema.d.ts +3 -0
  207. package/dist/prompt-assembly/catalog/schema.js +3 -0
  208. package/dist/prompt-assembly/overlay.js +2 -2
  209. package/dist/prompt-assembly/select.js +2 -2
  210. package/dist/prompts/default.d.ts +1 -1
  211. package/dist/shell/lex.d.ts +87 -8
  212. package/dist/shell/lex.js +283 -49
  213. package/dist/stores/file/index.d.ts +8 -6
  214. package/dist/tools/artifact/artifact-tool.js +10 -0
  215. package/dist/tools/fs/bash-program-position.d.ts +3 -15
  216. package/dist/tools/fs/bash-program-position.js +3 -10
  217. package/dist/tools/fs/bash-readonly-classifier.js +2 -0
  218. package/dist/tools/fs/fs-bash.d.ts +3 -3
  219. package/dist/tools/fs/fs-bash.js +72 -101
  220. package/dist/tools/fs/fs-read.d.ts +12 -0
  221. package/dist/tools/fs/fs-read.js +10 -9
  222. package/dist/tools/fs/fs-shared.d.ts +27 -31
  223. package/dist/tools/fs/fs-shared.js +12 -15
  224. package/dist/tools/fs/fs-write.js +1 -1
  225. package/dist/tools/fs/index.js +2 -2
  226. package/dist/tools/fs/read-deny-home.d.ts +1 -1
  227. package/dist/tools/fs/read-deny-home.js +5 -4
  228. package/dist/tools/fs/read-deny.d.ts +16 -3
  229. package/dist/tools/fs/read-deny.js +12 -9
  230. package/dist/tools/fs/safety.d.ts +7 -6
  231. package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
  232. package/dist/tools/fs/shell-read-bindings.js +15 -16
  233. package/dist/tools/fs/shell-read-device.js +1 -1
  234. package/dist/tools/fs/shell-read-plan.js +36 -47
  235. package/dist/tools/fs/shell-read-word.d.ts +1 -6
  236. package/dist/tools/fs/shell-read-word.js +2 -20
  237. package/dist/tools/fs/shell-reentry-text.js +1 -1
  238. package/dist/tools/web.d.ts +2 -2
  239. package/package.json +4 -1
  240. package/test/export-surface.snapshot.json +5654 -5520
  241. package/wire-changes/core@7.53.0.json +30 -8
  242. package/wire-changes/core@7.54.0.json +2870 -0
  243. package/dist/core/shell-scan.d.ts +0 -60
  244. package/dist/core/shell-scan.js +0 -183
@@ -1,17 +1,40 @@
1
1
  import { callerToolNameProblem } from "../caller-tool-name.js";
2
- import { engineCardTypes, handBandEffects } from "../tool-registry.js";
3
- import { callerCardIdOf, offendingResultCard, rosterMemberBoundProblem, schemaKeyBoundProblem, survivorsByName } from "../tool-roster.js";
2
+ import { describeToolCatalog } from "../tool-registry.js";
3
+ import { callerCardIdOf, rosterMemberBoundProblem, schemaKeyBoundProblem, survivorsByName } from "../tool-roster.js";
4
4
  import { toolFaceProblem } from "./tool-face-overlay.js";
5
- import { OFFLOAD_TOOL_NAME } from "../tool-result-store.js";
6
- import { PRESENT_PLAN_TOOL_NAME, ENTER_PLAN_MODE_TOOL_NAME } from "../present-plan-tool.js";
7
5
  const REPEAT_RISK = { read: 0, idempotent: 1, write: 2 };
8
6
  const leastRepeatSafe = (a, b) => (REPEAT_RISK[a] >= REPEAT_RISK[b] ? a : b);
7
+ function engineCandidatesOf(spec, deps) {
8
+ const hands = Boolean(deps.executionEnvFactory || deps.executionEnv);
9
+ const readOnlyHands = spec.handsReadOnly === true;
10
+ const out = [];
11
+ for (const e of describeToolCatalog()) {
12
+ if (!e.mountedBy.some((t) => t !== "scenario" && (t !== "hands" || hands)))
13
+ continue;
14
+ if (e.mountedBy.includes("hands") && e.face.ruleFace?.grammar === "command" && (e.face.effect === "read") !== readOnlyHands)
15
+ continue;
16
+ const effect = e.face.effect ?? "write";
17
+ for (const name of [e.name, ...(e.face.aliases ?? [])])
18
+ out.push([name, effect]);
19
+ }
20
+ return out;
21
+ }
22
+ function wakeEffectsOf(table, claimed, candidates) {
23
+ const wakeEffects = new Map(table);
24
+ const claims = new Set(claimed);
25
+ for (const [name, effect] of candidates) {
26
+ const prior = wakeEffects.get(name) ?? (claims.has(name) ? "write" : undefined);
27
+ wakeEffects.set(name, prior === undefined ? effect : leastRepeatSafe(prior, effect));
28
+ }
29
+ return wakeEffects;
30
+ }
9
31
  const tierOf = (t) => t.irreversibility ?? (t.reversibilityProbe ? "maybe" : undefined);
10
32
  export function prepareSafetyScan(input) {
11
33
  const { spec, deps } = input;
12
34
  const toolEffects = new Map();
13
35
  const survivors = survivorsByName(spec.tools ?? []);
14
36
  const claimedAliases = new Set();
37
+ const aliasClaims = [];
15
38
  const egressTools = new Set();
16
39
  const irreversibleTools = new Set();
17
40
  const irreversibilityTier = new Map();
@@ -52,18 +75,12 @@ export function prepareSafetyScan(input) {
52
75
  ...(t.ruleFace !== undefined ? { ruleFace: t.ruleFace } : {}),
53
76
  ...(t.renderHints !== undefined ? { renderHints: t.renderHints } : {}),
54
77
  };
55
- const faceProblem = toolFaceProblem(declared, t.parameters, { toolName: t.name });
78
+ const faceProblem = toolFaceProblem(declared, t.parameters, { toolName: t.name, cardId: callerCardIdOf(t) });
56
79
  if (faceProblem !== undefined) {
57
80
  const e = new Error(`Tool "${t.name}" declares a face its schema cannot carry: ${faceProblem}.`);
58
81
  e.code = "config.tool_face_invalid";
59
82
  throw e;
60
83
  }
61
- const foreignCard = offendingResultCard(t.renderHints, callerCardIdOf(t), engineCardTypes());
62
- if (foreignCard !== undefined) {
63
- const e = new Error(`Tool "${t.name}" declares a result card outside its own namespace: ${JSON.stringify(foreignCard)} (a caller card is "${callerCardIdOf(t)}/<card>"; engine cards and other contracts' namespaces are reserved).`);
64
- e.code = "config.tool_face_invalid";
65
- throw e;
66
- }
67
84
  }
68
85
  for (const [what, n] of [["name", t.name], ...(t.aliases ?? []).map((a) => ["alias", a])]) {
69
86
  const problem = callerToolNameProblem(n);
@@ -96,16 +113,21 @@ export function prepareSafetyScan(input) {
96
113
  markedBy(t.name, "deployment");
97
114
  }
98
115
  }
116
+ const candidates = engineCandidatesOf(spec, deps);
117
+ const engineNames = new Set(candidates.map(([n]) => n));
99
118
  for (const t of survivors.values()) {
100
119
  const tier = tierOf(t);
101
120
  for (const alias of t.aliases ?? []) {
102
121
  if (alias === t.name || survivors.has(alias))
103
122
  continue;
123
+ aliasClaims.push([alias, t.effect ?? "write"]);
104
124
  if (claimedAliases.has(alias))
105
125
  continue;
106
126
  claimedAliases.add(alias);
107
127
  if (t.effect)
108
128
  toolEffects.set(alias, t.effect);
129
+ if (engineNames.has(alias))
130
+ continue;
109
131
  if (tier !== undefined) {
110
132
  irreversibilityTier.set(alias, tier);
111
133
  if (tier === "always" || tier === "maybe") {
@@ -121,24 +143,9 @@ export function prepareSafetyScan(input) {
121
143
  }
122
144
  }
123
145
  }
124
- toolEffects.set(OFFLOAD_TOOL_NAME, "read");
125
- const claimerEffects = new Map([...claimedAliases, ...survivors.keys()].map((a) => [a, toolEffects.get(a) ?? "write"]));
126
- const recordHandEffect = (name, effect) => {
127
- const claimed = claimerEffects.get(name);
128
- toolEffects.set(name, claimed === undefined ? effect : leastRepeatSafe(claimed, effect));
129
- };
130
- if (deps.executionEnvFactory || deps.executionEnv) {
131
- for (const [name, effect] of handBandEffects())
132
- recordHandEffect(name, effect);
133
- if (spec.handsReadOnly === true)
134
- recordHandEffect("Bash", "read");
135
- }
136
- if (spec.enablePlanMode === true) {
137
- toolEffects.set(PRESENT_PLAN_TOOL_NAME, "read");
138
- toolEffects.set(ENTER_PLAN_MODE_TOOL_NAME, "read");
139
- }
140
146
  return {
141
147
  toolEffects,
148
+ wakeEffects: wakeEffectsOf(toolEffects, [...claimedAliases, ...survivors.keys()], [...aliasClaims, ...candidates]),
142
149
  egressTools,
143
150
  irreversibleTools,
144
151
  irreversibilityTier,
@@ -177,8 +177,8 @@ export interface PrepareSuspendSagaInput {
177
177
  readonly definition?: string;
178
178
  readonly lists: string;
179
179
  } | undefined;
180
- /** borrowed-readonly — the external-content-target fold (the row's monotonic bit). */
181
- externalContentTargetActive: boolean;
180
+ /** borrowed-readonly — the external-content-target fold (the row's monotonic bit). */ externalContentTargetActive: boolean;
181
+ /** borrowed-readonly — the leg's cross-boundary lane: the row's mark, and the record written before the row as the row's leaf. */ crossBoundary: import("./cross-boundary-lane.js").CrossBoundaryLane;
182
182
  /** borrowed-mutable — the run-scoped remote-lifecycle failure log (`Prepared.remoteEnvFailures`). Writer here: the
183
183
  * compensation's note binding (`push`). */
184
184
  remoteEnvFailures: Prepared["remoteEnvFailures"];
@@ -82,7 +82,7 @@ function stampPlacementRootSessionId(placementRootResolved) {
82
82
  return placementValueOrAbsent(placementRootResolved);
83
83
  }
84
84
  export function prepareSuspendSaga(input) {
85
- const { gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, reminderMark, handsCwdRef, handsRoot, handsHome, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, inheritedPathRuleAnchors, inheritedPathRuleInstallations, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, checkpointScope, toolCeiling, toolListsJudged, ownToolLists, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter } = input;
85
+ const { gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, reminderMark, handsCwdRef, handsRoot, handsHome, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, inheritedPathRuleAnchors, inheritedPathRuleInstallations, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, checkpointScope, toolCeiling, toolListsJudged, ownToolLists, externalContentTargetActive, crossBoundary, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter } = input;
86
86
  if (!gateMachineryActive)
87
87
  return { saga: undefined };
88
88
  const inFlightSpendMicroUsd = () => {
@@ -182,6 +182,7 @@ export function prepareSuspendSaga(input) {
182
182
  toolCeiling: toolCeiling !== undefined ? toolCeiling.map((l) => ({ ...(l.allow !== undefined ? { allow: persistedToolNameList(l.allow, "allowed") } : {}), deny: persistedToolNameList(l.deny, "denied") })) : undefined,
183
183
  toolListsJudged,
184
184
  ownToolLists: ownToolLists !== undefined ? { toolName: ownToolLists.toolName, ...(ownToolLists.definition !== undefined ? { definition: ownToolLists.definition } : {}), lists: ownToolLists.lists } : undefined,
185
+ crossBoundaryRecorded: crossBoundary.recorded() ? true : undefined,
185
186
  });
186
187
  const compensatePausedVM = (remoteEnv, snapshotId) => compensateUnparkedPause(remoteEnv, snapshotId, {
187
188
  boundMs: PARK_COMPENSATION_TIMEOUT_MS,
@@ -199,6 +200,7 @@ export function prepareSuspendSaga(input) {
199
200
  return { tag: "absent" };
200
201
  if (memoryEngineSession)
201
202
  await memoryEngineSession.harvest("checkpoint");
203
+ const recordUnwritten = await crossBoundary.owe(cp.leafId).then((entryId) => void (entryId !== undefined && (cp = { ...cp, leafId: entryId })), (err) => ({ err }));
202
204
  if (cutSignal?.aborted) {
203
205
  if (remoteEnv !== undefined && remoteHandle?.snapshotId !== undefined) {
204
206
  const back = await compensatePausedVM(remoteEnv, remoteHandle.snapshotId);
@@ -262,6 +264,8 @@ export function prepareSuspendSaga(input) {
262
264
  const own = judgeAsStored(stamped, fidelity);
263
265
  if (own.kind !== "ok")
264
266
  throw new Error(`the checkpoint row was not written: ${own.kind === "damaged" ? own.why : "it lists words this engine lacks"}`);
267
+ if (recordUnwritten !== undefined)
268
+ throw new Error(`the checkpoint row was not written: the session's cross-boundary record it points at could not be written first (${thrownText(recordUnwritten.err)})`);
265
269
  putAttempted = true;
266
270
  await checkpointStore.put(token, stamped);
267
271
  announceCommittedScreeningPark();
@@ -270,7 +274,7 @@ export function prepareSuspendSaga(input) {
270
274
  catch (putErr) {
271
275
  deps.onError?.(putErr, { phase: "config", sessionId });
272
276
  if (!putAttempted)
273
- return compensateNotWritten("the approval checkpoint was not written (the row failed its own requirement judge before the write; the deployment's error face carries why)");
277
+ return compensateNotWritten(recordUnwritten !== undefined ? `the session's cross-boundary record could not be written before its approval could be parked (${thrownText(recordUnwritten.err)}) — on a governed tree a row is not put without its record` : "the approval checkpoint was not written (a check before the write refused it — the row's own requirement judge; the deployment's error face carries why)");
274
278
  const confirmed = await confirmPutOutcome(putErr);
275
279
  if (confirmed === "committed") {
276
280
  try {
@@ -43,6 +43,7 @@ import { prepareTurnWiring } from "./prepare-turn-wiring.js";
43
43
  export { runGuardChain } from "./prepare-context-lane.js";
44
44
  import { preparePromptAssembly } from "./prepare-prompt-assembly.js";
45
45
  import { limitConfigError, prepareConfigDoors } from "./prepare-config-doors.js";
46
+ import { joinedCrossBoundaryTree, prepareCrossBoundaryLane } from "./cross-boundary-lane.js";
46
47
  import { prepareSafetyScan } from "./prepare-safety-scan.js";
47
48
  import { prepareAcquireReconcile } from "./prepare-acquire-reconcile.js";
48
49
  import { settleBranchWriteBack } from "./branch-writeback.js";
@@ -305,7 +306,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
305
306
  const { toolFaceLists, promptProfile, promptHost, promptBinding, lockedPreflight, resolvedInteractionPosture, microCompactKnob, resolvedRole, model, thinking, compModel, fableMitigations, memoryDelegationEvidence, memoryProvenance, memoryCapturePolicy, usageWindows, brainCallGuardrailRef, brainCallGuardrailMs } = doors;
306
307
  announceToolModelGate(deps.onNotice, model.id, doors.modelGate);
307
308
  const modelGateManifest = toolModelGateManifest(doors.modelGate);
308
- const { toolEffects, egressTools, irreversibleTools, irreversibilityTier, axisExplicitNegatives, reversibilityProbes, toolMarkSources } = prepareSafetyScan({ spec, deps });
309
+ const { toolEffects, wakeEffects, egressTools, irreversibleTools, irreversibilityTier, axisExplicitNegatives, reversibilityProbes, toolMarkSources } = prepareSafetyScan({ spec, deps });
309
310
  let shellGatedTools = new Set();
310
311
  refuseRequireExistingWithoutSession(spec);
311
312
  refuseRegistryScopeMismatch(spec, internals);
@@ -318,7 +319,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
318
319
  throw e;
319
320
  }
320
321
  const fileHistoryRequest = resolveFileHistoryRequest(spec, deps);
321
- const { acquired, session, conflictRef, wakeRecovered, branch } = await prepareAcquireReconcile({ sessions, spec, resume, toolEffects, report: (e, id) => deps.onError?.(e, { phase: "config", sessionId: id }), ...(internals?.sessionPlacement !== undefined ? { placement: internals.sessionPlacement } : {}), ...(() => { const g = durableParkGapFor(deps, spec); return g !== undefined ? { durableParkGap: g } : {}; })() });
322
+ const { acquired, session, conflictRef, wakeRecovered, branch } = await prepareAcquireReconcile({ sessions, spec, resume, wakeEffects, report: (e, id) => deps.onError?.(e, { phase: "config", sessionId: id }), ...(internals?.sessionPlacement !== undefined ? { placement: internals.sessionPlacement } : {}), ...(() => { const g = durableParkGapFor(deps, spec); return g !== undefined ? { durableParkGap: g } : {}; })() });
322
323
  const sessionId = acquired.sessionId;
323
324
  await holdSessionLock?.(sessionId);
324
325
  const onceLedger = await loadAnnounceOnceLedger(session, resume?.seed.announcedListings, deps.onError);
@@ -377,6 +378,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
377
378
  if (!handsEnabled)
378
379
  refuseUserAttachmentPathsWithoutWorkspace(userAttachmentsSeat);
379
380
  const externalContentTargetActive = executionEnv.externalContentTarget === true || resume?.seed.externalContentTarget === true;
381
+ const crossBoundaryTree = joinedCrossBoundaryTree(internals?.crossBoundaryTree, (m) => deps.onError?.(new Error(m), { phase: "config", sessionId }));
380
382
  const abortController = new AbortController();
381
383
  if (spec.signal?.aborted)
382
384
  abortController.abort();
@@ -457,7 +459,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
457
459
  let handsLessResolvedWriteFace;
458
460
  const mcpPool = installedPreflight.mcp?.length ? { pool: internals?.mcpPool ?? new McpConnectionPool(), owned: internals?.mcpPool === undefined } : undefined;
459
461
  const mountedMcpNow = mcpPool !== undefined ? () => mountedMcpOf({ declared: installedPreflight.mcp, roster: roster.tools, aggregateNames: new Set(mcp.tools.filter((t) => t.mcpRemoteName === undefined).map((t) => t.name)), pool: mcpPool.pool }) : undefined;
460
- const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, permissionMode, commitModeSeats, endModeCeiling, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, ancestorSessionRulesRef, ancestorRulesNow, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, runClampSource, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, frozenOnAsk, hookEnvSource, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, askSeat: doors.askSeat, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight: installedPreflight, pathRuleAnchors: { chainTop, onLeg: onLeg.chained }, checkpointSeat, checkpointScope, toolFaceSnapshot, mountsCallerTool, ...(mountedMcpNow !== undefined ? { mountedMcp: mountedMcpNow } : {}), promptProfile, resolvedInteractionPosture, permissionModeSeat, handsEnabled, reportUsage, harnessRef, skillGrants, requestAllowedTools: allowedToolTables.request, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, modBus: legMods.bus, ownModChain, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDeciderRef.current, autoModeDenialTracking: () => autoModeDenialTrackingRef.current, autoModeArming: () => autoModeArmingRef.current, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, resolvedWriteFace: () => resolvedWriteFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, handsLessResolvedWriteFace: () => handsLessResolvedWriteFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
462
+ const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, permissionMode, commitModeSeats, endModeCeiling, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, ancestorSessionRulesRef, ancestorRulesNow, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, runClampSource, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, frozenOnAsk, hookEnvSource, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, askSeat: doors.askSeat, crossBoundaryTree, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight: installedPreflight, pathRuleAnchors: { chainTop, onLeg: onLeg.chained }, checkpointSeat, checkpointScope, toolFaceSnapshot, mountsCallerTool, ...(mountedMcpNow !== undefined ? { mountedMcp: mountedMcpNow } : {}), promptProfile, resolvedInteractionPosture, permissionModeSeat, handsEnabled, reportUsage, harnessRef, skillGrants, requestAllowedTools: allowedToolTables.request, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, modBus: legMods.bus, ownModChain, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDeciderRef.current, autoModeDenialTracking: () => autoModeDenialTrackingRef.current, autoModeArming: () => autoModeArmingRef.current, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, resolvedWriteFace: () => resolvedWriteFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, handsLessResolvedWriteFace: () => handsLessResolvedWriteFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
461
463
  bindPermissionModeSeat(permissionMode);
462
464
  const personRowNotices = { onUnread: ruleStoreUnreadableNotice(deps.onNotice, { sessionId, runId }), onRowsDropped: ruleRowsDroppedNotice(deps.onNotice, { sessionId, runId }) };
463
465
  const readerOf = (signals) => personPathRowsOfTask({ deps, notices: personRowNotices, principal: spec.principal, ids: { sessionId, runId, taskId: hostTaskId }, root: taskRootFinal, rootCanonical: taskRootCanonical, leads: headLeads, chainTop, occurrences: toolOccurrences, signals });
@@ -475,8 +477,9 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
475
477
  const legExemptRoots = Object.freeze(dataRootSpellings(deps.memoryEngineDir));
476
478
  const legWriteGuard = { exemptRoots: legExemptRoots, rows: toolPolicyWriteGuardRows([installedToolPolicy, ...(inheritedParentConstraints ?? []).map((c) => c.policy)]) };
477
479
  const sideCallBookRef = {};
478
- const { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDeciderRef, autoModeDenialTrackingRef, autoModeArmingRef, armAutoMode, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline } = await prepareCapsAndWorkflow({ spec, deps, askSeat: doors.askSeat, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, checkpointSeat, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, parentSpecSeat, runClampSource, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, permissionMode, readDenyEntries: () => personRows.tablesReady().then(() => ({ entries: readDenyMatcher?.entries ?? [], ruleRows: pathTables?.ruleRows() ?? effectivePathDenyRules })), peerLaneActive, peerSendMessageBuiltIn, runnerSelf, memoryEngineSession: () => memoryEngineSession, centerAdoption: () => centerAdoptionRef.current, delegated: delegation.isDelegatedChild, sideCallBookRef });
480
+ const { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDeciderRef, autoModeDenialTrackingRef, autoModeArmingRef, armAutoMode, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline } = await prepareCapsAndWorkflow({ spec, deps, askSeat: doors.askSeat, internals, crossBoundaryTree, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, checkpointSeat, toolEffects, safetyAxes: { irreversibilityTier, irreversibleTools, reversibilityProbes, egressTools, toolMarkSources }, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, parentSpecSeat, runClampSource, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, permissionMode, readDenyEntries: () => personRows.tablesReady().then(() => ({ entries: readDenyMatcher?.entries ?? [], ruleRows: pathTables?.ruleRows() ?? effectivePathDenyRules })), peerLaneActive, peerSendMessageBuiltIn, runnerSelf, memoryEngineSession: () => memoryEngineSession, centerAdoption: () => centerAdoptionRef.current, delegated: delegation.isDelegatedChild, sideCallBookRef });
479
481
  const tools = roster.tools;
482
+ const crossBoundary = await prepareCrossBoundaryLane({ token: crossBoundaryTree, posture: doors.crossBoundaryPosture, externalContentTargetActive, env: executionEnv, session, resumeLeg: resume !== undefined, sessionId, runId, hostTaskId, deps });
480
483
  const pausedRef = {};
481
484
  const undeliveredContinuationRef = { current: { parkedSteers: [], orphanTasks: [] } };
482
485
  const remoteEnvFailures = [];
@@ -786,7 +789,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
786
789
  }
787
790
  }
788
791
  const { basePolicyForResumeEdit, denyNarrowingPolicy, skillGrantLane, allowEntryLanes, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, grantBindingOf, permissionRuleLane, ruleLaneFacts, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions, ancestorArbitrations, inheritedToolChecks } = await preparePolicyChain({ spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, additionalRootsCanonical, executionEnv, lockedPreflight: installedPreflight, pathRuleAnchors: { leg: legAnchors, chainTop }, headLeads, tools, harnessTools, selector: toolFaceSnapshot.selector, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, toolMarkSources, envHandToolNames, handsCwdRef, readDenyMatcher, personRows, questionToolMounted, runtimeCaps, inheritedAncestorRules, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, skillGrants, skillSpecs, allowedToolTables, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, modBus: legMods.bus, ownModChain, autoModeDecider: () => autoModeDeciderRef.current, readFace: () => resolvedReadFace, permissionMode, scratchpadDir: spec.envFacts?.scratchpadDir, toolRosterDeltas: rosterSeat, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef });
789
- const { onAsk, preToolContexts, blockedToolCalls, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, writeProtection, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace, sessionBoxBound } = prepareWiringManifest({ spec, deps, askSeat: doors.askSeat, internals, resume, sessionId, runId, hostTaskId, taskScope, modBus: legMods.bus, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, legWriteGuard, mcp, irreversibleTools, egressTools, shellReadStationArmed: handsReadFace.shellReadStationArmed, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, permissionMode, lockedPreflight, peerLaneRefs, frameSettlement, harness, pausedRef, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive: handsReadFace.readDenyBuiltinTiersActive, lspManagerWired, lspDiagnosticsLive: lspDiagnostics !== undefined, fileHistoryFact, sessionBox, checkpointScope, memoryPollution: () => memoryEngineSession?.pollution });
792
+ const { onAsk, preToolContexts, blockedToolCalls, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, writeProtection, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace, sessionBoxBound } = prepareWiringManifest({ spec, deps, askSeat: doors.askSeat, crossBoundaryStationEngaged: crossBoundary.stationEngaged, internals, resume, sessionId, runId, hostTaskId, taskScope, modBus: legMods.bus, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, legWriteGuard, mcp, irreversibleTools, egressTools, shellReadStationArmed: handsReadFace.shellReadStationArmed, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, permissionMode, lockedPreflight, peerLaneRefs, frameSettlement, harness, pausedRef, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive: handsReadFace.readDenyBuiltinTiersActive, lspManagerWired, lspDiagnosticsLive: lspDiagnostics !== undefined, fileHistoryFact, sessionBox, checkpointScope, memoryPollution: () => memoryEngineSession?.pollution });
790
793
  const writeProtectionCheck = writeProtection.mount?.check;
791
794
  writeTargetJudgeRef.current = writeProtection.judgeWriteTarget;
792
795
  if (fileHistoryBoundary !== undefined) {
@@ -796,20 +799,20 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
796
799
  });
797
800
  }
798
801
  const listPathRows = () => skillSpecs.flatMap((s) => compileSkillGrant(s, "model").rows).flatMap((r) => (r.behavior === "deny" && r.compiled.kind === "path" ? [r.compiled.rule] : []));
799
- const stampCallTarget = attachmentRootCanonical === undefined ? undefined : legCallTargetStamp({ env: executionEnv, root: attachmentRootCanonical, cwd: () => handsCwdRef?.current, judgesPaths: () => effectivePolicy?.pathRules !== undefined || basePolicyForResumeEdit?.pathRules !== undefined || permissionRuleLane !== undefined || skillSpecs.some((s) => compileSkillGrant(s, "model").rows.some((r) => r.compiled.kind === "path")) || allowedToolTables.request.holdsPathRows() || allowedToolTables.deployment.holdsPathRows(), leads: () => headLeads.resolve([...toolPolicyPathRules([effectivePolicy, basePolicyForResumeEdit, ...(inheritedParentConstraints ?? []).map((c) => c.policy)], legAnchors), ...bindPathRules(listPathRows().map((rule) => ({ parsed: rule, ruleText: rule.rule })), legAnchors)]) });
802
+ const stampCallTarget = attachmentRootCanonical === undefined ? undefined : legCallTargetStamp({ env: executionEnv, root: attachmentRootCanonical, cwd: () => handsCwdRef?.current, judgesPaths: () => parkLaneArmed || effectivePolicy?.pathRules !== undefined || basePolicyForResumeEdit?.pathRules !== undefined || permissionRuleLane !== undefined || skillSpecs.some((s) => compileSkillGrant(s, "model").rows.some((r) => r.compiled.kind === "path")) || allowedToolTables.request.holdsPathRows() || allowedToolTables.deployment.holdsPathRows(), leads: () => headLeads.resolve([...toolPolicyPathRules([effectivePolicy, basePolicyForResumeEdit, ...(inheritedParentConstraints ?? []).map((c) => c.policy)], legAnchors), ...bindPathRules(listPathRows().map((rule) => ({ parsed: rule, ruleText: rule.rule })), legAnchors)]) });
800
803
  const { askLane } = prepareAskLane({ gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, handsRoot: attachmentRootCanonical, stampCallTarget, advertisedWritableDirs, exemptRoots: legExemptRoots, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, grantBindingOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking: autoModeDenialTrackingRef, spec, deps, sessionId, runId, modBus: legMods.bus, notifyOwnHookCrash, grantReadRoot: handsReadFace.grantReadRoot });
801
804
  const inheritedAnchorRecords = chainAnchorRecords(chainTop, inheritedParentConstraints ?? []);
802
- const { saga } = prepareSuspendSaga({ gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, reminderMark, handsCwdRef, handsRoot: attachmentRootCanonical, handsHome: attachmentRootCanonical !== undefined ? legAnchors.home : undefined, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, inheritedPathRuleAnchors: chainTop !== legAnchors ? inheritedAnchorRecords.pathRuleAnchors : undefined, inheritedPathRuleInstallations: inheritedAnchorRecords.pathRuleInstallations, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, checkpointScope, toolCeiling, toolListsJudged, ownToolLists, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
805
+ const { saga } = prepareSuspendSaga({ gateMachineryActive, crossBoundary, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, reminderMark, handsCwdRef, handsRoot: attachmentRootCanonical, handsHome: attachmentRootCanonical !== undefined ? legAnchors.home : undefined, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, inheritedPathRuleAnchors: chainTop !== legAnchors ? inheritedAnchorRecords.pathRuleAnchors : undefined, inheritedPathRuleInstallations: inheritedAnchorRecords.pathRuleInstallations, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, checkpointScope, toolCeiling, toolListsJudged, ownToolLists, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
803
806
  const { suspendForResource, suspendForPlatformLimit, suspendForReview } = prepareBoundaryParks({ saga, spec, checkpointStore, checkpointScope, abortController, harness, session, sessions, sessionId, deps, priorLedger, maxSlices, maxSuspends, resourceTotal, priorSuspendCount, suspendChainBase, humanReviewRef, liveSpendRef, now, pausedRef, remoteEnvFailures, resourceSuspendEligible, durableSuspendInfraReady, incompleteSuspendAdapter });
804
807
  const { parkAsk } = prepareParkAsk({ askLane, saga, spec, deps, sessionId, checkpointStore, checkpointScope, toolRosterDeltas: rosterSeat, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, handsRoot: attachmentRootCanonical, stampCallTarget, advertisedWritableDirs, exemptRoots: legExemptRoots, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, toolMarkSources, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, ruleOffersOf, grantBindingOf, now, humanReviewRef, abortController, harness, pausedRef });
805
808
  const seatInputsFor = skillGateWiring({ tools, skillToolName: SKILL_TOOL_NAME, seatOf: skillSeatOf, mode: () => permissionMode.current, lane: skillGrantLane, onAllowed: (info) => emitTrace(deps.tracer, () => ({ kind: "permission.skill_allowed", version: 1, taskId: hostTaskId, ...info, entries: [...info.entries], ts: Date.now() })), allowEntries: { deploymentAllows: { ...allowEntryLanes.deployment, onAllowed: (info) => emitTrace(deps.tracer, () => ({ kind: "permission.allowed_tools_allowed", version: 1, taskId: hostTaskId, source: "deployment", ...info, entries: [...info.entries], ts: Date.now() })) }, requestAllows: { ...allowEntryLanes.request, onAllowed: (info) => emitTrace(deps.tracer, () => ({ kind: "permission.allowed_tools_allowed", version: 1, taskId: hostTaskId, source: "request", ...info, entries: [...info.entries], ts: Date.now() })) } } });
806
- const { approvedCallScreen } = prepareGateStations({ askLane, parkAsk, tools, toolRosterDeltas: rosterSeat, toolEffects, deps, toolCallGateArmedRef, effectivePolicy, modBus: legMods.bus, inheritedToolChecks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, toolOccurrences, batchHaltRef, blockedTracked, hookIdentity, reminderMark, hostTaskId, sessionId, handsCwdRef, stampCallTarget, readDenyInForce: (toolCallId) => ({ tiers: handsReadFace.readDenyBuiltinTiersActive, rows: [...readDenyAdditionsNormalized.map((e) => e.pattern), ...(pathTables?.forCall(toolCallId).ruleRows ?? handsReadFaceInput.denyRuleRows).filter((r) => r.faces.includes("read")).map((r) => r.rule)] }), hookEnvFace, writeProtectionCheck, shellReadCheck, readFace: () => resolvedReadFace, irreversibilityTier, reversibilityProbes, abortController, shellGatedTools, autoModeDecider: autoModeDeciderRef, autoModeDenialTracking: autoModeDenialTrackingRef, askRoute: { ...wiringManifest.ask, effective: askSeatEffective(wiringManifest) }, permissionMode, toolMarkSources, ...(deps.a2a?.isolatePeers === true ? { a2aIsolatePeers: true } : {}), ancestorArbitrations, runId, stopForDenialLimit, permissionRuleLane, seatInputsFor, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, frameSettlement });
809
+ const { approvedCallScreen } = prepareGateStations({ askLane, parkAsk, tools, toolRosterDeltas: rosterSeat, crossBoundaryCheck: crossBoundary.seat({ tools, roster: rosterSeat }), toolEffects, deps, toolCallGateArmedRef, effectivePolicy, modBus: legMods.bus, inheritedToolChecks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, toolOccurrences, batchHaltRef, blockedTracked, hookIdentity, reminderMark, hostTaskId, sessionId, handsCwdRef, stampCallTarget, readDenyInForce: (toolCallId) => ({ tiers: handsReadFace.readDenyBuiltinTiersActive, rows: [...readDenyAdditionsNormalized.map((e) => e.pattern), ...(pathTables?.forCall(toolCallId).ruleRows ?? handsReadFaceInput.denyRuleRows).filter((r) => r.faces.includes("read")).map((r) => r.rule)] }), hookEnvFace, writeProtectionCheck, shellReadCheck, readFace: () => resolvedReadFace, irreversibilityTier, reversibilityProbes, abortController, shellGatedTools, autoModeDecider: autoModeDeciderRef, autoModeDenialTracking: autoModeDenialTrackingRef, askRoute: { ...wiringManifest.ask, effective: askSeatEffective(wiringManifest) }, permissionMode, toolMarkSources, ...(deps.a2a?.isolatePeers === true ? { a2aIsolatePeers: true } : {}), ancestorArbitrations, runId, stopForDenialLimit, permissionRuleLane, seatInputsFor, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, frameSettlement });
807
810
  const postureFrameRef = { report: (err) => deps.onError?.(err, { phase: "degraded", sessionId }) };
808
811
  const { microCompact, charsPerToken } = prepareContextLane({ model, deps, sessionId, runId, hostTaskId, offloadStore, toolRosterDeltas: rosterSeat, microCompactKnob, harness, batchHaltRef, gitStatusRef, postureFrameRef, requestLossyRef, trimPressureRef, contextOverlay: legContextOverlay, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}) });
809
812
  const preparedHolder = {};
810
- const { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, readTaskFile, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, syntheticReadVerdict, consolidationWriteJudge, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveWriteFaceObserved, effectiveReadDenyObserved } = prepareTurnWiring({ deps, systemPromptSeat, harnessTools, fpRef, model, promptIdentityDigest: promptManifest.identity.artifact, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, readRoots, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, skillGrants: skillGrantLane, callerPolicy: installedToolPolicy, inheritedPolicies: (inheritedParentConstraints ?? []).map((c) => c.policy), persistedRuleLane: permissionRuleLane, ruleLaneFacts, personRowsBeyondRun, orgRuleLane: permissionRuleOrgLane, stampCallTarget, abortController, hostTaskId, taskScope, buildAssembleInputs, identityFor, adoptsCandidates, centerAdoptionRef, harnessRef, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder });
813
+ const { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, compactionRestore, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, syntheticReadVerdict, consolidationWriteJudge, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveWriteFaceObserved, effectiveReadDenyObserved } = prepareTurnWiring({ deps, systemPromptSeat, harnessTools, fpRef, model, promptIdentityDigest: promptManifest.identity.artifact, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, readRoots, modelFileReader: modelFileReaderSeat.current, reminderMark, reminderDisclosureCounts, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, skillGrants: skillGrantLane, callerPolicy: installedToolPolicy, inheritedPolicies: (inheritedParentConstraints ?? []).map((c) => c.policy), persistedRuleLane: permissionRuleLane, ruleLaneFacts, personRowsBeyondRun, orgRuleLane: permissionRuleOrgLane, stampCallTarget, abortController, hostTaskId, taskScope, buildAssembleInputs, identityFor, adoptsCandidates, centerAdoptionRef, harnessRef, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder });
811
814
  await onceLedger.settle(session, announcedListingsRef);
812
- const buildPrepared = () => ({ harness, session, sessionId, runId, registryAccess: { owner: hostTaskId, scope: taskScope }, reminderMark, reminderDisclosureCounts, fullShellReachable, approvalPosture: { get mode() { return permissionMode.current; }, askEffective: askSeatEffective(wiringManifest) }, ...(outputStyleFrame !== undefined ? { outputStyleFrame } : {}), permissionMode, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(mcpRedial !== undefined ? { mcpRedial } : {}), ...(a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, toolOccurrences, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(fileHistoryBoundary !== undefined ? { fileHistoryBoundary } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved, effectiveWriteFace: effectiveWriteFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(attachmentRootCanonical !== undefined ? { handsRoot: attachmentRootCanonical } : {}), ...(stampCallTarget !== undefined ? { stampCallTarget } : {}), toolProgressRef, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), exemptRoots: legExemptRoots, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, skillGrants: skillGrantLane, skillSpecs, ...(permissionRuleLane !== undefined ? { persistedRuleLane: permissionRuleLane } : {}), ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), consolidationWriteJudge, ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, endModeCeiling, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, promptIdentity, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, pausedRef, undeliveredContinuationRef, suspendProgressRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, workCutRef, brainCallGuardrailRef, gateStopRef, stopForDenialLimit, suspendForReview, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}), resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolRoster, toolRosterDeltas: rosterSeat, structuredProjector, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, microCompact, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit && withheldDiagnosticsOf ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent, withheldOf: withheldDiagnosticsOf } } : {}), stopRequestedRef, announcedSnapshotRecovered: onceLedger.recovered, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(projectInstructionContent !== undefined ? { projectInstructionContent } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, frameReceipts: { pending: [], listingSnapshotOwed: false }, frameSettlement, ...(userAttachmentsSeat !== undefined ? { userAttachments: userAttachmentsSeat } : {}), attachmentDelivery: createAttachmentDelivery(), ...(modelFileReaderSeat.current !== undefined ? { modelFileReader: modelFileReaderSeat.current } : {}), syntheticReadVerdict, ...(peerLaneRefs.boundaryRound !== undefined ? { peerBoundaryRound: peerLaneRefs.boundaryRound } : {}), gitStatusRef, postureFrameRef, listBackgroundTasks, hookIdentity, modBus: legMods.bus, sideCallBookRef, ...(sessionBoxBound !== undefined ? { sessionBox: sessionBoxBound } : {}), ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}), ...(shellReadCheck !== undefined ? { shellReadCheck } : {}), ...(toolDisclosureSeat !== undefined ? { toolDisclosure: toolDisclosureSeat } : {}), ...(approvedCallScreen !== undefined ? { approvedCallScreen } : {}) });
815
+ const buildPrepared = () => ({ harness, session, sessionId, runId, crossBoundary, registryAccess: { owner: hostTaskId, scope: taskScope }, reminderMark, reminderDisclosureCounts, fullShellReachable, approvalPosture: { get mode() { return permissionMode.current; }, askEffective: askSeatEffective(wiringManifest) }, ...(outputStyleFrame !== undefined ? { outputStyleFrame } : {}), permissionMode, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(mcpRedial !== undefined ? { mcpRedial } : {}), ...(a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, toolOccurrences, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(fileHistoryBoundary !== undefined ? { fileHistoryBoundary } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved, effectiveWriteFace: effectiveWriteFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(attachmentRootCanonical !== undefined ? { handsRoot: attachmentRootCanonical } : {}), ...(stampCallTarget !== undefined ? { stampCallTarget } : {}), toolProgressRef, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), exemptRoots: legExemptRoots, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, skillGrants: skillGrantLane, skillSpecs, ...(permissionRuleLane !== undefined ? { persistedRuleLane: permissionRuleLane } : {}), ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), consolidationWriteJudge, ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, endModeCeiling, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, promptIdentity, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, pausedRef, undeliveredContinuationRef, suspendProgressRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, workCutRef, brainCallGuardrailRef, gateStopRef, stopForDenialLimit, suspendForReview, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}), resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolRoster, toolRosterDeltas: rosterSeat, structuredProjector, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, ...(compactionRestore !== undefined ? { compactionRestore } : {}), recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, microCompact, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit && withheldDiagnosticsOf ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent, withheldOf: withheldDiagnosticsOf } } : {}), stopRequestedRef, announcedSnapshotRecovered: onceLedger.recovered, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(projectInstructionContent !== undefined ? { projectInstructionContent } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, frameReceipts: { pending: [], listingSnapshotOwed: false }, frameSettlement, ...(userAttachmentsSeat !== undefined ? { userAttachments: userAttachmentsSeat } : {}), attachmentDelivery: createAttachmentDelivery(), ...(modelFileReaderSeat.current !== undefined ? { modelFileReader: modelFileReaderSeat.current } : {}), syntheticReadVerdict, ...(peerLaneRefs.boundaryRound !== undefined ? { peerBoundaryRound: peerLaneRefs.boundaryRound } : {}), gitStatusRef, postureFrameRef, listBackgroundTasks, hookIdentity, modBus: legMods.bus, sideCallBookRef, ...(sessionBoxBound !== undefined ? { sessionBox: sessionBoxBound } : {}), ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}), ...(shellReadCheck !== undefined ? { shellReadCheck } : {}), ...(toolDisclosureSeat !== undefined ? { toolDisclosure: toolDisclosureSeat } : {}), ...(approvedCallScreen !== undefined ? { approvedCallScreen } : {}) });
813
816
  refuseLateRosterChanges(callerRoster.roster);
814
817
  rollback.commit();
815
818
  commitModeSeats(abortController.signal);
@@ -12,10 +12,11 @@ import { type ConsolidationWriteJudgeLeg } from "./memory-consolidation-write-ju
12
12
  import type { RunnerDeps, TaskSpec } from "../types.js";
13
13
  import type { CwdRef } from "../../tools/fs/fs-shared.js";
14
14
  import { type ContainmentFace } from "../../tools/fs/index.js";
15
- import type { PlacedReadDenyMatcher } from "../../tools/fs/read-deny-home.js";
16
15
  import type { ReadRootsSeat } from "./person-path-rows.js";
17
16
  import { type ReadFileState } from "../../tools/fs/safety.js";
18
17
  import type { Prepared } from "./contracts.js";
18
+ import type { ModelFileReader } from "../../tools/fs/fs-read.js";
19
+ import type { ReminderDisclosureCounts } from "../reminder-disclosure.js";
19
20
  export interface PrepareTurnWiringInput {
20
21
  /** borrowed-readonly — the deployment seats: `cacheBreakDetection` (the detector knob), `onError` (the attachment-skip
21
22
  * degraded line), `promptSource` (the center candidate's state and current artifact), `permissionRuleStore` and
@@ -73,8 +74,12 @@ export interface PrepareTurnWiringInput {
73
74
  /** borrowed-readonly — the read face's root set beside the attachment root, read per use: the write roots, the read
74
75
  * roots with the run's grants, the person's read directories as the run read them last (no call: `ready` first). */
75
76
  readRoots: (() => readonly string[]) & Pick<ReadRootsSeat, "ready">;
76
- /** borrowed-readonly — the run's read deny table (its latest; these readers are no call), or undefined (the reader's withheld arm). */
77
- readDenyMatcher: PlacedReadDenyMatcher | undefined;
77
+ /** borrowed-readonly — the leg's one file reader (the hands band's), or undefined without hands: the restore reads through it. */
78
+ modelFileReader: ModelFileReader | undefined;
79
+ /** borrowed-readonly — the run's reminder mark (the restore frames' marked blocks). */
80
+ reminderMark: string | undefined;
81
+ /** borrowed-mutable — the run's disclosure counters; the restore frames' scans bump them when a frame is delivered. */
82
+ reminderDisclosureCounts: ReminderDisclosureCounts | undefined;
78
83
  /** borrowed-readonly — the resolved read face, or undefined (the fence's ninth argument). */
79
84
  resolvedReadFace: ContainmentFace | undefined;
80
85
  /** borrowed-readonly — the tracked-cwd seat, read per call by the kept-tail normalizer (never written here). */
@@ -148,8 +153,8 @@ export interface PrepareTurnWiringResult {
148
153
  } | undefined;
149
154
  /** owned — the fixed prompt-overhead term in the compaction trigger's coordinate (`Prepared.promptOverheadTokens`). */
150
155
  promptOverheadTokens: number;
151
- /** owned — the fenced working-file reader, or undefined without hands (`Prepared.readTaskFile`). */
152
- readTaskFile: Prepared["readTaskFile"];
156
+ /** owned — the post-compaction restore, or undefined without hands (`Prepared.compactionRestore`). */
157
+ compactionRestore: Prepared["compactionRestore"];
153
158
  /** owned — the kept-tail path normalizer, or undefined without hands. */
154
159
  normalizeAttachmentPath: Prepared["normalizeAttachmentPath"];
155
160
  /** owned — the Read tool's dedup-stub predicate, or undefined without hands. */
@@ -8,14 +8,13 @@ import { createSyntheticReadJudge } from "../synthetic-read-verdict.js";
8
8
  import { createConsolidationWriteJudge } from "./memory-consolidation-write-judge.js";
9
9
  import { toolCallFaceOf } from "../tool-roster.js";
10
10
  import { ORG_ADJUDICATION_TIMEOUT_MS } from "../permission-rule-org.js";
11
- import { decodeTextBytes } from "../../tools/fs/encoding.js";
12
- import { applyContextShrinkToReadFileState, isReadDedupStubResult } from "../../tools/fs/index.js";
11
+ import { applyContextShrinkToReadFileState, isReadDedupStubResult, readFileStateAfterSummary } from "../../tools/fs/index.js";
13
12
  import { resolveKey } from "../../tools/fs/safety.js";
14
13
  import { PROMPT_HASH_SALT } from "./prompt-hash-salt.js";
15
14
  import { CHANGED_FILES_MTIME_EPS_MS } from "./turn-attachments.js";
16
- import { thrownText } from "../thrown-value.js";
15
+ import { readCompactionRestore } from "../user-attachment.js";
17
16
  export function prepareTurnWiring(input) {
18
- const { deps, systemPromptSeat, harnessTools, fpRef, model, promptIdentityDigest, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, readRoots, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, skillGrants, callerPolicy, inheritedPolicies, persistedRuleLane, ruleLaneFacts, personRowsBeyondRun, orgRuleLane, stampCallTarget, abortController, hostTaskId, taskScope, buildAssembleInputs, identityFor, adoptsCandidates, centerAdoptionRef, harnessRef, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder } = input;
17
+ const { deps, systemPromptSeat, harnessTools, fpRef, model, promptIdentityDigest, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, readRoots, modelFileReader, reminderMark, reminderDisclosureCounts, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, skillGrants, callerPolicy, inheritedPolicies, persistedRuleLane, ruleLaneFacts, personRowsBeyondRun, orgRuleLane, stampCallTarget, abortController, hostTaskId, taskScope, buildAssembleInputs, identityFor, adoptsCandidates, centerAdoptionRef, harnessRef, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder } = input;
19
18
  const cacheBreakDetector = deps.cacheBreakDetection === false ? undefined : new CacheBreakDetector();
20
19
  const cacheFingerprint = cacheBreakDetector
21
20
  ? { systemPrompt: systemPromptSeat.current, tools: toolsToFingerprintInputs(harnessTools) }
@@ -41,49 +40,6 @@ export function prepareTurnWiring(input) {
41
40
  promptManifest.lowering = turnSnapshot.lowering;
42
41
  const promptOverheadTokens = Math.ceil((systemPromptSeat.current.length +
43
42
  harnessTools.reduce((a, t) => a + t.name.length + (t.description?.length ?? 0) + JSON.stringify(t.parameters ?? {}).length, 0)) / charsPerToken);
44
- const announceAttachmentSkip = (path, reason) => {
45
- deps.onError?.(new Error(`working-file attachment skipped — ${path}: ${reason}`), {
46
- phase: "degraded",
47
- sessionId,
48
- classification: "attachment-read",
49
- });
50
- };
51
- const readTaskFile = handsEnabled
52
- ? async (path) => {
53
- try {
54
- let key = path;
55
- if (attachmentRootCanonical !== undefined) {
56
- await readRoots.ready(abortController.signal);
57
- if (abortController.signal.aborted)
58
- return null;
59
- const rk = await resolveKey(executionEnv, attachmentRootCanonical, path, abortController.signal, undefined, readRoots(), undefined, readDenyMatcher, resolvedReadFace);
60
- if (!rk.ok) {
61
- announceAttachmentSkip(path, rk.violation.message);
62
- if (rk.violation.code === "read_path_denied" && rk.violation.pattern !== undefined) {
63
- return { withheld: { pattern: rk.violation.pattern } };
64
- }
65
- return null;
66
- }
67
- key = rk.key;
68
- }
69
- const r = await executionEnv.readBinaryFile(key, abortController.signal);
70
- if (!r.ok) {
71
- announceAttachmentSkip(path, r.error.message);
72
- return null;
73
- }
74
- const d = decodeTextBytes(r.value);
75
- if (d.malformed) {
76
- announceAttachmentSkip(path, "malformed text encoding (truncated UTF-16 body)");
77
- return null;
78
- }
79
- return d.text;
80
- }
81
- catch (err) {
82
- announceAttachmentSkip(path, thrownText(err));
83
- return null;
84
- }
85
- }
86
- : undefined;
87
43
  const normalizeAttachmentPath = handsEnabled
88
44
  ? async (path) => {
89
45
  if (attachmentRootCanonical === undefined)
@@ -108,7 +64,7 @@ export function prepareTurnWiring(input) {
108
64
  .map(([path]) => path)
109
65
  : undefined;
110
66
  const onCompactionApplied = handsEnabled && readFileStateForCheckpoint
111
- ? (attachedComplete, preserveReadState) => applyContextShrinkToReadFileState(readFileStateForCheckpoint, { kind: "summarized", attachedComplete, ...(preserveReadState !== undefined ? { preserveKeys: preserveReadState } : {}) })
67
+ ? (preserveReadState) => applyContextShrinkToReadFileState(readFileStateForCheckpoint, { kind: "summarized", preserveKeys: preserveReadState })
112
68
  : undefined;
113
69
  const syntheticLayers = {
114
70
  skillGrants,
@@ -120,6 +76,15 @@ export function prepareTurnWiring(input) {
120
76
  ...(stampCallTarget !== undefined ? { stampCallTarget } : {}),
121
77
  };
122
78
  const syntheticReadVerdict = createSyntheticReadJudge({ ...syntheticLayers, signal: abortController.signal });
79
+ const announceRestoreSkip = (path, reason) => {
80
+ deps.onError?.(new Error(`compaction restore did not deliver ${path}: ${reason}`), { phase: "degraded", sessionId, classification: "attachment-read" });
81
+ };
82
+ const compactionRestore = handsEnabled && modelFileReader !== undefined
83
+ ? {
84
+ restore: (ask) => readCompactionRestore({ reader: modelFileReader, judge: syntheticReadVerdict, cwd: () => handsCwdRef?.current, mark: reminderMark, counts: reminderDisclosureCounts, signal: abortController.signal, report: announceRestoreSkip }, { candidates: ask.candidates, maxFiles: ask.maxFiles, perFileChars: ask.perFileChars, totalChars: ask.totalChars, charsPerToken: ask.charsPerToken, dedupAgainst: readFileStateAfterSummary(readFileStateForCheckpoint ?? new Map(), ask.preserveKeys) }),
85
+ undelivered: announceRestoreSkip,
86
+ }
87
+ : undefined;
123
88
  const consolidationWriteJudge = createConsolidationWriteJudge({ ruleStoreProvider: deps.permissionRuleStore, principal: spec.principal, localOwnerDeclared: deps.localOwnerRules === true, ...(callerPolicy !== undefined ? { callerPolicy } : {}) }, { rows: personRowsBeyondRun, lanes: ruleLaneFacts, layers: { skillGrants, ...(denyNarrowingPolicy !== undefined ? { denyNarrowingPolicy } : {}), inheritedPolicies, ...(stampCallTarget !== undefined ? { stampCallTarget } : {}) }, facts: () => {
124
89
  const p = preparedHolder.current;
125
90
  return { face: toolCallFaceOf(p?.toolRoster, "Write"), cwd: p?.cwdRef?.current, root: p?.handsRoot, advertisedWritableDirs: p?.advertisedWritableDirs, exemptRoots: p?.exemptRoots };
@@ -218,5 +183,5 @@ export function prepareTurnWiring(input) {
218
183
  const effectiveReadFaceObserved = carrierReadFace();
219
184
  const effectiveWriteFaceObserved = carrierWriteFace();
220
185
  const effectiveReadDenyObserved = readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized.map((e) => ({ ...e })) : undefined;
221
- return { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, readTaskFile, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, syntheticReadVerdict, consolidationWriteJudge, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveWriteFaceObserved, effectiveReadDenyObserved };
186
+ return { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, compactionRestore, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, syntheticReadVerdict, consolidationWriteJudge, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveWriteFaceObserved, effectiveReadDenyObserved };
222
187
  }
@@ -82,9 +82,9 @@ export interface PrepareWiringManifestInput {
82
82
  irreversibleTools: ReadonlySet<string>;
83
83
  /** borrowed-readonly — see `irreversibleTools`. */
84
84
  egressTools: ReadonlySet<string>;
85
- /** borrowed-readonly — the hands phase mounted the shell READ STATION (a real shell was mounted): the gate
86
- * machinery must run for it, under every doctrine — the read-only face's containment IS that station. */
85
+ /** borrowed-readonly — the hands phase mounted the shell READ STATION (a real shell was mounted): the gate machinery must run for it, under every doctrine. */
87
86
  shellReadStationArmed: boolean;
87
+ /** borrowed-readonly — the leg's cross-boundary station is engaged (a declared posture, a target leg, a governed tree): the gate machinery runs for it. */ crossBoundaryStationEngaged: boolean;
88
88
  /** borrowed-readonly — the effect collection; read only here (the ungated scans). */
89
89
  toolEffects: ReadonlyMap<string, ToolEffect>;
90
90
  /** borrowed-readonly — the per-task owned env when a factory minted one (durable infra, the hook-env predicate). */
@@ -117,7 +117,7 @@ function announceDurableGateUnavailable(args) {
117
117
  });
118
118
  }
119
119
  export function prepareWiringManifest(input) {
120
- const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, modBus, checkpointScope, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, legWriteGuard, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, permissionMode, lockedPreflight, peerLaneRefs, frameSettlement, sessionBox, harness, pausedRef, askSeat, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive, lspManagerWired, shellReadStationArmed, lspDiagnosticsLive, fileHistoryFact, memoryPollution } = input;
120
+ const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, modBus, checkpointScope, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, legWriteGuard, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, permissionMode, lockedPreflight, peerLaneRefs, frameSettlement, sessionBox, harness, pausedRef, askSeat, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive, lspManagerWired, shellReadStationArmed, crossBoundaryStationEngaged, lspDiagnosticsLive, fileHistoryFact, memoryPollution } = input;
121
121
  const onAsk = askSeat.value;
122
122
  const handWriteTools = toolRoster.entries.filter((e) => e.mountedBy === "hands" && (e.effect === "write" || e.effect === "idempotent")).map((e) => e.name);
123
123
  const hasEffectAwareGate = policyLayers.length > 0 || chainJudges(modBus);
@@ -249,7 +249,7 @@ export function prepareWiringManifest(input) {
249
249
  modBus.hasHandlers("classic.PreToolUse") ||
250
250
  egressTools.size > 0 ||
251
251
  irreversibleTools.size > 0 ||
252
- shellReadStationArmed ||
252
+ shellReadStationArmed || crossBoundaryStationEngaged ||
253
253
  resourceSuspendEligible ||
254
254
  platformSuspendArmed ||
255
255
  spec.enablePlanMode === true;
@@ -1,4 +1,4 @@
1
- import { isRemoteExecutionEnv, missingRestoreSurface } from "../remote-env.js";
1
+ import { frozenHandleCopy, isRemoteExecutionEnv, missingRestoreSurface } from "../remote-env.js";
2
2
  import { remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./remote-env-retry.js";
3
3
  import { rebaseWorkspacePathAcross } from "./workspace-path.js";
4
4
  export { remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./remote-env-retry.js";
@@ -49,7 +49,7 @@ export async function prepareWorkspaceRestore(input) {
49
49
  refuseIdentityMismatch(ownedEnv.workspaceHandle());
50
50
  const { outcome: restored, attempts: restoreAttempts } = await restoreWorkspaceWithRetry(ownedEnv, handle.snapshotId, {
51
51
  abortSignal: restoreSignal,
52
- priorHandle: handle,
52
+ priorHandle: frozenHandleCopy(handle),
53
53
  });
54
54
  if (!restored.ok) {
55
55
  failResume(`resumeVM failed after ${restoreAttempts} attempt(s) (${restored.error.code}): ${restored.error.message}`, restored.error, remoteEnvFailureNote("resumeVM", restored.error, restoreAttempts));
@@ -3,6 +3,14 @@ import { assertResumeConfigRecord, checkpointStoreSeat, refuseResumeDoors } from
3
3
  import { asResumeConfigRefusal } from "../mode-policy.js";
4
4
  import { describeSuppliedValue } from "./decide-continuation.js";
5
5
  import { detachSkillLists } from "../skill-grant.js";
6
+ import { isGateKind, PAUSE_REGISTRY } from "../pause-registry.js";
7
+ const DECIDE_ENTRY_BY_RESUME_GATE = {
8
+ policy_ask: "a `policy_ask` outcome (decision allow/deny bound to the pending tool call)",
9
+ dry_run_review: "a `dry_run_review` outcome (decision approve/reject)",
10
+ plan_review: "a `plan_review` outcome (decision approve/edit/reject)",
11
+ resource_limit: 'a `resource_limit` outcome (decision "continue")',
12
+ task_done: undefined,
13
+ };
6
14
  export async function resumeAdmission(input) {
7
15
  const { token, outcome, taskConfig, runner, sessions, parentConstraintRegistry } = input;
8
16
  let internals = input.internals;
@@ -46,15 +54,7 @@ export async function resumeAdmission(input) {
46
54
  if (outcomeGate === "wake") {
47
55
  suppliedMessage = outcome.message;
48
56
  const gk = cp.gate.kind;
49
- const decideEntry = gk === "human" || gk === "irreversible_ask"
50
- ? 'a `policy_ask` outcome (decision allow/deny bound to the pending tool call)'
51
- : gk === "needs_review"
52
- ? 'a `dry_run_review` outcome (decision approve/reject)'
53
- : gk === "plan_review"
54
- ? 'a `plan_review` outcome (decision approve/edit/reject)'
55
- : gk === "resource_limit"
56
- ? 'a `resource_limit` outcome (decision "continue")'
57
- : undefined;
57
+ const decideEntry = isGateKind(gk) ? DECIDE_ENTRY_BY_RESUME_GATE[PAUSE_REGISTRY[gk].resume] : undefined;
58
58
  if (gk !== "task_done") {
59
59
  throw new CheckpointError("wake.gate_pending", `cannot wake: this checkpoint awaits a pending gate decision (gate "${gk}") — wake is not a decision ` +
60
60
  `channel; resume it with ${decideEntry ?? "its own gate outcome"} instead`);
@@ -13,7 +13,7 @@ import { orgVerdictBeforeClaim } from "./permission-rule-lanes.js";
13
13
  import { chainCannotJudge } from "./call-hook-stations.js";
14
14
  import { thrownText } from "../thrown-value.js";
15
15
  import { wireOf } from "../tool-name-readings.js";
16
- import { parkedSkillApprovalRefusal } from "../skill-grant.js";
16
+ import { judgeApprovalObject } from "../approval-object.js";
17
17
  import { SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, normalizeSkills } from "./synthetic-tools.js";
18
18
  import { skillLoadReading } from "./skill-base-dir.js";
19
19
  export async function resumeApply(input) {
@@ -76,9 +76,9 @@ export async function resumeApply(input) {
76
76
  };
77
77
  if (plainPolicyOutcome?.decision === "allow" && cp.pendingAction.kind === "tool_approval") {
78
78
  const servedSkills = normalizeSkills(config.skills).filter((s) => skillLoadReading(s, SKILL_CONTENT_MAX_CHARS).loads);
79
- const skillRefusal = parkedSkillApprovalRefusal(cp.pendingAction, plainPolicyOutcome.updatedInput ?? cp.pendingAction.args, servedSkills, SKILL_TOOL_NAME);
80
- if (skillRefusal !== undefined)
81
- throw new CheckpointError("checkpoint.invalid_outcome", skillRefusal, { field: "boundGrantDigest" });
79
+ const claimed = judgeApprovalObject(cp.pendingAction, { args: plainPolicyOutcome.updatedInput ?? cp.pendingAction.args, skills: servedSkills, skillToolName: SKILL_TOOL_NAME }, "claim");
80
+ if (claimed !== "match")
81
+ throw new CheckpointError("checkpoint.invalid_outcome", claimed.message, { field: "boundGrantDigest" });
82
82
  }
83
83
  if (plainPolicyOutcome !== undefined &&
84
84
  plainPolicyOutcome.decision === "allow" &&
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * The resume ladder's APPROVAL-LANE capture and binding rung (E4), verbatim from
3
3
  * `Runner.resumeStream`: on a human / irreversible_ask row every deployment-supplied field of the
4
- * `policy_ask` decide is read exactly once into a plain twin (answer canonicalized, updatedInput cloned to the
5
- * JSON domain, the decision word, the refused keys, the host's decision facts and attribution, the deny note),
4
+ * `policy_ask` decide is read exactly once into a plain twin (answer and updatedInput by the one capture, in their
5
+ * JSON form, the decision word, the refused keys, the host's decision facts and attribution, the deny note),
6
6
  * then the decision-action binding (boundCallId, boundInputHash by version), the env_failed replay guard and
7
7
  * the content-ask answer binding. Synchronous; every refusal throws pre-CAS.
8
8
  */