SVRN-1029 — isSafeviewElem TypeError on node removal

Load this page through isolation (DOM mode / ACR1). It reproduces the renderer/thin-client crash introduced by commit be8a0c5725e ("Refactor DOM clearing to retain SV nodes").

Mechanism: removing a node fires the REMOVE_ELEMENT opcode. The thin-client's onRemoveNode unconditionally calls delUidForNodeAndDescendants(node), whose first statement is isSafeviewElem(node) — run on the raw origin-page node and every descendant. Inside it, id = node.id. A <form> containing <input name="id"> is DOM-clobbered: form.id returns that child element (not a string). It is truthy, so it passes the if (id && …) guard, then __startswith(id, 'cof-server:') calls id.substring(...)TypeError: id.substring is not a function.

Expected on a fixed build: every button removes its target and the page keeps rendering. On the broken build: the CRASH cases freeze / tear down the isolated tab (watch for renderer disconnect + surrogate reap); the SAFE control cases stay healthy.

status: ready. Open the surrogate/renderer console; click the buttons top to bottom.

Case A — remove a clobbered node directly (primary repro)

onRemoveNodedelUidForNodeAndDescendants(form)isSafeviewElem(form) on the clobbered node itself.

clobbered form A (form.id → the <input>)

Case B — remove an ancestor of a clobbered node (descendant recursion)

The removed node is an innocent <div>; the crash comes from delUidForNodeAndDescendants recursing into childNodes and reaching the clobbered form.

plain wrapper div (its own .id is fine)

clobbered form nested inside the removed subtree

Case C — mutation-driven removal (no button click needed)

Confirms the trigger is the removal itself, not any user gesture. This node is auto-removed 3s after you press start, via a script the page runs on its own.

clobbered form C — auto-removed on a timer

Case D — control: real string id (must NOT crash)

Same shape but the form has a normal string id and no clobbering child named id. isSafeviewElem should return cleanly. Use this to prove the fix is specific to clobbering.

normal form D (form.id === "realStringId")

Case E — control: plain element, no id (must NOT crash)

plain div E, no clobbering