packages/cua-driver/docs/driver-permission-modes-and-consent-plan.md
origin/main commit 767acf25f25ea668ffab428e4f2e8985896de98e0.9.1existing_profile browser attachment as the first
high-risk capability migrated to itThe implementation keeps this plan's three semantics but uses bounded as
the canonical middle-mode value; autonomous remains a compatibility alias.
This avoids conflating permission scope with an agent loop's task-continuation
autonomy. For an interactive CLI launch, --dangerously-bypass-approvals
selects unrestricted and serves as the explicit risk acknowledgement.
Programmatic and embedded launchers retain the two-part
CUA_DRIVER_PERMISSION_MODE=unrestricted plus
CUA_DRIVER_DANGEROUSLY_BYPASS_APPROVALS=1 contract. References to
autonomous below preserve the terminology used when this reviewed plan was
written.
This plan preserves the existing browser identity, endpoint, generation, reconnect, and cleanup work. The earlier attachment plan correctly rejects the generic MCP host marker as evidence of a human decision. This plan extends it by downgrading the assurance of the same-user-writable, file-backed TTY artifact and adding protected approval collectors plus driver-wide modes.
This project is complete when Cua Driver has one coherent authorization model in which:
standard is the default mode and asks through a protected channel only
when a capability or action needs human approval.autonomous runs without routine prompts inside a human-approved,
technically enforced capability envelope.unrestricted is an explicit launch-time bypass that the agent cannot
enable for itself and that is clearly unsafe outside an isolated
environment.existing_profile cannot attach from an agent-facing transport unless a
protected approval or an already-valid autonomous/unrestricted grant covers
the exact operation.Delivery requires merged code, cross-platform evidence for each advertised collector, release documentation, and post-install smoke tests. A local plan, passing unit tests, or a draft pull request is only a checkpoint.
Adopt three user-facing modes:
| Mode | Intended experience | Security meaning |
|---|---|---|
standard | One protected approval for a high-risk resource, then additional approval only for consequential actions or scope expansion | Human remains in the loop at defined boundaries |
autonomous | One protected session-start approval, then unattended work inside a declared capability envelope | Prompts are replaced by narrow, pre-authorized technical policy—not by model judgment |
unrestricted | No runtime approval prompts after explicit trusted launch | User accepts prompt-injection and unintended-action risk; the same built-in capability ceiling, managed/user policy, and hard integrity controls still apply |
yolo may be a deliberately alarming CLI alias, but unrestricted is the
canonical configuration value. The full flag should be
--dangerously-bypass-approvals.
Do not add a second permission-policy system. The July 2026 YAML/Rego engine is the capability foundation. Add a separate mode and consent layer around it.
The design separates concepts that are easy to conflate:
The new PermissionMode name is an agent-authorization concept. It is
unrelated to the existing macOS TCC startup “permissions gate,”
--no-permissions-gate, and CUA_DRIVER_RS_PERMISSIONS_GATE; documentation
and diagnostics must label the latter OS permissions to avoid ambiguity.
The effective decision is an intersection:
hard invariants
AND managed capability ceiling
AND user/session capability policy
AND mode-specific consent/grant decision
AND live resource identity proof
Evaluation rules:
ask requirement inside
the policy envelope.Treat the calling model and any content it observes as untrusted. The agent may:
APPROVE;The primary protected deployment assumes the agent can reach Cua Driver only through an authenticated/authorized daemon transport and cannot modify the daemon binary, policy, launcher, approval broker, or OS security state.
The in-process policy engine is not a boundary against arbitrary same-user native code. A local agent with unrestricted shell execution can call OS input APIs directly, read same-user files, start a second driver, attach to exposed debugging endpoints, or modify user-owned launch configuration.
For that threat, require at least one external boundary:
unrestricted never claims protection from prompt injection. On a personal
logged-in profile it is an explicit acceptance of account-action and data-loss
risk, not a secure mode.
| Priority | Gap | Consequence |
|---|---|---|
| P0 | Existing-profile approval is unsigned JSON in a same-user-writable temporary directory; its schema and UUID token format are public | Any same-user process can forge the artifact directly without invoking browser-approve; an agent-controlled PTY is a second, weaker forgery path |
| P0 | Generic MCP provenance is injected for browser_prepare only for active proxy sessions, with a parallel marker for downloads | It is not proof that a person approved; existing-profile correctly rejects it, and the mechanism must not be generalized as consent |
| P0 | No policy, or a configured policy path that does not exist, permits all calls | A typo or missing mount silently becomes unrestricted operation |
| P0 | Mode/policy selection is not protected from a same-user local agent | A shell-capable agent may restart an unprotected daemon unless launch ownership is separated |
| P1 | Policy decisions are only Allow, Deny, or Error | There is no protected ask/grant resolution layer |
| P1 | The policy engine constrains tool inputs but not responses, navigation caused by clicks/redirects, quotas, or caller identity | Data access and exfiltration can occur after an apparently allowed call |
| P1 | There is no persistent, non-optional high-risk-session indicator or emergency stop | Consent is not visibly ongoing or easily revocable |
| P1 | The agent cursor can be hidden, customized, or disabled | It is useful feedback but cannot serve as the security indicator |
| P1 | Generic low-level clicks and typing do not reveal semantic consequences | A policy cannot reliably infer purchases, sends, deletions, or account changes from coordinates alone |
| P2 | Generic MCP elicitation does not mandate a protected human-only UI | A client, hook, or agent-host implementation may synthesize accept |
| P2 | The policy engine does not authenticate callers | Different agents sharing a socket/process can inherit the same capability ceiling |
| P2 | Audit telemetry is not yet a user-visible authorization ledger | Incident review cannot reconstruct grants, denials, scope changes, and revocations |
standard — defaultstandard permits ordinary work inside policy without prompt fatigue but
requires protected consent for:
Ordinary read/navigation/input inside the approved resource and scope does not prompt again. Exact-identity reconnect does not prompt again while the grant is live and within its reconnect budget.
autonomous — bounded unattended operationThe human approves a session manifest before work begins. The manifest names:
Inside that manifest, calls run unattended. Scope expansion stops and asks; it never self-amends. High-consequence categories not explicitly present are denied, not inferred from the task prompt.
This is the preferred long-running mode. It provides the productivity goal of Codex/Claude-style automation while retaining a technical sandbox.
unrestricted — explicit bypassunrestricted bypasses interactive Cua approval prompts, but it does not
bypass:
It must be enabled outside the tool protocol through a trusted launcher,
native settings surface protected by OS authentication, or managed
configuration. It cannot be entered mid-session. The daemon must restart, show
a high-severity warning, record the mode, and default back to standard on the
next ordinary launch.
Administrators can disable the mode entirely. On a normal personal profile the UI must state that it provides no defense against prompt injection. Product documentation should recommend it only for disposable profiles, VMs, or other externally isolated environments.
All three modes use the same built-in capability ceiling. Mode changes prompt
resolution, not which classified capabilities exist. Managed and user policy
can narrow this ceiling; neither approval nor unrestricted can widen it.
The built-in ceiling is reviewed and deny-by-default at the classification boundary:
standard, a covering manifest in autonomous, and no prompt in
unrestricted.standard or explicit manifest entry in
autonomous.standard uses takeover or exact approval;
autonomous requires a separately explicit entry; unrestricted runs them
without Cua prompts.Before changing the default, maintainers must publish and test the exact
current-tool inventory mapped to R0-R4, including legacy aliases and platform
stubs. To limit breakage, all current tools remain representable in the
ceiling, but standard may add prompts or refusals where current behavior is
unprotected. The compatibility sequence remains opt-in, warning, then an
announced default flip.
Classify capabilities, not model prose:
| Class | Examples | standard | autonomous | unrestricted |
|---|---|---|---|---|
| R0: public metadata | tool schema, display size, driver version | Allow by policy | Allow by policy | Allow without prompt, inside the same ceiling |
| R1: local reversible control | inspect a test app, click/type in an isolated profile | Allow inside scope | Allow inside manifest | Allow without prompt, inside the same ceiling |
| R2: sensitive observation/control | screenshots, clipboard read, user documents, logged-in browser | Approve initial resource grant | Session-start manifest approval | Allow without prompt, inside the same ceiling; warn |
| R3: consequential external action | send message, publish, upload, download, submit form | Action confirmation unless explicitly pre-authorized | Allow only if named in manifest; otherwise deny/ask | Allow without prompt only if the operation remains inside the same ceiling |
| R4: critical/irreversible | credentials, payments, security settings, account deletion, legal acceptance | Human takeover or exact confirmation at the downstream action | Deny by default; require separately explicit grant | Allow without prompt only if inside the same ceiling; no safety claim |
This classification is metadata attached to typed operations. It must not rely only on an LLM or classifier guessing what a generic click means.
For generic pixel/keyboard tools, Cua cannot promise semantic interception. Therefore, when such tools target an authenticated or sensitive application:
Keep the existing policy contract backward-compatible: policy answers whether a call is inside the capability envelope. A new authorization coordinator then resolves consent.
enum CapabilityDecision {
Allow,
Deny(String),
Error(String),
}
enum AuthorizationDecision {
Allow { grant_id: Option<GrantId> },
RequireApproval(ApprovalRequest),
Deny(String),
Error(String),
}
// Coordinator composition, not caller-controlled input:
// (CapabilityDecision::Allow, typed_risk, startup_mode, live_grant)
// -> AuthorizationDecision
Do not force existing Rego policies to return a new ternary value in the first
release. data.cua.policy.allow: boolean remains valid. Risk metadata and mode
resolution occur after policy evaluation.
Load and intersect these layers:
The daemon reports hashes and provenance for every active layer, never the policy contents or sensitive arguments in telemetry.
CUA_DRIVER_POLICY_FILE is explicitly set and missing, unreadable, empty
in an unintended way, or unsupported, daemon startup fails.unrestricted once
modes reach general availability. standard loads a built-in baseline.--permission-mode unrestricted suppresses prompts within the same built-in
ceiling; it does not select a broader policy. Managed policy may reject the
mode.OnceLock initialization
ahead of UnixListener::bind, not merely changing the missing-path branch.Add enforcement beyond (tool, input arguments):
Rego can receive a sanitized authorization context, but secrets, raw page content, cookies, typed text, and full paths must not be included by default.
The repository already exposes a versioned dotted capability vocabulary from
the centralized default_capabilities_for map in tool.rs. The first
autonomous manifest uses canonical existing tool names plus that live map; it
does not invent tokens outside the advertised vocabulary. Static reviewed risk
metadata maps each canonical tool—and narrowly defined sub-operations where
the implementation can prove them—to R0-R4 before mode resolution.
Resource bindings such as PID, window, profile, tab, origin, and destination
remain typed grant fields enforced by the relevant adapter; they are not
reduced to regexes over arbitrary JSON. A later driver-wide phase may add
tokens such as browser.cookie.read, but only after every additive name has a
complete tool/sub-operation mapping, input/output semantics, and tests. New
vocabulary cannot be used in an accepted manifest until enforcement exists.
The daemon creates an internal request containing:
The agent may receive a correlation ID and a redacted description. Possession of either never grants authority.
Only an ApprovalBroker can resolve RequireApproval. The broker uses a
private daemon-owned channel with OS peer credentials and returns the decision
directly to the daemon. It never emits a bearer token into MCP results, CLI
stdout, inherited stdin, environment variables, or files readable by the
agent.
The collector contract is pluggable. The MVP collector is a trusted host UI; OS authentication and second-device flows are optional stronger or hostless collectors that can ship independently:
| Environment | Collector | Required property |
|---|---|---|
| Supported agent host | ProtectedHostCollector rendered by Codex, Claude, or another recognized client | Human response is outside the model/tool stream, hooks cannot auto-accept, and the authenticated result is bound to the exact request digest |
| macOS GUI (optional) | LAContext biometric approval plus daemon-owned explanatory UI | Enrolled biometric binds the decision to the device owner rather than merely a person at the trusted host |
| Windows GUI (optional) | Windows Hello/User Consent flow in a trusted daemon-owned UI | OS-authenticated result bound to the request |
| Linux desktop (optional) | polkit action with a registered authentication agent | Authenticated action through the desktop agent, with exact Cua action identity |
| Headless (optional) | second-device/device authorization flow | Approval occurs on a separately authenticated device and is bound to the request digest |
Biometric authentication is not an MVP dependency. It strengthens the claim
from “a person using the trusted host approved” to “the enrolled device owner
approved,” and provides a possible local collector when no trusted host exists.
If no recognized trusted host or optional protected collector is available,
existing_profile refuses in standard and autonomous. It never falls back
to passcode, TTY, or an agent-hosted confirmation. unrestricted remains the
explicit exception after trusted launch-time risk acceptance.
/dev/tty typed APPROVE is not a high-assurance collector when the agent can
own a PTY or drive the terminal. It may remain temporarily as a clearly labeled
legacy compatibility path for isolated-profile launch, but it must not
authorize existing_profile under standard or autonomous.
Generic elicitation/create is a transport feature, not automatically a
protected consent boundary. The MCP specification permits clients to choose
their interaction model, and automation/hooks may synthesize a response.
Use elicitation only when the client negotiates a Cua-recognized protected approval-provider capability that guarantees:
Without that contract, use an optional daemon-native or second-device
collector if one is installed; otherwise refuse the request in standard and
autonomous.
Form elicitation may present a confirmation but must never request passwords,
API keys, cookies, or biometrics.
All grants are:
The current five-minute artifact TTL, 30-minute idle TTL, and eight-hour absolute browser grant are starting values, not universal defaults. R3/R4 action confirmations should normally be single-use and expire in minutes.
Every R2+ grant creates persistent visible state owned by the trusted daemon:
unrestricted.The indicator is separate from the agent cursor. The cursor remains optional activity feedback; the security indicator cannot be hidden, recolored into invisibility, or disabled while a high-risk grant is live.
Add three revocation paths:
cua-driver revoke [--session <id>|--all] from a trusted local operator.The daemon must reject actions targeting its own broker, indicator, status item, or protected screen regions. Revocation closes browser/debug transports, cancels in-flight mutations, invalidates refs/targets, clears clipboard or temporary data owned by the grant, invokes session cleanup, and records the reason.
The shortcut is not an authorization boundary because an input-capable agent may synthesize the same keys. Enforcement comes from the protected Stop broker, grant revocation, and self-target refusal. On a surface where a persistent tamper-resistant indicator cannot be rendered, R2+ grants are unavailable unless the approving out-of-band device or host provides a continuously reachable indicator and Stop control bound to the grant.
This is a meaningful boundary only for agents constrained to the daemon. Same- user arbitrary native code still requires external isolation.
isolated_new remains low-friction and uses the built-in standard policy.isolated_named is treated as potentially persistent/sensitive and may need
an initial R2 grant depending on whether it contains authenticated state.existing_profile is R2 at attach and may produce R3/R4 actions afterward.standard, existing_profile requires trusted consent before attach.autonomous, existing_profile requires a trusted approval covering it
in the session manifest; subsequent in-scope use is unattended.unrestricted may attach without runtime approval after explicit trusted
launch-time risk acceptance. It cannot be entered or enabled by the running
agent.existing_profile is unavailable in
standard and autonomous; it must not fall back to TTY approval.An existing-profile grant binds at least:
The profile-wide CDP transport does not imply profile-wide authorization. Target attachment and command dispatch must be limited to tabs/resources covered by the grant.
page, generic JavaScript, raw CDP, and
shell routes that could bypass typed browser restrictions.window.open, target creation, history traversal, form submission, and
server/client-driven navigation—not only browser_navigate(url) arguments.Typed browser tools should surface known submit/action metadata when it can be proved, but Cua must not claim perfect semantic detection. For payments, credentials, account/security changes, legal acceptance, and destructive actions, use one of:
unrestricted risk acceptance.Model-emitted “are you sure?” text and classifiers may reduce mistakes but are not authorization boundaries.
Keep the current CDP transport while this consent work lands. Independently
spike chrome.debugger extension/native-messaging transport. Current Chrome
documentation lists the Input domain, so the spike should now test actual Cua
command coverage, target/window identity, extension install/update trust,
DevTools conflicts, service-worker lifecycle, enterprise controls, and
cross-platform packaging rather than treating Input availability as unknown.
Do not block the permission-mode project on that transport. If it proves viable, it is attractive for the real default profile because Chrome owns the debugger attachment UI and revocation semantics.
After browser attachment, migrate capability groups in this order:
Each group needs typed risk metadata, resource scoping, output/egress controls, grant lifecycle, indicator text, and adversarial tests before it is advertised as protected.
Illustrative CLI:
cua-driver serve --permission-mode standard
cua-driver serve --permission-mode autonomous --session-policy /trusted/task.yaml
cua-driver serve --permission-mode unrestricted --dangerously-bypass-approvals
Rules:
--permission-mode is accepted only by trusted daemon startup, never by
call, MCP, raw tool arguments, or a session tool.autonomous without a protected session-manifest approval refuses to bind
the public socket or starts in a pending state that serves only health.unrestricted requires both the mode and deliberately named danger flag in
CLI environments; native UI uses OS authentication and explicit warning.status, doctor, and health_report expose the effective mode and policy
provenance without exposing sensitive policy contents.Illustrative autonomous manifest:
version: 1
mode: autonomous
expires_after: 8h
idle_timeout: 30m
resources:
applications:
- bundle_id: com.google.Chrome
browser:
profile: Work
origins:
- https://docs.example.com
- https://app.example.com
allow:
tools:
- start_session
- end_session
- get_browser_state
- browser_navigate
- browser_click
- browser_type
- wait
deny:
tools:
- page
- shell_execute
ask:
tools:
- browser_download
- browser_set_input_files
ask belongs to the new session-manifest schema, not the existing YAML policy
schema. The manifest is compiled into an immutable in-memory authorization
layer and intersected with YAML/Rego and managed policy. The agent may propose
a manifest but cannot approve or install it.
| Scenario | Expected human interventions |
|---|---|
Read-only task in an isolated browser under standard | 0 |
Ordinary task in an already-approved logged-in profile under standard | 1 initial attach |
| Same-identity reconnect while grant is live | 0 |
Send/publish/purchase/account change under standard | 1 immediately before each consequential action or takeover |
Eight-hour bounded task under autonomous | 1 session-manifest approval; 0 inside scope |
| Autonomous scope expansion | 1 approval for the expansion |
unrestricted daemon session | 1 explicit trusted launch enablement; 0 runtime prompts |
Expiry, daemon restart, browser identity change, OS lock/user switch, explicit Stop, managed-policy change, and reconnect-budget exhaustion require a new grant or produce a refusal.
Add these core concepts without coupling them to one transport:
AuthorizationCoordinator
├── CapabilityPolicyStack
│ ├── HardInvariants
│ ├── ManagedPolicy
│ ├── UserPolicy (existing YAML/Rego)
│ └── SessionManifest
├── RiskClassifier (typed metadata, not model authority)
├── ApprovalBroker
│ ├── ProtectedHostCollector (MVP)
│ ├── MacOSBiometricCollector (optional)
│ ├── WindowsHelloCollector (optional)
│ ├── PolkitCollector (optional)
│ └── DeviceFlowCollector (optional)
├── Grants (generalized from ExistingProfileGrants/GrantLookup)
├── IndicatorController
└── AuditSink
Primary code areas:
cua-driver-core/src/policy.rs: policy stack, fail-closed loading,
authorization context, and composition.cua-driver-core/src/server.rs and cua-driver/src/serve.rs: one canonical
authorization call before registry dispatch; remove consent inference from
generic transport provenance.cua-driver/src/proxy.rs: early denial only; the daemon remains canonical
for grants and protected approval.cua-driver-core/src/session.rs: grant ownership, teardown, idle eviction,
and transport identity.cua-driver-core/src/browser/approval.rs: replace public artifacts for
existing_profile with broker-mediated grants; retain a compatibility path
only for low-risk isolated launch if needed.cua-driver-core/src/browser/grant.rs, prepare.rs, engine.rs, and
store.rs: consume generic grants, add origin/capability scope, and enforce
revocation during attach/reconnect/action.Today policy evaluation is duplicated in serve.rs, server.rs, and the
separate stdio proxy process. Before adding the coordinator, refactor the two
daemon dispatch paths to call exactly one daemon-side authorization function
covering stdio, HTTP/MCP, CLI, and raw socket dispatch. The proxy keeps a
redundant early-deny check as defense in depth and can never mint or satisfy a
grant. The generic grant implementation should evolve
ExistingProfileGrants, GrantLookup, and PrepareAuthorization rather than
create a parallel browser-independent store.
| Failure | Required result |
|---|---|
| Policy explicitly configured but missing/unreadable | Daemon does not expose action socket |
| User policy unset during migration window | Preserve documented allow-all compatibility and emit migration status/warning |
| User policy unset after default flip | Load the reviewed built-in ceiling and standard mode |
| Policy parse/evaluation error | Fail closed; stable structured error |
| Unsupported/absent protected collector | Sensitive request refuses; no TTY fallback |
| Approval timeout/cancel/decline | No grant; pending operation canceled |
| Agent replays approval correlation ID | Refuse; ID is non-authoritative |
| Agent changes PID/window/session after approval | Refuse and consume/cancel request |
| Policy or mode changes | Existing incompatible grants revoked before new calls |
| Indicator fails to render | R2+ grant is not activated or is immediately revoked |
| Stop during in-flight action | Cancel where possible, report honest partial-delivery state, revoke derivatives |
| Redirect/popup leaves approved origin scope | Pause/refuse/detach before further input or data release |
| Browser/daemon restart | In-memory grant lost; require new approval |
| Agent targets Cua consent/indicator UI | Hard refusal independent of mode |
Deny can become Allow after approval or mode resolution.standard after migration.existing_profile in standard or autonomous.APPROVE; existing_profile remains denied.accept; denied unless the protected-host
capability and authenticated response are present.page, JavaScript, raw CDP, shell, file, or response side channels.For every advertised platform/collector, record exact-SHA evidence for:
No platform/host combination advertises protected existing_profile until its
selected collector and indicator rows pass in the real environment. Headless
support requires a certified protected host or second-device flow;
/dev/tty is not substituted.
The initial protected-browser release requires all of the following:
existing_profile cannot use the file-backed artifact in standard or
autonomous; a protected local/host/device collector exists or the feature
remains unavailable.The following do not block the first-platform protected-browser release:
chrome.debugger transport spike.They remain required before Cua advertises the corresponding driver-wide or platform guarantee.
existing_profile approval path experimental.Exit: no accidental policy typo or ordinary agent transport silently gets a logged-in profile attachment.
serve.rs and server.rs to call one canonical daemon-side
authorization function; retain the separate proxy check as early denial.PermissionMode and immutable startup provenance.Exit: standard/autonomous/unrestricted decisions are deterministic and the agent cannot change them in-process.
existing_profile in
standard and autonomous; never downgrade to TTY confirmation.Exit: adversarial PTY and synthetic-MCP accept tests cannot mint a grant.
Exit: no R2+ grant can remain live without indicator and revocation coverage.
existing_profileExit: one protected approval supports ordinary autonomous browser work, with new intervention only for scope expansion or consequential actions.
Exit: long-running tasks need one bounded approval; bypass cannot be entered by an already-running standard/autonomous agent.
Migrate screen, input, clipboard/files, devices, shell/network, and consequential typed workflows in the priority order above. Each group ships only after input, output, egress, revocation, and live-platform tests pass.
Keep changes reviewable and release metadata accurate:
fix(cua-driver): fail closed before binding for configured permission policiesrefactor(cua-driver): unify daemon authorization dispatchfeat(cua-driver): add permission modes and policy compositionfeat(cua-driver): add protected approval broker and grantsfeat(cua-driver): add persistent authorization indicator and revocationfix(cua-driver): require protected consent for existing browser profilesfeat(cua-driver): add bounded autonomous session manifestsBefore each PR becomes ready, inspect its final files and live GitHub title, apply the appropriate release label/type, and wait for release-metadata CI.
standard the default in the next announced release boundary.unrestricted; require the explicit
mode/danger flag after the migration boundary.LAContext collector worth shipping for hostless use,
and can the installed daemon present it reliably without passcode fallback?chrome.debugger transport cover Cua's exact input, frame,
target-binding, and recording requirements in practice, and can its
extension/native-host supply chain be secured?chrome.debugger API and available CDP domains767acf25f, including policy.rs, serve.rs, server.rs, proxy.rs,
cli.rs, browser approval/grant/prepare code, current policy docs, and the
earlier browser plans.unrestricted suppress prompts without widening policy;
define the built-in baseline and default-flip boundary; make daemon dispatch
unification a prerequisite; eager-load policy before bind; accurately frame
the earlier plans; classify the emergency shortcut as an affordance; require
out-of-band indicator/Stop when local UI is unavailable; use existing tool
names for MVP manifests; add device-flow fallback; generalize the existing
browser grant store; disambiguate TCC permissions; and test direct artifact
forgery.chrome.debugger do not block
the first-platform protected-browser release. Browser-specific origin/data
bypass controls remain mandatory.unrestricted, a shared
reviewed ceiling, existing-tool MVP manifests, and an out-of-band
indicator/Stop substitute.