CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Why does a one-byte prefix decode as a replacement character after cleanup?
Our cleaned éX starts with UTF-8 bytes C3 A9. Taking only C3 yields a replacement character under Buffer decoding and fails fatal TextDecoder validation. The complete first code point is é; a byte prefix follows a different boundary.
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 |
|---|---|---|---|
| Marker before accent direct string / keep / invisible true | "éX"U+200B U+00E9 U+0058 | "éX"Removed 1 invisible character | {"utf8Hex":"e2808bc3a958","prefixHex":"e2","decodedPrefix":"�","fatalAccepted":false,"firstCodePoint":""}{"utf8Hex":"c3a958","prefixHex":"c3","decodedPrefix":"�","fatalAccepted":false,"firstCodePoint":"é"} |
| Accented first letter direct string / keep / invisible true | "éX"U+00E9 U+0058 | "éX"No selected invisible characters found | {"utf8Hex":"c3a958","prefixHex":"c3","decodedPrefix":"�","fatalAccepted":false,"firstCodePoint":"é"}{"utf8Hex":"c3a958","prefixHex":"c3","decodedPrefix":"�","fatalAccepted":false,"firstCodePoint":"é"} |
| Emoji first direct string / keep / invisible true | "😀X"U+1F600 U+0058 | "😀X"No selected invisible characters found | {"utf8Hex":"f09f988058","prefixHex":"f0","decodedPrefix":"�","fatalAccepted":false,"firstCodePoint":"😀"}{"utf8Hex":"f09f988058","prefixHex":"f0","decodedPrefix":"�","fatalAccepted":false,"firstCodePoint":"😀"} |
| ASCII control direct string / keep / invisible true | "ABX"U+0041 U+0042 U+0058 | "ABX"No selected invisible characters found | {"utf8Hex":"414258","prefixHex":"41","decodedPrefix":"A","fatalAccepted":true,"firstCodePoint":"A"}{"utf8Hex":"414258","prefixHex":"41","decodedPrefix":"A","fatalAccepted":true,"firstCodePoint":"A"} |
Removing the marker does not make the next character one byte
The marked-accent fixture is encoded from the exact supplied Unicode string. Its first byte initially belongs to the three-byte U+200B. After deletion, the full UTF-8 buffer begins C3 A9 for é followed by the ASCII X byte. Taking just the first byte leaves C3, which Buffer converts to a replacement character. The plain éX control repeats this incomplete-prefix behavior with no edit. The emoji control begins a four-byte sequence and likewise fails when only its leading byte is selected. The ASCII control supplies a complete A byte and decodes successfully. We retain full buffer hex, selected prefix hex, decoded prefix, fatal validation and the complete first code point to locate the loss in the byte selection.
String boundaries and encoded byte boundaries are separate
Our earlier UTF-16 slice example cuts a JavaScript string unit, and the grapheme guide selects complete displayed clusters. This observer instead encodes the whole string before taking a Buffer subarray. A complete first code point may require more than one UTF-8 byte, as the accent and emoji controls demonstrate. The fatal decoder receives only that selected byte buffer; it is a diagnostic independent of the cleaner and does not show that the homepage validates uploaded bytes. The encoded buffers are constructed locally from valid strings, not recovered from a damaged file. We do not implement a general byte-budget truncator, test streaming chunk joining here or promise that a complete code point is always a complete visual character.
Apply a byte quota without discarding the remaining sequence
When a destination has a byte limit, calculate the encoded size and preserve boundaries required by its encoding and display contract. Do not decode an arbitrary fixed-size prefix and then treat the replacement character as recoverable original text: the omitted bytes belong to the sequence you cut away. Keep the complete encoded buffer or source when a later correction needs those bytes. Our four controls show why cleanup and byte truncation cannot be combined into a single success counter. The attached code uses local buffers and no filesystem or network write. It does not choose the correct quota for a service or certify all truncation algorithms. Test the actual final bytes and destination decoder after any deliberate prefix operation, with explicit error behavior and retained version metadata.
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 Buffer subarray and UTF-8 conversion 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.