fix(review-batch3): 类型收紧生产清零137处(P1-2三步+延伸)+autoload class_name(ConfigDb/RngServiceCore)与_init标注(P2-1)+validate_skill_pool_links/ShopTable标注(P2-4)+相位enum外String面(P2-2)+typed-rows探针实证.tres装载转换;smoke缝合20处rows.assign+str(bb)同语义;审计生产双归零(240→103/83→59全测试链),单测7套绿,冒烟576/0同基线

This commit is contained in:
DKChan committed 2026-09-29 07:01:29 +08:00
1 parent f5edb65d25
commit 104cea6461
46 files changed
+233 -218

No files matched your search

+32 -32
View File
@@ -152,8 +152,8 @@ func _smoke_node_map_templates() -> void:
"抽签确定性:同种子逐位同图(实测 %s)" % String(names[0]))
# ⑤ N=1 池与现行固定图等价:单模板行过图校验(抽签取模 1 恒 0 = 回滚档)
var lt = load("res://data/schemas/level_table.gd").new()
lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30,
"templates": [tpl0]}]
lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30,
"templates": [tpl0]}])
check(lt.validate().is_empty(), "N=1 池表通过图校验(回滚档形态合法)")
# ⑥ 首次脚本分支:first_script=true 全关模板 0;false = 抽签(scope 恰一差异)
var rngF = load("res://core/rng_service.gd").new()
@@ -949,13 +949,13 @@ func _smoke_variation_framework() -> void:
check(_db.variation.row_by_id("nonexistent").is_empty(), "清单外 variant_id 返回空(读取通道在位)")
# 跨字段互锁负样本(加载期致命——枚举语义一致性闸)
var vt = load("res://data/schemas/variation_table.gd").new()
vt.rows = [{"variant_id": "bad1", "display_name": "坏行甲", "unlock_level": 1, "scope": "region",
vt.rows.assign([{"variant_id": "bad1", "display_name": "坏行甲", "unlock_level": 1, "scope": "region",
"effect": "flat_damage", "effect_value": 1, "trigger": "on_open", "placement": "any",
"board_types": [], "counter_items": []}]
"board_types": [], "counter_items": []}])
check(_errs_has_cross_field(vt.validate()), "跨字段互锁负样本①:flat_damage + placement=any 被拒(只出现在未打开的格子)")
vt.rows = [{"variant_id": "bad2", "display_name": "坏行乙", "unlock_level": 1, "scope": "region",
vt.rows.assign([{"variant_id": "bad2", "display_name": "坏行乙", "unlock_level": 1, "scope": "region",
"effect": "hide_number", "effect_value": 0, "trigger": "on_open", "placement": "any",
"board_types": [], "counter_items": []}]
"board_types": [], "counter_items": []}])
check(_errs_has_cross_field(vt.validate()), "跨字段互锁负样本②:hide_number + trigger≠on_number_shown 被拒")
@@ -2529,47 +2529,47 @@ func _smoke_skill_pool_death_void() -> void:
func _smoke_skill_pool_validation_reject() -> void:
var skill_table = load("res://data/schemas/skill_table.gd").new()
var enemy_table = load("res://data/schemas/enemy_table.gd").new()
enemy_table.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "ghost", "weight": 1}]}]
enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "ghost", "weight": 1}]}])
check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table), "dangling_skill"),
"加载校验拒绝:池条目 skill_id 悬空致命")
skill_table.rows = [{"skill_id": "a", "display_name": "a", "type": "damage", "damage_mult": 1.5, "cooldown_beats": 2}]
skill_table.rows.assign([{"skill_id": "a", "display_name": "a", "type": "damage", "damage_mult": 1.5, "cooldown_beats": 2}])
check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table), "pool_composition"),
"加载校验拒绝:池普攻行数 ≠ 1(空池不可能前提)")
skill_table.rows = [
skill_table.rows.assign([
{"skill_id": "b1", "display_name": "b1", "type": "buff", "buff_ref": "empower", "buff_duration": 2, "cooldown_beats": 3},
{"skill_id": "b2", "display_name": "b2", "type": "buff", "buff_ref": "fortify", "buff_duration": 2, "cooldown_beats": 4}]
enemy_table.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "b1", "weight": 1}, {"skill_id": "b2", "weight": 1}]}]
{"skill_id": "b2", "display_name": "b2", "type": "buff", "buff_ref": "fortify", "buff_duration": 2, "cooldown_beats": 4}])
enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "b1", "weight": 1}, {"skill_id": "b2", "weight": 1}]}])
check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table), "pool_composition"),
"加载校验拒绝:池增益技 > 1(每池增益 ≤1 纪律)")
skill_table.rows = [{"skill_id": "atk", "display_name": "a", "type": "basic", "damage_mult": 2.0, "cooldown_beats": 0}]
skill_table.rows.assign([{"skill_id": "atk", "display_name": "a", "type": "basic", "damage_mult": 2.0, "cooldown_beats": 0}])
check(not skill_table.validate().is_empty(), "加载校验拒绝:普攻配倍率 ≠ 1(域校验锁死)")
skill_table.rows = [{"skill_id": "atk", "display_name": "a", "type": "basic", "cooldown_beats": 2}]
skill_table.rows.assign([{"skill_id": "atk", "display_name": "a", "type": "basic", "cooldown_beats": 2}])
check(not skill_table.validate().is_empty(), "加载校验拒绝:普攻配冷却 ≠ 0(域校验锁死)")
skill_table.rows = [{"skill_id": "d", "display_name": "d", "type": "damage", "damage_mult": 30.0, "cooldown_beats": 1}]
skill_table.rows.assign([{"skill_id": "d", "display_name": "d", "type": "damage", "damage_mult": 30.0, "cooldown_beats": 1}])
check(not skill_table.validate().is_empty(), "加载校验拒绝:damage_mult 越域 [1.1,16]")
var et2 = load("res://data/schemas/enemy_table.gd").new()
et2.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "a", "weight": 0}]}]
et2.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "a", "weight": 0}]}])
check(not et2.validate().is_empty(), "加载校验拒绝:池权重 ≤ 0")
et2.rows = [{"enemy_id": "x", "display_name": "x", "pool": []}]
et2.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": []}])
check(not et2.validate().is_empty(), "加载校验拒绝:空池(禁)")
# 新效应词汇批(2026-09-19):妨害 / 必中附加分量校验组
skill_table.rows = [
skill_table.rows.assign([
{"skill_id": "w1", "display_name": "w1", "type": "debuff", "buff_ref": "off_guard", "buff_duration": 2, "cooldown_beats": 4},
{"skill_id": "w2", "display_name": "w2", "type": "debuff", "buff_ref": "off_guard", "buff_duration": 2, "cooldown_beats": 4}]
enemy_table.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "w1", "weight": 1}, {"skill_id": "w2", "weight": 1}]}]
{"skill_id": "w2", "display_name": "w2", "type": "debuff", "buff_ref": "off_guard", "buff_duration": 2, "cooldown_beats": 4}])
enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "w1", "weight": 1}, {"skill_id": "w2", "weight": 1}]}])
check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table), "pool_composition"),
"加载校验拒绝:池妨害技 > 1(每池妨害 ≤1 纪律)")
skill_table.rows = [{"skill_id": "w1", "display_name": "w1", "type": "debuff", "cooldown_beats": 4}]
skill_table.rows.assign([{"skill_id": "w1", "display_name": "w1", "type": "debuff", "cooldown_beats": 4}])
check(not skill_table.validate().is_empty(), "加载校验拒绝:妨害技缺 buff_ref(效果引用)")
skill_table.rows = [{"skill_id": "d", "display_name": "d", "type": "damage", "damage_mult": 1.5, "rider_mult": 1.5, "cooldown_beats": 1}]
skill_table.rows.assign([{"skill_id": "d", "display_name": "d", "type": "damage", "damage_mult": 1.5, "rider_mult": 1.5, "cooldown_beats": 1}])
check(not skill_table.validate().is_empty(), "加载校验拒绝:rider_mult 越域 (0,1]")
skill_table.rows = [{"skill_id": "b", "display_name": "b", "type": "buff", "buff_ref": "empower", "buff_duration": 2, "rider_mult": 0.5, "cooldown_beats": 1}]
skill_table.rows.assign([{"skill_id": "b", "display_name": "b", "type": "buff", "buff_ref": "empower", "buff_duration": 2, "rider_mult": 0.5, "cooldown_beats": 1}])
check(not skill_table.validate().is_empty(), "加载校验拒绝:非伤害技带必中附加分量")
# 施放类 side 守卫:妨害技引用敌方侧状态 → 拒绝(增益技引用主角侧同罪,本组以妨害反例覆盖)
skill_table.rows = [
skill_table.rows.assign([
{"skill_id": "atk", "display_name": "a", "type": "basic", "cooldown_beats": 0},
{"skill_id": "w1", "display_name": "w1", "type": "debuff", "buff_ref": "empower", "buff_duration": 2, "cooldown_beats": 4}]
enemy_table.rows = [{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "atk", "weight": 1}, {"skill_id": "w1", "weight": 1}]}]
{"skill_id": "w1", "display_name": "w1", "type": "debuff", "buff_ref": "empower", "buff_duration": 2, "cooldown_beats": 4}])
enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "atk", "weight": 1}, {"skill_id": "w1", "weight": 1}]}])
check(_has_err_category(_db.validate_skill_pool_links(skill_table, enemy_table, _db.status_effects), "cast_side"),
"加载校验拒绝:妨害技引用敌方侧状态(施放类 side 守卫)")
@@ -2676,34 +2676,34 @@ func _smoke_level_graph() -> void:
var lt = load("res://data/schemas/level_table.gd").new()
var good := [{"node_depth": 0, "type": "battle", "next": [1, 2]}, {"node_depth": 1, "type": "battle", "next": [2]},
{"node_depth": 2, "type": "boss"}]
lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": good}]
lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": good}])
check(lt.validate().is_empty(), "图校验正例:两岔合流小图零错误")
var dup = JSON.parse_string(JSON.stringify(good))
dup[1].node_depth = 0
lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dup}]
lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dup}])
check(_has_err_category(lt.validate(), "dup_key"), "图校验拒绝:节点编号重复(关卡内唯一定位地址)")
var dual = JSON.parse_string(JSON.stringify(good))
dual.append({"node_depth": 9, "type": "battle", "next": [2]})
lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dual}]
lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dual}])
check(_has_err_category(lt.validate(), "structural"),
"图校验拒绝:第二无入边节点(入口唯一违例——入口节点数 = 3)")
var boss_out = JSON.parse_string(JSON.stringify(good))
boss_out[2].next = [1]
lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": boss_out}]
lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": boss_out}])
check(_has_err_category(lt.validate(), "structural"), "图校验拒绝:Boss 带出边(终点不可外出)")
var cyc = JSON.parse_string(JSON.stringify(good))
cyc[1].next = [0]
lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": cyc}]
lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": cyc}])
check(_has_err_category(lt.validate(), "structural"), "图校验拒绝:回边 1→0(连线只朝前进方向 ⇒ 无环)")
var dang = JSON.parse_string(JSON.stringify(good))
dang[0].next = [1, 7]
lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dang}]
lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": dang}])
check(_has_err_category(lt.validate(), "dangling_next"), "图校验拒绝:出边指向不存在编号(悬空致命)")
var orphan = JSON.parse_string(JSON.stringify(good))
orphan[0].next = [1]
orphan[1].next = [2]
orphan.append({"node_depth": 5, "type": "battle", "next": [2]})
lt.rows = [{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": orphan}]
lt.rows.assign([{"level_index": 9, "display_name": "t", "rest_heal_pct": 30, "nodes": orphan}])
var orphan_errs: Array = lt.validate()
check(_has_err_category(orphan_errs, "structural"), "图校验拒绝:孤儿节点(从入口不可达 / 双入口同体违例)")
# ④ L2 选路推进:min / max 双路径全通(确定性路径轴——零随机流自开)