# PRD 0082: Authoritative failure boundaries - **Status:** Draft - **Author:** codex - **Created:** 2026-07-27 - **Issue:** #444 ## Summary Make every security- or lifecycle-sensitive snapshot distinguish authoritative empty state from unavailable state, and make every destructive or resource-consuming boundary revalidate the assumptions it acts on. This finishes the focused quality work begun under #444 without broad rewrites: cleanup cannot act on stale identities, policy introspection cannot publish a fabricated empty policy, gateway servers bound untrusted work, and daemon shutdown does not emit uncaught background-thread failures. ## Problem Several paths are individually fail-closed but compose into unsafe or misleading behavior: 1. `cleanup` prepares a plan, waits indefinitely for operator confirmation, then kills stored PIDs and removes stored paths without checking that those identities still describe the same orphan. A PID may be reused or a run directory may become active during the prompt. 2. The supervisor reuses egress's deny-all fallback for `list-egress-routes`. Deny-all is correct for enforcement, but presenting it as a successful empty route table can cause a later replace-all proposal to discard live routes. 3. The supervisor and Git HTTP services accept bounded declared body sizes but use blocking reads and unbounded request threads. An untrusted bottle can exhaust the shared gateway with slow or parallel requests. 4. macOS cleanup enumerates containers and networks independently and treats a failed query as an empty class, so a partial snapshot can still become a destructive plan. 5. Gateway log-pump threads race stream closure during shutdown and emit uncaught exceptions even when shutdown otherwise succeeds. These are one design problem: state used to authorize deletion, replacement, or resource allocation must be authoritative at the point of use. ## Goals / Success Criteria - Cleanup never signals a PID or recursively deletes a path solely because it appeared in a pre-confirmation snapshot. - Firecracker cleanup proves immediately before action that a PID is still the same Firecracker process and that a run directory is still orphaned. - All backend cleanup discovery primitives raise a typed enumeration error on operational failure. No backend may independently continue from a partial snapshot. - Shared cleanup control flow lives in the backend layer; concrete backends override resource-specific discovery and validation primitives rather than each implementing a bespoke failure policy. - `list-egress-routes` returns an MCP error when attribution or policy resolution is unavailable. A genuine, authoritatively resolved empty policy remains a successful empty list. - Supervisor and Git HTTP request bodies have total read deadlines, and each service bounds concurrent request work. Limits apply to authenticated callers because bottles themselves are untrusted. - Gateway child-output pumping treats expected stream closure during shutdown as completion while preserving diagnostics for unexpected failures. - Unit tests cover PID/path reuse, partial backend enumeration, transient policy resolution failure, slow bodies, concurrency saturation, and stream closure races. ## Non-goals - Further decomposition solely to reduce module line counts. - Replacing gateway stdlib HTTP services with a web framework. - Changing egress matching, DLP decisions, proposal semantics, or backend launch behavior beyond the synchronization required for safe cleanup. - Making cleanup silently skip uncertain resources. Uncertainty is an operator-visible failure. ## Design ### Shared backend control flow Follow the backend architecture rule used by gateway attachment: shared behavior lives above concrete backends; subclasses provide primitives, not control flow. Cleanup remains previewable, but confirmation authorizes a *new authoritative evaluation*, not blind execution of the displayed object. The shared flow: 1. asks each available backend for a preview; 2. displays the union and asks for confirmation; 3. refreshes each non-empty backend plan; 4. validates destructive identities immediately before action; 5. aborts loudly if the refreshed plan or any identity cannot be proven safe. Backend-specific primitives define how to identify a resource. Firecracker uses process start identity plus canonical config/run paths; container backends use authoritative CLI queries and stable resource names/labels. ### Enforcement state versus introspection state Egress enforcement retains its deny-all fallback because uncertainty must not grant network access. Supervisor introspection uses a strict resolver path: unattributed callers and resolver failures become typed MCP errors, while a successfully resolved policy containing zero routes returns `routes: []`. ### Gateway resource boundaries Both stdlib servers set a per-connection body deadline before reading and use a bounded request executor or semaphore. Saturated capacity fails quickly with a service-unavailable response. Existing size caps remain independent: supervisor proposals retain the 1 MiB cap and Git pack requests retain their larger protocol-appropriate cap. ### Shutdown diagnostics The gateway output pump catches only stream-closure exceptions expected after the supervisor closes child pipes. Other I/O failures remain visible and are reported through the supervisor's normal diagnostic channel. ## Implementation chunks 1. Existing fail-closed security and backend enumeration fixes. 2. FastAPI orchestrator transport and bounded control-plane bodies. 3. Egress request-policy and outbound-DLP pipeline extraction. 4. Supervisor MCP dispatch extraction. 5. Shared cleanup refresh/revalidation plus authoritative macOS discovery. 6. Strict supervisor introspection and bounded supervisor/Git HTTP work. 7. Gateway shutdown log-pump closure handling. ## Open questions None.