卡②(结构小件批p1-p7+V15): 七点定点修落地+运行期违约通道负面套件+wr10 偏运缝拆验收——①p1 状态角标判据去重(main_overlay_flow._sync_status_entry 一组重复赋值语句删除,battle_live 局部量随之退役=wr1 载体);②p2 确认窗开合归模态栈单口(main 两处 _on_confirm_* 改 _close_modal;存档删除入口改 root._open_modal(root.confirm_dialog) 后再 open,遮挡记账/挂起兜底/开侧同步同口);③p3 棋盘动作与 stop 两入口显式 settlement 空防护(锁谓词异常时不崩于空引用);④p4 会话更替即清队:_begin_session 首行 _row_pacer.flush()(待播行不住局态=机制保证非时序约定);⑤p5 缝拆:RewardEconomy 删跨域直持(_fx/_ctx/set_fx)改注入 luck_bias_query: Callable,reward_roll 发射与 bias_rewards 求和收回 BattleFxHost.luck_bias_for(cell_count)(三参形 dispatch,不带 facts——禁复用 fx_emit 的第四实参会打开 when 事实条件面),组装点 set_fx 一行换赋值一行 1 换 1;类变量 15−2+2 净 15,gdstyle 无第 16 枚;⑥p6/p7 RngService 未知用途标签与未播种取数两分支加 violation_handler 记录位+release 下 return null 空引用即刻崩(fail-fast 传导,合法路径不可达)——debug 下 assert 先中断函数本体两态不可判别,故记录位是唯一可观测面;⑦board_generator/reward_economy 各加 fatal_handler 注入位并由组装点接 orchestrator._fatal(release 剥 assert 后仍经 battle_result 封印真中止)。新件 tests/unit/core/run_time_fatal_test.gd(manifest 登记 expect=1 negative=true):wr5 协作件 _fatal 经组装点传导 p5 封印+缺省形态不外溢/wr6 未知标签通道/wr7 未播种通道(各用新建 RngService 实例,播种断言 _counter==0)。wr10 三条入 variant_placement_test=判定面夹具白盒装载(现网数据无 bias_rewards 行,沿 tree_rules_v11_test 先例)+接线同源+权重生效 77+4*2。验收:variant_placement 49 checks 全绿(wr10 ①②③ PASS:空订阅 0/命中 1 行/装载后 2;查询口有效且与宿主同源;偏运池实测 85);run_time_fatal_test 退出码 1 三点绿;pacing_queue 绿(wr4 前置夹具真入队 2 行→更替后清零);ui_click_probe 问题 0(wr2 遮挡账开/关两侧断言);round_flow_skill_pool 130 checks 绿;wr11 dump_battle 六组(L{1,2}×S{42,779401,779501})与改前 before_* 逐字节 cmp 全等;gdstyle 基线外新违规 0、恶化 1(level_map_screen 类变量 22>21=iter38 存量非本批触碰面)、基线文件零改动〔结构小件批 V15〕

This commit is contained in:
DKChan committed 2026-10-27 18:39:53 +08:00
1 parent 3a20a40891
commit ea322599f7
14 files changed
+211 -27

No files matched your search

+125
View File
@@ -0,0 +1,125 @@
# 运行期违约通道负面套件(独立进程,期望退出码 1;回归态退出码 2)
# 卡② 三测试点:①wr5 协作件 _fatal 经组装点传导 orchestrator 封印(p5)+缺省形态不外溢;
# ②wr6 未知用途标签违约通道(p6);③wr7 未播种取数违约通道(p7)。
# 载体纪律(卡面 §7):注入只经编排器组装点——本文件不出现该注入成员的名称字样(防撤销证明②空转);
# 三测试点各用新建 RngService 实例(播种断言 _counter == 0);回归态判据只取可观测面——
# handler 记录位与封印是否落。return 位在 debug 下两态不可判别(assert 先中断函数本体),
# 走静态判据+代码评审注记,禁写成运行期断言。
# 违约路径必产 SCRIPT ERROR(assert 失败不可捕获)——故本件 manifest 登记 negative=true(test-conventions §5)。
# 运行:godot --headless --path game --script res://tests/unit/core/run_time_fatal_test.gd
extends SceneTree
const ConfigDBScript := preload("res://core/config_db.gd")
const RngScript := preload("res://core/rng_service.gd")
const BoardGeneratorScript := preload("res://core/board_generator.gd")
const RewardEconomyScript := preload("res://core/reward_economy.gd")
const OrchestratorScript := preload("res://core/battle_orchestrator.gd")
const TAG_OK := "board_gen" # 在册合法标签(PURPOSE_TAGS 含;wr7 必须用合法标签——未知标签检查排在播种检查之前)
func _init() -> void:
var db = ConfigDBScript.new()
if not db.load_tables("res://data/tables", true):
push_error("[run_time_fatal_test] 表加载失败——夹具不可用(回归)")
quit(2)
return
# 正向/缺省形态先跑完再触发违约(防 SCRIPT ERROR 混入正向判定)
if not _default_form(db):
quit(2)
return
if not _seal_propagation(db):
quit(2)
return
if not _unknown_tag_channel():
quit(2)
return
if not _unseeded_channel():
quit(2)
return
print("[run_time_fatal_test] 三点全绿:封印传导+未知标签通道+未播种通道〔卡② wr5/wr6/wr7〕")
quit(1)
# 缺省形态(契约 2):不接组装点的协作件违约只落自身 push_error+assert,不外溢封印
func _default_form(db) -> bool:
var rng = RngScript.new()
rng.set_master_seed(3)
var oc = OrchestratorScript.new(db, rng)
var bare_bg = BoardGeneratorScript.new()
bare_bg._fatal("缺省形态违约①(未接组装点——不应外溢封印)")
var bare_re = RewardEconomyScript.new(db, rng)
bare_re._fatal("缺省形态违约②(未接组装点——不应外溢封印)")
if oc.battle_result == "fatal_error":
push_error("[run_time_fatal_test/缺省] 未接组装点的违约外溢到编排器封印(缺省形态破)")
return false
# 合法路径对照(不注入 handler):播种后取在册标签照常发号
var rng_ok = RngScript.new()
rng_ok.set_master_seed(3)
var rg = rng_ok.open_stream(TAG_OK)
if rg == null or rng_ok.counter() != 1:
push_error("[run_time_fatal_test/缺省] 合法取号路径被改变(rg=%s counter=%d)" % [str(rg), rng_ok.counter()])
return false
return true
# ①wr5(p5):两协作件违约经组装点接线传导 → orchestrator.battle_result 落 "fatal_error"
func _seal_propagation(db) -> bool:
var rng_a = RngScript.new()
rng_a.set_master_seed(5)
var oc_bg = OrchestratorScript.new(db, rng_a)
oc_bg._board_generator._fatal("测试违约①棋盘生成")
if oc_bg.battle_result != "fatal_error":
push_error("[run_time_fatal_test/wr5] 棋盘生成违约未传导封印(battle_result=%r)" % oc_bg.battle_result)
return false
var rng_b = RngScript.new()
rng_b.set_master_seed(5)
var oc_re = OrchestratorScript.new(db, rng_b)
oc_re._reward_economy._fatal("测试违约②地图战斗资源")
if oc_re.battle_result != "fatal_error":
push_error("[run_time_fatal_test/wr5] 地图战斗资源违约未传导封印(battle_result=%r)" % oc_re.battle_result)
return false
return true
# ②wr6(p6):未知用途标签 → handler 记录位为真(判据主体)+拿不到可用 RNG;合法标签对照另行验过
func _unknown_tag_channel() -> bool:
var rng_bad = RngScript.new()
rng_bad.set_master_seed(7)
if not _inject_handler(rng_bad, "wr6"):
return false
var recorded: Array = []
rng_bad.violation_handler = func(p: String) -> void: recorded.append(p)
var rg = rng_bad.open_stream("bogus_purpose")
if recorded.size() != 1 or String(recorded[0]) != "bogus_purpose":
push_error("[run_time_fatal_test/wr6] 未知标签违约通道未记录(recorded=%s)" % str(recorded))
return false
if rg != null:
push_error("[run_time_fatal_test/wr6] 未知标签竟返回可用 RNG(违约被放行)")
return false
return true
# ③wr7(p7):未播种取数 → handler 记录位为真+拿不到可用 RNG;同标签播种对照另行验过
func _unseeded_channel() -> bool:
var rng_bad = RngScript.new() # 不播种(_master_seed 缺省 -1)
if not _inject_handler(rng_bad, "wr7"):
return false
var recorded: Array = []
rng_bad.violation_handler = func(p: String) -> void: recorded.append(p)
var rg = rng_bad.open_stream(TAG_OK)
if recorded.size() != 1 or String(recorded[0]) != TAG_OK:
push_error("[run_time_fatal_test/wr7] 未播种违约通道未记录(recorded=%s)" % str(recorded))
return false
if rg != null:
push_error("[run_time_fatal_test/wr7] 未播种竟返回可用 RNG(EC7 违约被放行)")
return false
return true
# 成员在位前提检查(成员被移除时走干净退出 2,不落「赋值不存在的属性」式中途中断)
func _inject_handler(rng, label: String) -> bool:
if not (rng.get("violation_handler") is Callable):
push_error("[run_time_fatal_test/%s] violation_handler 成员缺失(p6/p7 形态未实装——回归)" % label)
return false
return true
@@ -0,0 +1 @@
uid://cer3wlsqhjy7i