@sema-agent/core 7.28.1 → 7.30.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 (162) hide show
  1. package/CHANGELOG.md +473 -1
  2. package/dist/agents/child-model-seat.d.ts +59 -7
  3. package/dist/agents/child-model-seat.js +33 -7
  4. package/dist/agents/cross-session-judge.d.ts +27 -5
  5. package/dist/agents/cross-session-judge.js +23 -12
  6. package/dist/agents/list-agents-tool.d.ts +31 -6
  7. package/dist/agents/list-agents-tool.js +66 -14
  8. package/dist/agents/peer-admission.d.ts +20 -8
  9. package/dist/agents/peer-admission.js +21 -12
  10. package/dist/agents/peer-directory.d.ts +29 -0
  11. package/dist/agents/peer-directory.js +20 -0
  12. package/dist/agents/peer-held-queue.d.ts +31 -4
  13. package/dist/agents/peer-held-queue.js +32 -1
  14. package/dist/agents/peer-session-drain.d.ts +91 -13
  15. package/dist/agents/peer-session-drain.js +409 -102
  16. package/dist/agents/read-inbox-tool.d.ts +22 -0
  17. package/dist/agents/read-inbox-tool.js +39 -0
  18. package/dist/agents/roster-store.d.ts +2 -4
  19. package/dist/agents/roster-store.js +1 -1
  20. package/dist/agents/send-message-tool.d.ts +4 -4
  21. package/dist/agents/send-message-tool.js +22 -2
  22. package/dist/agents/subagent.js +62 -44
  23. package/dist/agents/team-role.d.ts +34 -0
  24. package/dist/agents/team-role.js +17 -0
  25. package/dist/agents/verify.js +2 -2
  26. package/dist/brain/anthropic.js +4 -2
  27. package/dist/brain/open-responses.js +4 -3
  28. package/dist/brain/openai.js +2 -1
  29. package/dist/brain/stream-engine.js +6 -0
  30. package/dist/brain/stream-shared.d.ts +8 -0
  31. package/dist/brain/stream-shared.js +8 -0
  32. package/dist/core/auto-compaction.d.ts +42 -0
  33. package/dist/core/auto-compaction.js +35 -2
  34. package/dist/core/child-clamp-seats.d.ts +11 -0
  35. package/dist/core/child-clamp-seats.js +3 -0
  36. package/dist/core/context-edit.d.ts +3 -2
  37. package/dist/core/context-edit.js +6 -5
  38. package/dist/core/context-guard.d.ts +2 -1
  39. package/dist/core/context-guard.js +3 -2
  40. package/dist/core/context-settings.d.ts +103 -0
  41. package/dist/core/context-settings.js +60 -0
  42. package/dist/core/engine-notice.d.ts +18 -1
  43. package/dist/core/frame-settlement.d.ts +97 -0
  44. package/dist/core/frame-settlement.js +36 -0
  45. package/dist/core/governance-codes.d.ts +1 -1
  46. package/dist/core/governance-codes.js +4 -0
  47. package/dist/core/hooks.d.ts +10 -10
  48. package/dist/core/mailbox-store.d.ts +41 -7
  49. package/dist/core/mailbox-store.js +9 -3
  50. package/dist/core/message-utils.d.ts +13 -0
  51. package/dist/core/message-utils.js +6 -0
  52. package/dist/core/parent-spec-seat.d.ts +14 -1
  53. package/dist/core/parent-spec-seat.js +6 -0
  54. package/dist/core/permission-rule-model.js +1 -1
  55. package/dist/core/roles.d.ts +20 -0
  56. package/dist/core/roles.js +35 -16
  57. package/dist/core/runner/assemble-result.d.ts +2 -0
  58. package/dist/core/runner/assemble-result.js +3 -1
  59. package/dist/core/runner/compaction-call-options.d.ts +26 -2
  60. package/dist/core/runner/compaction-call-options.js +9 -0
  61. package/dist/core/runner/compaction-seams.d.ts +4 -3
  62. package/dist/core/runner/compaction-seams.js +13 -6
  63. package/dist/core/runner/contracts.d.ts +61 -7
  64. package/dist/core/runner/decide-continuation.d.ts +2 -1
  65. package/dist/core/runner/decide-continuation.js +11 -10
  66. package/dist/core/runner/initial-run-state.js +2 -2
  67. package/dist/core/runner/prepare-caps-and-workflow.js +9 -1
  68. package/dist/core/runner/prepare-config-doors.js +4 -1
  69. package/dist/core/runner/prepare-context-lane.d.ts +9 -2
  70. package/dist/core/runner/prepare-context-lane.js +15 -10
  71. package/dist/core/runner/prepare-delegation-surface.d.ts +3 -2
  72. package/dist/core/runner/prepare-delegation-surface.js +9 -3
  73. package/dist/core/runner/prepare-file-history.js +10 -8
  74. package/dist/core/runner/prepare-gate-stations.d.ts +4 -0
  75. package/dist/core/runner/prepare-gate-stations.js +3 -1
  76. package/dist/core/runner/prepare-inherited-gate.js +1 -0
  77. package/dist/core/runner/prepare-prompt-inputs.d.ts +6 -0
  78. package/dist/core/runner/prepare-prompt-inputs.js +2 -1
  79. package/dist/core/runner/prepare-task.js +22 -9
  80. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -1
  81. package/dist/core/runner/prepare-wiring-manifest.js +6 -1
  82. package/dist/core/runner/response-model-seat.d.ts +16 -0
  83. package/dist/core/runner/response-model-seat.js +27 -0
  84. package/dist/core/runner/retired-runner-deps.d.ts +3 -1
  85. package/dist/core/runner/retired-runner-deps.js +1 -0
  86. package/dist/core/runner/run-compaction-machinery.d.ts +4 -2
  87. package/dist/core/runner/run-compaction-machinery.js +5 -3
  88. package/dist/core/runner/run-harness-handlers.js +9 -2
  89. package/dist/core/runner/run-identity-wiring.js +19 -1
  90. package/dist/core/runner/run-leg.js +1 -1
  91. package/dist/core/runner/run-notification-lane.js +8 -2
  92. package/dist/core/runner/run-recovery-lanes.js +9 -5
  93. package/dist/core/runner/run-settle-and-teardown.d.ts +4 -22
  94. package/dist/core/runner/run-settle-and-teardown.js +6 -10
  95. package/dist/core/runner/run-stop-and-final-verify.js +1 -0
  96. package/dist/core/runner/run-terminal-adoption.js +5 -5
  97. package/dist/core/runner/run-turn-boundary.js +32 -5
  98. package/dist/core/runner/runtask.d.ts +8 -1
  99. package/dist/core/runner/runtask.js +33 -2
  100. package/dist/core/runner-deps.d.ts +44 -13
  101. package/dist/core/side-query.d.ts +6 -5
  102. package/dist/core/side-query.js +3 -1
  103. package/dist/core/swappable-deps.d.ts +20 -4
  104. package/dist/core/swappable-deps.js +6 -1
  105. package/dist/core/task-event.d.ts +13 -0
  106. package/dist/core/task-notification.d.ts +144 -2
  107. package/dist/core/task-notification.js +154 -5
  108. package/dist/core/task-result.d.ts +27 -3
  109. package/dist/core/task-spec.d.ts +7 -0
  110. package/dist/core/tool-catalog-entries.js +2 -1
  111. package/dist/core/tool-conformance.js +1 -0
  112. package/dist/core/tool-policy.d.ts +9 -4
  113. package/dist/core/tool-spec.d.ts +14 -0
  114. package/dist/core/wiring-manifest.d.ts +12 -0
  115. package/dist/core/wiring-manifest.js +5 -1
  116. package/dist/engine/harness/agent-harness.d.ts +14 -1
  117. package/dist/engine/harness/agent-harness.js +28 -3
  118. package/dist/engine/harness/types.d.ts +3 -1
  119. package/dist/engine/llm/types.d.ts +8 -7
  120. package/dist/engine/llm/types.js +1 -1
  121. package/dist/engine/session/import-validate.js +4 -0
  122. package/dist/index.d.ts +10 -7
  123. package/dist/index.js +7 -5
  124. package/dist/orchestration/run-workflow-tool.d.ts +4 -4
  125. package/dist/orchestration/workflow.d.ts +1 -1
  126. package/dist/orchestration/workflow.js +8 -5
  127. package/dist/shell/lex.d.ts +30 -51
  128. package/dist/shell/lex.js +237 -284
  129. package/dist/stores/cc/mailbox-store.js +3 -2
  130. package/dist/stores/file/corrupt-read-sink.d.ts +28 -2
  131. package/dist/stores/file/file-history-store.d.ts +2 -4
  132. package/dist/stores/file/file-history-store.js +1 -1
  133. package/dist/stores/file/fs-atomic.d.ts +16 -11
  134. package/dist/stores/file/fs-atomic.js +17 -6
  135. package/dist/stores/file/index.d.ts +5 -6
  136. package/dist/stores/file/index.js +1 -1
  137. package/dist/stores/file/mailbox-store.d.ts +4 -9
  138. package/dist/stores/file/mailbox-store.js +29 -30
  139. package/dist/stores/file/session-policy-store.d.ts +2 -0
  140. package/dist/stores/file/session-policy-store.js +1 -1
  141. package/dist/stores/file/session-store.d.ts +11 -7
  142. package/dist/stores/file/session-store.js +23 -16
  143. package/dist/stores/file/shared-ledger.js +3 -14
  144. package/dist/stores/file/tool-result-store.d.ts +2 -0
  145. package/dist/stores/file/tool-result-store.js +5 -2
  146. package/dist/stores/file/workflow-journal-store.js +14 -9
  147. package/dist/tools/fs/bash-program-position.d.ts +15 -24
  148. package/dist/tools/fs/bash-program-position.js +11 -29
  149. package/dist/tools/fs/bash-readonly-classifier.d.ts +125 -117
  150. package/dist/tools/fs/bash-readonly-classifier.js +400 -272
  151. package/dist/tools/fs/shell-read-check.js +3 -3
  152. package/dist/tools/fs/shell-read-establish.js +1 -1
  153. package/dist/tools/fs/shell-read-plan.d.ts +11 -6
  154. package/dist/tools/fs/shell-read-plan.js +167 -183
  155. package/dist/tools/fs/shell-read-word.d.ts +50 -0
  156. package/dist/tools/fs/shell-read-word.js +59 -0
  157. package/dist/tools/fs/shell-reentry-text.d.ts +10 -0
  158. package/dist/tools/fs/shell-reentry-text.js +73 -0
  159. package/package.json +1 -1
  160. package/test/export-surface.snapshot.json +58 -8
  161. package/wire-changes/core@7.29.0.json +185 -0
  162. package/wire-changes/core@7.30.0.json +1821 -0
@@ -68,6 +68,7 @@ import { isRemoteExecutionEnv } from "../remote-env.js";
68
68
  import { settleTeardownLeg } from "./teardown-bounded.js";
69
69
  import { defaultTaskRegistry } from "../task-registry.js";
70
70
  import { announcePeerLaneMount, judgeSessionBoxDrain } from "../../agents/peer-session-drain.js";
71
+ import { createFrameSettlement } from "../frame-settlement.js";
71
72
  import { createSchedulerTools } from "../../tools/scheduler-tools.js";
72
73
  import { selfOrchestrationFailClosedReason } from "../../orchestration/workflow-script-runner.js";
73
74
  import { remainingBudgetMicroUsd, resolveCheckpointStore } from "../checkpoint-store.js";
@@ -82,11 +83,11 @@ import { AdvertisedWritableDirs } from "./advertised-writable-dirs.js";
82
83
  import { resolveTaskRootCanonical } from "./task-root-canonical.js";
83
84
  import { createStructuredProjector } from "./tool-output-projection.js";
84
85
  import { asThrownError, thrownText } from "../thrown-value.js";
85
- function warnCompactionWindowHazard(tracer, spec, model, compModel, hostTaskId) {
86
+ function warnCompactionWindowHazard(tracer, spec, model, compModel, hostTaskId, overlay) {
86
87
  if (compModel === undefined)
87
88
  return;
88
89
  const compWindow = compModel.contextTokens ?? compModel.contextWindow;
89
- const mainWindow = resolveTriggerWindow(model).window;
90
+ const mainWindow = resolveTriggerWindow(model, overlay).window;
90
91
  if (compWindow > 0 && mainWindow > 0 && compWindow < mainWindow) {
91
92
  const merged = { ...DEFAULT_COMPACTION_SETTINGS, ...spec.compaction };
92
93
  const sanitized = sanitizeCompactionSettings(merged, mainWindow);
@@ -247,6 +248,14 @@ function refuseRequireExistingWithoutSession(spec) {
247
248
  throw e;
248
249
  }
249
250
  }
251
+ function refuseRegistryScopeMismatch(spec, internals) {
252
+ const registryScope = internals?.registryScope;
253
+ if (registryScope === undefined || spec.principal === undefined || registryScope === spec.principal)
254
+ return;
255
+ const e = new Error(`registry scope mismatch: principal "${spec.principal}" vs RunInternals.registryScope "${registryScope}" — a delegated run's registry domain is its principal, so the two must be equal (or only one given)`);
256
+ e.code = "config.registry_scope_mismatch";
257
+ throw e;
258
+ }
250
259
  function validateInputFaultNotice(onError, sessionId) {
251
260
  return ({ toolName, toolCallId, error }) => onError?.(new Error(`tool input pre-validation (validateInput) threw for ${toolName} (call ${toolCallId}) — read as no verdict; the call proceeded to the gate: ${thrownText(error)}`), { phase: "hook", sessionId });
252
261
  }
@@ -273,6 +282,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
273
282
  const { toolEffects, egressTools, irreversibleTools, irreversibilityTier, axisExplicitNegatives, reversibilityProbes } = prepareSafetyScan({ spec, deps });
274
283
  let shellGatedTools = new Set();
275
284
  refuseRequireExistingWithoutSession(spec);
285
+ refuseRegistryScopeMismatch(spec, internals);
276
286
  const { acquired, session, conflictRef, wakeRecovered, resumeAtBeforeParentId } = await prepareAcquireReconcile({ sessions, spec, resume, toolEffects, ...(internals?.sessionPlacement !== undefined ? { placement: internals.sessionPlacement } : {}), ...(() => { const g = durableParkGapFor(deps, spec); return g !== undefined ? { durableParkGap: g } : {}; })() });
277
287
  const sessionId = acquired.sessionId;
278
288
  const onceLedger = await loadAnnounceOnceLedger(session, resume?.seed.announcedListings, deps.onError);
@@ -285,13 +295,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
285
295
  (await derivedRouteFallsBack({ seat: "compaction-summary", derived: compModel, primary: model, brain: deps.brain, getApiKeyAndHeaders: spec.getApiKeyAndHeaders, onNotice: deps.onNotice, sessionId, runId }))) {
286
296
  effectiveCompModel = undefined;
287
297
  }
288
- warnCompactionWindowHazard(deps.tracer, spec, model, effectiveCompModel, hostTaskId);
298
+ warnCompactionWindowHazard(deps.tracer, spec, model, effectiveCompModel, hostTaskId, runnerSelf?.contextOverlayOf?.(resolvedRole.modelRef));
289
299
  const taskScope = internals?.registryScope ?? spec.principal ?? "default";
290
300
  internals?.peerSelfRef?.addAxis("s", sessionId);
291
301
  internals?.peerSelfRef?.addAxis("t", hostTaskId);
292
302
  const peerLaneActive = announcePeerLaneMount(deps, { sessionId, runId });
293
303
  const sessionBox = judgeSessionBoxDrain(deps, { sessionId, scope: taskScope, isDelegatedChild: delegation.isDelegatedChild });
294
304
  const peerLaneRefs = {};
305
+ const frameSettlement = createFrameSettlement();
295
306
  const peerSendMessageBuiltIn = runnerSelf !== undefined && !(toolFaceSnapshot.exclude ?? []).includes(SEND_MESSAGE_TOOL_NAME) && !(spec.tools ?? []).some((t) => t.name === SEND_MESSAGE_TOOL_NAME);
296
307
  const { reminderMark, reminderDisclosureCounts } = await adoptReminderMark(session, sessionId, resume?.seed.reminderMark, internals?.reminderMark, deps.onError);
297
308
  const offloadScope = spec.principal ?? "default";
@@ -373,6 +384,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
373
384
  const { canonical: taskRootCanonical } = await resolveTaskRootCanonical({ env: executionEnv, given: taskRootFinal, onNotice: deps.onNotice, sessionId, runId });
374
385
  const { trackFileEdit, fileHistoryBoundary, restoredFilePaths, rewindNotes, fileHistoryEnabled, historyScope, historyRoot, historyFs } = await prepareFileHistory({ deps, spec, internals, executionEnv, taskRootFinal, handsEnabled, sessionId, session, resumeAtBeforeParentId, abortController });
375
386
  const { noteFileEdited, editedFilesSnapshot, harnessRef, toolProgressRef, skillScope, forwardEvent, reviewRequestRef, requestReview, stopRequestedRef, requestStopAfterTurn, planModeRef, enterPlanMode, subagentRetain, worktreeIsolation } = prepareRunRefs({ spec, internals, executionEnv, taskRootFinal });
387
+ const legContextOverlay = () => runnerSelf?.contextOverlayOf?.(harnessRef.current?.getModelRef() ?? resolvedRole.modelRef);
376
388
  let resolvedReadFace;
377
389
  let resolvedWriteFace;
378
390
  let readDenyAdditionsNormalized = [];
@@ -523,7 +535,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
523
535
  handsLessResolvedFace = handsReadFace.handsLessResolvedFace;
524
536
  handsLessResolvedWriteFace = handsReadFace.handsLessResolvedWriteFace;
525
537
  shellGatedTools = handsReadFace.shellGatedTools;
526
- const { worktreeSessionRef } = prepareDelegationSurface({ spec, deps, internals, resume, sessionId, hostTaskId, taskScope, taskRootFinal, taskRootCanonical, executionEnv, runnerSelf, backgroundTaskToolsActive, shellReadAdmission, workflowToolsActive, peerLaneActive, peerSendMessageBuiltIn, peerLaneRefs, roster, toolEffects, axisExplicitNegatives, envHandToolNames, toolFaceSnapshot, firstPartyOffload, offloadStore, subagentRetain, enrichSpecToolCtx, handsCwdRef, wsSnapshot, rebaseWsPath, rebaseRestoredPath, workspaceStateSettle });
538
+ 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, handsCwdRef, wsSnapshot, rebaseWsPath, rebaseRestoredPath, workspaceStateSettle });
527
539
  const { liveQuestionFace, contentAskBindings, contentAskRoutable, lateStrandedAnswers, discloseStrandedAnswers, settleContentAskBindings, durableQuestionFace, questionToolMounted, mountedQuestionTool } = prepareQuestionFace({ frozenOnQuestion, spec, deps, checkpointStore, runtimeCaps, resolvedInteractionPosture, resume, sessionId, roster, inheritedUnavailableAsks: () => inheritedUnavailableAsks });
528
540
  if (spec.handsReadOnly !== true) {
529
541
  const sessionScope = sessionId ?? spec.principal ?? spec.taskId ?? "default";
@@ -582,7 +594,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
582
594
  }
583
595
  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, skillListingBudget: doors.skillListingBudget });
584
596
  const { memoryBlock: memoryBlockWithProject, instructionSources, projectInstructionContent, hasSkillManifest, skillsListing, sharedMemoryPairMounted, memoryEnginePairMounted } = projectContext;
585
- 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 } : {}) });
597
+ const { provider, featureFlags, userSystemPrompt, userAppendSystemPrompt, mcpInstructionsBlock, envFacts, tzValid, userTz, gitStatusRef } = await preparePromptInputs({ spec, deps, contextOverlay: legContextOverlay(), 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 } : {}) });
586
598
  const { deferred, memoryBlock, toolSearch: toolSearchPolicy } = prepareDeferClassify({ spec, deps, roster, toolFaceSnapshot, handsEnabled, fullShellReachable, promptProfile, model, mcp, a2a, sharedMemoryPairMounted, memoryEnginePairMounted, memoryBlock: memoryBlockWithProject, memoryRecallSegment, onceLedger, sessionId });
587
599
  prepareMemoryEngineSession({ memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, mcp, sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames, roster, contentOriginWrapRef });
588
600
  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 });
@@ -658,6 +670,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
658
670
  session,
659
671
  tools: [...harnessTools],
660
672
  model,
673
+ modelRef: resolvedRole.modelRef,
661
674
  thinkingLevel: thinking,
662
675
  systemPrompt: systemPromptSeat.current,
663
676
  ...(systemBlocks ? { systemBlocks } : {}),
@@ -694,7 +707,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
694
707
  }
695
708
  }
696
709
  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, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, hasSkillManifest, skillScope, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef });
697
- const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, writeProtectionCheck, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace, sessionBoxBound } = prepareWiringManifest({ spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, shellReadStationArmed: shellReadCheck !== undefined, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive: handsReadFace.readDenyBuiltinTiersActive, lspManagerWired, lspDiagnosticsLive: lspDiagnostics !== undefined, sessionBox });
710
+ const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, writeProtectionCheck, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace, sessionBoxBound } = prepareWiringManifest({ spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, shellReadStationArmed: shellReadCheck !== undefined, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, frameSettlement, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive: handsReadFace.readDenyBuiltinTiersActive, lspManagerWired, lspDiagnosticsLive: lspDiagnostics !== undefined, sessionBox });
698
711
  if (fileHistoryBoundary !== undefined) {
699
712
  harness.on("tool_call", async () => {
700
713
  await fileHistoryBoundary.settle();
@@ -705,13 +718,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
705
718
  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, ancestorRulesNow, inheritedShellGate, autoModeIntent, approverPosture: approverPostureResolved, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
706
719
  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 });
707
720
  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 });
708
- 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, writeProtectionCheck, shellReadCheck, irreversibilityTier, reversibilityProbes, abortController, shellGatedTools, autoModeDecider, autoModeDenialTracking, stopForDenialLimit, permissionRuleLane, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, notifyOwnHookCrash });
721
+ 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, writeProtectionCheck, shellReadCheck, irreversibilityTier, reversibilityProbes, abortController, shellGatedTools, autoModeDecider, autoModeDenialTracking, stopForDenialLimit, permissionRuleLane, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, notifyOwnHookCrash, frameSettlement });
709
722
  const postureFrameRef = {};
710
- const { microCompact, charsPerToken } = prepareContextLane({ model, deps, sessionId, runId, hostTaskId, offloadStore, microCompactKnob, harness, batchHaltRef, gitStatusRef, postureFrameRef, requestLossyRef, trimPressureRef, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}) });
723
+ const { microCompact, charsPerToken } = prepareContextLane({ model, deps, sessionId, runId, hostTaskId, offloadStore, microCompactKnob, harness, batchHaltRef, gitStatusRef, postureFrameRef, requestLossyRef, trimPressureRef, contextOverlay: legContextOverlay, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}) });
711
724
  const preparedHolder = {};
712
725
  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 });
713
726
  await onceLedger.settle(session, announcedListingsRef);
714
- const buildPrepared = () => ({ harness, session, sessionId, runId, reminderMark, reminderDisclosureCounts, approvalPosture: { autoMode: autoModeIntent, ...(approverPostureResolved !== undefined ? { approverPosture: approverPostureResolved } : {}) }, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(mcpRedial !== undefined ? { mcpRedial } : {}), ...(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, stopForDenialLimit, suspendForReview, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}), resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolRoster, toolRosterDeltas: rosterSeat, structuredProjector, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, microCompact, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { 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, frameReceipts: { pending: [], listingSnapshotOwed: false }, gitStatusRef, postureFrameRef, listBackgroundTasks, hookIdentity, ...(sessionBoxBound !== undefined ? { sessionBox: sessionBoxBound } : {}), hookTimeoutMs, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}), ...(shellReadCheck !== undefined ? { shellReadCheck } : {}), ...(toolDisclosureSeat !== undefined ? { toolDisclosure: toolDisclosureSeat } : {}) });
727
+ const buildPrepared = () => ({ harness, session, sessionId, runId, registryAccess: { owner: hostTaskId, scope: taskScope }, reminderMark, reminderDisclosureCounts, fullShellReachable, approvalPosture: { autoMode: autoModeIntent, ...(approverPostureResolved !== undefined ? { approverPosture: approverPostureResolved } : {}) }, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(mcpRedial !== undefined ? { mcpRedial } : {}), ...(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, stopForDenialLimit, suspendForReview, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}), resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolRoster, toolRosterDeltas: rosterSeat, structuredProjector, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, microCompact, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { 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, frameReceipts: { pending: [], listingSnapshotOwed: false }, frameSettlement, ...(peerLaneRefs.boundaryRound !== undefined ? { peerBoundaryRound: peerLaneRefs.boundaryRound } : {}), gitStatusRef, postureFrameRef, listBackgroundTasks, hookIdentity, ...(sessionBoxBound !== undefined ? { sessionBox: sessionBoxBound } : {}), hookTimeoutMs, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}), ...(shellReadCheck !== undefined ? { shellReadCheck } : {}), ...(toolDisclosureSeat !== undefined ? { toolDisclosure: toolDisclosureSeat } : {}) });
715
728
  rollback.commit();
716
729
  const prepared = buildPrepared();
717
730
  preparedHolder.current = prepared;
@@ -39,7 +39,7 @@ export interface PrepareWiringManifestInput {
39
39
  * `resourceSuspend` (the task-axis lane), `durableApproval` / `principal` (the synthesis and the notice), `interactiveTools` /
40
40
  * `mcp` / `checkpointStore` (manifest cells and the notice's cause), `enablePlanMode` (the gate-machinery predicate's
41
41
  * plan-mode term). Never mutated. */
42
- spec: Pick<TaskSpec, "onAsk" | "onQuestion" | "handsReadOnly" | "tools" | "resourceSuspend" | "durableApproval" | "principal" | "interactiveTools" | "mcp" | "checkpointStore" | "enablePlanMode" | "hooks">;
42
+ spec: Pick<TaskSpec, "onAsk" | "onQuestion" | "handsReadOnly" | "tools" | "resourceSuspend" | "durableApproval" | "principal" | "interactiveTools" | "mcp" | "checkpointStore" | "enablePlanMode" | "hooks" | "peerPresence">;
43
43
  /** borrowed-readonly — the deployment seats, whole: `onAsk` (the seat's deps half), `onError` (the warning), `executionEnv`
44
44
  * (the hook-env predicate), `checkpointStore` (durable infra), the manifest's dozen wiring facts (`backgroundAgentStore`,
45
45
  * `permissionRuleStore`, `permissionRuleSyncWired`, `onBackgroundChildEvent`, `lockedConfig`, `compliancePostureResolver`,
@@ -125,6 +125,11 @@ export interface PrepareWiringManifestInput {
125
125
  /** borrowed-mutable — the peer lane's late-bound facts. Writer here: `askEffective` ← the manifest's ask derivation (the
126
126
  * one fold of this session's permission-mode class). */
127
127
  peerLaneRefs: PeerLaneRefs;
128
+ /** borrowed-mutable — #1036's settlement seam, minted by the orchestrator. This phase writes
129
+ * its two predicate seats (`boxBacked` / `wantsEffects`) when it binds the drain; the ledgers
130
+ * themselves are written later, by the harness receipt sink, the compaction commit beat and the
131
+ * drain's own passes. */
132
+ frameSettlement: import("../frame-settlement.js").FrameSettlement;
128
133
  /** borrowed-readonly — the session-box drain's mount verdict (prepare-task's one judgment): present ⇒ this leg drains its own box. */
129
134
  sessionBox: SessionBoxBinding | undefined;
130
135
  /** borrowed-readonly — the built harness the peer drain binds to. */
@@ -1,4 +1,5 @@
1
1
  import { bindPeerLaneDrain } from "../../agents/peer-session-drain.js";
2
+ import { teamRoleOf } from "../../agents/team-role.js";
2
3
  import { resolveCheckpointStore } from "../checkpoint-store.js";
3
4
  import { createHookEnvCapabilities, mintHookInvocationIdentity } from "../hooks.js";
4
5
  import { wiredHookEntries } from "../hook-seats.js";
@@ -115,7 +116,7 @@ function announceDurableGateUnavailable(args) {
115
116
  });
116
117
  }
117
118
  export function prepareWiringManifest(input) {
118
- const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, sessionBox, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive, lspManagerWired, shellReadStationArmed, lspDiagnosticsLive } = input;
119
+ const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, frameSettlement, sessionBox, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive, lspManagerWired, shellReadStationArmed, lspDiagnosticsLive } = input;
119
120
  const onAsk = spec.onAsk ?? deps.onAsk;
120
121
  const handWriteTools = toolRoster.entries.filter((e) => e.mountedBy === "hands" && (e.effect === "write" || e.effect === "idempotent")).map((e) => e.name);
121
122
  const hasEffectAwareGate = Boolean(policyLayers.length > 0 || (hooks?.preToolUse !== undefined && !preToolUseObservational));
@@ -179,6 +180,8 @@ export function prepareWiringManifest(input) {
179
180
  const wiringManifest = deriveWiringManifest({
180
181
  half: "effective",
181
182
  leg: resume !== undefined ? "resume" : internals?.isDelegatedChild === true ? "child" : "root",
183
+ teamRole: teamRoleOf({ isDelegatedChild: delegation.isDelegatedChild, ...(internals?.explicitAgentName !== undefined ? { spawnName: internals.explicitAgentName } : {}) }),
184
+ ...(spec.peerPresence !== undefined ? { peerPresence: spec.peerPresence } : {}),
182
185
  askForm: wiringAskSeam.form,
183
186
  ...(wiringAskSeam.provenance !== undefined ? { askProvenance: wiringAskSeam.provenance } : {}),
184
187
  questionWired: wiringQuestionSeam.wired,
@@ -227,9 +230,11 @@ export function prepareWiringManifest(input) {
227
230
  inject: internals.onTaskNotification,
228
231
  ownTokens: () => internals?.peerSelfRef?.current.ownTokens ?? [],
229
232
  refs: peerLaneRefs,
233
+ settlement: frameSettlement,
230
234
  selfName: () => internals?.explicitAgentName,
231
235
  parked: () => pausedRef.current !== undefined,
232
236
  });
237
+ frameSettlement.boxBacked = (payload) => peerLaneRefs.isBoxBacked?.(payload) ?? false;
233
238
  }
234
239
  const parkLaneArmed = wiringManifest.parkLane.effective === true;
235
240
  const gateMachineryActive = effectivePolicy !== undefined ||
@@ -0,0 +1,16 @@
1
+ import type { EngineNotice } from "../engine-notice.js";
2
+ /** The seat the harness handlers hold for the run. */
3
+ export interface ResponseModelSeat {
4
+ /** Observe one assistant message: returns the provider-reported name when it carries one (the value the
5
+ * turn's frame reports), `undefined` otherwise, announcing a pair the leg has not announced yet. */
6
+ observe(message: {
7
+ readonly model?: unknown;
8
+ readonly responseModel?: unknown;
9
+ }): string | undefined;
10
+ }
11
+ /** Ids on the notice, so an operator can attribute it without joining on stream order. */
12
+ export interface ResponseModelSeatIds {
13
+ sessionId: string;
14
+ runId: string;
15
+ }
16
+ export declare function createResponseModelSeat(onNotice: ((notice: EngineNotice) => void) | undefined, ids: ResponseModelSeatIds): ResponseModelSeat;
@@ -0,0 +1,27 @@
1
+ import { deliverEngineNotice } from "../engine-notice.js";
2
+ import { providerReportedModel } from "../message-utils.js";
3
+ export function createResponseModelSeat(onNotice, ids) {
4
+ const announced = new Set();
5
+ return {
6
+ observe(message) {
7
+ const reported = providerReportedModel(message);
8
+ if (reported === undefined)
9
+ return undefined;
10
+ const requested = typeof message.model === "string" ? message.model : "";
11
+ const pair = `${requested}\u0000${reported}`;
12
+ if (!announced.has(pair)) {
13
+ announced.add(pair);
14
+ deliverEngineNotice(onNotice, {
15
+ code: "route.response_model_mismatch",
16
+ message: `The provider answered with model "${reported}" for a request sent as "${requested || "(unnamed)"}". ` +
17
+ `The run is unchanged — the engine keeps asking for the id the catalog names, and the served name is ` +
18
+ `reported beside it on every turn (turn_end.responseModel) and on the result (TaskResult.responseModel). ` +
19
+ `This is what an alias, a pool or a gateway-side substitution looks like from here; if the two were ` +
20
+ `meant to be the same model, the catalog id and the gateway disagree about which one that is.`,
21
+ detail: { requested, reported, sessionId: ids.sessionId, runId: ids.runId },
22
+ });
23
+ }
24
+ return reported;
25
+ },
26
+ };
27
+ }
@@ -1,3 +1,5 @@
1
1
  import type { RunnerDeps } from "../types.js";
2
- /** Runs in the pre-first-await config-doors phase, before any resource-bearing preparation, and pre-CAS on a resume. */
2
+ /** Runs on the caller's own argument at `new Runner` (the only point that still sees an inherited or
3
+ * non-enumerable seat — construction spreads deps into plain objects), and again in the pre-first-await
4
+ * config-doors phase and pre-CAS on a resume. */
3
5
  export declare function assertNoRetiredRunnerDeps(deps: RunnerDeps): void;
@@ -1,6 +1,7 @@
1
1
  import { assertNoRetiredKeys } from "../retired-keys.js";
2
2
  const RETIRED_RUNNER_DEPS_KEYS = {
3
3
  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",
4
+ peerAdmission: "the peer lane's knob table is `RunnerDeps.peerLane` (the same fields: admission gate, delivery budgets, listing window)",
4
5
  };
5
6
  export function assertNoRetiredRunnerDeps(deps) {
6
7
  assertNoRetiredKeys(deps, RETIRED_RUNNER_DEPS_KEYS, "RunnerDeps");
@@ -23,8 +23,10 @@ export interface RunCompactionMachineryInput {
23
23
  export interface RunCompactionMachineryResult {
24
24
  /** The accounted compaction brain — `complete` always provided, usage recorded inline. */
25
25
  compactionBrain: Brain;
26
- /** Whether ROUTINE turn-boundary compaction runs for this task. */
27
- withinTaskCompaction: boolean;
26
+ /** Whether ROUTINE turn-boundary compaction runs for this task, asked AT THE BOUNDARY. The request's own
27
+ * `compaction` is fixed for the leg, but the deployment's per-model overlay is a live seat — an operator
28
+ * who turns routine compaction off for a model reaches the legs already on it. */
29
+ withinTaskCompaction: () => boolean;
28
30
  /** §17.4: the consecutive-failure circuit breaker shared by every compaction lane of the run. */
29
31
  compactionBreaker: {
30
32
  failures: number;
@@ -1,5 +1,6 @@
1
1
  import { DEFAULT_COMPACTION_SETTINGS } from "../../internal/harness.js";
2
2
  import { resolveTriggerWindow } from "../context-edit.js";
3
+ import { compactionEnabled, contextOverlayFor } from "../context-settings.js";
3
4
  import { sanitizeCompactionSettings } from "../auto-compaction.js";
4
5
  import { isModelPriced, modelCostToPricing } from "../pricing.js";
5
6
  import { emitTrace } from "../trace.js";
@@ -45,10 +46,11 @@ export function runCompactionMachinery(input) {
45
46
  return msg;
46
47
  },
47
48
  };
48
- const withinTaskCompaction = (spec.compaction?.enabled ?? true) && (spec.compaction?.withinTask ?? true);
49
+ const legOverlay = () => contextOverlayFor(runner.deps.contextSettings, prepared.harness.getModelRef(), runner.deps);
50
+ const withinTaskCompaction = () => compactionEnabled(spec.compaction?.enabled, legOverlay()) && (spec.compaction?.withinTask ?? true);
49
51
  const compactionBreaker = { failures: 0 };
50
- if (spec.compaction?.enabled ?? true) {
51
- const prefixWindow = resolveTriggerWindow(prepared.model).window;
52
+ if (compactionEnabled(spec.compaction?.enabled, legOverlay())) {
53
+ const prefixWindow = resolveTriggerWindow(prepared.model, legOverlay()).window;
52
54
  if (Number.isFinite(prefixWindow) && prefixWindow > 0) {
53
55
  const prefixSettings = sanitizeCompactionSettings({ ...DEFAULT_COMPACTION_SETTINGS, ...spec.compaction }, prefixWindow);
54
56
  const prefixCompactAt = prefixWindow - prefixSettings.reserveTokens;
@@ -10,8 +10,10 @@ import { advanceCadenceClock, reduceToolEnd } from "./turn-attachments.js";
10
10
  import { gatedCallIdOf } from "./park-commit.js";
11
11
  import { hasVerifiableStructureSignal } from "./grounding-signal.js";
12
12
  import { batchResponseDigest, toolEndBodyFrom } from "./tool-end-body.js";
13
+ import { createResponseModelSeat } from "./response-model-seat.js";
13
14
  export function createHarnessHandlers(input) {
14
15
  const { prepared, stats, rs, deps } = input;
16
+ const responseModelSeat = createResponseModelSeat(deps.runnerHooks.onNotice, { sessionId: prepared.sessionId, runId: prepared.runId });
15
17
  const { spec, queue, internals, ident, parentToolCallId, subagentName, pushContent, emitCommitted, startedToolCallIds, toolStartAt, toolProgress, writeFamilyOf, toolLabels, postToolBatchHook, batchArgs, internalsNotifier } = deps;
16
18
  let lastWorkspaceCwd = prepared.cwdRef?.current;
17
19
  const announceWorkspaceMove = () => {
@@ -143,6 +145,9 @@ export function createHarnessHandlers(input) {
143
145
  if (m.role === "assistant" && typeof m.stopReason === "string") {
144
146
  rs.turn.turnStopReason = m.stopReason;
145
147
  }
148
+ if (m.role === "assistant") {
149
+ rs.turn.turnResponseModel = responseModelSeat.observe(m);
150
+ }
146
151
  if (m.role === "assistant") {
147
152
  const rep = m.repetition;
148
153
  if (rep !== undefined) {
@@ -291,13 +296,15 @@ export function createHarnessHandlers(input) {
291
296
  if (prepared.abortController.signal.aborted)
292
297
  prepared.workCutRef.abortedBeforeTurnEnd = true;
293
298
  const stopExtra = rs.turn.turnStopReason !== undefined ? { stopReason: rs.turn.turnStopReason } : {};
299
+ const servedExtra = rs.turn.turnResponseModel !== undefined ? { responseModel: rs.turn.turnResponseModel } : {};
294
300
  const usage = rs.turn.turnUsage ?? { inputTokens: 0, totalInputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, costMicroUsd: 0 };
295
301
  const turnUsageUnknown = rs.turn.turnUsage === undefined || rs.turn.turnUsageMissing;
296
302
  if (turnUsageUnknown)
297
303
  stats.usageMissing = true;
298
- queue.push({ type: "turn_end", usage, ...(turnUsageUnknown ? { usageMissing: true } : {}), ...stopExtra, ...ident() });
304
+ queue.push({ type: "turn_end", usage, ...(turnUsageUnknown ? { usageMissing: true } : {}), ...stopExtra, ...servedExtra, ...ident() });
299
305
  rs.turn.turnUsageMissing = false;
300
306
  rs.turn.turnStopReason = undefined;
307
+ rs.turn.turnResponseModel = undefined;
301
308
  if (parentToolCallId !== undefined) {
302
309
  const progress = {
303
310
  type: "task_progress",
@@ -336,7 +343,7 @@ export function createHarnessHandlers(input) {
336
343
  rs.degrade.degradeToModel &&
337
344
  rs.budget.maxCostMicroUsd !== undefined &&
338
345
  stats.costMicroUsd >= spec.limits.degrade.atCostFraction * rs.budget.maxCostMicroUsd) {
339
- void prepared.harness.setModel(rs.degrade.degradeToModel);
346
+ void prepared.harness.setModel(rs.degrade.degradeToModel, spec.limits.degrade.to);
340
347
  rs.degrade.recordDegraded({ from: prepared.model.id, to: rs.degrade.degradeToModel.id, reason: "budget", atTurn: stats.turns }, rs.degrade.degradeToModel);
341
348
  }
342
349
  const overAxis = rs.limits.budgetHit ? undefined : rs.budget.overBudget();
@@ -1,5 +1,6 @@
1
1
  import { uuidv7 } from "../../internal/harness.js";
2
2
  import { createSafeNotifier, observeThenableRejection } from "../safe-notify.js";
3
+ import { recordFrameReceipt, toolResultReceiptKey } from "../frame-settlement.js";
3
4
  import { discloseDroppedPending, renderTaskNotificationXml, taskNotificationDedupKey } from "../task-notification.js";
4
5
  import { deliverDelegationLifecycle, deliverEngineNotice, undrainedUserInputNotices } from "../types.js";
5
6
  export function runIdentityWiring(input) {
@@ -42,8 +43,12 @@ export function runIdentityWiring(input) {
42
43
  prepared.harness.onUndrainedEngineNotes = (payloads) => {
43
44
  if (notificationLane.sessionId === undefined)
44
45
  return;
45
- for (const p of payloads)
46
+ const boxBacked = prepared.frameSettlement.boxBacked;
47
+ for (const p of payloads) {
48
+ if (boxBacked !== undefined && boxBacked(p))
49
+ continue;
46
50
  pendingSessionNotifications.pend(notificationLane.sessionId, p);
51
+ }
47
52
  };
48
53
  prepared.harness.engineInjectionsHeld = () => prepared.batchHaltRef.current !== undefined;
49
54
  let undrainedUserAtEnd;
@@ -66,6 +71,19 @@ export function runIdentityWiring(input) {
66
71
  if (notificationLane.sessionId !== undefined && typeof payload?.task_id === "string" && typeof payload.status === "string")
67
72
  pendingSessionNotifications.markDelivered(notificationLane.sessionId, taskNotificationDedupKey(payload));
68
73
  };
74
+ prepared.harness.onFrameCommitted = (carrier, entryId) => {
75
+ const seam = prepared.frameSettlement;
76
+ if (seam.awaiting.size === 0)
77
+ return;
78
+ const key = carrier.kind === "tool_result"
79
+ ? toolResultReceiptKey(carrier.toolCallId)
80
+ : (() => {
81
+ const payload = carrier.payload;
82
+ return typeof payload?.task_id === "string" && typeof payload.status === "string" ? taskNotificationDedupKey(payload) : undefined;
83
+ })();
84
+ if (key !== undefined)
85
+ recordFrameReceipt(seam, key, carrier.kind === "tool_result" ? carrier.content : undefined, entryId);
86
+ };
69
87
  if (notifyRef)
70
88
  notifyRef.inject = injectTaskNotification;
71
89
  if (captureOptOutRef && prepared.memoryEngineSession?.captureOptOut !== undefined) {
@@ -107,7 +107,7 @@ export async function runLeg(input) {
107
107
  rs.limits.budgetAxis = "cost";
108
108
  }
109
109
  else {
110
- let continuation = resumeContinuation(resume, prepared.reminderMark);
110
+ let continuation = resumeContinuation(resume, prepared.reminderMark, prepared.fullShellReachable);
111
111
  const bgSnapshot = resume.cp.state.runningBackgroundTasks;
112
112
  let orphanTasks = [];
113
113
  if (bgSnapshot !== undefined && bgSnapshot.length > 0) {
@@ -1,9 +1,13 @@
1
1
  import { createPeerInboundChainRef, createPeerSelfRef } from "../../agents/peer-admission.js";
2
2
  import { boundInputHashOf } from "../canonical-json.js";
3
- import { createLiveNotificationLane, isDelegatedAgentTerminal, isTerminalTaskNotification, renderTaskNotificationXml, routeOrParkNotification, SystemInjectionQueue } from "../task-notification.js";
3
+ import { createLiveNotificationLane, DurableAppendObligations, isDelegatedAgentTerminal, isTerminalTaskNotification, renderTaskNotificationXml, routeOrParkNotification, SystemInjectionQueue, taskNotificationDedupKey } from "../task-notification.js";
4
4
  import { ToolDetachHub } from "../tool-detach.js";
5
5
  import { pendingContentAskCallId } from "./decide-continuation.js";
6
- export async function runNotificationLane(input) {
6
+ export function runNotificationLane(input) {
7
+ const obligations = new DurableAppendObligations();
8
+ return obligations.run(() => runNotificationLaneAs(input, obligations));
9
+ }
10
+ async function runNotificationLaneAs(input, obligations) {
7
11
  const { spec, queue, resume, internals, taskIdRef, runner, self, sessions, sessionReadStates, pendingSessionNotifications, prepareTask, next } = input;
8
12
  const prepareResume = resume
9
13
  ? {
@@ -68,6 +72,7 @@ export async function runNotificationLane(input) {
68
72
  const noteOptions = {
69
73
  provenance: "engine-note",
70
74
  enginePayload: item.payload,
75
+ engineNoteKey: taskNotificationDedupKey(item.payload),
71
76
  ...(item.payload.task_type !== "external" && isTerminalTaskNotification(item.payload) ? { capPreferred: true } : {}),
72
77
  };
73
78
  const deliver = item.priority === "later"
@@ -153,5 +158,6 @@ export async function runNotificationLane(input) {
153
158
  finally {
154
159
  if (notificationSessionId !== undefined)
155
160
  pendingSessionNotifications.liveLanes.unregister(notificationSessionId, takeAsDestination);
161
+ await obligations.settle();
156
162
  }
157
163
  }
@@ -1,11 +1,12 @@
1
- import { DEFAULT_COMPACTION_SETTINGS } from "../../internal/harness.js";
1
+ import { compactionKindOf } from "../task-notification.js";
2
2
  import { planRejectionClears } from "../context-edit.js";
3
3
  import { landStaleResultClears } from "./prepare-context-lane.js";
4
4
  import { DEFAULT_COMPACTION_INSTRUCTIONS, maybeCompact, mintCompactedEvent } from "../auto-compaction.js";
5
5
  import { emitTrace } from "../trace.js";
6
6
  import { isDegenerateCutMessage } from "../../brain/terminal-cause.js";
7
7
  import { rebaseCadenceWindows } from "./turn-attachments.js";
8
- import { buildWorkingFileAttachments, centerAdoptionOption, contextInstructionFilesOption, emitInputTruncated, forkContextOption } from "./compaction-call-options.js";
8
+ import { buildWorkingFileAttachments, centerAdoptionOption, contextInstructionFilesOption, emitInputTruncated, forkContextOption, legCompactionSettings, legContextOverlayOption } from "./compaction-call-options.js";
9
+ import { compactionEnabled } from "../context-settings.js";
9
10
  import { compactionRestateOptions } from "./compaction-restate.js";
10
11
  import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
11
12
  import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
@@ -13,7 +14,7 @@ import { asThrownError, thrownText } from "../thrown-value.js";
13
14
  export function runRecoveryLanes(input) {
14
15
  const { spec, prepared, queue, rs, ident, compactionBrain, compactionBreaker, windowSafetyOptions, runner } = input;
15
16
  const runForcedCompactionPass = async (lane, turnSignal) => {
16
- if (!(spec.compaction?.enabled ?? true))
17
+ if (!compactionEnabled(spec.compaction?.enabled, legContextOverlayOption(prepared, runner).contextOverlay))
17
18
  return false;
18
19
  if (compactionBreaker.failures >= MAX_CONSECUTIVE_COMPACTION_FAILURES)
19
20
  return false;
@@ -24,12 +25,13 @@ export function runRecoveryLanes(input) {
24
25
  epochDeclaredSections: prepared.epochDeclaredSections,
25
26
  ...centerAdoptionOption(prepared),
26
27
  model: prepared.harness.getModel(),
28
+ ...legContextOverlayOption(prepared, runner),
27
29
  compactionModel: prepared.compModel,
28
30
  ...forkContextOption(prepared, true),
29
31
  brain: compactionBrain,
30
32
  getApiKeyAndHeaders: spec.getApiKeyAndHeaders,
31
33
  thinking: prepared.thinking,
32
- settings: { ...DEFAULT_COMPACTION_SETTINGS, ...spec.compaction },
34
+ settings: legCompactionSettings(spec, legContextOverlayOption(prepared, runner).contextOverlay),
33
35
  customInstructions: spec.compaction?.instructions ?? DEFAULT_COMPACTION_INSTRUCTIONS,
34
36
  signal: passSignal,
35
37
  minTokens: 0,
@@ -52,6 +54,8 @@ export function runRecoveryLanes(input) {
52
54
  rs.counters.compactionFloor = Math.ceil(comp.postTriggerTokens * COMPACTION_REGROWTH_FACTOR);
53
55
  }
54
56
  queue.push(mintCompactedEvent(comp, "forced", ident()));
57
+ rs.counters.compactionPasses += 1;
58
+ rs.counters.compactionKind = compactionKindOf("forced");
55
59
  if (comp.phaseDurations !== undefined && comp.durationMs !== undefined) {
56
60
  const pd = comp.phaseDurations;
57
61
  const pdDur = comp.durationMs;
@@ -112,7 +116,7 @@ export function runRecoveryLanes(input) {
112
116
  return false;
113
117
  if (prepared.microCompact.clearOnRejection && attempt === 1) {
114
118
  const proj = prepared.microCompact.projectionRef.current;
115
- const compactionAvailable = (spec.compaction?.enabled ?? true) && compactionBreaker.failures < MAX_CONSECUTIVE_COMPACTION_FAILURES;
119
+ const compactionAvailable = compactionEnabled(spec.compaction?.enabled, legContextOverlayOption(prepared, runner).contextOverlay) && compactionBreaker.failures < MAX_CONSECUTIVE_COMPACTION_FAILURES;
116
120
  const declineArm = compactionAvailable ? "forced_compaction" : "none";
117
121
  const plan = proj === undefined
118
122
  ? { declined: "no_candidates" }
@@ -1,24 +1,3 @@
1
- /**
2
- * The run body's SETTLE AND TEARDOWN (R15), verbatim from `Runner.runLocked`: the end-of-task
3
- * compaction's frames and detector reset, the nested-stats fold, the prefix-cache observability and its loud
4
- * mismatch / low-hit disclosures, the cross-slice cumulative spend fold, the human-review and mechanism counters,
5
- * the result assembly (`assembleResult` — the one place the leg's facts become a TaskResult), the resume leg's
6
- * unstarted-action reopen compensation, the read-state seal and the settle-time workspace-state write, the
7
- * StopFailure observer, the delegation-lifecycle terminal, the reap-stash for a committed pause, the resumed-terminal
8
- * unpin, the memory harvest, the `task.end` trace, `setResult`, the sub-agent's terminal tick, the mooted manual
9
- * compaction, the forwarded-frame drain and the queue's `done` + close, the file-history boundary settle and the
10
- * prompt-suggestion kickoff — then, in its finally, the four teardown legs in the order they were: the shell-lane
11
- * children settle, the background-shell sweep, the registry clears / the background-agent abort / the retained
12
- * child sessions, and the owned env's teardown. The suggestion pass (`suggestNextPrompts`, with its four bounds) and the
13
- * owned-env teardown (`teardownOwnedEnv`) are the lane's own module-private functions since S7, verbatim from
14
- * the Runner's private methods: each has this one caller, and a sibling file would be a lane-to-lane reach (the S6 legs' reading).
15
- *
16
- * Async (eleven first-level awaits, all of them the same awaits at the same positions). The `queue.push("done")` and
17
- * the teardown legs' order are contract (the forwarded-frame drain lands before `done`; the env is torn down after
18
- * every reader of it); nothing here reorders them. Products: the result is PUBLISHED through `setResult` and the
19
- * effects are installed on the borrowed seats — nothing comes back to the driver (the same empty Result the seat
20
- * lanes whose products are all installations carry).
21
- */
22
1
  import type { AssistantMessage } from "../../internal/llm.js";
23
2
  import type { ResolvedReasoning } from "../../brain/reasoning.js";
24
3
  import type { PushQueue } from "../push-queue.js";
@@ -27,7 +6,7 @@ import { type CompactOutcome, type DelegationLifecycleEvent, type OwedUserInputA
27
6
  import { type Stats } from "./assemble-result.js";
28
7
  import type { EndOfTaskCompaction, InstallingPhaseResult, ManualCompactRef, Prepared, ResumeRun, RunInternals, RunnerDepsSeat, RunState, SuspendReap, TaskIdRef } from "./contracts.js";
29
8
  export interface RunSettleAndTeardownInput {
30
- /** borrowed-readonly — the task spec: the hooks slot, the suggestion opt-in, the retain / forward flags, the task id and principal. */
9
+ /** borrowed-readonly — the task spec: the hooks slot, the suggestion opt-in, the retain / forward flags, the task id. */
31
10
  spec: TaskSpec;
32
11
  /** borrowed-mutable — the run's event queue: the compaction / human-input / task_progress / done frames, then CLOSED here. */
33
12
  queue: PushQueue<TaskEvent>;
@@ -94,6 +73,9 @@ export interface RunSettleAndTeardownInput {
94
73
  };
95
74
  /** borrowed-readonly — the end-of-task compaction's outcome (the terminal-adoption lane's `finish` call). */
96
75
  comp: EndOfTaskCompaction;
76
+ /** borrowed-readonly — the run's compaction breaker: the ONE source of `TaskResult.compaction.breakerOpen`. */ compactionBreaker: {
77
+ readonly failures: number;
78
+ };
97
79
  /** borrowed-readonly — the adoption lane's unsettled undrained-input account, closed below (after the reopen). */
98
80
  owedUserInput: OwedUserInputAccount;
99
81
  /** borrowed-readonly — the stream's result setter: the assembled TaskResult is published through it exactly once. */
@@ -1,3 +1,4 @@
1
+ import { MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
1
2
  import { isSyntheticApiErrorMessage } from "../../internal/harness.js";
2
3
  import { adjudicateDerivedRoute, fallbackToPrimaryNotice, sameRouteIdentity } from "../../brain/route-adjudicator.js";
3
4
  import { isDegenerateCutMessage } from "../../brain/terminal-cause.js";
@@ -23,7 +24,7 @@ import { amendTerminal, terminalProjection } from "./terminal-projection.js";
23
24
  import { mintCompactedEvent } from "../auto-compaction.js";
24
25
  import { asThrownError } from "../thrown-value.js";
25
26
  export async function runSettleAndTeardown(input) {
26
- const { spec, queue, prepared, resume, internals, rs, stats, ident, parentToolCallId, subagentName, loopLatch, timeout, ownCommittedTailRef, emitDelegationLifecycle, taskIdRef, manualCompactRef, drainManualCompact, final, threw, abortedLive, userInterruptedLive, answerSettled, strandedHumanAnswers, reasoningResolution, comp, owedUserInput, setResult, onSuggestions, onSuspend, runner, sessions } = input;
27
+ const { spec, queue, prepared, resume, internals, rs, stats, ident, parentToolCallId, subagentName, loopLatch, timeout, ownCommittedTailRef, emitDelegationLifecycle, taskIdRef, manualCompactRef, drainManualCompact, final, threw, abortedLive, userInterruptedLive, answerSettled, strandedHumanAnswers, reasoningResolution, comp, compactionBreaker, owedUserInput, setResult, onSuggestions, onSuspend, runner, sessions } = input;
27
28
  try {
28
29
  if (comp?.compacted) {
29
30
  queue.push(mintCompactedEvent(comp, "auto", ident()));
@@ -100,6 +101,7 @@ export async function runSettleAndTeardown(input) {
100
101
  effectiveReadDenyPatterns: prepared.effectiveReadDenyPatterns,
101
102
  effectiveMemoryScopes: prepared.effectiveMemoryScopes,
102
103
  effectiveReasoning: reasoningResolution.current,
104
+ ...(rs.counters.compactionPasses > 0 || compactionBreaker.failures >= MAX_CONSECUTIVE_COMPACTION_FAILURES ? { compaction: { passes: rs.counters.compactionPasses, breakerOpen: compactionBreaker.failures >= MAX_CONSECUTIVE_COMPACTION_FAILURES, ...(rs.counters.compactionKind !== undefined ? { kind: rs.counters.compactionKind } : {}) } } : {}),
103
105
  retryAfterMs: rs.limits.platformTerminal?.retryAfterMs,
104
106
  abortedForTimeout: timeout.fired,
105
107
  abortedForTurns: rs.limits.turnsExceeded,
@@ -295,7 +297,7 @@ export async function runSettleAndTeardown(input) {
295
297
  hasDestroy(prepared.ownedEnv) &&
296
298
  isIsolated(prepared.ownedEnv) &&
297
299
  prepared.pausedRef.current === undefined;
298
- await settleTeardownLeg(() => defaultTaskRegistry.settleKilledForOwner({ owner: spec.taskId ?? prepared.sessionId, scope: spec.principal ?? "default", sessionId: prepared.sessionId }, {
300
+ await settleTeardownLeg(() => defaultTaskRegistry.settleKilledForOwner({ ...prepared.registryAccess, sessionId: prepared.sessionId }, {
299
301
  source: abortedLive &&
300
302
  !answerSettled &&
301
303
  !timeout.fired &&
@@ -325,14 +327,8 @@ export async function runSettleAndTeardown(input) {
325
327
  runner.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
326
328
  }
327
329
  }
328
- defaultTaskRegistry.clearBackgroundForOwner({
329
- owner: spec.taskId ?? prepared.sessionId,
330
- scope: spec.principal ?? "default",
331
- });
332
- defaultTaskRegistry.abortBackgroundAgentsForOwner({
333
- owner: spec.taskId ?? prepared.sessionId,
334
- scope: spec.principal ?? "default",
335
- }, { skipSessionScoped: true });
330
+ defaultTaskRegistry.clearBackgroundForOwner(prepared.registryAccess);
331
+ defaultTaskRegistry.abortBackgroundAgentsForOwner(prepared.registryAccess, { skipSessionScoped: true });
336
332
  if (prepared.subagentRetain) {
337
333
  await settleTeardownLeg(() => prepared.subagentRetain.disposeAll(), "subagentRetain.disposeAll", (e) => runner.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
338
334
  }
@@ -108,6 +108,7 @@ export function runStopAndFinalVerify(input) {
108
108
  stopHookActive: consecutiveBlocks > 0,
109
109
  consecutiveBlocks,
110
110
  getBranch: () => prepared.session.getBranch(),
111
+ backgroundTasks: () => prepared.listBackgroundTasks(),
111
112
  identity: prepared.hookIdentity,
112
113
  signal: sig,
113
114
  }));