CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Does assigning a fragment encode an existing percent escape again?
Our URL.hash setter retains A%20B, while encodeURIComponent of that same input produces A%2520B. A leading # is treated as the fragment marker, and empty text removes the fragment. Assign the intended representation deliberately.
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 fragment direct string / keep / invisible true | "AB"U+0041 U+200B U+0042 | "AB"Removed 1 invisible character | {"href":"https://example.test/p#A%E2%80%8BB","hash":"#A%E2%80%8BB","encodedWholeInput":"A%E2%80%8BB","decodedHash":"AB"}{"href":"https://example.test/p#AB","hash":"#AB","encodedWholeInput":"AB","decodedHash":"AB"} |
| Existing escape direct string / keep / invisible true | "A%20B"U+0041 U+0025 U+0032 U+0030 U+0042 | "A%20B"No selected invisible characters found | {"href":"https://example.test/p#A%20B","hash":"#A%20B","encodedWholeInput":"A%2520B","decodedHash":"A B"}{"href":"https://example.test/p#A%20B","hash":"#A%20B","encodedWholeInput":"A%2520B","decodedHash":"A B"} |
| Leading hash direct string / keep / invisible true | "#A B"U+0023 U+0041 U+0020 U+0042 | "#A B"No selected invisible characters found | {"href":"https://example.test/p#A%20B","hash":"#A%20B","encodedWholeInput":"%23A%20B","decodedHash":"A B"}{"href":"https://example.test/p#A%20B","hash":"#A%20B","encodedWholeInput":"%23A%20B","decodedHash":"A B"} |
| Empty fragment direct string / keep / invisible true | "" | ""No selected invisible characters found | {"href":"https://example.test/p","hash":"","encodedWholeInput":"","decodedHash":""}{"href":"https://example.test/p","hash":"","encodedWholeInput":"","decodedHash":""} |
The setter and component encoder process the same text differently
The marked AB fixture is assigned to the hash of a fresh HTTPS URL. Before cleanup the serialized fragment contains the UTF-8 percent bytes for U+200B; afterward it is simply #AB. Our existing-escape control supplies A%20B as literal input text. The setter retains that spelling in both hash and href, whereas encodeURIComponent turns the percent sign into %25. Decoding the serialized hash once yields A followed by a space and B. The two operations therefore cannot be substituted merely because both are associated with URL encoding.
A delimiter in the input changes how assignment is interpreted
The leading-hash control begins with # and contains a space. Assignment produces the same #A%20B fragment as the existing-escape reference, while whole-input component encoding also escapes the leading hash. Empty text yields an empty hash and the original path URL without a fragment marker. We save href as well as hash because an empty-looking fragment result needs its surrounding serialization to be interpreted. Every observer starts from the same fresh URL, so leftover state from a previous assignment cannot explain the outcome.
Track whether your value is raw text or an encoded fragment
Choose the representation accepted by the destination before pre-encoding a fragment or assigning it. Record the exact value supplied to the setter and the serialized result. This experiment uses valid percent sequences and one local decoding pass; it does not define behavior for malformed escapes, document navigation, browser history or anchor matching. The example domain is a parsing fixture and is never fetched. The earlier fragment guide starts with encoded text and asks where decoding happens. Here the new question concerns construction through the hash setter.
Cleanup only changes the string it receives
If an unwanted character is already represented by ASCII percent bytes, inspecting decoded content is a separate stage. That general boundary does not make every percent sequence unwanted. Our four authored controls preserve the exact distinction between raw marker text, existing escape text, a delimiter and empty content. No actual clipboard, Claude response or statistical detector participates. Treat the recorded URLs as reproducible serialization observations rather than proof that a destination link will scroll to a particular element or that any model-level watermark has been removed.
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
WHATWG URL hash setter 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.