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.
Open the Claude text cleaner · Full measured data
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.
| Fixture and mode | Input string and code points | Output and cleaner status | Observed before / after |
|---|---|---|---|
| Marked ASCII direct string / keep / invisible true | "AB"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.cjsReference 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.