@sema-agent/core 7.52.0 → 7.53.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 (191) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/README.md +3 -1
  3. package/dist/agents/cross-session-envelope.d.ts +8 -0
  4. package/dist/agents/cross-session-envelope.js +6 -0
  5. package/dist/agents/cross-session-judge.d.ts +21 -1
  6. package/dist/agents/cross-session-judge.js +8 -0
  7. package/dist/agents/cross-session-ref.d.ts +5 -0
  8. package/dist/agents/cross-session-ref.js +1 -0
  9. package/dist/agents/org-delivery-gate.d.ts +122 -0
  10. package/dist/agents/org-delivery-gate.js +69 -0
  11. package/dist/agents/peer-held-queue.d.ts +9 -4
  12. package/dist/agents/peer-held-queue.js +6 -5
  13. package/dist/agents/peer-session-drain.d.ts +35 -5
  14. package/dist/agents/peer-session-drain.js +271 -180
  15. package/dist/agents/read-inbox-tool.d.ts +7 -0
  16. package/dist/agents/read-inbox-tool.js +5 -1
  17. package/dist/agents/subagent.d.ts +3 -0
  18. package/dist/agents/subagent.js +99 -72
  19. package/dist/agents/tool-filter.d.ts +18 -0
  20. package/dist/agents/tool-filter.js +6 -0
  21. package/dist/brain/anthropic.d.ts +6 -1
  22. package/dist/brain/anthropic.js +4 -4
  23. package/dist/brain/model-presets.js +2 -1
  24. package/dist/brain/route-adjudicator.d.ts +6 -0
  25. package/dist/brain/routing.d.ts +24 -1
  26. package/dist/brain/routing.js +54 -19
  27. package/dist/brain/timeout.js +5 -4
  28. package/dist/core/a2a.d.ts +5 -2
  29. package/dist/core/a2a.js +30 -13
  30. package/dist/core/allow-entry.d.ts +2 -1
  31. package/dist/core/allow-entry.js +2 -2
  32. package/dist/core/auto-compaction.d.ts +57 -0
  33. package/dist/core/auto-compaction.js +28 -2
  34. package/dist/core/checkpoint-store.d.ts +29 -20
  35. package/dist/core/checkpoint-store.js +3 -3
  36. package/dist/core/compliance.js +3 -1
  37. package/dist/core/effective-path-target.d.ts +25 -6
  38. package/dist/core/effective-path-target.js +24 -2
  39. package/dist/core/engine-notice.d.ts +13 -2
  40. package/dist/core/gate-fold.js +3 -2
  41. package/dist/core/gate-lanes.js +11 -13
  42. package/dist/core/gate-outcome.d.ts +11 -6
  43. package/dist/core/governance-codes.d.ts +3 -1
  44. package/dist/core/governance-codes.js +3 -0
  45. package/dist/core/hands-band-screen.d.ts +7 -0
  46. package/dist/core/hands-band-screen.js +32 -0
  47. package/dist/core/hooks.d.ts +7 -5
  48. package/dist/core/hooks.js +5 -3
  49. package/dist/core/locked-config.d.ts +84 -32
  50. package/dist/core/locked-config.js +128 -42
  51. package/dist/core/mcp-probe.js +1 -1
  52. package/dist/core/mcp-server-spec.d.ts +88 -10
  53. package/dist/core/mcp-server-spec.js +183 -33
  54. package/dist/core/mcp.d.ts +21 -14
  55. package/dist/core/mcp.js +55 -51
  56. package/dist/core/memory-engine/engine.d.ts +14 -19
  57. package/dist/core/memory-engine/engine.js +7 -5
  58. package/dist/core/mode-policy.d.ts +3 -18
  59. package/dist/core/mode-policy.js +2 -16
  60. package/dist/core/mods/kernel/dispatch.js +13 -15
  61. package/dist/core/mods/kernel/events.d.ts +9 -6
  62. package/dist/core/mods/kernel/events.js +2 -2
  63. package/dist/core/mods/kernel/receive.d.ts +39 -10
  64. package/dist/core/mods/kernel/receive.js +119 -54
  65. package/dist/core/mods/kernel/site-rules.d.ts +80 -15
  66. package/dist/core/mods/kernel/site-rules.js +232 -40
  67. package/dist/core/mods/stations.d.ts +0 -6
  68. package/dist/core/mods/stations.js +0 -7
  69. package/dist/core/mounted-mcp.d.ts +57 -0
  70. package/dist/core/mounted-mcp.js +71 -2
  71. package/dist/core/own-property-receipt.d.ts +13 -0
  72. package/dist/core/own-property-receipt.js +3 -1
  73. package/dist/core/parent-spec-seat.d.ts +2 -2
  74. package/dist/core/permission-rule-model.d.ts +58 -9
  75. package/dist/core/permission-rule-model.js +81 -7
  76. package/dist/core/permission-rule-org.d.ts +163 -33
  77. package/dist/core/permission-rule-org.js +205 -71
  78. package/dist/core/permission-rules.d.ts +7 -1
  79. package/dist/core/permission-rules.js +37 -8
  80. package/dist/core/retention.js +7 -2
  81. package/dist/core/retired-keys.d.ts +8 -2
  82. package/dist/core/retired-keys.js +12 -1
  83. package/dist/core/roles.js +60 -10
  84. package/dist/core/rule-lane-reads.js +1 -1
  85. package/dist/core/runner/contracts.d.ts +1 -0
  86. package/dist/core/runner/gate-exit.js +4 -3
  87. package/dist/core/runner/mcp-redial.d.ts +52 -10
  88. package/dist/core/runner/mcp-redial.js +38 -9
  89. package/dist/core/runner/permission-rule-lanes.d.ts +5 -2
  90. package/dist/core/runner/permission-rule-lanes.js +22 -10
  91. package/dist/core/runner/person-path-rows.d.ts +3 -1
  92. package/dist/core/runner/person-path-rows.js +2 -2
  93. package/dist/core/runner/prepare-config-doors.d.ts +48 -2
  94. package/dist/core/runner/prepare-config-doors.js +161 -145
  95. package/dist/core/runner/prepare-defer-classify.js +4 -7
  96. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  97. package/dist/core/runner/prepare-delegation-surface.js +7 -5
  98. package/dist/core/runner/prepare-hands-readface.d.ts +1 -1
  99. package/dist/core/runner/prepare-hands-readface.js +2 -1
  100. package/dist/core/runner/prepare-inherited-gate.js +2 -2
  101. package/dist/core/runner/prepare-listings.d.ts +1 -1
  102. package/dist/core/runner/prepare-listings.js +4 -2
  103. package/dist/core/runner/prepare-memory-engine-session.d.ts +0 -6
  104. package/dist/core/runner/prepare-memory-engine-session.js +19 -6
  105. package/dist/core/runner/prepare-memory.d.ts +3 -2
  106. package/dist/core/runner/prepare-memory.js +6 -2
  107. package/dist/core/runner/prepare-offload-wrappers.d.ts +4 -4
  108. package/dist/core/runner/prepare-offload-wrappers.js +2 -1
  109. package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
  110. package/dist/core/runner/prepare-policy-chain.js +12 -12
  111. package/dist/core/runner/prepare-project-context.d.ts +1 -1
  112. package/dist/core/runner/prepare-project-context.js +6 -4
  113. package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
  114. package/dist/core/runner/prepare-prompt-assembly.js +20 -16
  115. package/dist/core/runner/prepare-prompt-inputs.d.ts +12 -6
  116. package/dist/core/runner/prepare-prompt-inputs.js +6 -3
  117. package/dist/core/runner/prepare-protocol-tools.d.ts +7 -5
  118. package/dist/core/runner/prepare-protocol-tools.js +19 -12
  119. package/dist/core/runner/prepare-question-face.d.ts +4 -2
  120. package/dist/core/runner/prepare-question-face.js +4 -3
  121. package/dist/core/runner/prepare-task.js +10 -10
  122. package/dist/core/runner/prepare-wiring-manifest.d.ts +8 -3
  123. package/dist/core/runner/prepare-wiring-manifest.js +8 -5
  124. package/dist/core/runner/resume-admission.d.ts +4 -1
  125. package/dist/core/runner/resume-admission.js +7 -5
  126. package/dist/core/runner/resume-internals-and-config.d.ts +3 -3
  127. package/dist/core/runner/resume-internals-and-config.js +3 -8
  128. package/dist/core/runner/retired-runner-deps.d.ts +5 -6
  129. package/dist/core/runner/retired-runner-deps.js +1 -4
  130. package/dist/core/runner/run-leg.js +42 -12
  131. package/dist/core/runner/run-recovery-lanes.js +5 -3
  132. package/dist/core/runner/run-terminal-adoption.js +6 -5
  133. package/dist/core/runner/run-turn-boundary.js +9 -3
  134. package/dist/core/runner/runtask.js +1 -1
  135. package/dist/core/runner/skills-seat.d.ts +15 -0
  136. package/dist/core/runner/skills-seat.js +57 -0
  137. package/dist/core/runner/sub-agent-deny-lists.d.ts +13 -11
  138. package/dist/core/runner/sub-agent-deny-lists.js +7 -5
  139. package/dist/core/runner/synthetic-tools.d.ts +5 -2
  140. package/dist/core/runner/synthetic-tools.js +2 -12
  141. package/dist/core/runner-deps.d.ts +29 -14
  142. package/dist/core/session-policy-store.d.ts +19 -0
  143. package/dist/core/session-policy-store.js +22 -2
  144. package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
  145. package/dist/core/task-event.d.ts +38 -2
  146. package/dist/core/task-notification.js +2 -2
  147. package/dist/core/task-spec.d.ts +1 -1
  148. package/dist/core/tool-policy.d.ts +3 -0
  149. package/dist/core/tool-policy.js +10 -4
  150. package/dist/core/types.d.ts +2 -2
  151. package/dist/core/types.js +1 -1
  152. package/dist/core/untrusted-text.d.ts +16 -0
  153. package/dist/core/untrusted-text.js +7 -2
  154. package/dist/core/user-attachment.d.ts +13 -2
  155. package/dist/core/user-attachment.js +47 -41
  156. package/dist/core/wiring-manifest.d.ts +4 -2
  157. package/dist/engine/harness/agent-harness.js +2 -1
  158. package/dist/engine/harness/types.d.ts +3 -0
  159. package/dist/engine/loop/agent-loop.d.ts +12 -1
  160. package/dist/engine/loop/agent-loop.js +17 -5
  161. package/dist/engine/loop/types.d.ts +7 -1
  162. package/dist/index.d.ts +15 -9
  163. package/dist/index.js +12 -6
  164. package/dist/internal/harness.d.ts +1 -0
  165. package/dist/internal/harness.js +1 -0
  166. package/dist/orchestration/goal.d.ts +24 -1
  167. package/dist/orchestration/goal.js +3 -2
  168. package/dist/prompt-assembly/artifact-store.d.ts +44 -9
  169. package/dist/prompt-assembly/artifact-store.js +38 -12
  170. package/dist/prompt-assembly/artifact.d.ts +12 -11
  171. package/dist/prompt-assembly/artifact.js +52 -21
  172. package/dist/prompt-assembly/assemble.d.ts +2 -0
  173. package/dist/prompt-assembly/assemble.js +2 -1
  174. package/dist/prompt-assembly/catalog/index.js +2 -1
  175. package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
  176. package/dist/prompt-assembly/catalog/memory.js +6 -0
  177. package/dist/prompt-assembly/catalog/schema.d.ts +16 -2
  178. package/dist/prompt-assembly/composer.d.ts +2 -0
  179. package/dist/prompt-assembly/composer.js +1 -1
  180. package/dist/prompt-assembly/overlay.d.ts +21 -11
  181. package/dist/prompt-assembly/overlay.js +55 -17
  182. package/dist/prompt-assembly/select.d.ts +21 -6
  183. package/dist/prompt-assembly/select.js +39 -2
  184. package/dist/prompts/default.d.ts +0 -11
  185. package/dist/prompts/default.js +0 -3
  186. package/dist/stores/file/permission-rule-store.d.ts +1 -1
  187. package/dist/stores/file/permission-rule-store.js +2 -1
  188. package/dist/tools/artifact/artifact-tool.js +4 -3
  189. package/package.json +1 -1
  190. package/test/export-surface.snapshot.json +65 -5
  191. package/wire-changes/core@7.53.0.json +1946 -0
@@ -20,7 +20,7 @@ import type { AgentTool } from "../../internal/harness.js";
20
20
  import { type OnQuestion } from "../ask-question.js";
21
21
  import type { CheckpointStore } from "../checkpoint-store.js";
22
22
  import type { RunnerDeps, RuntimeCaps, TaskSpec } from "../types.js";
23
- import type { PrepareResume } from "./contracts.js";
23
+ import type { PrepareResume, ToolFaceSnapshot } from "./contracts.js";
24
24
  import { type ContentAskBinding } from "./content-ask-bindings.js";
25
25
  import { RosterBuilder } from "../tool-roster.js";
26
26
  export { CONTENT_ASK_BINDING_CAP, type ContentAskBinding } from "./content-ask-bindings.js";
@@ -31,7 +31,9 @@ export interface PrepareQuestionFaceInput {
31
31
  /** borrowed-readonly — the REBOUND spec. Read: `durableApproval` (the durable face's opt-in), `interactiveTools`
32
32
  * (the override), `principal` (the tool's source identity), `interactiveQuestionFallback` (restores the
33
33
  * continuation under a resolved posture). Never mutated. */
34
- spec: Pick<TaskSpec, "durableApproval" | "interactiveTools" | "principal" | "interactiveQuestionFallback">;
34
+ spec: Pick<TaskSpec, "durableApproval" | "interactiveTools" | "principal" | "interactiveQuestionFallback" | "excludeAllTools">;
35
+ /** borrowed-readonly — the frozen tool face; its selector with the spec's `excludeAllTools` is the valve's reading: the tool mounts only if the valve leaves it. */
36
+ toolFaceSnapshot: Pick<ToolFaceSnapshot, "selector">;
35
37
  /** borrowed-readonly — the deployment seat `onError` (the stranded-answer and synthetic-continuation operator
36
38
  * lines; swallow-guarded). */
37
39
  deps: Pick<RunnerDeps, "onError">;
@@ -1,11 +1,12 @@
1
- import { createAskUserQuestionTool, isLiveQuestionFace } from "../ask-question.js";
1
+ import { valveLeaves } from "../../agents/tool-filter.js";
2
+ import { ASK_USER_QUESTION_TOOL_NAME, createAskUserQuestionTool, isLiveQuestionFace } from "../ask-question.js";
2
3
  import { boundInputHashOf } from "../canonical-json.js";
3
4
  import { durableParkOptInDeclared } from "../tool-policy.js";
4
5
  import { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js";
5
6
  import { RosterBuilder } from "../tool-roster.js";
6
7
  export { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js";
7
8
  export function prepareQuestionFace(input) {
8
- const { frozenOnQuestion, spec, deps, checkpointStore, runtimeCaps, resolvedInteractionPosture, resume, sessionId, roster, inheritedUnavailableAsks } = input;
9
+ const { frozenOnQuestion, spec, deps, checkpointStore, runtimeCaps, resolvedInteractionPosture, resume, sessionId, roster, toolFaceSnapshot, inheritedUnavailableAsks } = input;
9
10
  const tools = roster.tools;
10
11
  const onQuestion = frozenOnQuestion;
11
12
  const liveQuestionFace = isLiveQuestionFace(onQuestion) ? onQuestion : undefined;
@@ -58,7 +59,7 @@ export function prepareQuestionFace(input) {
58
59
  return liveQuestionFace(req, signal);
59
60
  }
60
61
  : onQuestion;
61
- const questionToolMounted = spec.interactiveTools === true || (spec.interactiveTools !== false && (onQuestion !== undefined || durableQuestionFace));
62
+ const questionToolMounted = (spec.interactiveTools === true || (spec.interactiveTools !== false && (onQuestion !== undefined || durableQuestionFace))) && valveLeaves(spec, toolFaceSnapshot.selector)({ name: ASK_USER_QUESTION_TOOL_NAME });
62
63
  let mountedQuestionTool;
63
64
  if (questionToolMounted)
64
65
  roster.mount((mountedQuestionTool =
@@ -86,7 +86,7 @@ import { announcePeerLaneMount, judgeSessionBoxDrain } from "../../agents/peer-s
86
86
  import { createFrameSettlement } from "../frame-settlement.js";
87
87
  import { createSchedulerTools } from "../../tools/scheduler-tools.js";
88
88
  import { selfOrchestrationFailClosedReason } from "../../orchestration/workflow-script-runner.js";
89
- import { compileToolSelector } from "../../agents/tool-filter.js";
89
+ import { compileToolSelector, valveLeaves } from "../../agents/tool-filter.js";
90
90
  import { boundOwnToolLists, boundToolListsJudgment, judgeRunToolLists } from "./sub-agent-deny-lists.js";
91
91
  import { remainingBudgetMicroUsd, resolveCheckpointStore } from "../checkpoint-store.js";
92
92
  import { checkpointSeatOf } from "../checkpoint-seat.js";
@@ -355,7 +355,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
355
355
  const sessionBox = judgeSessionBoxDrain(deps, { sessionId, scope: taskScope, isDelegatedChild: delegation.isDelegatedChild });
356
356
  const peerLaneRefs = {};
357
357
  const frameSettlement = createFrameSettlement();
358
- const peerSendMessageBuiltIn = runnerSelf !== undefined && toolFaceSnapshot.selector.admits({ name: SEND_MESSAGE_TOOL_NAME }) && !(spec.tools ?? []).some((t) => t.name === SEND_MESSAGE_TOOL_NAME);
358
+ const peerSendMessageBuiltIn = runnerSelf !== undefined && valveLeaves(spec, toolFaceSnapshot.selector)({ name: SEND_MESSAGE_TOOL_NAME }) && !(spec.tools ?? []).some((t) => t.name === SEND_MESSAGE_TOOL_NAME);
359
359
  const { reminderMark, reminderDisclosureCounts } = await adoptReminderMark(session, sessionId, resume?.seed.reminderMark, internals?.reminderMark, deps.onError);
360
360
  const offloadScope = spec.principal ?? "default";
361
361
  if (internals?.registryScope !== undefined && internals.registryScope !== offloadScope) {
@@ -549,7 +549,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
549
549
  for (const alias of t.aliases ?? [])
550
550
  memoryPairNameDomain.add(alias);
551
551
  }
552
- const memoryPairExcludedName = MEMORY_ENGINE_TOOL_NAMES.find((n) => !toolFaceSnapshot.selector.admits({ name: n }));
552
+ const memoryPairExcludedName = MEMORY_ENGINE_TOOL_NAMES.find((n) => !valveLeaves(spec, toolFaceSnapshot.selector)({ name: n }));
553
553
  const memoryPairOccupiedName = MEMORY_ENGINE_TOOL_NAMES.find((n) => memoryPairNameDomain.has(n));
554
554
  const memorySearchToolsPlanned = memoryPairExcludedName === undefined && memoryPairOccupiedName === undefined;
555
555
  const captureLineage = await (async () => {
@@ -569,7 +569,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
569
569
  taskRootPath: taskRootFinal,
570
570
  reminderMark,
571
571
  writeToolsMounted: (handsWriteHalfPlanned || tools.some((t) => t.name === "Write")) &&
572
- toolFaceSnapshot.selector.admits({ name: "Write" }) &&
572
+ valveLeaves(spec, toolFaceSnapshot.selector)({ name: "Write" }) &&
573
573
  !(handsEnabled && isRemoteExecutionEnv(executionEnv) && spec.memoryPersistenceCapable !== true),
574
574
  memoryProvenance,
575
575
  memoryCapturePolicy,
@@ -626,7 +626,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
626
626
  shellGatedTools = handsReadFace.shellGatedTools;
627
627
  await armAutoMode();
628
628
  const { worktreeSessionRef } = prepareDelegationSurface({ spec, deps, internals, resume, sessionId, hostTaskId, taskScope, taskRootFinal, taskRootCanonical, executionEnv, runnerSelf, backgroundTaskToolsActive, shellReadAdmission, workflowToolsActive, peerLaneActive, peerSendMessageBuiltIn, peerLaneRefs, sessionBox, roster, toolEffects, axisExplicitNegatives, envHandToolNames, toolFaceSnapshot, firstPartyOffload, offloadStore, subagentRetain, enrichSpecToolCtx, checkpointSeat, handsCwdRef, wsSnapshot, rebaseWsPath, rebaseRestoredPath, workspaceStateSettle });
629
- const { liveQuestionFace, contentAskBindings, contentAskRoutable, lateStrandedAnswers, discloseStrandedAnswers, settleContentAskBindings, durableQuestionFace, questionToolMounted, mountedQuestionTool } = prepareQuestionFace({ frozenOnQuestion, spec, deps, checkpointStore, runtimeCaps, resolvedInteractionPosture, resume, sessionId, roster, inheritedUnavailableAsks: () => inheritedUnavailableAsks });
629
+ const { liveQuestionFace, contentAskBindings, contentAskRoutable, lateStrandedAnswers, discloseStrandedAnswers, settleContentAskBindings, durableQuestionFace, questionToolMounted, mountedQuestionTool } = prepareQuestionFace({ frozenOnQuestion, spec, deps, checkpointStore, runtimeCaps, resolvedInteractionPosture, resume, sessionId, roster, toolFaceSnapshot, inheritedUnavailableAsks: () => inheritedUnavailableAsks });
630
630
  if (spec.handsReadOnly !== true) {
631
631
  const sessionScope = sessionId ?? spec.principal ?? spec.taskId ?? "default";
632
632
  roster.mountAll(createSchedulerTools(executionEnv, {
@@ -659,8 +659,8 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
659
659
  live.incomplete = true;
660
660
  }
661
661
  }
662
- const rosterCanPersist = rosterCanPersistMemory(tools.filter((t) => toolFaceSnapshot.selector.admits(t)), { effects: toolEffects, remoteHands: handsEnabled && isRemoteExecutionEnv(executionEnv) }, spec.memoryPersistenceCapable);
663
- const { memoryBlock: memoryBlockFromEngine, recallDisciplineSegment: memoryRecallSegment, seedFiles: memorySeedFiles } = composeMemoryInjection({ rosterCanPersist });
662
+ const rosterCanPersist = rosterCanPersistMemory(tools.filter(valveLeaves(spec, toolFaceSnapshot.selector)), { effects: toolEffects, remoteHands: handsEnabled && isRemoteExecutionEnv(executionEnv) }, spec.memoryPersistenceCapable);
663
+ const { memoryBlock: memoryBlockFromEngine, recallDisciplineSegment: memoryRecallSegment, seedFiles: memorySeedFiles } = composeMemoryInjection({ rosterCanPersist, isSubagent: delegation.isNonForkChild });
664
664
  if (memorySeedFiles?.length && seedContextFiles) {
665
665
  try {
666
666
  await seedContextFiles(memorySeedFiles);
@@ -671,10 +671,10 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
671
671
  }
672
672
  const projectContext = await prepareProjectContext({ deps, spec, internals, session, sessionId, runId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillGrants, allowedTools, allowedToolTables, roster, toolFaceSnapshot, onceLedger, memoryTools, memoryEngineSession, memorySearchToolsPlanned, memoryPairExcludedName, memoryPairOccupiedName, resume, skillListingBudget: doors.skillListingBudget });
673
673
  const { memoryBlock: memoryBlockWithProject, instructionSources, projectInstructionContent, skillSpecs, skillSeatOf, skillsListing, sharedMemoryPairMounted, memoryEnginePairMounted } = projectContext;
674
- const { featureFlags, sugar, mcpInstructionsBlock, envFacts, tzValid, userTz, dateAnchor, gitStatusRef } = await preparePromptInputs({ modBus: legMods.bus, spec, deps, contextOverlay: legContextOverlay(), failClosedReason: selfOrchestrationFailClosedReason(spec, deps), lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, resolvedWriteFace: resolvedWriteFace?.inForce(), toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical: (await readRoots.ready().then(readRoots)).filter((r) => !additionalRootsCanonical.includes(r)), sessionId, session, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}) });
674
+ const { featureFlags, sugar, mcpInstructionsBlock, envFacts, tzValid, userTz, dateAnchor, gitStatusRef } = await preparePromptInputs({ modBus: legMods.bus, spec, deps, contextOverlay: legContextOverlay(), failClosedReason: selfOrchestrationFailClosedReason(spec, deps), lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, resolvedWriteFace: resolvedWriteFace?.inForce(), toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, roster, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical: (await readRoots.ready().then(readRoots)).filter((r) => !additionalRootsCanonical.includes(r)), sessionId, session, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}) });
675
675
  judgeRunToolLists({ spec, tools: roster.tools, declaredPeers: { mcp: lockedPreflight.mcp, a2a: a2a.statuses }, own: { allow: toolFaceLists.allow, exclude: toolFaceLists.exclude }, layers: toolFaceSnapshot.selector.layers, legs: toolLegs, judgedUpstream: toolListsJudged !== undefined, toldUpstream: internals?.ownToolLists !== undefined && ownToolLists !== undefined && toolCeiling !== undefined, ownBy: ownToolLists, onceLedger, sessionId });
676
676
  const { deferred, memoryBlock, toolSearch: toolSearchPolicy } = prepareDeferClassify({ spec, deps, roster, toolFaceSnapshot, handsEnabled, fullShellReachable, promptProfile, model, mcp, a2a, sharedMemoryPairMounted, memoryEnginePairMounted, memoryBlock: memoryBlockWithProject, memoryRecallSegment, onceLedger, sessionId });
677
- prepareMemoryEngineSession({ memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, mcp, ...(mountedMcpNow !== undefined ? { mountedMcp: mountedMcpNow } : {}), sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames, roster, contentOriginWrapRef });
677
+ prepareMemoryEngineSession({ memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, ...(mountedMcpNow !== undefined ? { mountedMcp: mountedMcpNow } : {}), sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames, roster, contentOriginWrapRef });
678
678
  const { systemPromptSeat, renderWithDate, systemBlocks, promptManifest, promptIdentity, buildAssembleInputs, identityFor, adoptsCandidates, centerAdoptionRef } = await preparePromptAssembly({ session, deps, internals, resume, sugar, host: promptHost, binding: promptBinding, modBus: legMods.bus, signal: abortController.signal, featureFlags, mcpInstructionsBlock, memoryBlock, envFacts, promptProfile, fableMitigations, tools, model, sessionId, onceLedger });
679
679
  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 });
680
680
  if (toolSearch !== undefined)
@@ -786,7 +786,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
786
786
  }
787
787
  }
788
788
  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 });
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 });
790
790
  const writeProtectionCheck = writeProtection.mount?.check;
791
791
  writeTargetJudgeRef.current = writeProtection.judgeWriteTarget;
792
792
  if (fileHistoryBoundary !== undefined) {
@@ -114,7 +114,8 @@ export interface PrepareWiringManifestInput {
114
114
  /** borrowed-readonly — the model gate's per-leg read face, or undefined. */
115
115
  modelGateManifest: WiringManifest["modelGate"];
116
116
  /** borrowed-readonly — the leg's minted tool roster: rides the manifest's `tools` section and is the
117
- * source of the hand band's write-capable names for the ungated-write warning (what actually MOUNTED). */
117
+ * source of the hand band's write-capable names for the ungated-write warning (what actually MOUNTED) and of each MCP server's
118
+ * `toolCount` (its tools among the roster's names). */
118
119
  toolRoster: ToolRoster;
119
120
  /** borrowed-readonly — from the read-face phase: the built-in read-deny TIERS that leg's own
120
121
  * resolution materially activated; relayed onto the manifest (present iff non-empty), never
@@ -140,6 +141,9 @@ export interface PrepareWiringManifestInput {
140
141
  frameSettlement: import("../frame-settlement.js").FrameSettlement;
141
142
  /** borrowed-readonly — the session-box drain's mount verdict (prepare-task's one judgment): present ⇒ this leg drains its own box. */
142
143
  sessionBox: SessionBoxBinding | undefined;
144
+ /** borrowed-readonly, read late — the memory session's one-way pollution face (absent with no memory session). The drain marks
145
+ * it when it INJECTS a letter from another principal (the injection path; the tool path is accounted by `ReadInbox`'s class). */
146
+ memoryPollution?: () => Pick<NonNullable<Prepared["memoryEngineSession"]>["pollution"], "markPolluted"> | undefined;
143
147
  /** borrowed-readonly — the built harness the peer drain binds to. */
144
148
  harness: AgentHarness;
145
149
  /** borrowed-readonly — the durable-suspend holder; the drain's parked predicate reads `token` at run time. Not written here. */
@@ -202,7 +206,8 @@ export interface PrepareWiringManifestResult {
202
206
  * The wiring manifest's per-server MCP read face for one leg ({@link WiringManifest.mcp}): every
203
207
  * server the leg's FROZEN entry snapshot declared, in declaration order, joined by name to this leg's
204
208
  * materialization statuses. Pure projection — no connection logic, no second look at any transport:
205
- * · a status `connected` ⇒ `connected` with the mounted roster size (the intake's post-filter count);
209
+ * · a status `connected` ⇒ `connected` with the server's tools among `rosterNames` — the names of the roster the row is read
210
+ * against: a run's (the valve and the deployment's overlay applied), or the no-run probe's own dials (no run, so no lists apply);
206
211
  * · a status `failed` ⇒ `failed` with the failure record the materialization stamped (`errorCode`/`delivered`/
207
212
  * `httpStatus` = the MCP vocabulary's `McpFailure` spread flat) and the remote text SECRET-REDACTED (an HTTP endpoint's error body rides the SDK's message
208
213
  * verbatim, and a body that echoes the bearer it rejected must not reach a stream consumer),
@@ -213,6 +218,6 @@ export interface PrepareWiringManifestResult {
213
218
  * `liveness` is the status record's own observation deep-copied (see {@link WiringManifestMcpEntry.liveness}).
214
219
  * The entries are fresh objects so the manifest never aliases the status records the refresh face mutates.
215
220
  */
216
- export declare function mcpManifestEntries(entries: ReadonlyArray<import("../types.js").McpServerSpec> | undefined, statuses: ReadonlyArray<import("../mcp.js").McpServerStatus>): WiringManifestMcpEntry[];
221
+ export declare function mcpManifestEntries(entries: ReadonlyArray<import("../types.js").McpServerSpec> | undefined, statuses: ReadonlyArray<import("../mcp.js").McpServerStatus>, rosterNames: ReadonlyArray<string>): WiringManifestMcpEntry[];
217
222
  /** The M18 phase body — prepareTask's wiring-manifest stretch, verbatim (see the module header). */
218
223
  export declare function prepareWiringManifest(input: PrepareWiringManifestInput): PrepareWiringManifestResult;
@@ -3,6 +3,7 @@ import { teamRoleOf } from "../../agents/team-role.js";
3
3
  import { resolveCheckpointStore } from "../checkpoint-store.js";
4
4
  import { createHookEnvCapabilities, mintHookInvocationIdentity } from "../hooks.js";
5
5
  import { chainJudges } from "../mods/stations.js";
6
+ import { toolNamesOfServer } from "../mounted-mcp.js";
6
7
  import { isRemoteExecutionEnv, missingRestoreSurface } from "../remote-env.js";
7
8
  import { isVolatileOffloadStore } from "../tool-result-store.js";
8
9
  import { durableMandateSourceOf, isLiveApproverSeat } from "../tool-policy.js";
@@ -13,7 +14,7 @@ import { autoRunOnRecommendationEffective } from "./memory-consolidation-driver.
13
14
  import { GLOBAL_USAGE_KEY, usageRetryAfterMs, windowsGovernCost } from "../usage-window-store.js";
14
15
  import { LSP_CONTRACT_ID, askSeatEffective, countElicitOptIns, deriveHandsSeam, deriveLspSeam, deriveWiringManifest, resolveDeclaredDurability, resolveElicitSeam, resolveQuestionSeam, resolveSubagentTranscriptTier } from "../wiring-manifest.js";
15
16
  import { modePolicyOf } from "../mode-policy.js";
16
- export function mcpManifestEntries(entries, statuses) {
17
+ export function mcpManifestEntries(entries, statuses, rosterNames) {
17
18
  return (entries ?? []).map((entry) => {
18
19
  const status = statuses.find((s) => s.name === entry.name);
19
20
  const source = typeof entry.source === "string" && entry.source.length > 0 ? { source: inlineUntrusted(entry.source, 80) } : {};
@@ -21,7 +22,7 @@ export function mcpManifestEntries(entries, statuses) {
21
22
  if (status === undefined)
22
23
  return { name: entry.name, ...source, status: "skipped", toolCount: 0 };
23
24
  if (status.status === "connected")
24
- return { name: entry.name, ...source, status: "connected", toolCount: status.toolNames?.length ?? 0, ...liveness };
25
+ return { name: entry.name, ...source, status: "connected", toolCount: toolNamesOfServer(rosterNames, entry.name).length, ...liveness };
25
26
  return {
26
27
  name: entry.name,
27
28
  ...source,
@@ -116,13 +117,14 @@ function announceDurableGateUnavailable(args) {
116
117
  });
117
118
  }
118
119
  export function prepareWiringManifest(input) {
119
- 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 } = 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
121
  const onAsk = askSeat.value;
121
122
  const handWriteTools = toolRoster.entries.filter((e) => e.mountedBy === "hands" && (e.effect === "write" || e.effect === "idempotent")).map((e) => e.name);
122
123
  const hasEffectAwareGate = policyLayers.length > 0 || chainJudges(modBus);
124
+ const rosterHolds = new Set(toolRoster.entries.map((e) => e.name));
123
125
  const peerWriteUngated = modePolicyOf(permissionMode.current).unstated === "ask"
124
126
  ? []
125
- : mcp.tools.filter((t) => t.permissionSeat === "passthrough" && !irreversibleTools.has(t.name) && !egressTools.has(t.name) && (toolEffects.get(t.name) ?? "write") !== "read").map((t) => t.name);
127
+ : mcp.tools.filter((t) => rosterHolds.has(t.name) && t.permissionSeat === "passthrough" && !irreversibleTools.has(t.name) && !egressTools.has(t.name) && (toolEffects.get(t.name) ?? "write") !== "read").map((t) => t.name);
126
128
  const firstPartyWriteUngated = (spec.tools ?? [])
127
129
  .map((t) => t.name)
128
130
  .filter((name) => !irreversibleTools.has(name) && !egressTools.has(name) && toolEffects.get(name) === "write");
@@ -213,7 +215,7 @@ export function prepareWiringManifest(input) {
213
215
  ...(modelGateManifest !== undefined ? { modelGate: modelGateManifest } : {}),
214
216
  autoMode: { ...autoModeArmReason() },
215
217
  permissionMode: permissionMode.receipt(),
216
- mcp: mcpManifestEntries(lockedPreflight.mcp, mcp.statuses),
218
+ mcp: mcpManifestEntries(lockedPreflight.mcp, mcp.statuses, toolRoster.entries.map((e) => e.name)),
217
219
  ...(writeProtection.mount !== undefined ? { writeProtectionTargetView: writeProtection.mount.targetView } : {}),
218
220
  readDenyBuiltinTiersActive,
219
221
  autoConsolidationOnRecommendation: autoRunOnRecommendationEffective(deps),
@@ -238,6 +240,7 @@ export function prepareWiringManifest(input) {
238
240
  settlement: frameSettlement,
239
241
  selfName: () => internals?.explicitAgentName,
240
242
  parked: () => pausedRef.current !== undefined,
243
+ markExternalContent: (reason) => memoryPollution?.()?.markPolluted(reason, "observed"),
241
244
  });
242
245
  frameSettlement.boxBacked = (payload) => peerLaneRefs.isBoxBacked?.(payload) ?? false;
243
246
  }
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import { type Checkpoint, type CheckpointStore, type CheckpointToken, type PendingSteerEntry, type ResumeOutcome } from "../checkpoint-store.js";
14
14
  import type { InheritedGate, ResumeTaskConfig, RunInternals, RunnerDepsSeat } from "./contracts.js";
15
+ import type { SessionStore } from "../session.js";
15
16
  /** What the admission rung was called with. */
16
17
  export interface ResumeAdmissionInput<R> {
17
18
  /** borrowed-readonly — the checkpoint token the caller is redeeming. */
@@ -28,6 +29,8 @@ export interface ResumeAdmissionInput<R> {
28
29
  /** borrowed-readonly — the Runner's deployment deps, read LIVE through the Runner (the store resolution reads `checkpointStore`); the one home of why it is a
29
30
  * seat and not a captured object is {@link RunnerDepsSeat}. */
30
31
  runner: RunnerDepsSeat;
32
+ /** borrowed-readonly — the Runner's session store, fixed at its construction (unlike its deps): the retention capability door judges it. */
33
+ sessions: SessionStore;
31
34
  /** borrowed-readonly — the Runner's same-process parked-constraint registry; read for this token (never written here). */
32
35
  parentConstraintRegistry: ReadonlyMap<CheckpointToken, NonNullable<InheritedGate["parentConstraints"]>>;
33
36
  /** borrowed-readonly — the rung after admission, entered in this rung's last continuation with what it admitted. */
@@ -35,7 +38,7 @@ export interface ResumeAdmissionInput<R> {
35
38
  }
36
39
  /** What admission established — the constants every later rung reads. */
37
40
  export interface ResumeAdmissionResult {
38
- /** The caller's config, snapshotted once (own enumerable fields). */
41
+ /** The caller's config, snapshotted once (own enumerable fields), its MCP / A2A entries the frozen ones the doors judged. */
39
42
  config: ResumeTaskConfig;
40
43
  /** The trusted internals snapshot, with the parked parent chain re-supplied when this Runner spawned the leg. */
41
44
  internals: RunInternals | undefined;
@@ -1,16 +1,18 @@
1
1
  import { CheckpointError, readPendingSteerQueue, refuseRetiredModeSeed, resolveCheckpointStore, validatePendingSteer } from "../checkpoint-store.js";
2
- import { refuseResumeDoors } from "../mode-policy.js";
2
+ import { assertResumeConfigRecord, checkpointStoreSeat, refuseResumeDoors } from "./prepare-config-doors.js";
3
+ import { asResumeConfigRefusal } from "../mode-policy.js";
3
4
  import { describeSuppliedValue } from "./decide-continuation.js";
4
5
  import { detachSkillLists } from "../skill-grant.js";
5
6
  export async function resumeAdmission(input) {
6
- const { token, outcome, taskConfig, runner, parentConstraintRegistry } = input;
7
+ const { token, outcome, taskConfig, runner, sessions, parentConstraintRegistry } = input;
7
8
  let internals = input.internals;
8
9
  if (outcome === null || typeof outcome !== "object") {
9
10
  throw new CheckpointError("checkpoint.invalid_outcome", `resume outcome must be an object naming its gate (got ${outcome === null ? "null" : typeof outcome})`);
10
11
  }
11
- const config = typeof taskConfig === "object" && taskConfig !== null ? { ...taskConfig, ...(Array.isArray(taskConfig.skills) ? { skills: detachSkillLists(taskConfig.skills) } : {}) } : taskConfig;
12
+ asResumeConfigRefusal("taskConfig", () => assertResumeConfigRecord(taskConfig));
13
+ let config = { ...taskConfig, ...(Array.isArray(taskConfig.skills) ? { skills: detachSkillLists(taskConfig.skills) } : {}) };
12
14
  internals = internals !== undefined ? { ...internals } : undefined;
13
- const store = resolveCheckpointStore(config, runner.deps);
15
+ const store = asResumeConfigRefusal(checkpointStoreSeat(config), () => resolveCheckpointStore(config, runner.deps));
14
16
  if (!store) {
15
17
  throw new CheckpointError("checkpoint.not_found", "no CheckpointStore wired — cannot resume (set RunnerDeps.checkpointStore or taskConfig.checkpointStore)");
16
18
  }
@@ -39,7 +41,7 @@ export async function resumeAdmission(input) {
39
41
  const resumeSignal = config.signal;
40
42
  let suppliedMessage;
41
43
  refuseRetiredModeSeed(cp.state);
42
- refuseResumeDoors(config, cp.state.inheritedGate);
44
+ config = refuseResumeDoors(config, cp.state.inheritedGate, runner.deps, sessions);
43
45
  const parkedSteers = readPendingSteerQueue(cp.state);
44
46
  if (outcomeGate === "wake") {
45
47
  suppliedMessage = outcome.message;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The resume ladder's INTERNALS-AND-CONFIG rung (E7), verbatim from `Runner.resumeStream`:
3
- * the locked-policy guard on the resume-edit seat, the principal and placement identity-continuity rungs,
3
+ * the inherited constraints' retired-member door, the principal and placement identity-continuity rungs,
4
4
  * and the governance-window ENTRANCE check for a row that still owes a delivery.
5
5
  *
6
6
  * Synchronous by construction, with the ladder's ONE await at this rung handed back instead of taken: the
@@ -14,13 +14,13 @@ import type { ResumeTaskConfig, RunInternals, RunnerDepsSeat } from "./contracts
14
14
  export interface ResumeInternalsAndConfigInput {
15
15
  /** borrowed-readonly — the pending row (recorded principal, placement root, parked steers, background tasks). */
16
16
  cp: Checkpoint;
17
- /** borrowed-readonly — the config snapshot (`basePolicyForResumeEdit`, `principal`). */
17
+ /** borrowed-readonly — the config snapshot (`principal`). */
18
18
  config: ResumeTaskConfig;
19
19
  /** borrowed-readonly — the internals snapshot (`placementRoot`). */
20
20
  internals: RunInternals | undefined;
21
21
  /** borrowed-readonly — the ONE read of the outcome discriminant (a bare resource_limit continue owes nothing). */
22
22
  outcomeGate: ResumeOutcome["gate"];
23
- /** borrowed-readonly — the Runner's deployment deps, read LIVE through the Runner (reads `lockedConfig`, `usageWindowStore`, `usageWindows`); the one home of why it is a
23
+ /** borrowed-readonly — the Runner's deployment deps, read LIVE through the Runner (reads `usageWindowStore`, `usageWindows`); the one home of why it is a
24
24
  * seat and not a captured object is {@link RunnerDepsSeat}. */
25
25
  runner: RunnerDepsSeat;
26
26
  }
@@ -1,17 +1,12 @@
1
1
  import { CheckpointError, readPendingSteerQueue } from "../checkpoint-store.js";
2
+ import { asResumeConfigRefusal } from "../mode-policy.js";
2
3
  import { GLOBAL_USAGE_KEY, resolveUsageWindows, usageRetryAfterMs } from "../usage-window-store.js";
3
4
  import { placementValueOrAbsent } from "./checkpoint-scope.js";
4
- import { assertNoRetiredResumeSeats } from "./retired-runner-deps.js";
5
- import { resolveMicroCompactKnob } from "./prepare-config-doors.js";
5
+ import { assertNoRetiredInheritedConstraints } from "./retired-runner-deps.js";
6
6
  export function resumeInternalsAndConfig(input) {
7
7
  const { cp, config, internals, outcomeGate, runner } = input;
8
8
  let windowEntrance;
9
- assertNoRetiredResumeSeats(runner.deps, config, internals);
10
- resolveMicroCompactKnob(runner.deps.microCompact);
11
- if (runner.deps.lockedConfig?.keys?.includes("toolPolicy") === true && config.basePolicyForResumeEdit !== undefined) {
12
- throw new CheckpointError("checkpoint.invalid_outcome", "TaskSpec.basePolicyForResumeEdit is administratively locked by this deployment (locked key \"toolPolicy\") — a task-supplied " +
13
- "resume-edit policy is refused pre-CAS (the checkpoint stays pending); remove the field or change the deployment's lock configuration");
14
- }
9
+ asResumeConfigRefusal("deps", () => assertNoRetiredInheritedConstraints(internals));
15
10
  let recheckGovernanceWindow;
16
11
  {
17
12
  const rowPrincipal = cp.principal || undefined;
@@ -1,11 +1,10 @@
1
1
  import type { RunnerDeps } from "../types.js";
2
- import type { ResumeTaskConfig, RunInternals } from "./contracts.js";
2
+ import type { RunInternals } from "./contracts.js";
3
3
  /** Runs on the caller's own argument at `new Runner` (the only point that still sees an inherited seat — construction then
4
4
  * reads every own seat once into the plain copy the Runner keeps, `retainRunnerDeps`), and again in the pre-first-await
5
5
  * config-doors phase and pre-CAS on a resume. */
6
6
  export declare function assertNoRetiredRunnerDeps(deps: RunnerDeps): void;
7
- /** The resume ladder's pre-claim door: the retired seats of the deps, then the retired members of the caller policies this
8
- * resume installs (the prepare's own resolution, `callerPolicySeats`) and of the inherited constraints it is handed. The edit
9
- * re-check runs the resume-edit policy before the claim, and a refusal after the claim would burn the token on a store
10
- * without `reopen`. */
11
- export declare function assertNoRetiredResumeSeats(deps: RunnerDeps, config: ResumeTaskConfig, internals: RunInternals | undefined): void;
7
+ /** The resume ladder's pre-claim door over the inherited constraints a resume is handed: a retired member of one refuses before
8
+ * the claim (a refusal after it would burn the token on a store without `reopen`). The deps' retired seats and the caller
9
+ * policies' retired members are the config-door phase's, which a resume enters before the claim (`refuseResumeDoors`). */
10
+ export declare function assertNoRetiredInheritedConstraints(internals: RunInternals | undefined): void;
@@ -1,5 +1,4 @@
1
1
  import { assertNoRetiredKeys, assertNoRetiredToolPolicyKeys, RETIRED_HOOKS_REPLACEMENT } from "../retired-keys.js";
2
- import { assertCallerPoliciesCurrent, callerPolicySeats } from "../locked-config.js";
3
2
  const RETIRED_RUNNER_DEPS_KEYS = {
4
3
  hooks: RETIRED_HOOKS_REPLACEMENT,
5
4
  legacyRewindBoundaryProbe: "the rewind refusal always names both possibilities (never existed / retired whole-tree era); a deployment that holds that era's table answers the question on its own surface",
@@ -13,9 +12,7 @@ const RETIRED_RUNNER_DEPS_KEYS = {
13
12
  export function assertNoRetiredRunnerDeps(deps) {
14
13
  assertNoRetiredKeys(deps, RETIRED_RUNNER_DEPS_KEYS, "RunnerDeps");
15
14
  }
16
- export function assertNoRetiredResumeSeats(deps, config, internals) {
17
- assertNoRetiredRunnerDeps(deps);
18
- assertCallerPoliciesCurrent(callerPolicySeats(config, deps, deps.lockedConfig?.keys?.includes("toolPolicy") === true));
15
+ export function assertNoRetiredInheritedConstraints(internals) {
19
16
  for (const constraint of internals?.inheritedGate?.parentConstraints ?? [])
20
17
  assertNoRetiredToolPolicyKeys(constraint.policy);
21
18
  }
@@ -8,15 +8,17 @@ import { formatHookFeedback } from "../hooks.js";
8
8
  import { classicEventBase, failedHandlerClause, screenUserPrompt } from "../mods/stations.js";
9
9
  import { buildAppliedHumanInputEvent, buildHumanInputEvent, projectHumanInput } from "../human-input-projection.js";
10
10
  import { humanInputAttachmentsOf, readObjectiveAttachments, userAttachmentDeclarations } from "../user-attachment.js";
11
- import { uuidv7 } from "../../internal/harness.js";
11
+ import { readToolCallArguments, uuidv7 } from "../../internal/harness.js";
12
12
  import { ORG_ADJUDICATION_TIMEOUT_MS, settleOrgVerdictWithin } from "../permission-rule-org.js";
13
13
  import { applyPersistedTightening, disclosedRuleSet } from "../persisted-rule-arms.js";
14
+ import { argsReadBy, stampArgsReading } from "../effective-path-target.js";
14
15
  import { parkedSkillApprovalRefusal, skillRowRefusal } from "../skill-grant.js";
15
16
  import { SKILL_TOOL_NAME } from "./synthetic-tools.js";
16
17
  import { computeCostMicroUsd } from "../pricing.js";
17
18
  import { mintSystemReminder } from "../reminder-mint.js";
18
19
  import { hasDestroy } from "../remote-env.js";
19
- import { advertisedWritableRootsSeat, attestationOf, exemptRootsSeat, humanRefusalSentence, policyCannotAnswer, policyRefusalMessage, refuseOutOfContractDecision } from "../tool-policy.js";
20
+ import { advertisedWritableRootsSeat, attestationOf, exemptRootsSeat, humanRefusalSentence, ownedReading, policyCannotAnswer, policyRefusalMessage, refuseOutOfContractDecision } from "../tool-policy.js";
21
+ import { failedJudgmentDeny } from "./policy-throw.js";
20
22
  import { pathDenialCardOf } from "../../tools/fs/safety.js";
21
23
  import { callFaceSeat, judgeParkedToolIdentity, parkedRowLiveFace, rosterEntryNamed } from "../tool-roster.js";
22
24
  import { deliverEngineNotice } from "../types.js";
@@ -554,7 +556,18 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
554
556
  throw new CheckpointError("checkpoint.invalid_outcome", "pending action reached the resolver with no settlement record on its decision (gateOutcome) — refusing to execute or settle a decision that carries no record");
555
557
  }
556
558
  const humanRewrite = wireOf("resume.questionArgsShown", pendingAction) === ASK_USER_QUESTION_TOOL_NAME ? undefined : outcome.updatedInput;
557
- const resolvedArgs = humanRewrite !== undefined ? humanRewrite : pendingAction.args;
559
+ const liveTool = prepared.tools.find((x) => x.name === pendingAction.toolName);
560
+ const reading = liveTool === undefined ? undefined : ownedReading((a) => readToolCallArguments(liveTool, { type: "toolCall", id: pendingAction.toolCallId, name: pendingAction.toolName, arguments: {} }, a));
561
+ const beltFace = () => { const f = parkedRowLiveFace(prepared.toolRosterDeltas.current, pendingAction); if (f !== undefined && reading !== undefined)
562
+ stampArgsReading(f, reading); return f; };
563
+ const tryRead = (v) => { try {
564
+ return { args: reading === undefined ? v : argsReadBy(reading, v) };
565
+ }
566
+ catch (error) {
567
+ return { args: v, unread: { error } };
568
+ } };
569
+ const decided = outcome.decision === "allow" ? tryRead(humanRewrite !== undefined ? humanRewrite : pendingAction.args) : { args: humanRewrite !== undefined ? humanRewrite : pendingAction.args };
570
+ const resolvedArgs = decided.args;
558
571
  const pendingLabel = (() => { const l = prepared.tools.find((t) => t.name === pendingAction.toolName)?.label; return l !== undefined && l !== pendingAction.toolName ? { label: l } : {}; })();
559
572
  const spelledName = pendingAction.names?.[0] ?? pendingAction.toolName;
560
573
  const occurrences = prepared.toolOccurrences;
@@ -563,15 +576,21 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
563
576
  occurrences.gateRound(pendingAction.toolCallId, decidedGate, frozenInputSnapshot(resolvedArgs));
564
577
  let notExecuted = false;
565
578
  const resultRow = (text, isError) => withRowNotExecuted(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, text, isError), notExecuted);
566
- const settleEnd = async (isError, result, refusedBy) => {
579
+ const settleEnd = async (isError, result, refusedBy, neverRan) => {
567
580
  if (refusedBy !== undefined)
568
581
  occurrences.refuse(pendingAction.toolCallId, refusedBy);
569
- const settled = emitSettled(occurrences, callStart, { result, isError }, { push: emit, structured: prepared.structuredProjector, mediaByteCapBytes: runner.deps.mediaByteCapBytes });
582
+ const settled = emitSettled(occurrences, callStart, { result, isError, ...(neverRan ? { notExecuted: true } : {}) }, { push: emit, structured: prepared.structuredProjector, mediaByteCapBytes: runner.deps.mediaByteCapBytes });
570
583
  notExecuted = settled.notExecuted === true;
571
584
  const gate = settled.gate ?? decidedGate;
572
585
  const word = await resume.recordExecutionOutcome(gate);
573
586
  settleExecutionRecord(runner.deps.onNotice, word, { toolName: pendingAction.toolName, gate, sessionId: prepared.sessionId, runId: prepared.runId, scope: resume.cp.scope, ...(resume.cp.checkpointId !== undefined ? { checkpointId: resume.cp.checkpointId } : {}) });
574
587
  };
588
+ const settleUnreadable = async (error, which) => {
589
+ const marks = egressValue("same-principal", thrownMarksOf(error));
590
+ const text = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: the tool could not read ${which} — its argument preparation failed (${egressThrownText("same-principal", error)}). This approval is spent — the call has to be re-issued.`, prepared.reminderMark);
591
+ await settleEnd(true, { content: text, ...(marks !== undefined ? { details: marks } : {}) }, undefined, true);
592
+ emitCommitted(await prepared.session.appendMessage(resultRow(text, true)), "toolResult", pendingAction.toolCallId);
593
+ };
575
594
  if (outcome.decision === "deny") {
576
595
  const settlementKind = outcome.gateOutcome?.settlement?.kind;
577
596
  const reason = settlementKind === "policy_refused"
@@ -593,6 +612,8 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
593
612
  if (outcome.decision !== "allow") {
594
613
  throw new CheckpointError("checkpoint.invalid_outcome", `pending action reached the resolver with decision "${String(outcome.decision)}" — only "allow" executes and only "deny" injects a denial; refusing to execute`);
595
614
  }
615
+ if (decided.unread !== undefined)
616
+ return settleUnreadable(decided.unread.error, humanRewrite !== undefined ? "the arguments the decision edited it to" : "its arguments");
596
617
  const screened = await prepared.approvedCallScreen?.({ toolCallId: pendingAction.toolCallId, toolName: pendingAction.toolName, args: structuredClone(resolvedArgs), decidedBy: outcome.hostDecision.decidedBy });
597
618
  if (screened !== undefined && "refused" in screened) {
598
619
  const hookDenial = formatHookFeedback(screened.refused, prepared.reminderMark);
@@ -600,10 +621,13 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
600
621
  emitCommitted(await prepared.session.appendMessage(resultRow(hookDenial, true)), "toolResult", pendingAction.toolCallId);
601
622
  return;
602
623
  }
603
- const executedArgs = humanRewrite !== undefined ? resolvedArgs : screened !== undefined ? screened.args : resolvedArgs;
624
+ const rescreened = humanRewrite === undefined && screened !== undefined ? tryRead(screened.args) : undefined;
625
+ if (rescreened?.unread !== undefined)
626
+ return settleUnreadable(rescreened.unread.error, "the arguments a PreToolUse hook rewrote it to");
627
+ const executedArgs = rescreened !== undefined ? rescreened.args : resolvedArgs;
604
628
  const unseen = !deepJsonEqual(executedArgs, pendingAction.args);
605
629
  let beltReading;
606
- const beltReq = () => ({ toolName: pendingAction.toolName, args: executedArgs, toolCallId: pendingAction.toolCallId, ...callFaceSeat(parkedRowLiveFace(prepared.toolRosterDeltas.current, pendingAction)), budget: beltBudget, ...(prepared.cwdRef !== undefined ? { cwd: prepared.cwdRef.current } : {}), ...(prepared.handsRoot !== undefined ? { root: prepared.handsRoot } : {}), ...advertisedWritableRootsSeat(prepared.advertisedWritableDirs), ...exemptRootsSeat(prepared.exemptRoots), ...(beltReading !== undefined ? { targetReading: beltReading } : {}) });
630
+ const beltReq = () => ({ toolName: pendingAction.toolName, args: executedArgs, toolCallId: pendingAction.toolCallId, ...callFaceSeat(beltFace()), budget: beltBudget, ...(prepared.cwdRef !== undefined ? { cwd: prepared.cwdRef.current } : {}), ...(prepared.handsRoot !== undefined ? { root: prepared.handsRoot } : {}), ...advertisedWritableRootsSeat(prepared.advertisedWritableDirs), ...exemptRootsSeat(prepared.exemptRoots), ...(beltReading !== undefined ? { targetReading: beltReading } : {}) });
607
631
  const unjudgeable = unseen ? chainCannotJudge(resume.cp.state.inheritedGate) : undefined;
608
632
  if (unjudgeable !== undefined) {
609
633
  const chainDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: its input changed after the approval and the inherited ancestor chain cannot judge the changed input (${unjudgeable}). This approval is spent — the call has to be re-issued.`, prepared.reminderMark);
@@ -620,14 +644,20 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
620
644
  const card = pathDenialCardOf(attestationOf(d, { toolCallId: pendingAction.toolCallId, toolName: pendingAction.toolName })?.pathDenial);
621
645
  return card !== undefined ? { details: card } : {};
622
646
  };
647
+ const beltCheck = async (judge, seat) => { const signal = prepared.abortController.signal; try {
648
+ return await judge(signal);
649
+ }
650
+ catch (err) {
651
+ return failedJudgmentDeny(err, signal, (e) => runner.deps.onError?.(e, { phase: "hook", sessionId: prepared.sessionId }), seat, pendingAction);
652
+ } };
623
653
  const beltStamped = prepared.stampCallTarget?.(beltReq(), prepared.abortController.signal);
624
654
  if (beltStamped !== undefined)
625
655
  beltReading = (await beltStamped).targetReading;
626
656
  if (unseen && prepared.basePolicyForResumeEdit) {
627
- const rechecked = refuseOutOfContractDecision(await prepared.basePolicyForResumeEdit.check(beltReq(), prepared.abortController.signal));
657
+ const rechecked = refuseOutOfContractDecision(await beltCheck((signal) => prepared.basePolicyForResumeEdit.check(beltReq(), signal), "the deployment's tool policy re-checking a resumed call"));
628
658
  const personUnanswered = policyCannotAnswer(rechecked, outcome.hostDecision.decidedBy);
629
659
  const beltUnsafe = rechecked.action === "deny" ||
630
- (rechecked.updatedInput !== undefined && !deepJsonEqual(rechecked.updatedInput, executedArgs)) ||
660
+ (rechecked.updatedInput !== undefined && ((read) => read.unread !== undefined || !deepJsonEqual(read.args, executedArgs))(tryRead(rechecked.updatedInput))) ||
631
661
  personUnanswered;
632
662
  if (beltUnsafe) {
633
663
  const why = rechecked.action === "deny"
@@ -653,7 +683,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
653
683
  }
654
684
  if (prepared.permissionRuleOrg !== undefined) {
655
685
  const orgVerdict = prepared.permissionRuleOrg
656
- .adjudicate({ toolName: pendingAction.toolName, args: executedArgs, toolCallId: pendingAction.toolCallId, ...callFaceSeat(parkedRowLiveFace(prepared.toolRosterDeltas.current, pendingAction)) })
686
+ .adjudicate({ toolName: pendingAction.toolName, args: executedArgs, toolCallId: pendingAction.toolCallId, ...callFaceSeat(beltFace()) })
657
687
  .catch(() => ({ status: "unavailable", disclosures: ["the org adjudication face threw on resume"] }));
658
688
  let orgWaitCancelled = false;
659
689
  const org = await settleOrgVerdictWithin(orgVerdict, { status: "unavailable", disclosures: [`the org adjudication face did not answer within ${ORG_ADJUDICATION_TIMEOUT_MS}ms (or the task ended first)`] }, {
@@ -687,7 +717,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
687
717
  }
688
718
  }
689
719
  if (prepared.denyNarrowingPolicy) {
690
- const narrowed = refuseOutOfContractDecision(await prepared.denyNarrowingPolicy.check(beltReq(), prepared.abortController.signal));
720
+ const narrowed = refuseOutOfContractDecision(await beltCheck((signal) => prepared.denyNarrowingPolicy.check(beltReq(), signal), "the narrowing rules re-checking a resumed call"));
691
721
  if (narrowed.action === "deny") {
692
722
  const narrowedDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" is now denied by ${ruleSourcePhrase("narrowing")} and was not executed${narrowed.message ? `: ${narrowed.message}` : ""}.`, prepared.reminderMark);
693
723
  await settleEnd(true, { content: narrowedDenial, ...denialCard(narrowed) }, "policy");
@@ -729,7 +759,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
729
759
  }
730
760
  }
731
761
  if (prepared.shellReadCheck !== undefined) {
732
- const readCall = { toolName: pendingAction.toolName, ...callFaceSeat(parkedRowLiveFace(prepared.toolRosterDeltas.current, pendingAction)) };
762
+ const readCall = { toolName: pendingAction.toolName, ...callFaceSeat(beltFace()) };
733
763
  const judged = prepared.shellReadCheck.judge(readCall, executedArgs, prepared.cwdRef?.current, prepared.abortController.signal, {
734
764
  toolCallId: pendingAction.toolCallId,
735
765
  ...(unseen ? { seat: "rejudge" } : {}),
@@ -2,7 +2,7 @@ import { compactionKindOf } from "../task-notification.js";
2
2
  import { planRejectionClears } from "../context-edit.js";
3
3
  import { rosterToolName } from "../tool-roster.js";
4
4
  import { landStaleResultClears } from "./prepare-context-lane.js";
5
- import { DEFAULT_COMPACTION_INSTRUCTIONS, isCompactionManualCancel, maybeCompact, mintCompactedEvent } from "../auto-compaction.js";
5
+ import { compactionPassReport, DEFAULT_COMPACTION_INSTRUCTIONS, isCompactionManualCancel, maybeCompact, mintCompactedEvent } from "../auto-compaction.js";
6
6
  import { emitTrace } from "../trace.js";
7
7
  import { isDegenerateCutMessage } from "../../brain/terminal-cause.js";
8
8
  import { rebaseCadenceWindows } from "./turn-attachments.js";
@@ -22,6 +22,7 @@ export function runRecoveryLanes(input) {
22
22
  if (callerStop.signal.aborted)
23
23
  return false;
24
24
  const passSignal = AbortSignal.any([prepared.abortController.signal, callerStop.signal, ...(turnSignal !== undefined ? [turnSignal] : [])]);
25
+ const passReport = compactionPassReport(queue, ident);
25
26
  try {
26
27
  const comp = await maybeCompact({
27
28
  session: prepared.session,
@@ -50,6 +51,7 @@ export function runRecoveryLanes(input) {
50
51
  ...compactionRestateOptions(prepared),
51
52
  ...windowSafetyOptions(prepared.harness.getModel()),
52
53
  ...compactionHookOptions(runner, prepared, "forced", passSignal),
54
+ onStarted: passReport.onStarted,
53
55
  });
54
56
  if (comp.compacted) {
55
57
  compactionBreaker.failures = 0;
@@ -95,13 +97,13 @@ export function runRecoveryLanes(input) {
95
97
  catch (err) {
96
98
  if (isCompactionManualCancel(err) || (turnSignal?.aborted === true && !prepared.abortController.signal.aborted)) {
97
99
  emitTrace(rs.telemetry.tracer, () => ({ kind: "compaction.mooted", version: 1, taskId: rs.telemetry.taskId, reason: "cancelled", ts: Date.now() }));
98
- queue.push({ type: "compaction_outcome", outcome: "mooted", trigger: "forced", reason: "cancelled", ...ident() });
100
+ queue.push({ type: "compaction_outcome", outcome: "mooted", trigger: "forced", reason: "cancelled", ...passReport.end, ...ident() });
99
101
  return false;
100
102
  }
101
103
  compactionBreaker.failures += 1;
102
104
  runner.deps.onError?.(asThrownError(err), { phase: "compaction", sessionId: prepared.sessionId });
103
105
  const msg = thrownText(err);
104
- queue.push({ type: "compaction_outcome", outcome: "failed", trigger: "forced", reason: msg.length > 512 ? `${msg.slice(0, 512)}…` : msg, ...ident() });
106
+ queue.push({ type: "compaction_outcome", outcome: "failed", trigger: "forced", reason: msg.length > 512 ? `${msg.slice(0, 512)}…` : msg, ...passReport.end, ...ident() });
105
107
  return false;
106
108
  }
107
109
  };