Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Can a JSON reviver recover integer digits that Number has already rounded?

In our Node test, the reviver value rounds 9007199254740993 to 9007199254740992. Its context.source retains the original digits, allowing BigInt to preserve them. Converting the rounded value to BigInt cannot restore the lost digit.

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

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked integer

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 integer
direct string / keep / invisible true
"900719925474099​3"
U+0039 U+0030 U+0030 U+0037 U+0031 U+0039 U+0039 U+0032 U+0035 U+0034 U+0037 U+0034 U+0030 U+0039 U+0039 U+200B U+0033
"9007199254740993"
Removed 1 invisible character
{"error":"SyntaxError"}
{"type":"number","value":"9007199254740992","source":"9007199254740993","fromValue":"9007199254740992","fromSource":"9007199254740993"}
Unsafe integer
direct string / keep / invisible true
"9007199254740993"
U+0039 U+0030 U+0030 U+0037 U+0031 U+0039 U+0039 U+0032 U+0035 U+0034 U+0037 U+0034 U+0030 U+0039 U+0039 U+0033
"9007199254740993"
No selected invisible characters found
{"type":"number","value":"9007199254740992","source":"9007199254740993","fromValue":"9007199254740992","fromSource":"9007199254740993"}
{"type":"number","value":"9007199254740992","source":"9007199254740993","fromValue":"9007199254740992","fromSource":"9007199254740993"}
Safe integer
direct string / keep / invisible true
"42"
U+0034 U+0032
"42"
No selected invisible characters found
{"type":"number","value":"42","source":"42","fromValue":"42","fromSource":"42"}
{"type":"number","value":"42","source":"42","fromValue":"42","fromSource":"42"}
Quoted digits
direct string / keep / invisible true
"\"9007199254740993\""
U+0022 U+0039 U+0030 U+0030 U+0037 U+0031 U+0039 U+0039 U+0032 U+0035 U+0034 U+0037 U+0034 U+0030 U+0039 U+0039 U+0033 U+0022
"\"9007199254740993\""
No selected invisible characters found
{"type":"string","value":"9007199254740993","source":"\"9007199254740993\"","fromValue":null,"fromSource":null}
{"type":"string","value":"9007199254740993","source":"\"9007199254740993\"","fromValue":null,"fromSource":null}

A valid cleaned token can still lose numeric precision

The interrupted integer initially raises SyntaxError because its selected marker is inside the number token. Deletion produces valid JSON digits ending in 993. Parsing now reaches the root reviver, but the value field already ends in 992. The source field still contains the exact 993 spelling. Our observer converts both independently to BigInt and stores their decimal strings, exposing two different answers from the same callback invocation. The repair fixed JSON grammar; it did not increase the precision of the Number representation created during parsing.

The source and value branches have different evidence

Plain unsafe digits reproduce the discrepancy without any cleanup. The safe integer 42 yields identical source, value and both BigInt conversions, providing a reference within the exact integer range. Quoted digits remain a string and preserve the final three as text; their source field includes the original JSON quotes. We intentionally leave both BigInt diagnostics null for that string control instead of feeding quoted JSON source to a numeric constructor. The property type therefore matters when deciding whether source text represents a number literal or a string literal.

Retain original source before choosing a revival policy

For an integer field that must preserve every digit, keep its source representation and apply an explicit schema rather than blindly converting every JSON number. This observer uses primitive roots and integer spellings only. Decimal fractions, exponent forms, nested mutations and runtimes without reviver context support require separate checks. A schema may prefer quoted identifiers rather than a numeric token. The result demonstrates the current recorded Node runtime, not support in every browser or older server. Our downloads retain that version so the context field can be verified rather than assumed.

Precision recovery is separate from watermark interpretation

The earlier BigInt guide compares direct string conversion; the earlier reviver guide deletes matching keys. Here the new question is when the reviver receives a numeric value relative to precision loss and which source bytes remain represented as text. We never infer Claude provenance from a valid or invalid number. All four strings are synthetic and no model output, search ranking, detector score or statistical watermark was measured. Preserve the original JSON beside its parsed result when diagnosing a damaged identifier.

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 JSON.parse 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.