Repository navigation
Redaction searches only the written text of a request - #337
Merged
Merged
Conversation
…otocol structure
Redaction ran its rules over the whole raw JSON body and then exempted some
keys by name (custom rules only). A built-in rule could still match inside a
protocol value: with the mobile-number rule on, an 11-digit run inside a
Codex reasoning item id (`rs_` + hex) became `<<TW_PHONE_1>>`, the upstream
rejected `input[n].id`, and every later turn of the conversation failed.
Outbound redaction now only looks at the text people, models and tools wrote,
listed per request shape in the new `tw_dialect::written` module: system
prompts, every role's message text, reasoning text and summaries, tool-call
arguments and inputs, tool results and tool descriptions, for Anthropic,
Chat, Responses, Gemini and Converse requests, plus embeddings, legacy
completions, Gemini embeddings and Realtime client events. Ids, types, roles,
names, model names, signatures, encrypted content, media and configuration
are never searched, and neither are blocks or fields the list does not know.
Reasoning text stays on the list: answers are restored before they reach the
client, and history sent back has to be replaced again.
- `flow::Scope { Written(Shape), Whole }`; `find`, `look`, `look_from`,
`look_hits` and `replace` take the request's shape. Rules still run over
the raw text once; only when something matches is the body parsed and the
matches outside the written strings dropped. The key-name list is gone.
- The gateway names the shape from the path (`ClientApi::written`); a
converted hop uses the format it was converted to. Unknown paths and
WebSocket paths other than Responses and Realtime are not searched.
- Stored-body masking and security-log excerpts still mask the whole text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… sends it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Redaction ran its rules over the whole raw JSON request body and then exempted some keys by name, for custom rules only. Built-in rules could still match inside a protocol value. With the mobile-number rule on, an 11-digit run inside a Codex reasoning item id (
rs_followed by hex) was replaced with<<TW_PHONE_1>>; the upstream rejectedinput[n].id, and because history is resent every turn, every later turn of the conversation failed. The key-name exemption from v0.71.0 was a patch over the same root cause: the redactor did not know which strings in a request are text.Change
Outbound redaction now only looks at the text people, models and tools wrote, located by protocol structure in a new
tw_dialect::writtenmodule:input), legacy completions (prompt,suffix), Gemini embeddings, Realtime client events.tw_guard::redact::flowgainsScope { Written(Shape), Whole };find,look,look_from,look_hitsandreplacetake the request's shape. Rules still run once over the raw text; only when something matches is the body parsed and the matches outside the written strings dropped. The key-name list (structural) is removed.The gateway names the shape from the request path (
ClientApi::written); a converted hop uses the format it was converted to. Unknown paths, and WebSocket paths other than Responses and Realtime, are not searched. Stored-body masking and security-log excerpts still mask the whole text.Tests
writtenunit tests per shape, and the caller cross-check now also asserts that every system prompt, model and reasoning text the IR decodes is on the redaction list.reported_items_on_a_large_body_cost_linear_timeis timing-sensitive and failed locally under heavy machine load both with and without this change.🤖 Generated with Claude Code