CLAUDE WATERMARK REMOVER · PRACTICAL TEST
Can Object.assign change my cleaned text before throwing an error?
Yes in our fixture: text is updated, assignment to a read-only locked property throws TypeError, and the later field is never copied. A failed Object.assign is not an automatic rollback of earlier writes.
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 value direct string / keep / invisible true | "AB"U+0041 U+200B U+0042 | "AB"Removed 1 invisible character | {"error":"TypeError","text":"AB","locked":"fixed","hasLater":false,"keys":["text","locked"]}{"error":"TypeError","text":"AB","locked":"fixed","hasLater":false,"keys":["text","locked"]} |
| Plain value direct string / keep / invisible true | "AB"U+0041 U+0042 | "AB"No selected invisible characters found | {"error":"TypeError","text":"AB","locked":"fixed","hasLater":false,"keys":["text","locked"]}{"error":"TypeError","text":"AB","locked":"fixed","hasLater":false,"keys":["text","locked"]} |
| Empty value direct string / keep / invisible true | "" | ""No selected invisible characters found | {"error":"TypeError","text":"","locked":"fixed","hasLater":false,"keys":["text","locked"]}{"error":"TypeError","text":"","locked":"fixed","hasLater":false,"keys":["text","locked"]} |
| Retained joiner direct string / keep / invisible true | "AB"U+0041 U+200D U+0042 | "AB"No selected invisible characters found | {"error":"TypeError","text":"AB","locked":"fixed","hasLater":false,"keys":["text","locked"]}{"error":"TypeError","text":"AB","locked":"fixed","hasLater":false,"keys":["text","locked"]} |
The error occurs after one successful write
The target begins with text equal to old and an enumerable, non-writable locked property equal to fixed. The source order is text, locked and later. Object.assign first stores the supplied text, then throws TypeError while attempting to replace locked. The recorded target retains the new text, locked stays fixed, and hasLater is false. Recording only the exception would conceal the already completed mutation. Our keys field shows that the final object still has exactly text and locked rather than the unvisited source field.
Cleanup changes the payload but not the failure sequence
The marked input updates target.text with interrupted AB before cleanup and AB afterward. The ordinary text control reaches the same error with no selected marker. Empty text is also successfully written before the error, while the retained-joiner control preserves its joiner in the partially updated target. Every branch constructs a new target and source, avoiding state left behind by a prior failure. This makes the partial mutation reproducible without a server, shared configuration object or a real user record. The exclamation-style edits used in other guides are not involved here.
Define a commit policy before editing a live record
If a destination requires all fields to change together, an exception from a copying operation is not evidence that the record stayed unchanged. Review writable properties, setters and the intended transaction boundary before applying a cleaned payload to a shared target. Our fixture does not implement a transactional update, rollback routine or deep merge. It shows why the caller needs such a policy when partial state is unacceptable. Copying into a fresh object can have different semantics and still requires validation of the final record and its destination requirements.
Property failures differ from text failures
The cleaner neither creates the locked descriptor nor calls Object.assign. The TypeError is caused by the observer destination, while the cleaner produces its selected edit successfully. Earlier special-key coverage observes prototype assignment; this page uses ordinary text keys and a read-only data property. Earlier freeze coverage asks whether nested objects remain mutable, not whether a failed multi-property write leaves changes. All values are synthetic, and no global object is modified. These local mutation results establish no authorship, watermark removal or detector-score claim.
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 Object.assign 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.