From bb9ce8a117f2706cb7afe5ba6a2453d26ff1882c Mon Sep 17 00:00:00 2001
From: DKChan <524912269@qq.com>
Date: Fri, 6 Nov 2026 03:21:10 +0800
Subject: [PATCH] =?UTF-8?q?=E6=89=B92(QA=20harness=C2=B7B=E8=A6=86?=
=?UTF-8?q?=E7=9B=96=E6=80=BB=E8=A7=88=E9=9D=A2=E6=9D=BF+=E6=9C=AC?=
=?UTF-8?q?=E4=BD=93=E6=9E=9A=E4=B8=BE=E5=99=A8):=20=E4=B9=89=E5=8A=A1?=
=?UTF-8?q?=E5=B1=82=3Dtools/extract=5Fcapability=5Flist.py(README?=
=?UTF-8?q?=E8=83=BD=E5=8A=9B=E6=B8=85=E5=8D=95=E5=9B=9B=E5=88=97=E8=A1=A8?=
=?UTF-8?q?=E6=8C=89=E6=97=85=E7=A8=8B=E6=AE=B5=E8=A7=A3=E6=9E=90,7?=
=?UTF-8?q?=E6=AE=B5103=E8=A1=8C,=E7=94=A8=E4=BE=8B=E6=8C=87=E9=92=88?=
=?UTF-8?q?=E5=89=A5=E5=8F=8D=E5=BC=95=E5=8F=B7);=20=E6=89=A7=E8=A1=8C?=
=?UTF-8?q?=E5=B1=82=3Dtools/coverage=5Freceipts.py=E5=85=AD=E6=BA=90?=
=?UTF-8?q?=E5=9B=9E=E6=89=A7=E6=98=8E=E7=BB=86=E5=8C=96(=E5=86=92?=
=?UTF-8?q?=E7=83=9F/=E5=8D=95=E5=85=83=E9=9B=86=E6=88=90/=E7=B3=BB?=
=?UTF-8?q?=E7=BB=9F/=E6=8E=A2=E9=92=88/=E6=B8=B2=E6=9F=93/=E9=9D=99?=
=?UTF-8?q?=E6=80=81=E5=90=84=E4=B8=80.js,=E5=90=8D=C3=97=E7=BB=93?=
=?UTF-8?q?=E6=9E=9C=C3=97=E8=AE=A1=E6=95=B0=E7=B2=92=E5=BA=A6,=E6=97=A5?=
=?UTF-8?q?=E5=BF=97=E7=BC=BA=E5=A4=B1=3Dnot=5Frun=E4=BA=AE=E7=81=B0?=
=?UTF-8?q?=E4=B8=8D=E5=86=92=E5=85=85=E7=BB=BF)+run=5Fall=5Fgates.sh?=
=?UTF-8?q?=E6=9C=AB=E5=B0=BE=E6=8C=82=E7=82=B9(=E8=A7=82=E6=B5=8B?=
=?UTF-8?q?=E4=BB=B6=E9=9D=9E=E5=88=A4=E5=AE=9A=E4=BB=B6,=E8=A7=A3?=
=?UTF-8?q?=E6=9E=90=E5=A4=B1=E8=B4=A5=E6=89=93=E7=BA=A2=E5=AD=97=E4=B8=8D?=
=?UTF-8?q?=E7=BF=BB=E9=97=B8=E5=88=A4)+probe=5Fmanifest.js(=E9=9D=A2?=
=?UTF-8?q?=E6=9D=BFfile://=E6=97=A0=E6=B3=95=E5=88=97=E7=9B=AE=E5=BD=95,?=
=?UTF-8?q?=E6=8C=89=E7=8E=B0=E5=AD=98=E7=99=BB=E8=AE=B0=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E8=90=BD=E6=B8=85=E5=8D=95);=20=E6=9C=BA=E5=99=A8=E4=B9=89?=
=?UTF-8?q?=E5=8A=A1=E5=8F=8C=E6=BA=90=E4=B9=8B=E6=9C=AC=E4=BD=93=E6=BA=90?=
=?UTF-8?q?=3Dtools/coverage=5Fenum.py(=E4=B8=A4=E6=89=AB=E6=8F=8F?=
=?UTF-8?q?=E5=99=A8+=E6=AF=94=E5=AF=B9:.tres=E8=A1=8C=E9=9B=86/schema?=
=?UTF-8?q?=E8=AF=8D=E8=A1=A8=E5=AD=97=E6=AE=B5/tscn=E6=8C=89=E9=92=AE/gui?=
=?UTF-8?q?=5Finput=E8=87=AA=E7=BB=98=E7=B1=BB/=E5=B1=8F=E6=A8=A1=E6=80=81?=
=?UTF-8?q?=E6=B8=85=E5=8D=95=C3=97extract=5Fchecks=E6=96=AD=E8=A8=80?=
=?UTF-8?q?=E6=96=87=E6=96=99,865=E5=AE=9E=E4=BD=93/=E7=BC=BA=E5=8F=A3212)?=
=?UTF-8?q?;=20=E5=91=88=E7=8E=B0=E5=B1=82=3Dtools/coverage=5Freport.html(?=
=?UTF-8?q?=E5=9B=9B=E8=8A=82:=E5=85=AD=E5=B1=82=E9=97=B8=E5=86=B5/?=
=?UTF-8?q?=E8=83=BD=E5=8A=9B=E8=A1=8C=C3=97=E5=85=AD=E5=B1=82=E7=81=AF?=
=?UTF-8?q?=E6=8C=89=E6=97=85=E7=A8=8B=E6=AE=B5/=E6=8E=A7=E4=BB=B6?=
=?UTF-8?q?=E4=B8=8B=E9=92=BB=E4=BA=A4=E4=BA=92=E6=BA=90+=E6=B8=B2?=
=?UTF-8?q?=E6=9F=93golden=E5=B1=95=E7=A4=BA=E6=BA=90/=E6=9C=AC=E4=BD=93?=
=?UTF-8?q?=E5=AF=B9=E8=B4=A6=E7=BC=BA=E5=8F=A3=C3=97=E6=8E=A2=E9=92=88?=
=?UTF-8?q?=E5=91=BD=E4=B8=AD=E9=99=8D=E7=BA=A7=E6=8E=A2=E9=92=88=E6=89=BF?=
=?UTF-8?q?=E8=BD=BD;=E7=8A=B6=E6=80=81=E7=81=AF=E5=9B=9B=E6=80=81+?=
=?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=97=B6=E9=97=B4=E6=88=B3=E9=99=88=E6=97=A7?=
=?UTF-8?q?=E5=8F=AF=E8=A7=81+=E5=AE=8C=E5=A4=87=E6=80=A7=E8=BE=B9?=
=?UTF-8?q?=E7=95=8C=E9=A1=B5=E7=9C=89;JSONP=E7=9B=B4=E8=BD=BDfile://?=
=?UTF-8?q?=E5=8D=B3=E5=BC=80);=20=E8=B1=81=E5=85=8D=3Dtools/coverage=5Fex?=
=?UTF-8?q?emptions.js=E4=BA=BA=E5=B7=A5=E7=BB=B4=E6=8A=A4=E6=AF=8D?=
=?UTF-8?q?=E7=89=88;=20=E7=99=BB=E8=AE=B0=E4=BB=B6=E6=89=A9seen=E9=9D=A2(?=
=?UTF-8?q?=E5=9C=BA=E6=99=AF=E6=A0=91=E5=85=A8=E9=87=8FBaseButton+db?=
=?UTF-8?q?=E5=B8=83=E5=B1=80=E8=A1=A8hotspot=5Fkey=E5=85=AC=E5=85=B1?=
=?UTF-8?q?=E9=9D=A2=E6=9E=9A=E4=B8=BE,seen-hit=3D=E5=AD=98=E5=9C=A8?=
=?UTF-8?q?=E4=BD=86=E9=9B=B6=E7=9C=9F=E8=BE=93=E5=85=A5=E8=A6=86=E7=9B=96?=
=?UTF-8?q?=E7=BC=BA=E5=8F=A3=E6=95=B0=E6=8D=AE=E6=BA=90)=E3=80=82?=
=?UTF-8?q?=E8=AF=BB=E6=95=B0:=20=E4=B8=A4=E6=8E=A2=E9=92=88=E7=AA=84?=
=?UTF-8?q?=E8=B7=91=E7=BB=BF(screen=5Fflow=2019=E5=91=BD=E4=B8=AD/116?=
=?UTF-8?q?=E5=AD=98=E5=9C=A8,ui=5Fclick=2027=E5=91=BD=E4=B8=AD/91?=
=?UTF-8?q?=E5=AD=98=E5=9C=A8=E2=80=94=E2=80=94=E5=81=9C=E6=89=8B=E9=92=AE?=
=?UTF-8?q?/=E6=A0=91=E8=B4=AD=E4=B9=B0=E9=87=8D=E5=BB=BA=E4=BB=A3?=
=?UTF-8?q?=E7=AD=89=E7=9C=9F=E7=BC=BA=E5=8F=A3=E5=9C=A8=E5=86=8C,?=
=?UTF-8?q?=E5=BC=83=E5=9B=BE=E5=88=B7=E6=96=B0=E7=A1=AE=E8=AE=A4=E9=93=BE?=
=?UTF-8?q?=E8=B5=B0=E8=A7=86=E5=9B=BE=E6=96=B9=E6=B3=95=E5=B1=9E=E8=A1=94?=
=?UTF-8?q?=E6=8E=A5=E6=9D=A1=E7=9B=AE=E4=BD=99=E9=A1=B9);=20=E5=85=AD?=
=?UTF-8?q?=E6=BA=90=E6=98=8E=E7=BB=86=E5=8C=96=E5=AF=B9=E7=9C=9F=E5=AE=9E?=
=?UTF-8?q?=E9=97=B8=E6=97=A5=E5=BF=97=E6=8A=BD=E6=A0=B8(unit82=E5=A5=97?=
=?UTF-8?q?=E4=BB=B6/=E7=B3=BB=E7=BB=9F69=E6=A3=80=E6=9F=A5/=E6=8E=A2?=
=?UTF-8?q?=E9=92=8810=E6=AE=B5/=E9=9D=99=E6=80=8113=E6=9D=A1/golden?=
=?UTF-8?q?=E9=80=90=E5=B1=8FL1-L3);=20=E9=9D=A2=E6=9D=BF=E6=B5=8F?=
=?UTF-8?q?=E8=A7=88=E5=99=A8=E7=9C=9F=E5=AE=9E=E5=85=A5=E5=8F=A3=E5=9B=9B?=
=?UTF-8?q?=E8=8A=82=E6=B8=B2=E6=9F=93=E9=AA=8C=E8=BF=87;=20=E5=85=A8?=
=?UTF-8?q?=E9=87=8F=E6=A1=A3=E9=97=B8=E3=80=90=E9=AA=8C=E6=94=B6=E9=80=9A?=
=?UTF-8?q?=E8=BF=87=E3=80=91=E6=97=A0=E6=96=B0=E5=A2=9E=E7=BA=A2(exit=3D0?=
=?UTF-8?q?,=E5=9B=9E=E6=89=A7commit=2007d4977f,=E5=85=AD=E6=BA=90?=
=?UTF-8?q?=E6=98=8E=E7=BB=86=E5=8C=96=E5=9C=A8=E9=97=B8=E5=86=85=E5=AE=9E?=
=?UTF-8?q?=E8=B7=91=3D=E6=8C=82=E7=82=B9=E7=9C=9F=E8=B7=AF=E5=BE=84?=
=?UTF-8?q?=E9=AA=8C=E8=AF=81)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
game/probe/probe_coverage_recorder.gd | 35 ++++
tools/coverage_enum.py | 158 ++++++++++++++++++
tools/coverage_exemptions.js | 11 ++
tools/coverage_receipts.py | 184 +++++++++++++++++++++
tools/coverage_report.html | 226 ++++++++++++++++++++++++++
tools/extract_capability_list.py | 129 +++++++++++++++
tools/run_all_gates.sh | 2 +
7 files changed, 745 insertions(+)
create mode 100644 tools/coverage_enum.py
create mode 100644 tools/coverage_exemptions.js
create mode 100644 tools/coverage_receipts.py
create mode 100644 tools/coverage_report.html
create mode 100644 tools/extract_capability_list.py
diff --git a/game/probe/probe_coverage_recorder.gd b/game/probe/probe_coverage_recorder.gd
index feff5ca1..c7f2f27f 100644
--- a/game/probe/probe_coverage_recorder.gd
+++ b/game/probe/probe_coverage_recorder.gd
@@ -164,6 +164,38 @@ func _bump(key: String) -> void:
_hits[key] = int(_hits.get(key, 0)) + 1
+# ---- 场景树全量交互面枚举(控件缺口数据源:seen−hit=「存在但零真输入覆盖」)----
+# 成员面与登记同源:场景树全部 BaseButton(main 建树常驻——未开过的屏的钮也算存在;
+# 已接线钮复用接线键防序位错位,未接线者落盘期才补键——落盘是终态动作,序位计数此后不再消费)
+# +营地物件(经 db 布局表 hotspot_key 公共数据面枚举;物件命中见 _on_camp_object 的 #物件id 后缀)。
+func enumerate_seen() -> Array[String]:
+ var keys: Array[String] = []
+ _seen_into(_main, keys)
+ var db = _main.get("db")
+ if db != null and db.get("presentation") != null:
+ var layout = db.presentation.camp_scene_layout
+ if layout != null:
+ for spec in layout.layers:
+ var hk: StringName = spec.hotspot_key
+ var ck := "camp_object#" + String(hk)
+ if hk != &"" and not keys.has(ck):
+ keys.append(ck)
+ return keys
+
+
+func _seen_into(node: Node, keys: Array[String]) -> void:
+ if node is BaseButton:
+ var id := node.get_instance_id()
+ var key := String(_node_keys.get(id, ""))
+ if key == "":
+ key = _assign_key(node)
+ _node_keys[id] = key
+ if not keys.has(key):
+ keys.append(key)
+ for child in node.get_children():
+ _seen_into(child, keys)
+
+
# ---- 落盘(JSONP 式 .js——file:// 页面
+
+
+
+
+
+
+
+
+
+
+
+