merge(测试面收尾): 节点图换代三件直改批——宿主改名 node_map_determinism+验证集清单重生成(1067→1544,承接 986/1543,--diff 三对齐,退役词与旧名零命中)+level.tres 表尾叙事清偿+S11 标签假阳性随动;中途两次假红系他会话并行 Godot 干扰(串行跑闸在册场景),退净复跑全绿;master 格式换代批冲突按新版式解(删三条已完成条目)

This commit is contained in:
DKChan committed 2026-10-25 08:03:59 +08:00
commit 5a73ee4914
8 files changed
+2519 -1401

No files matched your search

+1 -1
View File
@@ -13,4 +13,4 @@ rows = [
; 节点图源已换代为参数化生成器(关卡节点图生成 v1.1)——本表逐关行只承载关卡序号/显示名/恢复比例,
; 不再携带节点数据;图 = f(参数档, 种子),参数档见 level_gen_params.tres 三行(消费侧按 level_index 解析后交 generate)。
; 旧 15 张模板池(3 关 × 5)随迭代 35 卡② 清出,历史查 git 提交史与 tools/t5_build_templates.py、t17_fanout2_rebuild.py 留档。
; 旧 15 张模板池(3 关 × 5)已清出,历史查 git 提交史与 tools/t5_build_templates.py、t17_fanout2_rebuild.py 留档。
@@ -1,4 +1,4 @@
# tests/integration/node_map_templates_test.gd — L2 集成用例:关卡节点图生成·确定性承载
# tests/integration/node_map_determinism_test.gd — L2 集成用例:关卡节点图生成·确定性承载
# 断言面 = 生成图确定性套(批 B 断言迁移自 smoke_all.gd,G12 施工组;
# 主会话裁决六整套集成不拆——跨四系统且走落盘)。
# 跨系统面 = RngService(纯派生流零计数器占用)×
@@ -7,7 +7,7 @@
# SaveManager+MetaProgression(首次冒险布尔位收束置位落盘——真实档写盘)。
# 与单元侧同入口同协议:extends SceneTree+Kit.check 主通道;--script 模式无 autoload,
# ConfigDB 显式实例化构造注入;表加载失败不中止(沿被迁断言面的源语义——诊断展开,红由具体断言落)。
# 运行:godot --headless --path game --script res://tests/integration/node_map_templates_test.gd
# 运行:godot --headless --path game --script res://tests/integration/node_map_determinism_test.gd
extends SceneTree
const Kit := preload("res://tests/unit/test_kit.gd")
@@ -23,12 +23,12 @@ func _init() -> void:
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上)
var load_ok: bool = _db.load_tables("res://data/tables", true)
if not load_ok:
push_error("[node_map_templates_test] 表加载返回失败——诊断如下(红由具体断言落)")
push_error("[node_map_determinism_test] 表加载返回失败——诊断如下(红由具体断言落)")
for d in _db.diagnostics():
if d.severity == "error" or d.severity == "fatal":
push_error(" [%s] %s: %s" % [d.severity, d.category, d.message])
_smoke_generated_map_determinism()
quit(Kit.finish("node_map_templates_test"))
quit(Kit.finish("node_map_determinism_test"))
# ---- 关卡节点图生成·确定性承载断言面 ----
+1 -1
View File
@@ -87,7 +87,7 @@ func _suites() -> Array:
{"path": "res://tests/unit/presentation/modal_flow_test.gd", "expect": 0}, # 模态编排纯逻辑(V6:直接 new/互斥域谓词/三例外锁/演播后排窗)
# ---- L2 集成层(跨系统用例,与 unit/ 的隔离断言面分工)----
{"path": "res://tests/integration/save_rng_roundtrip_test.gd", "expect": 0}, # 存档⇄RNG 快照往返(SaveManager 迁移链 × 断点消费 × RNG 续跑 × 停点态确定性)
{"path": "res://tests/integration/node_map_templates_test.gd", "expect": 0}, # 关卡节点图生成·确定性承载(生成图复现×首冒险置位落盘——批 B 自 smoke_all 迁入,裁决六整套集成不拆)
{"path": "res://tests/integration/node_map_determinism_test.gd", "expect": 0}, # 关卡节点图生成·确定性承载(生成图复现×首冒险置位落盘——批 B 自 smoke_all 迁入,裁决六整套集成不拆)
{"path": "res://tests/integration/cross_system_flow_test.gd", "expect": 0}, # 跨系统真实流×落盘(RNG 事件日志落盘/专长断点往返/存档摘要集成/试玩记录仪真实结算流——批 B 转办块宿主,裁决一/二/三/七)
# ---- core 四件与呈现层两件的直接单测 ----
{"path": "res://tests/unit/core/board_generator_test.gd", "expect": 0}, # 棋盘生成(尺寸合表/数字=八邻雷数/同种子逐位一致/可推理自洽)
@@ -33,7 +33,7 @@ func _test_pool_damage() -> void:
var d := _floor_val() + 9 # 表值推导的任意正探针量(非玩法行值)
Kit.check("中性双池 (0,0) 原样透传", DamageMathScript.pool_damage(d, 0, 0) == d)
Kit.check("负敌方池压低不增高", DamageMathScript.pool_damage(d, 0, int(db.settlement.pool_clamp_lo)) <= d)
Kit.check("正主角池抬升不低于原值", DamageMathScript.pool_damage(d, int(db.settlement.pool_clamp_hi), 0) >= d)
Kit.check("正·主角池抬升不低于原值", DamageMathScript.pool_damage(d, int(db.settlement.pool_clamp_hi), 0) >= d)
Kit.check("主角池单调不减(+50% vs +49% 探针档)", DamageMathScript.pool_damage(d, 50, 0) >= DamageMathScript.pool_damage(d, 49, 0))
Kit.check("对称性:池值互换结果不变(乘算交换)", DamageMathScript.pool_damage(d, 30, -20) == DamageMathScript.pool_damage(d, -20, 30))
Kit.check("输出非负(maxi(0,·) 封底)", DamageMathScript.pool_damage(d, int(db.settlement.pool_clamp_lo), int(db.settlement.pool_clamp_lo)) >= 0)
+2455 -1352
View File
File diff suppressed because it is too large. Load diff
+57 -18
View File
@@ -40,6 +40,7 @@ import bisect
import re
import subprocess
import sys
from datetime import date
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
@@ -326,24 +327,27 @@ def base_commit():
return "<git 不可用,未取得基点 commit>"
def render_list(entries, funcs_by_src, src_names) -> str:
"""生成验证集清单骨架。白话释义/处置两列留待回填(回填不动冻结列)。
多源按(源文件, 函数)分章——跨文件同名函数不并章;章头行号=该源文件内行号。"""
def render_list(entries, funcs_by_src, src_names, carry=None) -> str:
"""生成验证集清单。冻结列=机器提取;「白话释义/处置」两列:承接命中行用旧清单回填,
其余落(待填)由维护回填(回填不动冻结列)。多源按(源文件, 函数)分章——跨文件同名
函数不并章;章头行号=该源文件内行号。头注全部由当次数据生成,禁批次专名与写死计数。"""
carry = carry or {}
out = []
out.append("# 验证集清单(迁移参照物·冻结)")
out.append("# 验证集清单(断言快照·冻结)")
out.append("")
out.append("> 生成日期:2026-10-22 · 基点 commit:`%s` · 源:%s" % (base_commit(), "、".join(src_names)))
out.append("> 提取口径:静态 `check(` 调用点,括号配平归集(可跨行)。批 B 基点实测 smoke_all.gd 调用点 1065 处;")
out.append("> 行级 `grep -c \"check(\"` = 1067 是另一口径——多出的 2 行为 `func check(` 定义行与")
out.append("> 一处注释行(「禁恒真 check(true)」),非调用点。运行时计数大于静态计数=循环展开条目,")
out.append("> 两口径各自浮动,禁互相换算(tests/README「断言计数双口径」)。")
out.append("> 生成命令:`python tools/extract_checks.py --extract`(可复现;重新生成须 --force)。")
out.append("> 生成日期:%s · 基点 commit:`%s` · 源:%s" % (date.today().isoformat(), base_commit(), "、".join(src_names)))
out.append("> 提取口径:静态 `check(` 调用点,括号配平归集(可跨行);缺省源=三宿主遍历")
out.append("> (unit/**+integration/**+system_test.gd)。本基点实测 %d 个静态调用点;行级" % len(entries))
out.append("> `grep -c \"check(\"` 是另一口径(含 `func check(` 定义行与注释行),两口径各自浮动,")
out.append("> 禁互相换算(tests/README「断言计数双口径」)。运行时计数大于静态计数=循环展开条目。")
out.append("> 生成命令:`python tools/extract_checks.py --extract`(可复现;重新生成须 --force;")
out.append("> 承接旧清单回填列须 --carry-from <旧清单>)。")
out.append("> 冻结纪律:每条的「标签原文」「cond 摘要」「quiet」三列为机器提取逐字保真,禁任何改写;")
out.append("> cond 摘要=原文跨行折叠单行(连续空白并一空格),单元格内 `|`→`\\|`、`\\`→`\\\\` 转义,读回还原。")
out.append("> 「白话释义」「处置」两列由维护回填,不属冻结面。")
out.append("> 出口对账:`python tools/extract_checks.py --diff game/tests/验证集清单.md --src <宿主文件>...`")
out.append("> ——标签/cond/计数三对齐才算迁移完(合同 §五出口机检)。")
out.append("> 维护义务:此后断言新增/删除/改判必须同步本清单(test-conventions §9.3 锚)。")
out.append("> 「白话释义」「处置」两列由维护回填(未承接行为(待填)),不属冻结面。")
out.append("> 对账:`python tools/extract_checks.py --diff game/tests/验证集清单.md`(缺省三宿主源)")
out.append("> ——标签/cond/计数三对齐才算同步完。维护义务:断言新增/删除/改判必须同步本清单")
out.append("> (test-conventions §8.3 维护锚)。")
out.append("")
seq = 0
by_gf = []
@@ -361,8 +365,12 @@ def render_list(entries, funcs_by_src, src_names) -> str:
out.append("|---|---|---|---|---|---|---|")
for e in es:
seq += 1
out.append("| %d | %d | %s | %s | (待填) | | %s |" % (
seq, e["line"], esc_cell(label_cell(e)), esc_cell(fold(e["cond"])), esc_cell(fold(e["quiet"]))))
hit = carry.get((fold(e["cond"]), e["label_literal"], fold(e["label_suffix"])))
disp = esc_cell(hit[0]) if hit else "(待填)"
act = esc_cell(hit[1]) if hit else ""
out.append("| %d | %d | %s | %s | %s | %s | %s |" % (
seq, e["line"], esc_cell(label_cell(e)), esc_cell(fold(e["cond"])), disp, act,
esc_cell(fold(e["quiet"]))))
out.append("")
out.append("---")
out.append("全源共 %d 章、%d 条(静态调用点口径)。" % (len(by_gf), seq))
@@ -389,6 +397,8 @@ def parse_list(path: Path):
label_raw = unesc_cell(cells[2])
cond = unesc_cell(cells[3])
quiet = unesc_cell(cells[6])
disp = unesc_cell(cells[4])
action = unesc_cell(cells[5])
lit_m = LITERAL_RE.match(label_raw)
literal = lit_m.group(0) if lit_m else label_raw
suffix = label_raw[lit_m.end():].strip() if lit_m else ""
@@ -400,10 +410,25 @@ def parse_list(path: Path):
"label_suffix": suffix,
"cond": cond,
"quiet": quiet,
"disp": disp,
"action": action,
})
return entries
CARRY_RENAME = ("node_map_templates_test.gd", "node_map_determinism_test.gd")
def carry_cells(frozen_rows):
"""旧清单行 → 承接映射:指纹(与 entry_key 同构)→(白话释义, 处置)。
承接文本内的旧宿主文件名一并映射为新名(唯一在册更名对象)。"""
m = {}
for r in frozen_rows:
key = (fold(r["cond"]), r["label_literal"], fold(r["label_suffix"]))
m[key] = (r.get("disp", "").replace(*CARRY_RENAME), r.get("action", "").replace(*CARRY_RENAME))
return m
def _short(s, n=80):
s = s.replace("\n", " ")
return s if len(s) <= n else s[:n] + "…"
@@ -531,6 +556,8 @@ def main() -> int:
help="断言源文件(可多个;缺省=三宿主遍历 unit/**+integration/**+system_test.gd)")
ap.add_argument("--out", default=str(DEFAULT_OUT), help="--extract 输出路径")
ap.add_argument("--force", action="store_true", help="输出文件已存在时允许覆盖")
ap.add_argument("--carry-from", default=None, metavar="旧清单",
help="--extract 时按指纹承接旧清单「白话释义/处置」两列(旧宿主文件名映射为新名)")
args = ap.parse_args()
if sum(bool(x) for x in (args.extract, args.diff, args.list_funcs)) != 1:
print("[extract_checks] 用法:--extract / --diff <清单文件> / --list-funcs 三选一")
@@ -543,9 +570,21 @@ def main() -> int:
if out.exists() and not args.force:
print("[extract_checks] FAIL:清单已存在(%s)——冻结参照物防误覆,重生成须加 --force" % out)
return 2
carry = {}
if args.carry_from:
cf = Path(args.carry_from)
if not cf.is_file():
print("[extract_checks] FAIL:--carry-from 旧清单不可读:%s" % cf)
return 2
old_rows = parse_list(cf)
carry = carry_cells(old_rows)
print("[extract_checks] 旧清单 %d 行 → 承接指纹 %d 个" % (len(old_rows), len(carry)))
entries, funcs_by_src = extract_all(src_paths)
out.write_text(render_list(entries, funcs_by_src, [p.name for p in src_paths]), encoding="utf-8", newline="\n")
print("[extract_checks] 已生成 %s(%d 个源文件、%d 个调用点)" % (out, len(src_paths), len(entries)))
out.write_text(render_list(entries, funcs_by_src, [p.name for p in src_paths], carry), encoding="utf-8", newline="\n")
hitn = sum(1 for e in entries
if (fold(e["cond"]), e["label_literal"], fold(e["label_suffix"])) in carry)
print("[extract_checks] 已生成 %s(%d 个源文件、%d 个调用点、承接回填 %d 行)"
% (out, len(src_paths), len(entries), hitn))
return 0
if args.diff:
lp = Path(args.diff)
-24
View File
@@ -54,30 +54,6 @@
**状态**:待写卡
#### 验证集清单快照重生成——断言索引含退役措辞与旧行号(2026-10-25 登记,来源=审计发现)
**实况**:工程债证据=迭代 35 卡② 验收审计申报(git 历史可考:合回提交 5499eb9c 内的 reports/iter35-卡②-验收审计-2026-10-24.md,该产出物已按吸收即死退役):game/tests/验证集清单.md 是批 B 迁移时的断言文本快照索引,只由 tools/extract_checks.py 手工重生成、不进任何闸;卡② 断言面换代后十余行仍含 first_script/template_pick 等退役措辞与过期行号(实测 first_script 8 处、template_pick 2 处),与宿主现文不符。2026-10-25 规则修订(改动四类):本件属工程改动(测试基建维护,直改类)。执行口径=走重生成:tools/extract_checks.py 两小改(头注模板数据驱动化+新增 --carry-from 按同指纹承接「白话释义/处置」两列、承接文本内旧宿主文件名映射为新名)后 --extract --force 重生成(缺省三宿主全量口径;实测漂移=清单 1067 条 vs 现提取 1544 条〔消失 67/新增 539/字面变更 14 对〕,template_pick 实测 3 处——登记句「2 处」少数一行),--diff 须 PASS;重生成后 grep node_map_templates/first_script/template_pick 预期零命中(若命中须全为反向断言)。原需求卡片按违形退役:结论已回写本条目,卡片删除,全稿查 git 历史(提交 1fb44cf4)。
**改动面**:游戏代码+工具代码
**状态**:待执行
#### 测试宿主改名——node_map_templates_test.gd 已承载生成图确定性断言(2026-10-25 登记,来源=审计发现)
**实况**:工程债证据=迭代 35 卡② 反哺点⑧:game/tests/integration/node_map_templates_test.gd 现承载「生成图确定性断言套」,文件名中的 templates 是模板时代遗留;manifest 登记行=game/tests/run_all.gd:90。改名为 node_map_determinism_test.gd 须同批改 manifest 路径行。2026-10-25 规则修订(改动四类):本件属工程改动(测试基建维护,直改类)。执行口径=git mv 宿主两件(.gd+.uid)+改 run_all.gd:90 路径行+文件内 4 处自引用字面量(:1/:10/:26/:31),断言判据零改动,直跑新名退出码 0 为验收。原需求卡片按违形退役(结论已回写本条目,卡片删除,git 历史可考)。
**改动面**:游戏代码
**状态**:待执行
#### level.tres 表尾注释含迭代叙事(2026-10-25 登记,来源=审计发现)
**实况**:工程债证据=迭代 35 卡② 反哺点⑨:game/data/tables/level.tres 表尾注释写「旧 15 张模板池(3 关 × 5)随迭代 35 卡② 清出」,与 doc-conventions §5 禁写变更叙事有张力;卡② 卡片 T3 明令表尾写模板去向注记,故处置面限于叙事形态(删迭代号、保留图源换代事实句),不删去向事实。2026-10-25 规则修订(改动四类):本件属工程改动(数据表注释维护,直改类),执行口径=条目原裁(删迭代号、保留去向事实句、表内零改动)。原需求卡片按违形退役(结论已回写本条目,卡片删除,git 历史可考)。
**改动面**:游戏代码
**状态**:待执行
#### 架构与规范对齐批——代码结构审查发现的文档-实现漂移(2026-10-24 登记,来源=审计发现)
**实况**:审计报告=reports/审计-game代码结构审查-2026-10-24.md(§二 C3/C4/C5+§三 漂移清单)。漂移与待裁件七件:①架构文档「模块归属」多行 API 清单与实现不符(A2 try_* 便捷形/B2 ambush_grant_plan/B4 equivalence_supply 不存在;实有 grant_reserve_ap/finish_round_stop/check_skill_unlocks 未登记;damage_controller 与 settlement/ 五段类零条目——S7 落地的前置);②code-conventions §1.3 核心写调用位置——三拆件控制器(presentation/curio_interact_controller.gd、camp_shop_presenter.gd、treasure_interact_controller.gd)持写调用 vs 规范「只允许在组合根出现」的 spec-AC 冲突,须裁「改规范成文组合根家族」vs「调用收回 main」;③A3→EffectEngine 反向依赖(core/action_economy.gd:43-49)——真违约或事实源失真二选一(effect_engine 降层登记基础层 vs B1 代发 vs 仅补登记);④架构文档 :149/151 层合同计数写死 17 项 vs LAYER_CONTRACT 实 18 项;⑤明细行协议三处三个数(头注 9/实发 13/架构文档 15);⑥§1.3 例举 submit_window_selection 符号已退役;⑦core/effect_engine.gd:360 校验文案「9 项」实为 18 项。