CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Why does a single-line input join lines even when the cleaner preserves them?
Our text input strips CR and LF on value assignment, turning A B into AB. The cleaner preserves those line endings. U+2028 stays in the input in our control. Capture both the cleaned string and the destination value to locate the change.
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 were measured separately in Chromium 156 using detached native controls and programmatic value assignment. Node reruns the actual homepage callback and reads the saved browser observations; it does not independently rerun the browser. No form was submitted. 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 line direct string / keep / invisible true | "A\nB"U+0041 U+200B U+000A U+0042 | "A\nB"Removed 1 invisible character | {"input":"AB","inputUnits":3,"lineFeedRemaining":false,"sourceUnits":4,"unicodeSeparatorRemaining":false}{"input":"AB","inputUnits":2,"lineFeedRemaining":false,"sourceUnits":3,"unicodeSeparatorRemaining":false} |
| CRLF line direct string / keep / invisible true | "A\r\nB"U+0041 U+000D U+000A U+0042 | "A\r\nB"No selected invisible characters found | {"input":"AB","inputUnits":2,"lineFeedRemaining":false,"sourceUnits":4,"unicodeSeparatorRemaining":false}{"input":"AB","inputUnits":2,"lineFeedRemaining":false,"sourceUnits":4,"unicodeSeparatorRemaining":false} |
| Unicode separator direct string / keep / invisible true | "A
B"U+0041 U+2028 U+0042 | "A
B"No selected invisible characters found | {"input":"A
B","inputUnits":3,"lineFeedRemaining":false,"sourceUnits":3,"unicodeSeparatorRemaining":true}{"input":"A
B","inputUnits":3,"lineFeedRemaining":false,"sourceUnits":3,"unicodeSeparatorRemaining":true} |
| Plain value direct string / keep / invisible true | "AB"U+0041 U+0042 | "AB"No selected invisible characters found | {"input":"AB","inputUnits":2,"lineFeedRemaining":false,"sourceUnits":2,"unicodeSeparatorRemaining":false}{"input":"AB","inputUnits":2,"lineFeedRemaining":false,"sourceUnits":2,"unicodeSeparatorRemaining":false} |
Two processing stages remove different things
The first source has A, U+200B, a line feed and B. Before cleanup, the text input retains the marker but strips the line feed. The actual homepage callback removes the marker while preserving the line feed in its output. Assigning that cleaned output then produces AB in the destination. The saved source, cleaned output and receiving input value therefore describe three different strings. Blaming all missing characters on cleanup would misattribute the browser control sanitization.
The CRLF reference needs no invisible marker
A CRLF line break between A and B becomes AB on text-input assignment even without any cleanup change. The source length is four units while the input value has two. The ordinary AB reference remains two units at both stages. These controls establish that the destination can join lines by itself; no chosen removal checkbox or dash option is involved in that conversion. The measured control is specifically input type text, rather than a generic storage container for arbitrary multiline strings.
Not every separator follows the CRLF path
The U+2028 control retains its separator and remains three units in the single-line input. The unicodeSeparatorRemaining flag distinguishes that case from the stripped line-feed controls. A display that appears single-line does not imply that all Unicode line-like code points have been removed. This experiment does not test CSS wrapping, keyboard entry, clipboard formats, line-break serialization during submission or other input types. Earlier textarea coverage measures CRLF normalization to a line feed; this page instead measures removal from a different destination element.
Compare values at each boundary
When line structure matters, inspect the actual receiving field and choose a control suited to the content. Keep the cleaned string separately so assignment does not erase diagnostic evidence. The browser reproducer constructs detached elements, while the Node harness repeats the saved cleaner and consumes recorded destination observations. The fixtures are synthetic, not imported documents or Claude responses. A joined value is an observed control behavior here, not proof that line separators are watermarks or that any model-level signal was removed.
Reproduce this test
For a fresh native-control measurement, save and open reproduce-browser.html in your browser. It embeds the exact fixture observer and saved homepage script, runs locally, and shows its user agent. For the Node cleanup rerun, save reproduce.cjs, tested-app.js and browser-observations.json 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 HTML text-(type=text)-state-and-search-state-(type=search) 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.