From 3461e83bec685eeda0c020fe99a38227ad668f35 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Sat, 24 Oct 2026 19:35:01 +0800 Subject: [PATCH] =?UTF-8?q?test(=E8=BF=AD=E4=BB=A335=E5=8D=A1=E2=91=A1T3?= =?UTF-8?q?=20=E5=B0=BE=E7=BC=80=E5=AF=B9=E9=BD=90):=20=E6=9C=AC=E6=89=B9?= =?UTF-8?q?=E6=96=B0=E8=90=BD=E5=9C=B0=E6=96=AD=E8=A8=80=E8=A1=A5=E5=8F=AF?= =?UTF-8?q?=20grep=20=E5=B0=BE=E7=BC=80=EF=BC=88=E3=80=94v2=E3=80=95?= =?UTF-8?q?=E5=85=A5=E5=8F=A3=E5=80=99=E9=80=89=E6=95=B0=EF=BC=9D=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E6=A1=A3=20entry=5Fcount=20=E4=B8=8E=E7=AC=AC?= =?UTF-8?q?=E4=BA=8C=E5=85=A5=E5=8F=A3=E8=BF=9B=E5=85=A5=EF=BC=8F=E3=80=94?= =?UTF-8?q?v5=E3=80=95=E5=95=86=E5=BA=97=E4=B8=89=E6=80=A7=E8=B4=A8?= =?UTF-8?q?=E4=B8=8E=E6=89=AB=E6=8F=8F=E9=9D=A2=E9=9D=9E=E7=A9=BA=EF=BC=8F?= =?UTF-8?q?=E3=80=94v7=E3=80=95=E5=90=8C=E6=A1=A3=E5=90=8C=E7=A7=8D?= =?UTF-8?q?=E5=AD=90=E4=B8=A4=E6=AC=A1=E4=BA=A7=E5=9B=BE=E5=90=8C=E5=9B=BE?= =?UTF-8?q?=C2=B7=E8=B5=B7=E5=85=B3=E5=9B=BE=EF=BC=9D=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=99=A8=E7=9B=B4=E5=8F=96=C2=B7=E7=A7=8D=E5=AD=90=2042=20?= =?UTF-8?q?=E4=B8=A4=E5=BC=80=E5=B1=80=E5=90=8C=E5=9B=BE=C2=B7=E6=96=AD?= =?UTF-8?q?=E7=82=B9=E9=87=8D=E7=94=9F=E6=88=90=E5=90=8C=E5=9B=BE=C2=B7?= =?UTF-8?q?=E5=90=8C=E7=A7=8D=E5=AD=90=E9=87=8D=E5=BC=80=E5=B1=80=E5=90=8C?= =?UTF-8?q?=E5=9B=BE=EF=BC=8F=E3=80=94v8=E3=80=95=E5=BF=AB=E7=85=A7?= =?UTF-8?q?=E4=BB=A3=E5=B7=AE=E6=A0=87=E8=AE=B0=C2=B7=E5=8F=A5=E6=9F=84?= =?UTF-8?q?=E5=BE=80=E8=BF=94=C2=B7=E6=97=A7=E6=96=AD=E7=82=B9=E6=8B=92?= =?UTF-8?q?=E7=BB=9D=EF=BC=8F=E3=80=94v9=E3=80=95=E5=BF=AB=E7=85=A7?= =?UTF-8?q?=E6=97=A0=E5=B7=B2=E6=8A=BD=E6=A8=A1=E6=9D=BF=E9=94=AE=C2=B7?= =?UTF-8?q?=E8=A1=A8=E6=97=A0=20templates=20=E9=94=AE=EF=BC=8F=E3=80=94v4?= =?UTF-8?q?=E3=80=95=E4=B8=89=E5=85=B3=E5=9B=BE=E5=90=84=E5=90=AB=E5=A5=96?= =?UTF-8?q?=E5=8A=B1=E8=8A=82=E7=82=B9=EF=BC=89=EF=BC=8B=E5=95=86=E5=BA=97?= =?UTF-8?q?=E5=AE=BF=E4=B8=BB=E9=87=8D=E5=A4=8D=E6=AE=B5=E5=A4=B4=E6=B8=85?= =?UTF-8?q?=E7=90=86=E2=80=94=E2=80=94=E7=8B=AC=E7=AB=8B=E5=AE=A1=E8=AE=A1?= =?UTF-8?q?=E7=AC=AC=201=20=E4=BB=B6=EF=BC=88=E5=AF=B9=E7=85=A7=E8=A1=A8?= =?UTF-8?q?=E9=80=90=E8=A1=8C=E6=A0=B8=E5=B0=BE=E7=BC=80=E5=8F=AF=20grep?= =?UTF-8?q?=EF=BC=89=E7=9A=84=E6=89=A7=E8=A1=8C=E9=9D=A2=EF=BC=9B=E5=9B=9B?= =?UTF-8?q?=E5=AE=BF=E4=B8=BB=E5=A4=8D=E8=B7=91=2021/176/138=20=E5=85=A8?= =?UTF-8?q?=E7=BB=BF=E9=9B=B6=E9=94=99=E8=AF=AF=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../integration/node_map_templates_test.gd | 18 +++++++++--------- game/tests/unit/core/adventure_feats_test.gd | 2 +- game/tests/unit/core/breakpoint_resume_test.gd | 12 ++++++------ .../tests/unit/core/level_shop_economy_test.gd | 11 ++++------- reports/iter35-卡②-实现报告-2026-10-24.md | 11 ++++++++++- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/game/tests/integration/node_map_templates_test.gd b/game/tests/integration/node_map_templates_test.gd index 45d8a2fc..4a36e01d 100644 --- a/game/tests/integration/node_map_templates_test.gd +++ b/game/tests/integration/node_map_templates_test.gd @@ -40,7 +40,7 @@ func _smoke_generated_map_determinism() -> void: var g_b: Dictionary = gen.generate(params2, 910002) var g_c: Dictionary = gen.generate(params2, 910003) var nodes_a: Array = g_a.get("nodes", []) - Kit.check("同参数档同种子两次产图逐位同图(D2 执行边界)", + Kit.check("同参数档同种子两次产图逐位同图(D2 执行边界)〔v7〕", nodes_a == (g_b.get("nodes", []) as Array)) Kit.check("同参数档换种子即变图(图确为种子函数,非恒定输出)", nodes_a != (g_c.get("nodes", []) as Array)) @@ -50,7 +50,7 @@ func _smoke_generated_map_determinism() -> void: var runner1 = load("res://core/level_runner.gd").new(_db, _fresh_rng(910004)) Kit.check("单关起关受理(种子 910004——生成图直供,无兜底图)", runner1.start_level(2, 910004)) - Kit.check("起关生效图 = 生成器同档同种子直取逐位一致(消费侧无第二图源)", + Kit.check("起关生效图 = 生成器同档同种子直取逐位一致(消费侧无第二图源)〔v7〕", runner1.level_row.get("nodes", []) == (gen.generate(params2, 910004) as Dictionary).get("nodes", [])) # ③ 产图零统一流消费(纯派生流不占计数器号位——断点在任意号位重生成同图的机制承载) var rng_c = _fresh_rng(910005) @@ -61,11 +61,11 @@ func _smoke_generated_map_determinism() -> void: Kit.check("起关产图零计数器消费(同图不依赖取数号位)", rng_c.counter() == counter_before) var params3: Dictionary = _db.level_gen_params_row(3) var entry_count: int = int(params3.get("entry_count", -1)) - Kit.check("入口停点候选数=参数档入口个数(L3 档 %d——多入口首跳即选路,禁写死单入口)" % entry_count, + Kit.check("入口停点候选数=参数档入口个数(L3 档 %d——多入口首跳即选路,禁写死单入口)〔v2〕" % entry_count, entry_count >= 1 and (runner2.next_candidates() as Array).size() == entry_count) if entry_count >= 2: var eids: Array = runner2.next_candidate_ids() - Kit.check("第二入口经句柄显式进入(句柄 %d)" % int(eids[1]), + Kit.check("第二入口经句柄显式进入(句柄 %d)〔v2〕" % int(eids[1]), runner2.pick_next_node(int(eids[1])) and int(runner2.current_node_id()) == int(eids[1])) # ④ 开局种子承载:新档(首局)种子 42 两次开局逐位同图,且与生成器直取一致 DirAccess.remove_absolute(_bp_path) # 测试隔离——上轮落盘残留先删,断点面从零档起 @@ -77,7 +77,7 @@ func _smoke_generated_map_determinism() -> void: var adr_y = AdventureRunnerScript.new(_db, _fresh_rng(42)) Kit.check("同种子第二次开局受理", adr_y.start_adventure(42, {"hero_override": {}, "treasure_unlocked": {}})) - Kit.check("种子 42 两次开局图逐位同图(教学局恒同图——首局固定种子的确定性承载)", + Kit.check("种子 42 两次开局图逐位同图(教学局恒同图——首局固定种子的确定性承载)〔v7〕", adr_x.runner().nodes() == adr_y.runner().nodes()) Kit.check("开局图 = L1 参数档在种子 42 下的生成图(开局无隐式取数分叉)", adr_x.runner().nodes() == (gen.generate(_db.level_gen_params_row(1), 42) as Dictionary).get("nodes", [])) @@ -85,20 +85,20 @@ func _smoke_generated_map_determinism() -> void: Kit.check("停点断点落盘在档", sv_w.has_breakpoint()) var bp: Dictionary = sv_w.breakpoint_snapshot() var adr_z = AdventureRunnerScript.new(_db, load("res://core/rng_service.gd").new()) - Kit.check("断点续玩受理(代差标记键在档)", adr_z.resume_adventure(bp, + Kit.check("断点续玩受理(代差标记键在档)〔v8〕", adr_z.resume_adventure(bp, {"hero_override": {}, "treasure_unlocked": {}})) - Kit.check("续玩重生成图与中断前逐位同图", adr_z.runner().nodes() == adr_x.runner().nodes()) + Kit.check("续玩重生成图与中断前逐位同图〔v7〕", adr_z.runner().nodes() == adr_x.runner().nodes()) var adr_old = AdventureRunnerScript.new(_db, load("res://core/rng_service.gd").new()) var bp_old: Dictionary = bp.duplicate(true) bp_old.erase("graph_gen_v2") # 换代前旧断点形态(模板池时代无代差标记键) - Kit.check("缺生成图代差标记键的旧断点被显式拒绝(禁按新语义静默回放)", + Kit.check("缺生成图代差标记键的旧断点被显式拒绝(禁按新语义静默回放)〔v8〕", adr_old.resume_adventure(bp_old, {}) == false) # ⑥ 关卡表不再携带图数据(图源换代后 level 行只剩行级字段) var tpl_free := true for li in range(1, _db.level_count() + 1): if (_db.level_row(li) as Dictionary).has("templates"): tpl_free = false - Kit.check("level 表三行均无 templates 键(模板数据已清出)", + Kit.check("level 表三行均无 templates 键(模板数据已清出)〔v9〕", tpl_free and _db.level_count() == 3) # ⑦ 收束置位:新档 false → settle 置 true 恰一次(幂等) var sv = SaveManagerScript.new(_bp_path + ".flag.json") diff --git a/game/tests/unit/core/adventure_feats_test.gd b/game/tests/unit/core/adventure_feats_test.gd index d6ec9e6e..379390e1 100644 --- a/game/tests/unit/core/adventure_feats_test.gd +++ b/game/tests/unit/core/adventure_feats_test.gd @@ -162,7 +162,7 @@ func _smoke_adventure() -> void: rc += 1 if rc >= 1: reward_levels += 1 - Kit.check("三关生成图各含 ≥1 奖励节点(节点三选一候选位在图)", reward_levels == 3) + Kit.check("三关生成图各含 ≥1 奖励节点(节点三选一候选位在图)〔v4〕", reward_levels == 3) # 行进侧两断言走真实选路入口(满配赢下途中战→岔口按偏好显式点选):奖励支路经停即呈三选一、 # 进战载荷带节点深度——确定性评分策略恒选推进支路,奖励位不在扫描路由上,故显式点选验证接线 var rw: Dictionary = _drive_to_pref(autoplay, "reward") diff --git a/game/tests/unit/core/breakpoint_resume_test.gd b/game/tests/unit/core/breakpoint_resume_test.gd index bae37e7f..e6eba55c 100644 --- a/game/tests/unit/core/breakpoint_resume_test.gd +++ b/game/tests/unit/core/breakpoint_resume_test.gd @@ -157,9 +157,9 @@ func _init() -> void: var graph_j: Array = runner_j.nodes() var bp_j: Dictionary = sm_j.breakpoint_snapshot() Kit.check_quiet(not bp_j.has("template_pick"), - "P7 断点快照无已抽模板键(模板链路退役——件核面在档)") + "P7 断点快照无已抽模板键(模板链路退役——件核面在档)〔v9〕") Kit.check_quiet(int(bp_j.get("graph_gen_v2", 0)) == 1, - "P7 断点含生成图代差标记键(换代承载)") + "P7 断点含生成图代差标记键(换代承载)〔v8〕") var entry_id: int = int(runner_j.next_candidate_ids()[0]) var mid_id: int = _first_out_id(graph_j, entry_id) var bp_mid: Dictionary = bp_j.duplicate(true) @@ -169,17 +169,17 @@ func _init() -> void: Kit.check_quiet(adr_m.resume_adventure(bp_mid, params), "P7 中途停点断点续玩受理(句柄落档形态)") var runner_m = adr_m.runner() Kit.check_quiet(int(runner_m.current_node_id()) == mid_id, - "P7 停点句柄回读一致(图内 id 单空间寻址)") + "P7 停点句柄回读一致(图内 id 单空间寻址)〔v8〕") Kit.check_quiet(runner_m.visited_ids() == [entry_id], "P7 已到节点序按句柄往返一致") - Kit.check_quiet(runner_m.nodes() == graph_j, "P7 续玩重生成图与中断前逐位同图(断点不存图快照)") + Kit.check_quiet(runner_m.nodes() == graph_j, "P7 续玩重生成图与中断前逐位同图(断点不存图快照)〔v7〕") var adr_l = AdventureRunnerScript.new(db, load("res://core/rng_service.gd").new()) var bp_legacy: Dictionary = bp_mid.duplicate(true) bp_legacy.erase("graph_gen_v2") Kit.check_quiet(adr_l.resume_adventure(bp_legacy, params) == false, - "P7 缺生成图代差标记键的旧断点显式拒绝(禁按新句柄空间静默回放)") + "P7 缺生成图代差标记键的旧断点显式拒绝(禁按新句柄空间静默回放)〔v8〕") var adr_n = AdventureRunnerScript.new(db, load("res://core/rng_service.gd").new()) Kit.check_quiet(adr_n.start_adventure(910042, params) and adr_n.runner().nodes() == graph_j, - "P7 同种子重开局同图(开局入口复现承载)") + "P7 同种子重开局同图(开局入口复现承载)〔v7〕") _clear_disk() quit(Kit.finish("breakpoint_resume_test", "PASS — 断点往返/续玩确定性/幂等/退出清断点/装配存档回归/生成图换代 全绿")) diff --git a/game/tests/unit/core/level_shop_economy_test.gd b/game/tests/unit/core/level_shop_economy_test.gd index c2dce65a..ecdba9bf 100644 --- a/game/tests/unit/core/level_shop_economy_test.gd +++ b/game/tests/unit/core/level_shop_economy_test.gd @@ -1080,9 +1080,6 @@ func _shop_products_by_id(prods: Array) -> Dictionary: return out -# ---- ④ 商店编排性质(每终点前一位恰一店 · 店数=终点数 · 全路径恰穿一店)---- - - # ---- ④ 商店编排性质(生成图扫描面——三条性质 + 终点跨表解析)---- func _smoke_shop_graph() -> void: @@ -1126,11 +1123,11 @@ func _smoke_shop_graph() -> void: if _path_shop_count(nodes, p) != 1: path_bad += 1 print("商店编排扫描读数:图 %d 张·终点 %d 个·入口→终点路径 %d 条" % [graph_total, term_total, path_total]) - Kit.check("编排断言扫描面非空(三关参数档 × 种子 %d–%d=图 %d 张·终点 %d·路径 %d)" % [SWEEP_SEED_FROM, SWEEP_SEED_TO - 1, graph_total, term_total, path_total], + Kit.check("编排断言扫描面非空(三关参数档 × 种子 %d–%d=图 %d 张·终点 %d·路径 %d)〔v5〕" % [SWEEP_SEED_FROM, SWEEP_SEED_TO - 1, graph_total, term_total, path_total], graph_total == 3 * (SWEEP_SEED_TO - SWEEP_SEED_FROM) and term_total >= 3 and path_total >= 3) - Kit.check("性质① 每个终点的直接前驱恰一家商店(入边一条且源型别=shop·违例 %d/%d 终点)" % [pred_bad, term_total], pred_bad == 0) - Kit.check("性质② 每图商店节点数 = 终点数(违例 %d/%d 图)" % [count_bad, graph_total], count_bad == 0) - Kit.check("性质③ 每条入口→终点路径恰穿一家商店(违例 %d/%d 条路径)" % [path_bad, path_total], path_bad == 0) + Kit.check("性质① 每个终点的直接前驱恰一家商店(入边一条且源型别=shop·违例 %d/%d 终点)〔v5〕" % [pred_bad, term_total], pred_bad == 0) + Kit.check("性质② 每图商店节点数 = 终点数(违例 %d/%d 图)〔v5〕" % [count_bad, graph_total], count_bad == 0) + Kit.check("性质③ 每条入口→终点路径恰穿一家商店(违例 %d/%d 条路径)〔v5〕" % [path_bad, path_total], path_bad == 0) # 现行起关图(种子 %d)逐关读数——L1 单终点、L2/L3 多终点(每终点前一位恰一店的当关投影) for L in [1, 2, 3]: var cur_nodes: Array = _level_active_nodes(L) diff --git a/reports/iter35-卡②-实现报告-2026-10-24.md b/reports/iter35-卡②-实现报告-2026-10-24.md index bf6d9fa6..26145873 100644 --- a/reports/iter35-卡②-实现报告-2026-10-24.md +++ b/reports/iter35-卡②-实现报告-2026-10-24.md @@ -140,7 +140,16 @@ 卡片 §8 变异清单九条的落位:V1 两条(T1 已录)、V11 两条(覆盖批已录)、V2/V5×2/V6/V7/V8/V9 共六条(本表 M1–M7,V5 拆两条)。 -## 三、遗留读数义务 +## 三·一 实机目检总清单(真人判断项,登记即完成义务,不作为合回前置) + +| # | 观测项 | 真实入口 | 期望看到什么 | 本批机检已覆盖的部分 | +|---|---|---|---|---| +| 目检① | 三关选路观感不回归:多入口首跳、大岔口取舍、多终点走向可见 | 主菜单开局 → 关卡地图(`res://probe/ui_click_probe.tscn` 亦可走同路径) | 开局即出现两个可选入口(L2/L3);岔口处候选互异且分属不同支路;走 A 支只遇 A 支终点 Boss | 候选数=参数档 `entry_count`、第二入口句柄可进入、终点数=`exit_count`、岔口 ≥1、每终点前恰一店(`node_map_templates`/`level_shop_economy` 扫描面) | +| 目检② | 首局教学图体验(种子 42 固定图) | 新档开局(`is_first_adventure_done==false` → 恒种子 42) | 同一张图、节奏可教学:入口战→岔口→商店→Boss 的可读顺序,含至少一个奖励位与一个恢复位 | 种子 42 两开局逐位同图、开局图=参数档直取、三关图各含奖励/恢复节点、恢复公式两分支读数 | + +登记口径:以上两项由用户自行安排试玩;本批不以任何目检为停工或合回理由(硬性红线「真人检测只登记不阻塞」)。 + +## 三·二 其余遗留读数义务