@sema-agent/core 7.33.8 → 7.35.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 (228) hide show
  1. package/CHANGELOG.md +462 -3
  2. package/dist/agents/cross-session-judge.d.ts +16 -7
  3. package/dist/agents/cross-session-judge.js +18 -15
  4. package/dist/agents/peer-session-drain.d.ts +4 -0
  5. package/dist/agents/peer-session-drain.js +5 -2
  6. package/dist/agents/repair-loop.d.ts +1 -1
  7. package/dist/agents/subagent.d.ts +3 -0
  8. package/dist/agents/subagent.js +12 -3
  9. package/dist/brain/anthropic.js +1 -0
  10. package/dist/brain/errors.d.ts +23 -1
  11. package/dist/brain/errors.js +19 -2
  12. package/dist/brain/open-responses.js +1 -0
  13. package/dist/brain/openai.js +1 -0
  14. package/dist/brain/status-sink.d.ts +7 -1
  15. package/dist/brain/stream-engine.d.ts +3 -0
  16. package/dist/brain/stream-engine.js +2 -1
  17. package/dist/brain/stream-shared.d.ts +3 -1
  18. package/dist/brain/stream-shared.js +16 -4
  19. package/dist/core/a2a.d.ts +3 -1
  20. package/dist/core/a2a.js +1 -1
  21. package/dist/core/ask-origin.d.ts +379 -154
  22. package/dist/core/ask-origin.js +224 -45
  23. package/dist/core/ask-question.js +2 -1
  24. package/dist/core/ask-unresolvable-notice.d.ts +5 -2
  25. package/dist/core/ask-unresolvable-notice.js +4 -3
  26. package/dist/core/auto-mode-arming.d.ts +17 -4
  27. package/dist/core/auto-mode-arming.js +31 -6
  28. package/dist/core/auto-mode-defaults.d.ts +16 -7
  29. package/dist/core/auto-mode-defaults.js +2 -1
  30. package/dist/core/auto-mode-directive.d.ts +18 -30
  31. package/dist/core/auto-mode-directive.js +9 -18
  32. package/dist/core/auto-mode-prompt.d.ts +62 -1
  33. package/dist/core/auto-mode-prompt.js +42 -4
  34. package/dist/core/auto-mode-rebuild.d.ts +2 -1
  35. package/dist/core/auto-mode-rebuild.js +1 -0
  36. package/dist/core/auto-mode.d.ts +32 -3
  37. package/dist/core/auto-mode.js +80 -41
  38. package/dist/core/checkpoint-store.d.ts +54 -35
  39. package/dist/core/checkpoint-store.js +58 -3
  40. package/dist/core/child-clamp-seats.js +1 -0
  41. package/dist/core/classifier-unavailable-arm.d.ts +57 -0
  42. package/dist/core/classifier-unavailable-arm.js +17 -0
  43. package/dist/core/effective-path-target.d.ts +12 -0
  44. package/dist/core/effective-path-target.js +18 -7
  45. package/dist/core/engine-notice.d.ts +53 -2
  46. package/dist/core/fs-write-gate-policy.d.ts +5 -1
  47. package/dist/core/fs-write-gate-policy.js +4 -1
  48. package/dist/core/gate-fold.js +19 -3
  49. package/dist/core/gate-lanes.js +116 -50
  50. package/dist/core/gate-outcome.d.ts +40 -7
  51. package/dist/core/gate-outcome.js +26 -4
  52. package/dist/core/governance-codes.d.ts +18 -2
  53. package/dist/core/governance-codes.js +23 -1
  54. package/dist/core/hooks.d.ts +53 -29
  55. package/dist/core/hooks.js +1 -3
  56. package/dist/core/mcp.js +1 -1
  57. package/dist/core/message-utils.d.ts +2 -1
  58. package/dist/core/message-utils.js +2 -1
  59. package/dist/core/mode-policy.d.ts +185 -0
  60. package/dist/core/mode-policy.js +184 -0
  61. package/dist/core/oracle-isolation.d.ts +3 -3
  62. package/dist/core/permission-rule-model.d.ts +20 -3
  63. package/dist/core/permission-rule-model.js +40 -3
  64. package/dist/core/permission-rule-provider.d.ts +22 -11
  65. package/dist/core/permission-rule-provider.js +17 -7
  66. package/dist/core/permission-rules.d.ts +23 -1
  67. package/dist/core/permission-rules.js +56 -9
  68. package/dist/core/persisted-rule-arms.d.ts +14 -10
  69. package/dist/core/persisted-rule-arms.js +13 -6
  70. package/dist/core/present-plan-tool.d.ts +1 -1
  71. package/dist/core/present-plan-tool.js +3 -3
  72. package/dist/core/read-only-shell.d.ts +19 -19
  73. package/dist/core/read-only-shell.js +38 -12
  74. package/dist/core/retired-keys.d.ts +9 -3
  75. package/dist/core/retired-keys.js +5 -1
  76. package/dist/core/runner/active-skill-scope.js +5 -4
  77. package/dist/core/runner/assemble-result.js +2 -2
  78. package/dist/core/runner/classifier-ladder.d.ts +43 -1
  79. package/dist/core/runner/classifier-ladder.js +29 -0
  80. package/dist/core/runner/contracts.d.ts +62 -38
  81. package/dist/core/runner/denial-limit-arms.d.ts +35 -7
  82. package/dist/core/runner/denial-limit-arms.js +15 -9
  83. package/dist/core/runner/env-capability-census.js +1 -1
  84. package/dist/core/runner/file-history-request.d.ts +26 -0
  85. package/dist/core/runner/file-history-request.js +90 -0
  86. package/dist/core/runner/gate-exit.d.ts +30 -4
  87. package/dist/core/runner/gate-exit.js +28 -7
  88. package/dist/core/runner/permission-rule-lanes.d.ts +11 -6
  89. package/dist/core/runner/permission-rule-lanes.js +55 -48
  90. package/dist/core/runner/persisted-path-rows.d.ts +64 -0
  91. package/dist/core/runner/persisted-path-rows.js +89 -0
  92. package/dist/core/runner/prepare-artifact.d.ts +5 -1
  93. package/dist/core/runner/prepare-artifact.js +9 -3
  94. package/dist/core/runner/prepare-ask-lane.d.ts +6 -4
  95. package/dist/core/runner/prepare-ask-lane.js +3 -3
  96. package/dist/core/runner/prepare-caps-and-workflow.d.ts +39 -13
  97. package/dist/core/runner/prepare-caps-and-workflow.js +58 -29
  98. package/dist/core/runner/prepare-file-history.d.ts +9 -3
  99. package/dist/core/runner/prepare-file-history.js +4 -90
  100. package/dist/core/runner/prepare-gate-stations.d.ts +37 -9
  101. package/dist/core/runner/prepare-gate-stations.js +46 -29
  102. package/dist/core/runner/prepare-hands-readface.d.ts +40 -17
  103. package/dist/core/runner/prepare-hands-readface.js +64 -53
  104. package/dist/core/runner/prepare-inherited-gate.d.ts +30 -23
  105. package/dist/core/runner/prepare-inherited-gate.js +45 -25
  106. package/dist/core/runner/prepare-park-ask.d.ts +6 -4
  107. package/dist/core/runner/prepare-park-ask.js +7 -5
  108. package/dist/core/runner/prepare-policy-chain.d.ts +25 -4
  109. package/dist/core/runner/prepare-policy-chain.js +203 -180
  110. package/dist/core/runner/prepare-protocol-tools.d.ts +28 -0
  111. package/dist/core/runner/prepare-protocol-tools.js +13 -3
  112. package/dist/core/runner/prepare-run-refs.d.ts +6 -6
  113. package/dist/core/runner/prepare-run-refs.js +9 -4
  114. package/dist/core/runner/prepare-safety-scan.d.ts +5 -0
  115. package/dist/core/runner/prepare-safety-scan.js +19 -3
  116. package/dist/core/runner/prepare-suspend-saga.d.ts +5 -5
  117. package/dist/core/runner/prepare-suspend-saga.js +6 -6
  118. package/dist/core/runner/prepare-task.js +56 -24
  119. package/dist/core/runner/prepare-wiring-manifest.d.ts +10 -6
  120. package/dist/core/runner/prepare-wiring-manifest.js +5 -3
  121. package/dist/core/runner/read-root-grant.d.ts +9 -0
  122. package/dist/core/runner/read-root-grant.js +12 -0
  123. package/dist/core/runner/retired-runner-deps.js +1 -0
  124. package/dist/core/runner/run-brain-sinks.js +3 -1
  125. package/dist/core/runner/run-identity-wiring.js +1 -1
  126. package/dist/core/runner/run-leg.js +29 -18
  127. package/dist/core/runner/run-notification-lane.d.ts +3 -0
  128. package/dist/core/runner/run-notification-lane.js +3 -1
  129. package/dist/core/runner/run-telemetry-and-budget-seats.d.ts +2 -2
  130. package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
  131. package/dist/core/runner/run-turn-boundary.js +1 -1
  132. package/dist/core/runner/runtask.d.ts +1 -0
  133. package/dist/core/runner/runtask.js +8 -11
  134. package/dist/core/runner/session-mode-seats.d.ts +48 -0
  135. package/dist/core/runner/session-mode-seats.js +73 -0
  136. package/dist/core/runner/session-rule-policy.js +3 -2
  137. package/dist/core/runner/stream-mode-verb.d.ts +27 -0
  138. package/dist/core/runner/stream-mode-verb.js +19 -0
  139. package/dist/core/runner/turn-attachments.d.ts +3 -3
  140. package/dist/core/runner/turn-attachments.js +1 -1
  141. package/dist/core/runner/write-protection-station.d.ts +7 -1
  142. package/dist/core/runner/write-protection-station.js +6 -3
  143. package/dist/core/runner-deps.d.ts +31 -34
  144. package/dist/core/runtime-caps.d.ts +12 -3
  145. package/dist/core/safety-axis-vocab.d.ts +2 -2
  146. package/dist/core/safety-axis-vocab.js +1 -1
  147. package/dist/core/secret-env.d.ts +30 -58
  148. package/dist/core/secret-env.js +149 -586
  149. package/dist/core/sensitive-path-policy.d.ts +4 -2
  150. package/dist/core/sensitive-path-policy.js +41 -31
  151. package/dist/core/store-contracts/checkpoint-store-contract.js +2 -1
  152. package/dist/core/task-event.d.ts +1 -1
  153. package/dist/core/task-result.d.ts +1 -1
  154. package/dist/core/task-spec.d.ts +41 -89
  155. package/dist/core/task-stream.d.ts +16 -0
  156. package/dist/core/terminal-cause.js +1 -0
  157. package/dist/core/tighten-task-spec.d.ts +2 -2
  158. package/dist/core/tighten-task-spec.js +12 -14
  159. package/dist/core/tool-catalog-entries.js +4 -3
  160. package/dist/core/tool-policy.d.ts +84 -30
  161. package/dist/core/tool-policy.js +76 -16
  162. package/dist/core/tool-registry.d.ts +38 -0
  163. package/dist/core/tool-registry.js +25 -1
  164. package/dist/core/tool-roster.d.ts +17 -2
  165. package/dist/core/tool-roster.js +11 -1
  166. package/dist/core/tool-spec.d.ts +8 -9
  167. package/dist/core/trace.d.ts +18 -6
  168. package/dist/core/types.d.ts +2 -1
  169. package/dist/core/wiring-manifest.d.ts +31 -5
  170. package/dist/core/wiring-manifest.js +28 -1
  171. package/dist/core/write-protect.d.ts +11 -1
  172. package/dist/core/write-protect.js +26 -15
  173. package/dist/engine/execution-env/node-execution-env.d.ts +6 -1
  174. package/dist/engine/execution-env/node-execution-env.js +16 -3
  175. package/dist/engine/harness/agent-harness.js +2 -1
  176. package/dist/engine/harness/types.d.ts +6 -7
  177. package/dist/engine/llm/types.d.ts +2 -4
  178. package/dist/engine/loop/types.d.ts +7 -0
  179. package/dist/engine/lsp/node-lsp-manager.js +1 -1
  180. package/dist/index.d.ts +18 -8
  181. package/dist/index.js +15 -6
  182. package/dist/orchestration/workflow-governance.js +1 -1
  183. package/dist/orchestration/workflow-primitives.d.ts +1 -1
  184. package/dist/orchestration/workflow-size-guideline.js +2 -2
  185. package/dist/stores/file/index.d.ts +5 -3
  186. package/dist/stores/file/session-store.d.ts +8 -2
  187. package/dist/stores/file/session-store.js +5 -5
  188. package/dist/tools/artifact/artifact-tool.d.ts +17 -0
  189. package/dist/tools/artifact/artifact-tool.js +16 -1
  190. package/dist/tools/fs/bash-readonly-classifier.d.ts +28 -7
  191. package/dist/tools/fs/bash-readonly-classifier.js +88 -0
  192. package/dist/tools/fs/containment-face.d.ts +9 -3
  193. package/dist/tools/fs/containment-face.js +2 -0
  194. package/dist/tools/fs/file-read-check.d.ts +50 -0
  195. package/dist/tools/fs/file-read-check.js +79 -0
  196. package/dist/tools/fs/fs-bash.d.ts +3 -3
  197. package/dist/tools/fs/fs-read.d.ts +1 -0
  198. package/dist/tools/fs/fs-search-tools.d.ts +2 -2
  199. package/dist/tools/fs/fs-search-tools.js +4 -4
  200. package/dist/tools/fs/fs-shared.js +20 -6
  201. package/dist/tools/fs/fs-write.d.ts +4 -3
  202. package/dist/tools/fs/fs-write.js +9 -9
  203. package/dist/tools/fs/index.d.ts +39 -3
  204. package/dist/tools/fs/index.js +38 -15
  205. package/dist/tools/fs/read-deny-home.d.ts +93 -0
  206. package/dist/tools/fs/read-deny-home.js +225 -0
  207. package/dist/tools/fs/read-deny.d.ts +176 -34
  208. package/dist/tools/fs/read-deny.js +268 -61
  209. package/dist/tools/fs/safety.d.ts +6 -1
  210. package/dist/tools/fs/safety.js +18 -5
  211. package/dist/tools/fs/search.d.ts +3 -0
  212. package/dist/tools/fs/search.js +47 -9
  213. package/dist/tools/fs/shell-read-check.d.ts +52 -13
  214. package/dist/tools/fs/shell-read-check.js +199 -20
  215. package/dist/tools/fs/shell-read-establish.d.ts +7 -3
  216. package/dist/tools/fs/shell-read-establish.js +134 -21
  217. package/dist/tools/fs/shell-read-identity.d.ts +7 -0
  218. package/dist/tools/fs/shell-read-identity.js +21 -0
  219. package/dist/tools/fs/shell-read-judge.d.ts +92 -32
  220. package/dist/tools/fs/shell-read-judge.js +43 -18
  221. package/dist/tools/fs/shell-read-plan.d.ts +4 -0
  222. package/dist/tools/fs/shell-read-plan.js +26 -4
  223. package/dist/tools/fs/shell-read-write-targets.d.ts +73 -0
  224. package/dist/tools/fs/shell-read-write-targets.js +173 -0
  225. package/package.json +1 -1
  226. package/test/export-surface.snapshot.json +117 -11
  227. package/wire-changes/core@7.34.0.json +2621 -0
  228. package/wire-changes/core@7.35.0.json +584 -0
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * PrepareTask's INHERITED-GATE phase, verbatim from the driver: the live/seed fold of the
3
- * chain this run inherits (ancestor rules rev-monotonic per (session, principal), shellGate by max rank, the
4
- * re-supplied parent constraints with their rebuilt denial trackers, the auto-mode intent, the org-admission
5
- * freeze with its tighten-only intersection and the monotonic governed bit), the effective shellGate against the
3
+ * chain this run inherits (ancestor rules rev-monotonic per (session, principal), the shell floor, the
4
+ * re-supplied parent constraints with their rebuilt denial trackers, the permission mode's live seat, the org-admission
5
+ * freeze with its tighten-only intersection and the monotonic governed bit), the effective shell floor against the
6
6
  * spec, the three cells later phases fill for the children's chain (own session rules, own admitted org scopes,
7
7
  * own org verdict), the checkpoint-section closures the suspend serializer reads (face / org / F-012 stamps), the
8
8
  * FROZEN ask and question seats (spec over deps), the parent SPEC seat the children inherit, the two delegation refs the memory phase binds late, the ONE
@@ -44,9 +44,10 @@ import type { DelegationContentSafety } from "../memory-engine/delegation-proven
44
44
  import { type SessionPermissionRules } from "../session-policy-store.js";
45
45
  import type { SessionStore } from "../session.js";
46
46
  import { type OnAsk } from "../tool-policy.js";
47
- import type { ApproverPosture, RunnerDeps, RuntimeCaps, ShellGateDoctrine, TaskEvent, TaskSpec, ToolExecuteContext, ToolSpec } from "../types.js";
47
+ import type { PermissionMode, RunnerDeps, RuntimeCaps, ShellGateDoctrine, TaskEvent, TaskSpec, ToolExecuteContext, ToolSpec } from "../types.js";
48
+ import { PermissionModeController } from "../mode-policy.js";
48
49
  import type { ActiveSkillScope } from "./active-skill-scope.js";
49
- import type { InheritedGate, Prepared, PrepareResume, RunInternals, StopForDenialLimit, ToolFaceSnapshot } from "./contracts.js";
50
+ import type { InheritedGate, Prepared, PrepareResume, RunInternals, StopForDenialLimit, ToolFaceSnapshot, WriteFaceSeat } from "./contracts.js";
50
51
  export interface PrepareInheritedGateInput {
51
52
  /** borrowed-readonly — the REBOUND spec. Read: `shellGate` (the own doctrine the chain fold tightens), `durableApproval`
52
53
  * (the mandate tests + the children's copy), `onAsk`/`onQuestion` (the frozen seats), `handsReadOnly` / `interactiveTools`
@@ -65,10 +66,10 @@ export interface PrepareInheritedGateInput {
65
66
  /** borrowed-readonly — the trusted spawn-side channel: `inheritedGate` (the LIVE half of the chain fold), `ownOrgAdmissionRef`
66
67
  * (the same-session continuation's freeze), `delegationProvenance` (the F-012 stamp), and the identity / peer / notification
67
68
  * seats the ctx enrichment forwards. Never mutated. */
68
- internals: Pick<RunInternals, "inheritedGate" | "ownOrgAdmissionRef" | "delegationProvenance" | "memoryCaptureAncestors" | "parentTaskId" | "parentSessionId" | "rootSessionId" | "placementRoot" | "explicitAgentName" | "peerSelfRef" | "peerInboundChainRef" | "onTaskNotification" | "onSubagentSpawn" | "insideFork" | "questionFaceStripped"> | undefined;
69
+ internals: Pick<RunInternals, "inheritedGate" | "sessionModeSeats" | "ownOrgAdmissionRef" | "delegationProvenance" | "memoryCaptureAncestors" | "parentTaskId" | "parentSessionId" | "rootSessionId" | "placementRoot" | "explicitAgentName" | "peerSelfRef" | "peerInboundChainRef" | "onTaskNotification" | "onSubagentSpawn" | "insideFork" | "questionFaceStripped"> | undefined;
69
70
  /** borrowed-readonly — the resume leg, or undefined on a fresh one: `seed.inheritedGate` is the CHECKPOINT half of the chain
70
71
  * fold (the trust floor the live half may only tighten), `seed.readFace` the hands-less re-park's carried section. */
71
- resume: Pick<PrepareResume, "seed"> | undefined;
72
+ resume: Pick<PrepareResume, "seed" | "outcome"> | undefined;
72
73
  /** borrowed-readonly — the session store's fork face: `fork` / `release` are bound into the ctx's `hostSessionFork` (present
73
74
  * only when the store can fork). */
74
75
  sessions: Pick<SessionStore, "fork" | "release">;
@@ -95,10 +96,9 @@ export interface PrepareInheritedGateInput {
95
96
  promptProfile: ToolExecuteContext["promptProfile"];
96
97
  /** borrowed-readonly — the resolved interaction posture (ctx seat; absent ⇒ no key). */
97
98
  resolvedInteractionPosture: ToolExecuteContext["interactionPosture"];
98
- /** borrowed-readonly — the task's own auto-mode intent seat, screened and snapshotted before the first await. */
99
- autoModeSeat: boolean;
100
- /** borrowed-readonly — the task's own approver-posture seat, screened and snapshotted before the first await. */
101
- approverPostureSeat: ApproverPosture | undefined;
99
+ /** borrowed-readonly — the task's own permission-mode key, screened and snapshotted before the first await (undefined =
100
+ * declared nothing: a root runs `default`, a child inherits). */
101
+ permissionModeSeat: PermissionMode | undefined;
102
102
  /** borrowed-readonly — whether an execution env is wired at all (the full-shell predicate's first term). */
103
103
  handsEnabled: boolean;
104
104
  /** borrowed-readonly — the nested-usage sink the ctx forwards. */
@@ -121,8 +121,8 @@ export interface PrepareInheritedGateInput {
121
121
  }) => void;
122
122
  /** borrowed-readonly — see `requestReview`. */
123
123
  requestStopAfterTurn: () => void;
124
- /** borrowed-readonly — see `requestReview`. */
125
- enterPlanMode: () => void;
124
+ /** borrowed-readonly — see `requestReview`; a steer of the leg's mode seat into `plan`. */
125
+ enterPlanMode: () => Promise<void>;
126
126
  /** borrowed-readonly — the leg's reminder mark (ctx seat). */
127
127
  reminderMark: string;
128
128
  /** borrowed-readonly — the leg's disclosure counters (ctx seat; the outlets that bump them are not in this phase). */
@@ -163,8 +163,8 @@ export interface PrepareInheritedGateInput {
163
163
  observersActive: () => boolean;
164
164
  /** borrowed-readonly — LATE-BOUND: the hands mount's resolved read face (undefined until/unless hands mount). */
165
165
  resolvedReadFace: () => ContainmentFace | undefined;
166
- /** borrowed-readonly — LATE-BOUND: the hands mount's resolved WRITE face (the read seat's twin). */
167
- resolvedWriteFace: () => ContainmentFace | undefined;
166
+ /** borrowed-readonly — LATE-BOUND: the hands mount's WRITE face seat (the read seat's twin; read per call, and whether its fence is declared). */
167
+ resolvedWriteFace: () => WriteFaceSeat | undefined;
168
168
  /** borrowed-readonly — LATE-BOUND: the normalized deny additions in force (empty until the hands mount resolves them). */
169
169
  readDenyAdditionsNormalized: () => ReadonlyArray<{
170
170
  pattern: string;
@@ -173,7 +173,7 @@ export interface PrepareInheritedGateInput {
173
173
  /** borrowed-readonly — LATE-BOUND: the hands-less legs' resolved face (the carrier's second source). */
174
174
  handsLessResolvedFace: () => ContainmentFace | undefined;
175
175
  /** borrowed-readonly — LATE-BOUND: the hands-less legs' resolved WRITE face (same second source, write seat). */
176
- handsLessResolvedWriteFace: () => ContainmentFace | undefined;
176
+ handsLessResolvedWriteFace: () => WriteFaceSeat | undefined;
177
177
  /** borrowed-readonly — LATE-BOUND: the adopted center artifact (ctx `centerArtifactDigest` / `centerSourceRevision`). */
178
178
  centerAdoption: () => {
179
179
  artifact: PromptEpochArtifact;
@@ -189,22 +189,29 @@ export interface PrepareInheritedGateResult {
189
189
  seedInheritedGate: PrepareResume["seed"]["inheritedGate"];
190
190
  /** owned — the rev-monotonic fold of the two halves' ancestor rules (live replaces per (session, principal) only at ≥ rev). */
191
191
  inheritedAncestorRules: InheritedGate["ancestorRules"];
192
- /** owned — the max-rank fold of the two halves' shellGate doctrines (before the spec's own is applied). */
192
+ /** owned — the chain's shell floor (live or seed; the seed's migrated word), before the spec's own is applied. */
193
193
  inheritedShellGate: InheritedGate["shellGate"];
194
194
  /** owned — the live parent constraints with a fresh denial tracker attached per rebuilt decider. */
195
195
  inheritedParentConstraints: NonNullable<InheritedGate["parentConstraints"]>[number][] | undefined;
196
- /** owned — the auto-mode INTENT (own seat ∨ live chain ∨ checkpoint bit); the arming site judges the other two arms. */
197
- autoModeIntent: boolean;
198
- /** owned — the resolved approver POSTURE (own seat, else the live chain's, else the checkpoint's); rendered, never enforced. */
199
- approverPosture: ApproverPosture | undefined;
196
+ /** owned — the leg's live permission-mode seat: the spec's request clamped under the chain's ceiling (a parent's live
197
+ * seat, or the checkpoint's recorded word), folded against the arming facts the caps phase binds later. Every mode
198
+ * consumer reads `current` at its own call; the steer verb writes it. */
199
+ permissionMode: PermissionModeController;
200
+ /** owned — the leg's commit of its mode seats, called by the driver once prepare succeeded (never on a failed one):
201
+ * makes this leg its SESSION's current leg and holds the leg's own engine ceiling until `legSignal` aborts, so each
202
+ * move of that ceiling re-judges this leg. */
203
+ commitModeSeats: (legSignal: AbortSignal) => void;
204
+ /** owned — the leg has STOPPED (the run leg's teardown, after its loop settled): from here its children read the
205
+ * session's current leg. Idempotent; a leg that never reaches it keeps answering its children itself. */
206
+ endModeCeiling: () => void;
200
207
  /** owned — the seed ∩ live admitted org scopes (one side absent ⇒ the other; both absent ⇒ undefined). */
201
208
  inheritedAdmittedOrgScopes: readonly string[] | undefined;
202
209
  /** owned — the prior own org verdict: checkpoint ∩ same-session ref (either alone stands; neither ⇒ undefined). */
203
210
  priorOwnOrgVerdict: OwnOrgAdmissionVerdict | undefined;
204
211
  /** owned — the monotonic governed-provenance bit for this leg. */
205
212
  orgGovernedProvenance: boolean;
206
- /** owned — the spec's own shellGate tightened by the inherited doctrine. */
207
- effectiveShellGate: ShellGateDoctrine;
213
+ /** owned — the operator's shell floor in force (the spec's, or the chain's); undefined = no floor. */
214
+ effectiveShellGate: ShellGateDoctrine | undefined;
208
215
  /** borrowed-mutable — THIS task's own session-rule snapshot for its children's chain. Writers (R-3): the policy-chain
209
216
  * station's session-policy read, once per leg, when a store is wired and the task carries its own sessionId. Read by
210
217
  * `inheritedGateForChildren` at spawn time. */
@@ -5,10 +5,14 @@ import { createPreToolUseConstraintPolicy } from "../hooks.js";
5
5
  import { continuesLineage } from "../session-policy-store.js";
6
6
  import { StubExecutionEnv } from "../stub-env.js";
7
7
  import { askApproverIdentity, durableMandateSourceOf } from "../tool-policy.js";
8
+ import { deliverEngineNotice } from "../types.js";
9
+ import { PermissionModeController, modeRequestAfterResume } from "../mode-policy.js";
10
+ import { SessionModeSeats } from "./session-mode-seats.js";
11
+ import { migrateLegacyModeSeed } from "../checkpoint-store.js";
8
12
  import { attachRebuiltDenialTrackers, createDenialLimitStop } from "./denial-limit-arms.js";
9
13
  import { asThrownError } from "../thrown-value.js";
10
14
  export function prepareInheritedGate(input) {
11
- const { spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, toolFaceSnapshot, mountsCallerTool, promptProfile, resolvedInteractionPosture, autoModeSeat, approverPostureSeat, handsEnabled, reportUsage, harnessRef, skillScope, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun } = input;
15
+ const { spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, toolFaceSnapshot, mountsCallerTool, promptProfile, resolvedInteractionPosture, permissionModeSeat, handsEnabled, reportUsage, harnessRef, skillScope, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun } = input;
12
16
  const liveInheritedGate = internals?.inheritedGate;
13
17
  const seedInheritedGate = resume?.seed.inheritedGate;
14
18
  const inheritedAncestorRules = (() => {
@@ -28,19 +32,36 @@ export function prepareInheritedGate(input) {
28
32
  const extras = liveRules.filter((l) => !seedRules.some((s) => s.sessionId === l.sessionId && s.principal === l.principal));
29
33
  return [...merged, ...extras];
30
34
  })();
31
- const shellGateRank = { off: 0, classify: 1, always: 2 };
32
- const liveShellGate = liveInheritedGate?.shellGate;
33
- const seedShellGate = seedInheritedGate?.shellGate;
34
- const inheritedShellGate = liveShellGate === undefined
35
- ? seedShellGate
36
- : seedShellGate === undefined
37
- ? liveShellGate
38
- : shellGateRank[liveShellGate] >= shellGateRank[seedShellGate]
39
- ? liveShellGate
40
- : seedShellGate;
35
+ const modeSeed = migrateLegacyModeSeed(seedInheritedGate);
36
+ if (modeSeed.migrated !== undefined) {
37
+ deliverEngineNotice(deps.onNotice, {
38
+ code: "resume.legacy_mode_seed_migrated",
39
+ message: `the resumed checkpoint row carried pre-mode keys (${modeSeed.migrated.droppedKeys.join(", ")}); read once into ${modeSeed.migrated.permissionMode !== undefined ? `permissionMode: "${modeSeed.migrated.permissionMode}"` : "no mode of its own (the chain's ceiling stands)"}${modeSeed.shellGate !== undefined ? ' with the shell floor "always" kept' : ""} — the next suspend writes the one key; from 7.35.0 a row still carrying these keys is refused`,
40
+ detail: { migrated: { ...(modeSeed.migrated.permissionMode !== undefined ? { permissionMode: modeSeed.migrated.permissionMode } : {}), droppedKeys: [...modeSeed.migrated.droppedKeys] }, sessionId, runId },
41
+ });
42
+ }
43
+ const inheritedShellGate = liveInheritedGate?.shellGate ?? modeSeed.shellGate;
41
44
  const inheritedParentConstraints = attachRebuiltDenialTrackers(liveInheritedGate?.parentConstraints, deps.autoMode?.denialLimit);
42
- const autoModeIntent = autoModeSeat || liveInheritedGate?.autoModeRequested === true || seedInheritedGate?.autoModeRequested === true;
43
- const approverPosture = [approverPostureSeat, liveInheritedGate?.approverPosture, seedInheritedGate?.approverPosture].find((w) => w !== undefined);
45
+ const parentSeat = liveInheritedGate?.permissionModeCeiling;
46
+ const ceiling = parentSeat ?? liveInheritedGate?.permissionMode;
47
+ const announceModeFold = (receipt) => {
48
+ if (receipt.foldedBy === undefined)
49
+ return;
50
+ const requested = receipt.requested ?? "default";
51
+ const because = receipt.foldedBy === "operator_deny" ? "the deployment denies it for this principal" : receipt.foldedBy === "face_absent" ? "no auto-mode classifier face is wired on this deployment" : `the parent leg's mode is the ceiling a child's declaration is clamped under`;
52
+ const message = `permission mode "${requested}" is not available on this leg (${because}) — it runs under "${receipt.effective}"`;
53
+ deliverEngineNotice(deps.onNotice, { code: "config.permission_mode_unavailable", message, detail: { requested, effective: receipt.effective, by: receipt.foldedBy, sessionId, runId } });
54
+ if (receipt.foldedBy === "inherited_ceiling" && parentSeat !== undefined) {
55
+ deliverEngineNotice(deps.onNotice, { code: "config.permission_mode_unavailable", message: `${message} (a child leg, ${sessionId})`, detail: { requested, effective: receipt.effective, by: receipt.foldedBy, sessionId: parentSeat.sessionId, childSessionId: sessionId, runId } });
56
+ }
57
+ };
58
+ const permissionMode = new PermissionModeController(modeRequestAfterResume(permissionModeSeat, modeSeed, resume?.outcome), ceiling, { onFold: announceModeFold, ...(modeSeed.prePlanMode !== undefined ? { prePlanMode: modeSeed.prePlanMode } : {}) });
59
+ announceModeFold(permissionMode.receipt());
60
+ const { ceiling: legModeCeiling, commit: commitLegModeCeiling, end: endModeCeiling } = (internals?.sessionModeSeats ?? new SessionModeSeats()).legCeiling(sessionId, permissionMode);
61
+ const commitModeSeats = (legSignal) => {
62
+ commitLegModeCeiling();
63
+ parentSeat?.hold?.(permissionMode, legSignal);
64
+ };
44
65
  const liveAdmittedOrg = liveInheritedGate?.admittedOrgScopes;
45
66
  const seedAdmittedOrg = seedInheritedGate?.admittedOrgScopes;
46
67
  const inheritedAdmittedOrgScopes = liveAdmittedOrg === undefined ? seedAdmittedOrg : seedAdmittedOrg === undefined ? liveAdmittedOrg : liveAdmittedOrg.filter((s) => seedAdmittedOrg.includes(s));
@@ -64,8 +85,7 @@ export function prepareInheritedGate(input) {
64
85
  deps.compliancePostureResolver !== undefined ||
65
86
  inheritedOrgGoverned ||
66
87
  priorOwnOrgVerdict !== undefined;
67
- const specShellGate = spec.shellGate ?? "off";
68
- const effectiveShellGate = inheritedShellGate !== undefined && shellGateRank[inheritedShellGate] > shellGateRank[specShellGate] ? inheritedShellGate : specShellGate;
88
+ const effectiveShellGate = spec.shellGate ?? inheritedShellGate;
69
89
  const ownSessionRulesRef = {};
70
90
  const ancestorSessionRulesRef = { current: new Map() };
71
91
  const ancestorRulesNow = () => inheritedAncestorRules === undefined ? undefined : inheritedAncestorRules.map((a, i) => ancestorSessionRulesRef.current.get(i) ?? a);
@@ -92,8 +112,8 @@ export function prepareInheritedGate(input) {
92
112
  };
93
113
  const faceCheckpointState = () => faceCheckpointSection() !== undefined;
94
114
  const writeFaceCheckpointSection = () => {
95
- const face = input.resolvedWriteFace() ?? input.handsLessResolvedWriteFace();
96
- return face === "open" ? { face } : undefined;
115
+ const seat = input.resolvedWriteFace() ?? input.handsLessResolvedWriteFace();
116
+ return seat === undefined ? undefined : seat.inForce() === "open" ? { face: "open" } : seat.fenced ? { face: "roots" } : undefined;
97
117
  };
98
118
  const f012CheckpointState = () => (inheritedParentConstraints?.length ?? 0) > 0 ||
99
119
  seedInheritedGate?.constraintChain !== undefined ||
@@ -114,7 +134,7 @@ export function prepareInheritedGate(input) {
114
134
  const delegationSettlementRef = {};
115
135
  const delegationSettlementForChildren = () => delegationSettlementRef.current;
116
136
  const inheritedGateForChildren = () => {
117
- const autoModeDecider = input.autoModeDecider();
137
+ const autoModeDecider = permissionMode.current === "auto" ? input.autoModeDecider() : undefined;
118
138
  const autoModeDenialTracking = input.autoModeDenialTracking();
119
139
  const autoModeArming = input.autoModeArming();
120
140
  const ancestorRules = [
@@ -142,7 +162,7 @@ export function prepareInheritedGate(input) {
142
162
  ...(durableMandate ? { durableMandate: true } : {}),
143
163
  ...(contentMandate ? { contentMandate: true } : {}),
144
164
  ...(autoModeDecider !== undefined
145
- ? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}), ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
165
+ ? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}), ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}), liveMode: legModeCeiling } }
146
166
  : {}),
147
167
  },
148
168
  ]
@@ -158,7 +178,7 @@ export function prepareInheritedGate(input) {
158
178
  ...(durableMandate ? { durableMandate: true } : {}),
159
179
  ...(contentMandate ? { contentMandate: true } : {}),
160
180
  ...(autoModeDecider !== undefined
161
- ? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}), ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
181
+ ? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}), ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}), liveMode: legModeCeiling } }
162
182
  : {}),
163
183
  },
164
184
  ]
@@ -166,16 +186,16 @@ export function prepareInheritedGate(input) {
166
186
  ];
167
187
  return {
168
188
  ...(ancestorRules.length > 0 ? { ancestorRules } : {}),
169
- ...(effectiveShellGate !== "off" ? { shellGate: effectiveShellGate } : {}),
170
- ...(autoModeIntent ? { autoModeRequested: true } : {}),
171
- ...(approverPosture !== undefined ? { approverPosture } : {}),
189
+ ...(effectiveShellGate !== undefined ? { shellGate: effectiveShellGate } : {}),
190
+ permissionMode: permissionMode.current,
191
+ permissionModeCeiling: legModeCeiling,
172
192
  ...(parentConstraints.length > 0 ? { parentConstraints } : {}),
173
193
  admittedOrgScopes: memoryAdmittedOrgScopesRef.current,
174
194
  ...(orgGovernedProvenance ? { orgAdmissionGoverned: true } : {}),
175
195
  };
176
196
  };
177
197
  const carrierReadFace = () => input.resolvedReadFace() ?? input.handsLessResolvedFace();
178
- const carrierWriteFace = () => input.resolvedWriteFace() ?? input.handsLessResolvedWriteFace();
198
+ const carrierWriteFace = () => (input.resolvedWriteFace() ?? input.handsLessResolvedWriteFace())?.inForce();
179
199
  const fullShellReachable = handsEnabled &&
180
200
  !(executionEnv instanceof StubExecutionEnv) &&
181
201
  spec.handsReadOnly !== true &&
@@ -281,5 +301,5 @@ export function prepareInheritedGate(input) {
281
301
  ...(spec.enablePlanMode === true ? { enterPlanMode } : {}),
282
302
  };
283
303
  };
284
- return { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, approverPosture, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, ancestorSessionRulesRef, ancestorRulesNow, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, writeFaceCheckpointSection, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx };
304
+ return { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, permissionMode, commitModeSeats, endModeCeiling, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, ancestorSessionRulesRef, ancestorRulesNow, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, writeFaceCheckpointSection, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx };
285
305
  }
@@ -29,7 +29,7 @@ import type { RunnerDeps, RuntimeCaps, ShellGateDoctrine, TaskSpec } from "../ty
29
29
  import type { CwdRef } from "../../tools/fs/fs-shared.js";
30
30
  import type { AdvertisedWritableDirs } from "./advertised-writable-dirs.js";
31
31
  import { type ContentAskBinding } from "./content-ask-bindings.js";
32
- import type { AskLane, ParkAsk, Prepared, SuspendSaga } from "./contracts.js";
32
+ import type { AskLane, IrreversibilityTier, ParkAsk, Prepared, SuspendSaga } from "./contracts.js";
33
33
  import type { createRuleOffersOf } from "./permission-rule-lanes.js";
34
34
  import { type ToolRosterDeltaSeat } from "../tool-roster.js";
35
35
  export interface PrepareParkAskInput {
@@ -112,10 +112,12 @@ export interface PrepareParkAskInput {
112
112
  /** borrowed-mutable — the run-scoped remote-lifecycle failure log. Writer here: a refused `suspendVM` (`push`). */
113
113
  remoteEnvFailures: Prepared["remoteEnvFailures"];
114
114
  /** borrowed-readonly — the shell-seat provenance set: the shell-running tools whose tier is the engine's shell seat's, not a
115
- * deployment mark (the risk descriptor's `shellGated` is the gated tool's membership). */
115
+ * deployment mark (the risk descriptor's `shellGated` is the membership of the name the call's tier is read under). */
116
116
  shellGatedTools: ReadonlySet<string>;
117
- /** borrowed-readonly — the effective shell-gate doctrine persisted on the descriptor. */
118
- effectiveShellGate: ShellGateDoctrine;
117
+ /** borrowed-readonly — the per-tool tier, read only for the name the call's tier seat is read under (as at the gate). */
118
+ irreversibilityTier: IrreversibilityTier;
119
+ /** borrowed-readonly — the operator's shell floor (`"always"`), persisted on a shell-gated descriptor; undefined = no floor. */
120
+ effectiveShellGate: ShellGateDoctrine | undefined;
119
121
  /** borrowed-readonly — the EFFECTIVE durable-approval opt-in (the caller's, or the synthesized mandate scope): picks the
120
122
  * gate kind, the scope and the ttl. */
121
123
  durableApproval: TaskSpec["durableApproval"];
@@ -15,7 +15,7 @@ import { checkpointScopeOf } from "./checkpoint-scope.js";
15
15
  import { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js";
16
16
  import { DEFAULT_UNATTENDED_APPROVAL_TTL_MS, publishCommittedSuspend, sanitizedTtlMs } from "./park-commit.js";
17
17
  import { remoteEnvFailureNote } from "./remote-env-retry.js";
18
- import { callFaceSeat, parkedToolIdentity, parkedToolFace } from "../tool-roster.js";
18
+ import { callFaceSeat, firstNamed, parkedToolIdentity, parkedToolFace, ruleNamesOf } from "../tool-roster.js";
19
19
  class ParkRefusal extends Error {
20
20
  constructor(message, options) {
21
21
  super(message, options);
@@ -26,7 +26,7 @@ const wordlessDemand = (toolName) => {
26
26
  throw new Error(`a real-approval demand for "${toolName}" reached the park with no origin word — the origin stamp precedes every park`);
27
27
  };
28
28
  export function prepareParkAsk(input) {
29
- const { askLane, saga, spec, deps, sessionId, checkpointStore, toolRosterDeltas, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, advertisedWritableDirs, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, now, humanReviewRef, abortController, harness, pausedRef } = input;
29
+ const { askLane, saga, spec, deps, sessionId, checkpointStore, toolRosterDeltas, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, advertisedWritableDirs, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, now, humanReviewRef, abortController, harness, pausedRef } = input;
30
30
  if (askLane === undefined || saga === undefined)
31
31
  return { parkAsk: undefined };
32
32
  const { composedCallSignal, approvalPreviewOf } = askLane;
@@ -234,6 +234,7 @@ export function prepareParkAsk(input) {
234
234
  remoteHandle = parkOnlyHandle(parkOnlyRemoteEnv);
235
235
  }
236
236
  token = mintCheckpointToken();
237
+ const tierSeat = firstNamed(irreversibilityTier, ruleNamesOf(req));
237
238
  const riskDescriptor = buildRiskDescriptor({
238
239
  toolName: req.toolName,
239
240
  args: parkedArgs,
@@ -241,8 +242,8 @@ export function prepareParkAsk(input) {
241
242
  ...(shadowedRule !== undefined ? { shadowedRule } : {}),
242
243
  ...(probeReason !== undefined ? { probeReason } : {}),
243
244
  ...(probeCause !== undefined ? { probeCause } : {}),
244
- shellGated: shellGatedTools.has(req.toolName),
245
- shellGateDoctrine: effectiveShellGate,
245
+ shellGated: tierSeat !== undefined && shellGatedTools.has(tierSeat.name),
246
+ ...(effectiveShellGate !== undefined ? { shellGateDoctrine: effectiveShellGate } : {}),
246
247
  });
247
248
  gate =
248
249
  safety !== undefined || rowRealApproval !== undefined
@@ -281,6 +282,7 @@ export function prepareParkAsk(input) {
281
282
  const clearanceFacts = {
282
283
  ...(carry?.mandated === true || storedShapeMandated ? { mandated: true } : {}),
283
284
  ...(carry?.mandate !== undefined && !storedShapeMandated ? { mandate: carry.mandate } : {}),
285
+ ...(carry?.authoredBy === "deployment" ? { authoredBy: "deployment" } : {}),
284
286
  ...(rowRealApproval !== undefined ? { requiresRealApproval: true } : {}),
285
287
  ...(shadowedRule !== undefined ? { persistedRuleShadowed: shadowedRule } : {}),
286
288
  ...(askDecisionReason !== undefined ? { decisionReason: askDecisionReason } : {}),
@@ -315,7 +317,7 @@ export function prepareParkAsk(input) {
315
317
  ...(rowRealApproval !== undefined ? { requiresRealApproval: true } : {}),
316
318
  ...askMandateMember(clearanceFacts),
317
319
  ...askCarryRowMembers(carry),
318
- ...ruleOffersOf(req.toolName, parkedArgs, clearanceFacts),
320
+ ...ruleOffersOf(req, parkedArgs, clearanceFacts),
319
321
  boundInputHash: boundInputHashOf(parkedArgs),
320
322
  batchToolCallIds,
321
323
  completedCallIds,
@@ -32,7 +32,10 @@ import type { CwdRef } from "../../tools/fs/fs-shared.js";
32
32
  import type { ReadDenyMatcher } from "../../tools/fs/read-deny.js";
33
33
  import { type ActiveSkillScope } from "./active-skill-scope.js";
34
34
  import type { InheritedGate, IrreversibilityTier, PrepareResume, RunInternals, StopForDenialLimit } from "./contracts.js";
35
+ import { type Arbitration } from "../ask-origin.js";
36
+ import { type ModeGateSeats, type PermissionModeController } from "../mode-policy.js";
35
37
  import { createRuleOffersOf, type PermissionRuleLanes } from "./permission-rule-lanes.js";
38
+ import type { ToolCallLike } from "../tool-registry.js";
36
39
  export interface PreparePolicyChainInput {
37
40
  /** borrowed-readonly — the REBOUND spec. Read: `sessionId` / `principal` (the session-rule read and the lanes' identity),
38
41
  * `hooks` (spec over deps), `durableApproval` / `checkpointStore` (the mandate-park facility test and the sandbox arming's park prerequisites), `taskId` (the late-ask observer's detail).
@@ -54,6 +57,9 @@ export interface PreparePolicyChainInput {
54
57
  hostTaskId: string;
55
58
  /** borrowed-readonly — the FINAL task root (path rules resolve against it; the lanes' and the offers' root). */
56
59
  taskRootFinal: string;
60
+ /** borrowed-readonly — the leg's canonical write roots beyond the task root (`additionalDirectories` + advertised writable
61
+ * dirs): the `acceptEdits` mode gate allows writes inside the root and these, and asks outside them all. */
62
+ additionalRootsCanonical: readonly string[];
57
63
  /** borrowed-readonly — the run's resolved env (path rules resolve in it; the sandbox declaration is read off it). */
58
64
  executionEnv: ExecutionEnv;
59
65
  /** borrowed-readonly — the frozen preflight: `toolPolicy` (the caller slot) and `basePolicyForResumeEdit` (the lock-aware
@@ -83,6 +89,8 @@ export interface PreparePolicyChainInput {
83
89
  handsCwdRef: CwdRef | undefined;
84
90
  /** borrowed-readonly — the compiled read-deny judge, or undefined (the offer factory's directory negative control). */
85
91
  readDenyMatcher: ReadDenyMatcher | undefined;
92
+ /** borrowed-readonly — the run's one notice for a person's rule store that could not be read (`ruleStoreUnreadableNotice`). */
93
+ announceRuleStoreSkipped: (at: "prepare" | "call") => void;
86
94
  /** borrowed-readonly — whether the question tool mounted (the lanes' question-tool exclusion). */
87
95
  questionToolMounted: boolean;
88
96
  /** borrowed-readonly — the resolved per-principal entitlements; only `forceDurableGate` (the mandate-park facility and
@@ -117,8 +125,15 @@ export interface PreparePolicyChainInput {
117
125
  hookEnvSource: unknown;
118
126
  /** borrowed-readonly — the own-hook crash reporter (the timeout seat's bad-value disclosure). */
119
127
  notifyOwnHookCrash: (err: unknown) => void;
120
- /** borrowed-readonly — this task's own classifier instance, or undefined (the pass-through test's decider term). */
121
- autoModeDecider: AutoModeDecider | undefined;
128
+ /** borrowed-readonly — LATE-BOUND: this task's own classifier instance (the pass-through test's decider term), read at chain
129
+ * assembly (the arming runs after this phase, and again on a steer into `auto`). */
130
+ autoModeDecider: () => AutoModeDecider | undefined;
131
+ /** borrowed-readonly — the leg's live permission-mode seat: the mode gate policy layer and the inherited stations' arbitration
132
+ * read `current` per call. */
133
+ permissionMode: PermissionModeController;
134
+ /** borrowed-readonly — the task's scratchpad directory (the mode write gate's one exemption), or undefined. */
135
+ scratchpadDir: string | undefined;
136
+ /** borrowed-readonly — the leg's live roster seat; the mode write gate reads `current` per call. */ toolRosterDeltas: NonNullable<ModeGateSeats["roster"]>;
122
137
  /** borrowed-readonly — the run's ONE typed stop for a denial-limit bound (the fallback settlements call it). */
123
138
  stopForDenialLimit: StopForDenialLimit;
124
139
  /** borrowed-readonly — the effective delegation facts; only `isDelegatedChild` (the ask source identity). */
@@ -161,6 +176,12 @@ export interface PreparePolicyChainResult {
161
176
  /** borrowed-mutable — the inherited-unavailable marker channel. Writers: the inherited arms here (mark); the gate station
162
177
  * (the lifecycle-end sweep) and the park lane's consumers (delete on consumption). */
163
178
  inheritedUnavailableAsks: Set<string>;
179
+ /** owned — the inherited stations' MODE ARBITRATIONS by tool call (a release or a refusal made inside the fold,
180
+ * where an ancestor's ask is arbitrated before its frozen approver). Writers: the three inherited stations here; the gate's
181
+ * exit reads it onto the disposition and the gate station deletes it at the call's end. */
182
+ ancestorArbitrations: Map<string, Exclude<Arbitration, {
183
+ kind: "ask";
184
+ }>>;
164
185
  /** borrowed-mutable — the grant record. Writers: the inherited arms here (record a clean allow at a live approver);
165
186
  * the gate station (consume on reuse, sweep at settlement). */
166
187
  inheritedAskGrants: Map<string, {
@@ -179,7 +200,7 @@ export interface PreparePolicyChainResult {
179
200
  isDelegatedChild?: true;
180
201
  };
181
202
  /** owned — the engine-judged risk axes for an ask, from the same resolved sources the safety tightens use. */
182
- riskAxesOf: (toolName: string) => {
203
+ riskAxesOf: (call: Pick<ToolCallLike, "toolName" | "face">) => {
183
204
  riskAxes?: {
184
205
  irreversible?: boolean;
185
206
  egress?: boolean;
@@ -194,7 +215,7 @@ export interface PreparePolicyChainResult {
194
215
  /** owned — whether the sandbox-admission mode armed (declared isolation with its park prerequisites). */
195
216
  sandboxAdmissionArmed: boolean;
196
217
  /** owned — the NOT-CONTAINED classification: a call the declared sandbox does not contain. */
197
- sandboxBoundaryCapable: (toolName: string) => boolean;
218
+ sandboxBoundaryCapable: (call: Pick<ToolCallLike, "toolName" | "face">) => boolean;
198
219
  /** owned — the admission disclosure's trace emitter (the gate station emits it once the fold settles). */
199
220
  emitSandboxAdmitted: (info: {
200
221
  toolCallId: string;