CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Why is my cleaned word longer after toUpperCase()?
Uppercase mapping can expand characters. Our cleaned straße has six UTF-16 units, but STRASSE has seven; the ligature ffi becomes three letters. Lowercasing that result does not restore the original spelling.
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 German word direct string / keep / invisible true | "straße"U+0073 U+0074 U+0072 U+0061 U+200B U+00DF U+0065 | "straße"Removed 1 invisible character | {"upper":"STRASSE","inputUnits":7,"upperUnits":8,"roundTrip":"strasse","roundTripEqual":false}{"upper":"STRASSE","inputUnits":6,"upperUnits":7,"roundTrip":"strasse","roundTripEqual":false} |
| Plain German word direct string / keep / invisible true | "straße"U+0073 U+0074 U+0072 U+0061 U+00DF U+0065 | "straße"No selected invisible characters found | {"upper":"STRASSE","inputUnits":6,"upperUnits":7,"roundTrip":"strasse","roundTripEqual":false}{"upper":"STRASSE","inputUnits":6,"upperUnits":7,"roundTrip":"strasse","roundTripEqual":false} |
| Ligature direct string / keep / invisible true | "ffi"U+FB03 | "ffi"No selected invisible characters found | {"upper":"FFI","inputUnits":1,"upperUnits":3,"roundTrip":"ffi","roundTripEqual":false}{"upper":"FFI","inputUnits":1,"upperUnits":3,"roundTrip":"ffi","roundTripEqual":false} |
| ASCII word direct string / keep / invisible true | "road"U+0072 U+006F U+0061 U+0064 | "road"No selected invisible characters found | {"upper":"ROAD","inputUnits":4,"upperUnits":4,"roundTrip":"road","roundTripEqual":true}{"upper":"ROAD","inputUnits":4,"upperUnits":4,"roundTrip":"road","roundTripEqual":true} |
The later case mapping adds length independently of deletion
The marked German fixture contains seven units before cleanup and maps to an eight-unit uppercase result. Deletion removes its U+200B, leaving a six-unit word that maps to seven units. The plain German reference produces the same final uppercase text without cleanup. The ligature control expands from one unit to three uppercase letters. The ASCII word has the same length before and after mapping and lowercases back to its original sequence. We save the mapped string, both unit counts, the lowercase result and exact round-trip comparison for every stage. This locates the added length in the destination case conversion rather than attributing it to an invisible character reappearing.
Default case conversion is not a reversible character substitution
The observer calls toUpperCase followed by toLowerCase and uses no locale parameter. Our Turkish guide instead varies locale-sensitive lowercase behavior. This page holds the operation fixed and measures expansion and loss of original spelling in a round trip. The homepage leaves the visible sharp s and ligature untouched in these fixtures; it does not convert their case. Unit counts are JavaScript string lengths, not font widths, code-point quotas or bytes. We do not measure every Unicode casing rule, title casing, database comparisons or case-insensitive account policies. A visually useful uppercase label can therefore remain a different stored representation with a different count.
Apply length checks to the representation that is stored
If a destination uppercases cleaned input before saving it, validate its actual mapped output against that destination’s quota. Preserve the original spelling separately when a reversible display transformation matters. Do not reconstruct it by lowercasing the uppercase string: the German and ligature controls explicitly fail that test in our runtime. The ASCII success is a control for this word, not proof that all text round-trips. Our downloads retain every measured representation and a standalone script; they do not choose an identifier-equivalence policy or prescribe replacing legitimate letters. Review the destination’s casing contract before treating two mapped strings as the same record, and test the final stored text after an intentional edit.
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.