policy: resolve every knob consumer through the shared override chain
Review fixes (ds-review-bot warnings on #623): - One chain, every consumer: the override resolution (own post-seed switches ?? header baseline, closed-vocabulary validated) moves into pure exports (sandboxOverrideOf / approvalOverrideOf); the services delegate, and the permission presets consume them — current(session) and set() now see inherited baselines, so a child inheriting danger-full-access gets REAL knob switches when workspace-write is selected instead of a silent no-op, and a seed-carried preset selection is subsumed by the baseline. current(events) becomes current(session) (pre-release; the only callers were tests). - Unconditional durable validation: a malformed header baseline fails loud on every read, no longer shadowed by an own switch. - The two policy peers are declared optional (peerDependenciesMeta), so a thin spawn/fork deployment without policy plugins can consume the driver; verify-runtime-closure honors the flag. Red-first: inherited-preset derive/switch-away and seeded-selection tests in the permission suite; malformed-baseline-with-own-switch tests in both policy suites.
This commit is contained in:
@@ -19,7 +19,7 @@ Two families enforce the same mode vocabulary: the sandboxed bash executor (`@de
|
||||
- `ctx.sandboxPolicy.defaultMode` / `ctx.sandboxPolicy.workspaceRoot` — the deployment default and fallback root used by `resolve()`.
|
||||
- `effectiveSandboxMode(events)` — the pure fold of a session's `sandbox/mode` events (the last switch wins, or `undefined`), used inside `resolve()`.
|
||||
- `setSandboxMode(session, mode)` — THE write path for a per-session override: appends exactly one `sandbox/mode` event. The switch IS its event; nothing mutates the mode out of band.
|
||||
- `ctx.sandboxPolicy.overrideOf(session)` — the session's override chain, never the deployment default: the fold of the session's OWN switches (events past `SessionHeader.seedLength`), else the header's inherited `sandboxMode` delegation baseline, validated against the closed vocabulary on read (throws on foreign values — a durable boundary). The in-process subagent driver captures this at delegation and writes it into each child's creation-time header, so a delegating parent's tightened mode binds its children with no first-turn timing window ([rationale](../../../.agents/notes/implemented/feature/2026-07-25-subagent-policy-inheritance.md)).
|
||||
- `ctx.sandboxPolicy.overrideOf(session)` (the pure `sandboxOverrideOf` export, also consumed by the permission presets) — the session's override chain, never the deployment default: the fold of the session's OWN switches (events past `SessionHeader.seedLength`), else the header's inherited `sandboxMode` delegation baseline, validated against the closed vocabulary on read (throws on foreign values — a durable boundary). The in-process subagent driver captures this at delegation and writes it into each child's creation-time header, so a delegating parent's tightened mode binds its children with no first-turn timing window ([rationale](../../../.agents/notes/implemented/feature/2026-07-25-subagent-policy-inheritance.md)).
|
||||
- `SANDBOX_MODES` — every mode, for option advertisement and runtime validation.
|
||||
|
||||
The optional `./invariant` companion rejects a forged durable `sandbox/mode` event whose value falls outside that closed vocabulary; Session and its companion own the surrounding storage and turn-enclosure rules.
|
||||
|
||||
Reference in New Issue
Block a user