CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Why does URLSearchParams reject an entry with one or three items?
Our sequence constructor requires each entry to contain exactly two items. A missing value item and an extra third item both throw TypeError; an explicit empty string as the second item is accepted and serializes as q=.
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 value direct string / keep / invisible true | "AB"U+0041 U+200B U+0042 | "AB"Removed 1 invisible character | {"valid":{"entries":[["q","AB"]],"serialized":"q=A%E2%80%8BB"},"short":{"error":"TypeError"},"long":{"error":"TypeError"},"record":"q=A%E2%80%8BB"}{"valid":{"entries":[["q","AB"]],"serialized":"q=AB"},"short":{"error":"TypeError"},"long":{"error":"TypeError"},"record":"q=AB"} |
| Plain value direct string / keep / invisible true | "AB"U+0041 U+0042 | "AB"No selected invisible characters found | {"valid":{"entries":[["q","AB"]],"serialized":"q=AB"},"short":{"error":"TypeError"},"long":{"error":"TypeError"},"record":"q=AB"}{"valid":{"entries":[["q","AB"]],"serialized":"q=AB"},"short":{"error":"TypeError"},"long":{"error":"TypeError"},"record":"q=AB"} |
| Empty value direct string / keep / invisible true | "" | ""No selected invisible characters found | {"valid":{"entries":[["q",""]],"serialized":"q="},"short":{"error":"TypeError"},"long":{"error":"TypeError"},"record":"q="}{"valid":{"entries":[["q",""]],"serialized":"q="},"short":{"error":"TypeError"},"long":{"error":"TypeError"},"record":"q="} |
| Comma value direct string / keep / invisible true | "A,B"U+0041 U+002C U+0042 | "A,B"No selected invisible characters found | {"valid":{"entries":[["q","A,B"]],"serialized":"q=A%2CB"},"short":{"error":"TypeError"},"long":{"error":"TypeError"},"record":"q=A%2CB"}{"valid":{"entries":[["q","A,B"]],"serialized":"q=A%2CB"},"short":{"error":"TypeError"},"long":{"error":"TypeError"},"record":"q=A%2CB"} |
Pair shape is checked independently from its text value
For every supplied string the observer constructs a valid list containing one q-value pair, a short list entry containing only q, and a long entry with an extra third item. The valid branch succeeds, while both malformed shapes return TypeError. In the marked fixture only the valid pair serialization changes after cleanup: its percent-encoded marker disappears and the result is q=AB. The short and long branch errors persist. Deleting an invisible character from a value cannot supply a missing structural item or remove an extra array element.
An empty second item still completes the pair
The empty-value control constructs a genuine two-item entry whose second item is empty text. The saved entries list retains that empty string and serialized output is q=. The missing-value branch has no second item and fails instead. The comma-value control remains one value and serializes the comma as %2C; punctuation inside a string does not create another entry item. The record comparison gives the same valid serialization for each supplied string, while using a different constructor input shape. These observations make missing structure distinguishable from empty or comma-containing content.
Validate the outer representation before cleaning its fields
If query entries come from a table or parser, inspect that each intended pair has exactly the required components before passing it to this constructor. Keep an explicit policy for genuinely absent values rather than treating every malformed row as empty text. Our malformed lists are authored directly and never sent in a request. The observer does not implement a CSV parser, accept arbitrary iterables or define how a server interprets query data. It isolates three nested-array shapes and a plain-record reference in one runtime.
Constructor errors belong to a different layer
The cleaner operates on one string before the observer assembles these query inputs. Earlier record-array coverage examines coercion of an array stored as a record value; here the nested arrays are entries whose length is constrained. Earlier duplicate-export coverage starts with an already valid parameter list. Preserve input shape, constructor error and serialized value separately when troubleshooting. Our q field contains invented text only, with no credentials or network destination involved. None of the accepted pairs or rejected shapes establishes Claude authorship, statistical marking or an AI detector result.
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 constructor 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.