Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Why does an HTML pattern of AB reject ZABZ after cleanup?

HTML pattern checks the entire nonempty value. Our AB control passes, ZABZ fails, and an optional empty value passes. Removing U+200B repairs the interrupted AB fixture; it does not turn pattern validation into a substring search.

Tested October 25, 2026 · v24.22.1 · 4 measured runs

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked letters

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.

Before and after observations; full code points and strings are in the JSON download.
Fixture and modeInput string and code pointsOutput and cleaner statusObserved before / after
Marked letters
direct string / keep / invisible true
"A​B"
U+0041 U+200B U+0042
"AB"
Removed 1 invisible character
{"pattern":"AB","patternMismatch":true,"required":false,"valid":false,"value":"A​B"}
{"pattern":"AB","patternMismatch":false,"required":false,"valid":true,"value":"AB"}
Exact letters
direct string / keep / invisible true
"AB"
U+0041 U+0042
"AB"
No selected invisible characters found
{"pattern":"AB","patternMismatch":false,"required":false,"valid":true,"value":"AB"}
{"pattern":"AB","patternMismatch":false,"required":false,"valid":true,"value":"AB"}
Substring only
direct string / keep / invisible true
"ZABZ"
U+005A U+0041 U+0042 U+005A
"ZABZ"
No selected invisible characters found
{"pattern":"AB","patternMismatch":true,"required":false,"valid":false,"value":"ZABZ"}
{"pattern":"AB","patternMismatch":true,"required":false,"valid":false,"value":"ZABZ"}
Empty optional
direct string / keep / invisible true
""
""
No selected invisible characters found
{"pattern":"AB","patternMismatch":false,"required":false,"valid":true,"value":""}
{"pattern":"AB","patternMismatch":false,"required":false,"valid":true,"value":""}

Read the value and the mismatch flag together

The marked fixture contains A, U+200B and B. Its text remains intact when assigned to a text input, but patternMismatch is true for pattern AB. After the actual homepage callback removes the selected marker, the assigned value becomes AB and patternMismatch becomes false. The browser is checking a value against an attribute, while the cleaner only transforms the supplied string. Keeping those observations separate prevents a rejected field from being described as a failure of the removal operation.

A matching substring is insufficient

ZABZ contains the two letters AB contiguously, yet the native field still reports a mismatch. This is the control that distinguishes whole-value acceptance from an unanchored JavaScript search. The plain AB control succeeds without any character change. No explicit anchors appear in the attribute value. If a destination expects text surrounding AB, its chosen pattern needs to express that requirement; repeatedly cleaning ZABZ cannot make the outer letters disappear because they are ordinary content outside the deletion set.

The optional empty case has a different meaning

The empty control reports valid true and patternMismatch false with required false. That outcome does not show that empty text matches the literal letters AB. It shows why a format condition alone cannot express that content must exist. An application needs a separate presence requirement when empty input is unacceptable. This experiment deliberately leaves required unset to isolate the pattern behavior. It does not test custom validity messages, invalid regex syntax, interactive typing, server validation or every browser engine.

Reproduce the browser condition separately

The browser harness creates fresh detached input elements and reads their validity state without submitting a form. Browser observations retain the user agent; the Node rerun separately executes the saved homepage callback and reads those recorded browser results. Open the supplied browser reproducer for a new native-control run. These locally authored strings are not Claude responses, and an accepted pattern cannot certify authorship or statistical watermark removal. The earlier regex-pattern guide concerns changes inside regex source; this question instead concerns the HTML attribute acceptance contract.

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.cjs

Reference and next check

WHATWG HTML the-pattern-attribute 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.