Data scrubbing
Production telemetry can carry credentials and PII. LoopOps scrubs at ingest, before the row is written — the lake never holds the raw value, so there is nothing to scrub retroactively and nothing for a read surface to leak. The model is Sentry's server-side data scrubbing, adopted deliberately.
On by default
Sensitive field names (contains-match, Sentry's list): password, secret, passwd, api_key, apikey, auth, credentials, mysql_pwd, privatekey, private_key, token, bearer — the whole value becomes [Filtered], objects included.
Value patterns, masked inside every string value and message:
| Pattern | Becomes |
|---|---|
API keys (sk-…), bearer tokens, JWTs | [REDACTED:api_key] etc. |
| AWS / GitHub / Slack tokens | [REDACTED:aws_key] etc. |
| Card numbers (13–19 digits, Luhn-validated — order ids don't false-positive) | [REDACTED:card_number] |
Coverage is the whole attribute bag, deep — span, resource, scope, log body, exception detail — on both OTLP lanes and feedback comments.
One deliberate deviation from Sentry: the field-name filter applies only to string/object values. LoopOps counts LLM tokens (token_burn, gen_ai.usage.input_tokens) — a number is never a credential.
Per-project rules
GET /v1/redaction # any project key — the active config
POST /v1/redaction # agent key — change it (reason REQUIRED)
{ "mask_emails": true,
"sensitive_fields": ["customer_ref"],
"safe_fields": ["auth_mode"],
"reason": "pilot data-handling review" }
Or from your agent: loopops_redaction({ mask_emails: true, reason: "…" }).
mask_emails— opt-in email masking ([REDACTED:email]).sensitive_fields/safe_fields— add or exempt field names
(contains-match, ≤50 entries).
defaults: false— master switch, if you truly need raw values.
Every change requires a reason and is recorded as its own redaction.config_changed event — the scrubbing policy has a queryable history. Changes apply to new events within ~60 s and are never retroactive (Sentry's rule too).
Also in this layer
Producer-side capture flags (recordInputs / recordOutputs on the SDK) stop values from ever leaving your process — server scrub is the second line, not the only one. Raw feedback audio is transcribed at the edge and not retained.