streaming · pii redaction · testing

Streaming redaction: test the split as well as the sentence

Test sensitive values across stream partitions, finite buffer limits and JSON-mode fragments before shipping streamed AI workflows.

Godfrey Lebo Founder, Sether · 3 min read
In this article
Three ivory envelope sculptures cross a tilted amber-glass ring, illustrating a boundary between streaming chunks. Sether™ / Field notes streaming The split is the test. Check details across stream boundaries.
Conceptual illustration with fictional data.
Direct answer

A streaming redactor must recognise supported sensitive values across chunk boundaries. Test the same input under many partitions, including splits inside the value and splits inside the token on restoration.

TL;DR
  • Test splits inside originals and inside issued tokens.
  • Finite streaming buffers require workload-specific length tests.
  • Collect JSON-mode content fragments before restoring the inner document.

A complete string can pass a redaction test while its streamed equivalent leaks part of an address. The difference is timing. The detector can only inspect bytes it has received, and a stream may release an early prefix before the rest of a pattern arrives.

Animation: an email split across two streaming chunks is missed by a naive redactor and caught by Sether, which holds back a short tail.
Why streaming redaction has to hold back a tail of every chunk. Read the streaming docs →

Imagine two fictional chunks: Contact alice@ and example.com about the delivery. A detector applied independently to each chunk does not see the complete address in either call. Concatenating the redacted results afterward does not undo what has already left the process.

Preserve enough unfinished input

Sether's streaming redactor retains a tail instead of immediately emitting every received byte. Its default safeDistanceBytes is 256. It also retains an unfinished whitespace-free run, bounded by max(safeDistanceBytes × 4, 8192) bytes. The streaming documentation explains both mechanisms and their limits.

That limit matters. It is inaccurate to describe a finite buffer as a guarantee for every possible value length. If your inputs include unusually long secrets or identifiers, measure them, select a suitable configuration and test the actual pattern. Complete-payload redaction can be the clearer choice when streaming is unnecessary.

The documented Node interface is a transform:

Documented API example
import { Readable } from 'node:stream';
import { Sether } from '@raeven-co/sether';

const sether = new Sether();
const source = Readable.from(['Contact alice@', 'example.com']);
const redacted = source.pipe(sether.redact());

The example establishes the input path; the application must consume the resulting stream and handle errors. Node's stream documentation is the primary reference for consumption, errors and backpressure. Redaction does not replace those responsibilities.

Partition an example systematically

Begin with a fictional sentence whose expected matches you know. Run it as one chunk, then split it at every position around the sensitive value. Include a split before the delimiter, after it and immediately before the end of the value. Repeat with several values in one sentence so overlap decisions are exercised too.

Check the emitted output, not only the final restored sentence. A perfect redact-restore round trip can coexist with an outgoing disclosure if part of the original was allowed through. Assert that the supported original is absent from the complete outgoing stream and that restoration with the same vault returns the expected text.

Next split the tokenised output at different positions before restoration. The response stream can divide a token just as the request stream divided the original. Test cancellation and upstream errors so retained text is not accidentally logged or sent through a fallback path.

Distinguish transport JSON from content JSON

An SSE envelope may be valid JSON while its delta.content fragments collectively describe a second JSON document. Handling the envelope safely does not automatically restore that inner document safely.

For JSON-mode output streamed over SSE, Sether documents that the application should collect tokenised content fragments and call restoreJson on the complete inner document. This can trade immediate display for a clear structure boundary. Decide that trade before showing partially restored tool arguments or attempting to execute them.

Test the workload you actually ship

A short ASCII address does not exercise long credentials, national-format phone configuration or multilingual prose. Add examples drawn from the expected format classes, using invented values rather than production records. Include negative examples to catch damage to ordinary numbers and code.

The result should be a small reproducible corpus and a partition strategy, not a screenshot saying streaming worked once. Keep the documented limitations beside the acceptance criteria. If a new data format changes those criteria, update the tests before making a broader promise about coverage.

Frequently asked questions

Does a passing complete-string test prove streaming safety?

No. Test partitions inside supported values and tokens, plus the buffering limits of the actual configuration.

Can SSE JSON handling restore an inner JSON-mode document automatically?

A transport event and a document assembled from content fragments are separate layers. Collect tokenised inner fragments and restore the complete inner JSON as documented.

Godfrey Lebo

Written by Godfrey Lebo

Founder of Sether. Ships production software for a living and reads every comment below. More about the team.

Share: X LinkedIn Markdown

Comments

Emails and phone numbers in comments are hidden automatically. We take our own medicine.

No comments yet. Ask a question or share how you handle this. First comment gets our undivided attention.

Join the conversation

Questions, corrections and war stories are all welcome. Be kind, stay on topic.

By posting you agree to our terms. We store a one-way hash of your IP to fight spam, never the IP itself.