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:
1 parent
f5edb65d25
commit
104cea6461
46 files changed
+233
-218
No files matched your search
+32
-32
@@ -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 双路径全通(确定性路径轴——零随机流自开)
|
||||
|
||||
Reference in new issue
Block a user