@sema-agent/core 7.45.0 → 7.46.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 (127) hide show
  1. package/CHANGELOG.md +246 -1
  2. package/dist/agents/extra-tool-names.d.ts +65 -0
  3. package/dist/agents/extra-tool-names.js +124 -0
  4. package/dist/agents/subagent.d.ts +17 -5
  5. package/dist/agents/subagent.js +33 -25
  6. package/dist/agents/tool-filter.d.ts +17 -1
  7. package/dist/agents/tool-filter.js +7 -0
  8. package/dist/core/agent-config-dir.d.ts +20 -0
  9. package/dist/core/agent-config-dir.js +49 -0
  10. package/dist/core/allow-entry.d.ts +5 -3
  11. package/dist/core/allow-entry.js +3 -1
  12. package/dist/core/ask-origin.js +1 -1
  13. package/dist/core/checkpoint-store.d.ts +39 -2
  14. package/dist/core/effective-path-target.d.ts +136 -4
  15. package/dist/core/effective-path-target.js +110 -2
  16. package/dist/core/engine-notice.d.ts +5 -0
  17. package/dist/core/gate-fold.js +3 -0
  18. package/dist/core/gate-lanes.js +9 -3
  19. package/dist/core/governance-codes.d.ts +3 -1
  20. package/dist/core/governance-codes.js +3 -0
  21. package/dist/core/hooks.d.ts +3 -0
  22. package/dist/core/path-rule-binding.d.ts +65 -0
  23. package/dist/core/path-rule-binding.js +99 -0
  24. package/dist/core/permission-rule-model.d.ts +47 -18
  25. package/dist/core/permission-rule-model.js +38 -42
  26. package/dist/core/permission-rule-provider.d.ts +7 -0
  27. package/dist/core/permission-rule-provider.js +10 -3
  28. package/dist/core/permission-rule-store.d.ts +8 -0
  29. package/dist/core/permission-rule-store.js +6 -2
  30. package/dist/core/permission-rule-sync.js +2 -2
  31. package/dist/core/permission-rules.d.ts +22 -40
  32. package/dist/core/permission-rules.js +50 -43
  33. package/dist/core/runner/child-tree.d.ts +97 -0
  34. package/dist/core/runner/child-tree.js +104 -0
  35. package/dist/core/runner/construction-doors.d.ts +5 -0
  36. package/dist/core/runner/construction-doors.js +6 -0
  37. package/dist/core/runner/contracts.d.ts +46 -0
  38. package/dist/core/runner/permission-rule-lanes.d.ts +34 -25
  39. package/dist/core/runner/permission-rule-lanes.js +18 -12
  40. package/dist/core/runner/persisted-path-rows.d.ts +31 -7
  41. package/dist/core/runner/persisted-path-rows.js +31 -12
  42. package/dist/core/runner/prepare-ask-lane.d.ts +4 -0
  43. package/dist/core/runner/prepare-ask-lane.js +4 -2
  44. package/dist/core/runner/prepare-execution-env.d.ts +5 -2
  45. package/dist/core/runner/prepare-execution-env.js +10 -3
  46. package/dist/core/runner/prepare-gate-stations.d.ts +3 -0
  47. package/dist/core/runner/prepare-gate-stations.js +2 -1
  48. package/dist/core/runner/prepare-hands-readface.d.ts +8 -4
  49. package/dist/core/runner/prepare-hands-readface.js +6 -6
  50. package/dist/core/runner/prepare-inherited-gate.d.ts +8 -1
  51. package/dist/core/runner/prepare-inherited-gate.js +8 -2
  52. package/dist/core/runner/prepare-park-ask.d.ts +3 -0
  53. package/dist/core/runner/prepare-park-ask.js +5 -3
  54. package/dist/core/runner/prepare-policy-chain.d.ts +14 -2
  55. package/dist/core/runner/prepare-policy-chain.js +11 -4
  56. package/dist/core/runner/prepare-suspend-saga.d.ts +10 -0
  57. package/dist/core/runner/prepare-suspend-saga.js +7 -1
  58. package/dist/core/runner/prepare-task.js +37 -18
  59. package/dist/core/runner/prepare-turn-wiring.d.ts +2 -0
  60. package/dist/core/runner/prepare-turn-wiring.js +2 -1
  61. package/dist/core/runner/prepare-workspace-restore.d.ts +3 -0
  62. package/dist/core/runner/prepare-workspace-restore.js +1 -0
  63. package/dist/core/runner/resume-apply.js +17 -3
  64. package/dist/core/runner/resume-checkpoint-screen.js +13 -0
  65. package/dist/core/runner/run-leg.js +5 -1
  66. package/dist/core/runner/runtask.js +2 -2
  67. package/dist/core/runner/sub-agent-deny-lists.d.ts +1 -1
  68. package/dist/core/runner/write-protection-station.d.ts +3 -2
  69. package/dist/core/runner/write-protection-station.js +1 -0
  70. package/dist/core/runner-deps.d.ts +14 -0
  71. package/dist/core/sensitive-path-policy.d.ts +8 -0
  72. package/dist/core/sensitive-path-policy.js +18 -2
  73. package/dist/core/shell-wrapper-projection.d.ts +11 -0
  74. package/dist/core/shell-wrapper-projection.js +56 -0
  75. package/dist/core/shell-wrapper-table.d.ts +144 -34
  76. package/dist/core/shell-wrapper-table.js +40 -20
  77. package/dist/core/synthetic-read-verdict.d.ts +3 -0
  78. package/dist/core/synthetic-read-verdict.js +3 -1
  79. package/dist/core/tool-catalog-entries.d.ts +21 -0
  80. package/dist/core/tool-catalog-entries.js +9 -0
  81. package/dist/core/tool-policy.d.ts +30 -8
  82. package/dist/core/tool-policy.js +9 -7
  83. package/dist/core/tool-spec.d.ts +3 -2
  84. package/dist/core/write-protect.d.ts +4 -0
  85. package/dist/core/write-protect.js +30 -9
  86. package/dist/index.d.ts +5 -3
  87. package/dist/index.js +4 -2
  88. package/dist/orchestration/run-spec.js +8 -7
  89. package/dist/orchestration/workflow.js +1 -1
  90. package/dist/shell/lex.d.ts +7 -0
  91. package/dist/shell/lex.js +17 -0
  92. package/dist/tools/fs/bash-program-position.d.ts +8 -87
  93. package/dist/tools/fs/bash-program-position.js +33 -69
  94. package/dist/tools/fs/bash-readonly-classifier.d.ts +17 -444
  95. package/dist/tools/fs/bash-readonly-classifier.js +169 -1225
  96. package/dist/tools/fs/index.d.ts +3 -2
  97. package/dist/tools/fs/program-read-model.d.ts +694 -0
  98. package/dist/tools/fs/program-read-model.js +1252 -0
  99. package/dist/tools/fs/program-read-model.rows.d.ts +18 -0
  100. package/dist/tools/fs/program-read-model.rows.js +613 -0
  101. package/dist/tools/fs/read-deny-home.d.ts +19 -1
  102. package/dist/tools/fs/read-deny-home.js +62 -24
  103. package/dist/tools/fs/read-deny.d.ts +54 -14
  104. package/dist/tools/fs/read-deny.js +104 -50
  105. package/dist/tools/fs/removal-targets.d.ts +7 -6
  106. package/dist/tools/fs/removal-targets.js +22 -22
  107. package/dist/tools/fs/safety.d.ts +3 -0
  108. package/dist/tools/fs/safety.js +10 -3
  109. package/dist/tools/fs/shell-read-argv.d.ts +85 -0
  110. package/dist/tools/fs/shell-read-argv.js +386 -0
  111. package/dist/tools/fs/shell-read-bindings.d.ts +273 -0
  112. package/dist/tools/fs/shell-read-bindings.js +746 -0
  113. package/dist/tools/fs/shell-read-check.js +23 -15
  114. package/dist/tools/fs/shell-read-establish.js +79 -5
  115. package/dist/tools/fs/shell-read-judge.d.ts +11 -1
  116. package/dist/tools/fs/shell-read-judge.js +9 -1
  117. package/dist/tools/fs/shell-read-plan.d.ts +31 -7
  118. package/dist/tools/fs/shell-read-plan.js +299 -393
  119. package/dist/tools/fs/shell-read-word.d.ts +29 -26
  120. package/dist/tools/fs/shell-read-word.js +30 -38
  121. package/dist/tools/fs/shell-read-write-targets.d.ts +15 -64
  122. package/dist/tools/fs/shell-read-write-targets.js +83 -136
  123. package/dist/tools/fs/shell-reentry-text.d.ts +38 -6
  124. package/dist/tools/fs/shell-reentry-text.js +90 -53
  125. package/package.json +1 -1
  126. package/test/export-surface.snapshot.json +17 -3
  127. package/wire-changes/core@7.46.0.json +1522 -0
@@ -1,3 +1,4 @@
1
+ import { withArgsReading } from "../effective-path-target.js";
1
2
  import { policyAskClassOf } from "../ask-class.js";
2
3
  import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
3
4
  import { classifierUnavailableSeat } from "./classifier-ladder.js";
@@ -24,7 +25,7 @@ import { createLiveSessionRules, createSessionRulePolicy } from "./session-rule-
24
25
  import { thrownText } from "../thrown-value.js";
25
26
  import { heldBy, heldValues, seatOf, wireOf } from "../tool-name-readings.js";
26
27
  export async function preparePolicyChain(input) {
27
- const { spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, additionalRootsCanonical, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, toolMarkSources, envHandToolNames, handsCwdRef, readDenyMatcher, announceRuleStoreSkipped, questionToolMounted, runtimeCaps, inheritedAncestorRules, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, skillGrants, skillSpecs, allowedToolTables, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, readFace, permissionMode, scratchpadDir, toolRosterDeltas, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef } = input;
28
+ const { spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, additionalRootsCanonical, executionEnv, lockedPreflight, pathRuleAnchors, headLeads, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, toolMarkSources, envHandToolNames, handsCwdRef, readDenyMatcher, announceRuleStoreSkipped, announceRuleRowsDropped, questionToolMounted, runtimeCaps, inheritedAncestorRules, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, skillGrants, skillSpecs, allowedToolTables, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, readFace, permissionMode, scratchpadDir, toolRosterDeltas, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef } = input;
28
29
  const ancestorArbitrations = new Map();
29
30
  const arbitrateInherited = (ask, toolCallId, judged) => {
30
31
  const verdict = arbitrateByMode(permissionMode.current, judged.classification, { origin: judged.origin, ...askMandateMember(ancestorFacts(judged.ask.action === "ask" ? judged.ask : undefined)) });
@@ -315,7 +316,7 @@ export async function preparePolicyChain(input) {
315
316
  };
316
317
  };
317
318
  const inheritedAskEvidence = inheritedAskRuleEvidence(deps.permissionRuleStore);
318
- const listFacts = { root: taskRootFinal, sessionId, liveCwd: () => handsCwdRef?.current, home: executionEnv.homeDir };
319
+ const listFacts = { root: taskRootFinal, sessionId, liveCwd: () => handsCwdRef?.current, anchors: pathRuleAnchors.leg };
319
320
  const skillGrantLane = skillGrants.lane(listFacts);
320
321
  const allowEntryLanes = { request: allowedToolTables.request.lane(listFacts), deployment: allowedToolTables.deployment.lane(listFacts) };
321
322
  const { personal: permissionRuleLane, org: permissionRuleOrgLane } = createPermissionRuleLanes({
@@ -324,6 +325,9 @@ export async function preparePolicyChain(input) {
324
325
  principal: spec.principal,
325
326
  sessionId,
326
327
  root: taskRootFinal,
328
+ rootCanonical: pathRuleAnchors.leg.root,
329
+ chainTop: pathRuleAnchors.chainTop,
330
+ leads: headLeads,
327
331
  liveCwd: () => handsCwdRef?.current,
328
332
  home: executionEnv.homeDir,
329
333
  questionToolMounted,
@@ -331,6 +335,7 @@ export async function preparePolicyChain(input) {
331
335
  onRevisionDefect: (message) => deps.onError?.(new Error(message), { phase: "config", sessionId }),
332
336
  onDisclosure: (message) => emitTrace(deps.tracer, () => ({ kind: "permission.rule_store_unreadable", version: 1, taskId: hostTaskId, message, ts: Date.now() })),
333
337
  onStoreUnreadable: announceRuleStoreSkipped,
338
+ onRowsDropped: announceRuleRowsDropped,
334
339
  signal: abortController.signal,
335
340
  stripsAllow: (rule, req) => permissionMode.current === "auto" && autoStrippedRule(rule, req),
336
341
  });
@@ -366,7 +371,8 @@ export async function preparePolicyChain(input) {
366
371
  }
367
372
  let re;
368
373
  try {
369
- re = refuseOutOfContractDecision(await pol.check({ ...creq, args: editArgs }, csignal ?? abortController.signal));
374
+ const editReq = withArgsReading(creq, editArgs, csignal ?? abortController.signal);
375
+ re = refuseOutOfContractDecision(await pol.check(editReq !== undefined ? await editReq : { ...creq, args: editArgs }, csignal ?? abortController.signal));
370
376
  }
371
377
  catch (err) {
372
378
  return vetoed({
@@ -646,7 +652,8 @@ export async function preparePolicyChain(input) {
646
652
  }
647
653
  }
648
654
  const recheckLayers = [...recheckPrefix, ...postEmitterSameInstanceAdapters];
649
- const finalReq = { ...req, args: decision.updatedInput };
655
+ const finalRead = withArgsReading(req, decision.updatedInput, signal);
656
+ const finalReq = finalRead !== undefined ? await finalRead : { ...req, args: decision.updatedInput };
650
657
  let asked;
651
658
  const revalidated = {};
652
659
  let restated;
@@ -118,6 +118,10 @@ export interface PrepareSuspendSagaInput {
118
118
  reminderMark: string;
119
119
  /** borrowed-readonly — the hand's live tracked cwd, or undefined; `current` is read at mint time. Not written here. */
120
120
  handsCwdRef: CwdRef | undefined;
121
+ /** borrowed-readonly — the hands' root (the `root` every adjudicated request of the leg carries), or undefined (hands-less). */
122
+ handsRoot: string | undefined;
123
+ /** borrowed-readonly — the home the leg's caller policies installed `~/` at (absolute), or undefined. */
124
+ handsHome: string | undefined;
121
125
  /** borrowed-readonly — the active EnterWorktree session seat, or undefined; `current` is read at mint time. */
122
126
  worktreeSessionRef: Prepared["worktreeSessionRef"];
123
127
  /** borrowed-readonly — the resumed leg's not-yet-delivered continuation content; its orphan obituaries fold into this
@@ -140,6 +144,12 @@ export interface PrepareSuspendSagaInput {
140
144
  permissionMode: PermissionModeController;
141
145
  /** borrowed-readonly — the inherited admitted org scopes, or undefined (copied onto the row). */
142
146
  inheritedAdmittedOrgScopes: readonly string[] | undefined;
147
+ /** borrowed-readonly — the chain's top leg's anchors this leg carries (absent on a leg that is its own top): recorded on
148
+ * the data half so a resumed child judges the person's global / session rows and `~/` rows where its chain did. */
149
+ inheritedPathRuleAnchors: InheritedGate["pathRuleAnchors"];
150
+ /** borrowed-readonly — where each parent constraint this leg runs under was installed (position for position), recorded on
151
+ * the data half so a resume that re-supplies the chain uninstalled installs each entry there. */
152
+ inheritedPathRuleInstallations: InheritedGate["pathRuleInstallations"];
143
153
  /** borrowed-readonly — this leg's OWN org verdict seat; `current` is read at mint time. Not written here. */
144
154
  ownOrgVerdictRef: {
145
155
  current: OwnOrgAdmissionVerdict | undefined;
@@ -79,7 +79,7 @@ function stampPlacementRootSessionId(placementRootResolved) {
79
79
  return placementValueOrAbsent(placementRootResolved);
80
80
  }
81
81
  export function prepareSuspendSaga(input) {
82
- const { gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter } = input;
82
+ const { gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, reminderMark, handsCwdRef, handsRoot, handsHome, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, inheritedPathRuleAnchors, inheritedPathRuleInstallations, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter } = input;
83
83
  if (!gateMachineryActive)
84
84
  return { saga: undefined };
85
85
  const inFlightSpendMicroUsd = () => {
@@ -115,6 +115,8 @@ export function prepareSuspendSaga(input) {
115
115
  repairBundle: repairBundleForCheckpoint(parkedSpendMicroUsd),
116
116
  workspaceHandle,
117
117
  handsCwd: handsCwdRef?.current,
118
+ handsRoot,
119
+ handsHome,
118
120
  activeWorktree: worktreeSessionRef?.current ? { ...worktreeSessionRef.current } : undefined,
119
121
  runningBackgroundTasks: (() => {
120
122
  const live = defaultTaskRegistry
@@ -142,6 +144,8 @@ export function prepareSuspendSaga(input) {
142
144
  inheritedShellGate !== undefined ||
143
145
  modeRecorded ||
144
146
  inheritedAdmittedOrgScopes !== undefined ||
147
+ inheritedPathRuleAnchors !== undefined ||
148
+ inheritedPathRuleInstallations !== undefined ||
145
149
  ownOrgVerdictRef.current !== undefined ||
146
150
  orgGovernedProvenance ||
147
151
  requiresParentConstraint
@@ -151,6 +155,8 @@ export function prepareSuspendSaga(input) {
151
155
  ...(modeRecorded ? { permissionMode: declaredMode } : {}),
152
156
  ...(permissionMode.prePlanMode !== undefined ? { prePlanMode: permissionMode.prePlanMode } : {}),
153
157
  ...(inheritedAdmittedOrgScopes !== undefined ? { admittedOrgScopes: [...inheritedAdmittedOrgScopes] } : {}),
158
+ ...(inheritedPathRuleAnchors !== undefined ? { pathRuleAnchors: { ...inheritedPathRuleAnchors } } : {}),
159
+ ...(inheritedPathRuleInstallations !== undefined ? { pathRuleInstallations: inheritedPathRuleInstallations.map((r) => (r === null ? null : { ...r })) } : {}),
154
160
  ...(ownOrgVerdictRef.current !== undefined
155
161
  ? { ownAdmittedOrgScopes: [...ownOrgVerdictRef.current.scopes], ownAdmittedOrgWriteScope: ownOrgVerdictRef.current.writeScope }
156
162
  : {}),
@@ -8,7 +8,9 @@ import { brainToRuntime } from "../runtime.js";
8
8
  import { hasSessionFork } from "../session.js";
9
9
  import { SEND_MESSAGE_TOOL_NAME } from "../../agents/send-message-tool.js";
10
10
  import { callerToolMembership } from "../../agents/inherited-tool-pool.js";
11
- import { toolPolicyPathDenyRules, toolPolicyWriteTargetGuard } from "../tool-policy.js";
11
+ import { toolPolicyPathRules, toolPolicyWriteTargetGuard } from "../tool-policy.js";
12
+ import { bindPathRules, createHeadLeads } from "../path-rule-binding.js";
13
+ import { whereItsAnsweredPrefixLeads } from "../../tools/fs/read-deny-home.js";
12
14
  import { loadAnnounceOnceLedger } from "./announce-once-ledger.js";
13
15
  import { isValidReminderMark, mintReminderMark } from "../reminder-mint.js";
14
16
  import { clampPermissionMode } from "../ask-origin.js";
@@ -16,17 +18,18 @@ import { modePolicyOf, modeRequestAfterResume, refusePermissionModeDoors } from
16
18
  import { resolveOutputStyleFrame } from "../output-style.js";
17
19
  import { recordedModeSeed } from "../checkpoint-store.js";
18
20
  import { emitTrace } from "../trace.js";
19
- import { persistedPathRowsOfTask, ruleStoreUnreadableNotice } from "./persisted-path-rows.js";
21
+ import { persistedPathRowsOfTask, ruleRowsDroppedNotice, ruleStoreUnreadableNotice } from "./persisted-path-rows.js";
20
22
  import { reservedCollisions, reservedFor } from "../../brain/request-params.js";
21
23
  import { STALL_FIRST_BYTE_MS, STALL_FIRST_TOKEN_MS, STALL_IDLE_MS, withBrainCallGuardrail } from "../../brain/timeout.js";
22
24
  import { OFFLOAD_TOOL_NAME } from "../tool-result-store.js";
23
25
  import { OUTPUT_TOOL_NAME, SKILL_TOOL_NAME, createOutputTool } from "./synthetic-tools.js";
24
- import { skillGateWiring } from "../skill-grant.js";
26
+ import { compileSkillGrant, skillGateWiring } from "../skill-grant.js";
27
+ import { legCallTargetStamp } from "../effective-path-target.js";
25
28
  import { AllowEntryTable, screenAllowedToolsValue } from "../allow-entry.js";
26
29
  import { compileOutputSchema } from "./strict-output-schema.js";
27
30
  import { MEMORY_ENGINE_TOOL_NAMES } from "../memory-engine/tools.js";
28
31
  import { foldAdmissionFreeze } from "../memory-admission.js";
29
- import { deploymentCanRerootChild } from "./child-tree.js";
32
+ import { chainAnchorRecords, chainPolicyOnLeg, chainTopAnchors, deploymentCanRerootChild } from "./child-tree.js";
30
33
  import { prepareMemory } from "./prepare-memory.js";
31
34
  import { prepareMemoryEngineSession } from "./prepare-memory-engine-session.js";
32
35
  import { prepareDeferClassify } from "./prepare-defer-classify.js";
@@ -40,6 +43,7 @@ export { runGuardChain } from "./prepare-context-lane.js";
40
43
  import { preparePromptAssembly } from "./prepare-prompt-assembly.js";
41
44
  import { limitConfigError, prepareConfigDoors } from "./prepare-config-doors.js";
42
45
  import { prepareSafetyScan } from "./prepare-safety-scan.js";
46
+ import { isAbsolutePathForm } from "../../tools/fs/safety.js";
43
47
  import { prepareAcquireReconcile } from "./prepare-acquire-reconcile.js";
44
48
  import { settleBranchWriteBack } from "./branch-writeback.js";
45
49
  import { prepareHandsMount, resolveHandsLessReadFace } from "./prepare-hands-readface.js";
@@ -347,7 +351,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
347
351
  throw e;
348
352
  }
349
353
  const rollback = createRollbackStack((e) => deps.onError?.(e, { phase: "config", sessionId }));
350
- const { executionEnv, ownedEnvSeat, ownedEnvObservedAt, handsEnabled, taskRootInitial } = await prepareExecutionEnv({ deps, spec, internals, resume, placementRootResolved, sessionId, forgetOnThrow, rollback });
354
+ const { executionEnv, ownedEnvSeat, ownedEnvObservedAt, handsEnabled, taskRootInitial, placement } = await prepareExecutionEnv({ deps, spec, internals, resume, placementRootResolved, sessionId, forgetOnThrow, rollback });
351
355
  const externalContentTargetActive = executionEnv.externalContentTarget === true || resume?.seed.externalContentTarget === true;
352
356
  const abortController = new AbortController();
353
357
  if (spec.signal?.aborted)
@@ -400,8 +404,15 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
400
404
  }
401
405
  }
402
406
  const ownedEnv = ownedEnvSeat.current;
403
- const { taskRootFinal, rebaseRestoredPath } = await prepareWorkspaceRestore({ ownedEnv, deps, spec, internals, resume, taskRootInitial, abortController, sessionId });
407
+ const { taskRootFinal, rebaseRestoredPath } = await prepareWorkspaceRestore({ ownedEnv, deps, spec, internals, resume, taskRootInitial, placement, abortController, sessionId });
404
408
  const { canonical: taskRootCanonical } = await resolveTaskRootCanonical({ env: executionEnv, given: taskRootFinal, onNotice: deps.onNotice, sessionId, runId });
409
+ const legHome = executionEnv.homeDir;
410
+ const legAnchors = { root: taskRootCanonical, ...(legHome !== undefined && isAbsolutePathForm(legHome) ? { home: legHome } : {}) };
411
+ const chainTop = chainTopAnchors({ leg: legAnchors, live: internals?.inheritedGate?.pathRuleAnchors, seed: resume?.seed.inheritedGate?.pathRuleAnchors, placement, rebase: rebaseRestoredPath });
412
+ const onLeg = chainPolicyOnLeg({ leg: legAnchors, chainTop, placement, chain: (internals?.inheritedGate?.parentConstraints ?? []).map((c) => c.policy), installations: { live: internals?.inheritedGate?.pathRuleInstallations, seed: resume?.seed.inheritedGate?.pathRuleInstallations }, rebase: rebaseRestoredPath });
413
+ const [installedToolPolicy, installedBaseEdit] = [lockedPreflight.toolPolicy, lockedPreflight.basePolicyForResumeEdit].map(onLeg.own);
414
+ const installedPreflight = { ...lockedPreflight, toolPolicy: installedToolPolicy, basePolicyForResumeEdit: installedBaseEdit };
415
+ const headLeads = createHeadLeads((part) => whereItsAnsweredPrefixLeads(executionEnv, part));
405
416
  const { trackFileEdit, fileHistoryBoundary, restoredFilePaths, rewindNotes, fileHistoryEnabled, fileHistoryFact, historyScope, historyRoot, historyFs } = await prepareFileHistory({ deps, spec, request: fileHistoryRequest, internals, executionEnv, taskRootFinal, handsEnabled, sessionId, session, abortController });
406
417
  const { noteFileEdited, editedFilesSnapshot, harnessRef, toolProgressRef, skillGrants, forwardEvent, reviewRequestRef, requestReview, stopRequestedRef, requestStopAfterTurn, bindPermissionModeSeat, enterPlanMode, subagentRetain, worktreeIsolation } = prepareRunRefs({ spec, internals, executionEnv, taskRootFinal });
407
418
  const allowedToolTables = { request: new AllowEntryTable(), deployment: new AllowEntryTable() };
@@ -411,14 +422,19 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
411
422
  let readDenyAdditionsNormalized = [];
412
423
  let handsLessResolvedFace;
413
424
  let handsLessResolvedWriteFace;
414
- const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, permissionMode, commitModeSeats, endModeCeiling, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, ancestorSessionRulesRef, ancestorRulesNow, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, writeFaceCheckpointSection, skillGrantCheckpointSection, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, askSeat: doors.askSeat, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, checkpointSeat, toolFaceSnapshot, mountsCallerTool, promptProfile, resolvedInteractionPosture, permissionModeSeat, handsEnabled, reportUsage, harnessRef, skillGrants, requestAllowedTools: allowedToolTables.request, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, hooks: () => hooks, preToolUseObservational: () => preToolUseObservational, hookTimeoutMs: () => hookTimeoutMs, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDeciderRef.current, autoModeDenialTracking: () => autoModeDenialTrackingRef.current, autoModeArming: () => autoModeArmingRef.current, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, resolvedWriteFace: () => resolvedWriteFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, handsLessResolvedWriteFace: () => handsLessResolvedWriteFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
425
+ const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, permissionMode, commitModeSeats, endModeCeiling, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, ancestorSessionRulesRef, ancestorRulesNow, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, writeFaceCheckpointSection, skillGrantCheckpointSection, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, askSeat: doors.askSeat, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight: installedPreflight, pathRuleAnchors: { chainTop, onLeg: onLeg.chained }, checkpointSeat, toolFaceSnapshot, mountsCallerTool, promptProfile, resolvedInteractionPosture, permissionModeSeat, handsEnabled, reportUsage, harnessRef, skillGrants, requestAllowedTools: allowedToolTables.request, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, hooks: () => hooks, preToolUseObservational: () => preToolUseObservational, hookTimeoutMs: () => hookTimeoutMs, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDeciderRef.current, autoModeDenialTracking: () => autoModeDenialTrackingRef.current, autoModeArming: () => autoModeArmingRef.current, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, resolvedWriteFace: () => resolvedWriteFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, handsLessResolvedWriteFace: () => handsLessResolvedWriteFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
415
426
  bindPermissionModeSeat(permissionMode);
416
427
  const announceRuleStoreSkipped = ruleStoreUnreadableNotice(deps.onNotice, { sessionId, runId });
417
- const persistedPathRowsRead = persistedPathRowsOfTask({ deps, principal: spec.principal, sessionId, root: taskRootFinal, home: executionEnv.homeDir, taskId: hostTaskId, handsEnabled, signals: [abortController.signal, ...(spec.signal !== undefined ? [spec.signal] : [])], onUnread: announceRuleStoreSkipped });
428
+ const announceRuleRowsDropped = ruleRowsDroppedNotice(deps.onNotice, { sessionId, runId });
429
+ const persistedPathRowsRead = persistedPathRowsOfTask({ deps, principal: spec.principal, sessionId, root: taskRootFinal, rootCanonical: taskRootCanonical, leads: headLeads, chainTop, taskId: hostTaskId, handsEnabled, onRowsDropped: announceRuleRowsDropped, signals: [abortController.signal, ...(spec.signal !== undefined ? [spec.signal] : [])], onUnread: announceRuleStoreSkipped });
418
430
  const persistedPathRows = persistedPathRowsRead === undefined ? { readDirectories: [], denyRows: [] } : await persistedPathRowsRead;
419
- const effectivePathDenyRules = [...toolPolicyPathDenyRules([lockedPreflight.toolPolicy, ...(inheritedParentConstraints ?? []).map((c) => c.policy)]), ...persistedPathRows.denyRows];
431
+ const policyDenyRows = toolPolicyPathRules([installedToolPolicy, ...(inheritedParentConstraints ?? []).map((c) => c.policy)], legAnchors).filter((r) => r.faces.length > 0 && r.behavior === "deny");
432
+ for (const r of policyDenyRows)
433
+ if (r.unanchored !== undefined)
434
+ emitTrace(deps.tracer, () => ({ kind: "permission.rule_store_unreadable", version: 1, taskId: hostTaskId, message: `the deny rule ${r.rule} needs a ${r.unanchored.join(" / ")} base this task does not declare — the shell's file commands and the search tools do not judge it on this leg (the gate asks)`, ts: Date.now() }));
435
+ const effectivePathDenyRules = [...policyDenyRows.filter((r) => r.unanchored === undefined), ...persistedPathRows.denyRows];
420
436
  const writeProtectionJudgeRef = {};
421
- const writeGuards = { protection: () => writeProtectionJudgeRef.current, target: toolPolicyWriteTargetGuard([lockedPreflight.toolPolicy, ...(inheritedParentConstraints ?? []).map((c) => c.policy)]) };
437
+ const writeGuards = { protection: () => writeProtectionJudgeRef.current, target: toolPolicyWriteTargetGuard([installedToolPolicy, ...(inheritedParentConstraints ?? []).map((c) => c.policy)]) };
422
438
  const { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDeciderRef, autoModeDenialTrackingRef, autoModeArmingRef, armAutoMode, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline } = await prepareCapsAndWorkflow({ spec, deps, askSeat: doors.askSeat, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, checkpointSeat, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, parentSpecSeat, carrierReadFace, carrierWriteFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, permissionMode, readDenyEntries: () => ({ entries: readDenyMatcher?.entries ?? [], ruleRows: effectivePathDenyRules }), peerLaneActive, peerSendMessageBuiltIn, runnerSelf, memoryEngineSession: () => memoryEngineSession, centerAdoption: () => centerAdoptionRef.current, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized });
423
439
  const tools = roster.tools;
424
440
  const pausedRef = {};
@@ -556,7 +572,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
556
572
  if (internals?.ownOrgAdmissionRef !== undefined && ownOrgVerdictRef.current !== undefined) {
557
573
  internals.ownOrgAdmissionRef.current = ownOrgVerdictRef.current;
558
574
  }
559
- const handsReadFaceInput = { permissionMode, pathDenyRules: effectivePathDenyRules, writeGuards, persistedReadDirectories: persistedPathRows.readDirectories, 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, ...(trackFileEdit !== undefined ? { trackFileEdit } : {}), onFileEdited: noteFileEdited, harnessRef, toolProgressRef, ...(restoredFilePaths.length > 0 ? { restoredFilePaths } : {}) };
575
+ const handsReadFaceInput = { permissionMode, denyRuleRows: effectivePathDenyRules, headLeads, writeGuards, persistedReadDirectories: persistedPathRows.readDirectories, 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, ...(trackFileEdit !== undefined ? { trackFileEdit } : {}), onFileEdited: noteFileEdited, harnessRef, toolProgressRef, ...(restoredFilePaths.length > 0 ? { restoredFilePaths } : {}) };
560
576
  const handsReadFace = handsEnabled ? await prepareHandsMount(handsReadFaceInput) : resolveHandsLessReadFace(handsReadFaceInput);
561
577
  const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, shellReadCheck, shellReadAdmission, additionalRootsCanonical, additionalReadRootsCanonical, attachmentRootCanonical, readDenyMatcher, envHandToolNames, sealReadStateSeat } = handsReadFace;
562
578
  resolvedReadFace = handsReadFace.resolvedReadFace;
@@ -737,7 +753,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
737
753
  releaseSignal = () => sig.removeEventListener("abort", onExternalAbort);
738
754
  }
739
755
  }
740
- const { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, skillGrantLane, allowEntryLanes, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, grantBindingOf, permissionRuleLane, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions, ancestorArbitrations } = await preparePolicyChain({ spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, additionalRootsCanonical, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, toolMarkSources, envHandToolNames, handsCwdRef, readDenyMatcher, announceRuleStoreSkipped, questionToolMounted, runtimeCaps, inheritedAncestorRules, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, skillGrants, skillSpecs, allowedToolTables, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider: () => autoModeDeciderRef.current, readFace: () => resolvedReadFace, permissionMode, scratchpadDir: spec.envFacts?.scratchpadDir, toolRosterDeltas: rosterSeat, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef });
756
+ const { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, skillGrantLane, allowEntryLanes, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, grantBindingOf, permissionRuleLane, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions, ancestorArbitrations } = await preparePolicyChain({ spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, additionalRootsCanonical, executionEnv, lockedPreflight: installedPreflight, pathRuleAnchors: { leg: legAnchors, chainTop }, headLeads, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, toolMarkSources, envHandToolNames, handsCwdRef, readDenyMatcher, announceRuleStoreSkipped, announceRuleRowsDropped, questionToolMounted, runtimeCaps, inheritedAncestorRules, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, skillGrants, skillSpecs, allowedToolTables, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider: () => autoModeDeciderRef.current, readFace: () => resolvedReadFace, permissionMode, scratchpadDir: spec.envFacts?.scratchpadDir, toolRosterDeltas: rosterSeat, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef });
741
757
  const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, writeProtection, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace, sessionBoxBound } = prepareWiringManifest({ spec, deps, askSeat: doors.askSeat, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, shellReadStationArmed: handsReadFace.shellReadStationArmed, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, permissionMode, lockedPreflight, peerLaneRefs, frameSettlement, harness, pausedRef, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive: handsReadFace.readDenyBuiltinTiersActive, lspManagerWired, lspDiagnosticsLive: lspDiagnostics !== undefined, fileHistoryFact, sessionBox });
742
758
  const writeProtectionCheck = writeProtection?.check;
743
759
  writeProtectionJudgeRef.current = writeProtection?.judgeTarget;
@@ -747,18 +763,21 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
747
763
  return undefined;
748
764
  });
749
765
  }
750
- const { askLane } = prepareAskLane({ gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, handsRoot: attachmentRootCanonical, advertisedWritableDirs, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, grantBindingOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking: autoModeDenialTrackingRef, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash, grantReadRoot: handsReadFace.grantReadRoot });
751
- const { saga } = prepareSuspendSaga({ gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
766
+ const listPathRows = () => skillSpecs.flatMap((s) => compileSkillGrant(s, "model").rows).flatMap((r) => (r.behavior === "deny" && r.compiled.kind === "path" ? [r.compiled.rule] : []));
767
+ const stampCallTarget = attachmentRootCanonical === undefined ? undefined : legCallTargetStamp({ env: executionEnv, root: attachmentRootCanonical, cwd: () => handsCwdRef?.current, judgesPaths: () => effectivePolicy?.pathRules !== undefined || basePolicyForResumeEdit?.pathRules !== undefined || permissionRuleLane !== undefined || listPathRows().length > 0, leads: () => headLeads.resolve([...toolPolicyPathRules([effectivePolicy, basePolicyForResumeEdit, ...(inheritedParentConstraints ?? []).map((c) => c.policy)], legAnchors), ...bindPathRules(listPathRows().map((rule) => ({ parsed: rule, ruleText: rule.rule })), legAnchors)]) });
768
+ const { askLane } = prepareAskLane({ gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, handsRoot: attachmentRootCanonical, stampCallTarget, advertisedWritableDirs, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, grantBindingOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking: autoModeDenialTrackingRef, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash, grantReadRoot: handsReadFace.grantReadRoot });
769
+ const inheritedAnchorRecords = chainAnchorRecords(chainTop, inheritedParentConstraints ?? []);
770
+ const { saga } = prepareSuspendSaga({ gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, reminderMark, handsCwdRef, handsRoot: attachmentRootCanonical, handsHome: attachmentRootCanonical !== undefined ? legAnchors.home : undefined, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, inheritedPathRuleAnchors: chainTop !== legAnchors ? inheritedAnchorRecords.pathRuleAnchors : undefined, inheritedPathRuleInstallations: inheritedAnchorRecords.pathRuleInstallations, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
752
771
  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 });
753
- const { parkAsk } = prepareParkAsk({ askLane, saga, spec, deps, sessionId, checkpointStore, toolRosterDeltas: rosterSeat, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, handsRoot: attachmentRootCanonical, advertisedWritableDirs, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, toolMarkSources, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, grantBindingOf, now, humanReviewRef, abortController, harness, pausedRef });
772
+ const { parkAsk } = prepareParkAsk({ askLane, saga, spec, deps, sessionId, checkpointStore, toolRosterDeltas: rosterSeat, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, handsRoot: attachmentRootCanonical, stampCallTarget, advertisedWritableDirs, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, toolMarkSources, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, grantBindingOf, now, humanReviewRef, abortController, harness, pausedRef });
754
773
  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() })) } } });
755
- const { approvedCallScreen } = 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, hostTaskId, sessionId, ownGatePreToolUse, hookTimeoutMs, handsCwdRef, readDenyInForce: () => ({ tiers: handsReadFace.readDenyBuiltinTiersActive, rows: [...readDenyAdditionsNormalized.map((e) => e.pattern), ...handsReadFaceInput.pathDenyRules.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, notifyOwnHookCrash, frameSettlement });
774
+ const { approvedCallScreen } = 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, hostTaskId, sessionId, ownGatePreToolUse, hookTimeoutMs, handsCwdRef, stampCallTarget, readDenyInForce: () => ({ tiers: handsReadFace.readDenyBuiltinTiersActive, rows: [...readDenyAdditionsNormalized.map((e) => e.pattern), ...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, notifyOwnHookCrash, frameSettlement });
756
775
  const postureFrameRef = { report: (err) => deps.onError?.(err, { phase: "degraded", sessionId }) };
757
776
  const { microCompact, charsPerToken } = prepareContextLane({ model, deps, sessionId, runId, hostTaskId, offloadStore, toolRosterDeltas: rosterSeat, microCompactKnob, harness, batchHaltRef, gitStatusRef, postureFrameRef, requestLossyRef, trimPressureRef, contextOverlay: legContextOverlay, ...(readFileStateForCheckpoint !== undefined ? { readFileState: readFileStateForCheckpoint } : {}) });
758
777
  const preparedHolder = {};
759
- 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, skillGrants: skillGrantLane, callerPolicy: lockedPreflight.toolPolicy, inheritedPolicies: (inheritedParentConstraints ?? []).map((c) => c.policy), persistedRuleLane: permissionRuleLane, orgRuleLane: permissionRuleOrgLane, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder });
778
+ 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, skillGrants: skillGrantLane, callerPolicy: installedToolPolicy, inheritedPolicies: (inheritedParentConstraints ?? []).map((c) => c.policy), persistedRuleLane: permissionRuleLane, orgRuleLane: permissionRuleOrgLane, stampCallTarget, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder });
760
779
  await onceLedger.settle(session, announcedListingsRef);
761
- const buildPrepared = () => ({ harness, session, sessionId, runId, registryAccess: { owner: hostTaskId, scope: taskScope }, reminderMark, reminderDisclosureCounts, fullShellReachable, approvalPosture: { get mode() { return permissionMode.current; }, askEffective: askSeatEffective(wiringManifest) }, ...(outputStyleFrame !== undefined ? { outputStyleFrame } : {}), permissionMode, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(mcpRedial !== undefined ? { mcpRedial } : {}), ...(a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, gateOutcomes, 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 } : {}), toolProgressRef, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, skillGrants: skillGrantLane, skillSpecs, ...(permissionRuleLane !== undefined ? { persistedRuleLane: permissionRuleLane } : {}), ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, endModeCeiling, 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 } } : {}), 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 } : {}), ...(approvedCallScreen !== undefined ? { approvedCallScreen } : {}) });
780
+ const buildPrepared = () => ({ harness, session, sessionId, runId, registryAccess: { owner: hostTaskId, scope: taskScope }, reminderMark, reminderDisclosureCounts, fullShellReachable, approvalPosture: { get mode() { return permissionMode.current; }, askEffective: askSeatEffective(wiringManifest) }, ...(outputStyleFrame !== undefined ? { outputStyleFrame } : {}), permissionMode, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp, ...(mcpRedial !== undefined ? { mcpRedial } : {}), ...(a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, gateOutcomes, 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 } : {}), ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, skillGrants: skillGrantLane, skillSpecs, ...(permissionRuleLane !== undefined ? { persistedRuleLane: permissionRuleLane } : {}), ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, endModeCeiling, 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 } } : {}), 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 } : {}), ...(approvedCallScreen !== undefined ? { approvedCallScreen } : {}) });
762
781
  rollback.commit();
763
782
  commitModeSeats(abortController.signal);
764
783
  const prepared = buildPrepared();
@@ -92,6 +92,8 @@ export interface PrepareTurnWiringInput {
92
92
  persistedRuleLane: Prepared["persistedRuleLane"];
93
93
  /** borrowed-readonly — the org rule lane, or undefined (a layer of the judge). */
94
94
  orgRuleLane: Prepared["permissionRuleOrg"];
95
+ /** borrowed-readonly — the leg's target-reading stamp, or undefined (hands-less): the visibility judge stamps its request. */
96
+ stampCallTarget: Prepared["stampCallTarget"];
95
97
  /** borrowed-readonly — the run's abort controller; only `signal` (the deny door's and the stat's signal). */
96
98
  abortController: Pick<AbortController, "signal">;
97
99
  /** borrowed-readonly — the per-task identity (the background listing's owner). */
@@ -13,7 +13,7 @@ import { PROMPT_HASH_SALT } from "./prompt-hash-salt.js";
13
13
  import { CHANGED_FILES_MTIME_EPS_MS } from "./turn-attachments.js";
14
14
  import { thrownText } from "../thrown-value.js";
15
15
  export function prepareTurnWiring(input) {
16
- const { deps, systemPromptSeat, harnessTools, fpRef, model, epochArtifactDigestForSnapshot, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, additionalRootsCanonical, additionalReadRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, skillGrants, callerPolicy, inheritedPolicies, persistedRuleLane, orgRuleLane, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder } = input;
16
+ const { deps, systemPromptSeat, harnessTools, fpRef, model, epochArtifactDigestForSnapshot, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, additionalRootsCanonical, additionalReadRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, skillGrants, callerPolicy, inheritedPolicies, persistedRuleLane, orgRuleLane, stampCallTarget, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder } = input;
17
17
  const cacheBreakDetector = deps.cacheBreakDetection === false ? undefined : new CacheBreakDetector();
18
18
  const cacheFingerprint = cacheBreakDetector
19
19
  ? { systemPrompt: systemPromptSeat.current, tools: toolsToFingerprintInputs(harnessTools) }
@@ -109,6 +109,7 @@ export function prepareTurnWiring(input) {
109
109
  inheritedPolicies,
110
110
  ...(persistedRuleLane !== undefined ? { persistedRuleLane } : {}),
111
111
  ...(orgRuleLane !== undefined ? { orgRuleLane } : {}),
112
+ ...(stampCallTarget !== undefined ? { stampCallTarget } : {}),
112
113
  signal: abortController.signal,
113
114
  });
114
115
  const changedFilesReadDenied = async (paths) => {
@@ -29,6 +29,9 @@ export interface PrepareWorkspaceRestoreInput {
29
29
  * driver). Dead after this call by design (R-5): later phases read the returned
30
30
  * `taskRootFinal`, never this spelling. */
31
31
  taskRootInitial: string;
32
+ /** borrowed-readonly — where a delegated child landed against where it was asked (the execution-env phase's one
33
+ * judgment), reported beside the root it resolved; absent on a leg no delegation caller placed. */
34
+ placement?: import("./contracts.js").ChildPlacement | undefined;
32
35
  /** borrowed-readonly — prepare's abort seat; only `.signal` is read (kept as the object so the
33
36
  * moved body's `abortController.signal` spelling stays verbatim). */
34
37
  abortController: {
@@ -115,6 +115,7 @@ export async function prepareWorkspaceRestore(input) {
115
115
  isolated: internals.isolation === "worktree",
116
116
  remote: workspaceEnv !== undefined &&
117
117
  (isRemoteExecutionEnv(workspaceEnv) || workspaceEnv.hostLocalPaths === false),
118
+ ...(input.placement !== undefined ? { placement: input.placement } : {}),
118
119
  });
119
120
  }
120
121
  catch {
@@ -4,8 +4,10 @@ import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
4
4
  import { CheckpointError, remainingBudgetMicroUsd } from "../checkpoint-store.js";
5
5
  import { settledByDecider } from "../gate-outcome.js";
6
6
  import { mintHookInvocationIdentity, resolveHookTimeoutMs, runHookSeat } from "../hooks.js";
7
+ import { chainPolicyOnLeg, chainTopAnchors } from "./child-tree.js";
7
8
  import { checkToolPolicyProjection, policyCannotAnswer, refuseOutOfContractDecision } from "../tool-policy.js";
8
9
  import { callFaceSeat, parkedCallFaceOf } from "../tool-roster.js";
10
+ import { readCallTarget } from "../effective-path-target.js";
9
11
  import { inlineUntrusted } from "../untrusted-text.js";
10
12
  import { deepJsonEqual, describeSuppliedValue } from "./decide-continuation.js";
11
13
  import { orgVerdictBeforeClaim } from "./permission-rule-lanes.js";
@@ -110,14 +112,16 @@ export async function resumeApply(input) {
110
112
  resourceSpentMicroUsd: cp.resourceLedger?.spentMicroUsd ?? 0,
111
113
  suspendCount: cp.suspendCount ?? 0,
112
114
  };
113
- const editedReq = {
115
+ const editedCall = {
114
116
  toolName: cp.pendingAction.toolName,
115
117
  args: editedArgs,
116
118
  toolCallId: cp.pendingAction.toolCallId,
117
119
  budget: editBudget,
118
120
  ...callFaceSeat(parkedCallFaceOf(cp.pendingAction)),
119
121
  ...(cp.state.handsCwd !== undefined ? { cwd: cp.state.handsCwd } : {}),
122
+ ...(cp.state.handsRoot !== undefined ? { root: cp.state.handsRoot } : {}),
120
123
  };
124
+ const editedReq = { ...editedCall, targetReading: await readCallTarget(undefined, editedCall) };
121
125
  const ig = cp.state.inheritedGate;
122
126
  if (ig?.requiresParentConstraint === true) {
123
127
  const chain = ig.constraintChain;
@@ -139,10 +143,20 @@ export async function resumeApply(input) {
139
143
  const editBasePolicy = toolPolicyLocked
140
144
  ? (runner.deps.basePolicyForResumeEdit ?? runner.deps.toolPolicy)
141
145
  : (config.basePolicyForResumeEdit ?? runner.deps.basePolicyForResumeEdit ?? config.toolPolicy ?? runner.deps.toolPolicy);
142
- if (editBasePolicy !== undefined) {
146
+ const rowLeg = { ...(typeof cp.state.handsRoot === "string" ? { root: cp.state.handsRoot } : {}), ...(typeof cp.state.handsHome === "string" ? { home: cp.state.handsHome } : {}) };
147
+ const asRecorded = (p) => p;
148
+ const installedEditBase = chainPolicyOnLeg({
149
+ leg: rowLeg,
150
+ chainTop: chainTopAnchors({ leg: rowLeg, live: internals?.inheritedGate?.pathRuleAnchors, seed: cp.state.inheritedGate?.pathRuleAnchors, placement: undefined, rebase: asRecorded }),
151
+ placement: undefined,
152
+ chain: (internals?.inheritedGate?.parentConstraints ?? []).map((c) => c.policy),
153
+ installations: { live: internals?.inheritedGate?.pathRuleInstallations, seed: cp.state.inheritedGate?.pathRuleInstallations },
154
+ rebase: asRecorded,
155
+ }).own(editBasePolicy);
156
+ if (installedEditBase !== undefined) {
143
157
  let rechecked;
144
158
  try {
145
- rechecked = refuseOutOfContractDecision(await raceEditAbort(Promise.resolve(editBasePolicy.check(editedReq, editSignal))));
159
+ rechecked = refuseOutOfContractDecision(await raceEditAbort(Promise.resolve(installedEditBase.check(editedReq, editSignal))));
146
160
  }
147
161
  catch (err) {
148
162
  if (err instanceof CheckpointError)
@@ -1,8 +1,10 @@
1
1
  import { persistedReadDenyEntryProblem } from "../../tools/fs/read-deny.js";
2
+ import { isAbsolutePathForm } from "../../tools/fs/safety.js";
2
3
  import { isAskOrigin } from "../ask-origin.js";
3
4
  import { CHECKPOINT_FEATURES, CheckpointError, checkpointVersionOf, MAX_SUPPORTED_CHECKPOINT_VERSION, realApprovalOrgFact } from "../checkpoint-store.js";
4
5
  import { constraintChainDigest, constraintChainEntryOfSuppliedLayer } from "../tool-policy.js";
5
6
  import { readFrozenSkillGrants } from "../skill-grant.js";
7
+ import { chainInstallationGaps, chainInstallationRefusal } from "./child-tree.js";
6
8
  export function resumeCheckpointScreen(input) {
7
9
  const { cp, resumeSignal, internals, runner } = input;
8
10
  const { realApproval: realApprovalRow, face: faceRow, f012: f012Row } = CHECKPOINT_FEATURES;
@@ -49,6 +51,11 @@ export function resumeCheckpointScreen(input) {
49
51
  }
50
52
  if (readFrozenSkillGrants(cp.state.skillGrants) === undefined)
51
53
  throw new CheckpointError("checkpoint.invalid_outcome", "this checkpoint carries a skill-grant section (state.skillGrants) that does not read as grant rows under this engine — a damaged section, or a row an earlier release wrote whose entry this release reads as nothing (an entry with a surrounding space, say) — refusing to resume without the grant rows and refusals it carries; the checkpoint stays pending: finish it on a worker of the release that parked it, or expire it", { reason: "skill_grants_damaged" });
54
+ for (const field of ["handsRoot", "handsHome", "handsCwd"]) {
55
+ const coordinate = cp.state[field];
56
+ if (coordinate !== undefined && (typeof coordinate !== "string" || !isAbsolutePathForm(coordinate)))
57
+ throw new CheckpointError("checkpoint.invalid_outcome", `this checkpoint's state.${field} is not an absolute path — refusing to resume a row whose hands' coordinates are damaged (corruption guard), the checkpoint stays pending`, { reason: "hands_coordinates_damaged" });
58
+ }
52
59
  }
53
60
  if (realApprovalOrgFact(preCasGateBit) !== undefined && runner.deps.permissionRuleStore?.partitions.org !== true) {
54
61
  throw new CheckpointError("checkpoint.unsupported_version", `this checkpoint's approval was minted under organization governance (org ${String(realApprovalOrgFact(preCasGateBit))}, routed as ${String(preCasGateBit?.origin)}) and this worker has no org adjudication wiring (its permission-rule store carries no org partition) — a governed approval may only be redeemed where governance can be enforced; the checkpoint stays pending, resume it on an org-wired worker`, { reason: "governed_unwired" });
@@ -106,6 +113,12 @@ export function resumeCheckpointScreen(input) {
106
113
  }
107
114
  }
108
115
  }
116
+ const resupplied = (internals?.inheritedGate?.parentConstraints ?? []).map((pc) => pc.policy);
117
+ if (resupplied.length > 0) {
118
+ const gaps = chainInstallationGaps(resupplied, { live: internals?.inheritedGate?.pathRuleInstallations, seed: cp.state.inheritedGate?.pathRuleInstallations }, (p) => p);
119
+ if (gaps.length > 0)
120
+ throw chainInstallationRefusal(gaps, true);
121
+ }
109
122
  const resumeInternals = internals?.inheritedGate?.parentConstraints !== undefined
110
123
  ? {
111
124
  ...internals,
@@ -614,7 +614,8 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
614
614
  }
615
615
  const executedArgs = humanRewrite !== undefined ? resolvedArgs : screened !== undefined ? screened.args : resolvedArgs;
616
616
  const unseen = !deepJsonEqual(executedArgs, pendingAction.args);
617
- const beltReq = () => ({ toolName: pendingAction.toolName, args: executedArgs, toolCallId: pendingAction.toolCallId, ...callFaceSeat(parkedRowLiveFace(prepared.toolRosterDeltas.current, pendingAction)), budget: beltBudget, ...(prepared.cwdRef !== undefined ? { cwd: prepared.cwdRef.current } : {}), ...(prepared.handsRoot !== undefined ? { root: prepared.handsRoot } : {}), ...advertisedWritableRootsSeat(prepared.advertisedWritableDirs) });
617
+ let beltReading;
618
+ const beltReq = () => ({ toolName: pendingAction.toolName, args: executedArgs, toolCallId: pendingAction.toolCallId, ...callFaceSeat(parkedRowLiveFace(prepared.toolRosterDeltas.current, pendingAction)), budget: beltBudget, ...(prepared.cwdRef !== undefined ? { cwd: prepared.cwdRef.current } : {}), ...(prepared.handsRoot !== undefined ? { root: prepared.handsRoot } : {}), ...advertisedWritableRootsSeat(prepared.advertisedWritableDirs), ...(beltReading !== undefined ? { targetReading: beltReading } : {}) });
618
619
  const unjudgeable = unseen ? chainCannotJudge(resume.cp.state.inheritedGate) : undefined;
619
620
  if (unjudgeable !== undefined) {
620
621
  const chainDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: its input changed after the approval and the inherited ancestor chain cannot judge the changed input (${unjudgeable}). This approval is spent — the call has to be re-issued.`, prepared.reminderMark);
@@ -627,6 +628,9 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
627
628
  resourceSpentMicroUsd: prepared.resourceLedger?.spentMicroUsd ?? 0,
628
629
  suspendCount: resume.cp.suspendCount ?? 0,
629
630
  };
631
+ const beltStamped = prepared.stampCallTarget?.(beltReq(), prepared.abortController.signal);
632
+ if (beltStamped !== undefined)
633
+ beltReading = (await beltStamped).targetReading;
630
634
  if (unseen && prepared.basePolicyForResumeEdit) {
631
635
  const rechecked = refuseOutOfContractDecision(await prepared.basePolicyForResumeEdit.check(beltReq(), prepared.abortController.signal));
632
636
  const personUnanswered = policyCannotAnswer(rechecked, outcome.hostDecision.decidedBy);
@@ -45,7 +45,7 @@ import { streamLifecycleVerbs } from "./stream-lifecycle-verbs.js";
45
45
  import { streamHaltVerbs } from "./stream-halt-verbs.js";
46
46
  import { streamModeVerb } from "./stream-mode-verb.js";
47
47
  import { runNotificationLane } from "./run-notification-lane.js";
48
- import { assertNoRetiredRunnerDeps } from "./retired-runner-deps.js";
48
+ import { assertRunnerDepsDoors } from "./construction-doors.js";
49
49
  import { runLeg } from "./run-leg.js";
50
50
  import { runTerminalAdoption } from "./run-terminal-adoption.js";
51
51
  import { runSettleAndTeardown } from "./run-settle-and-teardown.js";
@@ -77,7 +77,7 @@ export class Runner {
77
77
  static PARENT_CONSTRAINT_REGISTRY_CAP = 1024;
78
78
  depsSeat;
79
79
  constructor(deps) {
80
- assertNoRetiredRunnerDeps(deps);
80
+ assertRunnerDepsDoors(deps);
81
81
  const runner = this;
82
82
  this.depsSeat = { get deps() { return runner.deps; } };
83
83
  this.deps = withDeploymentAllowedTools(deps);
@@ -3,7 +3,7 @@
3
3
  * list a deployment writes — the task's own definitions (`TaskSpec.agents`), the definitions a mounted delegation tool carries
4
4
  * (the `authored` faces — the engine's built-ins name tools of other vocabularies and are not judged) and its tool-level list.
5
5
  * Universe = the task's assembled roster plus every mounted delegation tool's pool, names and aliases; a pool the engine cannot
6
- * list (an `extraTools` factory) turns the refusals that need a roster into host notices. A tool's own lists are judged where
6
+ * list (an `extraTools` factory with no declared roster) turns the refusals that need a roster into host notices. A tool's own lists are judged where
7
7
  * the tool is mounted: only a tool a deployment mounted (depth 0) publishes them (`authored`, `agentToolLevelAllowTools`, `agentToolLevelDenyTools`), the
8
8
  * engine's nested copy for a delegated child carries neither.
9
9
  *
@@ -33,8 +33,9 @@ export interface LegWriteProtection extends WriteProtectionMount {
33
33
  export declare function mountWriteProtection(input: {
34
34
  /** borrowed-readonly — the deployment seats: the table (`writeProtectedPaths`; absent ⇒ the default
35
35
  * table, `[]` ⇒ opted out), the data root the memory library is materialized under
36
- * (`memoryEngineDir`; absent ⇒ the resolver's env/default chain) and the operator sink. */
37
- deps: Pick<RunnerDeps, "writeProtectedPaths" | "memoryEngineDir" | "onNotice">;
36
+ * (`memoryEngineDir`; absent ⇒ the resolver's env/default chain), the configuration root the host
37
+ * declared (`agentConfigDir`) and the operator sink. */
38
+ deps: Pick<RunnerDeps, "writeProtectedPaths" | "memoryEngineDir" | "agentConfigDir" | "onNotice">;
38
39
  /** The HANDS' environment, or `undefined` with no hands — the driver's own predicate, not a second
39
40
  * reading of the env seats, so the judge sees exactly the environment the write tools do. */
40
41
  env: ExecutionEnv | undefined;
@@ -6,6 +6,7 @@ export function mountWriteProtection(input) {
6
6
  const announced = new Set();
7
7
  const matcher = compileWriteProtection(input.deps.writeProtectedPaths, {
8
8
  ...(input.deps.memoryEngineDir !== undefined ? { dataRoot: input.deps.memoryEngineDir } : {}),
9
+ ...(input.deps.agentConfigDir !== undefined ? { agentConfigDir: input.deps.agentConfigDir } : {}),
9
10
  ...(input.env !== undefined ? { env: input.env } : {}),
10
11
  rootPath: input.rootPath,
11
12
  onViewAbsent: (absence) => {
@@ -227,6 +227,20 @@ export interface RunnerDeps {
227
227
  * ignored). Same deployment-only seat, clamp argument and checkpoint posture as the tiers key.
228
228
  */
229
229
  readDenyBuiltinExclude?: readonly string[];
230
+ /**
231
+ * Where the host keeps the agent's configuration directory when it is not `<home>/.sema` — an ABSOLUTE path of an
232
+ * existing directory, resolved by the host (the engine reads no environment variable for it). The rows of the
233
+ * `agent-config` tier that name that directory (`~/.sema/settings.json`, `~/.sema/settings.local.json`,
234
+ * `~/.sema/engine-data/.env`, `~/.sema/config-lkg-*.json`) are then ALSO placed at the same files below this root, so the model can neither read
235
+ * nor (through the write-protection table and a wired `createSensitivePathPolicy({ agentConfigDir })`) rewrite the
236
+ * relocated settings; the default `~/.sema` location stays refused. Rows of the home's dotted family (`~/.sema.*`)
237
+ * and the external tools' files are not part of the directory and stay anchored at the home. A symlink the root is
238
+ * reached through is followed (the target is guarded too). ABSENT = today's behaviour, the literal `~/.sema` under
239
+ * the declared and account homes. A value that is not a string, is empty or relative, or names no existing directory
240
+ * refuses `new Runner` with `config.agent_config_dir_invalid` — never read as absent. DEPLOYMENT seat only (no
241
+ * TaskSpec twin) and fixed at construction: `swapDeps` does not carry it.
242
+ */
243
+ agentConfigDir?: string;
230
244
  /**
231
245
  * backlog #286 (#279 — CC 2.1.233 `DANGEROUS_FILES`/`DANGEROUS_DIRECTORIES`/
232
246
  * `DANGEROUS_DIRECTORY_PATHS` parity): the WRITE-protection table. DEFAULT-ON: a path-confinable
@@ -155,6 +155,14 @@ export declare function createSensitivePathPolicy(opts: {
155
155
  * gate and the transcript gate keep speaking about the same directory.
156
156
  */
157
157
  dataRoot?: string;
158
+ /**
159
+ * The host's configuration root when it keeps the agent's configuration directory somewhere other than the home's
160
+ * `.sema` — the same absolute directory it hands the Runner (`RunnerDeps.agentConfigDir`). Every pattern that opens with
161
+ * the `.sema` segment (`.sema/settings.json`, `.sema/hooks`, …) then also guards the same tail below this root; the
162
+ * patterns themselves keep guarding every `.sema` anywhere. Absent ⇒ the list is judged as it stands. A value that is not
163
+ * the absolute path of an existing directory throws (`config.agent_config_dir_invalid`).
164
+ */
165
+ agentConfigDir?: string;
158
166
  /** Override the guarded tool set (default: `Write`, `Edit`, `MultiEdit`-legacy → Edit, `NotebookEdit`). */
159
167
  tools?: string[];
160
168
  }): ToolPolicy;