Files
deepseek-harness/packages/ui/permission
kingwl f505bd9258 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.
2026-07-26 22:02:02 +08:00
..

@deepseek-ai/dsh-permission

English | 中文

User-facing permission presets through ctx.permission (PermissionService). Each configured name bundles sandbox/mode with approval/policy; the defaults are workspace-write (workspace-write + ask) and danger-full-access (danger-full-access + never). UI adapters may expose the table as one selector, while sandbox execution and approval continue to consume their own knobs.

set(session, name) records a changed selection in a log-only permission/preset event, then calls each knob's setter only when its effective value changes. Both it and current(session) resolve the knobs through the same override chains execution reads (sandboxOverrideOf/approvalOverrideOf: own post-seed switches, else the inherited header baseline, else composition defaults), so a delegated child inheriting a wider baseline gets real knob switches when a narrower preset is selected, and a seed-carried selection is subsumed by the baseline. The selection event precedes the knob events and preserves user intent when presets share a bundle; a net-zero selection appends nothing. current(session) prefers a still-matching recorded own selection, then the first matching table entry, and otherwise returns custom. Clients may display custom as the current value, but cannot select it.

The service requires a confining ctx.bash executor and ctx.approval. A table entry named custom throws at load; composition defaults outside the table instead make a zero-event session derive custom. See the sandbox switching design.

Model Experience

Indirectly, through dsh-user-approval and dsh-tool-bash, which render the approval-policy prompt, switch notice, and sandboxed tool outcomes selected by this service's knob events; permission/preset itself is log-only.

KV Cache effect

No direct invalidation; the named consumer owns any request-prefix changes.

Known Limitations and Deferred Work

  • No shipped composition currently mounts the service — the ACP bridge was its only selector before ACP became automation-only; the preset table is kept for the interactive front door that next exposes a runtime policy switch.
  • Only two mechanism knobs are bundled — presets select sandbox mode and approval policy; an agent/profile choice is not part of PresetSpec yet.
  • custom is derived-only — callers can switch away from an unmatched knob combination but cannot target or persist a named custom preset through this service.
  • The preset table is process-level — configuration is fixed for the plugin lifetime; changing available presets requires reloading the plugin.