CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Can URLSearchParams.set discard values after cleaning a key?
Yes. Cleaning our marked name key creates two name entries. set("name", "Cy") then keeps one Cy entry and removes the duplicate; the percent-encoded marker remains a distinct key.
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 and plain keys direct string / keep / invisible true | "name=Ada&name=Bea&x=1"U+006E U+0061 U+200B U+006D U+0065 U+003D U+0041 U+0064 U+0061 U+0026 U+006E U+0061 U+006D U+0065 U+003D U+0042 U+0065 U+0061 U+00 … | "name=Ada&name=Bea&x=1"Removed 1 invisible character | {"original":[["name","Ada"],["name","Bea"],["x","1"]],"updated":[["name","Ada"],["name","Cy"],["x","1"]],"serialized":"na%E2%80%8Bme=Ada&name=Cy&x=1"}{"original":[["name","Ada"],["name","Bea"],["x","1"]],"updated":[["name","Cy"],["x","1"]],"serialized":"name=Cy&x=1"} |
| Two ordinary duplicates direct string / keep / invisible true | "name=Ada&name=Bea&x=1"U+006E U+0061 U+006D U+0065 U+003D U+0041 U+0064 U+0061 U+0026 U+006E U+0061 U+006D U+0065 U+003D U+0042 U+0065 U+0061 U+0026 U+00 … | "name=Ada&name=Bea&x=1"No selected invisible characters found | {"original":[["name","Ada"],["name","Bea"],["x","1"]],"updated":[["name","Cy"],["x","1"]],"serialized":"name=Cy&x=1"}{"original":[["name","Ada"],["name","Bea"],["x","1"]],"updated":[["name","Cy"],["x","1"]],"serialized":"name=Cy&x=1"} |
| Encoded marker key direct string / keep / invisible true | "na%E2%80%8Bme=Ada&name=Bea&x=1"U+006E U+0061 U+0025 U+0045 U+0032 U+0025 U+0038 U+0030 U+0025 U+0038 U+0042 U+006D U+0065 U+003D U+0041 U+0064 U+0061 U+0026 U+00 … | "na%E2%80%8Bme=Ada&name=Bea&x=1"No selected invisible characters found | {"original":[["name","Ada"],["name","Bea"],["x","1"]],"updated":[["name","Ada"],["name","Cy"],["x","1"]],"serialized":"na%E2%80%8Bme=Ada&name=Cy&x=1"}{"original":[["name","Ada"],["name","Bea"],["x","1"]],"updated":[["name","Ada"],["name","Cy"],["x","1"]],"serialized":"na%E2%80%8Bme=Ada&name=Cy&x=1"} |
| Absent target direct string / keep / invisible true | "x=1"U+0078 U+003D U+0031 | "x=1"No selected invisible characters found | {"original":[["x","1"]],"updated":[["x","1"],["name","Cy"]],"serialized":"x=1&name=Cy"}{"original":[["x","1"]],"updated":[["x","1"],["name","Cy"]],"serialized":"x=1&name=Cy"} |
The update changes multiplicity after key repair
Our initial query contains a marked name with Ada, a plain name with Bea and x with one. Before cleanup, set updates only the plain name to Cy and preserves the marked Ada entry. After selected deletion, both entries have the same key; set changes the first to Cy and removes the second, leaving two total entries. The ordinary-duplicate reference already has that result without a marker. The percent-encoded-marker reference remains distinct because the raw cleanup does not decode its notation. When name is absent, set appends a new entry. Ordered original and updated lists expose the value loss and append location directly.
An update is different from reading or sorting
The destination observer constructs a URLSearchParams object and mutates it with one set call. It never visits a URL or sends any request. The prior query-key article records get and getAll; the sorting article reorders existing entries. Neither operation establishes what this mutation removes. The fixed Cy value is an invented update label, not a user’s replacement value. The homepage returns edited text and does not choose a duplicate policy. In this experiment, percent decoding happens inside URLSearchParams after cleanup; that stage distinction explains why an encoded marked key still survives beside the updated plain name.
Decide whether duplicates should survive the update
Keep the original query pairs, enumerate decoded keys and identify the destination’s intended multiplicity. If multiple values should remain, select an API and policy that preserve them rather than assuming set updates every value independently. After a targeted key edit, compare both the number of pairs and each surviving value. A successful lookup is insufficient to reveal an entry removed by a later update. These four fixtures show a documented local mutation on known names and ordering. They do not predict framework parameter rules, establish a server’s business semantics or choose which original payload should be retained when two repaired keys coincide.
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 URLSearchParams set 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.