Phases & streaming
What input, output, and stream each inspect, and why the streaming lane is a bounded best-effort gate rather than a proof.
On this page
| Phase | What it inspects | Delivery boundary |
|---|---|---|
input |
Recognized request content before the provider call | Mutation or refusal before dispatch |
output |
Recognized content in a bounded buffered response | Mutation or suppression before release |
stream |
Supported response deltas incrementally | Only bytes still held can be transformed |
Unsupported detector/phase combinations are refused during activation. The stock gateway also rejects stream_fallback: buffer; it does not provide full-stream buffering. For a detector that declares streaming but has no incremental matcher, monitor records unavailable coverage and applies the effective mode and failure posture. It does not override an enforcing on_error: closed binding. stream_fallback: closed requires a fail-closed acknowledgement and suppresses unreleased bytes in enforcing mode. Monitor mode preserves traffic.
The lower-level Go stream-arm API can return a buffer directive to a custom embedding. That directive does not establish a stock gateway buffering implementation.
Failure posture
The same policy applies when extraction, a detector, transformation or stream release cannot complete.
| Effective mode and posture | Result on protection failure |
|---|---|
monitor |
Preserve traffic and disclose incomplete coverage |
enforce, on_error: open |
Allow traffic with a failure receipt; no clean or successful-mutation claim |
enforce, on_error: closed, acknowledgement present |
Refuse input or suppress unreleased output |
| Closed posture without acknowledgement | Configuration rejected |
A block finding is distinct from an execution failure. Receipts describe the execution state, selected action, applied transformation and delivery separately.
After an enforcing privacy control fails to finish, secondary cascade, shadow and cache-exploration calls are withheld with not_run and sanitized_incomplete, including under on_error: open. The open posture still controls client delivery; it does not authorize a secondary destination to receive an incompletely sanitized subject. A denied cascade invocation records representation: withheld and sent: false.
Streaming remains bounded
The stream has a finite hold-back window, raw-frame cap, retained matcher window and time budget. Its ordinary hold settings are three events, 2 KiB and 250 ms. Reaching a protection boundary, losing a pending candidate or receiving malformed frames applies the effective failure posture. A closed binding must suppress unreleased bytes when protection cannot be maintained. Bytes already released cannot be recalled.
secrets.* has no incremental matcher; choose and test its fallback explicitly. The embedded PII stream matchers have bounded candidate retention. Streaming is not whole-response semantic coverage, and media/tool fragments without a supported stream representation are not clean text.
A transformation is recorded as applied only after the complete operation has been validated and committed. Invalid, overlapping or no-longer-held spans cannot be reported as a successful redaction. Monitor findings remain findings and do not claim bytes changed.
For a credential requirement, use a validated buffered-output policy and test oversize, timeout and encoding failures under the intended posture. See the output recipe.
A schema is not a streaming check
A JSON schema is a claim about a whole document, and no incremental matcher can decide a half-arrived one. The response-schema detector therefore declares the output phase alone, and a binding that names stream beside it does not compile: “block a stream on a schema” is not a configuration that can be written.
So a streamed response from a gateway whose schema check is armed is delivered without being validated against it. The gateway’s protection read carries the reason stream_unsupported on that row, which is how the gap is published rather than left to be inferred.
Detectors that do carry an incremental matcher still act on the same stream: pii.email holds emitted events back inside its window and rewrites an address split across frames. Bytes already released stay released. Keep a call site whose value is a parseable object non-streaming, and read check a response against a JSON schema for the check itself, its limits and what a bad schema says.