diff --git a/crates/engine/src/js_dom_bridge_tests/part18.rs b/crates/engine/src/js_dom_bridge_tests/part18.rs index b8fcca538..776cec74d 100644 --- a/crates/engine/src/js_dom_bridge_tests/part18.rs +++ b/crates/engine/src/js_dom_bridge_tests/part18.rs @@ -2406,3 +2406,255 @@ fn t8r_inner_html_materialized_custom_element_ctor_once() { "t8r N1:innerHTML 物化的自定义元素 ctor 恰 1 次,查询产物为真实升级实例,createElement 基线不受扰" ); } + +// t8r-4(site-compat bilibili-20261002-r1 续):sel 路径 innerHTML 同步查询可见性。 +// 真站链:bilibili nano sendBar(树内元素)`(0,v.W)(sendBar, renderFragment())`(HTML +// 串注入)→ `this.template = { info: sendBar.querySelector('.{i}-video-info'), online: +// sendBar.querySelector('.{i}-video-info-online'), … }` → `template.info.style` 消费。 +// ZW 现状:树内容器 innerHTML 后 host apply 异步,立即相对查询走 host 快照 miss → +// null(注册表成员全 null → resize/hideDm/renderOnlineCount 消费崩,npd.314 null 簇)。 +// 修复:R322 host-miss 兜底臂扩扫桶 added 的解析顶层代理(R304 槽、无 handle 无 +// sel)——compound 匹配命中现场 _wcRebuildAsHandle 物化为 detached 真 handle 树 +//(全接口),原位替换桶成员/全局表/by-id 索引 + 写 sel 域父反链 + `_zwMatParsed` +// 标记(apply 代际边界 K3 定点清除)。setter 记账面(mutation 队列/CE attach/ +// _mo_notify/K3)保持解析代理原样零变化。已 upgrade CE 代理按代理返回不物化 +//(防二次 ctor)。 +// spec https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-innerhtml +#[test] +fn t8r4_sel_path_inner_html_immediate_query_materialized() { + use std::sync::{Arc, Mutex}; + use zero_script_sandbox::{Sandbox, V8Sandbox}; + let mut sandbox = V8Sandbox::with_config(zero_script_sandbox::SandboxConfig { + persistent_context: true, + ..Default::default() + }) + .unwrap(); + sandbox.execute(generate_js_dom_shim()).unwrap(); + let mutations = Arc::new(Mutex::new(Vec::::new())); + let dom_html = Arc::new(Mutex::new("
".to_string())); + let page_url = Arc::new(Mutex::new("https://zero.test/t8r4-sel".to_string())); + let canvas_registry = Arc::new(Mutex::new(crate::js_dom_bridge::CanvasRegistry::new())); + register_dom_callbacks(&mut sandbox, &mutations, &dom_html, &page_url, &canvas_registry, None); + let out = sandbox.execute(r#"(function(){ + var r = []; + var sendbar = document.querySelector('#sendbar'); + sendbar.innerHTML = '
x
'; + // ① 立即相对查询命中且全接口(真站 TypeError 根面)。 + var info = sendbar.querySelector('.bpx-video-info'); + r.push('info:' + (info === null ? 'null' : (typeof info.style === 'object' ? 'wrapper' : 'proxy'))); + var online = info ? info.querySelector('.bpx-video-info-online') : null; + r.push('online:' + (online && typeof online.style === 'object' ? 'ok' : 'bad')); + // ② querySelectorAll 融合(R309 兜底面)。 + var all = sendbar.querySelectorAll('div'); + r.push('qsa:' + (all.length === 2 ? 'ok' : 'len:' + all.length)); + // ③ childNodes/firstChild 融合(R304/R56 既有面零回归)。 + r.push('fc:' + (sendbar.firstChild && sendbar.firstChild.nodeType === 1 ? 'ok' : 'bad')); + r.push('cc:' + (sendbar.childNodes.length === 2 ? 'ok' : 'len:' + sendbar.childNodes.length)); + // ④ parentNode 反链(sel 域 append 家族同款)。 + r.push('parent:' + (info && info.parentNode === sendbar ? 'ok' : 'bad')); + // ⑤ 接口写读回(真站消费形态:this.template.info.style.width = …)。 + var sw = 'ok'; + try { info.style.setProperty('opacity', '0.6'); sw = info.style.getPropertyValue('opacity') === '0.6' ? 'ok' : 'bad'; } + catch (e) { sw = 'throw:' + e.name; } + r.push('styleWrite:' + sw); + // ⑥ 结构保真(第二顶层子 + 深层文本)。 + var dm = sendbar.querySelector('.bpx-video-dm'); + r.push('sib:' + (dm && online && online.textContent === 'x' ? 'ok' : 'bad')); + // ⑦ 负控制:不匹配选择器必须仍为 null(防过匹配护栏)。 + r.push('nope:' + (sendbar.querySelector('.nope') === null ? 'null' : 'hit')); + return r.join('|'); +})()"#).unwrap().value; + assert_eq!( + out, + "info:wrapper|online:ok|qsa:ok|fc:ok|cc:ok|parent:ok|styleWrite:ok|sib:ok|nope:null", + "t8r-4:sel 路径 innerHTML 后立即相对查询命中物化 wrapper(querySelector/querySelectorAll/childNodes/反链/接口写读回/结构保真/负控制)" + ); +} + +// t8r-4 变体:① 纯文本 sel 路径零回归(R34xx/R100 文本注册面);② 混合 markup+文本顶层; +// ③ 清空重注(二次 innerHTML 后新产物仍可查);④ sel 域 CE attach——setter 链已对解析 +// 代理 upgrade(prototype 印记),R322 扩扫臂判已 upgrade 按代理返回不物化,ctor 恒 1。 +#[test] +fn t8r4_sel_path_variants_and_ce_once() { + use std::sync::{Arc, Mutex}; + use zero_script_sandbox::{Sandbox, V8Sandbox}; + let mut sandbox = V8Sandbox::with_config(zero_script_sandbox::SandboxConfig { + persistent_context: true, + ..Default::default() + }) + .unwrap(); + sandbox.execute(generate_js_dom_shim()).unwrap(); + let mutations = Arc::new(Mutex::new(Vec::::new())); + let dom_html = Arc::new(Mutex::new("
".to_string())); + let page_url = Arc::new(Mutex::new("https://zero.test/t8r4-var".to_string())); + let canvas_registry = Arc::new(Mutex::new(crate::js_dom_bridge::CanvasRegistry::new())); + register_dom_callbacks(&mut sandbox, &mutations, &dom_html, &page_url, &canvas_registry, None); + let out = sandbox.execute(r#"(function(){ + var r = []; + // ① 纯文本 sel 路径零回归。 + var sb = document.querySelector('#sb2'); + sb.innerHTML = 'plain text'; + r.push('text:' + (sb.firstChild && sb.firstChild.nodeType === 3 && sb.firstChild.data === 'plain text' ? 'ok' : 'bad')); + // ② 混合 markup+文本顶层:元素子物化、尾文本子保持代理。 + sb.innerHTML = 'xtail'; + var hb = sb.querySelector('.h'); + var tl = sb.childNodes[1]; + r.push('mix:' + (hb && typeof hb.style === 'object' && tl && tl.nodeType === 3 && tl.data === 'tail' ? 'ok' : 'bad')); + // ③ 清空重注:二次 innerHTML 后新产物仍可查(旧物化树被替换)。 + var sb3 = document.querySelector('#sb3'); + sb3.innerHTML = '1'; + var first = sb3.querySelector('.a'); + sb3.innerHTML = '2'; + var second = sb3.querySelector('.b'); + r.push('reIh:' + (first && second && typeof second.style === 'object' ? 'ok' : 'bad')); + // ④ sel 域 CE attach ctor 恒 1(createElement 物化构造 + attach 不重复 upgrade)。 + var made = 0; + class T8r4Ce extends HTMLElement { + constructor() { super(); made++; } + } + customElements.define('t8r4-ce', T8r4Ce); + sb3.innerHTML = ''; + var q = sb3.querySelector('t8r4-ce'); + r.push('ctor:' + made); + r.push('isInst:' + (q instanceof T8r4Ce ? 'ok' : 'bad')); + return r.join('|'); +})()"#).unwrap().value; + assert_eq!( + out, + "text:ok|mix:ok|reIh:ok|ctor:1|isInst:ok", + "t8r-4:纯文本/混合顶层/清空重注零回归 + sel 域 CE attach ctor 恰 1 次" + ); +} + +// t8r-4 返修(PR #131 双审查统一返修轮):扩扫臂豁免面 + K3 作废臂钉测—— +// ① K3 `_zwMatParsed` 作废(审查① blocking):innerHTML → 查询触发物化 → host apply +// (apply → bump 代际)→ re-register → 断言 childNodes 无重复并入(K3 新臂禁用 +// 变异下物化 wrapper 留桶 + 反链,overlay 重复并入 = 3:仅被查询物化的首子); +// ② noWire 豁免(审查② F1):createContextualFragment + insertBefore 的 noWire 解析 +// 子匹配查询按代理返回(可见性=代理匹配面一致),apply 代际 bump 后不消失(豁免 +// 禁用变异下物化打标被 K3 作废 → post 丢子); +// ③ CE 后代单 ctor(审查② F2):setter 期 attach 已递归 upgrade 后代,匹配根的查询 +// 展平检测命中印记 → 整条目回退代理语义、ctor 恒 1(CE 检测禁用变异下 createElement +// 二次构造 → ctor:2)。 +// spec https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-innerhtml +#[test] +fn t8r4_k3_invalidate_nowire_and_ce_subtree() { + use std::sync::{Arc, Mutex}; + use zero_script_sandbox::{Sandbox, V8Sandbox}; + + let mut sandbox = V8Sandbox::with_config(zero_script_sandbox::SandboxConfig { + persistent_context: true, + ..Default::default() + }) + .unwrap(); + sandbox.execute(generate_js_dom_shim()).unwrap(); + let mutations = Arc::new(Mutex::new(Vec::::new())); + let dom_html = Arc::new(Mutex::new( + "
" + .to_string(), + )); + let page_url = Arc::new(Mutex::new("https://zero.test/t8r4-k3nw".to_string())); + let canvas_registry = Arc::new(Mutex::new(crate::js_dom_bridge::CanvasRegistry::new())); + + // 宿主 apply 语义(镜像 part26.rs slice13 的 host_apply:apply → bump,代际边界; + // bump 生产调用点 crates/webview/src/webview.rs:2245/4085)。 + fn host_apply( + sandbox: &mut V8Sandbox, + mutations: &Arc>>, + dom_html: &Arc>, + ) { + let tail: Vec = mutations.lock().unwrap().clone(); + if tail.is_empty() { + return; + } + let new_html = crate::js_dom_bridge::apply_mutations_to_html( + &dom_html.lock().unwrap().clone(), + &tail, + ) + .unwrap(); + *dom_html.lock().unwrap() = new_html; + crate::js_dom_bridge::bump_dom_view_gen(); + mutations.lock().unwrap().clear(); + crate::js_dom_bridge::bump_mut_drain_gen(); + sandbox + .execute("if (typeof globalThis.__zw_apply_generation_bump === 'function') globalThis.__zw_apply_generation_bump();") + .unwrap(); + } + + register_dom_callbacks(&mut sandbox, &mutations, &dom_html, &page_url, &canvas_registry, None); + + // 臂 ③:CE 后代单 ctor(纯 JS;先跑避免后续 re-register/reset 清桶干扰)。 + let ce_out = sandbox.execute(r#"(function(){ + var r = []; + globalThis.__ceMade = 0; + class T8r4CeSub extends HTMLElement { + constructor() { super(); globalThis.__ceMade++; } + } + customElements.define('t8r4-ce-sub', T8r4CeSub); + var cec = document.getElementById('cec'); + cec.innerHTML = '
'; + r.push('ceAfterSet:' + globalThis.__ceMade); + var q = cec.querySelector('.ce-root'); + r.push('ceHit:' + (q ? 'ok' : 'null')); + r.push('ceAfterQ:' + globalThis.__ceMade); + return r.join('|'); +})()"#).unwrap().value; + assert_eq!( + ce_out, + "ceAfterSet:1|ceHit:ok|ceAfterQ:1", + "t8r-4 返修③:CE 后代已 upgrade 时匹配根查询回退代理语义,ctor 恒 1" + ); + + // 臂 ②:noWire 豁免(纯 JS;bump 直调为忠实模拟生产调用点 webview.rs:2245/4085)。 + let nw_out = sandbox.execute(r#"(function(){ + var r = []; + var cnw = document.getElementById('nw'); + var fw = document.createRange().createContextualFragment('x'); + cnw.insertBefore(fw, null); + var h1 = cnw.querySelector('.nwel'); + r.push('nwPre:' + (h1 ? 'ok' : 'null')); + r.push('nwMat:' + (h1 && typeof h1.style === 'object' ? 'wrapper' : 'proxy')); + if (typeof globalThis.__zw_apply_generation_bump === 'function') globalThis.__zw_apply_generation_bump(); + r.push('nwPost:' + (cnw.querySelector('.nwel') !== null ? 'ok' : 'lost')); + r.push('nwFc:' + (cnw.firstChild ? 'yes' : 'null')); + return r.join('|'); +})()"#).unwrap().value; + assert_eq!( + nw_out, + "nwPre:ok|nwMat:proxy|nwPost:ok|nwFc:yes", + "t8r-4 返修②:noWire 解析子匹配查询按代理返回,apply 代际 bump 后不消失" + ); + + // 臂 ①:K3 `_zwMatParsed` 作废(Rust host apply 序列,镜像 slice13)。 + sandbox + .execute( + "var c1 = document.getElementById('k3c');\n\ + c1.innerHTML = 'ab';\n\ + var m1 = c1.querySelector('.k1');\n\ + globalThis.__k3mat = (m1 && typeof m1.style === 'object') ? 'wrapper' : (m1 ? 'proxy' : 'null');", + ) + .unwrap(); + assert_eq!( + sandbox.execute("globalThis.__k3mat").unwrap().value, + "wrapper", + "t8r-4 返修①:查询触发物化为 wrapper" + ); + host_apply(&mut sandbox, &mutations, &dom_html); + register_dom_callbacks(&mut sandbox, &mutations, &dom_html, &page_url, &canvas_registry, None); + sandbox + .execute( + "globalThis.__k3post = c1.childNodes.length;\n\ + globalThis.__k3c0 = c1.childNodes[0] ? c1.childNodes[0].textContent : '';", + ) + .unwrap(); + assert_eq!( + sandbox.execute("globalThis.__k3post").unwrap().value, + "2", + "t8r-4 返修①:apply 代际后物化 wrapper 已被 K3 作废,fresh 基底无重复并入" + ); + assert_eq!( + sandbox.execute("globalThis.__k3c0").unwrap().value, + "a", + "t8r-4 返修①:fresh 基底内容正确" + ); +} diff --git a/crates/engine/src/js_dom_shim/part04.js b/crates/engine/src/js_dom_shim/part04.js index 4ee8f74cd..da1550cca 100644 --- a/crates/engine/src/js_dom_shim/part04.js +++ b/crates/engine/src/js_dom_shim/part04.js @@ -7985,7 +7985,81 @@ if (_r322bq && _r322bq.added.length) { for (var _r322qa = 0; _r322qa < _r322bq.added.length; _r322qa++) { var _r322qn = _r322bq.added[_r322qa]; - if (!_r322qn || !_r322qn.__zwHandle) continue; + if (!_r322qn || !_r322qn.__zwHandle) { + // t8r-4(site-compat bilibili-20261002-r1 续):sel 路径 innerHTML 的 + // 解析代理物化兜底——setter 落树的 host apply 异步,窗口内立即相对 + // 查询走 host 快照 miss(npd.314:bilibili nano sendBar widget 注册 + // 表 this.template.info/online 等全 null → resize/hideDm/ + // renderOnlineCount 消费崩)。桶 added 的解析顶层代理(R304 槽、 + // 无 handle 无 sel)compound 匹配命中即现场 _wcRebuildAsHandle + // 物化为 detached 真 handle 树(全接口),原位替换桶成员/全局表/ + // by-id 索引并写 sel 域父反链(overlay/childNodes 融合同一 + // wrapper,R309 identity 双源教训),`_zwMatParsed` 标记供 apply + // 代际边界 K3 定点清除(快照已含本 turn——与解析补偿 added 同批 + // 作废)。物化失败回退代理原样(可见性保持既有 R3254-K3 代理匹配 + // 语义)。两类豁免(返修轮,双审查发现): + // ① noWire 槽(R97 fragment 视图/createContextualFragment 形态) + // ——子从未 wire 进 host 快照,物化打标会被 K3 在 apply 代际 + // 边界作废而整体消失(t8i 同源语义);匹配命中按代理返回 + // (可见性与代理匹配面一致),不物化不打标。 + // ② 子树含已 upgrade CE(含根)——物化经 createElement 会对已 + // upgrade 元素重复 ctor(setter 期 __zwCeAttachForAdded 已递归 + // upgrade 全子树,t8r N1 查询面变体);展平逐元素反查 registry + + // prototype 印记(_ceRunCtor 挂接语义),命中整条目回退代理。 + // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-innerhtml + if (!_r322qn || _r322qn.nodeType !== 1 || _r322qn.__zwSelector + || !_r322qn._zwSelPendingParent || _r322qn._zwSelPendingParent.parentSel !== sel) continue; + try { + if (!_matchCompoundOf(_r322qn, _r322compQ)) continue; + // noWire 槽(R97 fragment 视图/createContextualFragment 形态): + // 子从未 wire 进 host 快照,K3 apply 代际清除对它不豁免就会在 + // bump 后从 overlay 整体消失(t8i 同源语义)——匹配命中按代理 + // 返回(可见性与代理匹配面一致),不物化不打标。 + if (_r322qn._zwSelPendingParent.noWire) return _r322qn; + var _r322ceHit = false; + try { + var _r322flat = []; + _zwHCCollectSubtree(_r322qn, _r322flat); + for (var _r322fi = 0; _r322fi < _r322flat.length; _r322fi++) { + var _r322fe = _r322flat[_r322fi]; + if (!_r322fe || _r322fe.nodeType !== 1) continue; + var _r322ftag = ''; + try { _r322ftag = String(_r322fe.localName || _r322fe.tagName || '').toLowerCase(); } catch (_e322ft) {} + var _r322fis = null; + try { _r322fis = _r322fe.getAttribute('is'); } catch (_e322fi2) {} + var _r322freg = null; + if (_r322fis && globalThis.__zwCERegistryLookup) { + try { _r322freg = globalThis.__zwCERegistryLookup(String(_r322fis), _r322ftag); } catch (_e322fl) {} + } + if (!_r322freg && _r322ftag && typeof _ce_registry !== 'undefined') _r322freg = _ce_registry[_r322ftag] || null; + if (_r322freg && _r322freg.ctor) { + var _r322fup = false; + try { _r322fup = Object.getPrototypeOf(_r322fe) === _r322freg.ctor.prototype; } catch (_e322fp) {} + if (_r322fup) { _r322ceHit = true; break; } + } + } + } catch (_e322cf) {} + if (_r322ceHit) return _r322qn; + var _r322mw = (typeof _wcRebuildAsHandle === 'function') ? _wcRebuildAsHandle(_r322qn) : _r322qn; + if (_r322mw && _r322mw !== _r322qn && _r322mw.__zwHandle) { + // 物化(CE ctor 可同步执行页面代码)后写前校验桶槽未被重入 + // 改动——重入 splice/清空时按物化前索引写会腐化无关条目。 + if (_r322bq.added[_r322qa] !== _r322qn) continue; + _r322bq.added[_r322qa] = _r322mw; + if (_r322bq.addedSet) { _r322bq.addedSet.delete(_r322qn); _r322bq.addedSet.add(_r322mw); } + var _r322gi = _zwPendingAdded.indexOf(_r322qn); + if (_r322gi >= 0) _zwPendingAdded[_r322gi] = _r322mw; + if (_zwPendingAddedSet) { _zwPendingAddedSet.delete(_r322qn); _zwPendingAddedSet.add(_r322mw); } + _zwPAIdRemove(_r322qn); + _zwPAIdAdd(_r322mw); + _r322mw._zwMatParsed = true; + if (_zwNodeParent) { + _zwNodeParent[_r322mw.__zwHandle] = { parentSel: sel, parentHandle: null, nextSibling: _r322qn._zwSelPendingParent.nextSibling || null }; + } + } + return _r322mw || _r322qn; + } catch (_e322pm) { continue; } + } var _r322ql = (typeof _zwNodeParent !== 'undefined' && _zwNodeParent) ? _zwNodeParent[_r322qn.__zwHandle] : null; if (!_r322ql || _r322ql.parentSel !== sel) continue; var _r322qf = []; @@ -9624,6 +9698,13 @@ // pending-added 并入 = 同 turn firstChild/lastChild/childNodes 立即 // 反映新子;host apply(dom_html 换代)时 _zwChildBaseInvalidateAll // 全量失效换代(生命周期不变)。 + // t8r-4(site-compat bilibili-20261002-r1 续):sel 路径 setter **不做**本地物 + // 化——mutation 队列 addedNodes、CE attach、`_mo_notify` 桶展平与 K3 apply + // 代际清除全按解析代理原样记账(setter 物化会让 host apply 消费 wrapper + // 序列化出空壳、CE 双 ctor、apply 后桶残留双计)。查询面的立即可见性由 + // R322 兜底臂的解析代理物化承担(下方 querySelector host-miss 分支)—— + // spec innerHTML 同步替换子节点、后续查询立即可见。 + // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-innerhtml if (!handle && typeof _zwChildBaseCache !== 'undefined') _zwChildBaseCache.set(sel, []); // R34xx:纯文本 innerHTML → 本地文本节点注册(selection-rects 的 // el.childNodes[0] 文本节点——created handle 元素无 sel,host 不可查)。 diff --git a/crates/engine/src/js_dom_shim/part05.js b/crates/engine/src/js_dom_shim/part05.js index 90ac92ae4..0c85115d0 100644 --- a/crates/engine/src/js_dom_shim/part05.js +++ b/crates/engine/src/js_dom_shim/part05.js @@ -10079,19 +10079,38 @@ _r3kStale.push(_r3knd); _zwPendingAdded.splice(_r3kpa, 1); } + // t8r-4:查询面物化的 wrapper(R322 兜底臂打 `_zwMatParsed`)同批作废—— + // 它带 handle,上方解析补偿条件豁免它;但 apply 后快照已含该子,桶内 + // wrapper + 父反链残留会让 overlay 重复并入(vue_mount_lands 双份 + // `

` 同型)。物化 wrapper 无槽,桶定位走父反链(下方清理 + // 循环 `_r3kMatLink` 臂),反链与标记同批清除。 + else if (_r3knd && _r3knd.__zwHandle && _r3knd._zwMatParsed) { + _r3kStale.push(_r3knd); + _zwPendingAdded.splice(_r3kpa, 1); + } } if (_r3kStale.length) { for (var _r3ks = 0; _r3ks < _r3kStale.length; _r3ks++) { _zwPendingAddedSet && _zwPendingAddedSet.delete(_r3kStale[_r3ks]); _zwPAIdRemove(_r3kStale[_r3ks]); var _r3kSlot = _r3kStale[_r3ks]._zwSelPendingParent; - var _r3kB = _zwPendingByParent.get(_r3kSlot && _r3kSlot.parentSel ? _r3kSlot.parentSel : '_h:' + String(_r3kSlot && _r3kSlot.parentHandle == null ? '' : _r3kSlot && _r3kSlot.parentHandle)); + // t8r-4:物化 wrapper 无槽——桶定位走父反链,并同批清反链与物化标记。 + var _r3kMatLink = (!_r3kSlot && _r3kStale[_r3ks]._zwMatParsed && _r3kStale[_r3ks].__zwHandle + && typeof _zwNodeParent !== 'undefined' && _zwNodeParent) + ? _zwNodeParent[_r3kStale[_r3ks].__zwHandle] : null; + var _r3kLink = _r3kMatLink || _r3kSlot; + var _r3kB = _zwPendingByParent.get(_r3kLink && _r3kLink.parentSel ? _r3kLink.parentSel : '_h:' + String(_r3kLink && _r3kLink.parentHandle == null ? '' : _r3kLink && _r3kLink.parentHandle)); if (_r3kB) { var _r3ki = _r3kB.added.indexOf(_r3kStale[_r3ks]); if (_r3ki >= 0) _r3kB.added.splice(_r3ki, 1); _r3kB.addedSet && _r3kB.addedSet.delete(_r3kStale[_r3ks]); } - delete _r3kStale[_r3ks]._zwSelPendingParent; + if (_r3kMatLink) { + try { delete _zwNodeParent[_r3kStale[_r3ks].__zwHandle]; } catch (_e3kmu) {} + try { delete _r3kStale[_r3ks]._zwMatParsed; } catch (_e3kmu2) {} + } else { + delete _r3kStale[_r3ks]._zwSelPendingParent; + } } } // R3254-E2 切片 13(editing goal,2026-09-08):**removed 补偿同批作废**——