CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Why does cleaning a query suddenly match every string?
Our marker-only query becomes empty. String.includes of that empty query returns true for Alpha, Beta and even the empty target. A separate empty-query guard returns no matches in our example; that policy belongs to the search application.
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 only direct string / keep / invisible true | ""U+200B | ""Removed 1 invisible character | {"queryUnits":1,"empty":false,"matches":[{"text":"Alpha","includes":false},{"text":"Beta","includes":false},{"text":"","includes":false}],"guardedMatches":[]}{"queryUnits":0,"empty":true,"matches":[{"text":"Alpha","includes":true},{"text":"Beta","includes":true},{"text":"","includes":true}],"guardedMatches":[]} |
| Empty control direct string / keep / invisible true | "" | ""No selected invisible characters found | {"queryUnits":0,"empty":true,"matches":[{"text":"Alpha","includes":true},{"text":"Beta","includes":true},{"text":"","includes":true}],"guardedMatches":[]}{"queryUnits":0,"empty":true,"matches":[{"text":"Alpha","includes":true},{"text":"Beta","includes":true},{"text":"","includes":true}],"guardedMatches":[]} |
| Matching query direct string / keep / invisible true | "Alpha"U+0041 U+006C U+200B U+0070 U+0068 U+0061 | "Alpha"Removed 1 invisible character | {"queryUnits":6,"empty":false,"matches":[{"text":"Alpha","includes":false},{"text":"Beta","includes":false},{"text":"","includes":false}],"guardedMatches":[]}{"queryUnits":5,"empty":false,"matches":[{"text":"Alpha","includes":true},{"text":"Beta","includes":false},{"text":"","includes":false}],"guardedMatches":["Alpha"]} |
| Absent query direct string / keep / invisible true | "Z"U+005A | "Z"No selected invisible characters found | {"queryUnits":1,"empty":false,"matches":[{"text":"Alpha","includes":false},{"text":"Beta","includes":false},{"text":"","includes":false}],"guardedMatches":[]}{"queryUnits":1,"empty":false,"matches":[{"text":"Alpha","includes":false},{"text":"Beta","includes":false},{"text":"","includes":false}],"guardedMatches":[]} |
An invisible-looking query can change from nonempty to empty
Before cleanup the selected marker is one UTF-16 unit and occurs in none of our three targets. Deleting it produces a zero-length query, which includes accepts in Alpha, Beta and the empty target. The empty control already has that behavior with no edit. The interrupted Alpha control instead becomes a real matching query and selects only Alpha. The absent Z control remains nonempty and selects nothing. These controls separate empty-substring semantics from a successful content match. Our record includes query length, an explicit empty flag, every raw boolean and the result of an independently chosen guard. The homepage cleaner is only responsible for the string edit.
A guard encodes a product decision beyond the string method
The observer’s guardedMatches field returns an empty list when query length is zero. That is one explicit application policy, not a change to String.includes and not the only possible search experience. Some interfaces deliberately show all items when the query is empty. Our earlier word-boundary guide studies deletion joining neighboring content; here there are no surviving characters in the main query. We do not trim spaces, fold case, normalize accents or search a real collection. The three targets are fixed invented values. No search volume, user behavior or production ranking result can be inferred from their inclusion booleans or from the count of controls.
Check the query after the transformations your search uses
If a nonempty query is required, apply that requirement to the final query representation rather than only to the initial input. Inspect the empty case separately from a no-match case so a user can understand why an interface changes. Preserve source and result when debugging a query that appears visually blank. The marked Alpha row prevents incorrectly treating all cleanup as emptying the query, while the empty target shows why even target length does not rescue this particular raw check. The attached experiment does not implement a search component or prescribe its user experience. It provides a reproducible boundary that application code can handle according to its own documented empty-input policy.
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
ECMAScript string operations 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.