Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Why does mapping parseInt over three cleaned tens return 10, NaN, 2?

Our ["10", "10", "10"].map(parseInt) returns 10, NaN, 2 because map supplies an index as parseInt’s radix argument. A wrapper fixing radix 10 returns three tens. Cleanup does not change callback argument contracts.

Tested October 18, 2026 · v24.19.0 · 4 measured runs

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked middle value

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.

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 middle value
direct string / keep / invisible true
"10,1​0,10"
U+0031 U+0030 U+002C U+0031 U+200B U+0030 U+002C U+0031 U+0030
"10,10,10"
Removed 1 invisible character
{"fields":["10","1​0","10"],"direct":["10","NaN","2"],"explicitDecimal":["10","1","10"],"wholeNumbers":["10","NaN","10"]}
{"fields":["10","10","10"],"direct":["10","NaN","2"],"explicitDecimal":["10","10","10"],"wholeNumbers":["10","10","10"]}
Repeated tens
direct string / keep / invisible true
"10,10,10"
U+0031 U+0030 U+002C U+0031 U+0030 U+002C U+0031 U+0030
"10,10,10"
No selected invisible characters found
{"fields":["10","10","10"],"direct":["10","NaN","2"],"explicitDecimal":["10","10","10"],"wholeNumbers":["10","10","10"]}
{"fields":["10","10","10"],"direct":["10","NaN","2"],"explicitDecimal":["10","10","10"],"wholeNumbers":["10","10","10"]}
Different digits
direct string / keep / invisible true
"11,12,13"
U+0031 U+0031 U+002C U+0031 U+0032 U+002C U+0031 U+0033
"11,12,13"
No selected invisible characters found
{"fields":["11","12","13"],"direct":["11","NaN","1"],"explicitDecimal":["11","12","13"],"wholeNumbers":["11","12","13"]}
{"fields":["11","12","13"],"direct":["11","NaN","1"],"explicitDecimal":["11","12","13"],"wholeNumbers":["11","12","13"]}
Zero controls
direct string / keep / invisible true
"0,0,0"
U+0030 U+002C U+0030 U+002C U+0030
"0,0,0"
No selected invisible characters found
{"fields":["0","0","0"],"direct":["0","NaN","0"],"explicitDecimal":["0","0","0"],"wholeNumbers":["0","0","0"]}
{"fields":["0","0","0"],"direct":["0","NaN","0"],"explicitDecimal":["0","0","0"],"wholeNumbers":["0","0","0"]}

The unmarked reference already shows the callback mismatch

The observer splits the reference 10,10,10 into three fields and passes parseInt directly as the map callback. Its outputs are ten, NaN and two. A second mapping wraps parseInt and supplies radix ten explicitly; that produces ten for every field. A third mapping uses Number and also produces three tens for this reference. We save numerical outputs as text labels so NaN remains identifiable instead of becoming JSON null. The direct callback receives each field together with its array index, which parseInt interprets as its second argument. No invisible character is required to trigger the discrepancy. This is a caller-side argument contract, rather than a failure by the cleaner to remove enough content.

The marked field reveals two independent parsing issues

The authored marked input places U+200B inside the middle 10. The explicit decimal wrapper initially returns the leading prefix one for that field, while Number reports NaN. Cleanup joins the digits, so both paths then return ten. The direct parseInt mapping still reports NaN at index one and two for the last ten. The different-digit control produces eleven, NaN and one under the direct callback, while the zero control still produces NaN in the middle position. Earlier work covers direct parseInt with an explicit decimal radix accepting partial text. Here the independent gap is the extra arguments supplied by map, and the controls show why merely repairing a field does not repair that invocation.

Make callback arguments and field validation explicit

When mapping a parser that accepts optional arguments, use a wrapper if the collection callback supplies other arguments with different meanings. Verify the resulting numbers against the field’s complete grammar, type and range requirements; the explicit-radix wrapper still accepts prefixes in our marked pre-cleanup row and is not a complete validator. Keep a repeated-value control in a regression check because inconsistent outputs at different positions can reveal accidental index dependence. This reproducer uses comma splitting only to build a simple field list; it is not a CSV parser, benchmark or compatibility survey. The experiment establishes the recorded callback behavior and selected deletion while making no inference about the provenance of arbitrary text or a statistical watermark.

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

Reference and next check

ECMAScript Array.map 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.