From 6cb1cf5efc0f65019711b4e13c690739fbd70074 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 3 Nov 2026 07:00:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A1=E8=AE=A1=E6=95=B4=E6=94=B9(=E8=BF=AD?= =?UTF-8?q?=E4=BB=A350=C2=B7=E7=BC=BA=E6=BC=8F=E4=B8=89=E6=9D=A1=E8=A1=A5?= =?UTF-8?q?=E9=BD=90):=20V14=E8=90=BD=E5=9C=B0minesweeper=5Frules=5Ftest(?= =?UTF-8?q?=5Ftest=5Fpreview=5Freveal=5Freadonly=E4=BA=94=E6=96=AD?= =?UTF-8?q?=E8=A8=80:=E5=BD=A2=E6=80=81A/B=E9=9B=B6=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=86=99=E5=85=A5+=E5=AE=9E=E6=8C=96=E5=B7=AE=E9=9B=86F2?= =?UTF-8?q?=E5=90=8C=E5=8F=A3=E5=BE=84=E9=80=90=E4=BD=8D+preview=E5=89=8D?= =?UTF-8?q?=E5=90=8Ecell=5Frevealed=E9=9B=B6=E5=A2=9E=E9=87=8F=E2=80=94?= =?UTF-8?q?=E6=A0=B9=E5=9B=A0=3Dt8b=20patch=E8=84=9A=E6=9C=AC=E6=BC=8F?= =?UTF-8?q?=E5=86=99=E8=90=BD=E7=9B=98=E8=B0=83=E7=94=A8=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E9=9B=B6=E8=A7=A6=E7=A2=B0,12=E2=86=9217=20checks=E7=BB=BF)+V2?= =?UTF-8?q?=E5=85=B7=E5=90=8D=E6=89=BF=E6=8E=A5=E4=BB=B6=E8=90=BD=E5=9C=B0?= =?UTF-8?q?level=5Fshop=5Feconomy=5Ftest(=5Ftest=5Fspend=5Fdiscount=5Ffrom?= =?UTF-8?q?=5Frule=5Fkey:shop.tres=E9=9B=B6=E8=AF=8A=E6=96=AD+=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E4=B8=8D=E5=9C=A8=E4=BD=8D+=E6=8A=98=E5=90=8E?= =?UTF-8?q?=E4=BB=B7discount=5Fpct=E6=8E=A8=E5=AF=BC+=E6=9C=AA=E6=BF=80?= =?UTF-8?q?=E6=B4=BB=E5=8E=9F=E4=BB=B7=E2=80=94192=E2=86=92195=20checks?= =?UTF-8?q?=E7=BB=BF)+=E5=AE=9E=E7=8E=B0=E6=8A=A5=E5=91=8A=E7=AC=AC?= =?UTF-8?q?=E4=B9=9D=E8=8A=82=E8=AE=A2=E6=AD=A3=E4=B8=8E=E7=AC=AC=E5=8D=81?= =?UTF-8?q?=E8=8A=82=E5=AE=A1=E8=AE=A1=E6=95=B4=E6=94=B9=E8=AE=B0=E5=BD=95?= =?UTF-8?q?+=E5=86=B3=E5=AE=9A=E8=AE=B0=E5=BD=95#10(forge=5Ftable=E9=97=AD?= =?UTF-8?q?=E9=9B=86=E9=92=89=E6=95=B034=E2=86=9232=E8=A1=A5=E8=B4=A6?= =?UTF-8?q?=E2=80=94R3=E6=91=98=E5=90=8D=E5=BF=85=E7=84=B6=E8=BF=9E?= =?UTF-8?q?=E5=B8=A6=E5=BC=BA=E5=BA=A6=E4=B8=8D=E5=87=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unit/core/level_shop_economy_test.gd | 19 +++++++++ .../tests/unit/core/minesweeper_rules_test.gd | 42 +++++++++++++++++++ reports/iter50-实现报告-2026-11-03.md | 13 +++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/game/tests/unit/core/level_shop_economy_test.gd b/game/tests/unit/core/level_shop_economy_test.gd index c3b91d75..2fcac170 100644 --- a/game/tests/unit/core/level_shop_economy_test.gd +++ b/game/tests/unit/core/level_shop_economy_test.gd @@ -252,6 +252,7 @@ func _init() -> void: _smoke_multi_terminal_settlement() _smoke_shop_pool() _test_shelf_size_from_table() + _test_spend_discount_from_rule_key() _test_shop_node_entered_payload() _smoke_generated_coverage() quit(Kit.finish("level_shop_economy_test")) @@ -1575,3 +1576,21 @@ func _test_shelf_size_from_table() -> void: break st.shelf_size = saved Kit.check("夹具 shelf_size=5 → 货架五件可观测(实测 %d;真表值 3 回归=既有「进店抽 3」断言承载)〔架构整改 V9〕" % got5, got5 == 5) + + +# ---- 散折价收回规则键(架构整改 R2——shop.spend_discount 表字段退役,折价读 economy_spend.discount_pct)---- + +func _test_spend_discount_from_rule_key() -> void: + # 字段真删:shop.tres 加载零诊断 + spend_discount 属性不在位 + Kit.check("shop.tres 加载零诊断(spend_discount 字段真删——schema 与表行同卸)〔架构整改 V2〕", + _db.diagnostics_count("error") == 0 and _db.run.shop.get("spend_discount") == null) + # 80% 折价值逐位同(真实入口=LevelRunner 装配链 shop_session.current_price,economy_spend 注入) + var bonus: int = int(_db.run.shop.price_level_bonus_at(0)) + var spend_dict: Dictionary = {"economy_spend": {"discount_pct": 80}} + var lr_on = load("res://core/level_runner.gd").new(_db, _fresh_rng(777005), {"tree_rules": spend_dict}) + var lr_off = load("res://core/level_runner.gd").new(_db, _fresh_rng(777006), {"tree_rules": {}}) + var p_on: int = int(lr_on.shop.current_price({"base_price": 100, "price_increment": 0})) + var p_off: int = int(lr_off.shop.current_price({"base_price": 100, "price_increment": 0})) + var expect_on: int = maxi(1, int(floor(float(100 + bonus) * float(spend_dict["economy_spend"]["discount_pct"]) / 100.0))) + Kit.check("散激活:折后价 = (基价+关卡加成)×discount_pct/100 floor(%d vs 期望 %d)〔架构整改 V2〕" % [p_on, expect_on], p_on == expect_on) + Kit.check("散未激活:原价(无 economy_spend 键——%d)〔架构整改 V2〕" % p_off, p_off == 100 + bonus) diff --git a/game/tests/unit/core/minesweeper_rules_test.gd b/game/tests/unit/core/minesweeper_rules_test.gd index 3552ff8d..0adad56d 100644 --- a/game/tests/unit/core/minesweeper_rules_test.gd +++ b/game/tests/unit/core/minesweeper_rules_test.gd @@ -40,6 +40,7 @@ func _init() -> void: _test_reveal_advances() _test_seal_place() _test_reject_out_of_catalog() + _test_preview_reveal_readonly() quit(Kit.finish("minesweeper_rules_test")) @@ -110,3 +111,44 @@ func _test_reject_out_of_catalog() -> void: var o: Dictionary = (out[0] as Dictionary) if not out.is_empty() else {} Kit.check("目录外意图被拒(不静默吞掉)——实际载荷 %s" % str(o).substr(0, 80), out.size() == 1 and String(o.get("outcome", o.get("result", ""))) == "rejected") + + +# ---- V14 棋盘揭示预览只读口(架构整改——preview_reveal 与实挖揭示集同口径、零状态写入零事件)---- + +func _test_preview_reveal_readonly() -> void: + var events := 0 + _rules.cell_revealed.connect(func(_evt): events += 1) # 零发射哨兵(preview 全程不触发揭示事件) + # 形态 A:封印在场——preview(未开格) 不越封印且零状态写入 + var before_revealed := _rules.revealed_cells().size() + var before_seals := _rules.seal_count() + var c_open := _unrevealed_safe() + var prev_a: Array = _rules.preview_reveal(c_open) + Kit.check("V14 形态A:preview 返回集(真板形态——%d 格)" % prev_a.size(), prev_a.size() >= 0) + Kit.check("V14 形态A:调用前后零状态写入(revealed/seal 计数零变化)〔架构整改 V14〕", + _rules.revealed_cells().size() == before_revealed and _rules.seal_count() == before_seals) + # 形态 B:挖封印格——本格封印隐式退役只入模拟集,真实封印计数不动 + var seal_c := _unrevealed_safe() + _rules.settle_batch([{"action": "seal_place", "cell": seal_c}]) + var sealed_before := _rules.seal_count() + var prev_b: Array = _rules.preview_reveal(seal_c) + Kit.check("V14 形态B:preview(封印格) 零状态写入(seal_count 不变——隐式退役只入模拟集)〔架构整改 V14〕", + _rules.seal_count() == sealed_before) + # 同口径对照:preview(c) = settle_batch(dig c) 后 revealed 差集 ∖ {c}(F2——不含首格与已开格) + var dig_c := _unrevealed_safe() + var prev_c: Array = _rules.preview_reveal(dig_c) + var before := {} + for rc in _rules.revealed_cells(): + before[rc] = true + _rules.settle_batch([{"action": "dig", "cell": dig_c}]) + var after_diff := [] + for rc in _rules.revealed_cells(): + if not before.has(rc) and rc != dig_c: + after_diff.append(rc) + Kit.check("V14 同口径:preview(c) = 实挖揭示差集 ∖ {c}(F2——%d vs %d 格逐位)〔架构整改 V14〕" % [prev_c.size(), after_diff.size()], + str(prev_c) == str(after_diff)) + var events_before_previews := events # 三次 preview 调用前快照(此前增量=夹具自身实挖——与 preview 无关) + var _pa: Array = _rules.preview_reveal(_unrevealed_safe()) + var _pb: Array = _rules.preview_reveal(_unrevealed_safe()) + var _pc: Array = _rules.preview_reveal(_unrevealed_safe()) + Kit.check("V14 零事件:preview 全程 cell_revealed 零发射(前后增量 0——实测 %d→%d)〔架构整改 V14〕" % [events_before_previews, events], + events == events_before_previews) diff --git a/reports/iter50-实现报告-2026-11-03.md b/reports/iter50-实现报告-2026-11-03.md index 33ceb8bd..2ffc040e 100644 --- a/reports/iter50-实现报告-2026-11-03.md +++ b/reports/iter50-实现报告-2026-11-03.md @@ -100,6 +100,15 @@ 2. **透传确认读数**(T10):adventure_monte_carlo ab_a 档 N=5 零报错零脚本错误(BATCH perfect 终局计数落盘)——level_autoplay tree_rules 字典透传生效。 3. **MC 旧锚不重跑**(卡③总判据):六案现行值迁移全部同种子逐位回归(冒烟+77 套件),MC 采集端零改动。 -## 九、能力清单核对(收尾义务) +## 九、能力清单核对(收尾义务——经审计整改后更新) -`game/tests/README.md` 能力行与实际落地逐行核对:架构整改 10 新行(V1-V15 各行)与 5 改行、断言补齐 5 行(:164 减动效行等)、个体化批新增行——代表用例名与实际落地函数名一致(V13/V5 两处实现侧改名对齐,见 #6)。覆盖域表 :211「减动效开关存储契约」状态列翻转归反哺点清单。 +`game/tests/README.md` 能力行与实际落地逐行核对:架构整改 10 新行(V1-V15 各行)与 5 改行、断言补齐 5 行(:164 减动效行等)、个体化批新增行——代表用例名与实际落地函数名一致。**首版核对漏检两处名实断裂(V14/V2 函数未落地即报一致),经独立验收审计判缺漏后补齐(见第十节)**;V13/V5 两处实现侧改名对齐见 #6。覆盖域表 :211「减动效开关存储契约」状态列翻转归反哺点清单。 + +## 十、独立验收审计与整改(2026-11-03) + +- **首轮审计判定:不通过**(审计体=未参与实现子代理,报告全文落 `reports/iter50-验收审计-2026-11-03.md`)。缺漏三条:①R14/V14 `_test_preview_reveal_readonly` 从未落地(实现期 patch 脚本漏写落盘调用,minesweeper_rules_test 零触碰——虚假绿记录,根因在实现);②R2/V2 具名承接件 `_test_spend_discount_from_rule_key` 从未落笔(判据由申报 8 改造断言承载但名实断裂);③第九节名实核对结论失实(漏检上述两处)。 +- **整改**:①V14 落地 minesweeper_rules_test(挂载+五断言:形态A/B 零状态写入+实挖差集 F2 同口径逐位+preview 前后 cell_revealed 零增量——12→17 checks 绿);②V2 落地 level_shop_economy_test(shop.tres 加载零诊断+字段不在位+折后价 discount_pct 推导逐位+未激活原价对照——192→195 checks 绿);③本节与第九节订正。 +- **削弱申报程序缺项补账**:forge_table_test `_test_effect_kinds_closed` 钉数 34→32(审计判「例外——R3 摘名必然连带、强度不减、未按程序申报」)——补记为决定记录 #10。 +- **复验**:整改后由同一审计体复验两件落地测试与报告订正,判定见审计报告末节。 + +**实现决定记录补 #10**:forge_table_test 效果类型闭集钉数断言 34→32——甲案摘名(R3 被测面本身)的必然连带:该断言按其自身注释「钉现行数」必须随词表换代;强度不减(仍捕获任何增删),非削弱。属「随被测改动同步的计数对账」,性质同卡③申报 1-9 各条(夹具/引用形态迁移),未在卡面申报清单内——审计例外判定在案,此处补账。