@sema-agent/core 7.56.0 → 7.57.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 (173) hide show
  1. package/CHANGELOG.md +541 -0
  2. package/LICENSE +1 -1
  3. package/dist/agents/org-delivery-gate.js +3 -4
  4. package/dist/agents/peer-held-queue.d.ts +69 -49
  5. package/dist/agents/peer-held-queue.js +255 -106
  6. package/dist/agents/peer-session-drain.js +63 -43
  7. package/dist/agents/send-message-tool.js +3 -2
  8. package/dist/agents/subagent.js +8 -8
  9. package/dist/brain/anthropic.js +16 -8
  10. package/dist/brain/open-responses.js +10 -8
  11. package/dist/brain/openai.js +11 -9
  12. package/dist/brain/provider-dialect.d.ts +3 -2
  13. package/dist/brain/provider-dialect.js +2 -2
  14. package/dist/brain/request-params.d.ts +6 -0
  15. package/dist/brain/request-params.js +14 -1
  16. package/dist/brain/stream-engine.d.ts +9 -0
  17. package/dist/brain/stream-engine.js +24 -10
  18. package/dist/brain/stream-shared.d.ts +5 -4
  19. package/dist/brain/stream-shared.js +4 -4
  20. package/dist/core/allow-entry.d.ts +3 -10
  21. package/dist/core/allow-entry.js +17 -25
  22. package/dist/core/approval-object.d.ts +21 -5
  23. package/dist/core/approval-object.js +44 -17
  24. package/dist/core/ask-origin.d.ts +2 -2
  25. package/dist/core/auto-compaction.d.ts +71 -6
  26. package/dist/core/auto-compaction.js +42 -26
  27. package/dist/core/background-agent-store.d.ts +6 -2
  28. package/dist/core/background-agent-store.js +1 -1
  29. package/dist/core/checkpoint-requirements.d.ts +7 -1
  30. package/dist/core/checkpoint-requirements.js +2 -0
  31. package/dist/core/checkpoint-store.d.ts +17 -29
  32. package/dist/core/checkpoint-store.js +19 -11
  33. package/dist/core/cross-boundary-taint.js +4 -2
  34. package/dist/core/engine-notice.d.ts +3 -2
  35. package/dist/core/engine-notice.js +6 -0
  36. package/dist/core/file-history-store.d.ts +14 -8
  37. package/dist/core/file-history-store.js +14 -4
  38. package/dist/core/gate-lanes.js +2 -3
  39. package/dist/core/hooks.d.ts +2 -2
  40. package/dist/core/mailbox-store.d.ts +62 -1
  41. package/dist/core/mailbox-store.js +59 -0
  42. package/dist/core/mcp-name-judge.d.ts +46 -0
  43. package/dist/core/mcp-name-judge.js +61 -0
  44. package/dist/core/mcp-probe.d.ts +1 -1
  45. package/dist/core/mcp-probe.js +2 -5
  46. package/dist/core/mcp.js +10 -30
  47. package/dist/core/memory-engine/consolidation-driver.js +4 -3
  48. package/dist/core/memory-engine/distiller.js +26 -17
  49. package/dist/core/memory-engine/layout.js +5 -2
  50. package/dist/core/park-selfcheck.js +2 -0
  51. package/dist/core/permission-rule-consent.d.ts +5 -3
  52. package/dist/core/permission-rule-consent.js +20 -15
  53. package/dist/core/permission-rule-model.d.ts +43 -2
  54. package/dist/core/permission-rule-model.js +52 -8
  55. package/dist/core/permission-rule-org.js +1 -1
  56. package/dist/core/protocol-http-auth.d.ts +16 -2
  57. package/dist/core/protocol-http-auth.js +42 -11
  58. package/dist/core/protocol-naming.d.ts +20 -0
  59. package/dist/core/protocol-naming.js +20 -3
  60. package/dist/core/read-only-shell.d.ts +20 -5
  61. package/dist/core/read-only-shell.js +29 -14
  62. package/dist/core/remote-env.d.ts +37 -1
  63. package/dist/core/remote-env.js +11 -0
  64. package/dist/core/resume-startup-cause.d.ts +24 -2
  65. package/dist/core/resume-startup-cause.js +20 -1
  66. package/dist/core/roles.js +50 -7
  67. package/dist/core/runner/compact-session.d.ts +10 -0
  68. package/dist/core/runner/compact-session.js +202 -0
  69. package/dist/core/runner/compaction-call-options.d.ts +2 -2
  70. package/dist/core/runner/compaction-seams.d.ts +21 -1
  71. package/dist/core/runner/compaction-seams.js +11 -8
  72. package/dist/core/runner/contracts.d.ts +23 -16
  73. package/dist/core/runner/derived-route-fallback.d.ts +13 -0
  74. package/dist/core/runner/derived-route-fallback.js +6 -0
  75. package/dist/core/runner/env-capability-census.d.ts +3 -2
  76. package/dist/core/runner/env-capability-census.js +9 -3
  77. package/dist/core/runner/permission-rule-lanes.d.ts +7 -7
  78. package/dist/core/runner/permission-rule-lanes.js +17 -11
  79. package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -0
  80. package/dist/core/runner/prepare-acquire-reconcile.js +2 -1
  81. package/dist/core/runner/prepare-config-doors.d.ts +6 -0
  82. package/dist/core/runner/prepare-config-doors.js +4 -3
  83. package/dist/core/runner/prepare-hands-readface.d.ts +3 -1
  84. package/dist/core/runner/prepare-hands-readface.js +2 -0
  85. package/dist/core/runner/prepare-park-ask.d.ts +2 -0
  86. package/dist/core/runner/prepare-park-ask.js +2 -2
  87. package/dist/core/runner/prepare-policy-chain.js +2 -4
  88. package/dist/core/runner/prepare-task.d.ts +4 -1
  89. package/dist/core/runner/prepare-task.js +23 -27
  90. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +13 -0
  91. package/dist/core/runner/prepare-tool-disclosure-mount.js +13 -7
  92. package/dist/core/runner/rewind-files.d.ts +2 -5
  93. package/dist/core/runner/rewind-files.js +9 -51
  94. package/dist/core/runner/run-leg.js +10 -21
  95. package/dist/core/runner/run-notification-lane.d.ts +2 -0
  96. package/dist/core/runner/run-notification-lane.js +2 -2
  97. package/dist/core/runner/run-recovery-lanes.js +3 -4
  98. package/dist/core/runner/run-settle-and-teardown.js +5 -11
  99. package/dist/core/runner/run-terminal-adoption.js +3 -4
  100. package/dist/core/runner/run-turn-boundary.js +3 -5
  101. package/dist/core/runner/runtask.d.ts +8 -1
  102. package/dist/core/runner/runtask.js +28 -34
  103. package/dist/core/runner/send-message-continuation.js +1 -1
  104. package/dist/core/runner/session-verb-doors.d.ts +28 -0
  105. package/dist/core/runner/session-verb-doors.js +48 -0
  106. package/dist/core/runner/session-write-ledger.d.ts +30 -0
  107. package/dist/core/runner/session-write-ledger.js +101 -0
  108. package/dist/core/runner/stream-settle-backstop.js +11 -14
  109. package/dist/core/runner/sub-agent-deny-lists.d.ts +25 -3
  110. package/dist/core/runner/sub-agent-deny-lists.js +21 -10
  111. package/dist/core/runner/teardown-bounded.d.ts +1 -0
  112. package/dist/core/runner/teardown-bounded.js +1 -0
  113. package/dist/core/runner-deps.d.ts +2 -2
  114. package/dist/core/secret-env.d.ts +4 -0
  115. package/dist/core/secret-env.js +3 -0
  116. package/dist/core/session-policy-store.d.ts +7 -2
  117. package/dist/core/session-policy-store.js +1 -1
  118. package/dist/core/shell-wrapper-projection.d.ts +1 -1
  119. package/dist/core/store-contracts/background-agent-store-contract.js +1 -0
  120. package/dist/core/store-contracts/checkpoint-store-contract.js +2 -1
  121. package/dist/core/store-contracts/file-history-store-contract.js +9 -0
  122. package/dist/core/store-contracts/mailbox-store-contract.js +49 -1
  123. package/dist/core/task-registry-agent.d.ts +8 -4
  124. package/dist/core/task-registry-agent.js +14 -8
  125. package/dist/core/task-registry-shared.d.ts +35 -6
  126. package/dist/core/task-registry-shared.js +11 -0
  127. package/dist/core/task-registry.d.ts +1 -1
  128. package/dist/core/task-registry.js +1 -1
  129. package/dist/core/tool-catalog-entries.d.ts +6 -0
  130. package/dist/core/tool-catalog-entries.js +1 -0
  131. package/dist/core/tool-name-aliases.d.ts +32 -2
  132. package/dist/core/tool-name-aliases.js +23 -0
  133. package/dist/core/tool-name-readings.d.ts +4 -0
  134. package/dist/core/tool-name-readings.js +1 -0
  135. package/dist/core/tool-policy.d.ts +10 -6
  136. package/dist/core/tool-policy.js +4 -7
  137. package/dist/core/trace.d.ts +4 -1
  138. package/dist/core/trace.js +2 -1
  139. package/dist/core/untrusted-egress.d.ts +20 -0
  140. package/dist/core/untrusted-egress.js +77 -3
  141. package/dist/engine/harness/agent-harness.d.ts +7 -5
  142. package/dist/engine/harness/agent-harness.js +11 -2
  143. package/dist/engine/loop/agent-loop.d.ts +1 -4
  144. package/dist/engine/loop/agent-loop.js +26 -4
  145. package/dist/index.d.ts +12 -7
  146. package/dist/index.js +7 -4
  147. package/dist/internal/harness.d.ts +2 -1
  148. package/dist/internal/harness.js +1 -0
  149. package/dist/primitives/credential-ref.d.ts +89 -0
  150. package/dist/primitives/credential-ref.js +125 -0
  151. package/dist/primitives/index.d.ts +2 -0
  152. package/dist/primitives/index.js +1 -0
  153. package/dist/stores/file/checkpoint-store.d.ts +0 -4
  154. package/dist/stores/file/checkpoint-store.js +0 -1
  155. package/dist/stores/file/file-history-store.js +12 -4
  156. package/dist/stores/file/mailbox-store.d.ts +2 -1
  157. package/dist/stores/file/mailbox-store.js +26 -1
  158. package/dist/tools/fs/bash-readonly-classifier.d.ts +15 -19
  159. package/dist/tools/fs/bash-readonly-classifier.js +5 -10
  160. package/dist/tools/fs/fs-bash.js +10 -3
  161. package/dist/tools/fs/pattern-kill-guard.d.ts +3 -2
  162. package/dist/tools/fs/pattern-kill-guard.js +68 -36
  163. package/dist/tools/fs/shell-read-check.d.ts +10 -0
  164. package/dist/tools/fs/shell-read-check.js +7 -1
  165. package/dist/tools/fs/shell-read-identity.d.ts +12 -9
  166. package/dist/tools/fs/shell-read-identity.js +9 -4
  167. package/dist/tools/web.js +9 -7
  168. package/package.json +1 -1
  169. package/test/export-surface.snapshot.json +79 -3
  170. package/wire-changes/core-stores-sql@7.57.0.json +29 -0
  171. package/wire-changes/core@7.57.0.json +1487 -0
  172. package/wire-changes/mods-kernel@7.57.0.json +29 -0
  173. package/wire-changes/primitives@7.57.0.json +245 -0
@@ -74,7 +74,7 @@ export { compensateUnparkedPause } from "./prepare-suspend-saga.js";
74
74
  import { checkpointScopeOf, placementValueOrAbsent } from "./checkpoint-scope.js";
75
75
  export { DEFAULT_IRREVERSIBLE_SCOPE, checkpointScopeOf, placementValueOrAbsent } from "./checkpoint-scope.js";
76
76
  export { mcpManifestEntries } from "./prepare-wiring-manifest.js";
77
- import { derivedRouteFallsBack } from "./derived-route-fallback.js";
77
+ import { compactionSummaryFallback, compactionSummaryIsDerived } from "./derived-route-fallback.js";
78
78
  import { prepareAdvisor } from "./prepare-advisor.js";
79
79
  import { prepareProtocolTools } from "./prepare-protocol-tools.js";
80
80
  import { prepareQuestionFace } from "./prepare-question-face.js";
@@ -91,8 +91,8 @@ import { announcePeerLaneMount, judgeSessionBoxDrain } from "../../agents/peer-s
91
91
  import { createFrameSettlement } from "../frame-settlement.js";
92
92
  import { createSchedulerTools } from "../../tools/scheduler-tools.js";
93
93
  import { selfOrchestrationFailClosedReason } from "../../orchestration/workflow-script-runner.js";
94
- import { compileToolSelector, valveLeaves } from "../../agents/tool-filter.js";
95
- import { boundOwnToolLists, boundToolListsJudgment, judgeRunToolLists } from "./sub-agent-deny-lists.js";
94
+ import { valveLeaves } from "../../agents/tool-filter.js";
95
+ import { boundOwnToolLists, boundToolListsJudgment, judgeRunToolLists, ownListsWhereOf, readToolSelector } from "./sub-agent-deny-lists.js";
96
96
  import { remainingBudgetMicroUsd, resolveCheckpointStore } from "../checkpoint-store.js";
97
97
  import { checkpointSeatOf } from "../checkpoint-seat.js";
98
98
  import { handsWriteHalfMounts } from "../../tools/fs/index.js";
@@ -288,7 +288,7 @@ function refuseRegistryScopeMismatch(spec, internals) {
288
288
  function validateInputFaultNotice(onError, sessionId) {
289
289
  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 });
290
290
  }
291
- export async function prepareTask(request, deps, sessions, resume, internals, runnerSelf, runIdSink, holdSessionLock) {
291
+ export async function prepareTask(request, deps, sessions, resume, internals, runnerSelf, runIdSink, holdSessionLock, legWrites) {
292
292
  const runId = uuidv7();
293
293
  if (runIdSink !== undefined)
294
294
  runIdSink.runId = runId;
@@ -317,17 +317,6 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
317
317
  refuseRequireExistingWithoutSession(spec);
318
318
  refuseRegistryScopeMismatch(spec, internals);
319
319
  const ownToolLists = boundOwnToolLists(internals?.ownToolLists ?? resume?.seed.ownToolLists, toolFaceLists);
320
- const extraBodyRefusal = judgeExtraBody(model.extraBody, model.id).refused;
321
- if (extraBodyRefusal !== undefined)
322
- throw Object.assign(new Error(extraBodyRefusal.sentence), { code: extraBodyRefusal.code, ...(extraBodyRefusal.field !== undefined ? { detail: { field: extraBodyRefusal.field } } : {}) });
323
- for (const cap of MODEL_CAPABILITIES)
324
- capabilityOf(model, cap);
325
- const fileHistoryRequest = resolveFileHistoryRequest(spec, deps);
326
- const { acquired, session, conflictRef, wakeRecovered, branch } = await prepareAcquireReconcile({ sessions, spec, resume, wakeEffects, report: (e, id) => deps.onError?.(e, { phase: "config", sessionId: id }), ...(internals?.sessionPlacement !== undefined ? { placement: internals.sessionPlacement } : {}), ...(() => { const g = durableParkGapFor(deps, spec); return g !== undefined ? { durableParkGap: g } : {}; })() });
327
- const sessionId = acquired.sessionId;
328
- await holdSessionLock?.(sessionId);
329
- const onceLedger = await loadAnnounceOnceLedger(session, resume?.seed.announcedListings, deps.onError);
330
- const hostTaskId = spec.taskId ?? sessionId;
331
320
  const delegation = effectiveDelegationFacts(internals, resume?.seed.isDelegatedChild);
332
321
  const toolLegs = [
333
322
  ...(delegation.isDelegatedChild ? ["delegated"] : []),
@@ -339,18 +328,25 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
339
328
  const toolCeiling = internals?.toolCeiling ?? resume?.seed.toolCeiling;
340
329
  const toolListsJudged = boundToolListsJudgment(internals?.toolListsJudged ?? resume?.seed.toolListsJudged, toolFaceLists);
341
330
  const toolFaceSnapshot = Object.freeze({
342
- selector: compileToolSelector([...(toolCeiling ?? []), Object.freeze({ ...(toolFaceLists.allow !== undefined ? { allow: toolFaceLists.allow } : {}), deny: toolFaceLists.exclude ?? [] })], toolLegs),
331
+ selector: readToolSelector({ layers: [...(toolCeiling ?? []), { ...(toolFaceLists.allow !== undefined ? { allow: toolFaceLists.allow } : {}), deny: toolFaceLists.exclude ?? [] }], where: ownListsWhereOf(ownToolLists), legs: toolLegs }),
343
332
  defer: toolFaceLists.defer,
344
333
  alwaysLoad: toolFaceLists.alwaysLoad,
345
334
  restoreGated: toolFaceLists.restoreGated,
346
335
  });
336
+ const toolCeilingRead = toolCeiling === undefined ? undefined : toolFaceSnapshot.selector.layers.slice(0, -1);
337
+ const extraBodyRefusal = judgeExtraBody(model.extraBody, model.id).refused;
338
+ if (extraBodyRefusal !== undefined)
339
+ throw Object.assign(new Error(extraBodyRefusal.sentence), { code: extraBodyRefusal.code, ...(extraBodyRefusal.field !== undefined ? { detail: { field: extraBodyRefusal.field } } : {}) });
340
+ for (const cap of MODEL_CAPABILITIES)
341
+ capabilityOf(model, cap);
342
+ const fileHistoryRequest = resolveFileHistoryRequest(spec, deps);
343
+ const { acquired, session, conflictRef, wakeRecovered, branch } = await prepareAcquireReconcile({ sessions, spec, resume, wakeEffects, report: (e, id) => deps.onError?.(e, { phase: "config", sessionId: id }), ...(legWrites !== undefined ? { legWrites } : {}), ...(internals?.sessionPlacement !== undefined ? { placement: internals.sessionPlacement } : {}), ...(() => { const g = durableParkGapFor(deps, spec); return g !== undefined ? { durableParkGap: g } : {}; })() });
344
+ const sessionId = acquired.sessionId;
345
+ await holdSessionLock?.(sessionId);
346
+ const onceLedger = await loadAnnounceOnceLedger(session, resume?.seed.announcedListings, deps.onError);
347
+ const hostTaskId = spec.taskId ?? sessionId;
347
348
  const placementRootResolved = (internals = restorePlacementRoot(internals, resume?.seed.placementRootSessionId))?.placementRoot ?? internals?.rootSessionId ?? sessionId;
348
- let effectiveCompModel = compModel;
349
- if (spec.compactionModel === undefined &&
350
- compModel !== undefined &&
351
- (await derivedRouteFallsBack({ seat: "compaction-summary", derived: compModel, primary: model, brain: deps.brain, getApiKeyAndHeaders: spec.getApiKeyAndHeaders, onNotice: deps.onNotice, sessionId, runId })).action === "fall_back") {
352
- effectiveCompModel = undefined;
353
- }
349
+ const effectiveCompModel = compactionSummaryIsDerived(spec.compactionModel !== undefined, compModel) ? await compactionSummaryFallback({ derived: compModel, primary: model, brain: deps.brain, getApiKeyAndHeaders: spec.getApiKeyAndHeaders, onNotice: deps.onNotice, sessionId, runId }) : compModel;
354
350
  warnCompactionWindowHazard(deps.tracer, spec, model, effectiveCompModel, hostTaskId, runnerSelf?.contextOverlayOf?.(resolvedRole.modelRef));
355
351
  const taskScope = internals?.registryScope ?? spec.principal ?? "default";
356
352
  const checkpointScope = checkpointScopeOf(spec, internals?.checkpointScope || resume?.seed.legScope);
@@ -625,7 +621,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
625
621
  const modelFileReaderSeat = {};
626
622
  const handsReadFaceInput = { permissionMode, denyRuleRows: effectivePathDenyRules, headLeads, writeTargetJudge: () => writeTargetJudgeRef.current, personRows, handsEnabled, executionEnv, taskRootFinal, taskRootCanonical, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGate, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), firstPartyOffload, roster, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes, reminderMark, reminderDisclosureCounts, modelFileReaderSeat, ...(trackFileEdit !== undefined ? { trackFileEdit } : {}), onFileEdited: noteFileEdited, harnessRef, toolProgressRef, toolOccurrences };
627
623
  const handsReadFace = handsEnabled ? await prepareHandsMount(handsReadFaceInput) : resolveHandsLessReadFace(handsReadFaceInput);
628
- const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, shellReadCheck, shellReadAdmission, additionalRootsCanonical, attachmentRootCanonical, readDenyMatcher, readRoots, pathTables, envHandToolNames, sealReadStateSeat } = handsReadFace;
624
+ const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, shellReadCheck, shellReadAdmission, shellReadLandings, additionalRootsCanonical, attachmentRootCanonical, readDenyMatcher, readRoots, pathTables, envHandToolNames, sealReadStateSeat } = handsReadFace;
629
625
  resolvedReadFace = handsReadFace.resolvedReadFace;
630
626
  resolvedWriteFace = handsReadFace.resolvedWriteFace;
631
627
  readDenyAdditionsNormalized = handsReadFace.readDenyAdditionsNormalized;
@@ -681,7 +677,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
681
677
  const { memoryBlock: memoryBlockWithProject, instructionSources, projectMemoryFact, projectInstructionContent, skillSpecs, skillSeatOf, skillsListing, sharedMemoryPairMounted, memoryEnginePairMounted } = projectContext;
682
678
  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, internals, thinking, ownedEnv, delegation, resolvedRole, taskRole: promptHost.role, mcp, roster, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical: (await readRoots.ready().then(readRoots)).filter((r) => !additionalRootsCanonical.includes(r)), sessionId, session, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}) });
683
679
  const advisor = await prepareAdvisor({ spec, advisorTool: doors.advisorTool, deps, model, roster, selector: toolFaceSnapshot.selector, session, onceLedger, rootLeg: !delegation.isDelegatedChild, sessionId, runId, sideCallBookRef, lastSentRequest: () => lastBrainContextRef.current, brainCallGuardrailMs });
684
- 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 });
680
+ judgeRunToolLists({ spec, tools: roster.tools, declaredPeers: { mcp: lockedPreflight.mcp, a2a: a2a.statuses }, own: { allow: toolFaceLists.allow, exclude: toolFaceLists.exclude }, selector: toolFaceSnapshot.selector, legs: toolLegs, judgedUpstream: toolListsJudged !== undefined, toldUpstream: internals?.ownToolLists !== undefined && ownToolLists !== undefined && toolCeiling !== undefined, ownBy: ownToolLists, onceLedger, sessionId });
685
681
  const { deferred, memoryBlock, toolSearch: toolSearchPolicy } = prepareDeferClassify({ spec, deps, roster, toolFaceSnapshot, handsEnabled, fullShellReachable, promptTraits, model, mcp, a2a, sharedMemoryPairMounted, memoryEnginePairMounted, memoryBlock: memoryBlockWithProject, memoryRecallSegment, onceLedger, sessionId });
686
682
  prepareMemoryEngineSession({ memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, ...(mountedMcpNow !== undefined ? { mountedMcp: mountedMcpNow } : {}), sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames, roster, contentOriginWrapRef });
687
683
  const { systemPromptSeat, renderWithDate, systemBlocks, promptManifest, promptIdentity, buildAssembleInputs, identityFor, adoptsCandidates, centerAdoptionRef } = await preparePromptAssembly({ session, deps, internals, resume, sugar: sugar.overlays, host: { ...(sugar.hostRole !== undefined ? { role: sugar.hostRole } : {}), ...(promptHost.form !== undefined ? { form: promptHost.form } : {}) }, binding: promptBinding, modBus: legMods.bus, signal: abortController.signal, featureFlags, mcpInstructionsBlock, memoryBlock, envFacts, promptTraits, tools, model, sessionId, onceLedger });
@@ -808,9 +804,9 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
808
804
  const stampCallTarget = attachmentRootCanonical === undefined ? undefined : legCallTargetStamp({ env: executionEnv, root: attachmentRootCanonical, cwd: () => handsCwdRef?.current, judgesPaths: () => parkLaneArmed || effectivePolicy?.pathRules !== undefined || basePolicyForResumeEdit?.pathRules !== undefined || permissionRuleLane !== undefined || skillSpecs.some((s) => compileSkillGrant(s, "model").rows.some((r) => r.compiled.kind === "path")) || allowedToolTables.request.holdsPathRows() || allowedToolTables.deployment.holdsPathRows(), leads: () => headLeads.resolve([...toolPolicyPathRules([effectivePolicy, basePolicyForResumeEdit, ...(inheritedParentConstraints ?? []).map((c) => c.policy)], legAnchors), ...bindPathRules(listPathRows().map((rule) => ({ parsed: rule, ruleText: rule.rule })), legAnchors)]) });
809
805
  const { askLane } = prepareAskLane({ gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, handsRoot: attachmentRootCanonical, stampCallTarget, advertisedWritableDirs, exemptRoots: legExemptRoots, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, grantBindingOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking: autoModeDenialTrackingRef, spec, deps, sessionId, runId, modBus: legMods.bus, notifyOwnHookCrash, grantReadRoot: handsReadFace.grantReadRoot });
810
806
  const inheritedAnchorRecords = chainAnchorRecords(chainTop, inheritedParentConstraints ?? []);
811
- const { saga } = prepareSuspendSaga({ gateMachineryActive, crossBoundary, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, skillScopesCheckpointSection: () => legMods.skillScopes.frozen(), reminderMark, handsCwdRef, handsRoot: attachmentRootCanonical, handsHome: attachmentRootCanonical !== undefined ? legAnchors.home : undefined, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, inheritedPathRuleAnchors: chainTop !== legAnchors ? inheritedAnchorRecords.pathRuleAnchors : undefined, inheritedPathRuleInstallations: inheritedAnchorRecords.pathRuleInstallations, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, checkpointScope, toolCeiling, toolListsJudged, ownToolLists, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
807
+ const { saga } = prepareSuspendSaga({ gateMachineryActive, crossBoundary, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, skillScopesCheckpointSection: () => legMods.skillScopes.frozen(), reminderMark, handsCwdRef, handsRoot: attachmentRootCanonical, handsHome: attachmentRootCanonical !== undefined ? legAnchors.home : undefined, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, inheritedPathRuleAnchors: chainTop !== legAnchors ? inheritedAnchorRecords.pathRuleAnchors : undefined, inheritedPathRuleInstallations: inheritedAnchorRecords.pathRuleInstallations, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, checkpointScope, toolCeiling: toolCeilingRead, toolListsJudged, ownToolLists, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
812
808
  const { suspendForResource, suspendForPlatformLimit, suspendForReview } = prepareBoundaryParks({ saga, spec, checkpointStore, checkpointScope, abortController, harness, session, sessions, sessionId, deps, priorLedger, maxSlices, maxSuspends, resourceTotal, priorSuspendCount, suspendChainBase, humanReviewRef, liveSpendRef, now, pausedRef, remoteEnvFailures, resourceSuspendEligible, durableSuspendInfraReady, incompleteSuspendAdapter });
813
- const { parkAsk } = prepareParkAsk({ askLane, saga, spec, deps, sessionId, checkpointStore, checkpointScope, toolRosterDeltas: rosterSeat, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, handsRoot: attachmentRootCanonical, stampCallTarget, advertisedWritableDirs, exemptRoots: legExemptRoots, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, toolMarkSources, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, ruleOffersOf, grantBindingOf, now, humanReviewRef, abortController, harness, pausedRef });
809
+ const { parkAsk } = prepareParkAsk({ askLane, saga, spec, deps, sessionId, checkpointStore, checkpointScope, toolRosterDeltas: rosterSeat, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, handsRoot: attachmentRootCanonical, stampCallTarget, shellReadLandings, advertisedWritableDirs, exemptRoots: legExemptRoots, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, toolMarkSources, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, ruleOffersOf, grantBindingOf, now, humanReviewRef, abortController, harness, pausedRef });
814
810
  const seatInputsFor = skillGateWiring({ tools, skillToolName: SKILL_TOOL_NAME, seatOf: skillSeatOf, mode: () => permissionMode.current, lane: skillGrantLane, onAllowed: (info) => emitTrace(deps.tracer, () => ({ kind: "permission.skill_allowed", version: 1, taskId: hostTaskId, ...info, entries: [...info.entries], ts: Date.now() })), allowEntries: { deploymentAllows: { ...allowEntryLanes.deployment, onAllowed: (info) => emitTrace(deps.tracer, () => ({ kind: "permission.allowed_tools_allowed", version: 1, taskId: hostTaskId, source: "deployment", ...info, entries: [...info.entries], ts: Date.now() })) }, requestAllows: { ...allowEntryLanes.request, onAllowed: (info) => emitTrace(deps.tracer, () => ({ kind: "permission.allowed_tools_allowed", version: 1, taskId: hostTaskId, source: "request", ...info, entries: [...info.entries], ts: Date.now() })) } } });
815
811
  const { approvedCallScreen } = prepareGateStations({ askLane, parkAsk, tools, toolRosterDeltas: rosterSeat, crossBoundaryCheck: crossBoundary.seat({ tools, roster: rosterSeat }), deps, toolCallGateArmedRef, effectivePolicy, modBus: legMods.bus, inheritedToolChecks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, toolOccurrences, batchHaltRef, blockedTracked, hookIdentity, reminderMark, hostTaskId, sessionId, handsCwdRef, stampCallTarget, readDenyInForce: (toolCallId) => ({ tiers: handsReadFace.readDenyBuiltinTiersActive, rows: [...readDenyAdditionsNormalized.map((e) => e.pattern), ...(pathTables?.forCall(toolCallId).ruleRows ?? handsReadFaceInput.denyRuleRows).filter((r) => r.faces.includes("read")).map((r) => r.rule)] }), hookEnvFace, writeProtectionCheck, shellReadCheck, readFace: () => resolvedReadFace, irreversibilityTier, reversibilityProbes, abortController, shellGatedTools, autoModeDecider: autoModeDeciderRef, autoModeDenialTracking: autoModeDenialTrackingRef, askRoute: { ...wiringManifest.ask, effective: askSeatEffective(wiringManifest) }, permissionMode, toolMarkSources, ...(deps.a2a?.isolatePeers === true ? { a2aIsolatePeers: true } : {}), ancestorArbitrations, runId, stopForDenialLimit, permissionRuleLane, seatInputsFor, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, frameSettlement });
816
812
  const postureFrameRef = { report: (err) => deps.onError?.(err, { phase: "degraded", sessionId }) };
@@ -818,7 +814,7 @@ export async function prepareTask(request, deps, sessions, resume, internals, ru
818
814
  const preparedHolder = {};
819
815
  const { cacheBreakDetector, cacheFingerprint, promptOverheadTokens, compactionRestore, normalizeAttachmentPath, isDedupStubResult, recentlyReadFiles, onCompactionApplied, detectExternalChanges, syntheticReadVerdict, consolidationWriteJudge, listBackgroundTasks, centerCompactionCandidate, effectiveReadFaceObserved, effectiveWriteFaceObserved, effectiveReadDenyObserved } = prepareTurnWiring({ deps, systemPromptSeat, harnessTools, fpRef, model, promptIdentityDigest: promptManifest.identity.artifact, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, readRoots, modelFileReader: modelFileReaderSeat.current, reminderMark, reminderDisclosureCounts, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, skillGrants: skillGrantLane, callerPolicy: installedToolPolicy, inheritedPolicies: (inheritedParentConstraints ?? []).map((c) => c.policy), persistedRuleLane: permissionRuleLane, ruleLaneFacts, personRowsBeyondRun, orgRuleLane: permissionRuleOrgLane, stampCallTarget, abortController, hostTaskId, taskScope, buildAssembleInputs, identityFor, adoptsCandidates, centerAdoptionRef, harnessRef, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder });
820
816
  await onceLedger.settle(session, announcedListingsRef);
821
- const buildPrepared = () => ({ harness, session, sessionId, runId, crossBoundary, ...(doors.hostFloor !== undefined ? { hostFloor: doors.hostFloor } : {}), registryAccess: { owner: hostTaskId, scope: taskScope }, reminderMark, reminderDisclosureCounts, fullShellReachable, approvalPosture: { get mode() { return permissionMode.current; }, askEffective: askSeatEffective(wiringManifest) }, ...(outputStyleFrame !== undefined ? { outputStyleFrame } : {}), permissionMode, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(mcpRedial !== undefined ? { mcpRedial } : {}), ...(a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, toolOccurrences, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(fileHistoryBoundary !== undefined ? { fileHistoryBoundary } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved, effectiveWriteFace: effectiveWriteFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(attachmentRootCanonical !== undefined ? { handsRoot: attachmentRootCanonical } : {}), ...(stampCallTarget !== undefined ? { stampCallTarget } : {}), toolProgressRef, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), exemptRoots: legExemptRoots, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, skillGrants: skillGrantLane, skillSpecs, ...(permissionRuleLane !== undefined ? { persistedRuleLane: permissionRuleLane } : {}), ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), consolidationWriteJudge, ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, endModeCeiling, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, promptIdentity, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, pausedRef, undeliveredContinuationRef, suspendProgressRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, workCutRef, brainCallGuardrailRef, gateStopRef, stopForDenialLimit, suspendForReview, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}), resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolRoster, toolRosterDeltas: rosterSeat, structuredProjector, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, lastSentRequest: () => lastBrainContextRef.current, ...(advisor.instruction !== undefined ? { advisorInstruction: advisor.instruction } : {}), ...(compactionRestore !== undefined ? { compactionRestore } : {}), recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, microCompact, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit && withheldDiagnosticsOf ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent, withheldOf: withheldDiagnosticsOf } } : {}), stopRequestedRef, announcedSnapshotRecovered: onceLedger.recovered, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(projectInstructionContent !== undefined ? { projectInstructionContent } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(mcpUnavailable ? { mcpUnavailable } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, frameReceipts: { pending: [], listingSnapshotOwed: false }, frameSettlement, ...(userAttachmentsSeat !== undefined ? { userAttachments: userAttachmentsSeat } : {}), attachmentDelivery: createAttachmentDelivery(), ...(modelFileReaderSeat.current !== undefined ? { modelFileReader: modelFileReaderSeat.current } : {}), syntheticReadVerdict, ...(peerLaneRefs.boundaryRound !== undefined ? { peerBoundaryRound: peerLaneRefs.boundaryRound } : {}), gitStatusRef, postureFrameRef, listBackgroundTasks, hookIdentity, modBus: legMods.bus, sideCallBookRef, ...(sessionBoxBound !== undefined ? { sessionBox: sessionBoxBound } : {}), ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}), ...(shellReadCheck !== undefined ? { shellReadCheck } : {}), ...(toolDisclosureSeat !== undefined ? { toolDisclosure: toolDisclosureSeat } : {}), ...(approvedCallScreen !== undefined ? { approvedCallScreen } : {}), ...(toolCallStationRef.current !== undefined ? { toolCallStation: toolCallStationRef.current } : {}) });
817
+ const buildPrepared = () => ({ harness, session, sessionId, runId, crossBoundary, ...(doors.hostFloor !== undefined ? { hostFloor: doors.hostFloor } : {}), registryAccess: { owner: hostTaskId, scope: taskScope }, reminderMark, reminderDisclosureCounts, fullShellReachable, approvalPosture: { get mode() { return permissionMode.current; }, askEffective: askSeatEffective(wiringManifest) }, ...(outputStyleFrame !== undefined ? { outputStyleFrame } : {}), permissionMode, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(mcpRedial !== undefined ? { mcpRedial } : {}), ...(a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, toolOccurrences, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(fileHistoryBoundary !== undefined ? { fileHistoryBoundary } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved, effectiveWriteFace: effectiveWriteFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(attachmentRootCanonical !== undefined ? { handsRoot: attachmentRootCanonical } : {}), ...(stampCallTarget !== undefined ? { stampCallTarget } : {}), toolProgressRef, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), exemptRoots: legExemptRoots, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, skillGrants: skillGrantLane, skillSpecs, ...(permissionRuleLane !== undefined ? { persistedRuleLane: permissionRuleLane } : {}), ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), consolidationWriteJudge, ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, endModeCeiling, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, promptIdentity, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, pausedRef, undeliveredContinuationRef, suspendProgressRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, workCutRef, brainCallGuardrailRef, gateStopRef, stopForDenialLimit, suspendForReview, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}), resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolRoster, toolRosterDeltas: rosterSeat, structuredProjector, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, lastSentRequest: () => lastBrainContextRef.current, ...(advisor.instruction !== undefined ? { advisorInstruction: advisor.instruction } : {}), ...(compactionRestore !== undefined ? { compactionRestore } : {}), recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, microCompact, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit && withheldDiagnosticsOf ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent, withheldOf: withheldDiagnosticsOf } } : {}), stopRequestedRef, announcedSnapshotRecovered: onceLedger.recovered, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(projectInstructionContent !== undefined ? { projectInstructionContent } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(mcpUnavailable ? { mcpUnavailable } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, frameReceipts: { pending: [], listingSnapshotOwed: false }, frameSettlement, ...(userAttachmentsSeat !== undefined ? { userAttachments: userAttachmentsSeat } : {}), attachmentDelivery: createAttachmentDelivery(), ...(modelFileReaderSeat.current !== undefined ? { modelFileReader: modelFileReaderSeat.current } : {}), syntheticReadVerdict, ...(peerLaneRefs.boundaryRound !== undefined ? { peerBoundaryRound: peerLaneRefs.boundaryRound } : {}), gitStatusRef, postureFrameRef, listBackgroundTasks, hookIdentity, modBus: legMods.bus, sideCallBookRef, ...(sessionBoxBound !== undefined ? { sessionBox: sessionBoxBound } : {}), ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}), ...(shellReadCheck !== undefined ? { shellReadCheck } : {}), ...(shellReadLandings !== undefined ? { shellReadLandings } : {}), ...(toolDisclosureSeat !== undefined ? { toolDisclosure: toolDisclosureSeat } : {}), ...(approvedCallScreen !== undefined ? { approvedCallScreen } : {}), ...(toolCallStationRef.current !== undefined ? { toolCallStation: toolCallStationRef.current } : {}) });
822
818
  refuseLateRosterChanges(callerRoster.roster);
823
819
  rollback.commit();
824
820
  commitModeSeats(abortController.signal);
@@ -114,6 +114,19 @@ export interface PrepareToolDisclosureMountResult {
114
114
  /** owned — the deferral census seat, minted ONLY when something is deferred; absent ⇒ no `tool_disclosure` frame at all. */
115
115
  toolDisclosureSeat?: ToolDisclosureSeat;
116
116
  }
117
+ /**
118
+ * The ToolSearch activation set a branch's landed compactions restate: the union of every engine compaction entry's
119
+ * snapshot (activation is monotonic in-session and every snapshot restates the then-current set, so the union is the
120
+ * latest complete restatement plus whatever older names a snapshotless window preserved); hook-authored entries are
121
+ * skipped like every sibling carrier reader (their details are not engine shape). Unfiltered — a leg intersects it
122
+ * with its own deferred registry. The one reading for a leg's seed and for a pass with no leg (the out-of-run
123
+ * compaction restates it, so a wake whose floor sits at the newest compaction still sees it).
124
+ */
125
+ export declare function compactionActivationSnapshot(branch: ReadonlyArray<{
126
+ readonly type: string;
127
+ readonly fromHook?: boolean;
128
+ readonly details?: unknown;
129
+ }>): string[];
117
130
  /** Test seam (mirrors `__resetToolModelGateAnnouncements`): never called by production code.
118
131
  * Re-arms BOTH arms (a WeakMap has no clear — it is re-minted). */
119
132
  export declare function __resetMaterializeEnvAnnouncements(): void;
@@ -16,6 +16,16 @@ function materializeEnvLedger(onNotice) {
16
16
  }
17
17
  return lines;
18
18
  }
19
+ export function compactionActivationSnapshot(branch) {
20
+ const names = new Set();
21
+ for (const entry of branch) {
22
+ if (entry.type !== "compaction" || entry.fromHook === true)
23
+ continue;
24
+ for (const n of readCompactionActiveTools(entry.details))
25
+ names.add(n);
26
+ }
27
+ return [...names];
28
+ }
19
29
  export function __resetMaterializeEnvAnnouncements() {
20
30
  announcedMaterializeEnvBySink = new WeakMap();
21
31
  announcedMaterializeEnvConsole.clear();
@@ -144,13 +154,9 @@ export async function prepareToolDisclosureMount(input) {
144
154
  if (deferred.has(n))
145
155
  activeTools.add(n);
146
156
  }
147
- for (const entry of await session.getBranch()) {
148
- if (entry.type !== "compaction" || entry.fromHook === true)
149
- continue;
150
- for (const n of readCompactionActiveTools(entry.details)) {
151
- if (deferred.has(n))
152
- activeTools.add(n);
153
- }
157
+ for (const n of compactionActivationSnapshot(await session.getBranch())) {
158
+ if (deferred.has(n))
159
+ activeTools.add(n);
154
160
  }
155
161
  if (resume) {
156
162
  for (const n of resume.seed.activeTools)
@@ -2,14 +2,11 @@ import type { RewindFilesRequest, RewindFilesResult } from "../file-history-stor
2
2
  import type { SessionStore } from "../session.js";
3
3
  import type { RunnerDeps } from "../types.js";
4
4
  import type { SessionReadFileStates } from "./session-read-file-states.js";
5
+ import { type SessionLockSeats } from "./session-verb-doors.js";
5
6
  /** What the Runner lends the rewind: its current deps, its session store, its read-state seats, and its lock. */
6
- export interface RewindFilesSeats {
7
+ export interface RewindFilesSeats extends SessionLockSeats {
7
8
  deps: RunnerDeps;
8
9
  sessions: SessionStore;
9
10
  readStates: SessionReadFileStates;
10
- /** Whether a leg of this Runner holds or awaits `sessionId`'s lock. */
11
- sessionBusy(sessionId: string): boolean;
12
- /** Take `sessionId`'s lock; called synchronously after `sessionBusy` answered false, so nothing slips in between. */
13
- takeSessionLock(sessionId: string): Promise<() => void>;
14
11
  }
15
12
  export declare function rewindSessionFiles(seats: RewindFilesSeats, request: RewindFilesRequest): Promise<RewindFilesResult>;
@@ -1,12 +1,10 @@
1
- import { types } from "node:util";
2
- import { isPlainRecord } from "../mods/kernel/receive.js";
3
1
  import { hasDestroy } from "../remote-env.js";
4
- import { readMember } from "../thrown-value.js";
5
2
  import { resolveDeploymentFileHistory, storeUnconfiguredRefusal } from "./file-history-request.js";
6
3
  import { prepareExecutionEnv } from "./prepare-execution-env.js";
7
4
  import { noBoundaryRefusal, settleFileHistoryRestore } from "./file-history-restore.js";
8
5
  import { adoptForkedFileHistory, resolveFileHistoryCoordinates } from "./prepare-file-history.js";
9
6
  import { createRollbackStack } from "./rollback-stack.js";
7
+ import { acquireExistingSession, claimIdleSession, readPlainRequest, shownValue } from "./session-verb-doors.js";
10
8
  import { settleTeardownLeg } from "./teardown-bounded.js";
11
9
  const REQUEST_KEYS = new Set(["sessionId", "to", "dryRun", "signal"]);
12
10
  export async function rewindSessionFiles(seats, request) {
@@ -15,12 +13,9 @@ export async function rewindSessionFiles(seats, request) {
15
13
  const { wiredSeat, fileHistoryStore, captureStore } = resolveDeploymentFileHistory(deps);
16
14
  if (fileHistoryStore === undefined)
17
15
  throw storeUnconfiguredRefusal(wiredSeat, req.to);
18
- if (seats.sessionBusy(req.sessionId))
19
- throw sessionBusyRefusal(req.sessionId, req.to);
20
- const lock = seats.takeSessionLock(req.sessionId);
21
- const release = await lock;
16
+ const release = await claimIdleSession(seats, req.sessionId, () => sessionBusyRefusal(req.sessionId, req.to));
22
17
  try {
23
- const session = await acquireExistingSession(seats.sessions, req.sessionId);
18
+ const session = await acquireExistingSession(seats.sessions, req.sessionId, "Runner.rewindFiles", "nothing was rewound");
24
19
  const report = (err) => {
25
20
  try {
26
21
  deps.onError?.(err, { phase: "config", sessionId: req.sessionId });
@@ -72,56 +67,19 @@ function screenRewindFilesRequest(request) {
72
67
  e.code = "rewind.invalid_spec";
73
68
  throw e;
74
69
  };
75
- if (typeof request !== "object" || request === null)
76
- return bad(`the request must be a plain object, got ${request === null ? "null" : typeof request}`);
77
- if (types.isProxy(request) || !isPlainRecord(request))
78
- return bad("the request must be a plain data object (not a Proxy, and with no prototype that could supply a member)");
79
- let descriptors;
80
- try {
81
- descriptors = Object.getOwnPropertyDescriptors(request);
82
- }
83
- catch {
84
- return bad("the request could not be read");
85
- }
86
- const keys = Reflect.ownKeys(descriptors);
87
- const unknown = keys.filter((k) => typeof k !== "string" || !REQUEST_KEYS.has(k));
88
- if (unknown.length > 0)
89
- return bad(`unknown key ${unknown.map((k) => JSON.stringify(String(k))).join(", ")}`);
90
- const read = {};
91
- for (const k of keys) {
92
- const d = descriptors[k];
93
- if (!("value" in d))
94
- return bad(`member ${JSON.stringify(k)} is an accessor, not a value`);
95
- read[k] = d.value;
96
- }
97
- const { sessionId, to, dryRun, signal } = read;
70
+ const { sessionId, to, dryRun, signal } = readPlainRequest(request, REQUEST_KEYS, bad);
98
71
  if (typeof sessionId !== "string" || sessionId === "")
99
- return bad(`sessionId must be a non-empty string, got ${shown(sessionId)}`);
72
+ return bad(`sessionId must be a non-empty string, got ${shownValue(sessionId)}`);
100
73
  if (typeof to !== "string" || to === "")
101
- return bad(`to must be a non-empty entry id, got ${shown(to)}`);
74
+ return bad(`to must be a non-empty entry id, got ${shownValue(to)}`);
102
75
  if (dryRun !== undefined && typeof dryRun !== "boolean")
103
- return bad(`dryRun must be a boolean when given, got ${shown(dryRun)}`);
76
+ return bad(`dryRun must be a boolean when given, got ${shownValue(dryRun)}`);
104
77
  if (signal !== undefined && !(signal instanceof AbortSignal))
105
- return bad(`signal must be an AbortSignal when given, got ${shown(signal)}`);
78
+ return bad(`signal must be an AbortSignal when given, got ${shownValue(signal)}`);
106
79
  return { sessionId, to, dryRun: dryRun === true, signal };
107
80
  }
108
- function shown(v) {
109
- return typeof v === "string" ? JSON.stringify(v.slice(0, 40)) : v === null || typeof v === "boolean" || typeof v === "number" ? String(v) : `a ${typeof v}`;
110
- }
111
- async function acquireExistingSession(sessions, sessionId) {
112
- try {
113
- return await sessions.acquire(sessionId, { requireExisting: true });
114
- }
115
- catch (err) {
116
- if (readMember(err, "code") !== "not_found")
117
- throw err;
118
- const e = new Error(`Runner.rewindFiles: session "${sessionId}" does not exist — nothing was rewound`);
119
- e.code = "resume.session_not_found";
120
- throw e;
121
- }
122
- }
123
81
  function sessionBusyRefusal(sessionId, target) {
124
- const e = new Error(`Runner.rewindFiles: a task is running or queued on session "${sessionId}" in this Runner — rewinding its files to entry "${target}" now would move them under that task, so nothing was rewound; retry once it has ended`);
82
+ const e = new Error(`Runner.rewindFiles: a task is running or queued on session "${sessionId}" in this Runner, or a write one of its tasks issued has not settled — rewinding its files to entry "${target}" now would move them under that work, so nothing was rewound; retry once it has ended and its writes have settled`);
125
83
  e.code = "rewind.session_busy";
126
84
  return e;
127
85
  }
@@ -69,7 +69,6 @@ export async function runLeg(input) {
69
69
  const walltimeExhaustedResume = effectiveTimeoutMs !== undefined && effectiveTimeoutMs <= 0;
70
70
  const approvalWords = approvalWordsOf(resume.outcome);
71
71
  const approvalFrames = owedApprovalWords(approvalWords, uuidv7());
72
- let approvalCommitted = false;
73
72
  prepared.undeliveredContinuationRef.current.parkedSteers.push(...approvalFrames);
74
73
  const resumeWindowRetryAfterMs = !walltimeExhaustedResume && prepared.usageGovernance !== undefined ? await prepared.usageGovernance.check(Date.now()) : undefined;
75
74
  if (resumeWindowRetryAfterMs !== undefined) {
@@ -244,10 +243,10 @@ export async function runLeg(input) {
244
243
  (steer.trusted ? formatHookFeedback(projected, prepared.reminderMark) : delimitUntrusted("supervisor steering message", projected));
245
244
  if (steer.trusted)
246
245
  engineSegments.push({ start, end: continuation.length });
247
- appliedEvents.push({
246
+ appliedEvents.push(() => ({
248
247
  ...buildAppliedHumanInputEvent({ carrier: source, source, sessionSeq: nextHumanInputSeq(prepared.harness), inputId: steer.inputId, actor: steer.actor, principal: spec.principal }),
249
248
  ...ident(),
250
- });
249
+ }));
251
250
  }
252
251
  if (approvalWords !== undefined)
253
252
  continuation = withApprovalWords(continuation, engineSegments, approvalWords);
@@ -259,8 +258,6 @@ export async function runLeg(input) {
259
258
  prepared.batchHaltRef.current = { rejectedToolCallId: pending.toolCallId };
260
259
  prepared.undeliveredContinuationRef.current = { parkedSteers: [...resumeFrames.map(({ entry }) => entry).filter((e) => !withheldSteerIds.has(e.inputId)), ...approvalFrames], orphanTasks };
261
260
  if (!prepared.abortController.signal.aborted) {
262
- if (resume !== undefined)
263
- resume.decisionDelivered = true;
264
261
  registerAdvisorReceipt(prepared, continuation);
265
262
  if (gitResumeDelivered !== undefined) {
266
263
  const delivered = gitResumeDelivered;
@@ -284,24 +281,15 @@ export async function runLeg(input) {
284
281
  prepared.frameReceipts.pending.push({ source: "posture", text: continuation, commit: () => undefined });
285
282
  if (unavailableResume !== undefined)
286
283
  prepared.frameReceipts.pending.push({ source: "mcp_unavailable", text: continuation, commit: () => void (settleMcpUnavailable(prepared, unavailableResume.entries), queue.push({ type: "steering_injected", source: "mcp_unavailable", preview: redactThenCut(unavailableResume.body, 220), ...ident() }), (rs.attach.attachmentsInjected += 1)) });
287
- if (approvalFrames.length > 0) {
288
- prepared.frameReceipts.pending.push({
289
- source: "approval_feedback",
290
- text: continuation,
291
- commit: () => {
292
- approvalCommitted = true;
293
- const seat = prepared.undeliveredContinuationRef.current;
294
- seat.parkedSteers = seat.parkedSteers.filter((f) => !approvalFrames.includes(f));
295
- },
296
- });
297
- }
298
284
  final = await withBrainSinks(() => prepared.harness.prompt(continuation, {
299
285
  engineSegments,
300
286
  settleUnansweredToolCalls: rejectionHalt !== undefined ? { halt: rejectionHalt } : {},
301
- onDelivered: () => {
302
- prepared.undeliveredContinuationRef.current = { parkedSteers: approvalCommitted ? [] : [...approvalFrames], orphanTasks: [] };
303
- for (const e of appliedEvents)
304
- queue.push(e);
287
+ onCommitted: () => {
288
+ if (resume !== undefined)
289
+ resume.decisionDelivered = true;
290
+ prepared.undeliveredContinuationRef.current = { parkedSteers: [], orphanTasks: [] };
291
+ for (const applied of appliedEvents)
292
+ queue.push(applied());
305
293
  },
306
294
  }));
307
295
  await flushGitMirror();
@@ -830,7 +818,8 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
830
818
  for (;;) {
831
819
  const { targetReading: _belts, ...unread } = beltReq();
832
820
  const targetReading = (await prepared.stampCallTarget?.(unread, prepared.abortController.signal))?.targetReading;
833
- const atExecution = judgeApprovalObject(pendingAction, { tool: mounted().entry, args: executedArgs, skills: prepared.skillSpecs, skillToolName: SKILL_TOOL_NAME, ...(humanRewrite !== undefined ? { decided: resolvedArgs } : {}), targetReading }, "execution");
821
+ const reads = prepared.shellReadLandings?.(pendingAction.toolCallId);
822
+ const atExecution = judgeApprovalObject(pendingAction, { tool: mounted().entry, args: executedArgs, skills: prepared.skillSpecs, skillToolName: SKILL_TOOL_NAME, ...(humanRewrite !== undefined ? { decided: resolvedArgs } : {}), targetReading, reads }, "execution");
834
823
  if (atExecution !== "match")
835
824
  return atExecution.disposition === "reopen" ? reopen(atExecution) : vetoApproval(atExecution);
836
825
  tool = mounted().tool;
@@ -19,6 +19,8 @@ export interface RunNotificationLaneInput<R> {
19
19
  taskIdRef: TaskIdRef | undefined;
20
20
  /** borrowed-readonly — the stream layer's session-lock verb, handed to prepare; absent when the spec named its session. */
21
21
  holdSessionLock: ((sessionId: string) => Promise<void>) | undefined;
22
+ /** borrowed-mutable (the Runner's) — this leg's view of the session write ledger, handed to prepare; the stream layer closes it at the leg's end. */
23
+ legWrites: import("./session-write-ledger.js").LegWrites;
22
24
  /** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError` in the park closure — after the run, on a swapped
23
25
  * catalog it is still the CURRENT sink; `models` and prepare's `deps` at the natural-snapshot pin); the one home of why it
24
26
  * is a seat and not a captured object is {@link RunnerDepsSeat}. */
@@ -8,7 +8,7 @@ export function runNotificationLane(input) {
8
8
  return obligations.run(() => runNotificationLaneAs(input, obligations));
9
9
  }
10
10
  async function runNotificationLaneAs(input, obligations) {
11
- const { spec, queue, resume, internals, taskIdRef, holdSessionLock, runner, self, sessions, sessionReadStates, sessionModeSeats, pendingSessionNotifications, prepareTask, next } = input;
11
+ const { spec, queue, resume, internals, taskIdRef, holdSessionLock, legWrites, runner, self, sessions, sessionReadStates, sessionModeSeats, pendingSessionNotifications, prepareTask, next } = input;
12
12
  const prepareResume = resume
13
13
  ? {
14
14
  leafId: resume.cp.leafId,
@@ -128,7 +128,7 @@ async function runNotificationLaneAs(input, obligations) {
128
128
  }
129
129
  return injectTaskNotification(notification, opts);
130
130
  },
131
- }, self, taskIdRef, holdSessionLock);
131
+ }, self, taskIdRef, holdSessionLock, legWrites);
132
132
  pendingSessionNotifications.bindSessionBox(prepared.sessionId, prepared.sessionBox);
133
133
  const notificationLane = {
134
134
  get harness() { return notificationHarness; }, set harness(h) { notificationHarness = h; },
@@ -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 { compactionPassReport, DEFAULT_COMPACTION_INSTRUCTIONS, isCompactionManualCancel, maybeCompact, mintCompactedEvent } from "../auto-compaction.js";
5
+ import { compactionFailureReason, 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";
@@ -11,7 +11,7 @@ import { compactionEnabled } from "../context-settings.js";
11
11
  import { compactionRestateOptions } from "./compaction-restate.js";
12
12
  import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
13
13
  import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
14
- import { asThrownError, thrownText } from "../thrown-value.js";
14
+ import { asThrownError } from "../thrown-value.js";
15
15
  export function runRecoveryLanes(input) {
16
16
  const { spec, prepared, queue, rs, ident, compactionBrain, compactionBreaker, windowSafetyOptions, callerStop, runner } = input;
17
17
  const runForcedCompactionPass = async (lane, turnSignal) => {
@@ -102,8 +102,7 @@ export function runRecoveryLanes(input) {
102
102
  }
103
103
  compactionBreaker.failures += 1;
104
104
  runner.deps.onError?.(asThrownError(err), { phase: "compaction", sessionId: prepared.sessionId });
105
- const msg = thrownText(err);
106
- queue.push({ type: "compaction_outcome", outcome: "failed", trigger: "forced", reason: msg.length > 512 ? `${msg.slice(0, 512)}…` : msg, ...passReport.end, ...ident() });
105
+ queue.push({ type: "compaction_outcome", outcome: "failed", trigger: "forced", reason: compactionFailureReason(err), ...passReport.end, ...ident() });
107
106
  return false;
108
107
  }
109
108
  };
@@ -5,7 +5,7 @@ import { adjudicateDerivedRoute, fallbackToPrimaryNotice, sameRouteIdentity } fr
5
5
  import { isDegenerateCutMessage } from "../../brain/terminal-cause.js";
6
6
  import { hasBackgroundShell, sweepRunBoundaryBackgroundShells } from "../background-shell.js";
7
7
  import { resolveCheckpointStore } from "../checkpoint-store.js";
8
- import { reopenReasonOf, reopenedUnstartedSentence, resumeStartupCauseOf } from "../resume-startup-cause.js";
8
+ import { compensateUnstarted, reopenReasonOf, resumeStartupCauseOf, unstartedRowSentence } from "../resume-startup-cause.js";
9
9
  import { classicEventBase, observeClassic } from "../mods/stations.js";
10
10
  import { modelCostToPricing } from "../pricing.js";
11
11
  import { hasDestroy, isIsolated } from "../remote-env.js";
@@ -139,17 +139,11 @@ export async function runSettleAndTeardown(input) {
139
139
  resume.pendingActionStarted !== true &&
140
140
  result.terminal.kind !== "completed" &&
141
141
  result.terminal.kind !== "paused" &&
142
- !(resumeDecisionWasNegative(resume) && resume.decisionDelivered === true) &&
143
- resume.onEnvRestoreFailed !== undefined) {
142
+ !(resumeDecisionWasNegative(resume) && resume.decisionDelivered === true)) {
144
143
  const reopenReason = reopenReasonOf(resumeStartupCauseOf(result.terminal.kind === "failed" ? result.terminal.code : undefined));
145
- try {
146
- await resume.onEnvRestoreFailed(reopenReason);
147
- rowReturned = true;
148
- amendTerminal(result, "resume.reopened_unstarted", (m) => `${m ?? "the resume leg did not complete"} — ${reopenedUnstartedSentence(reopenReason)}`);
149
- }
150
- catch {
151
- amendTerminal(result, "resume.reopen_failed_unstarted", (m) => `${m ?? "the resume leg did not complete"} — the approved action never started, and reopening the checkpoint FAILED: its state is unprovable from here. Re-read it before deciding; do NOT issue a fresh approval on the assumption the old one is dead`);
152
- }
144
+ const row = await compensateUnstarted(resume.reopenUnstarted, reopenReason);
145
+ rowReturned = row.kind === "reopened";
146
+ amendTerminal(result, rowReturned ? "resume.reopened_unstarted" : "resume.reopen_failed_unstarted", (m) => `${m ?? "the resume leg did not complete"} — ${unstartedRowSentence(row)}`);
153
147
  }
154
148
  settleOwedUserInput(owedUserInput, rowReturned, { taskId: spec.taskId ?? prepared.sessionId, sessionId: prepared.sessionId, runId: prepared.runId, parent: parentLegIds(internals) }, runner.deps.onNotice);
155
149
  prepared.sealReadStateSeat?.(ownCommittedTailRef.current);
@@ -1,4 +1,4 @@
1
- import { compactionPassReport, DEFAULT_COMPACTION_INSTRUCTIONS, isCompactionManualCancel, maybeCompact } from "../auto-compaction.js";
1
+ import { compactionFailureReason, compactionPassReport, DEFAULT_COMPACTION_INSTRUCTIONS, isCompactionManualCancel, maybeCompact } from "../auto-compaction.js";
2
2
  import { eventDefaultOn } from "../../prompt-assembly/event-registry.js";
3
3
  import { appendInterruptionMarker, reconcileInterruptedSession } from "../session-reconcile.js";
4
4
  import { emitTrace } from "../trace.js";
@@ -11,7 +11,7 @@ import { compactionRestateOptions } from "./compaction-restate.js";
11
11
  import { MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
12
12
  import { emitSettled, reconciledEnd } from "./tool-end-body.js";
13
13
  import { isApprovalWordsFrame } from "./approval-feedback.js";
14
- import { asThrownError, thrownText } from "../thrown-value.js";
14
+ import { asThrownError } from "../thrown-value.js";
15
15
  export async function runTerminalAdoption(input) {
16
16
  const { spec, queue, prepared, rs, stats, ident, emitCommitted, startedToolCallIds, toolLabels, timeout, compactionBrain, compactionBreaker, windowSafetyOptions, undrainedUserAtEnd, userInputLostAtEnd, final, abortedLive, userInterruptedLive, callerStop, runner, sessions, next } = input;
17
17
  let { threw } = input;
@@ -185,8 +185,7 @@ async function finish(spec, prepared, opts, runner, sessions) {
185
185
  opts?.onCompactionOutcome?.("mooted", "cancelled", opts.passReport.end);
186
186
  }
187
187
  else {
188
- const failMsg = thrownText(err);
189
- const failReason = failMsg.length > 512 ? `${failMsg.slice(0, 512)}…` : failMsg;
188
+ const failReason = compactionFailureReason(err);
190
189
  emitTrace(opts?.telemetry?.tracer ?? spec.tracer ?? runner.deps.tracer, () => ({
191
190
  kind: "compaction.failed",
192
191
  version: 1,
@@ -1,7 +1,7 @@
1
1
  import { compactionKindOf } from "../task-notification.js";
2
2
  import { mintSystemReminder } from "../reminder-mint.js";
3
3
  import { eventDefaultOn } from "../../prompt-assembly/event-registry.js";
4
- import { compactionPassReport, DEFAULT_COMPACTION_INSTRUCTIONS, isCompactionManualCancel, maybeCompact, mintCompactedEvent, nextTrimForceBackoff, recordCompactionAndCheckRapidRefill } from "../auto-compaction.js";
4
+ import { compactionFailureReason, compactionPassReport, DEFAULT_COMPACTION_INSTRUCTIONS, isCompactionManualCancel, manualCompactOutcomeOf, maybeCompact, mintCompactedEvent, nextTrimForceBackoff, recordCompactionAndCheckRapidRefill } from "../auto-compaction.js";
5
5
  import { emitTrace } from "../trace.js";
6
6
  import { redactThenCut } from "../../agents/subagent-steps.js";
7
7
  import { ATTACHMENT_BYTE_CAP, CHANGED_FILES_MAX, TOTAL_TOKENS_REMINDER_DEFAULT_MODE, attachmentEnvelopeTags, clipToBytes, collectDateChange, collectDueAttachments, collectInstructionsChange, commitAgentListing, commitInstructionsChange, commitSkillsListing, isIntactSource, rebaseCadenceWindows, renderAgentListingFrame, renderMcpDroppedTools, renderMcpInstructionsDelta, selectMcpDroppedBatch, renderSkillsListingFrame, renderToolsDelta } from "./turn-attachments.js";
@@ -18,7 +18,6 @@ import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_C
18
18
  import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
19
19
  import { contextUsageSections } from "../../prompt-assembly/section-usage.js";
20
20
  import { asThrownError } from "../thrown-value.js";
21
- import { egressThrownText } from "../untrusted-egress.js";
22
21
  const BATCH_CONTEXT_MIN_KEEP_BYTES = 160;
23
22
  const BATCH_TRUNCATION_MARKER = "\n…[truncated]";
24
23
  export function createTurnBoundary(input) {
@@ -614,7 +613,7 @@ export function createTurnBoundary(input) {
614
613
  ts: Date.now(),
615
614
  }));
616
615
  }
617
- manualOutcome = comp.compacted ? "compacted" : comp.blocked ? "blocked" : comp.disabled ? "disabled" : "noop";
616
+ manualOutcome = manualCompactOutcomeOf(comp);
618
617
  if (forceManual && !comp.compacted && !comp.blocked) {
619
618
  if (comp.disabled) {
620
619
  emitTrace(rs.telemetry.tracer, () => ({ kind: "compaction.disabled", version: 1, taskId: rs.telemetry.taskId, ts: Date.now() }));
@@ -671,8 +670,7 @@ export function createTurnBoundary(input) {
671
670
  else if (!prepared.abortController.signal.aborted) {
672
671
  compactionBreaker.failures += 1;
673
672
  runnerHooks.onError?.(err, { phase: "compaction", sessionId: prepared.sessionId });
674
- const msg = egressThrownText("same-principal", err);
675
- const failReason = msg.length > 512 ? `${msg.slice(0, 512)}…` : msg;
673
+ const failReason = compactionFailureReason(err);
676
674
  emitTrace(rs.telemetry.tracer, () => ({
677
675
  kind: "compaction.failed",
678
676
  version: 1,
@@ -8,6 +8,7 @@ import type { AgentDefinition, ModelRef, ModelRoles, RunnerDeps, TaskEvent, Task
8
8
  import { type ContextSettings, type ContextWindowOverlay } from "../context-settings.js";
9
9
  import type { ResumeRun, ResumeTaskConfig, RunInternals, RunnerSelfSeat } from "./contracts.js";
10
10
  export type { ResumeTaskConfig } from "./contracts.js";
11
+ import type { CompactSessionRequest, CompactSessionResult } from "../auto-compaction.js";
11
12
  import type { RewindFilesRequest, RewindFilesResult } from "../file-history-store.js";
12
13
  /**
13
14
  * A stateless task runner. Holds shared deps (the external brain, model catalog) and an
@@ -18,6 +19,10 @@ export declare class Runner implements RunnerSelfSeat {
18
19
  readonly sessions: SessionStore;
19
20
  /** Per-sessionId serialization so two tasks never mutate one session concurrently. */
20
21
  private sessionLocks;
22
+ /** The lock's tail: the session writes this Runner's legs issued that have not settled — a session's next holder starts after them. */
23
+ private readonly sessionWrites;
24
+ /** The session-lock seats every out-of-run verb (`rewindFiles`, `compactSession`) is lent — ONE reading of "busy": a leg holds or awaits the lock, or a write issued to the session has not settled. */
25
+ private readonly verbLockSeats;
21
26
  /** Per-session read-file-state seats (CC parity: readFileState is session-scoped;
22
27
  * sema's map stays per-task, so the session scope lives here). A bounded CACHE, never an
23
28
  * authority: a durable resume's checkpoint seed wins on its leg, and a miss (cross-process,
@@ -134,8 +139,10 @@ export declare class Runner implements RunnerSelfSeat {
134
139
  * the same model resolution as tasks, returns real usage/model. No session, no tool execution, no
135
140
  * policy gate, no accounting — caller-trusted. */
136
141
  sideQuery(spec: SideQuerySpec): Promise<SideQueryResult>;
137
- /** The out-of-run code-only rewind, no model call and no session entry — the contract is {@link rewindSessionFiles}'s (refused while a leg of this Runner holds or awaits the session's lock). */
142
+ /** The out-of-run code-only rewind, no model call and no session entry — the contract is {@link rewindSessionFiles}'s (refused while a leg of this Runner holds or awaits the session's lock, or a write issued to it has not settled). */
138
143
  rewindFiles(request: RewindFilesRequest): Promise<RewindFilesResult>;
144
+ /** The out-of-run manual compaction, no run and no user turn — the contract is {@link compactIdleSession}'s (the one pass every lane runs; refused while a leg of this Runner holds or awaits the session's lock, or a write issued to it has not settled). */
145
+ compactSession(request: CompactSessionRequest): Promise<CompactSessionResult>;
139
146
  /** Run a task and stream live events; await `.result()` for the final TaskResult. `resume` (internal)
140
147
  * drives a durable resume through the same loop instead of a fresh objective prompt.
141
148
  * `internals` (internal) is a TRUSTED run-scoped channel for live per-task state the