@sema-agent/core 7.17.6 → 7.18.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 (164) hide show
  1. package/CHANGELOG.md +165 -13
  2. package/dist/agents/send-message-tool.js +1 -0
  3. package/dist/agents/subagent.d.ts +1 -0
  4. package/dist/agents/subagent.js +5 -0
  5. package/dist/agents/teacher.js +1 -0
  6. package/dist/agents/verify.js +3 -0
  7. package/dist/brain/route-adjudicator.d.ts +18 -0
  8. package/dist/brain/route-adjudicator.js +16 -0
  9. package/dist/core/agent-definition.d.ts +10 -0
  10. package/dist/core/artifact-host.d.ts +41 -4
  11. package/dist/core/artifact-host.js +18 -2
  12. package/dist/core/auto-mode.d.ts +141 -45
  13. package/dist/core/auto-mode.js +109 -3
  14. package/dist/core/checkpoint-store.d.ts +16 -2
  15. package/dist/core/engine-notice.d.ts +47 -1
  16. package/dist/core/engine-notice.js +7 -0
  17. package/dist/core/gate-lanes.js +2 -1
  18. package/dist/core/gate-outcome.d.ts +17 -2
  19. package/dist/core/gate-outcome.js +16 -0
  20. package/dist/core/governance-codes.d.ts +1 -1
  21. package/dist/core/governance-codes.js +8 -0
  22. package/dist/core/hook-seats.d.ts +66 -0
  23. package/dist/core/hook-seats.js +37 -0
  24. package/dist/core/runner/advertised-writable-dirs.d.ts +8 -3
  25. package/dist/core/runner/assemble-result.d.ts +2 -1
  26. package/dist/core/runner/assemble-result.js +1 -1
  27. package/dist/core/runner/classifier-ladder.d.ts +89 -0
  28. package/dist/core/runner/classifier-ladder.js +65 -0
  29. package/dist/core/runner/contracts.d.ts +69 -13
  30. package/dist/core/runner/decide-continuation.d.ts +1 -3
  31. package/dist/core/runner/decide-continuation.js +1 -7
  32. package/dist/core/runner/deferral-census.d.ts +52 -0
  33. package/dist/core/runner/deferral-census.js +44 -0
  34. package/dist/core/runner/derived-route-fallback.d.ts +8 -4
  35. package/dist/core/runner/derived-route-fallback.js +8 -3
  36. package/dist/core/runner/gate-exit.d.ts +12 -0
  37. package/dist/core/runner/gate-exit.js +6 -3
  38. package/dist/core/runner/prepare-artifact.d.ts +10 -2
  39. package/dist/core/runner/prepare-artifact.js +5 -4
  40. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
  41. package/dist/core/runner/prepare-caps-and-workflow.js +30 -31
  42. package/dist/core/runner/prepare-config-doors.d.ts +1 -1
  43. package/dist/core/runner/prepare-config-doors.js +5 -3
  44. package/dist/core/runner/prepare-defer-classify.d.ts +13 -19
  45. package/dist/core/runner/prepare-defer-classify.js +8 -3
  46. package/dist/core/runner/prepare-gate-stations.d.ts +26 -0
  47. package/dist/core/runner/prepare-gate-stations.js +1 -1
  48. package/dist/core/runner/prepare-hands-readface.d.ts +24 -7
  49. package/dist/core/runner/prepare-hands-readface.js +60 -24
  50. package/dist/core/runner/prepare-inherited-gate.d.ts +17 -4
  51. package/dist/core/runner/prepare-inherited-gate.js +10 -2
  52. package/dist/core/runner/prepare-lsp.d.ts +2 -2
  53. package/dist/core/runner/prepare-lsp.js +1 -1
  54. package/dist/core/runner/prepare-policy-chain.js +2 -0
  55. package/dist/core/runner/prepare-project-context.js +4 -2
  56. package/dist/core/runner/prepare-prompt-inputs.d.ts +4 -2
  57. package/dist/core/runner/prepare-prompt-inputs.js +4 -1
  58. package/dist/core/runner/prepare-run-refs.d.ts +9 -1
  59. package/dist/core/runner/prepare-run-refs.js +3 -2
  60. package/dist/core/runner/prepare-suspend-saga.d.ts +5 -0
  61. package/dist/core/runner/prepare-suspend-saga.js +5 -2
  62. package/dist/core/runner/prepare-task.js +18 -13
  63. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +5 -0
  64. package/dist/core/runner/prepare-tool-disclosure-mount.js +10 -2
  65. package/dist/core/runner/prepare-turn-wiring.d.ts +8 -4
  66. package/dist/core/runner/prepare-turn-wiring.js +3 -2
  67. package/dist/core/runner/prepare-wiring-manifest.d.ts +5 -5
  68. package/dist/core/runner/prepare-wiring-manifest.js +5 -2
  69. package/dist/core/runner/resume-checkpoint-screen.js +7 -0
  70. package/dist/core/runner/run-harness-handlers.js +4 -1
  71. package/dist/core/runner/run-identity-wiring.js +6 -2
  72. package/dist/core/runner/run-leg.d.ts +2 -0
  73. package/dist/core/runner/run-leg.js +35 -41
  74. package/dist/core/runner/run-notification-lane.js +55 -27
  75. package/dist/core/runner/run-settle-and-teardown.js +1 -0
  76. package/dist/core/runner/run-terminal-adoption.js +16 -13
  77. package/dist/core/runner/run-turn-boundary.js +3 -1
  78. package/dist/core/runner/runtask.d.ts +6 -5
  79. package/dist/core/runner/runtask.js +26 -14
  80. package/dist/core/runner/skill-base-dir.d.ts +54 -0
  81. package/dist/core/runner/skill-base-dir.js +42 -0
  82. package/dist/core/runner/synthetic-tools.d.ts +16 -19
  83. package/dist/core/runner/synthetic-tools.js +18 -10
  84. package/dist/core/runner/tool-defer-gate.d.ts +22 -9
  85. package/dist/core/runner/tool-defer-gate.js +15 -5
  86. package/dist/core/runner/tool-disclosure.d.ts +5 -0
  87. package/dist/core/runner/tool-disclosure.js +2 -0
  88. package/dist/core/runner/tool-progress-lane.d.ts +42 -0
  89. package/dist/core/runner/tool-progress-lane.js +61 -0
  90. package/dist/core/runner-deps.d.ts +48 -7
  91. package/dist/core/swappable-deps.d.ts +9 -7
  92. package/dist/core/swappable-deps.js +7 -3
  93. package/dist/core/task-event.d.ts +96 -29
  94. package/dist/core/task-notification.d.ts +142 -16
  95. package/dist/core/task-notification.js +106 -0
  96. package/dist/core/task-result.d.ts +9 -1
  97. package/dist/core/task-spec.d.ts +20 -3
  98. package/dist/core/tighten-task-spec.js +7 -5
  99. package/dist/core/tool-model-gate.d.ts +1 -1
  100. package/dist/core/tool-search-setting.d.ts +78 -0
  101. package/dist/core/tool-search-setting.js +90 -0
  102. package/dist/core/tool-spec.d.ts +8 -0
  103. package/dist/core/types.d.ts +1 -1
  104. package/dist/core/types.js +1 -1
  105. package/dist/core/wiring-manifest.d.ts +46 -0
  106. package/dist/core/wiring-manifest.js +9 -1
  107. package/dist/engine/execution-env/node-execution-env.js +10 -4
  108. package/dist/engine/harness/agent-harness.d.ts +42 -0
  109. package/dist/engine/harness/agent-harness.js +61 -29
  110. package/dist/engine/loop/agent-loop.d.ts +68 -3
  111. package/dist/engine/loop/agent-loop.js +109 -16
  112. package/dist/index.d.ts +10 -5
  113. package/dist/index.js +9 -5
  114. package/dist/internal/harness.d.ts +1 -1
  115. package/dist/orchestration/run-workflow-tool.d.ts +3 -0
  116. package/dist/orchestration/run-workflow-tool.js +6 -1
  117. package/dist/orchestration/workflow-governance.d.ts +7 -1
  118. package/dist/orchestration/workflow-governance.js +9 -5
  119. package/dist/orchestration/workflow-primitives.d.ts +3 -0
  120. package/dist/orchestration/workflow-primitives.js +6 -1
  121. package/dist/orchestration/workflow-types.d.ts +48 -13
  122. package/dist/orchestration/workflow-types.js +1 -1
  123. package/dist/orchestration/workflow.js +45 -17
  124. package/dist/prompt-assembly/epoch.js +2 -0
  125. package/dist/prompt-assembly/packs/sema-default.js +2 -2
  126. package/dist/prompt-assembly/section-usage.d.ts +26 -0
  127. package/dist/prompt-assembly/section-usage.js +10 -0
  128. package/dist/prompt-assembly/types.d.ts +8 -6
  129. package/dist/prompts/default.d.ts +13 -0
  130. package/dist/prompts/default.js +16 -8
  131. package/dist/tools/artifact/artifact-text.d.ts +10 -1
  132. package/dist/tools/artifact/artifact-text.js +6 -3
  133. package/dist/tools/artifact/artifact-tool.d.ts +12 -2
  134. package/dist/tools/artifact/artifact-tool.js +203 -70
  135. package/dist/tools/artifact/conformance.d.ts +56 -0
  136. package/dist/tools/artifact/conformance.js +349 -0
  137. package/dist/tools/artifact/local-stub.js +1 -1
  138. package/dist/tools/artifact/reject-breaker.d.ts +28 -0
  139. package/dist/tools/artifact/reject-breaker.js +42 -0
  140. package/dist/tools/fs/bash-lexer.d.ts +132 -0
  141. package/dist/tools/fs/bash-lexer.js +563 -0
  142. package/dist/tools/fs/bash-program-position.d.ts +142 -0
  143. package/dist/tools/fs/bash-program-position.js +125 -0
  144. package/dist/tools/fs/bash-readonly-classifier.d.ts +54 -16
  145. package/dist/tools/fs/bash-readonly-classifier.js +375 -530
  146. package/dist/tools/fs/containment-face.d.ts +89 -0
  147. package/dist/tools/fs/containment-face.js +81 -0
  148. package/dist/tools/fs/fs-bash.d.ts +46 -1
  149. package/dist/tools/fs/fs-bash.js +158 -22
  150. package/dist/tools/fs/fs-read.d.ts +1 -1
  151. package/dist/tools/fs/fs-search-tools.d.ts +3 -3
  152. package/dist/tools/fs/fs-write.d.ts +4 -3
  153. package/dist/tools/fs/fs-write.js +9 -9
  154. package/dist/tools/fs/index.d.ts +24 -5
  155. package/dist/tools/fs/index.js +18 -6
  156. package/dist/tools/fs/repo-map.d.ts +2 -2
  157. package/dist/tools/fs/safety.d.ts +3 -3
  158. package/dist/tools/fs/safety.js +4 -4
  159. package/package.json +1 -1
  160. package/test/export-surface.snapshot.json +85 -9
  161. package/wire-changes/core@7.17.6.json +81 -0
  162. package/wire-changes/core@7.17.7.json +49 -0
  163. package/dist/tools/fs/read-face.d.ts +0 -68
  164. package/dist/tools/fs/read-face.js +0 -47
@@ -70,7 +70,9 @@ export function prepareInheritedGate(input) {
70
70
  const readDenyAdditionsNormalized = input.readDenyAdditionsNormalized();
71
71
  if (resolvedReadFace === undefined && resume !== undefined) {
72
72
  const seed = resume.seed.readFace;
73
- return seed !== undefined ? { face: seed.face, ...(seed.denyEntries !== undefined ? { denyEntries: seed.denyEntries.map((e) => ({ ...e })) } : {}) } : undefined;
73
+ if (seed === undefined)
74
+ return undefined;
75
+ return { face: handsLessResolvedFace ?? seed.face, ...(seed.denyEntries !== undefined ? { denyEntries: seed.denyEntries.map((e) => ({ ...e })) } : {}) };
74
76
  }
75
77
  const face = resolvedReadFace ?? handsLessResolvedFace;
76
78
  if (face === undefined)
@@ -81,6 +83,10 @@ export function prepareInheritedGate(input) {
81
83
  return undefined;
82
84
  };
83
85
  const faceCheckpointState = () => faceCheckpointSection() !== undefined;
86
+ const writeFaceCheckpointSection = () => {
87
+ const face = input.resolvedWriteFace() ?? input.handsLessResolvedWriteFace();
88
+ return face === "open" ? { face } : undefined;
89
+ };
84
90
  const f012CheckpointState = () => (inheritedParentConstraints?.length ?? 0) > 0 ||
85
91
  seedInheritedGate?.constraintChain !== undefined ||
86
92
  internals?.delegationProvenance !== undefined;
@@ -160,6 +166,7 @@ export function prepareInheritedGate(input) {
160
166
  };
161
167
  };
162
168
  const carrierReadFace = () => input.resolvedReadFace() ?? input.handsLessResolvedFace();
169
+ const carrierWriteFace = () => input.resolvedWriteFace() ?? input.handsLessResolvedWriteFace();
163
170
  const fullShellReachable = handsEnabled &&
164
171
  !(executionEnv instanceof StubExecutionEnv) &&
165
172
  spec.handsReadOnly !== true &&
@@ -184,6 +191,7 @@ export function prepareInheritedGate(input) {
184
191
  ...(frozenOnQuestion !== undefined ? { onQuestion: frozenOnQuestion } : {}),
185
192
  ...(spec.handsReadOnly === true ? { handsReadOnly: true } : {}),
186
193
  ...(carrierReadFace() === "roots" ? { readFace: "roots" } : {}),
194
+ ...(carrierWriteFace() === "roots" ? { writeFace: "roots" } : {}),
187
195
  ...(readDenyAdditionsNormalized.length > 0 ? { readDenyPatterns: Object.freeze(readDenyAdditionsNormalized.map((e) => ({ ...e }))) } : {}),
188
196
  ...(spec.interactiveTools === false ? { interactiveTools: false } : {}),
189
197
  oneShot: spec.oneShot,
@@ -262,5 +270,5 @@ export function prepareInheritedGate(input) {
262
270
  ...(spec.enablePlanMode === true ? { enterPlanMode } : {}),
263
271
  };
264
272
  };
265
- return { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx };
273
+ return { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, writeFaceCheckpointSection, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx };
266
274
  }
@@ -48,9 +48,9 @@ export interface PrepareLspResult {
48
48
  lspDiagnostics: LspDiagnosticsRegistry | undefined;
49
49
  /** owned — the edit nudge (raw path in), or undefined when the lane is not live. */
50
50
  nudgeLspOnEdit: ((rawPath: string) => void) | undefined;
51
- /** borrowed-readonly — the run's registry key (= the session id): a session hosts one run at a time and the
52
- * run loop releases the key at the terminal. */
51
+ /** borrowed-readonly — the run's registry key (= the session id): one run per session, released at the terminal. */
53
52
  lspRunIdent: string;
53
+ /** Did a MANAGER seat resolve? The manifest's LSP-section presence condition, from the ONE fold that decided the mount. */ managerWired: boolean;
54
54
  }
55
55
  /** The M8 phase body — prepareTask's LSP stretch, verbatim (see the module header). */
56
56
  export declare function prepareLsp(input: PrepareLspInput): PrepareLspResult;
@@ -24,5 +24,5 @@ export function prepareLsp(input) {
24
24
  .catch(() => undefined);
25
25
  }
26
26
  : undefined;
27
- return { lspDiagnostics, nudgeLspOnEdit, lspRunIdent };
27
+ return { lspDiagnostics, nudgeLspOnEdit, lspRunIdent, managerWired: lspManager !== undefined };
28
28
  }
@@ -2,6 +2,7 @@ import { policyAskClassOf } from "../ask-class.js";
2
2
  import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
3
3
  import { resolveCheckpointStore } from "../checkpoint-store.js";
4
4
  import { cloneObserverInput, resolveHookTimeoutMs } from "../hooks.js";
5
+ import { assertHookSeatsCallable } from "../hook-seats.js";
5
6
  import { isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "../permission-rules.js";
6
7
  import { isIsolated } from "../remote-env.js";
7
8
  import { askApproverIdentity, carryEngineAttestations, carryPrecedingSettlement, checkToolPolicyProjection, combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, durableParkOptInDeclared, isLiveApproverSeat, resolveAsk, toolPolicyNameSets, attestAskUnresolvableCause } from "../tool-policy.js";
@@ -113,6 +114,7 @@ export async function preparePolicyChain(input) {
113
114
  const denyNarrowingPolicy = narrowingLayers.length === 0 ? undefined : narrowingLayers.length === 1 ? narrowingLayers[0] : combinePolicies(...narrowingLayers);
114
115
  const basePolicyForResumeEdit = lockedPreflight.basePolicyForResumeEdit ?? lockedPreflight.toolPolicy;
115
116
  const hooks = spec.hooks ?? deps.hooks;
117
+ assertHookSeatsCallable(hooks, spec.hooks !== undefined ? "spec" : "deps");
116
118
  const hookTimeoutMs = resolveHookTimeoutMs(hooks?.timeoutMs, notifyOwnHookCrash, hooks);
117
119
  const preToolUseObservational = hooks?.preToolUse !== undefined && hooks.preToolUseObservational === true;
118
120
  const ownGatePreToolUse = !preToolUseObservational
@@ -6,6 +6,7 @@ import { createSharedMemoryTools } from "../shared-memory/tools.js";
6
6
  import { SHARED_MEMORY_TOOL_NAMES } from "../shared-memory/types.js";
7
7
  import { defineTool } from "../tools.js";
8
8
  import { SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, createSkillTool, normalizeSkills } from "./synthetic-tools.js";
9
+ import { substitutedSkillLength } from "./skill-base-dir.js";
9
10
  import { RosterBuilder } from "../tool-roster.js";
10
11
  export async function prepareProjectContext(input) {
11
12
  const { deps, spec, internals, session, sessionId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillScope, roster, toolFaceSnapshot, onceLedger, memoryTools, memoryEngineSession, memorySearchToolsPlanned, memoryPairExcludedName, memoryPairOccupiedName, resume } = input;
@@ -74,9 +75,10 @@ export async function prepareProjectContext(input) {
74
75
  if (!declaredSkillRank.has(s.name))
75
76
  declaredSkillRank.set(s.name, declaredSkillRank.size);
76
77
  const skillSpecs = normalizeSkills(spec.skills ?? []).filter((s) => {
77
- if (s.content.length <= SKILL_CONTENT_MAX_CHARS)
78
+ const delivered = substitutedSkillLength(s.content, s.baseDir);
79
+ if (delivered <= SKILL_CONTENT_MAX_CHARS)
78
80
  return true;
79
- deps.onError?.(new Error(`Skill "${s.name}" content is ${s.content.length} chars, over the ${SKILL_CONTENT_MAX_CHARS}-char load limit — skill not loaded (skills are never truncated; shrink the body or move material to attachments/files).`), { phase: "config", sessionId });
81
+ deps.onError?.(new Error(`Skill "${s.name}" content is ${delivered} chars${delivered === s.content.length ? "" : ` once its base directory resolves (${s.content.length} as written)`}, over the ${SKILL_CONTENT_MAX_CHARS}-char load limit — skill not loaded (skills are never truncated; shrink the body or move material to attachments/files).`), { phase: "config", sessionId });
80
82
  return false;
81
83
  });
82
84
  const inheritedFrames = internals?.inheritedManifestScope ?? [];
@@ -22,7 +22,7 @@
22
22
  import type { ExecutionEnv, ThinkingLevel } from "../../internal/harness.js";
23
23
  import type { Model } from "../../internal/llm.js";
24
24
  import { type EnvironmentFacts, type PromptProvider } from "../../prompts/default.js";
25
- import type { ReadFace } from "../../tools/fs/index.js";
25
+ import type { ContainmentFace } from "../../tools/fs/index.js";
26
26
  import type { LockedPreflight } from "../locked-config.js";
27
27
  import type { MaterializedMcp } from "../mcp.js";
28
28
  import type { ResolvedRole } from "../roles.js";
@@ -53,7 +53,9 @@ export interface PreparePromptInputsInput {
53
53
  /** borrowed-readonly — the session's reminder mark (rides the prompt facts for the declaration). */
54
54
  reminderMark: string;
55
55
  /** borrowed-readonly — the resolved read face (the open-reads flag + the structured env fact). */
56
- resolvedReadFace: ReadFace | undefined;
56
+ resolvedReadFace: ContainmentFace | undefined;
57
+ /** borrowed-readonly — the resolved write face (the open-writes flag + the structured env fact). */
58
+ resolvedWriteFace: ContainmentFace | undefined;
57
59
  /** borrowed-readonly — the frozen tool face; only `defer` is read (the Workflow short-pointer flag). */
58
60
  toolFaceSnapshot: Pick<ToolFaceSnapshot, "defer">;
59
61
  /** borrowed-readonly — the resolved prompt profile (rides the flags to the legacy ctx). */
@@ -4,7 +4,7 @@ import { probeGitStatusLane } from "./git-status-frame.js";
4
4
  import { fenceMcpServerInstructions } from "./turn-attachments.js";
5
5
  const ULTRA_REASONING_TIERS = new Set(["xhigh", "max"]);
6
6
  export async function preparePromptInputs(input) {
7
- const { spec, deps, failClosedReason, lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical, sessionId, advertisedWritableDirs } = input;
7
+ const { spec, deps, failClosedReason, lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, resolvedWriteFace, toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical, sessionId, advertisedWritableDirs } = input;
8
8
  const provider = spec.promptProvider ?? deps.promptProvider ?? defaultPromptProvider;
9
9
  const promptPolicyEnabled = Boolean(lockedPreflight.toolPolicy);
10
10
  const promptHooks = spec.hooks ?? deps.hooks;
@@ -18,6 +18,7 @@ export async function preparePromptInputs(input) {
18
18
  isolationEnabled: isIsolated(executionEnv),
19
19
  reminderMark,
20
20
  readFaceOpen: resolvedReadFace === "open",
21
+ writeFaceOpen: resolvedWriteFace === "open",
21
22
  orchestrationEnabled: selfOrchestrationActive,
22
23
  orchestrationDeferred: selfOrchestrationActive && (toolFaceSnapshot.defer?.includes("Workflow") ?? false),
23
24
  promptProfile,
@@ -74,6 +75,8 @@ export async function preparePromptInputs(input) {
74
75
  }
75
76
  if (resolvedReadFace !== undefined)
76
77
  envFacts.readFace = resolvedReadFace;
78
+ if (resolvedWriteFace !== undefined)
79
+ envFacts.writeFace = resolvedWriteFace;
77
80
  if (additionalReadRootsCanonical.length > 0) {
78
81
  envFacts.additionalReadDirectories = [...additionalReadRootsCanonical];
79
82
  }
@@ -20,7 +20,7 @@ import type { SubagentWorktreeIsolation } from "../../agents/subagent.js";
20
20
  import { SubagentRetainLedger } from "../../agents/retain-ledger.js";
21
21
  import type { TaskEvent, TaskSpec } from "../types.js";
22
22
  import { ActiveSkillScope } from "./active-skill-scope.js";
23
- import type { Prepared, RunInternals } from "./contracts.js";
23
+ import type { Prepared, RunInternals, ToolProgressLane } from "./contracts.js";
24
24
  import { type EditedFilesLedger } from "./edited-files-ledger.js";
25
25
  export interface PrepareRunRefsInput {
26
26
  /** borrowed-readonly — the REBOUND spec. Read: `forwardSubagentEvents` (widens the forwarding filter),
@@ -52,6 +52,14 @@ export interface PrepareRunRefsResult {
52
52
  harnessRef: {
53
53
  current?: AgentHarness;
54
54
  };
55
+ /** borrowed-mutable — the tool-progress lane's seat (`Prepared.toolProgressRef`), the same late-bound
56
+ * shape and reason as `harnessRef`: the band is built HERE while the lane needs the run's content pusher
57
+ * and identity mint, which exist only after prepare returns. Writer (R-3): the driver, ONCE, right after
58
+ * `pushContent` exists. Readers: the band's progress seat and the harness-handler lane. Identity is the
59
+ * contract. Unbound is LEGITIMATE — a band outside a Runner has no run to tick on, and emissions no-op. */
60
+ toolProgressRef: {
61
+ current?: ToolProgressLane;
62
+ };
55
63
  /** borrowed-mutable — the per-task LIFO skill scope. Writers: the project-context phase (the inherited-
56
64
  * from-parent seed frame, `push`) and the `skill` tool minted over it (`push` on a manifest load; a frame
57
65
  * closes by `pop`). Readers: the tool ctx's `activeSkillScope()` snapshot and the skill-scope policy layer. */
@@ -12,6 +12,7 @@ export function prepareRunRefs(input) {
12
12
  const { spec, internals, executionEnv, taskRootFinal } = input;
13
13
  const { note: noteFileEdited, snapshot: editedFilesSnapshot } = createEditedFilesLedger();
14
14
  const harnessRef = {};
15
+ const toolProgressRef = {};
15
16
  const skillScope = new ActiveSkillScope();
16
17
  const forwardSink = internals?.onForwardEvent;
17
18
  const forwardEvent = forwardSink
@@ -19,7 +20,7 @@ export function prepareRunRefs(input) {
19
20
  if (e.type === "task_progress")
20
21
  forwardSink(e);
21
22
  else if (spec.forwardSubagentEvents === true &&
22
- (e.type === "text_delta" || e.type === "text_end" || e.type === "reasoning_delta" || e.type === "tool_start" || e.type === "tool_end")) {
23
+ (e.type === "text_delta" || e.type === "text_end" || e.type === "reasoning_delta" || e.type === "tool_start" || e.type === "tool_progress" || e.type === "tool_end")) {
23
24
  forwardSink(e);
24
25
  }
25
26
  }
@@ -41,5 +42,5 @@ export function prepareRunRefs(input) {
41
42
  };
42
43
  const subagentRetain = spec.retainSubagentSessions ? new SubagentRetainLedger(spec.retainSubagentSessions) : undefined;
43
44
  const worktreeIsolation = spec.handsReadOnly !== true ? createSubagentWorktreeHelper(executionEnv, taskRootFinal) : undefined;
44
- return { noteFileEdited, editedFilesSnapshot, harnessRef, skillScope, forwardEvent, reviewRequestRef, requestReview, stopRequestedRef, requestStopAfterTurn, planModeRef, enterPlanMode, subagentRetain, worktreeIsolation };
45
+ return { noteFileEdited, editedFilesSnapshot, harnessRef, toolProgressRef, skillScope, forwardEvent, reviewRequestRef, requestReview, stopRequestedRef, requestStopAfterTurn, planModeRef, enterPlanMode, subagentRetain, worktreeIsolation };
45
46
  }
@@ -109,12 +109,17 @@ export interface PrepareSuspendSagaInput {
109
109
  readFileStateForCheckpoint: ReadFileState | undefined;
110
110
  /** borrowed-readonly — the inherited-gate phase's read-face section builder (the row's `readFace`). */
111
111
  faceCheckpointSection: () => SerializedCheckpointState["readFace"];
112
+ /** borrowed-readonly — the inherited-gate phase's WRITE-face section builder (the row's `writeFace`). */
113
+ writeFaceCheckpointSection: () => SerializedCheckpointState["writeFace"];
112
114
  /** borrowed-readonly — the leg's reminder provenance mark (travels with the row). */
113
115
  reminderMark: string;
114
116
  /** borrowed-readonly — the hand's live tracked cwd, or undefined; `current` is read at mint time. Not written here. */
115
117
  handsCwdRef: CwdRef | undefined;
116
118
  /** borrowed-readonly — the active EnterWorktree session seat, or undefined; `current` is read at mint time. */
117
119
  worktreeSessionRef: Prepared["worktreeSessionRef"];
120
+ /** borrowed-readonly — the resumed leg's not-yet-delivered continuation content; its orphan obituaries fold into this
121
+ * snapshot at mint time (a re-park before delivery must not lose them). */
122
+ undeliveredContinuationRef: Prepared["undeliveredContinuationRef"];
118
123
  /** borrowed-readonly — the LIVE inherited parent constraints, or undefined (the row's `requiresParentConstraint`,
119
124
  * count, frozen chain and the screening-park disclosure's predicate). */
120
125
  inheritedParentConstraints: NonNullable<InheritedGate["parentConstraints"]>[number][] | undefined;
@@ -78,7 +78,7 @@ function stampPlacementRootSessionId(placementRootResolved) {
78
78
  return placementValueOrAbsent(placementRootResolved);
79
79
  }
80
80
  export function prepareSuspendSaga(input) {
81
- const { gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, inheritedParentConstraints, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, autoModeIntent, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter } = input;
81
+ const { gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, autoModeIntent, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter } = input;
82
82
  if (!gateMachineryActive)
83
83
  return { saga: undefined };
84
84
  const inFlightSpendMicroUsd = () => {
@@ -108,6 +108,7 @@ export function prepareSuspendSaga(input) {
108
108
  nestedStats: { ...nestedStats },
109
109
  readFileState: readFileStateForCheckpoint ? [...readFileStateForCheckpoint.entries()] : undefined,
110
110
  readFace: faceCheckpointSection(),
111
+ writeFace: writeFaceCheckpointSection(),
111
112
  reminderMark,
112
113
  repairBundle: repairBundleForCheckpoint(parkedSpendMicroUsd),
113
114
  workspaceHandle,
@@ -118,7 +119,9 @@ export function prepareSuspendSaga(input) {
118
119
  .list({ owner: hostTaskId, scope: taskScope, sessionId })
119
120
  .filter((t) => t.status === "pending" || t.status === "running")
120
121
  .map((t) => ({ id: t.task_id, ...(t.description !== undefined ? { description: t.description } : {}) }));
121
- return live.length > 0 ? live : undefined;
122
+ const owed = undeliveredContinuationRef.current.orphanTasks.filter((o) => !live.some((t) => t.id === o.id));
123
+ const all = [...owed, ...live];
124
+ return all.length > 0 ? all : undefined;
122
125
  })(),
123
126
  pendingSteerQueue: undefined,
124
127
  inheritedGate: (() => {
@@ -366,14 +366,17 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
366
366
  const ownedEnv = ownedEnvSeat.current;
367
367
  const { taskRootFinal, rebaseRestoredPath } = await prepareWorkspaceRestore({ ownedEnv, deps, spec, internals, resume, taskRootInitial, abortController, sessionId });
368
368
  const { trackFileEdit, fileHistoryBoundary, restoredFilePaths, rewindNotes, fileHistoryEnabled, historyScope, historyRoot, historyFs } = await prepareFileHistory({ deps, spec, internals, executionEnv, taskRootFinal, handsEnabled, sessionId, session, resumeAtBeforeParentId, abortController });
369
- const { noteFileEdited, editedFilesSnapshot, harnessRef, skillScope, forwardEvent, reviewRequestRef, requestReview, stopRequestedRef, requestStopAfterTurn, planModeRef, enterPlanMode, subagentRetain, worktreeIsolation } = prepareRunRefs({ spec, internals, executionEnv, taskRootFinal });
369
+ const { noteFileEdited, editedFilesSnapshot, harnessRef, toolProgressRef, skillScope, forwardEvent, reviewRequestRef, requestReview, stopRequestedRef, requestStopAfterTurn, planModeRef, enterPlanMode, subagentRetain, worktreeIsolation } = prepareRunRefs({ spec, internals, executionEnv, taskRootFinal });
370
370
  let resolvedReadFace;
371
+ let resolvedWriteFace;
371
372
  let readDenyAdditionsNormalized = [];
372
373
  let handsLessResolvedFace;
373
- const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, checkpointSeat, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, autoModeSeat, handsEnabled, reportUsage, harnessRef, skillScope, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, hooks: () => hooks, preToolUseObservational: () => preToolUseObservational, hookTimeoutMs: () => hookTimeoutMs, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDecider, autoModeDenialTracking: () => autoModeDenialTracking, autoModeArming: () => autoModeArming, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
374
- const { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDecider, autoModeDenialTracking, autoModeArming, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline } = await prepareCapsAndWorkflow({ spec, deps, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, checkpointSeat, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, parentSpecSeat, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf, memoryEngineSession: () => memoryEngineSession, centerAdoption: () => centerAdoptionRef.current, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized });
374
+ let handsLessResolvedWriteFace;
375
+ const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, writeFaceCheckpointSection, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, checkpointSeat, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, autoModeSeat, handsEnabled, reportUsage, harnessRef, skillScope, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, hooks: () => hooks, preToolUseObservational: () => preToolUseObservational, hookTimeoutMs: () => hookTimeoutMs, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDecider, autoModeDenialTracking: () => autoModeDenialTracking, autoModeArming: () => autoModeArming, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, resolvedWriteFace: () => resolvedWriteFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, handsLessResolvedWriteFace: () => handsLessResolvedWriteFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
376
+ const { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDecider, autoModeDenialTracking, autoModeArming, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline } = await prepareCapsAndWorkflow({ spec, deps, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, checkpointSeat, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, parentSpecSeat, carrierReadFace, carrierWriteFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf, memoryEngineSession: () => memoryEngineSession, centerAdoption: () => centerAdoptionRef.current, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized });
375
377
  const tools = roster.tools;
376
378
  const pausedRef = {};
379
+ const undeliveredContinuationRef = { current: { parkedSteers: [], orphanTasks: [] } };
377
380
  const remoteEnvFailures = [];
378
381
  const suspendLoopRef = { hit: false };
379
382
  const compactionReuseRef = { consecutive: 0 };
@@ -505,12 +508,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
505
508
  if (internals?.ownOrgAdmissionRef !== undefined && ownOrgVerdictRef.current !== undefined) {
506
509
  internals.ownOrgAdmissionRef.current = ownOrgVerdictRef.current;
507
510
  }
508
- const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGate, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), firstPartyOffload, roster, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes, reminderMark, reminderDisclosureCounts, ...(trackFileEdit !== undefined ? { trackFileEdit } : {}), onFileEdited: noteFileEdited, ...(restoredFilePaths.length > 0 ? { restoredFilePaths } : {}) };
511
+ const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGate, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), firstPartyOffload, roster, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes, reminderMark, reminderDisclosureCounts, ...(trackFileEdit !== undefined ? { trackFileEdit } : {}), onFileEdited: noteFileEdited, harnessRef, toolProgressRef, ...(restoredFilePaths.length > 0 ? { restoredFilePaths } : {}) };
509
512
  const handsReadFace = handsEnabled ? await prepareHandsMount(handsReadFaceInput) : resolveHandsLessReadFace(handsReadFaceInput);
510
513
  const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, additionalRootsCanonical, additionalReadRootsCanonical, attachmentRootCanonical, readDenyMatcher, envHandToolNames, sealReadStateSeat } = handsReadFace;
511
514
  resolvedReadFace = handsReadFace.resolvedReadFace;
515
+ resolvedWriteFace = handsReadFace.resolvedWriteFace;
512
516
  readDenyAdditionsNormalized = handsReadFace.readDenyAdditionsNormalized;
513
517
  handsLessResolvedFace = handsReadFace.handsLessResolvedFace;
518
+ handsLessResolvedWriteFace = handsReadFace.handsLessResolvedWriteFace;
514
519
  shellGatedTools = handsReadFace.shellGatedTools;
515
520
  const { worktreeSessionRef } = prepareDelegationSurface({ spec, deps, internals, resume, sessionId, hostTaskId, taskScope, taskRootFinal, executionEnv, runnerSelf, backgroundTaskToolsActive, workflowToolsActive, peerLaneActive, peerSendMessageBuiltIn, peerLaneRefs, roster, toolEffects, axisExplicitNegatives, envHandToolNames, toolFaceSnapshot, firstPartyOffload, offloadStore, subagentRetain, enrichSpecToolCtx, handsCwdRef, wsSnapshot, rebaseWsPath, rebaseRestoredPath, workspaceStateSettle });
516
521
  const { liveQuestionFace, contentAskBindings, contentAskRoutable, lateStrandedAnswers, discloseStrandedAnswers, settleContentAskBindings, durableQuestionFace, questionToolMounted, mountedQuestionTool } = prepareQuestionFace({ frozenOnQuestion, spec, deps, checkpointStore, runtimeCaps, resolvedInteractionPosture, resume, sessionId, roster, inheritedUnavailableAsks: () => inheritedUnavailableAsks });
@@ -531,8 +536,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
531
536
  deps.onError?.(new Error(`Fork DENIED for principal "${spec.principal ?? ""}" by runtimeCaps.allowFork=false ` +
532
537
  `(per-principal entitlement governance, not a misconfiguration — Agent(subagent_type:"fork") will refuse honestly)`), { phase: "config", sessionId });
533
538
  }
534
- const { lspDiagnostics, nudgeLspOnEdit, lspRunIdent } = prepareLsp({ spec, deps, executionEnv, taskRootFinal, handsEnabled, sessionId, handsCwdRef, roster, envHandToolNames });
535
- prepareArtifact({ deps, runId, taskId: hostTaskId, sessionId, agentName: internals?.explicitAgentName, executionEnv, rootCanonical: attachmentRootCanonical, additionalRootsCanonical: [...additionalRootsCanonical, ...additionalReadRootsCanonical], readDenyMatcher, resolvedReadFace, handsCwdRef, roster, firstPartyOffload, envHandToolNames });
539
+ const { lspDiagnostics, nudgeLspOnEdit, lspRunIdent, managerWired: lspManagerWired } = prepareLsp({ spec, deps, executionEnv, taskRootFinal, handsEnabled, sessionId, handsCwdRef, roster, envHandToolNames });
540
+ prepareArtifact({ deps, runId, taskId: hostTaskId, sessionId, agentName: internals?.explicitAgentName, onAsk: frozenOnAsk, executionEnv, rootCanonical: attachmentRootCanonical, additionalRootsCanonical: [...additionalRootsCanonical, ...additionalReadRootsCanonical], readDenyMatcher, resolvedReadFace, handsCwdRef, roster, firstPartyOffload, envHandToolNames });
536
541
  if (internals?.delegationProvenance !== undefined && resume !== undefined) {
537
542
  const live = internals.delegationProvenance.ref.current;
538
543
  const seed = resume.seed.delegationProvenance;
@@ -571,11 +576,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
571
576
  }
572
577
  const projectContext = await prepareProjectContext({ deps, spec, internals, session, sessionId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillScope, roster, toolFaceSnapshot, onceLedger, memoryTools, memoryEngineSession, memorySearchToolsPlanned, memoryPairExcludedName, memoryPairOccupiedName, resume });
573
578
  const { memoryBlock: memoryBlockWithProject, instructionSources, projectInstructionContent, hasSkillManifest, skillsListing, sharedMemoryPairMounted, memoryEnginePairMounted } = projectContext;
574
- const { provider, featureFlags, userSystemPrompt, userAppendSystemPrompt, mcpInstructionsBlock, envFacts, tzValid, userTz, gitStatusRef } = await preparePromptInputs({ spec, deps, failClosedReason: selfOrchestrationFailClosedReason(spec, deps), lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical, sessionId, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}) });
575
- const { deferred, memoryBlock } = prepareDeferClassify({ spec, deps, roster, toolFaceSnapshot, handsEnabled, fullShellReachable, promptProfile, model, mcp, a2a, sharedMemoryPairMounted, memoryEnginePairMounted, memoryBlock: memoryBlockWithProject, memoryRecallSegment, onceLedger, sessionId });
579
+ const { provider, featureFlags, userSystemPrompt, userAppendSystemPrompt, mcpInstructionsBlock, envFacts, tzValid, userTz, gitStatusRef } = await preparePromptInputs({ spec, deps, failClosedReason: selfOrchestrationFailClosedReason(spec, deps), lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, resolvedWriteFace, toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical, sessionId, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}) });
580
+ const { deferred, memoryBlock, toolSearch: toolSearchPolicy } = prepareDeferClassify({ spec, deps, roster, toolFaceSnapshot, handsEnabled, fullShellReachable, promptProfile, model, mcp, a2a, sharedMemoryPairMounted, memoryEnginePairMounted, memoryBlock: memoryBlockWithProject, memoryRecallSegment, onceLedger, sessionId });
576
581
  prepareMemoryEngineSession({ memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, mcp, sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames, roster, contentOriginWrapRef });
577
582
  const { systemPromptSeat, renderWithDate, systemBlocks, promptManifest, epochDeclaredSections, epochArtifactDigestForSnapshot, buildAssembleInputs, centerAdoptionRef } = await preparePromptAssembly({ session, deps, internals, resume, provider, userSystemPrompt, userAppendSystemPrompt, featureFlags, mcpInstructionsBlock, memoryBlock, envFacts, promptProfile, fableMitigations, tools, model, sessionId, reminderMark, onceLedger });
578
- const { activeTools, fpRef, turnSnapshotRef, harnessTools, toolsDeltaRef, toolMaterializeStatic, deferDirectCall, staticFaceForRef, listingRideRef, toolSearch } = await prepareToolDisclosureMount({ spec, deps, session, resume, deferred, tools, onceLedger, mcp, promptManifest, offloadReachableToolsRef, contentOriginWrapRef, rebuildHarnessToolsRef, harnessRef });
583
+ const { activeTools, fpRef, turnSnapshotRef, harnessTools, toolsDeltaRef, toolMaterializeStatic, deferDirectCall, staticFaceForRef, listingRideRef, toolSearch, toolDisclosureSeat } = await prepareToolDisclosureMount({ spec, deps, session, resume, deferred, tools, onceLedger, mcp, promptManifest, toolSearchPolicy, offloadReachableToolsRef, contentOriginWrapRef, rebuildHarnessToolsRef, harnessRef });
579
584
  if (toolSearch !== undefined)
580
585
  roster.mountEngineLane(toolSearch, { source: "builtin", mountedBy: "optional" });
581
586
  const rosterFacts = { effects: toolEffects, egress: egressTools, irreversibilityTier, reversibilityProbes, deferred, trustedTools: new Set(spec.memory?.trustedTools ?? []) };
@@ -683,7 +688,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
683
688
  }
684
689
  }
685
690
  const { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, permissionRuleLane, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions } = await preparePolicyChain({ spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, envHandToolNames, handsCwdRef, readDenyMatcher, questionToolMounted, runtimeCaps, inheritedAncestorRules, inheritedParentConstraints, seedInheritedGate, hasSkillManifest, skillScope, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef });
686
- const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace } = prepareWiringManifest({ spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, peerLaneActive, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster });
691
+ const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace } = prepareWiringManifest({ spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, peerLaneActive, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster, lspManagerWired, lspDiagnosticsLive: lspDiagnostics !== undefined });
687
692
  if (fileHistoryBoundary !== undefined) {
688
693
  harness.on("tool_call", async () => {
689
694
  await fileHistoryBoundary.settle();
@@ -691,15 +696,15 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
691
696
  });
692
697
  }
693
698
  const { askLane } = prepareAskLane({ gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, advertisedWritableDirs, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash });
694
- const { saga } = prepareSuspendSaga({ gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, inheritedParentConstraints, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, autoModeIntent, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
699
+ const { saga } = prepareSuspendSaga({ gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, autoModeIntent, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
695
700
  const { suspendForResource, suspendForPlatformLimit, suspendForReview } = prepareBoundaryParks({ 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 });
696
701
  const { parkAsk } = prepareParkAsk({ askLane, saga, spec, deps, sessionId, checkpointStore, toolRosterDeltas: rosterSeat, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, advertisedWritableDirs, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, now, humanReviewRef, abortController, harness, pausedRef });
697
702
  prepareGateStations({ askLane, parkAsk, tools, toolRosterDeltas: rosterSeat, 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, shellGatedTools, autoModeDecider, autoModeDenialTracking, stopForDenialLimit, permissionRuleLane, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, notifyOwnHookCrash });
698
703
  const { microCompact, charsPerToken } = prepareContextLane({ model, deps, sessionId, runId, hostTaskId, offloadStore, microCompactKnob, harness, batchHaltRef, gitStatusRef, requestLossyRef, trimPressureRef });
699
704
  const preparedHolder = {};
700
- const { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, readTaskFile, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveReadDenyObserved } = prepareTurnWiring({ deps, systemPromptSeat, harnessTools, fpRef, model, epochArtifactDigestForSnapshot, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, additionalRootsCanonical, additionalReadRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, readDenyAdditionsNormalized, preparedHolder });
705
+ const { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, readTaskFile, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveWriteFaceObserved, effectiveReadDenyObserved } = prepareTurnWiring({ deps, systemPromptSeat, harnessTools, fpRef, model, epochArtifactDigestForSnapshot, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, additionalRootsCanonical, additionalReadRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder });
701
706
  await onceLedger.settle(session, announcedListingsRef);
702
- const buildPrepared = () => ({ harness, session, sessionId, runId, reminderMark, reminderDisclosureCounts, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, gateOutcomes, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(fileHistoryBoundary !== undefined ? { fileHistoryBoundary } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, ...(permissionRuleLane !== undefined ? { persistedRuleLane: permissionRuleLane } : {}), ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, pausedRef, suspendProgressRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, workCutRef, brainCallGuardrailRef, gateStopRef, suspendForReview, 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 ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, stopRequestedRef, announcedSnapshotRecovered: onceLedger.recovered, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(projectInstructionContent !== undefined ? { projectInstructionContent } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, gitStatusRef, listBackgroundTasks, hookIdentity, hookTimeoutMs, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
707
+ const buildPrepared = () => ({ harness, session, sessionId, runId, reminderMark, reminderDisclosureCounts, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, gateOutcomes, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(fileHistoryBoundary !== undefined ? { fileHistoryBoundary } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved, effectiveWriteFace: effectiveWriteFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, toolProgressRef, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, ...(permissionRuleLane !== undefined ? { persistedRuleLane: permissionRuleLane } : {}), ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, 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, suspendForReview, 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 ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, stopRequestedRef, announcedSnapshotRecovered: onceLedger.recovered, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(projectInstructionContent !== undefined ? { projectInstructionContent } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, gitStatusRef, listBackgroundTasks, hookIdentity, hookTimeoutMs, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}), ...(toolDisclosureSeat !== undefined ? { toolDisclosure: toolDisclosureSeat } : {}) });
703
708
  rollback.commit();
704
709
  const prepared = buildPrepared();
705
710
  preparedHolder.current = prepared;
@@ -21,12 +21,15 @@ import type { MaterializedMcp, McpServerStatus } from "../mcp.js";
21
21
  import type { StoredSession } from "../session.js";
22
22
  import type { RunnerDeps, TaskSpec } from "../types.js";
23
23
  import type { Prepared, PrepareResume } from "./contracts.js";
24
+ import { type ToolDisclosureSeat } from "./deferral-census.js";
24
25
  export interface PrepareToolDisclosureMountInput {
25
26
  /** borrowed-readonly — the REBOUND spec. Read: `toolMaterializeStrategy` (the requested strategy, spec wins) and
26
27
  * `deferSelfResolve` (the direct-call lane, the interlock). Never mutated. */
27
28
  spec: Pick<TaskSpec, "toolMaterializeStrategy" | "deferSelfResolve">;
28
29
  /** borrowed-readonly — the deployment seats: only `onNotice` (the env-channel discard announcements). */
29
30
  deps: Pick<RunnerDeps, "onNotice">;
31
+ /** borrowed-readonly — the gate policy the classification was MEASURED under, carried from the classify phase; NOT re-resolved here (awaits sit between). */
32
+ toolSearchPolicy: import("../tool-search-setting.js").ResolvedToolSearch;
30
33
  /** borrowed-readonly — the acquired session: `buildContext` and `getBranch` seed the activation set (deferred names only). */
31
34
  session: Pick<StoredSession, "buildContext" | "getBranch">;
32
35
  /** borrowed-readonly — the resume leg, or undefined: `seed.activeTools` is the authoritative activation reseed. */
@@ -105,6 +108,8 @@ export interface PrepareToolDisclosureMountResult {
105
108
  listingRideRef: {
106
109
  current?: (newly: readonly string[]) => string | undefined;
107
110
  };
111
+ /** owned — the deferral census seat, minted ONLY when something is deferred; absent ⇒ no `tool_disclosure` frame at all. */
112
+ toolDisclosureSeat?: ToolDisclosureSeat;
108
113
  }
109
114
  /** Test seam (mirrors `__resetToolModelGateAnnouncements`): never called by production code.
110
115
  * Re-arms BOTH arms (a WeakMap has no clear — it is re-minted). */
@@ -2,6 +2,7 @@ import { readCompactionActiveTools } from "../../internal/harness.js";
2
2
  import { toolsToFingerprintInputs } from "../cache-break-detector.js";
3
3
  import { deliverEngineNotice } from "../types.js";
4
4
  import { TOOL_SEARCH_NAME, buildDeferredRegistry, extractDiscoveredToolNames, createPlaceholderTool, createToolSearchTool, staticSchemaRenderable } from "./tool-disclosure.js";
5
+ import { createDeferralCensus } from "./deferral-census.js";
5
6
  let announcedMaterializeEnvBySink = new WeakMap();
6
7
  const announcedMaterializeEnvConsole = new Set();
7
8
  function materializeEnvLedger(onNotice) {
@@ -26,7 +27,8 @@ function emitMaterializeEnvNotice(onNotice, message, detail) {
26
27
  deliverEngineNotice(onNotice, { code: "config.materialize_env_discarded", message, detail });
27
28
  }
28
29
  export async function prepareToolDisclosureMount(input) {
29
- const { spec, deps, session, resume, deferred, tools, onceLedger, mcp, promptManifest, offloadReachableToolsRef, contentOriginWrapRef, rebuildHarnessToolsRef, harnessRef } = input;
30
+ const { spec, deps, session, resume, deferred, tools, onceLedger, mcp, promptManifest, offloadReachableToolsRef, contentOriginWrapRef, rebuildHarnessToolsRef, harnessRef, toolSearchPolicy } = input;
31
+ let toolDisclosureSeat;
30
32
  const activeTools = new Set();
31
33
  const fpRef = {};
32
34
  const turnSnapshotRef = {};
@@ -77,6 +79,9 @@ export async function prepareToolDisclosureMount(input) {
77
79
  strategy: materializeStatic ? "static" : "swap",
78
80
  source: laneDegrade ? "degraded_no_direct_lane" : spec.toolMaterializeStrategy !== undefined ? "spec" : envStrategy !== undefined ? "env" : "default",
79
81
  };
82
+ const census = createDeferralCensus(deferred, toolSearchPolicy);
83
+ toolDisclosureSeat = census.seat;
84
+ const publishCensus = () => census.publish(activeTools);
80
85
  const everExempt = new Set();
81
86
  const staticFaceFor = (name) => {
82
87
  if (!materializeStatic)
@@ -122,6 +127,7 @@ export async function prepareToolDisclosureMount(input) {
122
127
  activeTools.delete(name);
123
128
  throw e;
124
129
  }
130
+ publishCensus();
125
131
  return listingRideRef.current?.([name]);
126
132
  }),
127
133
  };
@@ -202,9 +208,11 @@ export async function prepareToolDisclosureMount(input) {
202
208
  ...(materializeStatic
203
209
  ? { staticSchemaFor: (name) => (staticFaceFor(name) ? tools.find((t) => t.name === name)?.parameters : undefined) }
204
210
  : {}),
211
+ onActivationCommitted: publishCensus,
205
212
  serializeActivation,
206
213
  });
207
214
  harnessTools = buildToolList(activeTools);
215
+ publishCensus();
208
216
  toolSearchMounted = toolSearch;
209
217
  }
210
218
  else {
@@ -217,5 +225,5 @@ export async function prepareToolDisclosureMount(input) {
217
225
  turnSnapshotRef.current?.refreshTools(toolsToFingerprintInputs(list));
218
226
  };
219
227
  }
220
- return { activeTools, fpRef, turnSnapshotRef, harnessTools, toolsDeltaRef, toolMaterializeStatic, deferDirectCall, staticFaceForRef, listingRideRef, ...(toolSearchMounted !== undefined ? { toolSearch: toolSearchMounted } : {}) };
228
+ return { activeTools, fpRef, turnSnapshotRef, harnessTools, toolsDeltaRef, toolMaterializeStatic, deferDirectCall, staticFaceForRef, listingRideRef, ...(toolSearchMounted !== undefined ? { toolSearch: toolSearchMounted } : {}), ...(toolDisclosureSeat !== undefined ? { toolDisclosureSeat } : {}) };
221
229
  }
@@ -9,7 +9,7 @@ import { CacheBreakDetector, type ToolFingerprintInput } from "../cache-break-de
9
9
  import { type ToolPolicy } from "../tool-policy.js";
10
10
  import type { RunnerDeps, TaskSpec } from "../types.js";
11
11
  import type { CwdRef } from "../../tools/fs/fs-shared.js";
12
- import { type ReadFace } from "../../tools/fs/index.js";
12
+ import { type ContainmentFace } from "../../tools/fs/index.js";
13
13
  import type { ReadDenyMatcher } from "../../tools/fs/read-deny.js";
14
14
  import { type ReadFileState } from "../../tools/fs/safety.js";
15
15
  import type { Prepared } from "./contracts.js";
@@ -72,7 +72,7 @@ export interface PrepareTurnWiringInput {
72
72
  /** borrowed-readonly — the compiled read-deny judge, or undefined (the reader's withheld arm). */
73
73
  readDenyMatcher: ReadDenyMatcher | undefined;
74
74
  /** borrowed-readonly — the resolved read face, or undefined (the fence's ninth argument). */
75
- resolvedReadFace: ReadFace | undefined;
75
+ resolvedReadFace: ContainmentFace | undefined;
76
76
  /** borrowed-readonly — the tracked-cwd seat, read per call by the kept-tail normalizer (never written here). */
77
77
  handsCwdRef: CwdRef | undefined;
78
78
  /** borrowed-mutable — the live read-file state, or undefined. Writers here, at RUN time: `detectExternalChanges` evicts a
@@ -103,7 +103,9 @@ export interface PrepareTurnWiringInput {
103
103
  /** borrowed-readonly — the provider-declared sections in the epoch shape (the candidate's declared-sections TYPE). */
104
104
  epochDeclaredSections: EpochDeclaredSections;
105
105
  /** borrowed-readonly — the ONE carrier-face expression both delegation mounts consume (the observation seat). */
106
- carrierReadFace: () => ReadFace | undefined;
106
+ carrierReadFace: () => ContainmentFace | undefined;
107
+ /** borrowed-readonly — the same carrier expression on the WRITE seat. */
108
+ carrierWriteFace: () => ContainmentFace | undefined;
107
109
  /** borrowed-readonly — the normalized deny additions (the observation seat copies them). */
108
110
  readDenyAdditionsNormalized: ReadonlyArray<{
109
111
  pattern: string;
@@ -143,7 +145,9 @@ export interface PrepareTurnWiringResult {
143
145
  /** owned — the compaction-boundary center adoption candidate, or undefined (no source, or no adoption). */
144
146
  centerCompactionCandidate: Prepared["centerCompactionCandidate"];
145
147
  /** owned — the effective read face observed for the result seats (`Prepared.effectiveReadFace`), or undefined. */
146
- effectiveReadFaceObserved: ReadFace | undefined;
148
+ effectiveReadFaceObserved: ContainmentFace | undefined;
149
+ /** owned — the same observation on the WRITE seat (`Prepared.effectiveWriteFace`), or undefined. */
150
+ effectiveWriteFaceObserved: ContainmentFace | undefined;
147
151
  /** owned — the effective read-deny patterns observed (fresh copies), or undefined when none. */
148
152
  effectiveReadDenyObserved: Array<{
149
153
  pattern: string;
@@ -11,7 +11,7 @@ import { resolveKey } from "../../tools/fs/safety.js";
11
11
  import { PROMPT_HASH_SALT } from "./prompt-hash-salt.js";
12
12
  import { CHANGED_FILES_MTIME_EPS_MS } from "./turn-attachments.js";
13
13
  export function prepareTurnWiring(input) {
14
- const { deps, systemPromptSeat, harnessTools, fpRef, model, epochArtifactDigestForSnapshot, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, additionalRootsCanonical, additionalReadRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, readDenyAdditionsNormalized, preparedHolder } = input;
14
+ const { deps, systemPromptSeat, harnessTools, fpRef, model, epochArtifactDigestForSnapshot, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, additionalRootsCanonical, additionalReadRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder } = input;
15
15
  const cacheBreakDetector = deps.cacheBreakDetection === false ? undefined : new CacheBreakDetector();
16
16
  const cacheFingerprint = cacheBreakDetector
17
17
  ? { systemPrompt: systemPromptSeat.current, tools: toolsToFingerprintInputs(harnessTools) }
@@ -196,6 +196,7 @@ export function prepareTurnWiring(input) {
196
196
  : undefined;
197
197
  overheadState.promptChars = systemPromptSeat.current.length;
198
198
  const effectiveReadFaceObserved = carrierReadFace();
199
+ const effectiveWriteFaceObserved = carrierWriteFace();
199
200
  const effectiveReadDenyObserved = readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized.map((e) => ({ ...e })) : undefined;
200
- return { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, readTaskFile, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveReadDenyObserved };
201
+ return { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, readTaskFile, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveWriteFaceObserved, effectiveReadDenyObserved };
201
202
  }
@@ -37,7 +37,7 @@ export interface PrepareWiringManifestInput {
37
37
  * `resourceSuspend` (the task-axis lane), `durableApproval` / `principal` (the synthesis and the notice), `interactiveTools` /
38
38
  * `mcp` / `checkpointStore` (manifest cells and the notice's cause), `enablePlanMode` (the gate-machinery predicate's
39
39
  * plan-mode term). Never mutated. */
40
- spec: Pick<TaskSpec, "onAsk" | "onQuestion" | "handsReadOnly" | "tools" | "resourceSuspend" | "durableApproval" | "principal" | "interactiveTools" | "mcp" | "checkpointStore" | "enablePlanMode">;
40
+ spec: Pick<TaskSpec, "onAsk" | "onQuestion" | "handsReadOnly" | "tools" | "resourceSuspend" | "durableApproval" | "principal" | "interactiveTools" | "mcp" | "checkpointStore" | "enablePlanMode" | "hooks">;
41
41
  /** borrowed-readonly — the deployment seats, whole: `onAsk` (the seat's deps half), `onError` (the warning), `executionEnv`
42
42
  * (the hook-env predicate), `checkpointStore` (durable infra), the manifest's dozen wiring facts (`backgroundAgentStore`,
43
43
  * `permissionRuleStore`, `permissionRuleSyncWired`, `onBackgroundChildEvent`, `lockedConfig`, `compliancePostureResolver`,
@@ -57,13 +57,11 @@ export interface PrepareWiringManifestInput {
57
57
  hostTaskId: string;
58
58
  /** borrowed-readonly — the registry scope the peer drain binds under. */
59
59
  taskScope: string;
60
- /** borrowed-readonly — the resolved hook record (`spec.hooks ?? deps.hooks`): the effect-aware-gate term, the tracked flag
61
- * and the hook-env face's consumer test. */
60
+ /** borrowed-readonly — the resolved hook record (`spec.hooks ?? deps.hooks`): the effect-aware-gate term, the tracked flag and the hook-env consumer test. */
62
61
  hooks: Hooks | undefined;
63
62
  /** borrowed-readonly — whether the deployment declared its screening face observational (then it is no gate). */
64
63
  preToolUseObservational: boolean;
65
- /** borrowed-readonly — the caller-facing policy layers; only their COUNT is read (an effect-aware gate exists). */
66
- policyLayers: ReadonlyArray<unknown>;
64
+ /** borrowed-readonly — the caller-facing policy layers; only their COUNT is read (an effect-aware gate exists). */ policyLayers: ReadonlyArray<unknown>;
67
65
  /** borrowed-readonly — the policy chain's effective policy, or undefined; only its PRESENCE is read (the first term of the
68
66
  * gate-machinery predicate below). Never called here. */
69
67
  effectivePolicy: ToolPolicy | undefined;
@@ -106,6 +104,8 @@ export interface PrepareWiringManifestInput {
106
104
  /** borrowed-readonly — the leg's minted tool roster: rides the manifest's `tools` section and is the
107
105
  * source of the hand band's write-capable names for the ungated-write warning (what actually MOUNTED). */
108
106
  toolRoster: ToolRoster;
107
+ /** borrowed-readonly — from the LSP phase's manager fold: gates the manifest's LSP section (absent ⇒ byte-identical manifest). */ lspManagerWired: boolean;
108
+ /** borrowed-readonly — from the LSP phase: is the diagnostics lane live? The `lane` word's only input. */ lspDiagnosticsLive: boolean;
109
109
  /** borrowed-readonly — the arming outcome the caps phase minted (the manifest's auto-mode face). */
110
110
  autoModeArmReason: AutoModeArmFact;
111
111
  /** borrowed-readonly — the frozen preflight; only `mcp` (the declared servers the manifest face joins). */