Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Why does editing a Buffer slice change my original cleaned bytes?

Our Buffer.slice returns a different object sharing storage: writing 0x58 through it changes the original buffer too. Buffer.from(buffer) preserves the prior bytes in an independent copy. Cleanup changes string content; it does not choose byte ownership.

Tested October 22, 2026 · v24.19.0 · 4 measured runs

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked ASCII

Measured inputs and outputs

These are locally constructed test strings, not evidence that Claude inserts these characters. We executed the saved homepage script snapshot with a minimal DOM harness and compared exact strings. The invisible-checkbox state and dash mode appear in each row. The observations below test this page's specific question. Destination observations run independently on the exact input and cleaned strings in the recorded Node runtime. We make no detector-score or statistical-watermark removal claim.

Before and after observations; full code points and strings are in the JSON download.
Fixture and modeInput string and code pointsOutput and cleaner statusObserved before / after
Marked ASCII
direct string / keep / invisible true
"A​B"
U+0041 U+200B U+0042
"AB"
Removed 1 invisible character
{"initial":"41e2808b42","sourceAfter":"58e2808b42","viewAfter":"58e2808b42","copyAfter":"41e2808b42","sameViewObject":false}
{"initial":"4142","sourceAfter":"5842","viewAfter":"5842","copyAfter":"4142","sameViewObject":false}
Plain ASCII
direct string / keep / invisible true
"AB"
U+0041 U+0042
"AB"
No selected invisible characters found
{"initial":"4142","sourceAfter":"5842","viewAfter":"5842","copyAfter":"4142","sameViewObject":false}
{"initial":"4142","sourceAfter":"5842","viewAfter":"5842","copyAfter":"4142","sameViewObject":false}
Emoji
direct string / keep / invisible true
"😀"
U+1F600
"😀"
No selected invisible characters found
{"initial":"f09f9880","sourceAfter":"589f9880","viewAfter":"589f9880","copyAfter":"f09f9880","sameViewObject":false}
{"initial":"f09f9880","sourceAfter":"589f9880","viewAfter":"589f9880","copyAfter":"f09f9880","sameViewObject":false}
Empty string
direct string / keep / invisible true
""
""
No selected invisible characters found
{"initial":"","sourceAfter":"","viewAfter":"","copyAfter":"","sameViewObject":false}
{"initial":"","sourceAfter":"","viewAfter":"","copyAfter":"","sameViewObject":false}

A different object still changes the same bytes

The marked ASCII input encodes as hex 41e2808b42. The observer creates a full slice and an independent Buffer.from copy, then writes byte 0x58 through the slice. The source and slice both become 58e2808b42 while the copy retains its original hex. After cleanup, the corresponding initial bytes are 4142 and the source and slice become 5842; the copy stays 4142. The identity check says the view is not the source object in both branches. Different object identity therefore does not establish independent byte storage.

The emoji control exposes the byte-level edit

For the emoji source, initial UTF-8 hex is f09f9880. Changing the first byte through the slice yields 589f9880 in both source and view, while the copy keeps f09f9880. We report hex and do not label that mutated byte sequence a successfully edited character. The empty control has no first byte to write; all three buffers remain empty, though the object identity check still differs. Plain AB reproduces the aliasing without selected characters. These controls distinguish ownership from encoding correctness, length and the homepage removal count. No user file is opened or changed.

Copy bytes before an independent working edit

When retaining a before record for a byte transformation, create an independent copy before mutating the working buffer. Keep its initial hash or hex beside the later observation if exact bytes matter. A view can be useful for deliberate shared editing, but it is unsuitable as an independent baseline when another view will write the same storage. Our observer recreates its buffers for each call, so the before and after cleanup branches cannot modify each other. The homepage itself returns strings and does not use this buffer mutation path; all byte edits happen only in the downloaded experiment.

This test concerns storage rather than prefix validity

An earlier byte-prefix guide asks whether truncation splits UTF-8. Here the full byte length is retained and one deliberate write exposes storage sharing. We do not benchmark copying, test ArrayBuffer overloads, transfer memory to a worker or guarantee that a copied buffer remains unchanged by its own later writes. Four synthetic strings and the recorded Node version bound the results. The exact mutation is intentionally visible in the harness, avoiding any implication that cleanup silently damaged a buffer. Neither an intact copy nor a changed view establishes watermark removal, original authorship or the provenance of a document.

Reproduce this test

Save reproduce.cjs and tested-app.js in the same folder. Run the command below with Node.js. The harness prints its runtime, script SHA-256 and every measured row. Compare those rows with the original record. Using a newer script or runtime creates a new experiment; retain the version information with your rerun.

node reproduce.cjs

Reference and next check

Node.js Buffers and typed arrays provides the relevant primary definition. The table and fixture analysis are original measurements. For broader inspection, use our Unicode inspector. Read the scope distinction before interpreting cleanup as a watermark result.