iter56-卡1:结算期文字列表退役与日志零文案(迭代56卡1): 撤B区逐行文字列表(row_pacer文字入带三调用/行格式化域删净——FX排播链零diff保留)+日志step行零文案(text/display_name不落盘)+reward_ineffective六发射点补reason结构化(full_layers/full_hp/no_enemy_alive/hero_down); 分析工具改读结构化字段(target==all_enemies/reason优先text兜底双分支)+analyze_parity_check对拍载体。读数: R1零逐行文字/R2 FX链行型分布独立推导逐位一致/R3零文案+全字段落盘/R4判读等价三读数全一致/R5四类reason逐一命中——各T提交信息载; 能力行:137/:138名实一致(_smoke_settle_zero_rows/_assert_fx_chain/_assert_no_text_and_full_payload/_assert_four_reasons); 测试削弱全部申报内(§10清单+§5.5同生死波及面11处登记实现报告); 中档审计通过
This commit is contained in:
1 parent
9251d35650
commit
908e518306
40 files changed
+1258
-1298
No files matched your search
@@ -0,0 +1,108 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 日志 step 行零文案与全字段落盘断言(结算期文字列表退役批 T2——日志零文案只存字段):
|
||||
# 真实入口 = sim 采集链(LevelAutoplay.run_level 挂 PlaytestLogger.start_session → 真实结算 →
|
||||
# close_session 落盘 JSONL 读回),断言:
|
||||
# ① 全型 step 行零中文文案(text / display_name 两键不存在);
|
||||
# ② 公共七字段(kind/type/source/cell/round/value/highlight)与平铺原件(origin_cell/round_index/
|
||||
# source_class)逐型在位——日志逐行全字段落盘义务不变(公共字段集除文案两键外零删减);
|
||||
# ③ payload 键抽样在位(damage 行 roll/ac/tier/normal/pierce/magic/baseline——改前键集实证在册,
|
||||
# 反事实精确重算数据面不被零文案改动静默吞键)。
|
||||
# 运行:godot --headless --path game --script res://tests/unit/presentation/playtest_logger_step_fields_test.gd(expect 0)
|
||||
extends SceneTree
|
||||
|
||||
const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
const ConfigDBScript := preload("res://core/config_db.gd")
|
||||
|
||||
var _problems: Array = []
|
||||
|
||||
|
||||
func check(cond: bool, msg: String) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
if not cond:
|
||||
_problems.append(msg)
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/08-Alpha版本标准.md:154 演出链在役(逐行结算排播已随 v1.29 退役)——
|
||||
# 日志零文案只存字段(text/display_name 不落盘),其余全字段与 payload 逐键保留
|
||||
var db = ConfigDBScript.new()
|
||||
if not db.load_tables("res://data/tables", true):
|
||||
_problems.append("数值表加载失败(夹具前提)")
|
||||
_finish()
|
||||
return
|
||||
_assert_no_text_and_full_payload(db)
|
||||
_finish()
|
||||
|
||||
|
||||
func _assert_no_text_and_full_payload(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:87 显示名等玩家可见文案是数据面字段(日志消费端零文案)
|
||||
var logger = load("res://presentation/playtest_logger.gd").new()
|
||||
logger.ap_per_round = int(db.run.action_economy.ap_per_round) # 注入序前置(守卫拒后开——R5 必填)
|
||||
var log_path: String = logger.start_session(4242)
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
var st = autoplay.run_level(db, 4242, 1, 0, 0, false, logger, "normal", "min")
|
||||
logger.close_session()
|
||||
check(bool(st.get("terminated", false)) or int(st.get("rounds", 0)) > 0,
|
||||
"真实结算已跑(夹具前提:rounds>0——result=%s log_path=%s)" % [String(st.get("result", "?")), String(st.get("log_path", "?"))])
|
||||
# 落盘 JSONL 读回(start_session 返回路径——采集链同源)
|
||||
var f := FileAccess.open(log_path, FileAccess.READ)
|
||||
check(f != null, "日志文件可读(%s)" % log_path)
|
||||
if f == null:
|
||||
return
|
||||
var steps: Array = []
|
||||
while not f.eof_reached():
|
||||
var line := f.get_line()
|
||||
if line.strip_edges() == "":
|
||||
continue
|
||||
var parsed: Variant = JSON.parse_string(line)
|
||||
if parsed is Dictionary and String(parsed.get("kind", "")) == "step":
|
||||
steps.append(parsed)
|
||||
f.close()
|
||||
check(steps.size() > 0, "step 行非空(断言前提:%d 行)" % steps.size())
|
||||
# ---- ① 全型零文案(text / display_name 两键不存在)----
|
||||
var text_hits := 0
|
||||
var display_hits := 0
|
||||
for s in steps:
|
||||
if (s as Dictionary).has("text"):
|
||||
text_hits += 1
|
||||
if (s as Dictionary).has("display_name"):
|
||||
display_hits += 1
|
||||
check(text_hits == 0, "全 step 行零 text 键(命中 %d/%d)〔退役改 V-退役卡 R3〕" % [text_hits, steps.size()])
|
||||
check(display_hits == 0, "全 step 行零 display_name 键(命中 %d/%d)〔退役改 V-退役卡 R3〕" % [display_hits, steps.size()])
|
||||
# ---- ② 公共七字段 + 平铺原件逐型在位 ----
|
||||
var common := ["kind", "type", "source", "cell", "round", "value", "highlight",
|
||||
"origin_cell", "round_index", "source_class"]
|
||||
var misses: Array[String] = []
|
||||
for s in steps:
|
||||
for k in common:
|
||||
if not (s as Dictionary).has(k):
|
||||
misses.append("%s 缺 %s" % [String(s.get("type", "?")), k])
|
||||
check(misses.is_empty(), "公共字段与平铺原件逐行在位(缺:%s)〔退役改 V-退役卡 R3〕" % [", ".join(misses)])
|
||||
# ---- ③ damage 行 payload 键并集抽样(反事实精确重算数据面在册——单行键随行型分布,
|
||||
# 并集才是改前契约形态:掷点键逐行必有、分量键按攻击来源分布)----
|
||||
var dmg_union := {}
|
||||
var dmg_seen := 0
|
||||
for s in steps:
|
||||
if String(s.get("type", "")) == "damage":
|
||||
dmg_seen += 1
|
||||
for k in (s as Dictionary).keys():
|
||||
dmg_union[k] = true
|
||||
check(dmg_seen > 0, "damage 行在册(抽样前提:%d 行)" % dmg_seen)
|
||||
var payload_missing: Array[String] = []
|
||||
for k in ["roll", "ac", "tier", "normal", "baseline"]:
|
||||
if not dmg_union.has(k):
|
||||
payload_missing.append(k)
|
||||
check(payload_missing.is_empty(),
|
||||
"damage 行 payload 键并集在位(缺:%s)〔退役改 V-退役卡 R3〕" % [", ".join(payload_missing)])
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
if _problems.is_empty():
|
||||
print("[playtest_logger_step_fields_test] PASS — 日志 step 行零文案与全字段落盘 全绿")
|
||||
quit(0)
|
||||
else:
|
||||
for p in _problems:
|
||||
push_error("[playtest_logger_step_fields_test] FAIL — " + p)
|
||||
print("[playtest_logger_step_fields_test] FAIL — " + p)
|
||||
quit(1)
|
||||
Reference in new issue
Block a user