卡②(结构小件批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:
1 parent
3a20a40891
commit
ea322599f7
14 files changed
+211
-27
No files matched your search
@@ -242,6 +242,25 @@ func _smoke_global_variant() -> void:
|
||||
eco.board_skew = 50
|
||||
var v50: Dictionary = _rows_weight_map(eco._biased_cell_rows(0))
|
||||
Kit.check("域上界 v=50:守恒成立且逐行权重恒正(域 [0,50] 安全)", eco._pool_weight(eco._biased_cell_rows(0)) == 77 and int(v50.get("heal_minor", -1)) > 0)
|
||||
# wr10 偏运判定收口+注入接线(p5 缝拆)——判定面夹具白盒装载(现网 game/data/tables/ 无产出
|
||||
# bias_rewards 的数据行,先例=tree_rules_v11_test 读 _triggers);命中数前置写在消息里防空扫描面假绿。
|
||||
var wrng = load("res://core/rng_service.gd").new()
|
||||
wrng.set_master_seed(42)
|
||||
var woc = load("res://core/battle_orchestrator.gd").new(_db, wrng)
|
||||
var wfx = woc.fx_host()
|
||||
var empty_bias: int = wfx.luck_bias_for(4)
|
||||
wfx.engine._push_trigger("feat", "wr10_fixture", {"on": "reward_roll",
|
||||
"do": {"kind": "bias_rewards", "value": 2}}, {})
|
||||
var hit_rows: int = wfx.engine._triggers.size()
|
||||
var loaded_bias: int = wfx.luck_bias_for(4)
|
||||
Kit.check("wr10①判定面:空订阅=%d / 装载后命中 %d 行 → luck_bias_for(4)=%d(期望 0/1/2;命中 0 即判据空转)" % [empty_bias, hit_rows, loaded_bias],
|
||||
empty_bias == 0 and hit_rows == 1 and loaded_bias == 2)
|
||||
Kit.check("wr10②接线面:组装点注入的查询口有效且与宿主查询口同源",
|
||||
woc._reward_economy.luck_bias_query.is_valid() and woc._reward_economy.luck_bias_query == wfx.luck_bias_for)
|
||||
woc._reward_economy.board_skew = 0
|
||||
var wbias: int = int(woc._reward_economy.luck_bias_query.call(4))
|
||||
Kit.check("wr10③权重生效面:注入回调取回 %d → 偏运池合计 77+4*2(实测 %d)" % [wbias, woc._reward_economy._pool_weight(woc._reward_economy._biased_cell_rows(wbias))],
|
||||
wbias == 2 and woc._reward_economy._pool_weight(woc._reward_economy._biased_cell_rows(wbias)) == 77 + 4 * 2)
|
||||
# 普通图摇号全链路确定性(off 路径)——同种子普通图资源映射逐位相同(golden 对拍另有批前快照)
|
||||
var nrng = load("res://core/rng_service.gd").new()
|
||||
nrng.set_master_seed(42)
|
||||
|
||||
@@ -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
|
||||
@@ -139,6 +139,14 @@ func _init() -> void:
|
||||
"跨区弹道按行 target_id 解析站桩(id 与名同传——d12)〔wd12〕")
|
||||
check(ffx.calls.size() == 2, "两路解析成功后演出层各接一拍(记参面非空)〔wd12〕")
|
||||
rp.free()
|
||||
# ---- 断言⑤:会话更替即清队(wr4——前置夹具入队再走真实入口 _begin_session;
|
||||
# 无夹具则改前改后皆绿:flush 无队列可清时两种形态同值)----
|
||||
UiKit.motion_scale = 1.0 # 常态入队(减动效快路同帧直落不入队——夹具须真落队列)
|
||||
main._on_step_row({"type": "damage", "target": "hero", "value": 1})
|
||||
main._on_step_row({"type": "heal", "target": "hero", "value": 2})
|
||||
check(main._row_queue.size() == 2, "会话更替夹具已入队(前提:%d 行)〔wr4〕" % main._row_queue.size())
|
||||
main._begin_session(false)
|
||||
check(main._row_queue.is_empty(), "会话更替后待播队列清零(_begin_session 内机制 flush)〔wr4〕")
|
||||
_finish()
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user