diff --git a/game/README.md b/game/README.md index a997e1e4..53ae9193 100644 --- a/game/README.md +++ b/game/README.md @@ -2,9 +2,9 @@ > // VERTICAL SLICE - NOT FOR PRODUCTION > // Validation Question(v2,2026-09-11):线性第一关(战×2→道具→战×2→恢复→Boss)能否承载 -> // "数值提升→通关期望改善"的 Roguelike 元进度验证——基线属性应该难到打不过、天赋数值提升把 -> // 通关期望拉回可玩带,且这条曲线能用数值调整板 + 批量模拟**测量出来** -> // (通关攻击期望 / 败北血量数学期望);v1 的单战斗循环问题(逐行归因 P2 / Core headless 可跑) +> // "数值提升→冒险成功期望改善"的 Roguelike 元进度验证——基线属性应该难到打不过、天赋数值提升把 +> // 冒险成功期望拉回可玩带,且这条曲线能用数值调整板 + 批量模拟**测量出来** +> // (冒险成功攻击期望 / 败北血量数学期望);v1 的单战斗循环问题(逐行归因 P2 / Core headless 可跑) > // 已于 2026-09-10 验证并保持回归(初版断言面 46 项,后并迁系统测试宿主,沿革查 git log)。 > // Date: 2026-09-10(v1)· 2026-09-11(v2 关卡扩展)· 引擎 Godot 4.7.2 · 本目录仅作设计验证参考,禁止 import 进生产代码 @@ -12,10 +12,10 @@ 1. 用 Godot 4.7.2 打开本目录(含 `project.godot` 的文件夹) 2. 按 F5 运行(主场景 `presentation/main.tscn`) -3. **主入口:`▶ 开始冒险(三关连探:地精洞窟 → 幽暗地域 → 灰矮人矿城)`**——一条命走完三关(冒险结构实现批 2026-09-21:生命/GP/加算区跨关同账、非末关通关发大奖励〔上限提升+血回满+钥石〕、任意战斗倒下冒险终、结算屏出冒险摘要五件事;选路停点可「放弃冒险」(同失败结算,2026-09-21 用户拍板补入口));首关节点链:战→战→赏→战→战→疗→王。唯一试玩入口 = 完整冒险——单关测试直入口(L2/L3)已退役(2026-09-23 用户拍板) -4. `调试` 角标浮窗(恒开——2026-10-16 用户令 DS_DEBUG 写死,原环境变量门控退役;2026-10-04 迭代 14.5 调试整合批:原数值调整板/随机种子框/两层调试三散件收一):攻击/生命百分比加成(模拟天赋树解锁)+ 批量模拟(输出通关率/承伤期望/败北节点分布)+ 两层调试入口 +3. **主入口:`▶ 开始冒险(三关连探:地精洞窟 → 幽暗地域 → 灰矮人矿城)`**——一条命走完三关(冒险结构实现批 2026-09-21:生命/GP/加算区跨关同账、非末关的关卡完成发大奖励〔上限提升+血回满+钥石〕、任意战斗倒下冒险终、结算屏出冒险摘要五件事;选路停点可「放弃冒险」(同失败结算,2026-09-21 用户拍板补入口));首关节点链:战→战→赏→战→战→疗→王。唯一试玩入口 = 完整冒险——单关测试直入口(L2/L3)已退役(2026-09-23 用户拍板) +4. `调试` 角标浮窗(恒开——2026-10-16 用户令 DS_DEBUG 写死,原环境变量门控退役;2026-10-04 迭代 14.5 调试整合批:原数值调整板/随机种子框/两层调试三散件收一):攻击/生命百分比加成(模拟天赋树解锁)+ 批量模拟(输出关卡完成率/承伤期望/败北节点分布)+ 两层调试入口 -headless 冒烟(752 项断言〔计数随批增长,现值以最新批末闸读数为准〕,含关卡线性推进/满配通关/裸装败北/回放确定性;2026-10-02 性能报告实测 60.55 秒,报告在 `性能实测报告(已退役,git 历史可查)`): +headless 冒烟(752 项断言〔计数随批增长,现值以最新批末闸读数为准〕,含关卡线性推进/满配冒险成功/裸装败北/回放确定性;2026-10-02 性能报告实测 60.55 秒,报告在 `性能实测报告(已退役,git 历史可查)`): ``` Godot_v4.7.2-stable_win64_console.exe --headless --path . --script res://probe/smoke_all.gd @@ -35,7 +35,7 @@ Godot_v4.7.2-stable_win64_console.exe --headless --path . res://probe/ui_tune_pr 其余八场景探针(ui_click_probe 行为链 / ui_input_probe 输入合成 / ui_struct_probe 全屏结构 / ui_contrast_probe 对比度 / ui_probe·ui_tune_probe 调参面板 / t17_defer_probe 结算演播延迟链回归 / shot_probe·fx_probe·fx_shot_probe·board_shot_probe 画面与特效采样;全部由 `tools/probe_gate.sh` 与 `tools/render_gate.sh` 调度,闸清单见 `tools/run_all_gates.sh`)+ 板图校准工具 `sim/calibrate_boards.gd`(board_calibration.csv 重跑入口,--script 运行): -全冒险期望扫描(零加成三关连探批量——通关率/止步分布/败退节点;调参期难度读数一律走全冒险口径): +全冒险期望扫描(零加成三关连探批量——关卡完成率/止步分布/败退节点;调参期难度读数一律走全冒险口径): ``` Godot_v4.7.2-stable_win64_console.exe --headless --path . --script res://sim/adventure_monte_carlo.gd -- [N] [seed0] diff --git a/game/core/adventure_runner.gd b/game/core/adventure_runner.gd index a91d904e..b7c8f14f 100644 --- a/game/core/adventure_runner.gd +++ b/game/core/adventure_runner.gd @@ -7,9 +7,9 @@ class_name AdventureRunner extends RefCounted signal level_started(level_index: int, display_name: String) ## 每关开始(含冒险首关)——呈现层重取 runner()、刷新图条与层名行 -signal curio_choice_presented(payload: Dictionary) ## 专长三选一停点(非末关通关恰一次;通道白名单后候选恒专长+回血在载荷)——{level_index, candidates, heal_gained, hp_before, hp_after, keystone_gained, keystone_total, gp, aux_cleared} +signal curio_choice_presented(payload: Dictionary) ## 专长三选一停点(非末关的关卡完成恰一次;通道白名单后候选恒专长+回血在载荷)——{level_index, candidates, heal_gained, hp_before, hp_after, keystone_gained, keystone_total, gp, aux_cleared} signal curio_resolved(result: Dictionary) ## 三选一兑付完成(pick_curio/替换受理后恰一次)——{picked, value, hp_before, hp_after, level_index} -signal adventure_finished(summary: Dictionary) ## 冒险结算(completed/failed/abandoned)——summary 五件事:打穿没有/通关几关/止步第几关/钥石合计/主种子(+additive keystone_drops) +signal adventure_finished(summary: Dictionary) ## 冒险结算(completed/failed/abandoned)——summary 五件事:打穿没有/完成几关/止步第几关/钥石合计/主种子(+additive keystone_drops) # ---- 转发族(签名与 LevelRunner 同款——呈现层对接透明;S6 经 _forward_* 方法)---- signal node_entered(node: Dictionary, info: Dictionary) signal choices_presented(candidates: Array) @@ -266,7 +266,7 @@ func _resume_pending(bp_pending: Dictionary) -> void: var migrated: Array[Variant] = [] for c in (bp_pending.get("candidates", []) as Array): if c is Dictionary: - # T4——feat_id 随迁移(通关渠道候选=纯专长令牌,身份键 relic|tier|feat_id 三段全要) + # T4——feat_id 随迁移(关卡完成渠道候选=纯专长令牌,身份键 relic|tier|feat_id 三段全要) var mig := {"kind": String((c as Dictionary).get("kind", "")), "tier": String((c as Dictionary).get("tier", ""))} if String(mig["kind"]) == "relic": mig["feat_id"] = String((c as Dictionary).get("feat_id", "")) @@ -339,7 +339,7 @@ func continue_to_next_level() -> bool: # 停点空候选消化(池空=三选一环节整体跳过:候选 0 件时停点视同已处理, # 呈现层跳开选择面直接走后续推进。仅空候选合法;非空停点拒绝——零自动推进契约不破,正常 -# 消化仍只走 pick_curio/apply_node_curio 兑付。触发源=渠道白名单过滤后池空(关卡 Boss 通关 +# 消化仍只走 pick_curio/apply_node_curio 兑付。触发源=渠道白名单过滤后池空(关卡 Boss 击破=关卡完成 # 渠道只出专长,专长零配置/旧档 deck 无 relic 余库即空集)。) func skip_empty_curio() -> bool: if _curio_pending.is_empty(): @@ -390,7 +390,7 @@ func _feat_payload_keys(feat_id: String) -> Dictionary: # 三选一件兑付共享体(TP0——令牌消费、摘牌单点,含 relic 分支): # 属性件写加算区 + 件获取计数、AP 件写第四轴、GP 件走钱包、恢复件当即回血(封顶生效上限—— -# 与账本置满/通关回血同式 effective_max_hp)、relic 件入持有集(散件单体保底——效果接线面 +# 与账本置满/关卡完成回血同式 effective_max_hp)、relic 件入持有集(散件单体保底——效果接线面 # 按挂点消费,档位质变由 FeatsEngine 求值)。兑付即从 _curio_deck 摘除该令牌(选中踢池; # 未选候选从未摘牌=自动回池)。道具件不入此体——未知件返回 false 由调用方按渠道名报错。 func _apply_curio_pick(kind: String, tier: String, value: int, feat_id: String = "") -> bool: @@ -483,7 +483,7 @@ func _finish_curio_pick(picked: String, value: int, hp_before: int, tier: String _snapshot_breakpoint() -# ---- 奖励节点三选一(与通关三选一共享同池同权重同次数上限)---- +# ---- 奖励节点三选一(与关卡完成三选一共享同池同权重同次数上限)---- # 候选呈现(节点到达时调用——恰一 reward_pick scope 洗牌 + 道具件掷定 scope;本停点断点不载, # 续玩重建到选路停点后重走重抽,恢复的全局计数器保证同候选逐位复现)。 @@ -498,7 +498,7 @@ func present_node_curio(candidates: Array) -> void: _node_curio_pending = {"candidates": candidates.duplicate(true)} -# 点选兑付(节点域——无部分回血无钥石;令牌消费与牌库摘牌与通关三选一同库;relic 同权入持有集) +# 点选兑付(节点域——无部分回血无钥石;令牌消费与牌库摘牌与关卡完成三选一同库;relic 同权入持有集) func apply_node_curio(kind: String, tier: String = "", feat_id: String = "") -> bool: if kind == "feat_ticket": return _redeem_feat_ticket() # T5 拿到即开——节点停点候选替换为专长三选一(呈现层本地重绘) @@ -562,7 +562,7 @@ func node_curio_pending_state() -> Dictionary: } -# 三选一刷新(免费位 X/Y——组合根唯一调用口;无停点/无余量 false 零副作用)。通关停点重抽后重发 +# 三选一刷新(免费位 X/Y——组合根唯一调用口;无停点/无余量 false 零副作用)。关卡完成停点重抽后重发 # curio_choice_presented(呈现层重建卡片+刷新余量);节点停点由组合根读 node_curio_pending_state 重 present。 func refresh_curio() -> bool: return _refresh_curio_common(false) @@ -651,7 +651,7 @@ func _feat_ticket_consider(rg: RandomNumberGenerator) -> bool: func _redeem_feat_ticket() -> bool: _feat_ticket_sold += 1 _feat_ticket_pity = 0 - var cands: Array[Variant] = _draw_curio_candidates("level_clear") # 专长池(与通关渠道同白名单) + var cands: Array[Variant] = _draw_curio_candidates("level_clear") # 专长池(与关卡完成渠道同白名单) if cands.is_empty(): push_error("[冒险结构] 专长凭证兑付失败——专长池空集") _feat_ticket_sold -= 1 @@ -668,7 +668,7 @@ func _redeem_feat_ticket() -> bool: # Boss 钥石逐杀掉落(掉落渠道 = Boss/精英击杀;首杀/复杀两档读 meta.tres boss_keystone; # 首杀判据 = 存档 boss_first_kill 标记位〔断点未注入 = 恒首杀——模拟/冒烟零扰动;标记仍在收束 -# apply_adventure_summary 逐通关关次置位〕;末关 Boss 照常入账;明细随摘要 additive 键供结算面归因) +# apply_adventure_summary 逐关卡完成关次置位〕;末关 Boss 照常入账;明细随摘要 additive 键供结算面归因) func _boss_keystone_drop(li: int) -> void: var first := true if _save_manager != null: @@ -779,7 +779,7 @@ func _on_level_finished(payload: Dictionary) -> void: # Boss 钥石逐杀掉落(击杀掉落渠道,末关照常入账;首杀/复杀读 meta.tres boss_keystone) _boss_keystone_drop(level_index) if level_index < levels_total: - # 通关兑付(非末关恰一次;三层奖励框架):部分回血先行 → 加权洗牌掷 3 → 三选一停点 + # 关卡完成兑付(非末关恰一次;三层奖励框架):部分回血先行 → 加权洗牌掷 3 → 三选一停点 #(顺序即契约——回血按当刻账本与上限结算,选择停点零自动推进) var hp_before := int(ledger.get("hero_hp", 0)) var max_eff := effective_max_hp() # 回血封顶口径含调试浮窗 pct(同战斗内上限) @@ -791,7 +791,7 @@ func _on_level_finished(payload: Dictionary) -> void: _curio_paid_refreshes = 0 # 付费刷计数随停点清零(对齐商店进店清零) var pick_payload: Dictionary[Variant, Variant] = { "level_index": level_index, - "candidates": _draw_curio_candidates("level_clear"), # T4 渠道白名单——关底 Boss 击败=通关渠道只出专长 + "candidates": _draw_curio_candidates("level_clear"), # T4 渠道白名单——关底 Boss 击败=关卡完成渠道只出专长 "heal_gained": heal, "hp_before": hp_before, "hp_after": int(ledger.get("hero_hp", 0)), @@ -805,12 +805,12 @@ func _on_level_finished(payload: Dictionary) -> void: curio_choice_presented.emit(pick_payload) _snapshot_breakpoint() # 选择停点可中断(契约 5——续玩不重抽不静默丢失) return - # 末关通关:不发三选一与部分回血(没有下一战可受益)、Boss 钥石照常入账——冒险完成结算 + # 末关的关卡完成:不发三选一与部分回血(没有下一战可受益)、Boss 钥石照常入账——冒险完成结算 _settle("completed") func _settle(result: String) -> void: - # 冒险摘要五件事:打穿没有 / 通关几关 / 止步第几关 / 钥石入账合计 / 本局主种子 + # 冒险摘要五件事:打穿没有 / 完成几关 / 止步第几关 / 钥石入账合计 / 本局主种子 summary = { "result": result, "cleared": result == "completed", diff --git a/game/core/config_db.gd b/game/core/config_db.gd index ea4362e0..e6370402 100644 --- a/game/core/config_db.gd +++ b/game/core/config_db.gd @@ -254,7 +254,7 @@ func level_gen_params_row(level_index: int) -> Dictionary: return level_gen_params.row_by_level_index(level_index) if level_gen_params != null else {} -# 序列总关数(AdventureRunner levels_total / MetaProgression 通关累加域的取数口径) +# 序列总关数(AdventureRunner levels_total / MetaProgression 关卡完成累加域的取数口径) func level_count() -> int: return level.rows.size() if level != null else 0 diff --git a/game/core/config_db_cross_validator.gd b/game/core/config_db_cross_validator.gd index 4e7d8912..eab43084 100644 --- a/game/core/config_db_cross_validator.gd +++ b/game/core/config_db_cross_validator.gd @@ -40,7 +40,7 @@ func cross_validate(loaded: Dictionary, push_diag: Callable) -> void: if not treasure_live.has(treasure_eff): push_diag.call("error", "reward_dangling_treasure", "RewardTable %s aux 行引用无效道具 %s(retired/deferred/不存在): %s" % [row.get("reward_id"), treasure_eff, "双表校验"]) # ①c F2 投放维度覆盖校验不启用:挖格不掉道具,秘宝 - # 唯一来路=三选一共享池〔节点/通关〕;共享池为「抽到道具位再动态掷定具体道具」,维度覆盖不可 + # 唯一来路=三选一共享池〔节点/关卡完成〕;共享池为「抽到道具位再动态掷定具体道具」,维度覆盖不可 # 静态校验。 # ② SettlementTable.effect_pool_map 悬空 for eff in st_tab.effect_pool_map.keys(): diff --git a/game/core/level_runner.gd b/game/core/level_runner.gd index 8d88a30c..aec898ba 100644 --- a/game/core/level_runner.gd +++ b/game/core/level_runner.gd @@ -561,7 +561,7 @@ func _on_battle_finished(payload: Dictionary) -> void: hero_hp = maxi(1, int(payload.get("hero_hp", 0))) # despawn 前捕获值(载荷自包含) _gain_wallet(int(payload.get("gp_dropped", 0))) # 战斗完成入账(clamp ≥0——破财可把 escrow 打负,钱包入账时钳制) if String(node.get("type", "")) == "boss" or result == "defeat": - # Boss 胜利 = 关卡通关;任意战斗败北 = 关卡失败(漂移⑦清偿——每战结果上报冒险结构, + # Boss 胜利 = 关卡完成;任意战斗败北 = 关卡失败(漂移⑦清偿——每战结果上报冒险结构, # 失败结算归 AdventureRunner;本类只发 level_finished) level_result = "victory" if result == "victory" else "defeat" var hp_left := hero_hp if result == "victory" else 0 @@ -742,7 +742,7 @@ func _gain_wallet(amount: int) -> void: wallet_changed.emit("gain", gp, {"amount": amount}) -# 冒险收束清零(通关/倒下/放弃——局内货币生命周期终点,不入存档不入摘要;public——冒险模式由 +# 冒险收束清零(冒险成功/倒下/放弃——局内货币生命周期终点,不入存档不入摘要;public——冒险模式由 # AdventureRunner._settle 在冒险收束时调用,单关模式 = 关卡收束即冒险收束) func close_wallet() -> void: gp = 0 @@ -772,7 +772,7 @@ func _emit_wallet_event(event: String, gp_now: int, extra: Dictionary) -> void: wallet_changed.emit(event, gp_now, extra) -# 购血(商店 max_hp 商品——当前生命 +Δ 并封顶新上限,与账本置满/通关回血同式) +# 购血(商店 max_hp 商品——当前生命 +Δ 并封顶新上限,与账本置满/关卡完成回血同式) func _gain_max_hp_flat(flat: int) -> void: hero_hp = mini(hero_hp + flat, effective_max_hp()) diff --git a/game/core/meta_progression.gd b/game/core/meta_progression.gd index 46c4b6b5..25749848 100644 --- a/game/core/meta_progression.gd +++ b/game/core/meta_progression.gd @@ -271,7 +271,7 @@ func forge_shop_status() -> Array: # (keystone_drops 副本随摘要入 recent_summaries)。 # 钥石为 Boss 逐杀掉落——掉落金额已在冒险内逐杀入账(summary.keystone_total # 含全部掉落;首杀/复杀判定在 AdventureRunner._boss_keystone_drop,首杀标记在下方 -# apply_adventure_summary 逐通关关次置位)。本函数只做标记+入账+归档。 +# apply_adventure_summary 逐关卡完成关次置位)。本函数只做标记+入账+归档。 func settle_adventure(summary: Dictionary) -> Dictionary: # 首次冒险布尔位置位(关卡节点图生成 v0.4——完成/失败/放弃三结局同经本收束挂点,写入只在收束) save.mark_first_adventure_done() diff --git a/game/core/save_manager.gd b/game/core/save_manager.gd index e5475a88..ed4a56fa 100644 --- a/game/core/save_manager.gd +++ b/game/core/save_manager.gd @@ -7,7 +7,7 @@ class_name SaveManagerCore extends Node -const SAVE_FORMAT_VERSION := 7 # registry schema_version:v7=锻造工坊域(meta 新域 forge_routes〔六路线等级 levels+直购解锁清单 unlocked+当前武器/甲选中标记 weapon/armor;无特效域〕,旧档缺键由 _normalize 按默认补齐=初始持有态〔sword/light 在档余四锁、选中=初始路线〕,v6→v7 空迁移=缺键补齐模式);v6=生涯终身计数域(meta 两新域 adventure_total〔冒险总局数,开局即计含放弃与失败〕/adventure_cleared〔通关局数,三关全通才计 1——判定字段 summary.cleared〕,旧档缺键由 _normalize 按默认补零,收束自增唯一入账=apply_adventure_summary);v5=天赋树域(meta 三新域 tree_nodes〔node_id→已购等级〕/fork_sides〔fork_group→a|b〕/migration_note〔三体系迁移补偿注记〕);v4=同调位域(meta 三新域 boss_kill_count/attunement_equipped/attune_refresh_level——旧档缺键 = 合法空态);v3=断点附随件扩列+摘要 keystone_drops;v2=断点域出生;v1=首版;高版本拒读 owner=存档序列化 +const SAVE_FORMAT_VERSION := 7 # registry schema_version:v7=锻造工坊域(meta 新域 forge_routes〔六路线等级 levels+直购解锁清单 unlocked+当前武器/甲选中标记 weapon/armor;无特效域〕,旧档缺键由 _normalize 按默认补齐=初始持有态〔sword/light 在档余四锁、选中=初始路线〕,v6→v7 空迁移=缺键补齐模式);v6=生涯终身计数域(meta 两新域 adventure_total〔冒险总局数,开局即计含放弃与失败〕/adventure_cleared〔冒险成功局数,三关全通才计 1——判定字段 summary.cleared〕,旧档缺键由 _normalize 按默认补零,收束自增唯一入账=apply_adventure_summary);v5=天赋树域(meta 三新域 tree_nodes〔node_id→已购等级〕/fork_sides〔fork_group→a|b〕/migration_note〔三体系迁移补偿注记〕);v4=同调位域(meta 三新域 boss_kill_count/attunement_equipped/attune_refresh_level——旧档缺键 = 合法空态);v3=断点附随件扩列+摘要 keystone_drops;v2=断点域出生;v1=首版;高版本拒读 owner=存档序列化 const SUMMARY_CAP := 10 # 最近冒险摘要保留条数(最新在前) const TREE_STRUCT_VERSION := 2 # 树结构版本标记(12 节点 v0.8 结构;加载检测缺失 @@ -154,7 +154,7 @@ func delete_slot(slot: int) -> bool: return true -# 摘要三项按槽窥视读器(sv7/sv8,契约 5/9):钥石余额/通关局数/冒险总局数。 +# 摘要三项按槽窥视读器(sv7/sv8,契约 5/9):钥石余额/冒险成功局数/冒险总局数。 # 只读零副作用:不激活、不写盘、不触发 _corrupt_fallback 改名(.corrupt.bak 只在正式进档路径产生)。 # 返回 {"readable", "has_file", "keystone", "cleared", "total"}——readable=true=可读槽(空槽=零值合法态, # .tmp 残留按空槽——主文件不在即空);readable=false=不可读槽(损坏/高版本/缺版本字段/打开失败, @@ -285,7 +285,7 @@ func _default_data() -> Dictionary[String, Variant]: "recent_summaries": [], "first_adventure_done": false, "adventure_total": 0, # 生涯终身计数·冒险总局数(开局即计含放弃与失败,收束唯一入账) - "adventure_cleared": 0, # 生涯终身计数·通关局数(三关全通才计 1——判定字段 summary.cleared) + "adventure_cleared": 0, # 生涯终身计数·冒险成功局数(三关全通才计 1——判定字段 summary.cleared) "vision_used": 0, # 生涯终身计数·真视类工具累计使用次数(信标网络解锁行为条件; # 受理成功唯一计数点=battle 层经冒险层聚合、收束入账;缺键补零不升版本) "forge_routes": { # 锻造工坊域(六路线等级+直购解锁清单+当前选中标记;无特效域) @@ -417,7 +417,7 @@ func boss_first_kill_marked(level_index: int) -> bool: # ---- 同调位账本域(里程碑谓词表计数源 + 装配关系 + Y 升级态)---- -# Boss 击杀总数(含重复——底稿裁决 4 计数源;收束入账 = apply_adventure_summary 逐通关关次 +1, +# Boss 击杀总数(含重复——底稿裁决 4 计数源;收束入账 = apply_adventure_summary 逐关卡完成关次 +1, # Boss 恒唯一终点故 levels_cleared 即本次冒险 Boss 击杀数) func boss_kill_count() -> int: return int(_data["meta"].get("boss_kill_count", 0)) @@ -431,8 +431,8 @@ func adventure_total() -> int: return int(_data["meta"].get("adventure_total", 0)) -# 通关局数(口径=三关全通才计 1——判定字段 summary.cleared,adventure_runner「completed」 -# 唯一出口=末关通关) +# 冒险成功局数(口径=三关全通才计 1——判定字段 summary.cleared,adventure_runner「completed」 +# 唯一出口=末关的关卡完成) func adventure_cleared() -> int: return int(_data["meta"].get("adventure_cleared", 0)) @@ -558,7 +558,7 @@ func set_attune_refresh_level(n: int) -> void: _data["meta"]["attune_refresh_level"] = maxi(0, n) -# 同调位计数源组装(Attunement 服务取数口——clear_count = 逐关通关次数合计〔含重复关,底稿 §2.1 口径〕; +# 同调位计数源组装(Attunement 服务取数口——clear_count = 逐关完成次数合计〔含重复关,底稿 §2.1 口径〕; # clear_count(level_index) 逐关访问器零改动复用) func recent_summaries() -> Array: return _data["meta"]["recent_summaries"].duplicate(true) # 值拷贝出户(本类契约「禁碰内部结构」——消费方直改不得渗入存档内存态) @@ -566,10 +566,10 @@ func recent_summaries() -> Array: # 域更新原语(正式冒险收束唯一入账口——组合根经本函数入账,禁直改内部结构): # 钥石入账(summary.keystone_total——逐杀掉落已在冒险内计入,boss_drops 参数为 -# 摘要归档副本不重复入账)+ 逐通关关次 clear_count +1 与 Boss 首杀标记 + Boss 击杀总数累计 +# 摘要归档副本不重复入账)+ 逐关卡完成关次 clear_count +1 与 Boss 首杀标记 + Boss 击杀总数累计 # (同调位里程碑计数源)+ 摘要头部插入(cap 10,最新在前,元素附 # keystone_drops 副本——复盘可归因)+ 生涯终身计数自增(总局数开局即计: -# 三结局同经本口恰计一次;通关局数按 summary.cleared 判定三关全通才计 1。终身计数写入 +# 三结局同经本口恰计一次;冒险成功局数按 summary.cleared 判定三关全通才计 1。终身计数写入 # 单口=本函数,禁第二写入点)。 func apply_adventure_summary(summary: Dictionary, boss_drops: Array = []) -> void: _data["meta"]["adventure_total"] = adventure_total() + 1 diff --git a/game/data/schemas/adventure_table.gd b/game/data/schemas/adventure_table.gd index a1f635a5..ef87d79b 100644 --- a/game/data/schemas/adventure_table.gd +++ b/game/data/schemas/adventure_table.gd @@ -1,7 +1,7 @@ ## VERTICAL SLICE - NOT FOR PRODUCTION ## 冒险大奖励表(奇物三选一令牌池)schema:档位配额/件值/已拿上限的类型化读取(单行全局;垂直切片验证:三关连探一条命走完)。 ## kind/tier 词表封闭——断点附随件与牌库剔除态依赖,扩件走本表+registry 修订,禁调用侧私扩。 -## 档位配额总量是结构锚(validate 硬断言):改投放总量=重裁非调参;全部 knob provisional,上调须重扫通关率带。 +## 档位配额总量是结构锚(validate 硬断言):改投放总量=重裁非调参;全部 knob provisional,上调须重扫关卡完成率带。 class_name AdventureTable extends Resource @@ -36,7 +36,7 @@ const TIER_LEGENDARY := "legendary" ## validate() 硬断言;此后改总量=重裁非调参)。 const TIER_QUOTAS := {"common": 70, "excellent": 25, "rare": 7, "legendary": 0} -# —— 通关部分回血(固定型,非末关通关兑付)—— +# —— 关卡完成部分回血(固定型,非末关兑付)—— @export var clear_heal_pct: int = 20 # [0,100] knob——回复生效上限的百分比,封顶上限不回满 # —— 三选一候选数—— diff --git a/game/data/schemas/treasure_item_table.gd b/game/data/schemas/treasure_item_table.gd index 7dd35bd3..20acd403 100644 --- a/game/data/schemas/treasure_item_table.gd +++ b/game/data/schemas/treasure_item_table.gd @@ -9,8 +9,8 @@ extends Resource @export var rows: Array[Variant] = [] # Array[Dictionary] 键 item_id # 计数键封闭枚举(就地内联于本表,无独立谓词表; -# 通关口径=C6(通关=打通整局冒险),键名 adventure_cleared -# (生涯通关局数,save_manager 生涯计数域在役);扩 vision_used(真视类工具 +# 解锁口径=C6(冒险成功=打通整局冒险),键名 adventure_cleared +# (生涯冒险成功局数,save_manager 生涯计数域在役);扩 vision_used(真视类工具 # 累计使用——信标网络行为条件计数;use_treasure 受理成功处累计、冒险收束导出入档); # 键域以本枚举为准) const UNLOCK_COUNTER_KEYS := ["adventure_cleared", "boss_kill_count", "vision_used"] diff --git a/game/data/tables/adventure.tres b/game/data/tables/adventure.tres index 59dc7beb..17a5c641 100644 --- a/game/data/tables/adventure.tres +++ b/game/data/tables/adventure.tres @@ -48,6 +48,6 @@ feat_ticket_pity_step = 5 ; 洗牌改令牌 Fisher-Yates(不放回抽 3,消费 reward_pick 封闭流)。 ; 迭代 11 第②批 商店共享池注记:货架 = 令牌级抽签(同 kind 去重每 kind 至多一卡、价格公式 tier-blind ; ceil(基价×b^(关序−1)×A^visit) 维持批②裁定、购买消费在架令牌本体)。 -; 末关通关不发三选一与回血(奖励只朝下一战生效)。 +; 末关的关卡完成不发三选一与回血(奖励只朝下一战生效)。 ; 全部 provisional-pending-曲线调参批(值锚与上调约束归 难度曲线与Boss;档位配额结构锚 70/25/7/0—— ; schema TIER_QUOTAS,validate 硬断言,改总量须重裁)。 diff --git a/game/data/tables/enemy.tres b/game/data/tables/enemy.tres index e8c5c1de..5279f5ff 100644 --- a/game/data/tables/enemy.tres +++ b/game/data/tables/enemy.tres @@ -765,7 +765,7 @@ rows = [{ ; 敌方攻击区间批(2026-09-14 用户拍板②第二步——"上限掺运气"敌方侧:atk 上阶/下阶,中点恒等行值; ; roll 时机 = 遭遇骰同流〔encounter〕spawn 期整战持久,每拍抖动否决〔数字可读性锚〕;B2 零随机纪律保持 -; ——收 override 即确定值。宽度 ±3 provisional 归 C3 测量迭代;验收 = 完美策略档 0 加成通关 ≤40%。 +; ——收 override 即确定值。宽度 ±3 provisional 归 C3 测量迭代;验收 = 完美策略档 0 加成关卡完成 ≤40%。 ; 护甲等级掷点批(2026-09-16 用户拍板):armor_class 字段入列(缺省 0 向后兼容)——防守方掷点判定阈值基数, ; 与 armor_type(克制属性轴)两概念严格分离、不做映射。首关六行暂定 0(正式行值归怪物/敌人系统设定批—— @@ -868,7 +868,7 @@ rows = [{ ; d6 巢群/d7 小队/d9 石君王】。清单:L2 d0 45→50 · d1 18→22 · d4 20→24 · d5 68→88+atk3 · d6 18→22 · ; d7 18→22 · d9 80→112+atk3;L3 d0 50→62+atk3 · d1 25→30+atk3 · d4 20→26+atk3 · d5 76→98+atk3 · ; d6 20→26+atk3 · d7 20→26+atk3 · d9 92→140+atk3。 -; 目标对齿(熟练玩家):S0 零成长 L2 达 boss ~20%/通 ~0%、L3 ~0;S1(≈5 次 L1 通关锻造后,hero 快照 +; 目标对齿(熟练玩家):S0 零成长 L2 达 boss ~20%/通 ~0%、L3 ~0;S1(≈5 次 L1 关卡完成锻造后,hero 快照 ; 攻4/血26/甲11)L2 达 ~70%/通 ~50%;S2(攻6/血32/甲12)L3 通 ~55%。验证 = hero.tres 阶段快照 MC ; (设计文档 §6,快照后恢复基线)。验证出带微调旋钮序:L2 d1/d6/d7 血 22→20 → d4 24→22 → d9 112→108。 ; provisional 未提交。 diff --git a/game/data/tables/meta.tres b/game/data/tables/meta.tres index dda26b7d..33d05bf1 100644 --- a/game/data/tables/meta.tres +++ b/game/data/tables/meta.tres @@ -52,7 +52,7 @@ attune_refresh_upgrade = [{ ; ; 数值设计批·关卡成长×永久成长对齿(2026-09-22——设计权威 qa-data/数值设计_关卡成长×永久成长_v1.md, ; game-balancer 工作流,用户三拍板 1A/2A/3A):forge base_price 10→20(三行同,ratio 150% 不变, -; 效果档 血+3/攻+1/甲+1 不变)——S1 一档(攻+2/血+6/甲+1 ≈ 120 GP)对齐「≈5 次 L1 通关开门」节奏 +; 效果档 血+3/攻+1/甲+1 不变)——S1 一档(攻+2/血+6/甲+1 ≈ 120 GP)对齐「≈5 次 L1 关卡完成开门」节奏 ; (实测 L1 通关局收入 ≈29-35 GP)。换算率表维持全 0(墙/钥匙闭环不依赖该轴,留扩展)。 ; 配套怪表改动见 enemy.tres 同日批注。provisional 未提交。 ; diff --git a/game/data/tables/treasure_items.tres b/game/data/tables/treasure_items.tres index 057813d0..78122b08 100644 --- a/game/data/tables/treasure_items.tres +++ b/game/data/tables/treasure_items.tres @@ -8,7 +8,7 @@ script = ExtResource("1") ; 旧 12 行删除——venom_edge/seal_burst 已随迭代 20 专长批迁出删除,本批实删 12 行)。三档=普通 7/优秀 3/稀有 2 ; (传说留空=空集合法,迭代 20 追认③先例)。解锁混合制(契约 8 逐件分配锁定表,2026-10-11 用户裁 C1): ; 钥石购买件 unlock_keystone_cost(provisional 占位);条件件 unlock_requires 谓词行——计数键 -; adventure_cleared=生涯通关局数(C6 裁:通关=打通整局冒险)/boss_kill_count=生涯 Boss 击杀/vision_used= +; adventure_cleared=生涯冒险成功局数(C6 裁:打通整局冒险)/boss_kill_count=生涯 Boss 击杀/vision_used= ; 真视类工具累计使用(本批新增计数域)。全部数值 provisional 归调参批(契约 7)。 ; 常时参数面件(无订阅行——效果=开局/装板参数注入,非事件订阅):阔视野带/储备罐/远程镐/信标网络/刷新练习/ ; 刷新执照六件 effect_kinds 挂参数 kind,由注入面按装配集 kind 分发读取(_attune_refresh_x_total 先例)。 diff --git a/game/presentation/battle_narrator.gd b/game/presentation/battle_narrator.gd index d66cf267..fdb1f7cd 100644 --- a/game/presentation/battle_narrator.gd +++ b/game/presentation/battle_narrator.gd @@ -47,7 +47,7 @@ static func debug_open_line(seed_val: int, level: int, level_mode: bool) -> Stri # 调试战斗终局文案(level_end = 关内两层模式的关卡末) static func battle_end_text(result: String, level_end: bool) -> String: if level_end: - return "关卡通关!" + return "关卡完成!" if result == "victory": return "战斗胜利!敌人全灭。" return "战斗失败……探险者倒下了。" @@ -87,9 +87,9 @@ static func curio_pick_header(payload: Dictionary) -> String: var lines: Array[String] = ["第 %d 层通过!" % int(payload.get("level_index", 0))] var heal := int(payload.get("heal_gained", 0)) if heal > 0: - lines.append("通关回血 +%d(生命 %d → %d)" % [heal, int(payload.get("hp_before", 0)), int(payload.get("hp_after", 0))]) + lines.append("关卡完成回血 +%d(生命 %d → %d)" % [heal, int(payload.get("hp_before", 0)), int(payload.get("hp_after", 0))]) else: - lines.append("生命已满——通关回血 0(合法态)") + lines.append("生命已满——关卡完成回血 0(合法态)") lines.append("选择一件提升带走(另两件丢弃不可反悔):") return "\n".join(lines) @@ -151,19 +151,19 @@ static func bonus_keystone_line(payload: Dictionary) -> String: return "钥石 +%d · 累计 %d" % [int(payload.get("keystone_gained", 0)), int(payload.get("keystone_total", 0))] -# 奖励节点三选一头部行(与通关三选一共享同库;渠道白名单分流——node-reward.md v2) +# 奖励节点三选一头部行(与关卡完成三选一共享同库;渠道白名单分流——node-reward.md v2) static func node_curio_header() -> String: - return "关卡奖励点\n从冒险牌库抽三选一(属性值提升与补给;与通关专长三选一同库分流):\n选择一件带走:" + return "关卡奖励点\n从冒险牌库抽三选一(属性值提升与补给;与关卡完成专长三选一同库分流):\n选择一件带走:" -# 冒险结算屏文案(摘要五件事:打穿没有 / 通关几关 / 止步第几关 / 钥石合计 / 主种子) +# 冒险结算屏文案(摘要五件事:打穿没有 / 完成几关 / 止步第几关 / 钥石合计 / 主种子) static func adventure_summary_text(summary: Dictionary) -> String: var verdict := "冒险失败 · 未打穿" if bool(summary.get("cleared", false)): verdict = "冒险完成 · 已打穿" elif String(summary.get("result", "")) == "abandoned": verdict = "冒险放弃 · 未打穿" - return "%s\n通关 %d 关 · 止步第 %d 层 · 钥石合计 %d · 主种子 %d" % [ + return "%s\n完成 %d 关 · 止步第 %d 层 · 钥石合计 %d · 主种子 %d" % [ verdict, int(summary.get("levels_cleared", 0)), int(summary.get("stopped_at", 0)), int(summary.get("keystone_total", 0)), int(summary.get("master_seed", 0))] diff --git a/game/presentation/curio_interact_controller.gd b/game/presentation/curio_interact_controller.gd index 5fa0e55a..7a15dd3a 100644 --- a/game/presentation/curio_interact_controller.gd +++ b/game/presentation/curio_interact_controller.gd @@ -25,7 +25,7 @@ var _fatal_screen: Callable var _gp_summary: Callable # () → 战斗总结 GP 行文案(组合根 lambda——_last_gain_amount 取数面在根) var _pending_curio := {} # 三选一停点载荷暂存(战斗总结结算确认后开三选一面;续玩停点复用) -var _curio_context := "level_clear" # 三选一面上下文(level_clear=通关停点→推进下一关 / reward_node=奖励节点→回图选路) +var _curio_context := "level_clear" # 三选一面上下文(level_clear=关卡完成停点→推进下一关 / reward_node=奖励节点→回图选路) func _init(ctx: CurioFlowContext) -> void: @@ -82,7 +82,7 @@ func _skip_empty_stop() -> bool: return true -# 三选一停点(非末关通关恰一次):Boss 胜利先经战斗总结结算面(settlement-summary v1.1——钥石 +# 三选一停点(非末关的关卡完成恰一次):Boss 胜利先经战斗总结结算面(settlement-summary v1.1——钥石 # 增量行在其上),确认后进三选一面(level-clear.md v2);续玩停点恢复同入口(零自动推进契约) func on_presented(payload: Dictionary) -> void: if String(payload.get("context", "")) == "feat_ticket": @@ -111,7 +111,7 @@ func on_presented(payload: Dictionary) -> void: _refresh_presentations.call() -# 奖励节点三选一(与通关三选一共享同池同权重同上限;CurioPickOverlay 共用面)。 +# 奖励节点三选一(与关卡完成三选一共享同池同权重同上限;CurioPickOverlay 共用面)。 # 无替换子交互(同调装配不可变,见类头)。 func present_node_curio() -> void: var adventure = _adventure_get.call() @@ -177,7 +177,7 @@ func _curio_card_texts(candidates: Array) -> Array: # 新件写行即有名有姓) # 三选一刷新(X/Y 双源 + 对齐商店 MC-1——免费位用尽转 GP 付费档: -# 同 shop_refresh_cost_base/curve 旋钮、同冒险钱包 runner.gp;通关停点经重发 curio_choice_presented 直落 +# 同 shop_refresh_cost_base/curve 旋钮、同冒险钱包 runner.gp;关卡完成停点经重发 curio_choice_presented 直落 # 选择面,节点停点在此读在途态重 present——零自动推进契约不破,停点仍在途) func on_refresh() -> void: var adventure = _adventure_get.call() @@ -228,7 +228,7 @@ func on_resolved(result: Dictionary) -> void: _refresh_presentations.call() -# 继续钮:收三选一面 → 上下文分派(通关停点=推进下一关 / 奖励节点=兑付确认回图选路——零自动推进) +# 继续钮:收三选一面 → 上下文分派(关卡完成停点=推进下一关 / 奖励节点=兑付确认回图选路——零自动推进) func on_continue() -> void: _close_modal.call(curio_overlay) curio_overlay.close_pick() diff --git a/game/presentation/hud_presenter.gd b/game/presentation/hud_presenter.gd index d11cbf0c..0f6aaf79 100644 --- a/game/presentation/hud_presenter.gd +++ b/game/presentation/hud_presenter.gd @@ -188,10 +188,10 @@ static func outcome_text(outcome: Dictionary) -> String: static func tune_sim_report(n: int, atk_pct: int, hp_pct: int, wins: int, dmg_all: Array, hp_left_win: Array, hp_boss: Array, rounds_all: Array, death_nodes: Dictionary, base_hp: int) -> String: var lines: Array[String] = [] lines.append("[b]模拟 N=%d(atk+%d%% / hp+%d%%)[/b]" % [n, atk_pct, hp_pct]) - lines.append("通关率 [color=#%s]%.0f%%[/color](%d/%d)" % [UiKit.HEX_LOG_WIN, 100.0 * float(wins) / float(maxi(1, n)), wins, n]) + lines.append("关卡完成率 [color=#%s]%.0f%%[/color](%d/%d)" % [UiKit.HEX_LOG_WIN, 100.0 * float(wins) / float(maxi(1, n)), wins, n]) lines.append("整关承伤:均 %.1f · p90 %.0f(基础 HP %d)" % [_mean(dmg_all), _p90(dmg_all), base_hp]) if not hp_left_win.is_empty(): - lines.append("通关剩余 HP 均 %.1f · 进 Boss HP 均 %.1f" % [_mean(hp_left_win), _mean(hp_boss)]) + lines.append("关卡完成剩余 HP 均 %.1f · 进 Boss HP 均 %.1f" % [_mean(hp_left_win), _mean(hp_boss)]) lines.append("平均轮数 %.1f" % _mean(rounds_all)) if death_nodes.is_empty(): lines.append("败北节点:—") diff --git a/game/presentation/main_adventure_flow.gd b/game/presentation/main_adventure_flow.gd index e6aa68b9..70dffc74 100644 --- a/game/presentation/main_adventure_flow.gd +++ b/game/presentation/main_adventure_flow.gd @@ -51,7 +51,7 @@ static func _on_runner_node(root: Variant, node: Dictionary, info: Dictionary) - root._show_board_fx_for_node(t) root.log_view.append_bb(root.Narrator.node_banner(root.run_scope.runner, node, t)) elif t == "reward": - # 奖励节点三选一(与通关三选一共享同池同权重同上限;CurioPickOverlay 共用面)。 + # 奖励节点三选一(与关卡完成三选一共享同池同权重同上限;CurioPickOverlay 共用面)。 # 呈现编排归 curio_interact_controller.present_node_curio。 root._bonus.present_node_curio() root.log_view.append_bb(root.Narrator.reward_line()) diff --git a/game/presentation/tune_sim_controller.gd b/game/presentation/tune_sim_controller.gd index 051a1f53..4f681dab 100644 --- a/game/presentation/tune_sim_controller.gd +++ b/game/presentation/tune_sim_controller.gd @@ -35,7 +35,7 @@ func is_running() -> bool: func run(n: int) -> void: _running = true - # 共享日志会话(模拟运行与真人试玩同日志合规——操作/轮次/战斗/通关全量 JSONL; + # 共享日志会话(模拟运行与真人试玩同日志合规——操作/轮次/战斗/关卡完成全量 JSONL; # 一文件多局,run 行携带种子切分局次) var logger = PlaytestLogger.new() logger.ap_per_round = int(db.action_economy.ap_per_round) diff --git a/game/presentation/views/camp_overlay_view.gd b/game/presentation/views/camp_overlay_view.gd index 36d95259..f9e6903d 100644 --- a/game/presentation/views/camp_overlay_view.gd +++ b/game/presentation/views/camp_overlay_view.gd @@ -542,7 +542,7 @@ func _rebuild_recent(data: Dictionary) -> void: verdict = "完成" elif String(s.get("result", "")) == "abandoned": verdict = "放弃" - lines.append("最近冒险:%s · 通关 %d 关 · 钥石 +%d · 种子 %d" % [verdict, + lines.append("最近冒险:%s · 完成 %d 关 · 钥石 +%d · 种子 %d" % [verdict, int(s.get("levels_cleared", 0)), int(s.get("keystone_total", 0)), int(s.get("master_seed", 0))]) _recent_list.text = " | ".join(lines) diff --git a/game/presentation/views/career_overlay.gd b/game/presentation/views/career_overlay.gd index 3b169e8e..796935b5 100644 --- a/game/presentation/views/career_overlay.gd +++ b/game/presentation/views/career_overlay.gd @@ -8,8 +8,8 @@ extends Control signal closed var _total_label: Label # 冒险总局数(开局即计含放弃与失败) -var _cleared_label: Label # 通关局数(三关全通才计 1) -var _clears_label: Label # 各关通关次数(一行三关——display_name ×次数) +var _cleared_label: Label # 冒险成功局数(三关全通才计 1) +var _clears_label: Label # 各关完成次数(一行三关——display_name ×次数) var _boss_first_label: Label # Boss 首杀(已首杀关数/总关数) var _boss_kills_label: Label # Boss 总击杀(含重复) var _keystone_badge: UiKit.KeystoneBadge # 钥石余额(badge 工厂件——状态面板同形制) @@ -33,14 +33,14 @@ func _init() -> void: UiKit.FS_HINT, false, UiKit.WARM_SOFT) box.add_child(hint) - # 组一·冒险战绩(终身计数域——存档 v6:总局数开局即计、通关局数三关全通才计) + # 组一·冒险战绩(终身计数域——存档 v6:总局数开局即计、冒险成功局数三关全通才计) # 对比度口径:页底=暖亮档深棕(BG_BRIGHT),文字全用亮墨族 token(WARM 9.0:1 / WARM_SOFT 8.0:1 / # CANDLE 7.2:1 / INK_L_GOLD 9.1:1 实测对 BG_BRIGHT 全过 §7.2 ≥4.5:1——深墨族〔INK_LABEL〕 # 压深棕底仅 ~1.3:1 属违例,禁用) _section_head(box, "冒险战绩") _total_label = _row(box, "冒险总局数") - _cleared_label = _row(box, "通关局数") - _clears_label = _row(box, "各关通关次数") + _cleared_label = _row(box, "冒险成功局数") + _clears_label = _row(box, "各关完成次数") _boss_first_label = _row(box, "Boss 首杀") _boss_kills_label = _row(box, "Boss 总击杀") diff --git a/game/presentation/views/curio_pick_overlay.gd b/game/presentation/views/curio_pick_overlay.gd index 13dd1c91..46e2eb67 100644 --- a/game/presentation/views/curio_pick_overlay.gd +++ b/game/presentation/views/curio_pick_overlay.gd @@ -1,5 +1,5 @@ ## VERTICAL SLICE - NOT FOR PRODUCTION -## 提升三选一覆盖层(模态):通关停点的三卡点选→确认→兑付反馈两态呈现。 +## 提升三选一覆盖层(模态):关卡完成停点的三卡点选→确认→兑付反馈两态呈现。 ## 文案拼装归 Narrator 经组合根喂入——本类零文案装配。 class_name CurioPickOverlay extends Control diff --git a/game/presentation/views/save_select_overlay.gd b/game/presentation/views/save_select_overlay.gd index bd7ac8dd..0d308ae4 100644 --- a/game/presentation/views/save_select_overlay.gd +++ b/game/presentation/views/save_select_overlay.gd @@ -1,5 +1,5 @@ ## VERTICAL SLICE - NOT FOR PRODUCTION -## 选档界面·全屏页:3 存档位(新档/进档/删档)+ 槽摘要三项(钥石余额/通关局数/冒险总局数)。 +## 选档界面·全屏页:3 存档位(新档/进档/删档)+ 槽摘要三项(钥石余额/冒险成功局数/冒险总局数)。 ## 结构树层级:选档 → 进档 → 营地(本面零存档内功能入口——禁营地/冒险/生涯跳转与购买/查看入口); ## 删档必经二次确认(确认弹窗与分派归组合根消费方编排——本面只发意图信号)。 ## 槽数与槽态(空/有档)唯一来自组合根喂入数据(open_save_select 每开重建——组合根经卡① 窥视 API @@ -15,7 +15,7 @@ signal load_slot_requested(slot: int) signal delete_slot_requested(slot: int) var _rows_box: VBoxContainer -var _summary_labels: Dictionary[int, Label] = {} # 槽号→摘要读数 label(通关/冒险两值——探针取值缝) +var _summary_labels: Dictionary[int, Label] = {} # 槽号→摘要读数 label(冒险成功/冒险两值——探针取值缝) var _occupied_flags: Dictionary[int, bool] = {} # 槽号→有档态(操作集二分断言缝;判定源=喂入数据) var _new_btns: Dictionary[int, Button] = {} # 槽号→新档钮(空/坏槽——操作集断言与点击链驱动缝) var _load_btns: Dictionary[int, Button] = {} # 槽号→进档钮(有档槽) @@ -84,7 +84,7 @@ func _build_slot_row(sd: Dictionary) -> void: sp.size_flags_horizontal = Control.SIZE_EXPAND_FILL if occupied: row.add_child(UiKit.keystone_badge("钥石 %d" % int(sd.get("keystone", 0)))) - var summary_l := UiKit.label("通关 %d 局 · 冒险 %d 局" % [int(sd.get("cleared", 0)), int(sd.get("total", 0))], + var summary_l := UiKit.label("冒险成功 %d 局 · 冒险 %d 局" % [int(sd.get("cleared", 0)), int(sd.get("total", 0))], UiKit.FS_BODY, false, UiKit.CANDLE) _summary_labels[slot] = summary_l # 摘要读数缝(禁词断言枚举 Label 全集时含此件) row.add_child(summary_l) diff --git a/game/presentation/views/ui_kit.gd b/game/presentation/views/ui_kit.gd index 7431323b..aabf3afd 100644 --- a/game/presentation/views/ui_kit.gd +++ b/game/presentation/views/ui_kit.gd @@ -208,7 +208,7 @@ const HEX_LOG_DMG_BODY := "e0a050" # 伤害行正文橙 const HEX_LOG_VOIDED := "b08060" # 未生效行暗橙(⚠ 划线) const HEX_LOG_CAST := "b09a72" # 施放行暖石(✦ 具名技能) const HEX_LOG_DECAY := "8a9ab0" # 状态衰减蓝灰 -const HEX_LOG_WIN := "80d080" # 胜利判定绿(模拟报告通关率同档) +const HEX_LOG_WIN := "80d080" # 胜利判定绿(模拟报告关卡完成率同档) const HEX_ROUTE_NOTE := "d0c090" # 奖励点预告暗金(narrator 行) const HEX_SEED_NOTE := "c8a860" # 种子/开场行暗金(narrator 行) @@ -400,7 +400,7 @@ const FS_H1 := 34 # 主标题/演算暴击 # ── 秘宝解锁条件计数键 → 呈现标签(秘宝匣柜台条件进度文案单点;键域= # TreasureItemTable.UNLOCK_COUNTER_KEYS 封闭枚举,键出域走「条件」兜底不炸)── -const TREASURE_REQ_LABELS := {"adventure_cleared": "通关", "boss_kill_count": "Boss击杀", "vision_used": "真视使用"} +const TREASURE_REQ_LABELS := {"adventure_cleared": "冒险成功", "boss_kill_count": "Boss击杀", "vision_used": "真视使用"} # 秘宝档位 → 呈现名(契约 2 三档;legendary 传说空集合法不在柜) const TREASURE_TIER_LABELS := {"common": "普通", "excellent": "优秀", "rare": "稀有", "legendary": "传说"} diff --git a/game/probe/ui_click_probe.gd b/game/probe/ui_click_probe.gd index b57d332c..a4da50f5 100644 --- a/game/probe/ui_click_probe.gd +++ b/game/probe/ui_click_probe.gd @@ -31,7 +31,7 @@ var _tested_curio_head := false # 迭代36 卡A——三选一头部旧话清 var _tested_map_cap := false # 迭代36 卡A——地图屏加成帽换代断言(每 run 一次) var _tested_status := false # 状态面板角标开合/守卫断言(每 run 一次) var _tested_map_status := false # 地图屏角标一次性 case(选路态零扰动) -var _inter_confirms := 0 # 大奖励屏确认计数(冒险推进停点——首见确认推进 L2,再见 = L2 通关收口) +var _inter_confirms := 0 # 大奖励屏确认计数(冒险推进停点——首见确认推进 L2,再见 = L2 关卡完成收口) var _settlement_confirms := 0 # 卡⑥ 胜利结算框确认计数(观测面——每场普通战斗胜利恰一) var _route_clicks := 0 # 选路覆盖层点击计数(岔路使用率观测面) var _locktest_state := 0 # T1 D1 锁期/重放断言状态机(0=待注入 1=等重放 2=完结)——每 run 一次 @@ -368,7 +368,7 @@ func _ready() -> void: _problems.append("生涯页关闭后未恢复开始层") # 换回全新零档(营地购买态不泄入后续冒险段——确定性;档案残留下次段首清理兜底) ProbeUiUtil.isolate_save(main, "smoke_click_probe_reset", true, false, true) # 零档换注(继续上局钮已随三入口化撤出——卡② mn8) - main.debug_overlay.set_sliders(400, 200) # 高加成保 L1 可通关——L2 岔路选路段只能经冒险推进到达(单关直入口退役) + main.debug_overlay.set_sliders(400, 200) # 高加成保 L1 可完成——L2 岔路选路段只能经冒险推进到达(单关直入口退役) main.debug_overlay.seed_edit.text = "42" # 种子钉死(种子框默认为空=非首局随机,行为走查确定性禁依赖默认分支) var t1 := Time.get_ticks_msec() main._start_adventure_from_menu() @@ -399,7 +399,7 @@ func _ready() -> void: _problems.append("首格未可点(cells=0)") print("[click_probe] 首格可点计时 %dms(进入战斗屏口径,≤500ms AC)· 场景冷启动 %dms(含 UI 构建 %dms,观测项)" % [ first_cell_ms, t_total, t_ui_ready]) - const ACTION_BUDGET_FRAMES := 20000 # 主循环帧预算(坏态挂死兜底上限——常态通关远低于此;有挂帧证据才收紧,勿让坏态等满预算才报) + const ACTION_BUDGET_FRAMES := 20000 # 主循环帧预算(坏态挂死兜底上限——常态跑完远低于此;有挂帧证据才收紧,勿让坏态等满预算才报) var action_budget := ACTION_BUDGET_FRAMES # P0-2 回归:本 while 循环体缩进必须整体在循环内——continue 落在 # 循环外成解析错误、探针不可加载。bonus 分支保留为体内兄弟分支。 @@ -411,7 +411,7 @@ func _ready() -> void: _seals_placed.clear() continue if main.curio_overlay.visible: - # 三选一停点(CurioPickOverlay——奖励节点/通关兑付共用面,须与硬锁态适配, + # 三选一停点(CurioPickOverlay——奖励节点/关卡完成兑付共用面,须与硬锁态适配, # 未适配则走到即卡死)。两态分派:result 态(兑付反馈——点继续推进)/ # 待选态(点首件+确认)。真实信号路径全线。〔无替换子态——装配不可变契约。〕 # 三选一停点输入锁定断言(停点态断言面:待选/兑付两态共用此层)。 @@ -475,7 +475,7 @@ func _ready() -> void: _seals_placed.clear() continue if main._inter_overlay.visible: - # 大奖励屏(冒险级停点——非末关通关恰一次):首见确认推进 L2(真实按钮信号路径);再见 = L2 已通关,收口 + # 大奖励屏(冒险级停点——非末关的关卡完成恰一次):首见确认推进 L2(真实按钮信号路径);再见 = L2 已关卡完成,收口 if not main._input_locked(): _problems.append("大奖励屏打开时输入未锁定") _inter_confirms += 1 @@ -491,7 +491,7 @@ func _ready() -> void: _problems.append("大奖励确认后未推进到第二关(level_index != 2)") else: _done = true - print("[click_probe] 第二关大奖励屏(L2 通关)——探针收口 · 选路口点击 %d 次" % _route_clicks) + print("[click_probe] 第二关大奖励屏(L2 关卡完成)——探针收口 · 选路口点击 %d 次" % _route_clicks) break _seals_placed.clear() continue @@ -639,7 +639,7 @@ func _ready() -> void: # 驱动设计(0/0 白板局生存性不成立的实证处置——L2 记录进实现报告): # ① 菜单开新局·白板反向=独立短局:0/0 滑条开局断言 L1 开场行零后缀(不开驱动—— # 断言完成后该局被 ② 的开局自然替换,白板局生存性不参与判定); - # ② 局内加算区正向=生存局:400/200 滑条开局保可通关(:363 先例),三选一专选 atk/max_hp + # ② 局内加算区正向=生存局:400/200 滑条开局保可完成(:363 先例),三选一专选 atk/max_hp # 卡(无则任选推进——不触后缀、循环重试);至大奖励屏先 reset_sliders() 再确认进下一层 # ——L2 开场行时点 pct=0 且新档 ov=0,后缀只能归因局内加算区(变异:回退条件 hunk→红); # ③ 断点续玩正向:L2 入口选路停点(bonus 已入账、bonus_pending/bonus_result 皆空——选路停点形) diff --git a/game/probe/ui_struct_probe.gd b/game/probe/ui_struct_probe.gd index 2c7bc0f3..9c687982 100644 --- a/game/probe/ui_struct_probe.gd +++ b/game/probe/ui_struct_probe.gd @@ -431,10 +431,10 @@ func _save_select_contract(main: Node, tpl: String) -> void: else: if not (has_new and not has_load and not has_del): problems.append("[savesel] 行%d 操作集失守(空/坏槽应=仅新档、零进档删档含置灰形态)〔sl4〕" % row_idx) - # sl2 摘要三项逐槽读数:槽1 喂入值逐字(钥石 555/通关 2 局/冒险 7 局) + # sl2 摘要三项逐槽读数:槽1 喂入值逐字(钥石 555/冒险成功 2 局/冒险 7 局) var sum1: Label = sso._summary_labels.get(1) - if sum1 == null or sum1.text != "通关 2 局 · 冒险 7 局": - problems.append("[savesel] 槽1 摘要读数失守(got=%s 应=通关 2 局 · 冒险 7 局)〔sl2〕" % (sum1.text if sum1 else "null")) + if sum1 == null or sum1.text != "冒险成功 2 局 · 冒险 7 局": + problems.append("[savesel] 槽1 摘要读数失守(got=%s 应=冒险成功 2 局 · 冒险 7 局)〔sl2〕" % (sum1.text if sum1 else "null")) var all_texts: Array[String] = [] _collect_labels(sso, all_texts) var has_keystone := false @@ -443,7 +443,7 @@ func _save_select_contract(main: Node, tpl: String) -> void: has_keystone = true if not has_keystone: problems.append("[savesel] 槽1 钥石徽读数缺失(应=钥石 555)〔sl2〕") - # sl3 摘要禁项:断点/种子/「继续」/停点/「 关」(关数形——「通关」无空格不误伤)零命中 + # sl3 摘要禁项:断点/种子/「继续」/停点/「 关」(关数形——摘要「冒险成功 X 局 · 冒险 Y 局」不含「关」字)零命中 #(裁决 4——零未完冒险读数;词形覆盖=对照表 sl3 缺陷形态「断点关数拼进槽卡」的拦截面) for needle in ["断点", "种子", "继续", "停点", " 关"]: for t in all_texts: diff --git a/game/probe/ui_tune_probe.gd b/game/probe/ui_tune_probe.gd index 481cddc7..c02479d9 100644 --- a/game/probe/ui_tune_probe.gd +++ b/game/probe/ui_tune_probe.gd @@ -72,8 +72,11 @@ func _ready() -> void: if main.debug_overlay.is_running(): problems.append("模拟未在预算帧内完成(疑似挂死)") var out: String = main.debug_overlay.output_text() - if not out.contains("通关率"): - problems.append("模拟输出缺通关率") + if not out.contains("关卡完成率"): + problems.append("模拟输出缺关卡完成率") + # 口径换代 V7:胜局统计行措辞钉子(atk+100% 加成档 10 局必有胜局——hp_left_win 非空路径恒出) + if not out.contains("关卡完成剩余 HP 均"): + problems.append("模拟输出缺关卡完成剩余 HP 行〔口径换代 V7〕") if not out.contains("败北节点"): problems.append("模拟输出缺败北节点") if "N=10" not in out: diff --git a/game/sim/adventure_monte_carlo.gd b/game/sim/adventure_monte_carlo.gd index 5c02fb9d..718a2e9c 100644 --- a/game/sim/adventure_monte_carlo.gd +++ b/game/sim/adventure_monte_carlo.gd @@ -6,7 +6,7 @@ # 刷新/行进序列/逐战上限序列——后续统计分析的取数面); # ② 全量操作日志 = playtest_logger 共享会话 JSONL(与真人试玩同合规口径,每策略一批一文件, # run 行携带种子/策略切分局次,落 user://logs/)。 -# 本工具只采集与落盘数据,不做统计判读(通关率/败因分布归分析会话)。 +# 本工具只采集与落盘数据,不做统计判读(关卡完成率/败因分布归分析会话)。 # 运行:Godot_console.exe --headless --path . --script res://sim/adventure_monte_carlo.gd -- [N] [seed0] [normal|perfect|both] [route min|max] extends SceneTree diff --git a/game/sim/auto_player.gd b/game/sim/auto_player.gd index 37f092a0..a2d3b5b6 100644 --- a/game/sim/auto_player.gd +++ b/game/sim/auto_player.gd @@ -33,7 +33,7 @@ static func choose_dig(minesweeper) -> Dictionary: # 进阶级 = 联动定式(1-1 / 1-2 / 1-2-1 / 1-2-2-1 / 子集缩减)与概率分析——本切片归完美档 subset 推理承载, # 不入普通画像(新手不可靠掌握)。本档语义 = 只做新手级推理 + 无处可推时按既有口径盲挖边界格(新手冲动)+ # 不主动刷新(新手无刷新策略意识)。测量定位:教会基础规则后的真实玩家下限近似 -# (乱点/最近格口径测的是无认知玩家下限,对通关率带判读失真,不作普通画像)。 +# (乱点/最近格口径测的是无认知玩家下限,对关卡完成率带判读失真,不作普通画像)。 # 普通画像单步决策入口(每动作一查——挖掘揭示新数字后重推理):move/dig/seal/stop 四值(无 refresh)。 static func novice_action(minesweeper) -> Dictionary: diff --git a/game/sim/level_autoplay.gd b/game/sim/level_autoplay.gd index a719f0d1..ff3e8cf6 100644 --- a/game/sim/level_autoplay.gd +++ b/game/sim/level_autoplay.gd @@ -1,16 +1,16 @@ # VERTICAL SLICE - NOT FOR PRODUCTION -# 日志合规:任何模拟运行与真人试玩同日志——操作记录 / 轮次状态 / 战斗结束 / 通关结束 全量 JSONL。 +# 日志合规:任何模拟运行与真人试玩同日志——操作记录 / 轮次状态 / 战斗结束 / 关卡完成 全量 JSONL。 # logger=null 时自建会话(每局一文件),批量调用方传共享 logger(log_run 局次标记切分)。 -# 关卡自动通关策略(理性玩家近似)——呈现层数值调整板的批量模拟与 headless 扫描 +# 关卡自动完成策略(理性玩家近似)——呈现层数值调整板的批量模拟与 headless 扫描 # 共用同一实现,保证"面板模拟读数"与"扫描表读数"同口径。策略与 smoke_all 战斗自动玩家同族: # 挖最近可挖格 / 无可挖停手 / 奖励恢复点立即确认。 # run_level = 机制夹具/单战锚点专用(smoke_all 机制断言、rhythm/defense/damage 单战扫描)—— -# 通关率/难度类测量禁用本入口(满血零上下文进关,与真实冒险条件通关率脱节),一律走 run_adventure。 +# 关卡完成率/难度类测量禁用本入口(满血零上下文进关,与真实冒险条件关卡完成率脱节),一律走 run_adventure。 # 策略档 policy:"normal"(默认)/ "perfect"(零盲挖/全封印/卡死刷新——上界测量仪,求解器与 # 动作语义见 auto_player.gd 完美策略档节)。 # 选路驱动(零自动推进):兑付确认/战斗胜利后 runner 进选路态,驱动循环按 route 策略显式 # pick_next_node;route = "min"/"max"(候选节点句柄最小/最大——确定性路径轴,零随机流自开;默认 "min")。 -# run_adventure 三关连探驱动(AdventureRunner——主种子恰一次、通关兑付停点确认、adventure_finished +# run_adventure 三关连探驱动(AdventureRunner——主种子恰一次、关卡完成兑付停点确认、adventure_finished # 置 result/summary;外层每关重取 runner 实例经 _drive_level 复用单关驱动)。 # 大奖励停点 = 三选一驱动(候选取首件/替换放弃新件)。 # 普通档 v3 = 完美策略 + 受控失误注入(失误流走独立策略 RNG——种子派生自局种子,逐局确定性/ @@ -303,7 +303,7 @@ static func _pick_token(candidates: Array, feat_mode: String = "off") -> Diction return best -# 三选一兑付完成 → 上下文分派(通关停点=推进下一关 / 奖励节点=回图选路) +# 三选一兑付完成 → 上下文分派(关卡完成停点=推进下一关 / 奖励节点=回图选路) static func _on_adventure_curio_resolved(result: Dictionary, st: Dictionary, adr) -> void: st.reward_events.append({"curio_resolved": result.duplicate(true)}) if String(result.get("context", "")) == "reward_node": diff --git a/game/sim/verifier_batch.gd b/game/sim/verifier_batch.gd index 0fb1cf35..39165bd3 100644 --- a/game/sim/verifier_batch.gd +++ b/game/sim/verifier_batch.gd @@ -2,16 +2,16 @@ # 判定端 tools/balance_verifier.py 的数据源,本文件零判定逻辑 # 两段一次采集,stdout 以「VJSON 」前缀行出机器读 JSON(其余行为人读进度/摘要): # adventure 段 全冒险连探基线(run_adventure 零永久强化)× 双画像 × na——止步分布、败退节点 -# (摘要 defeat 明细 + 末场战斗敌方名)与逐关条件通关率派生源;inject 档行带 +# (摘要 defeat 明细 + 末场战斗敌方名)与逐关条件关卡完成率派生源;inject 档行带 # inject_tag/override(flat 三键) # campaign 段 营地循环战役 × 双画像 × k 局——SaveManager 隔离档 + MetaProgression 真实账本: # 逐局 hero_override() 注入 → 冒险 → settle_adventure 入账 → 花费策略买锻造, -# 回答「累计几次通关冒险后下一关可过」(元进度换算率标定的模拟读数源) +# 回答「累计几次冒险成功后下一关可过」(元进度换算率标定的模拟读数源) # 运行:Godot_console.exe --headless --path . --script res://sim/verifier_batch.gd -- [k=v ...] # na=40(基线冒险局数) k=40(战役局数) seed0=8000 # only=adventure,campaign(缺省全段) spend=hp_first|atk_first|armor_first(锻造花费优先序) # inject=max_hp:3,atk:1(冒险段 flat 注入档——三键 {max_hp, atk, armor_class},缺省全零白板; -# 换算率标定用:每档与白板同种子流配对,逐关条件通关率差 = 该档的带平移量实测) +# 换算率标定用:每档与白板同种子流配对,逐关条件关卡完成率差 = 该档的带平移量实测) # 种子纪律:unique 逐局独立(掷点测量修复批 A 案——seed0 + 全局游标,每掷点恰消费一次)。 # 同 seed0 跨档复用 = 配对读数(同序种子流——分析侧按种子配对消方差)。 # 日志合规:全段共享 playtest_logger 会话(与真人试玩同日志),分析工具可直接消费。 @@ -108,7 +108,7 @@ func _emit(row: Dictionary) -> void: print("VJSON " + JSON.stringify(row)) -# ---- adventure 段:全冒险连探基线(零永久强化——止步分布/败退节点归因/逐关条件通关率派生源); +# ---- adventure 段:全冒险连探基线(零永久强化——止步分布/败退节点归因/逐关条件关卡完成率派生源); # inject 档 = 同种子流配对的 OFAT 边际读数(行带 inject_tag/override flat 三键) ---- func _seg_adventure(db, autoplay, logger, opt: Dictionary, counts: Dictionary) -> void: diff --git a/game/tests/README.md b/game/tests/README.md index 10c6e4b7..11d14a72 100644 --- a/game/tests/README.md +++ b/game/tests/README.md @@ -150,7 +150,7 @@ timeout 120s godot --headless --script tests/run_all.gd `tests/static_scan.sh` 头注**——迭代 32 两卡是代码实现批,按流水线红线禁写 `design/`,故这两段未进架构文档。 新违规案例必须**先补扫描规则再修码**。 -S11 代码注释禁用词:扫描 game/ 全域 .gd/.tres/.md/.json/.sh 的注释面;禁词全部由 `design/gdd/术语表.md`「退役词对照」第一列解析供给(脚本内不内联任何词面——单一事实源);解析结果再按「巢穴」「旗」「flag_*」三条整行排除,另设同形异义豁免「去重闸」(封印重判去重的机制判别器,与某闸档退役词后二字同形——行内含「去重闸」整行跳过);三层豁免(闸门自指/显式留档 4 处/非注释面天然不取);两道自检(扫描面文件数非空+词表解析非空)。 +S11 代码注释禁用词:扫描 game/ 全域 .gd/.tres/.md/.json/.sh 的注释面;禁词全部由 `design/gdd/术语表.md`「退役词对照」第一列解析供给(脚本内不内联任何词面——单一事实源);解析结果再按「巢穴」「旗」「flag_*」三条整行排除,另设同形异义豁免「去重闸」(封印重判去重的机制判别器,与某闸档退役词后二字同形——行内含「去重闸」整行跳过);三层豁免(闸门自指/显式留档 20 处〔契约原名引述与带日期历史读数注释,清单见 `tests/static_scan.sh` 头注〕/非注释面天然不取);两道自检(扫描面文件数非空+词表解析非空)。 S12 效果引擎无状态化旧件零残留:扫描 game/ 全域 `.gd` 与 `game/data/tables/*.tres`,禁已删符号(`counters_export`/`counters_seed`/`_reset_tree_limited_counters` 等)与带引号的旧计数器 id 字面(引号锚定,不误伤 `adv_`/`round_` 前缀新名);扫描面文件数为零即判红。 diff --git a/game/tests/integration/cross_system_flow_test.gd b/game/tests/integration/cross_system_flow_test.gd index 8d3a68a5..57e536d5 100644 --- a/game/tests/integration/cross_system_flow_test.gd +++ b/game/tests/integration/cross_system_flow_test.gd @@ -116,14 +116,14 @@ func _save_summary_integration() -> void: var ks_run := 0 for li in range(1, int(_db.level.rows.size()) + 1): ks_run += int(_db.meta_boss_keystone_row(li).get("first_kill", 0)) - Kit.check("摘要集成:冒险驱动满配通关(seed 42)", String(st9.get("result", "")) == "completed") + Kit.check("摘要集成:冒险驱动满配冒险成功(seed 42)", String(st9.get("result", "")) == "completed") Kit.check("集成钥石余额 = ΣBoss 首杀行值(%d——逐杀掉落全源)" % f9.keystone_balance(), f9.keystone_balance() == ks_run) - Kit.check("集成通关次数表全 1", f9.clear_count(1) == 1 and f9.clear_count(2) == 1 and f9.clear_count(3) == 1) + Kit.check("集成关卡完成次数表全 1", f9.clear_count(1) == 1 and f9.clear_count(2) == 1 and f9.clear_count(3) == 1) Kit.check("集成三关首杀标记齐", f9.boss_first_kill_marked(1) and f9.boss_first_kill_marked(2) and f9.boss_first_kill_marked(3)) Kit.check("集成 recent 1 条且 seed 42", f9.recent_summaries().size() == 1 and int(f9.recent_summaries()[0].get("master_seed", -1)) == 42) var st9b: Dictionary = LevelAutoplay.run_adventure(_db, 42, 900, 400) f9.apply_adventure_summary(st9b.get("summary", {})) - Kit.check("第二局后通关次数全 2", f9.clear_count(1) == 2 and f9.clear_count(2) == 2 and f9.clear_count(3) == 2) + Kit.check("第二局后关卡完成次数全 2", f9.clear_count(1) == 2 and f9.clear_count(2) == 2 and f9.clear_count(3) == 2) Kit.check("第二局后余额翻倍(2 × Σ首杀——模拟驱动恒首杀口径)", f9.keystone_balance() == 2 * ks_run) Kit.check("集成 recent 长度 2", f9.recent_summaries().size() == 2) Kit.check("集成写盘成功", f9.write_to_disk()) diff --git a/game/tests/static_scan.sh b/game/tests/static_scan.sh index 609c6ab7..76c5ce99 100644 --- a/game/tests/static_scan.sh +++ b/game/tests/static_scan.sh @@ -127,9 +127,13 @@ fi # 在册断言标签成片误红;代价=该行同时出现的真闸档用词也不报,靠文档域 08 闸兜住) # 扫描面:game/ 全域 .gd/.tres/.md/.json/.sh(.txt 不收=第三方许可证非本仓库文本) # 注释文本提取:.gd/.sh 取 # 后文本;.tres 取 ; 后文本;.md 取整行;.json 无注释语法(保留扩展名但不产生注释段) -# 三层豁免依序:①闸门自指(行内含检查/禁令形态即跳过)②显式留档豁免单 7 处 ③非注释面天然不取 +# 三层豁免依序:①闸门自指(行内含检查/禁令形态即跳过)②显式留档豁免单 20 处 ③非注释面天然不取 # 豁免单新增三处(2026-10-26 令牌配额口径清扫批 B4b 用户裁定保留):adventure_table.gd:26 档名映射对照注 # +adventure_table.gd:93 与 curio_deck.gd:130 四口径契约④原名引述——合法载体非残留,改写即断链 +# 豁免单再增 13 处(2026-10-26 口径换代批用户裁「带日期历史读数注释保留原文」): +# hero.tres:21/:36、enemy.tres:751/:891、action_economy.tres:15/:16/:26/:27、status_effects.tres:91、 +# meta.tres:48/:56/:62(.tres 十二处历史读数/带日期批记录)+level_autoplay.gd:560(完美档 41% 历史实证)—— +# 历史读数原文锚定当时实测口径,改写即失真;现行口径描述不豁免(已随批换代) if [ -d game/core ]; then S11_TABLE="design/gdd/术语表.md" @@ -184,6 +188,7 @@ else if(FILENAME~"adventure_table"&&FNR==26)next if(FILENAME~"adventure_table"&&FNR==93)next if(FILENAME~"curio_deck"&&FNR==130)next + if(FILENAME~"level_autoplay"&&FNR==560)next print FILENAME":"FNR":"words[i] next } @@ -201,6 +206,18 @@ else if($0~/contains\(|find\(|grep|has_char\(|禁「|禁『|零「|零『/)next if(index(cmt,"去重闸")>0)next if(FILENAME~"enemy.tres"&&FNR==653)next + if(FILENAME~"hero.tres"&&FNR==21)next + if(FILENAME~"hero.tres"&&FNR==36)next + if(FILENAME~"enemy.tres"&&FNR==751)next + if(FILENAME~"enemy.tres"&&FNR==891)next + if(FILENAME~"action_economy.tres"&&FNR==15)next + if(FILENAME~"action_economy.tres"&&FNR==16)next + if(FILENAME~"action_economy.tres"&&FNR==26)next + if(FILENAME~"action_economy.tres"&&FNR==27)next + if(FILENAME~"status_effects.tres"&&FNR==91)next + if(FILENAME~"meta.tres"&&FNR==48)next + if(FILENAME~"meta.tres"&&FNR==56)next + if(FILENAME~"meta.tres"&&FNR==62)next print FILENAME":"FNR":"words[i] next } diff --git a/game/tests/unit/core/adventure_feats_test.gd b/game/tests/unit/core/adventure_feats_test.gd index fedf9f3f..05013fdf 100644 --- a/game/tests/unit/core/adventure_feats_test.gd +++ b/game/tests/unit/core/adventure_feats_test.gd @@ -99,11 +99,11 @@ func _api_mark_node(_node: Dictionary, _info: Dictionary, seq: Array) -> void: seq.append("node_entered") -# ③ 冒险验收断言(映射 冒险结构.md 验收标准——表覆盖/满配通关/种子复现/大奖励/败北线/ +# ③ 冒险验收断言(映射 冒险结构.md 验收标准——表覆盖/满配冒险成功/种子复现/大奖励/败北线/ # 重复拒绝/GP 跨关延续/加算区同账/恢复数学/放弃) -# ③ 冒险验收断言(映射 冒险结构.md 验收标准——表覆盖/满配通关/种子复现/大奖励/败北线/ +# ③ 冒险验收断言(映射 冒险结构.md 验收标准——表覆盖/满配冒险成功/种子复现/大奖励/败北线/ # 重复拒绝/GP 跨关延续/加算区同账/恢复数学/放弃) func _smoke_adventure() -> void: print("--- 冒险结构验收(三关序列 · 大奖励 · 摘要五件事 · 账本封闭)---") @@ -129,11 +129,11 @@ func _smoke_adventure() -> void: cov_miss += 1 Kit.check("生成图每个战斗/Boss 节点经解析链命中敌行集与棋盘行(扫描 %d 节点,缺失 %d)〔fv24〕" % [cov_scan, cov_miss], cov_scan > 0 and cov_miss == 0) - # ② 满配通关 + ④ 三层奖励兑付(三选一恰 2 次 · 回血封顶 · 钥石逐杀 · 候选零重复) + # ② 满配冒险成功 + ④ 三层奖励兑付(三选一恰 2 次 · 回血封顶 · 钥石逐杀 · 候选零重复) var st: Dictionary = autoplay.run_adventure(_db, 42, 900, 400) var sum: Dictionary = st["summary"] - Kit.check("满配通关(42 / atk+900 / hp+400——cleared=true;v2 怪阶梯后旧 200/100 档不再满配)", String(st["result"]) == "completed" and bool(sum.get("cleared", false))) - Kit.check("通关几关 = 3(levels_cleared)", int(sum.get("levels_cleared", -1)) == 3) + Kit.check("满配冒险成功(42 / atk+900 / hp+400——cleared=true;v2 怪阶梯后旧 200/100 档不再满配)", String(st["result"]) == "completed" and bool(sum.get("cleared", false))) + Kit.check("完成几关 = 3(levels_cleared)", int(sum.get("levels_cleared", -1)) == 3) var ks_exp := 0 for li in range(1, int(_db.level.rows.size()) + 1): ks_exp += int(_db.meta_boss_keystone_row(li).get("first_kill", 0)) @@ -151,7 +151,7 @@ func _smoke_adventure() -> void: node_picks += 1 # 奖励节点三选一(每关奖励节点各 1 次) elif (ev as Dictionary).has("curio_resolved"): resolves.append((ev as Dictionary)["curio_resolved"]) - Kit.check("通关三选一恰呈现 2 次、恰兑付 2 次(L1/L2 后——末关不发;resolves 含节点回执另计)", picks.size() == 2 and resolves.size() == 2 + node_picks) + Kit.check("关卡完成三选一恰呈现 2 次、恰兑付 2 次(L1/L2 后——末关不发;resolves 含节点回执另计)", picks.size() == 2 and resolves.size() == 2 + node_picks) # 奖励节点在生成图里是可选路位(旧单链模板的「L1 必经 1 个」形状前提随模板消亡)—— # 接线证明拆两半:图侧每关含 ≥1 奖励节点,行进侧种子扫描内确有经停(扫描零经停=三选一接线不可达) var reward_levels := 0 @@ -242,7 +242,7 @@ func _smoke_adventure() -> void: if rk == "max_hp": hp_acc += int(r.get("value", max_flat)) Kit.check("三选一候选 2–3 枚且零重复(令牌洗牌不放回——kind+tier 复合身份)", cand_ok) - Kit.check("通关部分回血封顶(floor(观测上限×比例) 封顶——购血观测值精确断言,核代码增补)", heal_ok) + Kit.check("关卡完成部分回血封顶(floor(观测上限×比例) 封顶——购血观测值精确断言,核代码增补)", heal_ok) Kit.check("钥石逐杀入账(首杀档位 + 累计逐位)", ks_gain_ok) Kit.check("点选恰兑付选中一件(值=令牌档位表值;未选项零生效)", resolve_ok) var seq: Array = st["encounter_max_hp_seq"] @@ -271,7 +271,7 @@ func _smoke_adventure() -> void: Kit.check("零配 L1 败北种子可达(seed=%s)" % str(lose.get("s", -1)), not lose.is_empty()) if not lose.is_empty(): var sl: Dictionary = lose["st"]["summary"] - Kit.check("L1 败北摘要:未打穿 · 通关 0 关 · 钥石 0 · 止步第 1 层", + Kit.check("L1 败北摘要:未打穿 · 完成 0 关 · 钥石 0 · 止步第 1 层", not bool(sl["cleared"]) and int(sl["levels_cleared"]) == 0 \ and int(sl["keystone_total"]) == 0 and int(sl["stopped_at"]) == 1) var dl: Dictionary = sl.get("defeat", {}) @@ -351,8 +351,8 @@ func _smoke_adventure() -> void: var acc_shop := int(a8.run_ledger.bonus.get("max_hp", -1)) # L1 三选一后 + 商店 3(首件随种子) Kit.check("统一冒险加算区含商店值(max_hp=%d ≥ 商店 3——L1 三选一件值另计)" % acc_shop, acc_shop >= 3) a8._on_level_finished({"result": "victory", "hp": int(r8.hero_hp), "node_index": r8.node_index, - "node_id": r8.current_node_id(), "node_type": "shop"}) # 模拟 L2 通关(victory 载荷直调——非末关) - Kit.check("L2 通关三选一停点在案(直调兑付前——零自动推进)", not a8._curio_pending.is_empty()) + "node_id": r8.current_node_id(), "node_type": "shop"}) # 模拟 L2 关卡完成(victory 载荷直调——非末关) + Kit.check("L2 关卡完成三选一停点在案(直调兑付前——零自动推进)", not a8._curio_pending.is_empty()) Kit.check("未兑付推进拒绝(选择停点零自动推进契约)", not a8.continue_to_next_level()) var l2_cands: Array = a8._curio_pending["candidates"] var l2_pick: Dictionary = l2_cands[0] @@ -361,7 +361,7 @@ func _smoke_adventure() -> void: var expect_acc: int = acc_shop + (int(a8._curio_result.get("value", 0)) if picked2 == "max_hp" else 0) Kit.check("三选一属性件与商店购买同账累加(max_hp=%d = %d + 三选一%s)" % [int(a8.run_ledger.bonus.get("max_hp", -1)), acc_shop, picked2], int(a8.run_ledger.bonus.get("max_hp", -1)) == expect_acc) var max_eff8: int = a8.effective_max_hp() # 账本生效上限含调试浮窗 pct(a8 已 set 400) - Kit.check("通关部分回血封顶(hp %d ≤ 生效上限 %d——血回满语义退役)" % [int(a8.ledger["hero_hp"]), max_eff8], int(a8.ledger["hero_hp"]) <= max_eff8) + Kit.check("关卡完成部分回血封顶(hp %d ≤ 生效上限 %d——血回满语义退役)" % [int(a8.ledger["hero_hp"]), max_eff8], int(a8.ledger["hero_hp"]) <= max_eff8) Kit.check("兑付后推进受理(下一关开始)", a8.continue_to_next_level()) # ⑨ 恢复点数学(接口③封顶公式三读数 + 同式两落点一致) var a9 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(99)) @@ -406,7 +406,7 @@ func _smoke_adventure() -> void: treasure_seen = true break Kit.check("池收缩——40 次重抽零 aux 候选(停点渠道 aux 卡退役,迭代 11 第①批 T7)", not treasure_seen) - # 满血回 0 合法(通关回血封顶口径) + # 满血回 0 合法(关卡完成回血封顶口径) var a12 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(12)) a12.start_adventure(12) var cap := {"payload": {}} @@ -414,7 +414,7 @@ func _smoke_adventure() -> void: var max_full := int(_db.hero.max_hp) + int(a12._base_override.get("max_hp", 0)) a12.ledger["hero_hp"] = max_full a12._on_level_finished({"result": "victory", "hp": max_full, "node_index": 1, "node_id": 1, "node_type": "shop"}) - Kit.check("满血通关回血 0 合法(封顶口径——heal_gained=0 非负溢出)", int(cap["payload"].get("heal_gained", -1)) == 0) + Kit.check("满血关卡完成回血 0 合法(封顶口径——heal_gained=0 非负溢出)", int(cap["payload"].get("heal_gained", -1)) == 0) # ⑬ 奖励节点共享池(同库同池同摘牌;TP0:attack 令牌耗尽后节点域同样零出现) var a13 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(13)) Kit.check("节点共享池场景:冒险启动(seed 13)", a13.start_adventure(13, {"treasure_unlocked": {"wide_scout_band": true}})) @@ -509,7 +509,7 @@ func _smoke_feats() -> void: if String((t as Dictionary).get("kind", "")) == "relic": deck_relic += 1 Kit.check("专长带入池:5 行 relic 每件 1 张(四级 rarity 直映射)——牌库 102+5=107", deck_relic == 5 and a_r._curio_deck.size() == 107) - # 渠道白名单断言(渠道轴定位:通关渠道只出专长/节点渠道零专长) + # 渠道白名单断言(渠道轴定位:关卡完成渠道只出专长/节点渠道零专长) var feat_seen: Dictionary = {} var node_relic_seen := false for i in 60: @@ -519,7 +519,7 @@ func _smoke_feats() -> void: for t in a_r._draw_curio_candidates("reward_node"): if String((t as Dictionary).get("kind", "")) == "relic": node_relic_seen = true - Kit.check("通关渠道只出专长(60 次重抽 ≥2 种不同 relic——身份键 feat_id 同档可多件)", feat_seen.size() >= 2) + Kit.check("关卡完成渠道只出专长(60 次重抽 ≥2 种不同 relic——身份键 feat_id 同档可多件)", feat_seen.size() >= 2) Kit.check("节点渠道零专长(60 次重抽零 relic——专长在非 Boss 渠道只以专长凭证形态出现)", not node_relic_seen) # T5 专长凭证行为断言(A5 拿到即开 / A6 保底计数——契约④四口径;独立 runner 防污染 a_r 牌库) var a_t = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(91)) diff --git a/game/tests/unit/core/breakpoint_resume_test.gd b/game/tests/unit/core/breakpoint_resume_test.gd index 8ce75e20..e3a180aa 100644 --- a/game/tests/unit/core/breakpoint_resume_test.gd +++ b/game/tests/unit/core/breakpoint_resume_test.gd @@ -96,7 +96,7 @@ func _init() -> void: adr_e._curio_taken["attack"] = 1 # 白盒预置计数(断点附随件往返的判据面——计数不可由加算区反推) adr_e._on_level_finished({"result": "victory", "hp": 30, "node_index": 1, "node_id": 1, "node_type": "shop"}) var cands_e: Array = (adr_e._curio_pending.get("candidates", []) as Array).duplicate() - Kit.check_quiet(not cands_e.is_empty(), "P5 非末关通关三选一停点在案(直调 victory——L1 非末关)") + Kit.check_quiet(not cands_e.is_empty(), "P5 非末关的关卡完成三选一停点在案(直调 victory——L1 非末关)") var sm_f = SaveManagerScript.new(_bp_path) Kit.check_quiet(sm_f.load_from_disk() and sm_f.has_breakpoint(), "P5 选择停点断点在档(选择停点可中断契约)") var bp_f: Dictionary = sm_f.breakpoint_snapshot() diff --git a/game/tests/unit/core/curio_refresh_paid_test.gd b/game/tests/unit/core/curio_refresh_paid_test.gd index 26392adc..b5ac2cad 100644 --- a/game/tests/unit/core/curio_refresh_paid_test.gd +++ b/game/tests/unit/core/curio_refresh_paid_test.gd @@ -23,9 +23,9 @@ func _init() -> void: Kit.check_quiet(adr.curio_stop_pending() == false, "无停点=在途谓词 false") Kit.check_quiet(adr.refresh_curio() == false and adr.refresh_curio_paid() == false, "无停点:免费/付费刷新皆拒绝零副作用") - # ---- ② 免费位优先序 X→Y(白盒造通关停点——smoke_all ⑫ 同构)---- + # ---- ② 免费位优先序 X→Y(白盒造关卡完成停点——smoke_all ⑫ 同构)---- adr._curio_pending = {"candidates": _cands(), "payload": {}} - Kit.check_quiet(adr.curio_stop_pending() == true, "通关停点在途=谓词 true") + Kit.check_quiet(adr.curio_stop_pending() == true, "关卡完成停点在途=谓词 true") adr._attune_refresh_x = 1 adr._attune_refresh_y = 2 Kit.check_quiet(adr.refresh_curio() and adr._attune_refresh_x == 0 and adr._attune_refresh_y == 2, "X 优先消耗(x1y2→x0y2)") diff --git a/game/tests/unit/core/level_shop_economy_test.gd b/game/tests/unit/core/level_shop_economy_test.gd index 0288f789..a0771fe6 100644 --- a/game/tests/unit/core/level_shop_economy_test.gd +++ b/game/tests/unit/core/level_shop_economy_test.gd @@ -1,6 +1,6 @@ # tests/unit/core/level_shop_economy_test.gd — 关卡图与 GP 商店单元测试宿主 # 断言面 = 七套(批 B 断言迁移自 smoke_all.gd,G8 施工组): -# 关卡节点图·生成图推进(满配通关/恢复点公式/败北线/回放确定性/属性覆盖恢复) +# 关卡节点图·生成图推进(满配冒险成功/恢复点公式/败北线/回放确定性/属性覆盖恢复) # 分支节点图(图校验正反/L2·L3 行进与行集定点/混编运行面/真图类型可见性) # GP 冒险钱包·到账(掷定窗口/关级加值) # escrow 隔离(格面兑付入缓冲/破财直验/钱包钳制不透支) @@ -323,15 +323,15 @@ func _smoke_generated_coverage() -> void: # ---- 关卡节点图·生成图推进冒烟(图 = 该关参数档 × 种子)---- func _smoke_level() -> void: - print("--- 关卡节点图·生成图推进(参数档×种子产图·满配通关/恢复公式/败北线/回放确定性)---") + print("--- 关卡节点图·生成图推进(参数档×种子产图·满配冒险成功/恢复公式/败北线/回放确定性)---") var autoplay = load("res://sim/level_autoplay.gd") var hero_base := {"atk": int(_db.hero.atk), "hp": int(_db.hero.max_hp), "ac": int(_db.hero.armor_class)} # 配置基线快照——⑤ 回基线对比用(改表自动跟随,不再硬编码) var nodes1: Array = _level_active_nodes(1) var params1: Dictionary = _db.level_gen_params_row(1) Kit.check("L1 现行起关图取数非空(种子 %d × 参数档 → 节点 %d 颗)" % [ACTIVE_GRAPH_SEED, nodes1.size()], not nodes1.is_empty()) - # ① 满配通关路径(atk+200%/hp+100%——测试面板同源的属性覆盖) + # ① 满配冒险成功路径(atk+200%/hp+100%——测试面板同源的属性覆盖) var win = autoplay.run_level(_db, ACTIVE_GRAPH_SEED, 1, 200, 100) - Kit.check("关卡·满配(atk+200/hp+100)通关(实测:%s @节点 %d)" % [win.result, win.defeat_node_index], win.result == "victory") + Kit.check("关卡·满配(atk+200/hp+100)完成(实测:%s @节点 %d)" % [win.result, win.defeat_node_index], win.result == "victory") # 行进面读数与图读数自洽:路径逐跳为图出边,路径上战斗/Boss 计数 = battles 读数 var by_id1 := _nodes_by_id(nodes1) var path_battles := 0 @@ -339,10 +339,10 @@ func _smoke_level() -> void: var vkind := String(by_id1.get(int(vid), {}).get("type", "")) if vkind == "battle" or vkind == "boss": path_battles += 1 - Kit.check("L1 通关路径逐跳为图出边(入口起步·末节点无出边——句柄轴行进自洽)", _path_in_graph(nodes1, win.visited_ids)) - Kit.check("L1 通关路径战斗/Boss 节点数 = 行进 battles 读数(路径 %d 节点·战斗 %d 颗·battles %d)" % [win.visited_ids.size(), path_battles, int(win.battles)], + Kit.check("L1 关卡完成路径逐跳为图出边(入口起步·末节点无出边——句柄轴行进自洽)", _path_in_graph(nodes1, win.visited_ids)) + Kit.check("L1 关卡完成路径战斗/Boss 节点数 = 行进 battles 读数(路径 %d 节点·战斗 %d 颗·battles %d)" % [win.visited_ids.size(), path_battles, int(win.battles)], path_battles == int(win.battles) and path_battles >= 2) - # 终点恒落最长路径步数:Boss 深度 = 参数档层高,且通关路径末节点即该终点 + # 终点恒落最长路径步数:Boss 深度 = 参数档层高,且关卡完成路径末节点即该终点 var boss_depth1 := -1 for n in nodes1: if String(n.get("type", "")) == "boss": @@ -350,7 +350,7 @@ func _smoke_level() -> void: var last_id := -1 if win.visited_ids.size() > 0: last_id = int(win.visited_ids[win.visited_ids.size() - 1]) - Kit.check("L1 终点 Boss 深度 = 参数档层高 %d 且通关路径末节点落该深度(实测终点深度 %d·末句柄 %d)" % [int(params1.get("layers", -1)), boss_depth1, last_id], + Kit.check("L1 终点 Boss 深度 = 参数档层高 %d 且关卡完成路径末节点落该深度(实测终点深度 %d·末句柄 %d)" % [int(params1.get("layers", -1)), boss_depth1, last_id], boss_depth1 == int(params1.get("layers", -1)) and int(by_id1.get(last_id, {}).get("depth", -1)) == boss_depth1) Kit.check("L1 终点恰一个(大岔口自 L2 起的图侧投影)", _terminal_ids(nodes1).size() == 1 and _ids_of_type(nodes1, "boss").size() == 1) Kit.check("L1 生成图含岔口(出度 ≥2 节点 %d 处)" % _fork_ids(nodes1).size(), _fork_ids(nodes1).size() >= 1) @@ -371,7 +371,7 @@ func _smoke_level() -> void: else: Kit.check("恢复点公式·缺口不足档:回复封顶到缺口 2(实测 %d,比例项 %d)" % [int(rest_narrow["healed"]), expect_pct], int(rest_narrow["healed"]) == mini(expect_pct, 2) and expect_pct > 2) - # ③ 裸装败北路径(atk1/hp10——Roguelike 基线应难以通关) + # ③ 裸装败北路径(atk1/hp10——Roguelike 基线应难以完成) var lose = autoplay.run_level(_db, ACTIVE_GRAPH_SEED, 1, -80, -80) Kit.check("关卡·裸装(atk≈1/hp≈10)败北路径可达(实测:%s)" % lose.result, lose.result == "defeat") Kit.check("败北节点记录在域内(节点 %d,图节点数 %d)" % [lose.defeat_node_index, nodes1.size()], @@ -488,7 +488,7 @@ func _smoke_level_graph() -> void: Kit.check("图校验拒绝:非 Boss 终点(终点恒为 Boss)〔v1〕", _has_err_category(LT.validate_graph(orphan), "structural")) # ④ L2 选路推进:min / max 双路径全通(确定性路径轴——同种子同图,方向轴只换候选取值) var win_min: Dictionary = autoplay.run_level(_db, ACTIVE_GRAPH_SEED, 2, 200, 100, false, null, "normal", "min") - Kit.check("L2·满配 min 路径通关(实测:%s)" % win_min.result, win_min.result == "victory") + Kit.check("L2·满配 min 路径完成(实测:%s)" % win_min.result, win_min.result == "victory") var n2_last := -1 if win_min.visited_ids.size() > 0: n2_last = int(win_min.visited_ids[win_min.visited_ids.size() - 1]) @@ -501,7 +501,7 @@ func _smoke_level_graph() -> void: _path_shop_count(nodes2, win_min.visited_ids) == 1) Kit.check("选路口发生 %d 次(每节点兑付后——零自动推进)" % win_min.choices, win_min.choices >= 3) var win_max: Dictionary = autoplay.run_level(_db, ACTIVE_GRAPH_SEED, 2, 200, 100, false, null, "normal", "max") - Kit.check("L2·满配 max 路径(候选取最大句柄)通关(实测:%s·路径 %s)" % [win_max.result, str(win_max.visited_ids)], win_max.result == "victory") + Kit.check("L2·满配 max 路径(候选取最大句柄)完成(实测:%s·路径 %s)" % [win_max.result, str(win_max.visited_ids)], win_max.result == "victory") var n2_last_max := -1 if win_max.visited_ids.size() > 0: n2_last_max = int(win_max.visited_ids[win_max.visited_ids.size() - 1]) @@ -973,7 +973,7 @@ func _smoke_shop_room() -> void: var shop_run := {} for s in range(42, 92): var r0 = load("res://core/level_runner.gd").new(_db, _fresh_rng(s)) - r0.set_hero_override(900, 400) # 行进段快速通关档(购买断言与百分比轴正交——加算区单独断言) + r0.set_hero_override(900, 400) # 行进段快速完成档(购买断言与百分比轴正交——加算区单独断言) r0.start_level(2, s) var st := _battle_st("normal") var guard := 60 diff --git a/game/tests/unit/core/meta_progression_forge_test.gd b/game/tests/unit/core/meta_progression_forge_test.gd index 967bd3be..93901791 100644 --- a/game/tests/unit/core/meta_progression_forge_test.gd +++ b/game/tests/unit/core/meta_progression_forge_test.gd @@ -159,7 +159,7 @@ func _meta_settle_and_workshop() -> void: var row1: Dictionary = _db.meta_boss_keystone_row(1) var row2: Dictionary = _db.meta_boss_keystone_row(2) # ⑥ 逐杀掉落收束入账(掉落已在冒险内逐杀入账〔summary.keystone_total 含全部〕, - # keystone_drops 明细随摘要归档;首杀标记仍由 apply 逐通关关次置位) + # keystone_drops 明细随摘要归档;首杀标记仍由 apply 逐关卡完成关次置位) var d1: Dictionary = mp.settle_adventure({"result": "failed", "cleared": false, "levels_cleared": 1, "stopped_at": 2, "keystone_total": int(row1.get("first_kill", 0)), "keystone_drops": [{"level": 1, "first": true, "amount": int(row1.get("first_kill", 0))}], @@ -186,21 +186,21 @@ func _meta_settle_and_workshop() -> void: "master_seed": 13}) Kit.check("重复杀第三轮恒定不递减(验收5——无衰减曲线)", not bool(d3["boss_drops"][0].get("first", true)) and int(d3["boss_drops"][0].get("amount", 0)) == int(row1.get("repeat_kill", -1))) - # 混合归因:通关两关 → L1 重复 + L2 首杀(明细随摘要逐笔归档) + # 混合归因:完成两关 → L1 重复 + L2 首杀(明细随摘要逐笔归档) var d4: Dictionary = mp.settle_adventure({"result": "failed", "cleared": false, "levels_cleared": 2, "stopped_at": 0, "keystone_total": int(row1.get("repeat_kill", 0)) + int(row2.get("first_kill", 0)), "keystone_drops": [{"level": 1, "first": false, "amount": int(row1.get("repeat_kill", 0))}, {"level": 2, "first": true, "amount": int(row2.get("first_kill", 0))}], "master_seed": 14}) - Kit.check("两关通关逐关归因:L1 重复档 + L2 首杀档(first_kill 金额)", + Kit.check("两关完成逐关归因:L1 重复档 + L2 首杀档(first_kill 金额)", not bool(d4["boss_drops"][0].get("first", true)) and bool(d4["boss_drops"][1].get("first", false)) and int(d4["boss_drops"][1].get("amount", 0)) == int(row2.get("first_kill", -1))) - # ⑦ 败北零通关摘要:余额只增不减(零入账)、clear_counts 不变 + # ⑦ 败北零关卡完成摘要:余额只增不减(零入账)、clear_counts 不变 var bal_before: int = sv.keystone_balance() var cc1_before: int = sv.clear_count(1) var dz: Dictionary = mp.settle_adventure({"result": "failed", "cleared": false, "levels_cleared": 0, "stopped_at": 1, "keystone_total": 0, "master_seed": 15}) - Kit.check("败北零通关摘要:零入账零标记(钥石只增不减——验收1;败北局 clear_counts 不变)", + Kit.check("败北零关卡完成摘要:零入账零标记(钥石只增不减——验收1;败北局 clear_counts 不变)", dz["boss_drops"].is_empty() and sv.keystone_balance() == bal_before and sv.clear_count(1) == cc1_before) # ⑧ 秘宝解锁服务(V3 钥石购买/V4 条件解锁;注入=直调解锁写口+直置存档生涯计数, # 不走正常资源积累流程——卡片 7.1 测试方式) @@ -217,10 +217,10 @@ func _meta_settle_and_workshop() -> void: and sv_u.keystone_balance() == 0) Kit.check("已解锁重复购买拒绝〔秘宝批 V3〕", not mp_u.buy_treasure_unlock("morning_order")) - Kit.check("条件未达不解锁(远程镐=通关 1 次)〔秘宝批 V4〕", + Kit.check("条件未达不解锁(远程镐=冒险成功 1 次)〔秘宝批 V4〕", mp_u.refresh_treasure_unlocks().is_empty() and not sv_u.item_unlocked("ranged_pick")) sv_u._data["meta"]["adventure_cleared"] = 1 # 直置存档生涯计数(调试注入口径) - Kit.check("远程镐=adventure_cleared≥1 达标恰解锁一次+重复刷新幂等(C6:通关=打通整局冒险)〔秘宝批 V4〕", + Kit.check("远程镐=adventure_cleared≥1 达标恰解锁一次+重复刷新幂等(C6:冒险成功=打通整局冒险)〔秘宝批 V4〕", (mp_u.refresh_treasure_unlocks() as Array).has("ranged_pick") and sv_u.item_unlocked("ranged_pick") and mp_u.refresh_treasure_unlocks().is_empty()) sv_u._data["meta"]["boss_kill_count"] = 3 @@ -230,7 +230,7 @@ func _meta_settle_and_workshop() -> void: Kit.check("天眼单条件不足不解锁(AND 语义——cleared 3 达 boss 4 未达)〔秘宝批 V4〕", not sv_u.item_unlocked("sky_eye")) sv_u._data["meta"]["boss_kill_count"] = 4 - Kit.check("天眼双条件 AND(通关≥3 且 Boss≥4)达标解锁〔秘宝批 V4〕", + Kit.check("天眼双条件 AND(冒险成功≥3 且 Boss≥4)达标解锁〔秘宝批 V4〕", (mp_u.refresh_treasure_unlocks() as Array).has("sky_eye")) sv_u._data["meta"]["vision_used"] = 10 Kit.check("信标网络=真视类工具累计使用≥10(行为计数新域——use_treasure 受理成功累计)〔秘宝批 V4〕", @@ -267,7 +267,7 @@ func _meta_settle_and_workshop() -> void: and int(mp_a.attune_camp_status()["refresh"]["charges"]) == 1) mp_a.settle_adventure({"result": "failed", "cleared": false, "levels_cleared": 1, "stopped_at": 2, "keystone_total": 0, "master_seed": 21}) - Kit.check("通关 1 关 → Slots 恒 0(旧「按击杀 Boss 次数自动涨」条件已删——槽位唯一来源=树点亮)且 Boss 击杀总数=1(计数域保留)〔天赋树批 V14〕", + Kit.check("完成 1 关 → Slots 恒 0(旧「按击杀 Boss 次数自动涨」条件已删——槽位唯一来源=树点亮)且 Boss 击杀总数=1(计数域保留)〔天赋树批 V14〕", Attunement.slots(_db, sv_a) == 0 and sv_a.boss_kill_count() == 1) sv_a.set_tree_level("att_socket1", 1) Kit.check("树上点亮同调位 1 → Slots=1(槽位收编树节点——Q2 裁甲)", diff --git a/game/tests/unit/core/save_boot_no_activate_test.gd b/game/tests/unit/core/save_boot_no_activate_test.gd index 4ac1d291..7f6a60e1 100644 --- a/game/tests/unit/core/save_boot_no_activate_test.gd +++ b/game/tests/unit/core/save_boot_no_activate_test.gd @@ -27,7 +27,7 @@ func _test_no_arg_instance_has_no_activation() -> void: "sv2 无参实例无激活态(路径空/激活号 0/写盘目标空)〔卡① sv2〕") Kit.check_quiet(sm.keystone_balance() == 0 and not sm.has_breakpoint() and sm.adventure_total() == 0 and sm.adventure_cleared() == 0, - "sv2 内存=默认合法空态(钥石/断点/总局数/通关数全零值——访问器 fail-safe)〔卡① sv2〕") + "sv2 内存=默认合法空态(钥石/断点/总局数/冒险成功数全零值——访问器 fail-safe)〔卡① sv2〕") # attach_path 注入任意隔离路径=注入即激活(契约 7 单路径语义——隔离面行为零变化) sm.attach_path("user://smoke_boot_noact_iso.json") Kit.check_quiet(sm.has_write_target() and sm.keystone_balance() == 0, diff --git a/game/tests/unit/core/save_manager_domain_test.gd b/game/tests/unit/core/save_manager_domain_test.gd index d33c1ca2..8e23fd32 100644 --- a/game/tests/unit/core/save_manager_domain_test.gd +++ b/game/tests/unit/core/save_manager_domain_test.gd @@ -78,11 +78,11 @@ func _smoke_save() -> void: w.unlock_item("probe_compass") w.apply_adventure_summary({"result": "failed", "cleared": false, "levels_cleared": 2, "stopped_at": 3, "keystone_total": 3, "master_seed": 99}) - Kit.check("apply 原语入账(钥石 7+3、通关次数 1/1/0)", + Kit.check("apply 原语入账(钥石 7+3、关卡完成次数 1/1/0)", w.keystone_balance() == 10 and w.clear_count(1) == 1 and w.clear_count(2) == 1 and w.clear_count(3) == 0) - Kit.check("首杀标记随通关关卡置位(1/2 有、3 无)", + Kit.check("首杀标记随关卡完成置位(1/2 有、3 无)", w.boss_first_kill_marked(1) and w.boss_first_kill_marked(2) and not w.boss_first_kill_marked(3)) - Kit.check("生涯终身计数随 apply 自增恰一(中止局:总局数 1、通关局数 0——迭代 18 卡④)", + Kit.check("生涯终身计数随 apply 自增恰一(中止局:总局数 1、冒险成功局数 0——迭代 18 卡④)", w.adventure_total() == 1 and w.adventure_cleared() == 0) Kit.check("写盘成功", w.write_to_disk()) var r = sm_script.new(paths[0]) @@ -95,7 +95,7 @@ func _smoke_save() -> void: and r.forge_unlocked_purchases() == ["spear"] and r.forge_weapon() == "spear" and r.forge_armor() == "ward") Kit.check("道具解锁往返相等", r.item_unlocked("probe_compass") and not r.item_unlocked("rope")) - Kit.check("通关次数表往返相等", r.clear_count(1) == 1 and r.clear_count(2) == 1 and r.clear_count(3) == 0) + Kit.check("关卡完成次数表往返相等", r.clear_count(1) == 1 and r.clear_count(2) == 1 and r.clear_count(3) == 0) Kit.check("首杀标记往返相等", r.boss_first_kill_marked(1) and r.boss_first_kill_marked(2) and not r.boss_first_kill_marked(3)) Kit.check("生涯终身计数往返相等(1/0)", r.adventure_total() == 1 and r.adventure_cleared() == 0) @@ -265,11 +265,11 @@ func _smoke_save() -> void: f13b.load_from_disk() f13b.apply_adventure_summary({"result": "completed", "cleared": true, "levels_cleared": 3, "stopped_at": 0, "keystone_total": 0, "master_seed": 1}) - Kit.check("收束自增恰一·通关局(三关全通 cleared=true:总局数+1 且通关局数+1)", + Kit.check("收束自增恰一·冒险成功局(三关全通 cleared=true:总局数+1 且冒险成功局数+1)", f13b.adventure_total() == 1 and f13b.adventure_cleared() == 1) f13b.apply_adventure_summary({"result": "abandoned", "cleared": false, "levels_cleared": 1, "stopped_at": 2, "keystone_total": 0, "master_seed": 2}) - Kit.check("收束自增恰一·中止局(放弃局:仅总局数+1,通关局数不动)", + Kit.check("收束自增恰一·中止局(放弃局:仅总局数+1,冒险成功局数不动)", f13b.adventure_total() == 2 and f13b.adventure_cleared() == 1) # ⑮ 旧档破坏性废弃(契约 4:换代前结构检测=树域废弃重置,禁迁移禁折算)〔V16〕 @@ -321,11 +321,11 @@ func _smoke_save() -> void: var mp13 = load("res://core/meta_progression.gd").new(_db, f13b) mp13.settle_adventure({"result": "failed", "cleared": false, "levels_cleared": 2, "stopped_at": 3, "keystone_total": 0, "master_seed": 3}) - Kit.check("收束链自增·中止局(settle_adventure 真实挂点:总局数+1、通关局数不动)", + Kit.check("收束链自增·中止局(settle_adventure 真实挂点:总局数+1、冒险成功局数不动)", f13b.adventure_total() == 3 and f13b.adventure_cleared() == 1) mp13.settle_adventure({"result": "completed", "cleared": true, "levels_cleared": 3, "stopped_at": 0, "keystone_total": 0, "master_seed": 4}) - Kit.check("收束链自增·通关局(三关全通:总局数+1 且通关局数+1——全链恰一)", + Kit.check("收束链自增·冒险成功局(三关全通:总局数+1 且冒险成功局数+1——全链恰一)", f13b.adventure_total() == 4 and f13b.adventure_cleared() == 2) # 段尾清理(测试文件绝不残留) diff --git a/game/tests/unit/core/save_slot_summary_test.gd b/game/tests/unit/core/save_slot_summary_test.gd index ba9592e7..ae0be20e 100644 --- a/game/tests/unit/core/save_slot_summary_test.gd +++ b/game/tests/unit/core/save_slot_summary_test.gd @@ -46,7 +46,7 @@ func _test_peek_three_slots_distinct_values() -> void: var ps: Dictionary = t.peek_slot_summary(i) Kit.check_quiet(bool(ps.get("readable", false)) and int(ps.get("keystone", -1)) == 200 * i and int(ps.get("cleared", -1)) == i and int(ps.get("total", -1)) == 5 * i, - "sv7 窥视三项逐槽正确·槽 %d(钥石/通关/总局)〔卡① sv7〕" % i) + "sv7 窥视三项逐槽正确·槽 %d(钥石/冒险成功/总局)〔卡① sv7〕" % i) Kit.check_quiet(t.active_slot() == 0 and not t.has_write_target() and t.keystone_balance() == 0, "sv7 窥视不激活不写内存(激活号 0/无写盘目标/内存余额零)〔卡① sv7〕") # 路径注入口同语义(契约 7 注入面) diff --git a/game/tests/unit/data_config/table_structure_guard_test.gd b/game/tests/unit/data_config/table_structure_guard_test.gd index 285d5bad..c180a42c 100644 --- a/game/tests/unit/data_config/table_structure_guard_test.gd +++ b/game/tests/unit/data_config/table_structure_guard_test.gd @@ -93,7 +93,7 @@ func _smoke_adventure_table() -> void: if _db.adventure == null: return Kit.check("AdventureTable.validate() 零违例(全键域检+档位配额结构锚在案)", _db.adventure.validate().is_empty()) - Kit.check("clear_heal_pct ∈ [0,100](%d——通关部分回血比例)" % int(_db.adventure.clear_heal_pct), + Kit.check("clear_heal_pct ∈ [0,100](%d——关卡完成部分回血比例)" % int(_db.adventure.clear_heal_pct), int(_db.adventure.clear_heal_pct) >= 0 and int(_db.adventure.clear_heal_pct) <= 100) for tier in _db.adventure.TIERS: Kit.check("档位配额结构锚(四级 70/25/7/0——迭代 31 卡② 净删两件投放):%s = %d 张" % [tier, int(_db.adventure.TIER_QUOTAS[tier])], @@ -464,7 +464,7 @@ func _smoke_nine_types_gp_stream() -> void: gp_pos = int(row.weight) if String(row.get("reward_id", "")) == "gp_lose": gp_neg = int(row.weight) - Kit.check("奖励字典 18 行(九型×正负 18 格——aux 挖格投放四行已退役 2026-10-01 用户拍板甲:战斗/挖格不掉道具,秘宝唯一来路=三选一共享池〔节点/通关〕;清图槽独立批尾不计)", + Kit.check("奖励字典 18 行(九型×正负 18 格——aux 挖格投放四行已退役 2026-10-01 用户拍板甲:战斗/挖格不掉道具,秘宝唯一来路=三选一共享池〔节点/关卡完成〕;清图槽独立批尾不计)", cell_rows == 18) # 危险格负向直伤当量(负向≈正向 2 倍定价——真人反馈「三雷 3/4 血无后果感」的投值口径) var mine_power := {"heal_backlash": 6, "pierce_snare": 8, "magic_recoil": 8} # 危险格负向直伤当量(抬档值;依据见 numfix 报告) diff --git a/game/tests/unit/presentation/battle_narrator_test.gd b/game/tests/unit/presentation/battle_narrator_test.gd index ce7dd670..e58a8085 100644 --- a/game/tests/unit/presentation/battle_narrator_test.gd +++ b/game/tests/unit/presentation/battle_narrator_test.gd @@ -22,6 +22,7 @@ func _init() -> void: _test_end_text_differs_by_result() _test_phase_text_nonempty() _test_boss_name_uses_boss_rowset() + _test_level_clear_wording() quit(Kit.finish("battle_narrator_test")) @@ -36,9 +37,9 @@ func _test_numeric_lines_carry_values() -> void: func _test_end_text_differs_by_result() -> void: - # 关卡收束(level_end=true)恒为「关卡通关!」——单场胜负文案只在非收束态出现 + # 关卡收束(level_end=true)恒为「关卡完成!」——单场胜负文案只在非收束态出现 var level: String = NarratorScript.battle_end_text("lose", true) - Kit.check("关卡收束态恒为「关卡通关!」(实际「%s」)" % level, level == "关卡通关!") + Kit.check("关卡收束态恒为「关卡完成!」(实际「%s」)" % level, level == "关卡完成!") var win: String = NarratorScript.battle_end_text("victory", false) var lose: String = NarratorScript.battle_end_text("lose", false) Kit.check("单场胜负文案互异(胜「%s」/负「%s」)" % [win, lose], win != lose) @@ -80,3 +81,21 @@ func _test_boss_name_uses_boss_rowset() -> void: var got: String = NarratorScript.boss_name(runner, db) Kit.check("Boss 名取自 Boss 行集首行(期望「%s」实际「%s」)〔fv24〕" % [boss_expect, got], got == boss_expect) Kit.check("Boss 名与同深度战斗行集名不同(期望「%s」≠「%s」——行类路由可判别)〔fv24〕" % [boss_expect, battle_name], boss_expect != battle_name) + + +# 关卡完成停点文案族措辞钉子(口径换代批):回血行/满血合法态/渠道句/摘要关数行—— +# 旧措辞退役后玩家可见面由本组断言钉在新措辞上(撤销证明:回退 battle_narrator 对应行→断言红→复原复绿) +func _test_level_clear_wording() -> void: + var healed: String = NarratorScript.curio_pick_header({"level_index": 1, "heal_gained": 5, "hp_before": 10, "hp_after": 15}) + Kit.check("关卡完成回血行带入回血量与生命区间(实际「%s」)〔口径换代 V1〕" % healed, + healed.contains("关卡完成回血 +5(生命 10 → 15)")) + var full_hp: String = NarratorScript.curio_pick_header({"level_index": 1, "heal_gained": 0, "hp_before": 12, "hp_after": 12}) + Kit.check("满血零回血合法态文案(实际「%s」)〔口径换代 V1〕" % full_hp, + full_hp.contains("生命已满——关卡完成回血 0(合法态)")) + var node_header: String = NarratorScript.node_curio_header() + Kit.check("奖励节点头部行渠道句点明关卡完成三选一(实际「%s」)〔口径换代 V2〕" % node_header, + node_header.contains("与关卡完成专长三选一同库分流")) + var summary: String = NarratorScript.adventure_summary_text( + {"cleared": false, "result": "failed", "levels_cleared": 1, "stopped_at": 2, "keystone_total": 4, "master_seed": 42}) + Kit.check("冒险摘要完成关数行(实际「%s」)〔口径换代 V3〕" % summary, + summary.contains("完成 1 关 · 止步第 2 层") and not summary.contains("通关")) diff --git a/game/tests/unit/presentation/reward_overlay_test.gd b/game/tests/unit/presentation/reward_overlay_test.gd index c619ca07..0f02d1b9 100644 --- a/game/tests/unit/presentation/reward_overlay_test.gd +++ b/game/tests/unit/presentation/reward_overlay_test.gd @@ -1,6 +1,6 @@ extends SceneTree # 三选一覆盖层 UI 直验套件—— -# 守 node_overlay.show_reward_items 的继任共用面;奖励节点三选一与通关三选一共用 CurioPickOverlay, +# 守 node_overlay.show_reward_items 的继任共用面;奖励节点三选一与关卡完成三选一共用 CurioPickOverlay, # 本套件守共用面的「功能存在 ≠ 功能可达」盲区:选择外发/强制确认两段式/结果态。 # 〔无替换子面板路段——装配不可变契约 1,overlay 无 replace 态。〕 # 运行:godot --headless --path game --script res://tests/unit/presentation/reward_overlay_test.gd(expect 0) diff --git a/game/tests/unit/presentation/theme_projection_test.gd b/game/tests/unit/presentation/theme_projection_test.gd index 09bb9178..fc43789c 100644 --- a/game/tests/unit/presentation/theme_projection_test.gd +++ b/game/tests/unit/presentation/theme_projection_test.gd @@ -52,6 +52,7 @@ func _init() -> void: _smoke_diag_button_retired() _status_panel_projection() _career_overlay_projection() + _camp_recent_projection() quit(Kit.finish("theme_projection_test")) @@ -806,6 +807,20 @@ func _all_labels(root: Node) -> Array: return out +# ---- 营地最近冒险行投影(口径换代 V6:完成关数措辞钉子——open_camp 全量重建路径直调; +# 最小档 data=recent 单条 completed 局,其余键缺省走 .get 兜底——与组合根 _camp_data 投影同键面)---- +func _camp_recent_projection() -> void: + print("--- 营地·最近冒险行投影(open_camp 最小档)---") + var camp = load("res://presentation/views/camp_overlay_view.gd").new() + camp.open_camp({"balance": 0, "recent": [ + {"result": "completed", "levels_cleared": 2, "keystone_total": 5, "master_seed": 42}]}) + var recent_text: String = String(camp._recent_list.text) + Kit.check("营地最近冒险行完成关数措辞(实际「%s」)〔口径换代 V6〕" % recent_text, + recent_text.contains("完成 2 关") and not recent_text.contains("通关")) + camp.visible = false + camp.free() + + # ---- 生涯页只读投影一致性(汇总段六类九项逐行 == SaveManager 计数访问器/ # MetaProgression 访问器读数;投影拼装与 HudPresenter.career_data 同构(同访问器族同序)。 # 只读性连接巡检与零动效断言归 ui_struct_probe 呈现侧,本段只管数据面+旧档载入显示 @@ -837,17 +852,27 @@ func _career_overlay_projection() -> void: Kit.check("生涯页开层可见(open_career 直开——零动效路径)", co.visible) Kit.check("总局数投影 = adventure_total() 读数(%s)" % co._total_label.text, String(co._total_label.text) == "2 局") - Kit.check("通关局数投影 = adventure_cleared() 读数(%s)" % co._cleared_label.text, + Kit.check("冒险成功局数投影 = adventure_cleared() 读数(%s)" % co._cleared_label.text, String(co._cleared_label.text) == "1 局(三关全通)") var expect_clears: Array[String] = [] for row in (data["clears"] as Array): expect_clears.append("%s ×%d" % [String(row.get("display_name", "")), int(row.get("count", 0))]) - Kit.check("各关通关次数投影 = clear_count() 逐关读数(%s)" % co._clears_label.text, + Kit.check("各关完成次数投影 = clear_count() 逐关读数(%s)" % co._clears_label.text, String(co._clears_label.text) == " · ".join(expect_clears)) Kit.check("Boss 首杀/总杀投影 = 首杀标记计数 + boss_kill_count()(%s / %s)" % [co._boss_first_label.text, co._boss_kills_label.text], String(co._boss_first_label.text) == "3/3 关" and String(co._boss_kills_label.text) == "4 次") Kit.check("钥石余额徽投影 = keystone_balance() 读数(%s)" % co._keystone_badge.value_label.text, String(co._keystone_badge.value_label.text) == "钥石 %d" % mp.keystone_balance()) + # 口径换代(2026-10-26):行标签换代钉子+生涯页零「通关」残留(负断言兜全页) + var career_label_texts: Array[String] = [] + for career_lbl: Label in _all_labels(co): + career_label_texts.append(String(career_lbl.text)) + var career_labels_joined: String = "|".join(career_label_texts) + Kit.check("生涯页行标签换代(冒险成功局数/各关完成次数)〔口径换代 V4〕", + career_labels_joined.contains("冒险成功局数") and career_labels_joined.contains("各关完成次数")) + Kit.check("生涯页 label 全集零「通关」残留〔口径换代 V4〕", not career_labels_joined.contains("通关")) + Kit.check("秘宝解锁条件标签冒险成功口径(UiKit 单点常量)〔口径换代 V5〕", + UiKit.TREASURE_REQ_LABELS["adventure_cleared"] == "冒险成功") co.visible = false co.free() # 旧档载入显示(完成定义 6):v5 现役档形态(计数域两键不存在)升 v6 → 生涯页正常呈现缺省值 @@ -866,7 +891,7 @@ func _career_overlay_projection() -> void: "count": v5.clear_count(i + 1)}) var co_v5 = load("res://presentation/views/career_overlay.gd").new() co_v5.open_career(data_v5) - Kit.check("旧档载入后生涯页正常显示(v5 升 v6:总局数/通关局数显示 0,既有钥石余额原样呈现)", + Kit.check("旧档载入后生涯页正常显示(v5 升 v6:总局数/冒险成功局数显示 0,既有钥石余额原样呈现)", co_v5.visible and String(co_v5._total_label.text) == "0 局" \ and String(co_v5._cleared_label.text) == "0 局(三关全通)" \ and String(co_v5._keystone_badge.value_label.text) == "钥石 3") diff --git a/game/tests/验证集清单.md b/game/tests/验证集清单.md index 260ab97e..1b7653f1 100644 --- a/game/tests/验证集清单.md +++ b/game/tests/验证集清单.md @@ -1,8 +1,8 @@ # 验证集清单(断言快照·冻结) -> 生成日期:2026-10-26 · 基点 commit:`7d2fbe158fa38d98b917762aa8812a80c8d70aea` · 源:cross_system_flow_test.gd、node_map_determinism_test.gd、save_rng_roundtrip_test.gd、system_test.gd、damage_controller_test.gd、damage_math_test.gd、roll_multiplier_test.gd、round_flow_skill_pool_test.gd、seal_polarity_test.gd、skill_unlock_test.gd、variant_placement_test.gd、source_guard_test.gd、system_contracts_test.gd、adventure_feats_test.gd、board_gen_reward_test.gd、board_generator_test.gd、breakpoint_resume_test.gd、config_db_cross_validator_test.gd、config_db_resolver_test.gd、curio_refresh_paid_test.gd、effect_words_t1_test.gd、feat_vouchers_test.gd、level_map_type_vis_test.gd、level_shop_economy_test.gd、level_table_validate_test.gd、meta_progression_forge_test.gd、minesweeper_rules_test.gd、node_map_generator_test.gd、node_map_growth_test.gd、pool_case_d_test.gd、save_boot_no_activate_test.gd、save_manager_domain_test.gd、save_slot_isolation_test.gd、save_slot_summary_test.gd、settle_segments_test.gd、treasure_effects_test.gd、treasure_items_test.gd、tree_requires_level_test.gd、tree_rules_v11_test.gd、config_db_fatal_oob_test.gd、config_db_test.gd、counter_prefix_fatal_test.gd、forge_table_test.gd、level_gen_params_test.gd、reward_dangling_treasure_test.gd、rng_service_test.gd、rng_stream_boot_test.gd、table_structure_guard_test.gd、treasure_target_violation_test.gd、example_test.gd、battle_narrator_test.gd、forge_workbench_test.gd、hud_presenter_test.gd、level_map_info_fog_test.gd、modal_flow_test.gd、pacing_queue_test.gd、player_copy_sweep_test.gd、reward_overlay_test.gd、standee_fx_sweep_test.gd、terrain_tile_sets_test.gd、theme_projection_test.gd、type_glow_test.gd、ui_font_asset_test.gd、test_kit.gd +> 生成日期:2026-10-26 · 基点 commit:`54395b8b434c2662924947e886c65c7393d88de4` · 源:cross_system_flow_test.gd、node_map_determinism_test.gd、save_rng_roundtrip_test.gd、system_test.gd、damage_controller_test.gd、damage_math_test.gd、roll_multiplier_test.gd、round_flow_skill_pool_test.gd、seal_polarity_test.gd、skill_unlock_test.gd、variant_placement_test.gd、source_guard_test.gd、system_contracts_test.gd、adventure_feats_test.gd、board_gen_reward_test.gd、board_generator_test.gd、breakpoint_resume_test.gd、config_db_cross_validator_test.gd、config_db_resolver_test.gd、curio_refresh_paid_test.gd、effect_words_t1_test.gd、feat_vouchers_test.gd、level_map_type_vis_test.gd、level_shop_economy_test.gd、level_table_validate_test.gd、meta_progression_forge_test.gd、minesweeper_rules_test.gd、node_map_generator_test.gd、node_map_growth_test.gd、pool_case_d_test.gd、save_boot_no_activate_test.gd、save_manager_domain_test.gd、save_slot_isolation_test.gd、save_slot_summary_test.gd、settle_segments_test.gd、treasure_effects_test.gd、treasure_items_test.gd、tree_requires_level_test.gd、tree_rules_v11_test.gd、config_db_fatal_oob_test.gd、config_db_test.gd、counter_prefix_fatal_test.gd、forge_table_test.gd、level_gen_params_test.gd、reward_dangling_treasure_test.gd、rng_service_test.gd、rng_stream_boot_test.gd、table_structure_guard_test.gd、treasure_target_violation_test.gd、example_test.gd、battle_narrator_test.gd、forge_workbench_test.gd、hud_presenter_test.gd、level_map_info_fog_test.gd、modal_flow_test.gd、pacing_queue_test.gd、player_copy_sweep_test.gd、reward_overlay_test.gd、standee_fx_sweep_test.gd、terrain_tile_sets_test.gd、theme_projection_test.gd、type_glow_test.gd、ui_font_asset_test.gd、test_kit.gd > 提取口径:静态 `check(` 调用点,括号配平归集(可跨行);缺省源=三宿主遍历 -> (unit/**+integration/**+system_test.gd)。本基点实测 1583 个静态调用点;行级 +> (unit/**+integration/**+system_test.gd)。本基点实测 1591 个静态调用点;行级 > `grep -c "check("` 是另一口径(含 `func check(` 定义行与注释行),两口径各自浮动, > 禁互相换算(tests/README「断言计数双口径」)。运行时计数大于静态计数=循环展开条目。 > 生成命令:`python tools/extract_checks.py --extract`(可复现;重新生成须 --force; @@ -32,12 +32,12 @@ | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 5 | 119 | "摘要集成:冒险驱动满配通关(seed 42)" | String(st9.get("result", "")) == "completed" | (待填) | | | +| 5 | 119 | "摘要集成:冒险驱动满配冒险成功(seed 42)" | String(st9.get("result", "")) == "completed" | (待填) | | | | 6 | 120 | "集成钥石余额 = ΣBoss 首杀行值(%d——逐杀掉落全源)" ↩ % f9.keystone_balance() | f9.keystone_balance() == ks_run | (待填) | | | -| 7 | 121 | "集成通关次数表全 1" | f9.clear_count(1) == 1 and f9.clear_count(2) == 1 and f9.clear_count(3) == 1 | (待填) | | | +| 7 | 121 | "集成关卡完成次数表全 1" | f9.clear_count(1) == 1 and f9.clear_count(2) == 1 and f9.clear_count(3) == 1 | (待填) | | | | 8 | 122 | "集成三关首杀标记齐" | f9.boss_first_kill_marked(1) and f9.boss_first_kill_marked(2) and f9.boss_first_kill_marked(3) | (待填) | | | | 9 | 123 | "集成 recent 1 条且 seed 42" | f9.recent_summaries().size() == 1 and int(f9.recent_summaries()[0].get("master_seed", -1)) == 42 | (待填) | | | -| 10 | 126 | "第二局后通关次数全 2" | f9.clear_count(1) == 2 and f9.clear_count(2) == 2 and f9.clear_count(3) == 2 | (待填) | | | +| 10 | 126 | "第二局后关卡完成次数全 2" | f9.clear_count(1) == 2 and f9.clear_count(2) == 2 and f9.clear_count(3) == 2 | (待填) | | | | 11 | 127 | "第二局后余额翻倍(2 × Σ首杀——模拟驱动恒首杀口径)" | f9.keystone_balance() == 2 * ks_run | (待填) | | | | 12 | 128 | "集成 recent 长度 2" | f9.recent_summaries().size() == 2 | (待填) | | | | 13 | 129 | "集成写盘成功" | f9.write_to_disk() | (待填) | | | @@ -825,25 +825,25 @@ |---|---|---|---|---|---|---| | 456 | 113 | "序列关数 = 行集关数(三关正式序列生效)" | int(_db.level.rows.size()) == 3 | (待填) | | | | 457 | 130 | "生成图每个战斗/Boss 节点经解析链命中敌行集与棋盘行(扫描 %d 节点,缺失 %d)〔fv24〕" ↩ % [cov_scan, cov_miss] | cov_scan > 0 and cov_miss == 0 | (待填) | | | -| 458 | 135 | "满配通关(42 / atk+900 / hp+400——cleared=true;v2 怪阶梯后旧 200/100 档不再满配)" | String(st["result"]) == "completed" and bool(sum.get("cleared", false)) | (待填) | | | -| 459 | 136 | "通关几关 = 3(levels_cleared)" | int(sum.get("levels_cleared", -1)) == 3 | (待填) | | | +| 458 | 135 | "满配冒险成功(42 / atk+900 / hp+400——cleared=true;v2 怪阶梯后旧 200/100 档不再满配)" | String(st["result"]) == "completed" and bool(sum.get("cleared", false)) | (待填) | | | +| 459 | 136 | "完成几关 = 3(levels_cleared)" | int(sum.get("levels_cleared", -1)) == 3 | (待填) | | | | 460 | 140 | "钥石合计 = ΣBoss 首杀行值(%d——逐杀掉落新口径;断点未注入恒首杀)" ↩ % int(sum.get("keystone_total", -1)) | int(sum.get("keystone_total", -1)) == ks_exp | (待填) | | | | 461 | 142 | "逐杀掉落明细恰 3 笔(L1/L2/L3——additive 摘要键 keystone_drops)" | drops.size() == 3 | (待填) | | | | 462 | 143 | "摘要携带主种子(42)" | int(sum.get("master_seed", -1)) == 42 | (待填) | | | -| 463 | 154 | "通关三选一恰呈现 2 次、恰兑付 2 次(L1/L2 后——末关不发;resolves 含节点回执另计)" | picks.size() == 2 and resolves.size() == 2 + node_picks | (待填) | | | +| 463 | 154 | "关卡完成三选一恰呈现 2 次、恰兑付 2 次(L1/L2 后——末关不发;resolves 含节点回执另计)" | picks.size() == 2 and resolves.size() == 2 + node_picks | (待填) | | | | 464 | 165 | "三关生成图各含 ≥1 奖励节点(节点三选一候选位在图)〔v4〕" | reward_levels == 3 | (待填) | | | | 465 | 169 | "奖励分支点选→三选一候选可取且停点在途(候选 %s 件)" ↩ % str((rw.get("cands", []) as Array).size()) | bool(rw.get("pending", false)) and (rw.get("cands", []) as Array).size() >= 1 | (待填) | | | | 466 | 182 | "奖励三选一点选兑付受理(件=%s)" ↩ % String(rw_pc.get("kind", "")) | rw_pick_ok | (待填) | | | | 467 | 188 | "进战载荷两样=关卡序号+节点深度(实测 depth=%s 句柄=%s)〔v6〕" ↩ % [str(enc_probe.get("node_depth", -1)), str(node_probe.get("id", -1))] | not enc_probe.is_empty() and int(enc_probe.get("node_depth", -1)) == int(node_probe.get("depth", -1)) and int(enc_probe.get("level_index", -1)) == 1 and int(node_probe.get("id", -1)) != int(node_probe.get("depth", -1)) | (待填) | | | | 468 | 197 | "奖励节点兑付回执与经停逐笔相等(context=reward_node——同账计数 %d/%d)" ↩ % [node_resolves, node_picks] | node_resolves == node_picks | (待填) | | | | 469 | 244 | "三选一候选 2–3 枚且零重复(令牌洗牌不放回——kind+tier 复合身份)" | cand_ok | (待填) | | | -| 470 | 245 | "通关部分回血封顶(floor(观测上限×比例) 封顶——购血观测值精确断言,核代码增补)" | heal_ok | (待填) | | | +| 470 | 245 | "关卡完成部分回血封顶(floor(观测上限×比例) 封顶——购血观测值精确断言,核代码增补)" | heal_ok | (待填) | | | | 471 | 246 | "钥石逐杀入账(首杀档位 + 累计逐位)" | ks_gain_ok | (待填) | | | | 472 | 247 | "点选恰兑付选中一件(值=令牌档位表值;未选项零生效)" | resolve_ok | (待填) | | | | 473 | 258 | "各战上限入参 ∈ [基础, 基础+3×件值+购血余量](覆盖值通道——双渠道共享上限 3;模拟档贪心购血合法叠加〔数值修复批 v3.4〕;首战=基础 %d)" ↩ % exp_base | seq_ok | (待填) | | | | 474 | 261 | "同种子两局逐位可复现(summary/上限序列/行进序列/三选一载荷——reward_pick 封闭流)" | st2["summary"] == sum and st2["encounter_max_hp_seq"] == seq and st2["visited_ids"] == st["visited_ids"] and st2["reward_events"] == st["reward_events"] | (待填) | | | | 475 | 271 | "零配 L1 败北种子可达(seed=%s)" ↩ % str(lose.get("s", -1)) | not lose.is_empty() | (待填) | | | -| 476 | 274 | "L1 败北摘要:未打穿 · 通关 0 关 · 钥石 0 · 止步第 1 层" | not bool(sl["cleared"]) and int(sl["levels_cleared"]) == 0 \\ and int(sl["keystone_total"]) == 0 and int(sl["stopped_at"]) == 1 | (待填) | | | +| 476 | 274 | "L1 败北摘要:未打穿 · 完成 0 关 · 钥石 0 · 止步第 1 层" | not bool(sl["cleared"]) and int(sl["levels_cleared"]) == 0 \\ and int(sl["keystone_total"]) == 0 and int(sl["stopped_at"]) == 1 | (待填) | | | | 477 | 278 | "L1 败北败退明细:层号/节点编号/节点类型在案(数值验证取数面 2026-09-22)" | int(dl.get("level_index", -1)) == 1 and int(dl.get("node_id", -1)) >= 0 \\ and String(dl.get("node_type", "")) in ["battle", "boss"] | (待填) | | | | 478 | 287 | "半配(atk+50)L2 败北种子可达(seed=%s)" ↩ % str(half.get("s", -1)) | not half.is_empty() | (待填) | | | | 479 | 290 | "L2 败北摘要:L1 已过(钥石=L1 首杀掉落)· 止步第 2 层" | not bool(sh["cleared"]) and int(sh["levels_cleared"]) == 1 \\ and int(sh["keystone_total"]) == int(_db.meta_boss_keystone_row(1).get("first_kill", 0)) \\ and int(sh["stopped_at"]) == 2 | (待填) | | | @@ -858,11 +858,11 @@ | 488 | 349 | "进店余额 ≥ hp_up L2 首价(%d = 基价 %d + 关卡加成 %d——配置推导)" ↩ % [hp_price + l2_price_bonus, hp_price, l2_price_bonus] | gp0 >= hp_price + l2_price_bonus | (待填) | | | | 489 | 350 | "购买 hp_up 受理(出账 + 加算区)" | r8.buy_product("hp_up") | (待填) | | | | 490 | 352 | "统一冒险加算区含商店值(max_hp=%d ≥ 商店 3——L1 三选一件值另计)" ↩ % acc_shop | acc_shop >= 3 | (待填) | | | -| 491 | 355 | "L2 通关三选一停点在案(直调兑付前——零自动推进)" | not a8._curio_pending.is_empty() | (待填) | | | +| 491 | 355 | "L2 关卡完成三选一停点在案(直调兑付前——零自动推进)" | not a8._curio_pending.is_empty() | (待填) | | | | 492 | 356 | "未兑付推进拒绝(选择停点零自动推进契约)" | not a8.continue_to_next_level() | (待填) | | | | 493 | 359 | "三选一点选兑付受理(候选取首件)" | a8.pick_curio(String(l2_pick.get("kind", "")), String(l2_pick.get("tier", "")), String(l2_pick.get("feat_id", ""))) | (待填) | | | | 494 | 362 | "三选一属性件与商店购买同账累加(max_hp=%d = %d + 三选一%s)" ↩ % [int(a8.run_ledger.bonus.get("max_hp", -1)), acc_shop, picked2] | int(a8.run_ledger.bonus.get("max_hp", -1)) == expect_acc | (待填) | | | -| 495 | 364 | "通关部分回血封顶(hp %d ≤ 生效上限 %d——血回满语义退役)" ↩ % [int(a8.ledger["hero_hp"]), max_eff8] | int(a8.ledger["hero_hp"]) <= max_eff8 | (待填) | | | +| 495 | 364 | "关卡完成部分回血封顶(hp %d ≤ 生效上限 %d——血回满语义退役)" ↩ % [int(a8.ledger["hero_hp"]), max_eff8] | int(a8.ledger["hero_hp"]) <= max_eff8 | (待填) | | | | 496 | 365 | "兑付后推进受理(下一关开始)" | a8.continue_to_next_level() | (待填) | | | | 497 | 368 | "恢复点数学:floor(100×30%)=30 · 封顶缺口 5 · 满血回 0 合法" | int(a9.apply_rest(30, 70, 100)) == 30 and int(a9.apply_rest(30, 95, 100)) == 5 \\ and int(a9.apply_rest(30, 100, 100)) == 0 | (待填) | | | | 498 | 372 | "同一公式两个落点逐位一致(LevelRunner.rest_heal_amount 内置默认)" | int(lr9.rest_heal_amount(30, 70, 100)) == 30 and int(lr9.rest_heal_amount(30, 95, 100)) == 5 | (待填) | | | @@ -874,7 +874,7 @@ | 504 | 398 | "池耗即枯竭(attack/ap 令牌耗尽不出候选——%s)" ↩ % str(draw) | not draw_kinds.has("attack") and not draw_kinds.has("ap") | (待填) | | | | 505 | 399 | "池耗后候选恒 ≥2(稀有档余量——防「三选项全不可选」死角)" | (draw as Array).size() >= 2 | (待填) | | | | 506 | 408 | "池收缩——40 次重抽零 aux 候选(停点渠道 aux 卡退役,迭代 11 第①批 T7)" | not treasure_seen | (待填) | | | -| 507 | 417 | "满血通关回血 0 合法(封顶口径——heal_gained=0 非负溢出)" | int(cap["payload"].get("heal_gained", -1)) == 0 | (待填) | | | +| 507 | 417 | "满血关卡完成回血 0 合法(封顶口径——heal_gained=0 非负溢出)" | int(cap["payload"].get("heal_gained", -1)) == 0 | (待填) | | | | 508 | 420 | "节点共享池场景:冒险启动(seed 13)" | a13.start_adventure(13, {"treasure_unlocked": {"wide_scout_band": true}}) | (待填) | | | | 509 | 431 | "奖励节点共享池:令牌耗尽同样不出候选(同库同池——%s)" ↩ % str(ncands13) | not has_attack13 | (待填) | | | | 510 | 435 | "奖励节点 GP 件入账(钱包「奖励入账」收口——+%d)" ↩ % int(_db.adventure.curio_value("gp", "common")) | a13.apply_node_curio("gp", "common") and int(a13.ledger.get("gp", 0)) == gp13 + int(_db.adventure.curio_value("gp", "common")) | (待填) | | | @@ -898,7 +898,7 @@ | 523 | 502 | "新 schema 构造表 validate 零违例(四级 rarity/cap 字段/词表全过——流派标签已退役零 archetype)" | rt.validate().is_empty() | (待填) | | | | 524 | 506 | "专长带场景:冒险启动(seed 72——注入 5 行临时表)" | a_r.start_adventure(72) | (待填) | | | | 525 | 511 | "专长带入池:5 行 relic 每件 1 张(四级 rarity 直映射)——牌库 102+5=107" | deck_relic == 5 and a_r._curio_deck.size() == 107 | (待填) | | | -| 526 | 522 | "通关渠道只出专长(60 次重抽 ≥2 种不同 relic——身份键 feat_id 同档可多件)" | feat_seen.size() >= 2 | (待填) | | | +| 526 | 522 | "关卡完成渠道只出专长(60 次重抽 ≥2 种不同 relic——身份键 feat_id 同档可多件)" | feat_seen.size() >= 2 | (待填) | | | | 527 | 523 | "节点渠道零专长(60 次重抽零 relic——专长在非 Boss 渠道只以专长凭证形态出现)" | not node_relic_seen | (待填) | | | | 528 | 531 | "A5 专长凭证兑付受理(节点渠道——拿到即开)" | a_t.apply_node_curio("feat_ticket", "excellent") | (待填) | | | | 529 | 537 | "A5 拿到即开——停点候选已替换为专长三选一(全 relic)" | tkt_all_relic | (待填) | | | @@ -1213,10 +1213,10 @@ | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| | 690 | 331 | "L1 现行起关图取数非空(种子 %d × 参数档 → 节点 %d 颗)" ↩ % [ACTIVE_GRAPH_SEED, nodes1.size()] | not nodes1.is_empty() | (待填) | | | -| 691 | 334 | "关卡·满配(atk+200/hp+100)通关(实测:%s @节点 %d)" ↩ % [win.result, win.defeat_node_index] | win.result == "victory" | (待填) | | | -| 692 | 342 | "L1 通关路径逐跳为图出边(入口起步·末节点无出边——句柄轴行进自洽)" | _path_in_graph(nodes1, win.visited_ids) | (待填) | | | -| 693 | 343 | "L1 通关路径战斗/Boss 节点数 = 行进 battles 读数(路径 %d 节点·战斗 %d 颗·battles %d)" ↩ % [win.visited_ids.size(), path_battles, int(win.battles)] | path_battles == int(win.battles) and path_battles >= 2 | (待填) | | | -| 694 | 353 | "L1 终点 Boss 深度 = 参数档层高 %d 且通关路径末节点落该深度(实测终点深度 %d·末句柄 %d)" ↩ % [int(params1.get("layers", -1)), boss_depth1, last_id] | boss_depth1 == int(params1.get("layers", -1)) and int(by_id1.get(last_id, {}).get("depth", -1)) == boss_depth1 | (待填) | | | +| 691 | 334 | "关卡·满配(atk+200/hp+100)完成(实测:%s @节点 %d)" ↩ % [win.result, win.defeat_node_index] | win.result == "victory" | (待填) | | | +| 692 | 342 | "L1 关卡完成路径逐跳为图出边(入口起步·末节点无出边——句柄轴行进自洽)" | _path_in_graph(nodes1, win.visited_ids) | (待填) | | | +| 693 | 343 | "L1 关卡完成路径战斗/Boss 节点数 = 行进 battles 读数(路径 %d 节点·战斗 %d 颗·battles %d)" ↩ % [win.visited_ids.size(), path_battles, int(win.battles)] | path_battles == int(win.battles) and path_battles >= 2 | (待填) | | | +| 694 | 353 | "L1 终点 Boss 深度 = 参数档层高 %d 且关卡完成路径末节点落该深度(实测终点深度 %d·末句柄 %d)" ↩ % [int(params1.get("layers", -1)), boss_depth1, last_id] | boss_depth1 == int(params1.get("layers", -1)) and int(by_id1.get(last_id, {}).get("depth", -1)) == boss_depth1 | (待填) | | | | 695 | 355 | "L1 终点恰一个(大岔口自 L2 起的图侧投影)" | _terminal_ids(nodes1).size() == 1 and _ids_of_type(nodes1, "boss").size() == 1 | (待填) | | | | 696 | 356 | "L1 生成图含岔口(出度 ≥2 节点 %d 处)" ↩ % _fork_ids(nodes1).size() | _fork_ids(nodes1).size() >= 1 | (待填) | | | | 697 | 357 | "进 Boss HP 携带在域内(%d)" ↩ % win.hp_at_boss | win.hp_at_boss >= 1 and win.hp_at_boss <= int(_db.hero.max_hp) * 3 | (待填) | | | @@ -1248,12 +1248,12 @@ | 718 | 479 | "图校验拒绝:回边 1→0(目标深度须严格大于源)〔v1〕" | _has_err_category(LT.validate_graph(cyc), "structural") | (待填) | | | | 719 | 482 | "图校验拒绝:出边指向不存在句柄(悬空致命)〔v1〕" | _has_err_category(LT.validate_graph(dang), "dangling_next") | (待填) | | | | 720 | 488 | "图校验拒绝:非 Boss 终点(终点恒为 Boss)〔v1〕" | _has_err_category(LT.validate_graph(orphan), "structural") | (待填) | | | -| 721 | 491 | "L2·满配 min 路径通关(实测:%s)" ↩ % win_min.result | win_min.result == "victory" | (待填) | | | +| 721 | 491 | "L2·满配 min 路径完成(实测:%s)" ↩ % win_min.result | win_min.result == "victory" | (待填) | | | | 722 | 496 | "L2 min 路径逐跳为图出边·末节点为 Boss(实测路径 %s·末句柄型别 %s)" ↩ % [str(win_min.visited_ids), n2_last_type] | _path_in_graph(nodes2, win_min.visited_ids) and n2_last_type == "boss" | (待填) | | | | 723 | 498 | "L2 min 路径终点深度 = 参数档层高 %d(行进读数 %d——终点落最长路径步数)" ↩ % [int(params2.get("layers", -1)), int(win_min.boss_depth)] | int(win_min.boss_depth) == int(params2.get("layers", -1)) | (待填) | | | | 724 | 500 | "L2 min 路径穿商店恰 1 家(路径句柄 %s 型别计数 = 1——必经恰一店的行进面)" ↩ % str(win_min.visited_ids) | _path_shop_count(nodes2, win_min.visited_ids) == 1 | (待填) | | | | 725 | 502 | "选路口发生 %d 次(每节点兑付后——零自动推进)" ↩ % win_min.choices | win_min.choices >= 3 | (待填) | | | -| 726 | 504 | "L2·满配 max 路径(候选取最大句柄)通关(实测:%s·路径 %s)" ↩ % [win_max.result, str(win_max.visited_ids)] | win_max.result == "victory" | (待填) | | | +| 726 | 504 | "L2·满配 max 路径(候选取最大句柄)完成(实测:%s·路径 %s)" ↩ % [win_max.result, str(win_max.visited_ids)] | win_max.result == "victory" | (待填) | | | | 727 | 509 | "L2 max 路径逐跳为图出边·末节点为 Boss·穿商店恰 1 家" | _path_in_graph(nodes2, win_max.visited_ids) and n2_last_max_type == "boss" and _path_shop_count(nodes2, win_max.visited_ids) == 1 | (待填) | | | | 728 | 512 | "L2 max 与 min 路径分岔(方向轴生效——两路终点句柄 %d / %d 不同)" ↩ % [n2_last, n2_last_max] | n2_last != n2_last_max and win_max.visited_ids != win_min.visited_ids | (待填) | | | | 729 | 519 | "手动驱动:L2 启动(入口战斗直接开打——入口无前置兑付;图 = 参数档 × 种子 %d)" ↩ % ACTIVE_GRAPH_SEED | runner.start_level(2, ACTIVE_GRAPH_SEED) | (待填) | | | @@ -1474,17 +1474,17 @@ | 889 | 173 | "余额 = 累计入账(逐杀掉落合计——无重复加账)" | sv.keystone_balance() == int(row1.get("first_kill", 0)) | (待填) | | | | 890 | 181 | "再通 L1:{first:false, amount=repeat_kill}(首杀标记置位后转小额)" | not bool(drop2.get("first", true)) and int(drop2.get("amount", 0)) == int(row1.get("repeat_kill", -1)) | (待填) | | | | 891 | 187 | "重复杀第三轮恒定不递减(验收5——无衰减曲线)" | not bool(d3["boss_drops"][0].get("first", true)) and int(d3["boss_drops"][0].get("amount", 0)) == int(row1.get("repeat_kill", -1)) | (待填) | | | -| 892 | 195 | "两关通关逐关归因:L1 重复档 + L2 首杀档(first_kill 金额)" | not bool(d4["boss_drops"][0].get("first", true)) and bool(d4["boss_drops"][1].get("first", false)) and int(d4["boss_drops"][1].get("amount", 0)) == int(row2.get("first_kill", -1)) | (待填) | | | -| 893 | 203 | "败北零通关摘要:零入账零标记(钥石只增不减——验收1;败北局 clear_counts 不变)" | dz["boss_drops"].is_empty() and sv.keystone_balance() == bal_before and sv.clear_count(1) == cc1_before | (待填) | | | +| 892 | 195 | "两关完成逐关归因:L1 重复档 + L2 首杀档(first_kill 金额)" | not bool(d4["boss_drops"][0].get("first", true)) and bool(d4["boss_drops"][1].get("first", false)) and int(d4["boss_drops"][1].get("amount", 0)) == int(row2.get("first_kill", -1)) | (待填) | | | +| 893 | 203 | "败北零关卡完成摘要:零入账零标记(钥石只增不减——验收1;败北局 clear_counts 不变)" | dz["boss_drops"].is_empty() and sv.keystone_balance() == bal_before and sv.clear_count(1) == cc1_before | (待填) | | | | 894 | 210 | "条件件误购拒绝(购买件专属——契约 8 分配面)〔秘宝批 V3 反例〕" | not mp_u.buy_treasure_unlock("sky_eye") and not sv_u.item_unlocked("sky_eye") and not mp_u.buy_treasure_unlock("ranged_pick") | (待填) | | | | 895 | 213 | "余额不足购买拒绝且零副作用(余额 10 < 价 25)〔秘宝批 V3〕" | not mp_u.buy_treasure_unlock("twin_loader") and sv_u.keystone_balance() == 10 | (待填) | | | | 896 | 215 | "钥石购买解锁:余额足→解锁态落档+余额扣减正确(价 10)〔秘宝批 V3〕" | mp_u.buy_treasure_unlock("morning_order") and sv_u.item_unlocked("morning_order") and sv_u.keystone_balance() == 0 | (待填) | | | | 897 | 218 | "已解锁重复购买拒绝〔秘宝批 V3〕" | not mp_u.buy_treasure_unlock("morning_order") | (待填) | | | -| 898 | 220 | "条件未达不解锁(远程镐=通关 1 次)〔秘宝批 V4〕" | mp_u.refresh_treasure_unlocks().is_empty() and not sv_u.item_unlocked("ranged_pick") | (待填) | | | -| 899 | 223 | "远程镐=adventure_cleared≥1 达标恰解锁一次+重复刷新幂等(C6:通关=打通整局冒险)〔秘宝批 V4〕" | (mp_u.refresh_treasure_unlocks() as Array).has("ranged_pick") and sv_u.item_unlocked("ranged_pick") and mp_u.refresh_treasure_unlocks().is_empty() | (待填) | | | +| 898 | 220 | "条件未达不解锁(远程镐=冒险成功 1 次)〔秘宝批 V4〕" | mp_u.refresh_treasure_unlocks().is_empty() and not sv_u.item_unlocked("ranged_pick") | (待填) | | | +| 899 | 223 | "远程镐=adventure_cleared≥1 达标恰解锁一次+重复刷新幂等(C6:冒险成功=打通整局冒险)〔秘宝批 V4〕" | (mp_u.refresh_treasure_unlocks() as Array).has("ranged_pick") and sv_u.item_unlocked("ranged_pick") and mp_u.refresh_treasure_unlocks().is_empty() | (待填) | | | | 900 | 227 | "刷新执照=boss_kill_count≥3(阈值读 unlock_requires 行值不硬编)〔秘宝批 V4〕" | (mp_u.refresh_treasure_unlocks() as Array).has("refresh_license") | (待填) | | | | 901 | 230 | "天眼单条件不足不解锁(AND 语义——cleared 3 达 boss 4 未达)〔秘宝批 V4〕" | not sv_u.item_unlocked("sky_eye") | (待填) | | | -| 902 | 233 | "天眼双条件 AND(通关≥3 且 Boss≥4)达标解锁〔秘宝批 V4〕" | (mp_u.refresh_treasure_unlocks() as Array).has("sky_eye") | (待填) | | | +| 902 | 233 | "天眼双条件 AND(冒险成功≥3 且 Boss≥4)达标解锁〔秘宝批 V4〕" | (mp_u.refresh_treasure_unlocks() as Array).has("sky_eye") | (待填) | | | | 903 | 236 | "信标网络=真视类工具累计使用≥10(行为计数新域——use_treasure 受理成功累计)〔秘宝批 V4〕" | (mp_u.refresh_treasure_unlocks() as Array).has("beacon_network") | (待填) | | | | 904 | 241 | "解锁态持久投影一致(reload 面同源读数;5 件=购买 1+条件 4)〔秘宝批 V4〕" | r_n == 5 | (待填) | | | | 905 | 244 | "摘要最新在前 + 元素含掉落明细副本(复盘可归因——验收5)" | rs.size() >= 5 and String(rs[0].get("result", "")) != "" and rs[0].has("boss_drops") and (rs[1] as Dictionary).has("keystone_drops") and int(rs[0].get("master_seed", -1)) == 15 | (待填) | | | @@ -1492,7 +1492,7 @@ | 907 | 258 | "白板档同调位求值 = 0(0 起步裁决)且 Y=0(未购无刷新能力——P1 甲初始 0 同构)" | Attunement.slots(_db, sv_a) == 0 and int(mp_a.attune_camp_status()["refresh"]["charges"]) == 0 | (待填) | | | | 908 | 260 | "满位禁选(Slots 0 时装配拒绝;兼未解锁拒绝前置——直置解锁后下方装配)〔秘宝批 V5〕" | mp_a.toggle_attunement("morning_order") == false | (待填) | | | | 909 | 265 | "Y 升级购买入账(Lv1 → 每冒险 +1 次刷新)" | mp_a.buy_attune_refresh() and sv_a.attune_refresh_level() == 1 and int(mp_a.attune_camp_status()["refresh"]["charges"]) == 1 | (待填) | | | -| 910 | 270 | "通关 1 关 → Slots 恒 0(旧「按击杀 Boss 次数自动涨」条件已删——槽位唯一来源=树点亮)且 Boss 击杀总数=1(计数域保留)〔天赋树批 V14〕" | Attunement.slots(_db, sv_a) == 0 and sv_a.boss_kill_count() == 1 | (待填) | | | +| 910 | 270 | "完成 1 关 → Slots 恒 0(旧「按击杀 Boss 次数自动涨」条件已删——槽位唯一来源=树点亮)且 Boss 击杀总数=1(计数域保留)〔天赋树批 V14〕" | Attunement.slots(_db, sv_a) == 0 and sv_a.boss_kill_count() == 1 | (待填) | | | | 911 | 273 | "树上点亮同调位 1 → Slots=1(槽位收编树节点——Q2 裁甲)" | Attunement.slots(_db, sv_a) == 1 | (待填) | | | | 912 | 275 | "稀有件入普通格拒绝(件档 rank 3 > 装入位序 1——契约 2 档位格校验)〔秘宝批 V5〕" | not mp_a.toggle_attunement("sky_eye") | (待填) | | | | 913 | 277 | "装配持久写入 + 满位禁选(Slots 1 装第二件拒绝)〔秘宝批 V5 换主语〕" | mp_a.toggle_attunement("morning_order") and mp_a.toggle_attunement("twin_loader") == false | (待填) | | | @@ -1763,16 +1763,16 @@ | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1071 | 81 | "apply 原语入账(钥石 7+3、通关次数 1/1/0)" | w.keystone_balance() == 10 and w.clear_count(1) == 1 and w.clear_count(2) == 1 and w.clear_count(3) == 0 | (待填) | | | -| 1072 | 83 | "首杀标记随通关关卡置位(1/2 有、3 无)" | w.boss_first_kill_marked(1) and w.boss_first_kill_marked(2) and not w.boss_first_kill_marked(3) | (待填) | | | -| 1073 | 85 | "生涯终身计数随 apply 自增恰一(中止局:总局数 1、通关局数 0——迭代 18 卡④)" | w.adventure_total() == 1 and w.adventure_cleared() == 0 | (待填) | | | +| 1071 | 81 | "apply 原语入账(钥石 7+3、关卡完成次数 1/1/0)" | w.keystone_balance() == 10 and w.clear_count(1) == 1 and w.clear_count(2) == 1 and w.clear_count(3) == 0 | (待填) | | | +| 1072 | 83 | "首杀标记随关卡完成置位(1/2 有、3 无)" | w.boss_first_kill_marked(1) and w.boss_first_kill_marked(2) and not w.boss_first_kill_marked(3) | (待填) | | | +| 1073 | 85 | "生涯终身计数随 apply 自增恰一(中止局:总局数 1、冒险成功局数 0——迭代 18 卡④)" | w.adventure_total() == 1 and w.adventure_cleared() == 0 | (待填) | | | | 1074 | 87 | "写盘成功" | w.write_to_disk() | (待填) | | | | 1075 | 89 | "读回成功" | r.load_from_disk() | (待填) | | | | 1076 | 90 | "钥石余额往返相等(10)" | r.keystone_balance() == 10 | (待填) | | | | 1077 | 91 | "树域往返相等(tree_nodes/fork_sides——迭代 21 换代承载)" | r.tree_level("sp_hp") == 2 and r.tree_level("sp_hit") == 1 and r.fork_side("fg_posture") == "b" | (待填) | | | | 1078 | 93 | "锻造工坊域往返相等(levels/unlocked/weapon/armor——迭代 23 T5)〔锻造工坊批 V8〕" | r.forge_route_level("spear") == 3 and r.forge_route_level("sword") == 0 and r.forge_unlocked_purchases() == ["spear"] and r.forge_weapon() == "spear" and r.forge_armor() == "ward" | (待填) | | | | 1079 | 97 | "道具解锁往返相等" | r.item_unlocked("probe_compass") and not r.item_unlocked("rope") | (待填) | | | -| 1080 | 98 | "通关次数表往返相等" | r.clear_count(1) == 1 and r.clear_count(2) == 1 and r.clear_count(3) == 0 | (待填) | | | +| 1080 | 98 | "关卡完成次数表往返相等" | r.clear_count(1) == 1 and r.clear_count(2) == 1 and r.clear_count(3) == 0 | (待填) | | | | 1081 | 99 | "首杀标记往返相等" | r.boss_first_kill_marked(1) and r.boss_first_kill_marked(2) and not r.boss_first_kill_marked(3) | (待填) | | | | 1082 | 101 | "生涯终身计数往返相等(1/0)" | r.adventure_total() == 1 and r.adventure_cleared() == 0 | (待填) | | | | 1083 | 103 | "冒险摘要往返相等(1 条,seed 99)" | r.recent_summaries().size() == 1 and int(s0.get("master_seed", -1)) == 99 and int(s0.get("keystone_total", -1)) == 3 | (待填) | | | @@ -1812,8 +1812,8 @@ | 1117 | 248 | "v2 旧断点续玩受理(缺 bonus 附随件走常规重建路径——g 裁 semver 口径)" | adr_v2.resume_adventure(fv2.breakpoint_snapshot(), {"hero_override": {}}) | (待填) | | | | 1118 | 257 | "v5 旧档升 v7:计数域缺省补零且既有余额原样(迁移只增字段不改值——v5→v6→v7 链式)" | f13.load_from_disk() and f13.adventure_total() == 0 and f13.adventure_cleared() == 0 and f13.keystone_balance() == 9 | (待填) | | | | 1119 | 260 | "升档幂等:v7 档写盘再载零漂移(重复迁移零副作用——锻造工坊域同批补齐)" | f13.write_to_disk() and f13.load_from_disk() and int(JSON.parse_string(FileAccess.open(paths[11], FileAccess.READ).get_as_text()).get("version", -1)) == 7 and f13.adventure_total() == 0 and f13.adventure_cleared() == 0 | (待填) | | | -| 1120 | 268 | "收束自增恰一·通关局(三关全通 cleared=true:总局数+1 且通关局数+1)" | f13b.adventure_total() == 1 and f13b.adventure_cleared() == 1 | (待填) | | | -| 1121 | 272 | "收束自增恰一·中止局(放弃局:仅总局数+1,通关局数不动)" | f13b.adventure_total() == 2 and f13b.adventure_cleared() == 1 | (待填) | | | +| 1120 | 268 | "收束自增恰一·冒险成功局(三关全通 cleared=true:总局数+1 且冒险成功局数+1)" | f13b.adventure_total() == 1 and f13b.adventure_cleared() == 1 | (待填) | | | +| 1121 | 272 | "收束自增恰一·中止局(放弃局:仅总局数+1,冒险成功局数不动)" | f13b.adventure_total() == 2 and f13b.adventure_cleared() == 1 | (待填) | | | | 1122 | 283 | "换代前结构存档:树域废弃重置(旧节点 id/fork 侧/forge_levels 旧域残留清退)、钥石余额零折算零变动" | f15.load_from_disk() and f15.keystone_balance() == 33 and f15.tree_nodes().is_empty() and f15.fork_sides().is_empty() | (待填) | | | | 1123 | 288 | "废弃重置后后续购买正常受理(无残留脏节点)" | mp16.tree_buy("sp_hp") and f15.tree_level("sp_hp") == 1 | (待填) | | | | 1124 | 297 | "v6 旧档升 v7:既有域逐位不动(钥石/树/生涯计数零折算——迁移只增不改)〔锻造工坊批 V8〕" | f16.load_from_disk() and f16.keystone_balance() == 21 and f16.tree_level("sp_hp") == 1 and f16.adventure_total() == 4 and f16.adventure_cleared() == 1 | (待填) | | | @@ -1821,8 +1821,8 @@ | 1126 | 307 | "forge_routes 域键集恰四项(无特效域——满级特效本期不做,契约 7)〔锻造工坊批 V8/V11〕" | fr_keys == ["armor", "levels", "unlocked", "weapon"] | (待填) | | | | 1127 | 311 | "levels 六路线键集恰全(sword/spear/staff/light/heavy/ward)〔锻造工坊批 V8〕" | lv_keys == ["heavy", "light", "spear", "staff", "sword", "ward"] | (待填) | | | | 1128 | 316 | "forge_routes_snapshot 值拷贝出户(改快照不渗档)〔锻造工坊批 V8〕" | f16.forge_route_level("sword") == 0 | (待填) | | | -| 1129 | 324 | "收束链自增·中止局(settle_adventure 真实挂点:总局数+1、通关局数不动)" | f13b.adventure_total() == 3 and f13b.adventure_cleared() == 1 | (待填) | | | -| 1130 | 328 | "收束链自增·通关局(三关全通:总局数+1 且通关局数+1——全链恰一)" | f13b.adventure_total() == 4 and f13b.adventure_cleared() == 2 | (待填) | | | +| 1129 | 324 | "收束链自增·中止局(settle_adventure 真实挂点:总局数+1、冒险成功局数不动)" | f13b.adventure_total() == 3 and f13b.adventure_cleared() == 1 | (待填) | | | +| 1130 | 328 | "收束链自增·冒险成功局(三关全通:总局数+1 且冒险成功局数+1——全链恰一)" | f13b.adventure_total() == 4 and f13b.adventure_cleared() == 2 | (待填) | | | ## S137 _smoke_save_slots(行 359–499 · 31 条 · 源 game/tests/unit/core/save_manager_domain_test.gd · 去向:待分类回填) @@ -2061,7 +2061,7 @@ |---|---|---|---|---|---|---| | 1252 | 92 | "db.adventure 已加载(adventure.tres 入 manifest)" | _db.adventure != null | (待填) | | | | 1253 | 95 | "AdventureTable.validate() 零违例(全键域检+档位配额结构锚在案)" | _db.adventure.validate().is_empty() | (待填) | | | -| 1254 | 96 | "clear_heal_pct ∈ [0,100](%d——通关部分回血比例)" ↩ % int(_db.adventure.clear_heal_pct) | int(_db.adventure.clear_heal_pct) >= 0 and int(_db.adventure.clear_heal_pct) <= 100 | (待填) | | | +| 1254 | 96 | "clear_heal_pct ∈ [0,100](%d——关卡完成部分回血比例)" ↩ % int(_db.adventure.clear_heal_pct) | int(_db.adventure.clear_heal_pct) >= 0 and int(_db.adventure.clear_heal_pct) <= 100 | (待填) | | | | 1255 | 99 | "档位配额结构锚(四级 70/25/7/0——迭代 31 卡② 净删两件投放):%s = %d 张" ↩ % [tier, int(_db.adventure.TIER_QUOTAS[tier])] | int(_db.adventure.tier_total(tier)) == int(_db.adventure.TIER_QUOTAS[tier]) | (待填) | | | | 1256 | 101 | "令牌池总量 = 102 张(四级 普通 70/优秀 25/稀有 7/传说 0——迭代 31 卡② 净删两件投放 104→102)〔凭证裁削批 V5〕" | int(_db.adventure.deck_total()) == 102 | (待填) | | | | 1257 | 102 | "数值对(四级换代承袭):小GP 20/大GP 50 · 小增伤 +1/大 +2 · 小生命 +5/大 +10 · 小护甲 +1/大 +2" | int(_db.adventure.curio_value("gp", "common")) == 20 and int(_db.adventure.curio_value("gp", "excellent")) == 50 and int(_db.adventure.curio_value("attack", "common")) == 1 and int(_db.adventure.curio_value("attack", "excellent")) == 2 and int(_db.adventure.curio_value("max_hp", "common")) == 5 and int(_db.adventure.curio_value("max_hp", "excellent")) == 10 and int(_db.adventure.curio_value("armor", "common")) == 1 and int(_db.adventure.curio_value("armor", "excellent")) == 2 | (待填) | | | @@ -2137,7 +2137,7 @@ | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| | 1304 | 452 | "格面资源十型封闭(第九型 gp 九型批 2026-09-20 / 第十型 treasure_item 秘宝内容批 2026-09-29——词表 v1.2)" | RewardTable.CELL_TYPES.size() == 10 and RewardTable.CELL_TYPES.has("gp") and RewardTable.CELL_TYPES.has("treasure_item") | (待填) | | | -| 1305 | 467 | "奖励字典 18 行(九型×正负 18 格——aux 挖格投放四行已退役 2026-10-01 用户拍板甲:战斗/挖格不掉道具,秘宝唯一来路=三选一共享池〔节点/通关〕;清图槽独立批尾不计)" | cell_rows == 18 | (待填) | | | +| 1305 | 467 | "奖励字典 18 行(九型×正负 18 格——aux 挖格投放四行已退役 2026-10-01 用户拍板甲:战斗/挖格不掉道具,秘宝唯一来路=三选一共享池〔节点/关卡完成〕;清图槽独立批尾不计)" | cell_rows == 18 | (待填) | | | | 1306 | 474 | "危险格负向直伤 %s power=%d(卡⑧投值)" ↩ % [rid, int(mine_power[rid])] | int(row.get("power", -1)) == int(mine_power[rid]) | (待填) | | | | 1307 | 487 | "正向 cell 行权重 ≥1 全在池 / 负向行权重恒 0 不入池(正向合计 %d——配置推导)" ↩ % pos_weight | pos_all_in_pool and neg_all_zero | (待填) | | | | 1308 | 489 | "gp 型两行(GP 袋 gp_gain 正向 weight 2 / 破财 gp_loss 负向 weight 0 不入池)" | gp_pos == 2 and gp_neg == 0 | (待填) | | | @@ -2159,483 +2159,501 @@ | 1314 | 13 | "headless SceneTree 协议可用(quit(code) 通道)" | _test_headless_protocol() | (待填) | | | | 1315 | 14 | "命名规范可执行:test_[scenario]_[expected]" | _test_naming_convention_followed() | (待填) | | | -## S167 _test_numeric_lines_carry_values(行 30–35 · 3 条 · 源 game/tests/unit/presentation/battle_narrator_test.gd · 去向:待分类回填) +## S167 _test_numeric_lines_carry_values(行 31–36 · 3 条 · 源 game/tests/unit/presentation/battle_narrator_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1316 | 30 | "休整叙述带入回复量与当前血量(实际「%s」)" ↩ % rest | rest.contains("12") and rest.contains("30") and rest.contains("40") | (待填) | | | -| 1317 | 33 | "商店叙述带入 GP 数(实际「%s」)" ↩ % shop | shop.contains("77") | (待填) | | | -| 1318 | 34 | "奖励行与休整行互异(不是同一句套所有场景)" | NarratorScript.reward_line() != rest | (待填) | | | +| 1316 | 31 | "休整叙述带入回复量与当前血量(实际「%s」)" ↩ % rest | rest.contains("12") and rest.contains("30") and rest.contains("40") | (待填) | | | +| 1317 | 34 | "商店叙述带入 GP 数(实际「%s」)" ↩ % shop | shop.contains("77") | (待填) | | | +| 1318 | 35 | "奖励行与休整行互异(不是同一句套所有场景)" | NarratorScript.reward_line() != rest | (待填) | | | -## S168 _test_end_text_differs_by_result(行 41–47 · 4 条 · 源 game/tests/unit/presentation/battle_narrator_test.gd · 去向:待分类回填) +## S168 _test_end_text_differs_by_result(行 42–48 · 4 条 · 源 game/tests/unit/presentation/battle_narrator_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1319 | 41 | "关卡收束态恒为「关卡通关!」(实际「%s」)" ↩ % level | level == "关卡通关!" | (待填) | | | -| 1320 | 44 | "单场胜负文案互异(胜「%s」/负「%s」)" ↩ % [win, lose] | win != lose | (待填) | | | -| 1321 | 45 | "胜利文案非空(实际「%s」)" ↩ % win | win != "" | (待填) | | | -| 1322 | 47 | "未知结果有兜底文案不吐空串(实际「%s」)" ↩ % unknown | unknown != "" | (待填) | | | +| 1319 | 42 | "关卡收束态恒为「关卡完成!」(实际「%s」)" ↩ % level | level == "关卡完成!" | (待填) | | | +| 1320 | 45 | "单场胜负文案互异(胜「%s」/负「%s」)" ↩ % [win, lose] | win != lose | (待填) | | | +| 1321 | 46 | "胜利文案非空(实际「%s」)" ↩ % win | win != "" | (待填) | | | +| 1322 | 48 | "未知结果有兜底文案不吐空串(实际「%s」)" ↩ % unknown | unknown != "" | (待填) | | | -## S169 _test_phase_text_nonempty(行 52–54 · 2 条 · 源 game/tests/unit/presentation/battle_narrator_test.gd · 去向:待分类回填) +## S169 _test_phase_text_nonempty(行 53–55 · 2 条 · 源 game/tests/unit/presentation/battle_narrator_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1323 | 52 | "相位叙述非空(实际「%s」)" ↩ % t | t != "" | (待填) | | | -| 1324 | 54 | "Boss 在场时叙述带入 Boss 名(实际「%s」)" ↩ % boss | boss.contains("灰矮人石君王") | (待填) | | | +| 1323 | 53 | "相位叙述非空(实际「%s」)" ↩ % t | t != "" | (待填) | | | +| 1324 | 55 | "Boss 在场时叙述带入 Boss 名(实际「%s」)" ↩ % boss | boss.contains("灰矮人石君王") | (待填) | | | -## S170 _test_boss_name_uses_boss_rowset(行 81–82 · 2 条 · 源 game/tests/unit/presentation/battle_narrator_test.gd · 去向:待分类回填) +## S170 _test_boss_name_uses_boss_rowset(行 82–83 · 2 条 · 源 game/tests/unit/presentation/battle_narrator_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1325 | 81 | "Boss 名取自 Boss 行集首行(期望「%s」实际「%s」)〔fv24〕" ↩ % [boss_expect, got] | got == boss_expect | (待填) | | | -| 1326 | 82 | "Boss 名与同深度战斗行集名不同(期望「%s」≠「%s」——行类路由可判别)〔fv24〕" ↩ % [boss_expect, battle_name] | boss_expect != battle_name | (待填) | | | +| 1325 | 82 | "Boss 名取自 Boss 行集首行(期望「%s」实际「%s」)〔fv24〕" ↩ % [boss_expect, got] | got == boss_expect | (待填) | | | +| 1326 | 83 | "Boss 名与同深度战斗行集名不同(期望「%s」≠「%s」——行类路由可判别)〔fv24〕" ↩ % [boss_expect, battle_name] | boss_expect != battle_name | (待填) | | | -## S171 _run(行 27–102 · 13 条 · 源 game/tests/unit/presentation/forge_workbench_test.gd · 去向:待分类回填) +## S171 _test_level_clear_wording(行 90–101 · 4 条 · 源 game/tests/unit/presentation/battle_narrator_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1327 | 27 | "ConfigDb 加载(工作间测试夹具前提)" | false | (待填) | | | -| 1328 | 44 | "锁定态:工作间不可见(forge_workshop 钥匙未点亮)〔锻造工坊批 V13〕" | not ov._forge_workbench.visible and ov._forge_lock_l.visible | (待填) | | | -| 1329 | 46 | "锁定态:两区零行板(占位纪律——零购买路径)〔锻造工坊批 V13〕" | ov._forge_zone_weapon.get_child_count() == 0 and ov._forge_zone_armor.get_child_count() == 0 | (待填) | | | -| 1330 | 52 | "解锁态:工作间可见(钥匙点亮展开)〔锻造工坊批 V13〕" | ov._forge_workbench.visible | (待填) | | | -| 1331 | 53 | "两区各三路线(武器锻造区 3 + 护甲锻造区 3)〔锻造工坊批 V13〕" | ov._forge_zone_weapon.get_child_count() == 3 and ov._forge_zone_armor.get_child_count() == 3 | (待填) | | | -| 1332 | 56 | "六路线行册恰全(sword/spear/staff/light/heavy/ward)〔锻造工坊批 V13〕" | rows.has("sword") and rows.has("spear") and rows.has("staff") and rows.has("light") and rows.has("heavy") and rows.has("ward") | (待填) | | | -| 1333 | 63 | "长剑行:购买钮「锻造 20」(0 级位几何价)+选中钮「当前」禁用〔锻造工坊批 V13〕" | rsw.get("buy_btn") != null and String(rsw.buy_btn.text) == "锻造 20" and not rsw.buy_btn.disabled and rsw.get("select_btn") != null and String(rsw.select_btn.text) == "当前" and rsw.select_btn.disabled | (待填) | | | -| 1334 | 66 | "轻甲行:购买钮「锻造 20」+选中钮「当前」禁用〔锻造工坊批 V13〕" | rli.get("buy_btn") != null and String(rli.buy_btn.text) == "锻造 20" and String(rli.select_btn.text) == "当前" and rli.select_btn.disabled | (待填) | | | -| 1335 | 73 | "长枪行:解锁钮「解锁 200」+无购买钮+无选中钮〔锻造工坊批 V13〕" | rsp.get("unlock_btn") != null and String(rsp.unlock_btn.text) == "解锁 200" and not rsp.unlock_btn.disabled and rsp.get("buy_btn") == null and rsp.get("select_btn") == null | (待填) | | | -| 1336 | 76 | "魔法护甲行:解锁钮「解锁 200」+状态含并联双通道文案(练满轻甲锻造 或 200 钥石直购)〔锻造工坊批 V13〕" | rwa.get("unlock_btn") != null and String(rwa.status_l.text).contains("练满轻甲锻造") and String(rwa.status_l.text).contains("200") | (待填) | | | -| 1337 | 84 | "余额 0:长剑购买钮禁用+长枪解锁钮禁用(余额联动常态防线)〔锻造工坊批 V13〕" | rows.sword.buy_btn.disabled and rows.spear.unlock_btn.disabled | (待填) | | | -| 1338 | 92 | "长剑满级:无购买钮+状态「已满级」+长枪派生解锁出解锁钮消失(练满通道)〔锻造工坊批 V13〕" | rows.sword.get("buy_btn") == null and String(rows.sword.status_l.text) == "已满级" and rows.spear.get("unlock_btn") == null and rows.spear.get("buy_btn") != null | (待填) | | | -| 1339 | 101 | "三意图信号外发(buy=spear/unlock=heavy/select=spear——UI 只发意图)〔锻造工坊批 V13〕" | buys == ["spear"] and unlocks == ["heavy"] and selects == ["spear"] | (待填) | | | +| 1327 | 90 | "关卡完成回血行带入回血量与生命区间(实际「%s」)〔口径换代 V1〕" ↩ % healed | healed.contains("关卡完成回血 +5(生命 10 → 15)") | (待填) | | | +| 1328 | 93 | "满血零回血合法态文案(实际「%s」)〔口径换代 V1〕" ↩ % full_hp | full_hp.contains("生命已满——关卡完成回血 0(合法态)") | (待填) | | | +| 1329 | 96 | "奖励节点头部行渠道句点明关卡完成三选一(实际「%s」)〔口径换代 V2〕" ↩ % node_header | node_header.contains("与关卡完成专长三选一同库分流") | (待填) | | | +| 1330 | 100 | "冒险摘要完成关数行(实际「%s」)〔口径换代 V3〕" ↩ % summary | summary.contains("完成 1 关 · 止步第 2 层") and not summary.contains("通关") | (待填) | | | -## S172 _test_accepted_text(行 20–20 · 1 条 · 源 game/tests/unit/presentation/hud_presenter_test.gd · 去向:待分类回填) +## S172 _run(行 27–102 · 13 条 · 源 game/tests/unit/presentation/forge_workbench_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1340 | 20 | "受理态文案固定为「执行完成。」(实际「%s」)" ↩ % t | t == "执行完成。" | (待填) | | | +| 1331 | 27 | "ConfigDb 加载(工作间测试夹具前提)" | false | (待填) | | | +| 1332 | 44 | "锁定态:工作间不可见(forge_workshop 钥匙未点亮)〔锻造工坊批 V13〕" | not ov._forge_workbench.visible and ov._forge_lock_l.visible | (待填) | | | +| 1333 | 46 | "锁定态:两区零行板(占位纪律——零购买路径)〔锻造工坊批 V13〕" | ov._forge_zone_weapon.get_child_count() == 0 and ov._forge_zone_armor.get_child_count() == 0 | (待填) | | | +| 1334 | 52 | "解锁态:工作间可见(钥匙点亮展开)〔锻造工坊批 V13〕" | ov._forge_workbench.visible | (待填) | | | +| 1335 | 53 | "两区各三路线(武器锻造区 3 + 护甲锻造区 3)〔锻造工坊批 V13〕" | ov._forge_zone_weapon.get_child_count() == 3 and ov._forge_zone_armor.get_child_count() == 3 | (待填) | | | +| 1336 | 56 | "六路线行册恰全(sword/spear/staff/light/heavy/ward)〔锻造工坊批 V13〕" | rows.has("sword") and rows.has("spear") and rows.has("staff") and rows.has("light") and rows.has("heavy") and rows.has("ward") | (待填) | | | +| 1337 | 63 | "长剑行:购买钮「锻造 20」(0 级位几何价)+选中钮「当前」禁用〔锻造工坊批 V13〕" | rsw.get("buy_btn") != null and String(rsw.buy_btn.text) == "锻造 20" and not rsw.buy_btn.disabled and rsw.get("select_btn") != null and String(rsw.select_btn.text) == "当前" and rsw.select_btn.disabled | (待填) | | | +| 1338 | 66 | "轻甲行:购买钮「锻造 20」+选中钮「当前」禁用〔锻造工坊批 V13〕" | rli.get("buy_btn") != null and String(rli.buy_btn.text) == "锻造 20" and String(rli.select_btn.text) == "当前" and rli.select_btn.disabled | (待填) | | | +| 1339 | 73 | "长枪行:解锁钮「解锁 200」+无购买钮+无选中钮〔锻造工坊批 V13〕" | rsp.get("unlock_btn") != null and String(rsp.unlock_btn.text) == "解锁 200" and not rsp.unlock_btn.disabled and rsp.get("buy_btn") == null and rsp.get("select_btn") == null | (待填) | | | +| 1340 | 76 | "魔法护甲行:解锁钮「解锁 200」+状态含并联双通道文案(练满轻甲锻造 或 200 钥石直购)〔锻造工坊批 V13〕" | rwa.get("unlock_btn") != null and String(rwa.status_l.text).contains("练满轻甲锻造") and String(rwa.status_l.text).contains("200") | (待填) | | | +| 1341 | 84 | "余额 0:长剑购买钮禁用+长枪解锁钮禁用(余额联动常态防线)〔锻造工坊批 V13〕" | rows.sword.buy_btn.disabled and rows.spear.unlock_btn.disabled | (待填) | | | +| 1342 | 92 | "长剑满级:无购买钮+状态「已满级」+长枪派生解锁出解锁钮消失(练满通道)〔锻造工坊批 V13〕" | rows.sword.get("buy_btn") == null and String(rows.sword.status_l.text) == "已满级" and rows.spear.get("unlock_btn") == null and rows.spear.get("buy_btn") != null | (待填) | | | +| 1343 | 101 | "三意图信号外发(buy=spear/unlock=heavy/select=spear——UI 只发意图)〔锻造工坊批 V13〕" | buys == ["spear"] and unlocks == ["heavy"] and selects == ["spear"] | (待填) | | | -## S173 _test_reject_text_by_reason(行 36–38 · 2 条 · 源 game/tests/unit/presentation/hud_presenter_test.gd · 去向:待分类回填) +## S173 _test_accepted_text(行 20–20 · 1 条 · 源 game/tests/unit/presentation/hud_presenter_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1341 | 36 | "棋盘面各拒绝原因文案逐类正确(错 %d 项 %s)" ↩ % [bad.size(), str(bad)] | bad.is_empty() | (待填) | | | -| 1342 | 38 | "资源面拒绝文案为「AP 不足。」(实际「%s」)" ↩ % ap | ap == "AP 不足。" | (待填) | | | +| 1344 | 20 | "受理态文案固定为「执行完成。」(实际「%s」)" ↩ % t | t == "执行完成。" | (待填) | | | -## S174 _test_unknown_reason_fallback(行 43–47 · 2 条 · 源 game/tests/unit/presentation/hud_presenter_test.gd · 去向:待分类回填) +## S174 _test_reject_text_by_reason(行 36–38 · 2 条 · 源 game/tests/unit/presentation/hud_presenter_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1343 | 43 | "未知拒绝原因兜底为「动作被拒。」而非空串(实际「%s」)" ↩ % t | t == "动作被拒。" | (待填) | | | -| 1344 | 47 | "棋盘面未知子因兜底带前缀可诊断(实际「%s」)" ↩ % sub | sub.begins_with("棋盘面拒绝: ") | (待填) | | | +| 1345 | 36 | "棋盘面各拒绝原因文案逐类正确(错 %d 项 %s)" ↩ % [bad.size(), str(bad)] | bad.is_empty() | (待填) | | | +| 1346 | 38 | "资源面拒绝文案为「AP 不足。」(实际「%s」)" ↩ % ap | ap == "AP 不足。" | (待填) | | | -## S175 _test_fog_hides_type(行 50–55 · 3 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) +## S175 _test_unknown_reason_fallback(行 43–47 · 2 条 · 源 game/tests/unit/presentation/hud_presenter_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1345 | 50 | "可见集内节点:图标/类型文字均绘制〔fv2〕" | bool(shown["draw_icon"]) and bool(shown["draw_label"]) | (待填) | | | -| 1346 | 53 | "雾下节点:图标与类型文字均不绘制(显隐语义,非灰化)〔fv2〕" | not bool(fogged["draw_icon"]) and not bool(fogged["draw_label"]) | (待填) | | | -| 1347 | 55 | "雾下非 Boss 节点无 Boss 描边〔fv2〕" | not bool(fogged["boss_border"]) | (待填) | | | +| 1347 | 43 | "未知拒绝原因兜底为「动作被拒。」而非空串(实际「%s」)" ↩ % t | t == "动作被拒。" | (待填) | | | +| 1348 | 47 | "棋盘面未知子因兜底带前缀可诊断(实际「%s」)" ↩ % sub | sub.begins_with("棋盘面拒绝: ") | (待填) | | | -## S176 _test_boss_exempt_and_multi_boss(行 64–72 · 4 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) +## S176 _test_fog_hides_type(行 50–55 · 3 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1348 | 64 | "多终点:两个 Boss 节点均带 Boss 描边〔fv3〕" | bool(boss_a["boss_border"]) and bool(boss_b["boss_border"]) | (待填) | | | -| 1349 | 66 | "Boss 不入雾:可见集与图标/文字三通道均在〔fv3〕" | bool(boss_a["draw_icon"]) and bool(boss_a["draw_label"]) and bool(boss_b["draw_icon"]) | (待填) | | | -| 1350 | 69 | "Boss 豁免独立于可见集:不在 type_vis 的 Boss 仍出示类型〔fv3〕" | bool(far_boss["draw_icon"]) and bool(far_boss["draw_label"]) | (待填) | | | -| 1351 | 72 | "Boss 豁免不扩散:雾下非 Boss 仍隐类型〔fv3〕" | not bool(fogged_battle["draw_icon"]) | (待填) | | | +| 1349 | 50 | "可见集内节点:图标/类型文字均绘制〔fv2〕" | bool(shown["draw_icon"]) and bool(shown["draw_label"]) | (待填) | | | +| 1350 | 53 | "雾下节点:图标与类型文字均不绘制(显隐语义,非灰化)〔fv2〕" | not bool(fogged["draw_icon"]) and not bool(fogged["draw_label"]) | (待填) | | | +| 1351 | 55 | "雾下非 Boss 节点无 Boss 描边〔fv2〕" | not bool(fogged["boss_border"]) | (待填) | | | -## S177 _test_details_never_shown(行 86–88 · 2 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) +## S177 _test_boss_exempt_and_multi_boss(行 64–72 · 4 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1352 | 86 | "决策面不消费内容键:携带 enemy_id/reward_id 与不带者输出逐键相等〔fv5〕" | same | (待填) | | | -| 1353 | 87 | "label_text 不含内容值(实际「%s」)〔fv5〕" ↩ % String(b["label_text"]) | not String(b["label_text"]).contains("goblin_secret") and not String(b["label_text"]).contains("reward_secret") | (待填) | | | +| 1352 | 64 | "多终点:两个 Boss 节点均带 Boss 描边〔fv3〕" | bool(boss_a["boss_border"]) and bool(boss_b["boss_border"]) | (待填) | | | +| 1353 | 66 | "Boss 不入雾:可见集与图标/文字三通道均在〔fv3〕" | bool(boss_a["draw_icon"]) and bool(boss_a["draw_label"]) and bool(boss_b["draw_icon"]) | (待填) | | | +| 1354 | 69 | "Boss 豁免独立于可见集:不在 type_vis 的 Boss 仍出示类型〔fv3〕" | bool(far_boss["draw_icon"]) and bool(far_boss["draw_label"]) | (待填) | | | +| 1355 | 72 | "Boss 豁免不扩散:雾下非 Boss 仍隐类型〔fv3〕" | not bool(fogged_battle["draw_icon"]) | (待填) | | | -## S178 _test_label_three_states(行 95–100 · 3 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) +## S178 _test_details_never_shown(行 86–88 · 2 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1354 | 95 | "当前位文案=「当前位置」〔fv2〕" | String(ScreenScript.node_display(node, 3, [3], true, false)["label_text"]) == "当前位置" | (待填) | | | -| 1355 | 97 | "候选文案=「战斗 · 可选」〔fv2〕" | String(ScreenScript.node_display(node, 3, [3], false, true)["label_text"]) == "战斗 · 可选" | (待填) | | | -| 1356 | 99 | "其余文案=类型名「战斗」〔fv2〕" | String(ScreenScript.node_display(node, 3, [3], false, false)["label_text"]) == "战斗" | (待填) | | | +| 1356 | 86 | "决策面不消费内容键:携带 enemy_id/reward_id 与不带者输出逐键相等〔fv5〕" | same | (待填) | | | +| 1357 | 87 | "label_text 不含内容值(实际「%s」)〔fv5〕" ↩ % String(b["label_text"]) | not String(b["label_text"]).contains("goblin_secret") and not String(b["label_text"]).contains("reward_secret") | (待填) | | | -## S179 _test_big_graph_fit(行 164–190 · 6 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) +## S179 _test_label_three_states(行 95–100 · 3 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1357 | 164 | "大图夹具规模:≥11 层 × ≥6 槽(实测最大层 %d/最大槽 %d)〔fv8〕" ↩ % [maxl, maxslot] | maxl >= 10 and maxslot >= 5 | (待填) | | | -| 1358 | 170 | "大图拟合:画布 min.x 覆盖最深节点(%.1f ≥ %.1f)〔fv8〕" ↩ % [min_size.x, need_w] | min_size.x >= need_w - 0.01 | (待填) | | | -| 1359 | 172 | "大图拟合:画布 min.y 覆盖最宽层底节点(%.1f ≥ %.1f)〔fv8〕" ↩ % [min_size.y, need_h] | min_size.y >= need_h - 0.01 | (待填) | | | -| 1360 | 180 | "大图布局:全节点方块落在拟合画布内(origin=(%.1f,%.1f) size=(%.1f,%.1f))〔fv8〕" ↩ % [origin.x, origin.y, min_size.x, min_size.y] | all_in | (待填) | | | -| 1361 | 187 | "大图呈现:两个终点 Boss 均有描边标记〔fv8〕" | disp.has(boss_ids[0]) and disp.has(boss_ids[1]) and bool(disp[boss_ids[0]]["boss_border"]) and bool(disp[boss_ids[1]]["boss_border"]) | (待填) | | | -| 1362 | 190 | "大图呈现:入口停点远处战斗节点(句柄 32,层 6)类型入雾〔fv8〕" | not bool(disp[32]["draw_icon"]) | (待填) | | | +| 1358 | 95 | "当前位文案=「当前位置」〔fv2〕" | String(ScreenScript.node_display(node, 3, [3], true, false)["label_text"]) == "当前位置" | (待填) | | | +| 1359 | 97 | "候选文案=「战斗 · 可选」〔fv2〕" | String(ScreenScript.node_display(node, 3, [3], false, true)["label_text"]) == "战斗 · 可选" | (待填) | | | +| 1360 | 99 | "其余文案=类型名「战斗」〔fv2〕" | String(ScreenScript.node_display(node, 3, [3], false, false)["label_text"]) == "战斗" | (待填) | | | -## S180 _init(行 105–140 · 9 条 · 源 game/tests/unit/presentation/pacing_queue_test.gd · 去向:待分类回填) +## S180 _test_big_graph_fit(行 164–190 · 6 条 · 源 game/tests/unit/presentation/level_map_info_fog_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1363 | 105 | "排空前后核心诊断快照逐位一致(AC⑤ 演出关停零分叉)" | snap_before == snap_after | (待填) | | | -| 1364 | 107 | "结算行已产生(断言前提)" | rows_seen.size() > 0 | (待填) | | | -| 1365 | 108 | "排空后队列恒空(flush 完整性)" | main._row_queue.is_empty() | (待填) | | | -| 1366 | 117 | "末信号行原文在明细带(排空不吞行:『%s』)" ↩ % last_text | last_text != "" and main.log_view.parsed_text().contains(last_text) | (待填) | | | -| 1367 | 123 | "常态段间延迟 >0 且 ≥ 段内(%f/%f)" ↩ % [d_on, d_same] | d_on > 0.0 and d_on >= d_same | (待填) | | | -| 1368 | 125 | "减动效段间延迟归零(行不跳过——同帧直落快路)" | main.pace_delay_for("damage", "heal") == 0.0 | (待填) | | | -| 1369 | 135 | "结算标出按行 target_id 解析站桩(id 与名同传——d12)〔wd12〕" | fstage.calls.size() == 1 and fstage.calls[0] == ["goblin_b", "哥布林"] | (待填) | | | -| 1370 | 138 | "跨区弹道按行 target_id 解析站桩(id 与名同传——d12)〔wd12〕" | fstage.calls.size() == 2 and fstage.calls[1] == ["goblin_b", "哥布林"] | (待填) | | | -| 1371 | 140 | "两路解析成功后演出层各接一拍(记参面非空)〔wd12〕" | ffx.calls.size() == 2 | (待填) | | | +| 1361 | 164 | "大图夹具规模:≥11 层 × ≥6 槽(实测最大层 %d/最大槽 %d)〔fv8〕" ↩ % [maxl, maxslot] | maxl >= 10 and maxslot >= 5 | (待填) | | | +| 1362 | 170 | "大图拟合:画布 min.x 覆盖最深节点(%.1f ≥ %.1f)〔fv8〕" ↩ % [min_size.x, need_w] | min_size.x >= need_w - 0.01 | (待填) | | | +| 1363 | 172 | "大图拟合:画布 min.y 覆盖最宽层底节点(%.1f ≥ %.1f)〔fv8〕" ↩ % [min_size.y, need_h] | min_size.y >= need_h - 0.01 | (待填) | | | +| 1364 | 180 | "大图布局:全节点方块落在拟合画布内(origin=(%.1f,%.1f) size=(%.1f,%.1f))〔fv8〕" ↩ % [origin.x, origin.y, min_size.x, min_size.y] | all_in | (待填) | | | +| 1365 | 187 | "大图呈现:两个终点 Boss 均有描边标记〔fv8〕" | disp.has(boss_ids[0]) and disp.has(boss_ids[1]) and bool(disp[boss_ids[0]]["boss_border"]) and bool(disp[boss_ids[1]]["boss_border"]) | (待填) | | | +| 1366 | 190 | "大图呈现:入口停点远处战斗节点(句柄 32,层 6)类型入雾〔fv8〕" | not bool(disp[32]["draw_icon"]) | (待填) | | | -## S181 _sweep_hero_panel(行 47–50 · 2 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) +## S181 _init(行 105–140 · 9 条 · 源 game/tests/unit/presentation/pacing_queue_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1372 | 47 | "C 区专长段头==「专长」(u1 换代——段头文案钉值)〔wa1〕" | feat_head != null and feat_head.text == "专长" | (待填) | | | -| 1373 | 49 | "C 区属性值提升段头==「属性值提升」(u2 换代——同屏两段同标撞车消除)〔wa1〕" | curio_head != null and curio_head.text == "属性值提升" | (待填) | | | +| 1367 | 105 | "排空前后核心诊断快照逐位一致(AC⑤ 演出关停零分叉)" | snap_before == snap_after | (待填) | | | +| 1368 | 107 | "结算行已产生(断言前提)" | rows_seen.size() > 0 | (待填) | | | +| 1369 | 108 | "排空后队列恒空(flush 完整性)" | main._row_queue.is_empty() | (待填) | | | +| 1370 | 117 | "末信号行原文在明细带(排空不吞行:『%s』)" ↩ % last_text | last_text != "" and main.log_view.parsed_text().contains(last_text) | (待填) | | | +| 1371 | 123 | "常态段间延迟 >0 且 ≥ 段内(%f/%f)" ↩ % [d_on, d_same] | d_on > 0.0 and d_on >= d_same | (待填) | | | +| 1372 | 125 | "减动效段间延迟归零(行不跳过——同帧直落快路)" | main.pace_delay_for("damage", "heal") == 0.0 | (待填) | | | +| 1373 | 135 | "结算标出按行 target_id 解析站桩(id 与名同传——d12)〔wd12〕" | fstage.calls.size() == 1 and fstage.calls[0] == ["goblin_b", "哥布林"] | (待填) | | | +| 1374 | 138 | "跨区弹道按行 target_id 解析站桩(id 与名同传——d12)〔wd12〕" | fstage.calls.size() == 2 and fstage.calls[1] == ["goblin_b", "哥布林"] | (待填) | | | +| 1375 | 140 | "两路解析成功后演出层各接一拍(记参面非空)〔wd12〕" | ffx.calls.size() == 2 | (待填) | | | -## S182 _sweep_narrator(行 57–64 · 7 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) +## S182 _sweep_hero_panel(行 47–50 · 2 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1374 | 57 | "奖励点头部含「冒险牌库」(u3 机制事实①同库)〔wa4〕" | head.contains("冒险牌库") | (待填) | | | -| 1375 | 58 | "奖励点头部含「属性值提升与补给」(u3 机制事实②渠道分流)〔wa4〕" | head.contains("属性值提升与补给") | (待填) | | | -| 1376 | 59 | "奖励点头部含「同库分流」(u3 机制事实②措辞)〔wa4〕" | head.contains("同库分流") | (待填) | | | -| 1377 | 60 | "奖励点头部零「同权重」旧话(u3 清零)〔wa4〕" | not head.contains("同权重") | (待填) | | | -| 1378 | 61 | "奖励点头部零「同上限」旧话(u3 清零)〔wa4〕" | not head.contains("同上限") | (待填) | | | -| 1379 | 62 | "奖励点头部零「提升池」旧话(u3 清零)〔wa4〕" | not head.contains("提升池") | (待填) | | | -| 1380 | 63 | "专长卡兜底==「专长\\n???」(u11 换代——数据缺行真实兜底路径)〔wa3〕" | String(narrator.feat_card_text({})) == "专长\\n???" | (待填) | | | +| 1376 | 47 | "C 区专长段头==「专长」(u1 换代——段头文案钉值)〔wa1〕" | feat_head != null and feat_head.text == "专长" | (待填) | | | +| 1377 | 49 | "C 区属性值提升段头==「属性值提升」(u2 换代——同屏两段同标撞车消除)〔wa1〕" | curio_head != null and curio_head.text == "属性值提升" | (待填) | | | -## S183 _sweep_legend(行 75–79 · 5 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) +## S183 _sweep_narrator(行 57–64 · 7 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1381 | 75 | "图例封印行存在(wa5 夹具前提)〔wa5〕" | not seal_row.is_empty() | (待填) | | | -| 1382 | 76 | "图例封印行含「标空」(u4——与「标中」成对)〔wa5〕" | String(seal_row[2] if seal_row.size() > 2 else "").contains("标空") | (待填) | | | -| 1383 | 77 | "图例封印行含「受挖掘惩罚」(u4 雷字清零换代)〔wa5〕" | String(seal_row[2] if seal_row.size() > 2 else "").contains("受挖掘惩罚") | (待填) | | | -| 1384 | 78 | "图例封印行零「插错」(u4 旗族遗留词干清零)〔wa5〕" | not String(seal_row[2] if seal_row.size() > 2 else "").contains("插错") | (待填) | | | -| 1385 | 79 | "图例封印行零「挖雷」(u4 雷字清零)〔wa5〕" | not String(seal_row[2] if seal_row.size() > 2 else "").contains("挖雷") | (待填) | | | +| 1378 | 57 | "奖励点头部含「冒险牌库」(u3 机制事实①同库)〔wa4〕" | head.contains("冒险牌库") | (待填) | | | +| 1379 | 58 | "奖励点头部含「属性值提升与补给」(u3 机制事实②渠道分流)〔wa4〕" | head.contains("属性值提升与补给") | (待填) | | | +| 1380 | 59 | "奖励点头部含「同库分流」(u3 机制事实②措辞)〔wa4〕" | head.contains("同库分流") | (待填) | | | +| 1381 | 60 | "奖励点头部零「同权重」旧话(u3 清零)〔wa4〕" | not head.contains("同权重") | (待填) | | | +| 1382 | 61 | "奖励点头部零「同上限」旧话(u3 清零)〔wa4〕" | not head.contains("同上限") | (待填) | | | +| 1383 | 62 | "奖励点头部零「提升池」旧话(u3 清零)〔wa4〕" | not head.contains("提升池") | (待填) | | | +| 1384 | 63 | "专长卡兜底==「专长\\n???」(u11 换代——数据缺行真实兜底路径)〔wa3〕" | String(narrator.feat_card_text({})) == "专长\\n???" | (待填) | | | -## S184 _sweep_source_names(行 92–104 · 4 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) +## S184 _sweep_legend(行 75–79 · 5 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1386 | 92 | "状态槽 mine_hit 效果行在座(wa6 夹具前提)〔wa6〕" | slot != null | (待填) | | | -| 1387 | 95 | "状态槽来源注记==「危险格」(u5 换代——meta tooltip 消费半)〔wa6〕" | row_view._tip_label.text.contains("来源:危险格") | (待填) | | | -| 1388 | 98 | "结算表 source_label_map[mine_hit]==「危险格」(u6 换代——ConfigDB 真装载)〔wa7〕" | String(_db.settlement.source_label_map.get("mine_hit", "")) == "危险格" | (待填) | | | -| 1389 | 103 | "战斗日志 mine_hit 来源行含「(危险格)」(u6 消费半——_format_row 生产路径)〔wa7〕" | row_txt.contains("(危险格)") | (待填) | | | +| 1385 | 75 | "图例封印行存在(wa5 夹具前提)〔wa5〕" | not seal_row.is_empty() | (待填) | | | +| 1386 | 76 | "图例封印行含「标空」(u4——与「标中」成对)〔wa5〕" | String(seal_row[2] if seal_row.size() > 2 else "").contains("标空") | (待填) | | | +| 1387 | 77 | "图例封印行含「受挖掘惩罚」(u4 雷字清零换代)〔wa5〕" | String(seal_row[2] if seal_row.size() > 2 else "").contains("受挖掘惩罚") | (待填) | | | +| 1388 | 78 | "图例封印行零「插错」(u4 旗族遗留词干清零)〔wa5〕" | not String(seal_row[2] if seal_row.size() > 2 else "").contains("插错") | (待填) | | | +| 1389 | 79 | "图例封印行零「挖雷」(u4 雷字清零)〔wa5〕" | not String(seal_row[2] if seal_row.size() > 2 else "").contains("挖雷") | (待填) | | | -## S185 _sweep_board_glyph(行 133–142 · 4 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) +## S185 _sweep_source_names(行 92–104 · 4 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1390 | 133 | "棋盘夹具含挖掘射程内未开危险格(wa8 前提——实测 %d 步)〔wa8〕" ↩ % glow_steps | mine_cell.x >= 0 | (待填) | | | -| 1391 | 139 | "已开危险格 glyph==「危」(u7 换代)〔wa8〕" | u.glyph == "危" | (待填) | | | -| 1392 | 140 | "已开危险格 plate==true(u9 牌载哨兵包含项随动)〔wa8〕" | u.plate == true | (待填) | | | -| 1393 | 141 | "已开危险格 glyph_color==RED_MINE(u7 墨色不随字形换代漂移)〔wa8〕" | u.glyph_color == UiKit.RED_MINE | (待填) | | | +| 1390 | 92 | "状态槽 mine_hit 效果行在座(wa6 夹具前提)〔wa6〕" | slot != null | (待填) | | | +| 1391 | 95 | "状态槽来源注记==「危险格」(u5 换代——meta tooltip 消费半)〔wa6〕" | row_view._tip_label.text.contains("来源:危险格") | (待填) | | | +| 1392 | 98 | "结算表 source_label_map[mine_hit]==「危险格」(u6 换代——ConfigDB 真装载)〔wa7〕" | String(_db.settlement.source_label_map.get("mine_hit", "")) == "危险格" | (待填) | | | +| 1393 | 103 | "战斗日志 mine_hit 来源行含「(危险格)」(u6 消费半——_format_row 生产路径)〔wa7〕" | row_txt.contains("(危险格)") | (待填) | | | -## S186 _sweep_token_scans(行 148–158 · 2 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) +## S186 _sweep_board_glyph(行 133–142 · 4 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1394 | 148 | "board_view.gd 源零 \\"雷\\" 字面量(u7/u8/u9 哨兵族统一钉住)〔wa8〕" | board_src.count("\\"雷\\"") == 0 | (待填) | | | -| 1395 | 157 | "battle_orchestrator.gd 玩家面字符串字面量零「挖雷」(u13——注释保留面不入域)〔wa12〕" | orch_hits == 0 | (待填) | | | +| 1394 | 133 | "棋盘夹具含挖掘射程内未开危险格(wa8 前提——实测 %d 步)〔wa8〕" ↩ % glow_steps | mine_cell.x >= 0 | (待填) | | | +| 1395 | 139 | "已开危险格 glyph==「危」(u7 换代)〔wa8〕" | u.glyph == "危" | (待填) | | | +| 1396 | 140 | "已开危险格 plate==true(u9 牌载哨兵包含项随动)〔wa8〕" | u.plate == true | (待填) | | | +| 1397 | 141 | "已开危险格 glyph_color==RED_MINE(u7 墨色不随字形换代漂移)〔wa8〕" | u.glyph_color == UiKit.RED_MINE | (待填) | | | -## S187 _init(行 75–132 · 18 条 · 源 game/tests/unit/presentation/standee_fx_sweep_test.gd · 去向:待分类回填) +## S187 _sweep_token_scans(行 148–158 · 2 条 · 源 game/tests/unit/presentation/player_copy_sweep_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1396 | 75 | "站桩 enemy_id 访问器读装载值〔wd12〕" | s1.enemy_id() == "goblin_a" and s2.enemy_id() == "goblin_b" | (待填) | | | -| 1397 | 76 | "同名敌按 id 精确解析(不做名子串撞车)〔wd12〕" | stage._card_by_id("goblin_b") == s2 and stage._card_by_id("goblin_a") == s1 | (待填) | | | -| 1398 | 78 | "空 id / 未登记 id 恒不命中(名兜底归调用点)〔wd12〕" | stage._card_by_id("") == null and stage._card_by_id("no_such") == null | (待填) | | | -| 1399 | 83 | "伤害行按 target_id 命中正确站桩(闪白落点)〔wd12〕" | s2._flash_count == 1 and s1._flash_count == 0 | (待填) | | | -| 1400 | 88 | "弹道落点按 target_id 取站桩中心〔wd12〕" | c_b != null and c_b == c_b_expect | (待填) | | | -| 1401 | 91 | "无 target_id 时按名兜底同旧行为(首命中)〔wd12〕" | c_fallback != null and c_fallback == c_fallback_expect | (待填) | | | -| 1402 | 95 | "蓄力技能(heavy)置 _intent_charge=true〔wd2〕" | s1._intent_charge | (待填) | | | -| 1403 | 97 | "非蓄力攻击技(goblin_slash)零置位〔wd2〕" | not s1._intent_charge | (待填) | | | -| 1404 | 99 | "增益系零置位〔wd2〕" | not s1._intent_charge | (待填) | | | -| 1405 | 101 | "普攻零表示路径复位 _intent_charge〔wd2〕" | not s1._intent_charge | (待填) | | | -| 1406 | 108 | "首开胜利画面创建庆祝句柄〔wd4〕" | first != null and first.is_valid() | (待填) | | | -| 1407 | 111 | "重开胜利画面:旧句柄已 kill、新句柄在位(至多一个活跃)〔wd4〕" | first != null and not first.is_valid() and second != null and second.is_valid() | (待填) | | | -| 1408 | 114 | "close 必杀庆祝句柄(句柄清空)〔wd4〕" | ov.get_meta(&"celebrate_tw", null) == null | (待填) | | | -| 1409 | 119 | "模拟运行期调试入口钮同置灰〔wd5〕" | dbg._dbg_btn.disabled | (待填) | | | -| 1410 | 121 | "模拟收尾调试入口钮恢复(未锁定)〔wd5〕" | not dbg._dbg_btn.disabled | (待填) | | | -| 1411 | 130 | "控制器运行中 is_running()=true(驱动回调内读数)〔wd8〕" | drv.seen == [true, true] | (待填) | | | -| 1412 | 131 | "控制器收尾 is_running()=false〔wd8〕" | not ctrl.is_running() and not panel.running | (待填) | | | -| 1413 | 132 | "两局报告全文注入面板(run 收尾链路完整)〔wd8〕" | String(panel.report) != "" | (待填) | | | +| 1398 | 148 | "board_view.gd 源零 \\"雷\\" 字面量(u7/u8/u9 哨兵族统一钉住)〔wa8〕" | board_src.count("\\"雷\\"") == 0 | (待填) | | | +| 1399 | 157 | "battle_orchestrator.gd 玩家面字符串字面量零「挖雷」(u13——注释保留面不入域)〔wa12〕" | orch_hits == 0 | (待填) | | | -## S188 _init(行 24–34 · 2 条 · 源 game/tests/unit/presentation/terrain_tile_sets_test.gd · 去向:待分类回填) +## S188 _init(行 75–132 · 18 条 · 源 game/tests/unit/presentation/standee_fx_sweep_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1414 | 24 | "前置:表加载零 error" | load_ok and db.diagnostics_count("error") == 0 | (待填) | | | -| 1415 | 34 | "前置:board_gen 词表非空(%d 型)" ↩ % types.size() | types.size() > 0 | (待填) | | | +| 1400 | 75 | "站桩 enemy_id 访问器读装载值〔wd12〕" | s1.enemy_id() == "goblin_a" and s2.enemy_id() == "goblin_b" | (待填) | | | +| 1401 | 76 | "同名敌按 id 精确解析(不做名子串撞车)〔wd12〕" | stage._card_by_id("goblin_b") == s2 and stage._card_by_id("goblin_a") == s1 | (待填) | | | +| 1402 | 78 | "空 id / 未登记 id 恒不命中(名兜底归调用点)〔wd12〕" | stage._card_by_id("") == null and stage._card_by_id("no_such") == null | (待填) | | | +| 1403 | 83 | "伤害行按 target_id 命中正确站桩(闪白落点)〔wd12〕" | s2._flash_count == 1 and s1._flash_count == 0 | (待填) | | | +| 1404 | 88 | "弹道落点按 target_id 取站桩中心〔wd12〕" | c_b != null and c_b == c_b_expect | (待填) | | | +| 1405 | 91 | "无 target_id 时按名兜底同旧行为(首命中)〔wd12〕" | c_fallback != null and c_fallback == c_fallback_expect | (待填) | | | +| 1406 | 95 | "蓄力技能(heavy)置 _intent_charge=true〔wd2〕" | s1._intent_charge | (待填) | | | +| 1407 | 97 | "非蓄力攻击技(goblin_slash)零置位〔wd2〕" | not s1._intent_charge | (待填) | | | +| 1408 | 99 | "增益系零置位〔wd2〕" | not s1._intent_charge | (待填) | | | +| 1409 | 101 | "普攻零表示路径复位 _intent_charge〔wd2〕" | not s1._intent_charge | (待填) | | | +| 1410 | 108 | "首开胜利画面创建庆祝句柄〔wd4〕" | first != null and first.is_valid() | (待填) | | | +| 1411 | 111 | "重开胜利画面:旧句柄已 kill、新句柄在位(至多一个活跃)〔wd4〕" | first != null and not first.is_valid() and second != null and second.is_valid() | (待填) | | | +| 1412 | 114 | "close 必杀庆祝句柄(句柄清空)〔wd4〕" | ov.get_meta(&"celebrate_tw", null) == null | (待填) | | | +| 1413 | 119 | "模拟运行期调试入口钮同置灰〔wd5〕" | dbg._dbg_btn.disabled | (待填) | | | +| 1414 | 121 | "模拟收尾调试入口钮恢复(未锁定)〔wd5〕" | not dbg._dbg_btn.disabled | (待填) | | | +| 1415 | 130 | "控制器运行中 is_running()=true(驱动回调内读数)〔wd8〕" | drv.seen == [true, true] | (待填) | | | +| 1416 | 131 | "控制器收尾 is_running()=false〔wd8〕" | not ctrl.is_running() and not panel.running | (待填) | | | +| 1417 | 132 | "两局报告全文注入面板(run 收尾链路完整)〔wd8〕" | String(panel.report) != "" | (待填) | | | -## S189 _test_set_completeness(行 56–56 · 1 条 · 源 game/tests/unit/presentation/terrain_tile_sets_test.gd · 去向:待分类回填) +## S189 _init(行 24–34 · 2 条 · 源 game/tests/unit/presentation/terrain_tile_sets_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1416 | 56 | "图型 %s 瓦片套完整(16 墙 + %d 地面,缺=%s)" ↩ % [String(bt), variants, str(missing)] | missing.is_empty() | (待填) | | | +| 1418 | 24 | "前置:表加载零 error" | load_ok and db.diagnostics_count("error") == 0 | (待填) | | | +| 1419 | 34 | "前置:board_gen 词表非空(%d 型)" ↩ % types.size() | types.size() > 0 | (待填) | | | -## S190 _test_hue_domains(行 72–82 · 4 条 · 源 game/tests/unit/presentation/terrain_tile_sets_test.gd · 去向:待分类回填) +## S190 _test_set_completeness(行 56–56 · 1 条 · 源 game/tests/unit/presentation/terrain_tile_sets_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1417 | 72 | "图型 %s 抽检样本可读" ↩ % String(bt) | false | (待填) | | | -| 1418 | 77 | "图型 %s 墙顶均值色相在带 %s(实测 %.3f)" ↩ % [String(bt), str(band), float(wall["h"])] | float(wall["h"]) >= float(band[0]) and float(wall["h"]) <= float(band[1]) | (待填) | | | -| 1419 | 79 | "图型 %s 图底分离(墙顶明度 %.3f > 地面 %.3f)" ↩ % [String(bt), wall_v[bt], floor_v[bt]] | wall_v[bt] > floor_v[bt] | (待填) | | | -| 1420 | 82 | "deep_underdark 墙顶更暗于 underdark(更深蓝黑方向)" | float(wall_v["deep_underdark"]) < float(wall_v["underdark"]) | (待填) | | | +| 1420 | 56 | "图型 %s 瓦片套完整(16 墙 + %d 地面,缺=%s)" ↩ % [String(bt), variants, str(missing)] | missing.is_empty() | (待填) | | | -## S191 _test_digit_ink_modes(行 137–159 · 5 条 · 源 game/tests/unit/presentation/terrain_tile_sets_test.gd · 去向:待分类回填) +## S191 _test_hue_domains(行 72–82 · 4 条 · 源 game/tests/unit/presentation/terrain_tile_sets_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1421 | 137 | "图型 %s 数字墨族断言样本可读" ↩ % String(bt) | false | (待填) | | | -| 1422 | 144 | "图型 %s 双峰纹理落牌(亮族 p90 %.2f/均值 %.2f,深族 p90 %.2f/均值 %.2f 均未过门)" ↩ % [ String(bt), float(mode["cr_p90_bright"]), float(mode["cr_mean_bright"]), float(mode["cr_p90_dark"]), float(mode["cr_mean_dark"])] | float(mode["cr_mean_dark"]) < float(TilePaletteScript.DIGIT_INK_CR_MEAN_DARK) | (待填) | | | -| 1423 | 151 | "图型 %s 所选%s 对 p90 ≥%.1f(实测 %.2f)" ↩ % [String(bt), mode_name, float(TilePaletteScript.DIGIT_INK_CR_P90), cr_p90] | cr_p90 >= float(TilePaletteScript.DIGIT_INK_CR_P90) | (待填) | | | -| 1424 | 155 | "图型 %s 所选%s 对均值 ≥%.1f(实测 %.2f)" ↩ % [String(bt), mode_name, mean_gate, cr_mean] | cr_mean >= mean_gate | (待填) | | | -| 1425 | 158 | "图型 %s 呈现模式期望=%s(实测=%s)" ↩ % [String(bt), "色牌" if bool(expect_plate[bt]) else "直画", mode_name] | plate == bool(expect_plate[bt]) | (待填) | | | +| 1421 | 72 | "图型 %s 抽检样本可读" ↩ % String(bt) | false | (待填) | | | +| 1422 | 77 | "图型 %s 墙顶均值色相在带 %s(实测 %.3f)" ↩ % [String(bt), str(band), float(wall["h"])] | float(wall["h"]) >= float(band[0]) and float(wall["h"]) <= float(band[1]) | (待填) | | | +| 1423 | 79 | "图型 %s 图底分离(墙顶明度 %.3f > 地面 %.3f)" ↩ % [String(bt), wall_v[bt], floor_v[bt]] | wall_v[bt] > floor_v[bt] | (待填) | | | +| 1424 | 82 | "deep_underdark 墙顶更暗于 underdark(更深蓝黑方向)" | float(wall_v["deep_underdark"]) < float(wall_v["underdark"]) | (待填) | | | -## S192 _smoke_type_glow(行 214–374 · 24 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S192 _test_digit_ink_modes(行 137–159 · 5 条 · 源 game/tests/unit/presentation/terrain_tile_sets_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1426 | 214 | "V1 微光默认开(Q4 丙案——呈现态布尔缺省 true,生产写入面零显式开)" | bool(snap.get("enabled", false)) | (待填) | | | -| 1427 | 216 | "V1 夹具全集合法九型 ⇒ 清单外登记为空(禁静默空光通道零误报)" | (snap.get("errors", []) as Array).is_empty() | (待填) | | | -| 1428 | 219 | "V1 作用集恒等:微光格集合 == _diggable ∩ 身份可查(期望 %d,实测 %d)" ↩ % [expect.size(), (snap.get("cells", {}) as Dictionary).size()] | _glow_key_set_equal(snap.get("cells", {}), expect) | (待填) | | | -| 1429 | 221 | "V1 夹具前提:英雄未开邻格 ≥5(实测 %d——novice %d 步)" ↩ % [expect.size(), steps] | expect.size() >= 5 | (待填) | | | -| 1430 | 231 | "V1 已开格/r0 出生展开区零微光(S1)%s" ↩ % ("" if opened_leak == "" else "违例:" + opened_leak) | opened_leak == "" | (待填) | | | -| 1431 | 248 | "V2 夹具前提:未开邻格派定 ≥5 型(实测 %d)" ↩ % mapped | mapped >= 5 | (待填) | | | -| 1432 | 257 | "V2 九型→五组逐格映射(attack/defense/action/gp→增益/heal→治疗/pierce→穿刺/blast→群伤/magic→魔法)%s" ↩ % ("" if map_bad == "" else "违例:" + map_bad) | map_bad == "" | (待填) | | | -| 1433 | 271 | "V2 清单外 cell_type 显式登记(errors=%s)" ↩ % str(errs) | errs.has("keystone") | (待填) | | | -| 1434 | 272 | "V2 清单外格零微光(无静默空光——%s 不在作用集)" ↩ % str(bogus_cell) | not (snap.get("cells", {}) as Dictionary).has(bogus_cell) | (待填) | | | -| 1435 | 274 | "V2 清单外格剔除后作用集 = 派定数 −1(%d→%d)" ↩ % [mapped, (snap.get("cells", {}) as Dictionary).size()] | (snap.get("cells", {}) as Dictionary).size() == mapped - 1 | (待填) | | | -| 1436 | 287 | "V1 封锁格零微光(query null ⇒ 天然惰性——%s)" ↩ % str(blocked_cell) | not (snap.get("cells", {}) as Dictionary).has(blocked_cell) | (待填) | | | -| 1437 | 289 | "V1 封锁格零登记(errors 仍仅清单外一条——%s)" ↩ % str(snap.get("errors", [])) | (snap.get("errors", []) as Array).size() == 1 | (待填) | | | -| 1438 | 291 | "V1 封锁格剔除后作用集 = 派定数 −1(实测 %d)" ↩ % (snap.get("cells", {}) as Dictionary).size() | (snap.get("cells", {}) as Dictionary).size() == mapped - 1 | (待填) | | | -| 1439 | 297 | "V1 封锁解除后作用集复位恒等(期望 %d,实测 %d)" ↩ % [expect.size(), (snap.get("cells", {}) as Dictionary).size()] | _glow_key_set_equal(snap.get("cells", {}), expect) | (待填) | | | -| 1440 | 303 | "V7 off 态开关读数=false" | not bool(snap.get("enabled", true)) | (待填) | | | -| 1441 | 304 | "V7 off 态作用集为空(基线保护面)" | (snap.get("cells", {}) as Dictionary).is_empty() | (待填) | | | -| 1442 | 307 | "V7 on 态开关读数=true(复现)" | bool(snap_on.get("enabled", false)) | (待填) | | | -| 1443 | 308 | "V7 off→on 作用集逐位复现(关前 %d 格/开后 %d 格,组号逐位一致)" ↩ % [ (snap_before_off.get("cells", {}) as Dictionary).size(), (snap_on.get("cells", {}) as Dictionary).size()] | _glow_map_equal(snap_on.get("cells", {}), snap_before_off.get("cells", {})) | (待填) | | | -| 1444 | 311 | "V7 off→on 作用集与独立重算期望集恒等(%d 格)" ↩ % (snap_on.get("cells", {}) as Dictionary).size() | _glow_key_set_equal(snap_on.get("cells", {}), expect) | (待填) | | | -| 1445 | 315 | "V7 微光开关零玩法写入(已开集/英雄位/封印数三面对照逐位一致)" | revealed_before == revealed_after and hero_before == ms.hero_pos() and seals_before == ms.seal_count() | (待填) | | | -| 1446 | 328 | "V3 换图 rebuild 后作用集按新板重算(期望 %d,实测 %d——零旧板残留)" ↩ % [expect2.size(), (snap2.get("cells", {}) as Dictionary).size()] | _glow_key_set_equal(snap2.get("cells", {}), expect2) | (待填) | | | -| 1447 | 330 | "V3 换图清清单外登记(rebuild 清零)" | (snap2.get("errors", []) as Array).is_empty() | (待填) | | | -| 1448 | 371 | "契约 1 同板同序列 on/off 两态结算逐位一致(%d 步对照——A 开态/B 关态)%s" ↩ % [seq_steps, diverge] | diverge == "" | (待填) | | | -| 1449 | 374 | "契约 1 对照前提:同序列 ≥5 步(实测 %d)" ↩ % seq_steps | seq_steps >= 5 | (待填) | | | +| 1425 | 137 | "图型 %s 数字墨族断言样本可读" ↩ % String(bt) | false | (待填) | | | +| 1426 | 144 | "图型 %s 双峰纹理落牌(亮族 p90 %.2f/均值 %.2f,深族 p90 %.2f/均值 %.2f 均未过门)" ↩ % [ String(bt), float(mode["cr_p90_bright"]), float(mode["cr_mean_bright"]), float(mode["cr_p90_dark"]), float(mode["cr_mean_dark"])] | float(mode["cr_mean_dark"]) < float(TilePaletteScript.DIGIT_INK_CR_MEAN_DARK) | (待填) | | | +| 1427 | 151 | "图型 %s 所选%s 对 p90 ≥%.1f(实测 %.2f)" ↩ % [String(bt), mode_name, float(TilePaletteScript.DIGIT_INK_CR_P90), cr_p90] | cr_p90 >= float(TilePaletteScript.DIGIT_INK_CR_P90) | (待填) | | | +| 1428 | 155 | "图型 %s 所选%s 对均值 ≥%.1f(实测 %.2f)" ↩ % [String(bt), mode_name, mean_gate, cr_mean] | cr_mean >= mean_gate | (待填) | | | +| 1429 | 158 | "图型 %s 呈现模式期望=%s(实测=%s)" ↩ % [String(bt), "色牌" if bool(expect_plate[bt]) else "直画", mode_name] | plate == bool(expect_plate[bt]) | (待填) | | | -## S193 _smoke_battle_log_view(行 391–422 · 6 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S193 _smoke_type_glow(行 215–375 · 24 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1450 | 391 | "敌方伤害行格式化(baseline 行不读退役 attach)" | enemy_txt.contains("撕咬") and enemy_txt.contains("〔掷 15 vs 护甲 12") | (待填) | | | -| 1451 | 393 | "退役伏击/基线拆行文案不再出现" | not enemy_txt.contains("伏击") and not enemy_txt.contains("基线") | (待填) | | | -| 1452 | 400 | "主角穿刺型暴击行金框(单分量 payload 不触发三分量拆行)" | hero_txt.contains("暴击×") and hero_txt.contains("⚔击杀") and hero_txt.contains("■") | (待填) | | | -| 1453 | 402 | "退役三分量拆行文案不再出现" | not hero_txt.contains(" + 穿刺 ") | (待填) | | | -| 1454 | 408 | "未生效行聚合计数 ×2 呈现" | agg_txt.contains("⚠") and agg_txt.contains("×2") | (待填) | | | -| 1455 | 421 | "行型 %s 格式化落地(解析文本增长)" ↩ % String(row_type) | view.parsed_text().length() > before | (待填) | | | +| 1430 | 215 | "V1 微光默认开(Q4 丙案——呈现态布尔缺省 true,生产写入面零显式开)" | bool(snap.get("enabled", false)) | (待填) | | | +| 1431 | 217 | "V1 夹具全集合法九型 ⇒ 清单外登记为空(禁静默空光通道零误报)" | (snap.get("errors", []) as Array).is_empty() | (待填) | | | +| 1432 | 220 | "V1 作用集恒等:微光格集合 == _diggable ∩ 身份可查(期望 %d,实测 %d)" ↩ % [expect.size(), (snap.get("cells", {}) as Dictionary).size()] | _glow_key_set_equal(snap.get("cells", {}), expect) | (待填) | | | +| 1433 | 222 | "V1 夹具前提:英雄未开邻格 ≥5(实测 %d——novice %d 步)" ↩ % [expect.size(), steps] | expect.size() >= 5 | (待填) | | | +| 1434 | 232 | "V1 已开格/r0 出生展开区零微光(S1)%s" ↩ % ("" if opened_leak == "" else "违例:" + opened_leak) | opened_leak == "" | (待填) | | | +| 1435 | 249 | "V2 夹具前提:未开邻格派定 ≥5 型(实测 %d)" ↩ % mapped | mapped >= 5 | (待填) | | | +| 1436 | 258 | "V2 九型→五组逐格映射(attack/defense/action/gp→增益/heal→治疗/pierce→穿刺/blast→群伤/magic→魔法)%s" ↩ % ("" if map_bad == "" else "违例:" + map_bad) | map_bad == "" | (待填) | | | +| 1437 | 272 | "V2 清单外 cell_type 显式登记(errors=%s)" ↩ % str(errs) | errs.has("keystone") | (待填) | | | +| 1438 | 273 | "V2 清单外格零微光(无静默空光——%s 不在作用集)" ↩ % str(bogus_cell) | not (snap.get("cells", {}) as Dictionary).has(bogus_cell) | (待填) | | | +| 1439 | 275 | "V2 清单外格剔除后作用集 = 派定数 −1(%d→%d)" ↩ % [mapped, (snap.get("cells", {}) as Dictionary).size()] | (snap.get("cells", {}) as Dictionary).size() == mapped - 1 | (待填) | | | +| 1440 | 288 | "V1 封锁格零微光(query null ⇒ 天然惰性——%s)" ↩ % str(blocked_cell) | not (snap.get("cells", {}) as Dictionary).has(blocked_cell) | (待填) | | | +| 1441 | 290 | "V1 封锁格零登记(errors 仍仅清单外一条——%s)" ↩ % str(snap.get("errors", [])) | (snap.get("errors", []) as Array).size() == 1 | (待填) | | | +| 1442 | 292 | "V1 封锁格剔除后作用集 = 派定数 −1(实测 %d)" ↩ % (snap.get("cells", {}) as Dictionary).size() | (snap.get("cells", {}) as Dictionary).size() == mapped - 1 | (待填) | | | +| 1443 | 298 | "V1 封锁解除后作用集复位恒等(期望 %d,实测 %d)" ↩ % [expect.size(), (snap.get("cells", {}) as Dictionary).size()] | _glow_key_set_equal(snap.get("cells", {}), expect) | (待填) | | | +| 1444 | 304 | "V7 off 态开关读数=false" | not bool(snap.get("enabled", true)) | (待填) | | | +| 1445 | 305 | "V7 off 态作用集为空(基线保护面)" | (snap.get("cells", {}) as Dictionary).is_empty() | (待填) | | | +| 1446 | 308 | "V7 on 态开关读数=true(复现)" | bool(snap_on.get("enabled", false)) | (待填) | | | +| 1447 | 309 | "V7 off→on 作用集逐位复现(关前 %d 格/开后 %d 格,组号逐位一致)" ↩ % [ (snap_before_off.get("cells", {}) as Dictionary).size(), (snap_on.get("cells", {}) as Dictionary).size()] | _glow_map_equal(snap_on.get("cells", {}), snap_before_off.get("cells", {})) | (待填) | | | +| 1448 | 312 | "V7 off→on 作用集与独立重算期望集恒等(%d 格)" ↩ % (snap_on.get("cells", {}) as Dictionary).size() | _glow_key_set_equal(snap_on.get("cells", {}), expect) | (待填) | | | +| 1449 | 316 | "V7 微光开关零玩法写入(已开集/英雄位/封印数三面对照逐位一致)" | revealed_before == revealed_after and hero_before == ms.hero_pos() and seals_before == ms.seal_count() | (待填) | | | +| 1450 | 329 | "V3 换图 rebuild 后作用集按新板重算(期望 %d,实测 %d——零旧板残留)" ↩ % [expect2.size(), (snap2.get("cells", {}) as Dictionary).size()] | _glow_key_set_equal(snap2.get("cells", {}), expect2) | (待填) | | | +| 1451 | 331 | "V3 换图清清单外登记(rebuild 清零)" | (snap2.get("errors", []) as Array).is_empty() | (待填) | | | +| 1452 | 372 | "契约 1 同板同序列 on/off 两态结算逐位一致(%d 步对照——A 开态/B 关态)%s" ↩ % [seq_steps, diverge] | diverge == "" | (待填) | | | +| 1453 | 375 | "契约 1 对照前提:同序列 ≥5 步(实测 %d)" ↩ % seq_steps | seq_steps >= 5 | (待填) | | | -## S194 _smoke_level_open_line(行 429–435 · 3 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S194 _smoke_battle_log_view(行 392–423 · 6 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1456 | 429 | "开场行 boosted=true 尾接「(含面板加成)」〔wc1〕" | String(NarratorScript.level_open_line("第一层", 42, 5, 30, true)).contains("(含面板加成)") | (待填) | | | -| 1457 | 431 | "开场行 boosted=false 零后缀(白板局不带)〔wc1〕" | not String(NarratorScript.level_open_line("第一层", 42, 5, 30, false)).contains("(含面板加成)") | (待填) | | | -| 1458 | 433 | "开场行种子/两值带入不受后缀位影响(数值带入回归)〔wc1〕" | String(NarratorScript.level_open_line("第一层", 42, 5, 30, true)).contains("种子 42") and String(NarratorScript.level_open_line("第一层", 42, 5, 30, true)).contains("攻击 5 / 生命 30") | (待填) | | | +| 1454 | 392 | "敌方伤害行格式化(baseline 行不读退役 attach)" | enemy_txt.contains("撕咬") and enemy_txt.contains("〔掷 15 vs 护甲 12") | (待填) | | | +| 1455 | 394 | "退役伏击/基线拆行文案不再出现" | not enemy_txt.contains("伏击") and not enemy_txt.contains("基线") | (待填) | | | +| 1456 | 401 | "主角穿刺型暴击行金框(单分量 payload 不触发三分量拆行)" | hero_txt.contains("暴击×") and hero_txt.contains("⚔击杀") and hero_txt.contains("■") | (待填) | | | +| 1457 | 403 | "退役三分量拆行文案不再出现" | not hero_txt.contains(" + 穿刺 ") | (待填) | | | +| 1458 | 409 | "未生效行聚合计数 ×2 呈现" | agg_txt.contains("⚠") and agg_txt.contains("×2") | (待填) | | | +| 1459 | 422 | "行型 %s 格式化落地(解析文本增长)" ↩ % String(row_type) | view.parsed_text().length() > before | (待填) | | | -## S195 _smoke_global_theme(行 444–539 · 22 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S195 _smoke_level_open_line(行 430–436 · 3 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1459 | 444 | "V1 项目主题挂载(project.godot gui/theme/custom → main_theme.tres)" | th != null | (待填) | | | -| 1460 | 453 | "V1 主题类型覆盖 %s" ↩ % t | type_set.has(t) | (待填) | | | -| 1461 | 455 | "V1 红线 Button 类型词条零接触" | not type_set.has("Button") | (待填) | | | -| 1462 | 463 | "V1 红线 focus 族词条零定义%s" ↩ % ("" if focus_hits == "" else "(违例:" + focus_hits + ")") | focus_hits == "" | (待填) | | | -| 1463 | 467 | "V1 滚动条槽/柄三态词条在位" | vsb.has_theme_stylebox("scroll") and vsb.has_theme_stylebox("grabber") and vsb.has_theme_stylebox("grabber_highlight") and vsb.has_theme_stylebox("grabber_pressed") | (待填) | | | -| 1464 | 470 | "V1 滚动条 scroll_focus 未定义(红线)" | not th.has_stylebox("scroll_focus", "VScrollBar") and not th.has_stylebox("scroll_focus", "HScrollBar") | (待填) | | | -| 1465 | 473 | "V1 滑轨槽/填充/柄词条在位" | hsl.has_theme_stylebox("slider") and hsl.has_theme_stylebox("grabber_area") and hsl.has_theme_stylebox("grabber_area_highlight") and hsl.has_theme_icon("grabber") and hsl.has_theme_icon("grabber_highlight") and hsl.has_theme_icon("grabber_disabled") | (待填) | | | -| 1466 | 479 | "V1 LineEdit 词条在位(含占位色 font_placeholder_color)" | le.has_theme_stylebox("normal") and le.has_theme_color("font_color") and le.has_theme_color("font_placeholder_color") | (待填) | | | -| 1467 | 483 | "V1 SpinBox 箭头词条在位(updown 合并槽)" | sp.has_theme_icon("updown") | (待填) | | | -| 1468 | 486 | "V1 分隔线词条在位" | hsep.has_theme_stylebox("separator") and vsep.has_theme_stylebox("separator") | (待填) | | | -| 1469 | 490 | "V1 TooltipPanel 词条在位" | tpanel.has_theme_stylebox("panel") | (待填) | | | -| 1470 | 491 | "V1 TooltipLabel 词条在位" | tlabel.has_theme_color("font_color") and tlabel.has_theme_font_size("font_size") | (待填) | | | -| 1471 | 499 | "V2 冻结值锚定(已填充段=BG_ROOT #3A2E22,槽=暖石 #B8A582)" | fill_c.is_equal_approx(Color8(58, 46, 34)) and track_c.is_equal_approx(Color8(184, 165, 130)) | (待填) | | | -| 1472 | 502 | "V2 滑轨两段对比 %.2f:1 ≥4.5:1(拖到中点一眼可辨)" ↩ % ratio | ratio >= 4.5 | (待填) | | | -| 1473 | 504 | "V2 滑轨 stylebox 类型均为 StyleBoxFlat" | false | (待填) | | | -| 1474 | 507 | "V3 CheckBox 四态图标非空" | cbx.get_theme_icon("checked") != null and cbx.get_theme_icon("unchecked") != null and cbx.get_theme_icon("checked_disabled") != null and cbx.get_theme_icon("unchecked_disabled") != null | (待填) | | | -| 1475 | 511 | "V3 CheckButton 四态图标非空(与 CheckBox 同套 checked/unchecked 名,4.7 源码实证)" | cbt.get_theme_icon("checked") != null and cbt.get_theme_icon("unchecked") != null and cbt.get_theme_icon("checked_disabled") != null and cbt.get_theme_icon("unchecked_disabled") != null | (待填) | | | -| 1476 | 515 | "V3 PopupMenu 词条存在(弹层预盖)" | pm.has_theme_stylebox("panel") and pm.has_theme_stylebox("hover") and pm.has_theme_font_size("font_size") | (待填) | | | -| 1477 | 519 | "V3 OptionButton 词条存在(预盖)" | ob.has_theme_stylebox("normal") and ob.has_theme_stylebox("hover") and ob.has_theme_stylebox("pressed") and ob.has_theme_color("font_color") | (待填) | | | -| 1478 | 533 | "V4 退役实现零残留(%s)%s" ↩ % [path, "" if bad == "" else "违例:" + bad] | bad == "" | (待填) | | | -| 1479 | 536 | "V6 主题 default_font 非空(挂主题顶掉 custom_font 也不丢中文字形)" | th.default_font != null | (待填) | | | -| 1480 | 539 | "V6 Label 实取字体非空(中文字形防御实证)" | lbl.get_theme_font("font") != null | (待填) | | | +| 1460 | 430 | "开场行 boosted=true 尾接「(含面板加成)」〔wc1〕" | String(NarratorScript.level_open_line("第一层", 42, 5, 30, true)).contains("(含面板加成)") | (待填) | | | +| 1461 | 432 | "开场行 boosted=false 零后缀(白板局不带)〔wc1〕" | not String(NarratorScript.level_open_line("第一层", 42, 5, 30, false)).contains("(含面板加成)") | (待填) | | | +| 1462 | 434 | "开场行种子/两值带入不受后缀位影响(数值带入回归)〔wc1〕" | String(NarratorScript.level_open_line("第一层", 42, 5, 30, true)).contains("种子 42") and String(NarratorScript.level_open_line("第一层", 42, 5, 30, true)).contains("攻击 5 / 生命 30") | (待填) | | | -## S196 _smoke_button_five_states(行 552–624 · 23 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S196 _smoke_global_theme(行 445–540 · 22 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1481 | 552 | "V1 普通钮 %s 样式盒非空" ↩ % st | b.has_theme_stylebox_override(st) | (待填) | | | -| 1482 | 558 | "V1 普通钮 normal/hover/disabled 均为石纹九宫格贴图样式盒" | n_sb is StyleBoxTexture and h_sb is StyleBoxTexture and d_sb is StyleBoxTexture | (待填) | | | -| 1483 | 562 | "V1 普通钮 hover=modulate 提亮(乙案,异于常态 WHITE)" | h_mod != Color.WHITE and h_mod.r > 1.0 | (待填) | | | -| 1484 | 566 | "V1 普通钮 disabled=本族底 α0.45 幽灵化(甲案)" | is_equal_approx(d_mod.a, 0.45) and d_mod.r == 1.0 and d_mod.g == 1.0 | (待填) | | | -| 1485 | 569 | "V1 普通钮 disabled≠pressed(旧错配已修正)" | _sb_content_differs(d_sb, p_sb) | (待填) | | | -| 1486 | 571 | "V1 普通钮 focus 样式盒为扁平环(StyleBoxFlat)" | f_sb is StyleBoxFlat | (待填) | | | -| 1487 | 573 | "V1 焦点环色=INK(与 font_focus_color 同源)" | fsb.border_color == uikit_s.INK | (待填) | | | -| 1488 | 574 | "V1 焦点环宽=2px" | is_equal_approx(fsb.border_width_left, 2.0) and is_equal_approx(fsb.border_width_right, 2.0) and is_equal_approx(fsb.border_width_top, 2.0) and is_equal_approx(fsb.border_width_bottom, 2.0) | (待填) | | | -| 1489 | 577 | "V1 焦点环内缩=1px" | is_equal_approx(fsb.expand_margin_left, -1.0) and is_equal_approx(fsb.expand_margin_top, -1.0) and is_equal_approx(fsb.expand_margin_right, -1.0) and is_equal_approx(fsb.expand_margin_bottom, -1.0) | (待填) | | | -| 1490 | 580 | "V1 焦点环无底(叠加态不遮钮底)" | not fsb.draw_center and fsb.bg_color.a < 0.001 | (待填) | | | -| 1491 | 585 | "V1 主钮 %s 样式盒非空" ↩ % st | pb.has_theme_stylebox_override(st) | (待填) | | | -| 1492 | 589 | "V1 主钮 pressed/disabled=本族平涂(非石纹)" | ppn is StyleBoxFlat and pdd is StyleBoxFlat | (待填) | | | -| 1493 | 591 | "V1 主钮 pressed=烛光黄深档(现行值不动)" | (ppn as StyleBoxFlat).bg_color == Color8(214, 172, 88) | (待填) | | | -| 1494 | 593 | "V1 主钮 disabled=本族底 α0.45 幽灵化" | is_equal_approx((pdd as StyleBoxFlat).bg_color.a, 0.45) | (待填) | | | -| 1495 | 595 | "V1 主钮 disabled≠pressed" | _sb_content_differs(ppn, pdd) | (待填) | | | -| 1496 | 596 | "V1 主钮 hover=提亮档(承现行不动)" | (phv as StyleBoxFlat).bg_color == uikit_s.CANDLE.lightened(0.06) | (待填) | | | -| 1497 | 602 | "V1 危险钮 %s 样式盒非空" ↩ % st | db.has_theme_stylebox_override(st) | (待填) | | | -| 1498 | 605 | "V1 危险钮 pressed/disabled=本族平涂(非石纹,旧错配已修正)" | dpr is StyleBoxFlat and dds is StyleBoxFlat | (待填) | | | -| 1499 | 607 | "V1 危险钮 pressed=深红深档(暗于常态)" | (dpr as StyleBoxFlat).bg_color.r < 180.0 / 255.0 | (待填) | | | -| 1500 | 609 | "V1 危险钮 disabled=本族底 α0.45 幽灵化" | is_equal_approx((dds as StyleBoxFlat).bg_color.a, 0.45) | (待填) | | | -| 1501 | 611 | "V1 危险钮 disabled≠pressed" | _sb_content_differs(dpr, dds) | (待填) | | | -| 1502 | 616 | "V2 红线维持 Button 类型词条零接触" | not th.get_type_list().has("Button") | (待填) | | | -| 1503 | 623 | "V2 红线维持 focus 族词条零定义%s" ↩ % ("" if focus_hits == "" else "(违例:" + focus_hits + ")") | focus_hits == "" | (待填) | | | +| 1463 | 445 | "V1 项目主题挂载(project.godot gui/theme/custom → main_theme.tres)" | th != null | (待填) | | | +| 1464 | 454 | "V1 主题类型覆盖 %s" ↩ % t | type_set.has(t) | (待填) | | | +| 1465 | 456 | "V1 红线 Button 类型词条零接触" | not type_set.has("Button") | (待填) | | | +| 1466 | 464 | "V1 红线 focus 族词条零定义%s" ↩ % ("" if focus_hits == "" else "(违例:" + focus_hits + ")") | focus_hits == "" | (待填) | | | +| 1467 | 468 | "V1 滚动条槽/柄三态词条在位" | vsb.has_theme_stylebox("scroll") and vsb.has_theme_stylebox("grabber") and vsb.has_theme_stylebox("grabber_highlight") and vsb.has_theme_stylebox("grabber_pressed") | (待填) | | | +| 1468 | 471 | "V1 滚动条 scroll_focus 未定义(红线)" | not th.has_stylebox("scroll_focus", "VScrollBar") and not th.has_stylebox("scroll_focus", "HScrollBar") | (待填) | | | +| 1469 | 474 | "V1 滑轨槽/填充/柄词条在位" | hsl.has_theme_stylebox("slider") and hsl.has_theme_stylebox("grabber_area") and hsl.has_theme_stylebox("grabber_area_highlight") and hsl.has_theme_icon("grabber") and hsl.has_theme_icon("grabber_highlight") and hsl.has_theme_icon("grabber_disabled") | (待填) | | | +| 1470 | 480 | "V1 LineEdit 词条在位(含占位色 font_placeholder_color)" | le.has_theme_stylebox("normal") and le.has_theme_color("font_color") and le.has_theme_color("font_placeholder_color") | (待填) | | | +| 1471 | 484 | "V1 SpinBox 箭头词条在位(updown 合并槽)" | sp.has_theme_icon("updown") | (待填) | | | +| 1472 | 487 | "V1 分隔线词条在位" | hsep.has_theme_stylebox("separator") and vsep.has_theme_stylebox("separator") | (待填) | | | +| 1473 | 491 | "V1 TooltipPanel 词条在位" | tpanel.has_theme_stylebox("panel") | (待填) | | | +| 1474 | 492 | "V1 TooltipLabel 词条在位" | tlabel.has_theme_color("font_color") and tlabel.has_theme_font_size("font_size") | (待填) | | | +| 1475 | 500 | "V2 冻结值锚定(已填充段=BG_ROOT #3A2E22,槽=暖石 #B8A582)" | fill_c.is_equal_approx(Color8(58, 46, 34)) and track_c.is_equal_approx(Color8(184, 165, 130)) | (待填) | | | +| 1476 | 503 | "V2 滑轨两段对比 %.2f:1 ≥4.5:1(拖到中点一眼可辨)" ↩ % ratio | ratio >= 4.5 | (待填) | | | +| 1477 | 505 | "V2 滑轨 stylebox 类型均为 StyleBoxFlat" | false | (待填) | | | +| 1478 | 508 | "V3 CheckBox 四态图标非空" | cbx.get_theme_icon("checked") != null and cbx.get_theme_icon("unchecked") != null and cbx.get_theme_icon("checked_disabled") != null and cbx.get_theme_icon("unchecked_disabled") != null | (待填) | | | +| 1479 | 512 | "V3 CheckButton 四态图标非空(与 CheckBox 同套 checked/unchecked 名,4.7 源码实证)" | cbt.get_theme_icon("checked") != null and cbt.get_theme_icon("unchecked") != null and cbt.get_theme_icon("checked_disabled") != null and cbt.get_theme_icon("unchecked_disabled") != null | (待填) | | | +| 1480 | 516 | "V3 PopupMenu 词条存在(弹层预盖)" | pm.has_theme_stylebox("panel") and pm.has_theme_stylebox("hover") and pm.has_theme_font_size("font_size") | (待填) | | | +| 1481 | 520 | "V3 OptionButton 词条存在(预盖)" | ob.has_theme_stylebox("normal") and ob.has_theme_stylebox("hover") and ob.has_theme_stylebox("pressed") and ob.has_theme_color("font_color") | (待填) | | | +| 1482 | 534 | "V4 退役实现零残留(%s)%s" ↩ % [path, "" if bad == "" else "违例:" + bad] | bad == "" | (待填) | | | +| 1483 | 537 | "V6 主题 default_font 非空(挂主题顶掉 custom_font 也不丢中文字形)" | th.default_font != null | (待填) | | | +| 1484 | 540 | "V6 Label 实取字体非空(中文字形防御实证)" | lbl.get_theme_font("font") != null | (待填) | | | -## S197 _smoke_texture_filter(行 631–673 · 9 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S197 _smoke_button_five_states(行 553–625 · 23 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1504 | 631 | "V3 工程设置 default_texture_filter=0(Nearest,翻转面=立绘/瓦片/九宫格 crisp)" | v != null and int(v) == 0 | (待填) | | | -| 1505 | 635 | "V3 白名单在位:暗角 vignette 显式 LINEAR" | vg.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR | (待填) | | | -| 1506 | 639 | "V3 白名单在位:光柱 beams 显式 LINEAR" | bm.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR | (待填) | | | -| 1507 | 657 | "T4 光柱带心峰值 α≈0.05(8bit 截断量化下限 12/255,实测 %.5f)" ↩ % max_a | max_a >= 12.0 / 255.0 and max_a <= 0.05 | (待填) | | | -| 1508 | 659 | "T4 光柱带内连续 alpha 过渡像素 %d 个(旧零过渡硬边已修)" ↩ % mid_a | mid_a > 100 | (待填) | | | -| 1509 | 660 | "T4 光柱纵向衰减生效(上半亮度 %.0f > 下半 %.0f 的 2 倍——上亮下暗)" ↩ % [top_sum, bot_sum] | top_sum > bot_sum * 2.0 | (待填) | | | -| 1510 | 664 | "V3 白名单在位:地图渐变 gradient_base 显式 LINEAR" | gb.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR | (待填) | | | -| 1511 | 669 | "V3 脚影显式 LINEAR 不丢(board_world.gd)" | bw_src.contains("shadow.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR") | (待填) | | | -| 1512 | 672 | "V3 状态图标显式 LINEAR 不丢(status_slot_row.gd)" | ss_src.contains("icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR") | (待填) | | | +| 1485 | 553 | "V1 普通钮 %s 样式盒非空" ↩ % st | b.has_theme_stylebox_override(st) | (待填) | | | +| 1486 | 559 | "V1 普通钮 normal/hover/disabled 均为石纹九宫格贴图样式盒" | n_sb is StyleBoxTexture and h_sb is StyleBoxTexture and d_sb is StyleBoxTexture | (待填) | | | +| 1487 | 563 | "V1 普通钮 hover=modulate 提亮(乙案,异于常态 WHITE)" | h_mod != Color.WHITE and h_mod.r > 1.0 | (待填) | | | +| 1488 | 567 | "V1 普通钮 disabled=本族底 α0.45 幽灵化(甲案)" | is_equal_approx(d_mod.a, 0.45) and d_mod.r == 1.0 and d_mod.g == 1.0 | (待填) | | | +| 1489 | 570 | "V1 普通钮 disabled≠pressed(旧错配已修正)" | _sb_content_differs(d_sb, p_sb) | (待填) | | | +| 1490 | 572 | "V1 普通钮 focus 样式盒为扁平环(StyleBoxFlat)" | f_sb is StyleBoxFlat | (待填) | | | +| 1491 | 574 | "V1 焦点环色=INK(与 font_focus_color 同源)" | fsb.border_color == uikit_s.INK | (待填) | | | +| 1492 | 575 | "V1 焦点环宽=2px" | is_equal_approx(fsb.border_width_left, 2.0) and is_equal_approx(fsb.border_width_right, 2.0) and is_equal_approx(fsb.border_width_top, 2.0) and is_equal_approx(fsb.border_width_bottom, 2.0) | (待填) | | | +| 1493 | 578 | "V1 焦点环内缩=1px" | is_equal_approx(fsb.expand_margin_left, -1.0) and is_equal_approx(fsb.expand_margin_top, -1.0) and is_equal_approx(fsb.expand_margin_right, -1.0) and is_equal_approx(fsb.expand_margin_bottom, -1.0) | (待填) | | | +| 1494 | 581 | "V1 焦点环无底(叠加态不遮钮底)" | not fsb.draw_center and fsb.bg_color.a < 0.001 | (待填) | | | +| 1495 | 586 | "V1 主钮 %s 样式盒非空" ↩ % st | pb.has_theme_stylebox_override(st) | (待填) | | | +| 1496 | 590 | "V1 主钮 pressed/disabled=本族平涂(非石纹)" | ppn is StyleBoxFlat and pdd is StyleBoxFlat | (待填) | | | +| 1497 | 592 | "V1 主钮 pressed=烛光黄深档(现行值不动)" | (ppn as StyleBoxFlat).bg_color == Color8(214, 172, 88) | (待填) | | | +| 1498 | 594 | "V1 主钮 disabled=本族底 α0.45 幽灵化" | is_equal_approx((pdd as StyleBoxFlat).bg_color.a, 0.45) | (待填) | | | +| 1499 | 596 | "V1 主钮 disabled≠pressed" | _sb_content_differs(ppn, pdd) | (待填) | | | +| 1500 | 597 | "V1 主钮 hover=提亮档(承现行不动)" | (phv as StyleBoxFlat).bg_color == uikit_s.CANDLE.lightened(0.06) | (待填) | | | +| 1501 | 603 | "V1 危险钮 %s 样式盒非空" ↩ % st | db.has_theme_stylebox_override(st) | (待填) | | | +| 1502 | 606 | "V1 危险钮 pressed/disabled=本族平涂(非石纹,旧错配已修正)" | dpr is StyleBoxFlat and dds is StyleBoxFlat | (待填) | | | +| 1503 | 608 | "V1 危险钮 pressed=深红深档(暗于常态)" | (dpr as StyleBoxFlat).bg_color.r < 180.0 / 255.0 | (待填) | | | +| 1504 | 610 | "V1 危险钮 disabled=本族底 α0.45 幽灵化" | is_equal_approx((dds as StyleBoxFlat).bg_color.a, 0.45) | (待填) | | | +| 1505 | 612 | "V1 危险钮 disabled≠pressed" | _sb_content_differs(dpr, dds) | (待填) | | | +| 1506 | 617 | "V2 红线维持 Button 类型词条零接触" | not th.get_type_list().has("Button") | (待填) | | | +| 1507 | 624 | "V2 红线维持 focus 族词条零定义%s" ↩ % ("" if focus_hits == "" else "(违例:" + focus_hits + ")") | focus_hits == "" | (待填) | | | -## S198 _smoke_contrast_inks(行 682–698 · 9 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S198 _smoke_texture_filter(行 632–674 · 9 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1513 | 682 | "V4 顺位徽标/重甲徽标 GOLD_BRIGHT 对舞台底 %.2f:1 ≥4.5:1" ↩ % r_order | r_order >= 4.5 | (待填) | | | -| 1514 | 684 | "V4 魔法护甲徽标 HERO_BLUE_BRIGHT 对舞台底 %.2f:1 ≥4.5:1" ↩ % r_ward | r_ward >= 4.5 | (待填) | | | -| 1515 | 686 | "V4 RAP 反馈行 STONE_DEEP 对数据板 %.2f:1 ≥4.5:1" ↩ % r_rap | r_rap >= 4.5 | (待填) | | | -| 1516 | 689 | "V4 顺位徽标①②③ 墨=GOLD_BRIGHT(13px 行原位)" | sb_src.contains("HORIZONTAL_ALIGNMENT_LEFT, -1, 13, UiKit.GOLD_BRIGHT") | (待填) | | | -| 1517 | 691 | "V4 魔法护甲徽标墨=HERO_BLUE_BRIGHT" | sb_src.contains("col = UiKit.HERO_BLUE_BRIGHT") | (待填) | | | -| 1518 | 692 | "V4 重甲徽标墨=GOLD_BRIGHT" | sb_src.contains("col = UiKit.GOLD_BRIGHT") | (待填) | | | -| 1519 | 693 | "V4 意图蓄力档判据=分档布尔(standee_body:179 CHARGE_SKILL_IDS 判定;旧 GOLD_DEEP 恒不可达判据清零)〔wd2〕" | sb_src.contains("_intent_charge = pid in CHARGE_SKILL_IDS") and not sb_src.contains("if _intent_col == UiKit.GOLD_DEEP:") | (待填) | | | -| 1520 | 696 | "V4 RAP 反馈行墨=STONE_DEEP(原位行锚定)" | ap_src.contains('UiKit.label("",UiKit.FS_CAPTION, false, UiKit.STONE_DEEP)') | (待填) | | | -| 1521 | 698 | "V4 RAP 反馈行旧墨 STONE_FAINT 清零(含注记面)" | not ap_src.contains("STONE_FAINT") | (待填) | | | +| 1508 | 632 | "V3 工程设置 default_texture_filter=0(Nearest,翻转面=立绘/瓦片/九宫格 crisp)" | v != null and int(v) == 0 | (待填) | | | +| 1509 | 636 | "V3 白名单在位:暗角 vignette 显式 LINEAR" | vg.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR | (待填) | | | +| 1510 | 640 | "V3 白名单在位:光柱 beams 显式 LINEAR" | bm.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR | (待填) | | | +| 1511 | 658 | "T4 光柱带心峰值 α≈0.05(8bit 截断量化下限 12/255,实测 %.5f)" ↩ % max_a | max_a >= 12.0 / 255.0 and max_a <= 0.05 | (待填) | | | +| 1512 | 660 | "T4 光柱带内连续 alpha 过渡像素 %d 个(旧零过渡硬边已修)" ↩ % mid_a | mid_a > 100 | (待填) | | | +| 1513 | 661 | "T4 光柱纵向衰减生效(上半亮度 %.0f > 下半 %.0f 的 2 倍——上亮下暗)" ↩ % [top_sum, bot_sum] | top_sum > bot_sum * 2.0 | (待填) | | | +| 1514 | 665 | "V3 白名单在位:地图渐变 gradient_base 显式 LINEAR" | gb.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR | (待填) | | | +| 1515 | 670 | "V3 脚影显式 LINEAR 不丢(board_world.gd)" | bw_src.contains("shadow.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR") | (待填) | | | +| 1516 | 673 | "V3 状态图标显式 LINEAR 不丢(status_slot_row.gd)" | ss_src.contains("icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR") | (待填) | | | -## S199 _smoke_element_details(行 707–726 · 8 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S199 _smoke_contrast_inks(行 683–699 · 9 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1522 | 707 | "T5② BCard 图标槽白图标对比 %.2f:1 ≥3:1(硬约束)" ↩ % r_white | r_white >= 3.0 | (待填) | | | -| 1523 | 710 | "T5② 明度差降档生效(槽对卡面 %.2f:1 < 旧 %.2f:1)" ↩ % [r_new, r_old] | r_new < r_old | (待填) | | | -| 1524 | 712 | "T5② BCard 图标槽落柔和档(SLOT_BACKDROP_SOFT)" | uk_src.contains("UiKit.panel_flat(SLOT_BACKDROP_SOFT, PANEL_BORDER, 0, 1)") | (待填) | | | -| 1525 | 715 | "T5② B 区状态图标槽仍用深档(SLOT_BACKDROP,未误伤)" | ss_src.contains("UiKit.SLOT_BACKDROP") | (待填) | | | -| 1526 | 719 | "T5③ 商店卡片区垂直居中(ALIGNMENT_CENTER)" | shop_src.contains("_cards_box.alignment = BoxContainer.ALIGNMENT_CENTER") | (待填) | | | -| 1527 | 723 | "T5③ 营地三 holder 统一 min 高 336(实测 %d 处)" ↩ % camp_min | camp_min == 3 | (待填) | | | -| 1528 | 725 | "T5③ 营地四栏面板纵向 FILL 等高(实测 %d 处)" ↩ % camp_fill | camp_fill == 4 | (待填) | | | -| 1529 | 726 | "T5③ 三处锁文垂直居中在位" | camp_src.count("SIZE_SHRINK_CENTER") >= 3 | (待填) | | | +| 1517 | 683 | "V4 顺位徽标/重甲徽标 GOLD_BRIGHT 对舞台底 %.2f:1 ≥4.5:1" ↩ % r_order | r_order >= 4.5 | (待填) | | | +| 1518 | 685 | "V4 魔法护甲徽标 HERO_BLUE_BRIGHT 对舞台底 %.2f:1 ≥4.5:1" ↩ % r_ward | r_ward >= 4.5 | (待填) | | | +| 1519 | 687 | "V4 RAP 反馈行 STONE_DEEP 对数据板 %.2f:1 ≥4.5:1" ↩ % r_rap | r_rap >= 4.5 | (待填) | | | +| 1520 | 690 | "V4 顺位徽标①②③ 墨=GOLD_BRIGHT(13px 行原位)" | sb_src.contains("HORIZONTAL_ALIGNMENT_LEFT, -1, 13, UiKit.GOLD_BRIGHT") | (待填) | | | +| 1521 | 692 | "V4 魔法护甲徽标墨=HERO_BLUE_BRIGHT" | sb_src.contains("col = UiKit.HERO_BLUE_BRIGHT") | (待填) | | | +| 1522 | 693 | "V4 重甲徽标墨=GOLD_BRIGHT" | sb_src.contains("col = UiKit.GOLD_BRIGHT") | (待填) | | | +| 1523 | 694 | "V4 意图蓄力档判据=分档布尔(standee_body:179 CHARGE_SKILL_IDS 判定;旧 GOLD_DEEP 恒不可达判据清零)〔wd2〕" | sb_src.contains("_intent_charge = pid in CHARGE_SKILL_IDS") and not sb_src.contains("if _intent_col == UiKit.GOLD_DEEP:") | (待填) | | | +| 1524 | 697 | "V4 RAP 反馈行墨=STONE_DEEP(原位行锚定)" | ap_src.contains('UiKit.label("",UiKit.FS_CAPTION, false, UiKit.STONE_DEEP)') | (待填) | | | +| 1525 | 699 | "V4 RAP 反馈行旧墨 STONE_FAINT 清零(含注记面)" | not ap_src.contains("STONE_FAINT") | (待填) | | | -## S200 _smoke_diag_button_retired(行 733–746 · 7 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S200 _smoke_element_details(行 708–727 · 8 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1530 | 733 | "V6 主区无 build_diag_button 调用残留(旧实现同批清理)" | not main_src.contains("build_diag_button") | (待填) | | | -| 1531 | 735 | "V6 转储入口连接随迁(组合根接浮窗 diagnose_requested 信号)" | main_src.contains("debug_overlay.diagnose_requested.connect(_on_diagnose_pressed)") | (待填) | | | -| 1532 | 737 | "V6 转储编排承接函数在位(dump_diagnosis 卡死取证保留)" | main_src.contains("func _on_diagnose_pressed()") | (待填) | | | -| 1533 | 740 | "V6 build_diag_button 工厂已退役(ui_assembler 零残留)" | not asm_src.contains("build_diag_button") | (待填) | | | -| 1534 | 743 | "V6 调试浮窗 diagnose_requested 信号在位" | dbg_src.contains("signal diagnose_requested") | (待填) | | | -| 1535 | 744 | "V6 浮窗转储钮外发方法在位(纯视图边界)" | dbg_src.contains("_emit_diagnose_requested") | (待填) | | | -| 1536 | 745 | "V6 浮窗诊断转储钮在位(玩家画面角落钮清零后唯一入口)" | dbg_src.contains('UiKit.button("转储")') | (待填) | | | +| 1526 | 708 | "T5② BCard 图标槽白图标对比 %.2f:1 ≥3:1(硬约束)" ↩ % r_white | r_white >= 3.0 | (待填) | | | +| 1527 | 711 | "T5② 明度差降档生效(槽对卡面 %.2f:1 < 旧 %.2f:1)" ↩ % [r_new, r_old] | r_new < r_old | (待填) | | | +| 1528 | 713 | "T5② BCard 图标槽落柔和档(SLOT_BACKDROP_SOFT)" | uk_src.contains("UiKit.panel_flat(SLOT_BACKDROP_SOFT, PANEL_BORDER, 0, 1)") | (待填) | | | +| 1529 | 716 | "T5② B 区状态图标槽仍用深档(SLOT_BACKDROP,未误伤)" | ss_src.contains("UiKit.SLOT_BACKDROP") | (待填) | | | +| 1530 | 720 | "T5③ 商店卡片区垂直居中(ALIGNMENT_CENTER)" | shop_src.contains("_cards_box.alignment = BoxContainer.ALIGNMENT_CENTER") | (待填) | | | +| 1531 | 724 | "T5③ 营地三 holder 统一 min 高 336(实测 %d 处)" ↩ % camp_min | camp_min == 3 | (待填) | | | +| 1532 | 726 | "T5③ 营地四栏面板纵向 FILL 等高(实测 %d 处)" ↩ % camp_fill | camp_fill == 4 | (待填) | | | +| 1533 | 727 | "T5③ 三处锁文垂直居中在位" | camp_src.count("SIZE_SHRINK_CENTER") >= 3 | (待填) | | | -## S201 _status_panel_projection(行 762–792 · 10 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S201 _smoke_diag_button_retired(行 734–747 · 7 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1537 | 762 | "状态面板开层可见(open_status 直开——P4 甲零动效路径)" | po.visible | (待填) | | | -| 1538 | 763 | "余额徽投影 = 快照 balance 读数(sv4 回归锚)〔sv4〕" | String(po._balance_badge.value_label.text) == "钥石 77" | (待填) | | | -| 1539 | 765 | "属性行全值投影 = 契约4 钉值格式逐字(生命/上限/攻击/AC/GP 五现值)〔sv1〕" | String(po._attrs_label.text) == "生命 13/29 · 攻击 7 · 护甲 AC 11 · GP 41" | (待填) | | | -| 1540 | 767 | "秘宝行投影 = 受理序 join+已用件「(已用)」尾缀〔sv2〕" | String(po._curios_label.text) == "青苔密卷 · 锈蚀怀表(已用)" | (待填) | | | -| 1541 | 769 | "专长行投影 = 行串 join〔sv3〕" | String(po._feats_label.text) == "疼痛记忆 ×2 · 双管镐 ×1" | (待填) | | | -| 1542 | 776 | "面板子树零「道具工坊/天赋树」文案(跨关概览退役零残留)〔sv5〕" | stale == "" | (待填) | | | -| 1543 | 777 | "旧段成员退役(_workshop_holder/_tree_label 零残留——契约2 数据/成员层面清零)〔sv5〕" | po.get("_workshop_holder") == null and po.get("_tree_label") == null | (待填) | | | -| 1544 | 784 | "空秘宝态句=「未携带秘宝」〔sv2〕" | String(po2._curios_label.text) == "未携带秘宝" | (待填) | | | -| 1545 | 785 | "空专长态句=「未获专长」〔sv3〕" | String(po2._feats_label.text) == "未获专长" | (待填) | | | -| 1546 | 791 | "提示行=「查看本局冒险进度(只读)」(新定位换代)〔sv8〕" | hint_txt == "查看本局冒险进度(只读)" | (待填) | | | +| 1534 | 734 | "V6 主区无 build_diag_button 调用残留(旧实现同批清理)" | not main_src.contains("build_diag_button") | (待填) | | | +| 1535 | 736 | "V6 转储入口连接随迁(组合根接浮窗 diagnose_requested 信号)" | main_src.contains("debug_overlay.diagnose_requested.connect(_on_diagnose_pressed)") | (待填) | | | +| 1536 | 738 | "V6 转储编排承接函数在位(dump_diagnosis 卡死取证保留)" | main_src.contains("func _on_diagnose_pressed()") | (待填) | | | +| 1537 | 741 | "V6 build_diag_button 工厂已退役(ui_assembler 零残留)" | not asm_src.contains("build_diag_button") | (待填) | | | +| 1538 | 744 | "V6 调试浮窗 diagnose_requested 信号在位" | dbg_src.contains("signal diagnose_requested") | (待填) | | | +| 1539 | 745 | "V6 浮窗转储钮外发方法在位(纯视图边界)" | dbg_src.contains("_emit_diagnose_requested") | (待填) | | | +| 1540 | 746 | "V6 浮窗诊断转储钮在位(玩家画面角落钮清零后唯一入口)" | dbg_src.contains('UiKit.button("转储")') | (待填) | | | -## S202 _career_overlay_projection(行 837–872 · 8 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) +## S202 _status_panel_projection(行 763–793 · 10 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1547 | 837 | "生涯页开层可见(open_career 直开——零动效路径)" | co.visible | (待填) | | | -| 1548 | 838 | "总局数投影 = adventure_total() 读数(%s)" ↩ % co._total_label.text | String(co._total_label.text) == "2 局" | (待填) | | | -| 1549 | 840 | "通关局数投影 = adventure_cleared() 读数(%s)" ↩ % co._cleared_label.text | String(co._cleared_label.text) == "1 局(三关全通)" | (待填) | | | -| 1550 | 845 | "各关通关次数投影 = clear_count() 逐关读数(%s)" ↩ % co._clears_label.text | String(co._clears_label.text) == " · ".join(expect_clears) | (待填) | | | -| 1551 | 847 | "Boss 首杀/总杀投影 = 首杀标记计数 + boss_kill_count()(%s / %s)" ↩ % [co._boss_first_label.text, co._boss_kills_label.text] | String(co._boss_first_label.text) == "3/3 关" and String(co._boss_kills_label.text) == "4 次" | (待填) | | | -| 1552 | 849 | "钥石余额徽投影 = keystone_balance() 读数(%s)" ↩ % co._keystone_badge.value_label.text | String(co._keystone_badge.value_label.text) == "钥石 %d" % mp.keystone_balance() | (待填) | | | -| 1553 | 858 | "v5 现役档升 v6 载入成功(计数域缺省补零)" | v5.load_from_disk() and v5.adventure_total() == 0 and v5.adventure_cleared() == 0 | (待填) | | | -| 1554 | 869 | "旧档载入后生涯页正常显示(v5 升 v6:总局数/通关局数显示 0,既有钥石余额原样呈现)" | co_v5.visible and String(co_v5._total_label.text) == "0 局" \\ and String(co_v5._cleared_label.text) == "0 局(三关全通)" \\ and String(co_v5._keystone_badge.value_label.text) == "钥石 3" | (待填) | | | +| 1541 | 763 | "状态面板开层可见(open_status 直开——P4 甲零动效路径)" | po.visible | (待填) | | | +| 1542 | 764 | "余额徽投影 = 快照 balance 读数(sv4 回归锚)〔sv4〕" | String(po._balance_badge.value_label.text) == "钥石 77" | (待填) | | | +| 1543 | 766 | "属性行全值投影 = 契约4 钉值格式逐字(生命/上限/攻击/AC/GP 五现值)〔sv1〕" | String(po._attrs_label.text) == "生命 13/29 · 攻击 7 · 护甲 AC 11 · GP 41" | (待填) | | | +| 1544 | 768 | "秘宝行投影 = 受理序 join+已用件「(已用)」尾缀〔sv2〕" | String(po._curios_label.text) == "青苔密卷 · 锈蚀怀表(已用)" | (待填) | | | +| 1545 | 770 | "专长行投影 = 行串 join〔sv3〕" | String(po._feats_label.text) == "疼痛记忆 ×2 · 双管镐 ×1" | (待填) | | | +| 1546 | 777 | "面板子树零「道具工坊/天赋树」文案(跨关概览退役零残留)〔sv5〕" | stale == "" | (待填) | | | +| 1547 | 778 | "旧段成员退役(_workshop_holder/_tree_label 零残留——契约2 数据/成员层面清零)〔sv5〕" | po.get("_workshop_holder") == null and po.get("_tree_label") == null | (待填) | | | +| 1548 | 785 | "空秘宝态句=「未携带秘宝」〔sv2〕" | String(po2._curios_label.text) == "未携带秘宝" | (待填) | | | +| 1549 | 786 | "空专长态句=「未获专长」〔sv3〕" | String(po2._feats_label.text) == "未获专长" | (待填) | | | +| 1550 | 792 | "提示行=「查看本局冒险进度(只读)」(新定位换代)〔sv8〕" | hint_txt == "查看本局冒险进度(只读)" | (待填) | | | -## S203 _test_grouping_closed(行 61–79 · 7 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) +## S203 _camp_recent_projection(行 818–819 · 1 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1555 | 61 | "九型封闭:%s → 组%d(期望组%d)" ↩ % [t, got, int(TYPE_EXPECT[t])] | got == int(TYPE_EXPECT[t]) | (待填) | | | -| 1556 | 65 | "清单外值「%s」→ GLOW_NONE(禁静默空光)" ↩ % bad | UiKitScript.glow_group_for_cell_type(bad) == UiKitScript.GLOW_NONE | (待填) | | | -| 1557 | 70 | "两带并存锚定:卡顶带 blast→TG_MAGIC(E5 回滚既存行为未动)" | band_blast == UiKitScript.TG_MAGIC | (待填) | | | -| 1558 | 71 | "两带并存锚定:格面微光 blast→群伤组(与卡顶带刻意不同)" | UiKitScript.glow_group_for_cell_type("blast") == UiKitScript.GLOW_AOE | (待填) | | | -| 1559 | 74 | "glow_color_for_group 群伤组 = TG_GLOW_AOE" | UiKitScript.glow_color_for_group(UiKitScript.GLOW_AOE) == UiKitScript.TG_GLOW_AOE | (待填) | | | -| 1560 | 76 | "glow_color_for_group 无组(GLOW_NONE)→ 全透明" | UiKitScript.glow_color_for_group(UiKitScript.GLOW_NONE) == Color(0, 0, 0, 0) | (待填) | | | -| 1561 | 78 | "glow_color_for_group 越界组号 → 全透明" | UiKitScript.glow_color_for_group(99) == Color(0, 0, 0, 0) | (待填) | | | +| 1551 | 818 | "营地最近冒险行完成关数措辞(实际「%s」)〔口径换代 V6〕" ↩ % recent_text | recent_text.contains("完成 2 关") and not recent_text.contains("通关") | (待填) | | | -## S204 _test_frozen_hue_face(行 88–102 · 5 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) +## S204 _career_overlay_projection(行 852–897 · 11 条 · 源 game/tests/unit/presentation/theme_projection_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1562 | 88 | "实现值锚定:%s = #%02X%02X%02X(色值单点 ui_kit,逐位钉死)" ↩ % [CONST_NAME[g], int(m.r8), int(m.g8), int(m.b8)] | impl_const == m | (待填) | | | -| 1563 | 93 | "冻结色相保持:%s ΔH=%.3f° ≤0.2° 且 ΔS=%.4f ≤0.01(只动明度档)" ↩ % [g, dh * 360.0, ds] | dh <= 0.2 / 360.0 and ds <= 0.01 | (待填) | | | -| 1564 | 98 | "群伤组专项:H 与冻结 #FF2D55 差 %.4f°(零移动)" ↩ % (absf(aoe_m.h - aoe_f.h) * 360.0) | absf(aoe_m.h - aoe_f.h) < 0.001 | (待填) | | | -| 1565 | 100 | "群伤组专项:S 与冻结差 %.4f ≤0.01(8bit 量化噪声级)" ↩ % absf(aoe_m.s - aoe_f.s) | absf(aoe_m.s - aoe_f.s) <= 0.01 | (待填) | | | -| 1566 | 102 | "群伤组专项:V=0.65 明度档( provisional 域内)" | absf(aoe_m.v - 166.0 / 255.0) < 0.002 | (待填) | | | +| 1552 | 852 | "生涯页开层可见(open_career 直开——零动效路径)" | co.visible | (待填) | | | +| 1553 | 853 | "总局数投影 = adventure_total() 读数(%s)" ↩ % co._total_label.text | String(co._total_label.text) == "2 局" | (待填) | | | +| 1554 | 855 | "冒险成功局数投影 = adventure_cleared() 读数(%s)" ↩ % co._cleared_label.text | String(co._cleared_label.text) == "1 局(三关全通)" | (待填) | | | +| 1555 | 860 | "各关完成次数投影 = clear_count() 逐关读数(%s)" ↩ % co._clears_label.text | String(co._clears_label.text) == " · ".join(expect_clears) | (待填) | | | +| 1556 | 862 | "Boss 首杀/总杀投影 = 首杀标记计数 + boss_kill_count()(%s / %s)" ↩ % [co._boss_first_label.text, co._boss_kills_label.text] | String(co._boss_first_label.text) == "3/3 关" and String(co._boss_kills_label.text) == "4 次" | (待填) | | | +| 1557 | 864 | "钥石余额徽投影 = keystone_balance() 读数(%s)" ↩ % co._keystone_badge.value_label.text | String(co._keystone_badge.value_label.text) == "钥石 %d" % mp.keystone_balance() | (待填) | | | +| 1558 | 871 | "生涯页行标签换代(冒险成功局数/各关完成次数)〔口径换代 V4〕" | career_labels_joined.contains("冒险成功局数") and career_labels_joined.contains("各关完成次数") | (待填) | | | +| 1559 | 873 | "生涯页 label 全集零「通关」残留〔口径换代 V4〕" | not career_labels_joined.contains("通关") | (待填) | | | +| 1560 | 874 | "秘宝解锁条件标签冒险成功口径(UiKit 单点常量)〔口径换代 V5〕" | UiKit.TREASURE_REQ_LABELS["adventure_cleared"] == "冒险成功" | (待填) | | | +| 1561 | 883 | "v5 现役档升 v6 载入成功(计数域缺省补零)" | v5.load_from_disk() and v5.adventure_total() == 0 and v5.adventure_cleared() == 0 | (待填) | | | +| 1562 | 894 | "旧档载入后生涯页正常显示(v5 升 v6:总局数/冒险成功局数显示 0,既有钥石余额原样呈现)" | co_v5.visible and String(co_v5._total_label.text) == "0 局" \\ and String(co_v5._cleared_label.text) == "0 局(三关全通)" \\ and String(co_v5._keystone_badge.value_label.text) == "钥石 3" | (待填) | | | -## S205 _test_render_params(行 107–113 · 3 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) +## S205 _test_grouping_closed(行 61–79 · 7 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1567 | 107 | "泛光强度 α = 170/255(v2 呈现参数冻结)" | is_equal_approx(UiKitScript.TYPE_GLOW_ALPHA, 170.0 / 255.0) | (待填) | | | -| 1568 | 109 | "带宽 = cell÷8(TYPE_GLOW_BAND_FRAC=0.125)" | is_equal_approx(UiKitScript.TYPE_GLOW_BAND_FRAC, 0.125) | (待填) | | | -| 1569 | 111 | "组号常量域连续(GLOW_NONE=0…GLOW_MAGIC=5)" | UiKitScript.GLOW_NONE == 0 and UiKitScript.GLOW_BUFF == 1 and UiKitScript.GLOW_HEAL == 2 and UiKitScript.GLOW_PIERCE == 3 and UiKitScript.GLOW_AOE == 4 and UiKitScript.GLOW_MAGIC == 5 | (待填) | | | +| 1563 | 61 | "九型封闭:%s → 组%d(期望组%d)" ↩ % [t, got, int(TYPE_EXPECT[t])] | got == int(TYPE_EXPECT[t]) | (待填) | | | +| 1564 | 65 | "清单外值「%s」→ GLOW_NONE(禁静默空光)" ↩ % bad | UiKitScript.glow_group_for_cell_type(bad) == UiKitScript.GLOW_NONE | (待填) | | | +| 1565 | 70 | "两带并存锚定:卡顶带 blast→TG_MAGIC(E5 回滚既存行为未动)" | band_blast == UiKitScript.TG_MAGIC | (待填) | | | +| 1566 | 71 | "两带并存锚定:格面微光 blast→群伤组(与卡顶带刻意不同)" | UiKitScript.glow_group_for_cell_type("blast") == UiKitScript.GLOW_AOE | (待填) | | | +| 1567 | 74 | "glow_color_for_group 群伤组 = TG_GLOW_AOE" | UiKitScript.glow_color_for_group(UiKitScript.GLOW_AOE) == UiKitScript.TG_GLOW_AOE | (待填) | | | +| 1568 | 76 | "glow_color_for_group 无组(GLOW_NONE)→ 全透明" | UiKitScript.glow_color_for_group(UiKitScript.GLOW_NONE) == Color(0, 0, 0, 0) | (待填) | | | +| 1569 | 78 | "glow_color_for_group 越界组号 → 全透明" | UiKitScript.glow_color_for_group(99) == Color(0, 0, 0, 0) | (待填) | | | -## S206 _test_gamma_ladder(行 128–139 · 3 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) +## S206 _test_frozen_hue_face(行 88–102 · 5 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1570 | 128 | "阶梯单调:%s 合成亮度 %.4f < 上一档 %.4f(伽马合成空间)" ↩ % [g, lum, prev_lum] | lum < prev_lum | (待填) | | | -| 1571 | 134 | "相邻组模型 CR:%s/%s = %.3f ≥1.20(色弱互辨预判)" ↩ % [order[i], order[i + 1], cr] | cr >= 1.20 | (待填) | | | -| 1572 | 138 | "群伤/魔法线性亮度序:群伤 %.4f < 魔法 %.4f(首版 CIE L* 排反事故的守门)" ↩ % [aoe_lin, magic_lin] | aoe_lin < magic_lin | (待填) | | | +| 1570 | 88 | "实现值锚定:%s = #%02X%02X%02X(色值单点 ui_kit,逐位钉死)" ↩ % [CONST_NAME[g], int(m.r8), int(m.g8), int(m.b8)] | impl_const == m | (待填) | | | +| 1571 | 93 | "冻结色相保持:%s ΔH=%.3f° ≤0.2° 且 ΔS=%.4f ≤0.01(只动明度档)" ↩ % [g, dh * 360.0, ds] | dh <= 0.2 / 360.0 and ds <= 0.01 | (待填) | | | +| 1572 | 98 | "群伤组专项:H 与冻结 #FF2D55 差 %.4f°(零移动)" ↩ % (absf(aoe_m.h - aoe_f.h) * 360.0) | absf(aoe_m.h - aoe_f.h) < 0.001 | (待填) | | | +| 1573 | 100 | "群伤组专项:S 与冻结差 %.4f ≤0.01(8bit 量化噪声级)" ↩ % absf(aoe_m.s - aoe_f.s) | absf(aoe_m.s - aoe_f.s) <= 0.01 | (待填) | | | +| 1574 | 102 | "群伤组专项:V=0.65 明度档( provisional 域内)" | absf(aoe_m.v - 166.0 / 255.0) < 0.002 | (待填) | | | -## S207 _test_probe_api_shape(行 146–153 · 5 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) +## S207 _test_render_params(行 107–113 · 3 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1573 | 146 | "probe 键集 = {enabled, cells, errors}" | snap.has("enabled") and snap.has("cells") and snap.has("errors") and snap.size() == 3 | (待填) | | | -| 1574 | 148 | "probe 默认态:enabled=true(Q4 丙案生产默认开)" | bool(snap.get("enabled", false)) | (待填) | | | -| 1575 | 149 | "probe 默认态:作用集空(无板未派生)" | (snap.get("cells", {}) as Dictionary).is_empty() | (待填) | | | -| 1576 | 150 | "probe 默认态:清单外登记空" | (snap.get("errors", []) as Array).is_empty() | (待填) | | | -| 1577 | 152 | "set_type_glow_enabled(false) → probe enabled=false(无板不崩)" | not bool(view.type_glow_probe().get("enabled", true)) | (待填) | | | +| 1575 | 107 | "泛光强度 α = 170/255(v2 呈现参数冻结)" | is_equal_approx(UiKitScript.TYPE_GLOW_ALPHA, 170.0 / 255.0) | (待填) | | | +| 1576 | 109 | "带宽 = cell÷8(TYPE_GLOW_BAND_FRAC=0.125)" | is_equal_approx(UiKitScript.TYPE_GLOW_BAND_FRAC, 0.125) | (待填) | | | +| 1577 | 111 | "组号常量域连续(GLOW_NONE=0…GLOW_MAGIC=5)" | UiKitScript.GLOW_NONE == 0 and UiKitScript.GLOW_BUFF == 1 and UiKitScript.GLOW_HEAL == 2 and UiKitScript.GLOW_PIERCE == 3 and UiKitScript.GLOW_AOE == 4 and UiKitScript.GLOW_MAGIC == 5 | (待填) | | | -## S208 _init(行 16–28 · 6 条 · 源 game/tests/unit/presentation/ui_font_asset_test.gd · 去向:待分类回填) +## S208 _test_gamma_ladder(行 128–139 · 3 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) | 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | |---|---|---|---|---|---|---| -| 1578 | 16 | "随包字体守卫装载非空(res://assets/fonts/ui_font_fusion_pixel_zh_hans.ttf)" | f != null | (待填) | | | -| 1579 | 18 | "中文字形在集(攻/雷/旗/封)" | f.has_char("攻".unicode_at(0)) and f.has_char("雷".unicode_at(0)) \\ and f.has_char("旗".unicode_at(0)) and f.has_char("封".unicode_at(0)) | (待填) | | | -| 1580 | 20 | "中文字形在集(危——已开危险格字形换代前置,迭代36 u12/wa9)" | f.has_char("危".unicode_at(0)) | (待填) | | | -| 1581 | 21 | "ASCII/数字字形在集(A/0/%)" | f.has_char("A".unicode_at(0)) and f.has_char("0".unicode_at(0)) and f.has_char("%".unicode_at(0)) | (待填) | | | -| 1582 | 25 | "中文采样文本宽度 > 0(C6 headless 判据)" | w_cn > 0.0 and w_label > 0.0 | (待填) | | | -| 1583 | 28 | "字体缺失时后续断言跳过(缺位=回归,此行仅占位计数)" | false | (待填) | | | +| 1578 | 128 | "阶梯单调:%s 合成亮度 %.4f < 上一档 %.4f(伽马合成空间)" ↩ % [g, lum, prev_lum] | lum < prev_lum | (待填) | | | +| 1579 | 134 | "相邻组模型 CR:%s/%s = %.3f ≥1.20(色弱互辨预判)" ↩ % [order[i], order[i + 1], cr] | cr >= 1.20 | (待填) | | | +| 1580 | 138 | "群伤/魔法线性亮度序:群伤 %.4f < 魔法 %.4f(首版 CIE L* 排反事故的守门)" ↩ % [aoe_lin, magic_lin] | aoe_lin < magic_lin | (待填) | | | + +## S209 _test_probe_api_shape(行 146–153 · 5 条 · 源 game/tests/unit/presentation/type_glow_test.gd · 去向:待分类回填) + +| 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | +|---|---|---|---|---|---|---| +| 1581 | 146 | "probe 键集 = {enabled, cells, errors}" | snap.has("enabled") and snap.has("cells") and snap.has("errors") and snap.size() == 3 | (待填) | | | +| 1582 | 148 | "probe 默认态:enabled=true(Q4 丙案生产默认开)" | bool(snap.get("enabled", false)) | (待填) | | | +| 1583 | 149 | "probe 默认态:作用集空(无板未派生)" | (snap.get("cells", {}) as Dictionary).is_empty() | (待填) | | | +| 1584 | 150 | "probe 默认态:清单外登记空" | (snap.get("errors", []) as Array).is_empty() | (待填) | | | +| 1585 | 152 | "set_type_glow_enabled(false) → probe enabled=false(无板不崩)" | not bool(view.type_glow_probe().get("enabled", true)) | (待填) | | | + +## S210 _init(行 16–28 · 6 条 · 源 game/tests/unit/presentation/ui_font_asset_test.gd · 去向:待分类回填) + +| 序号 | 行号 | 标签原文 | cond 摘要 | 白话释义 | 处置 | quiet | +|---|---|---|---|---|---|---| +| 1586 | 16 | "随包字体守卫装载非空(res://assets/fonts/ui_font_fusion_pixel_zh_hans.ttf)" | f != null | (待填) | | | +| 1587 | 18 | "中文字形在集(攻/雷/旗/封)" | f.has_char("攻".unicode_at(0)) and f.has_char("雷".unicode_at(0)) \\ and f.has_char("旗".unicode_at(0)) and f.has_char("封".unicode_at(0)) | (待填) | | | +| 1588 | 20 | "中文字形在集(危——已开危险格字形换代前置,迭代36 u12/wa9)" | f.has_char("危".unicode_at(0)) | (待填) | | | +| 1589 | 21 | "ASCII/数字字形在集(A/0/%)" | f.has_char("A".unicode_at(0)) and f.has_char("0".unicode_at(0)) and f.has_char("%".unicode_at(0)) | (待填) | | | +| 1590 | 25 | "中文采样文本宽度 > 0(C6 headless 判据)" | w_cn > 0.0 and w_label > 0.0 | (待填) | | | +| 1591 | 28 | "字体缺失时后续断言跳过(缺位=回归,此行仅占位计数)" | false | (待填) | | | --- -全源共 208 章、1583 条(静态调用点口径)。 +全源共 210 章、1591 条(静态调用点口径)。 diff --git a/reports/iter-supplement-通关换代-代拍板-2026-10-26.md b/reports/iter-supplement-通关换代-代拍板-2026-10-26.md new file mode 100644 index 00000000..7361a1b4 --- /dev/null +++ b/reports/iter-supplement-通关换代-代拍板-2026-10-26.md @@ -0,0 +1,11 @@ +# 代拍板追认单:通关口径换代批(提前实施卡批) + +依据需求卡片 v1.1 §10 代拍板白名单,逐条追认(备案确认): + +| # | 白名单授权 | 实际执行 | 追认 | +|---|---|---|---| +| 1 | B/C 面标签与注释措辞在映射表两可时的具体选词(限标签/注释面) | 全部按卡内映射表与逐处换法表执行;表外裁量仅两处——①ui_click_probe:402「常态通关远低于此」→「常态跑完远低于此」(帧预算语境,卡内映射表 v1.1 已补行)②「非末关通关」族防连读歧义统一「非末关的关卡完成」(grilling 应修 4 折入项) | 无越权 | +| 2 | 豁免单行号按实施后实测定 | 13 行豁免行号与卡片基线完全一致(C 面同位替换零行数变化)——零偏移 | 无偏差 | +| 3 | V1-V7 断言夹具数据具体取值 | V1(heal 5/10→15;满血 0/12→12)、V3(cleared=false/failed/1 关/止步 2/钥石 4/种子 42)、V6(recent 单条 completed/2 关/5 钥石/种子 42)、V7(探针既有 atk+100%/N=10 档)——全部确定性取值 | 无越权 | + +白名单外零拍板。批内三次异常处置(worktree 环境补搬 assets、尾缀避词、S11 头注避词)均属 L1 自救(卡 §9 预案内),无 L2/L3 事件。 diff --git a/reports/iter-supplement-通关换代-反哺点-2026-10-26.md b/reports/iter-supplement-通关换代-反哺点-2026-10-26.md new file mode 100644 index 00000000..d63c8760 --- /dev/null +++ b/reports/iter-supplement-通关换代-反哺点-2026-10-26.md @@ -0,0 +1,13 @@ +# GDD 反哺点清单:通关口径换代批(提前实施卡批) + +实现批禁写 design/ 与根规则文件;以下条目由用户在会话中裁决后归文档批落文(执行入口 doc-design): + +| # | 文档 | 关联点 | 反哺内容 | 依据 | +|---|---|---|---|---| +| ① | design/gdd/术语表.md v1.23 | 「关卡完成」「冒险成功」「冒险落幕」三行+退役词对照 | **预期零改动**——三行与退役词对照已由 termsweep2-20261026 批立入,本批实施数据(12 产品字串/111 随动/84 注释全消化)与三行口径零冲突(T0 核对+全批实施验证) | 卡片 §6;无落文义务,本条为核对注记 | +| ② | design/engineering/architecture/architecture.md「测试与质量域」节 | S11 规则行是否载豁免计数 | **预期零改动**——实查该节无 S11 行(S11/S12 规则说明自持于 game/tests/README.md 与 static_scan.sh 头注,README:149 明示);豁免单计数已随批在 README 订正 4→20 | 卡片 §6 T0 查证项 | +| ③ | 体验验证清单.md | 生涯页目检项引语(:107/:193/:198) | **已随批落地**(用户 B 表指令授权批内改)——引语随 a6/a7 换代+:107 关卡完成率口径;:258 历史读数记载行按豁免保留 | 卡片 §6 q5 | +| ④ | 待办清单.md | 「game 面玩家可见字串『通关』退役换代」条目 | **已随批删除**(活干完登记即毁——quotaface 先例) | 卡片 §6 | +| ⑤ | game/tests/README.md | S11 豁免计数「4 处」过期(quotaface 漏同步,实际 7) | **已随批订正**(4→20 并注明清单见 static_scan.sh 头注)——game/ 内 .md 属批内可写面 | 实现报告 §五.4 | + +结论:①②为核对注记(零落文义务);③④⑤已随批完成。**无待裁决反哺点**——用户无需另行落文。 diff --git a/reports/iter-supplement-通关换代-实现报告-2026-10-26.md b/reports/iter-supplement-通关换代-实现报告-2026-10-26.md new file mode 100644 index 00000000..e32081e6 --- /dev/null +++ b/reports/iter-supplement-通关换代-实现报告-2026-10-26.md @@ -0,0 +1,76 @@ +# 实现报告:通关口径换代批(提前实施卡批 · termsweep-game-20261026) + +- 依据:reports/需求卡片-通关口径换代批-2026-10-26.md v1.1(已随批退役,git 历史可考) +- 执行形态:提前实施卡批(用户 2026-10-26 裁准,先例 quotaface-20261026);分支 termsweep-game-20261026 +- 状态:**全部落地,批末全量域闸见批末回执** + +## 一 · 各卡状态 + +| 卡 | 内容 | 状态 | +|---|---|---| +| T0 | worktree+缓存三件套(.godot/.import 边车/assets 三目录——art 113 png 不入 git 需手工搬)+前置验证(V6 open_camp 最小 data 健壮性经 grilling 读码+实跑双确认) | 完成 | +| T1 | A 面产品字串 12 条(A 表逐字)+wr1 随动+V1-V3 新增断言 | 完成 | +| T2 | B 面断言随动(12 文件 58 处+theme_projection 3 处)+三探针(wr2/wr3+V7+ui_click 7)+V4-V6+验证集清单重生成 1591 条对账零差异 | 完成 | +| T3 | C 面注释清扫 61 条+S11 豁免单 7→20 处+tests/README 计数订正 | 完成 | +| T4 | 体验验证清单 3 行引语+件核三判据 | 完成 | +| T5 | 产出物三份+删卡删条目+全量域闸 | 完成(本报告即其一) | + +## 二 · 实际对照表(卡片 §8 的实现侧回填) + +| 需求点 | 改动(文件:行) | 验收测试 | 层级 | 真实入口 | 撤销证明 | 结果 | +|---|---|---|---|---|---|---| +| a1 关卡完成文案 | battle_narrator.gd:50 | battle_narrator_test:41(wr1 随动) | 单元 | 直调 battle_end_text | 回退→wr1 红→复绿 | 绿 | +| a2/a3 回血两分支 | battle_narrator.gd:90/:92 | 〔口径换代 V1〕battle_narrator_test._test_level_clear_wording | 单元 | 直调 curio_pick_header | 回退→V1 双红→复绿 | 绿 | +| a4 渠道句 | battle_narrator.gd:156 | 〔口径换代 V2〕同上 | 单元 | 直调 node_curio_header | 回退→V2 红→复绿 | 绿 | +| a5 完成关数行 | battle_narrator.gd:166(+:159 注释) | 〔口径换代 V3〕同上 | 单元 | 直调 adventure_summary_text | 回退→V3 红(含负断言)→复绿 | 绿 | +| a6/a7 生涯标签 | career_overlay.gd:42/:43 | 〔口径换代 V4〕theme_projection_test(树内 label 收集) | 接口 | open_career+_all_labels | 分条回退→V4 双红→复绿 | 绿 | +| a8 槽摘要 | save_select_overlay.gd:87 | ui_struct_probe:436(wr2 随动) | 探针 | 场景实例化+喂入数据 | 回退→sl2 红→复绿 | 绿 | +| a9 解锁标签 | ui_kit.gd:403 | 〔口径换代 V5〕theme_projection_test | 单元 | UiKit 常量直读 | 回退→V5 红→复绿 | 绿 | +| a10 最近冒险行 | camp_overlay_view.gd:545 | 〔口径换代 V6〕theme_projection_test._camp_recent_projection | 接口 | open_camp 最小档直调 | 回退→V6 红→复绿 | 绿 | +| a11 完成率读数 | hud_presenter.gd:191 | ui_tune_probe:75(wr3 随动) | 探针 | 批量模拟输出 | 回退→wr3 红→复绿 | 绿 | +| a12 剩余 HP 行 | hud_presenter.gd:194 | 〔口径换代 V7〕ui_tune_probe(同报告补检) | 探针 | 批量模拟输出 | 回退→V7 红(与 wr3 双红验证独立钉住)→复绿 | 绿 | +| q2 断言随动 | 13 文件 60 处+探针 13+清单 38 | extract_checks --diff 零差异+各套件闸 | 机器对账 | 由 a1-a12 撤销证明连带覆盖 | 连带 | 绿 | +| q3 注释清扫 | C 面 61 条(豁免 13 行保留) | S11 零命中(等价验证器)+豁免撤销证明 | 静态 | 非行为改动(注释文本,零运行时语义) | hero.tres:21 去豁免→红→还原 | 绿 | +| q4 S11 豁免单 | static_scan.sh 7→20 处 | S11 零命中+头注避词自检 | 静态 | 同上 | 同上 | 绿 | +| q5 目检项引语 | 体验验证清单 :107/:193/:198 | --docs 域 doc_term_audit(批末全量档) | 文档域 | 非行为改动(引语) | — | 绿(批末闸) | + +**撤销证明记录表**(a1-a12 十二条+q4 豁免一条,全部「回退 hunk→最窄断言红→复原复绿」逐条执行,执行序见 git 提交 54395b8b/51c6cf56 信息): + +| # | 撤销对象 | 变红断言 | 红/绿 | +|---|---|---|---| +| a1 | battle_narrator:50 | 「关卡收束态恒为「关卡完成!」」(1/17 失败) | 红→复绿 | +| a2/a3 | :90/:92 | V1 两条(回血行/满血合法态) | 红→复绿 | +| a4 | :156 | V2 渠道句 | 红→复绿 | +| a5 | :166 | V3(输出含「通关 1 关」负断言同时抓) | 红→复绿 | +| a6 | career:42 | V4 双断言(标签缺失+旧词残留) | 红→复绿 | +| a7 | career:43 | V4 双断言 | 红→复绿 | +| a8 | save_select:87 | ui_struct sl2「got=通关 2 局」 | 红→复绿 | +| a9 | ui_kit:403 | V5 | 红→复绿 | +| a10 | camp:545 | V6(「实际…通关 2 关」实测抓旧文案) | 红→复绿 | +| a11 | hud:191 | wr3「缺关卡完成率」 | 红→复绿 | +| a12 | hud:194 | V7「缺关卡完成剩余 HP 行」 | 红→复绿 | +| q4 | S11 豁免 hero.tres:21 | 验证器精确命中 hero.tres:21 | 红→复绿 | + +## 三 · 实机目检总清单(登记不阻塞——验收时间由用户自排) + +1. 战斗总结结算:单关末行「关卡完成!」(非末关收束态); +2. 三选一停点头部:回血行「关卡完成回血 +N(生命 X → Y)」/满血态「生命已满——关卡完成回血 0(合法态)」; +3. 奖励节点三选一头行「与关卡完成专长三选一同库分流」; +4. 冒险结算屏:「完成 N 关 · 止步第 M 层 · 钥石合计 K · 主种子 S」; +5. 生涯页行标签「冒险成功局数〔1 局(三关全通)〕」「各关完成次数」; +6. 选档界面槽摘要「冒险成功 X 局 · 冒险 Y 局」; +7. 营地秘宝匣解锁条件行「冒险成功 0/1」形(adventure_cleared 条件件); +8. 营地底栏最近冒险「最近冒险:完成 · 完成 N 关 · …」; +9. 调试浮层批量模拟报告「关卡完成率 N%(W/T)」「关卡完成剩余 HP 均 x · 进 Boss HP 均 y」。 + +## 四 · 遗留读数义务 + +- 零数值改动=零 MC:全部改动为字串/标签/注释/断言文本,计数器键名(adventure_cleared/level_clear_counts)、存档域键、sim-data 锚与 JSONL 数据键、RNG 流名、数值行逐字未动;11 号 MC 对拍按零数值改动红线不补跑(quotaface 同款)。 +- 断言条件表达式仅 wr1/wr2/wr3 三处随产品字串换代(判据随动非削弱),其余 57 处仅标签文本;零断言删除、零阈值放宽、零扫描面缩小。 + +## 五 · 异常与处置记录 + +1. worktree 环境红(theme_projection V1 主题段 7 失败)=.import 边车与 assets(art/fonts/theme,113 png 不入 git)未搬——补拷后 166 checks 全绿;坑册三件套的完整形态应含 assets 目录,已随 T2 提交信息留档。 +2. 断言尾缀「通关换代」自撞 S11(新词含退役词「通关」进验证集清单 .md 整行扫描面)——尾缀改「口径换代 Vn」、S11 头注同避词;根因=卡短名含退役词,后续批次命名避开退役词。 +3. S11 头注初版「通关口径换代批」自撞(static_scan.sh 属 .sh 扫描面)——改「口径换代批」。 +4. tests/README.md S11 豁免计数「4 处」为 quotaface 批漏同步(实际已 7)——随批订正为 20。 diff --git a/reports/iter-supplement-通关换代-验收审计-2026-10-26.md b/reports/iter-supplement-通关换代-验收审计-2026-10-26.md new file mode 100644 index 00000000..7e6db063 --- /dev/null +++ b/reports/iter-supplement-通关换代-验收审计-2026-10-26.md @@ -0,0 +1,76 @@ +# 验收审计报告:通关口径换代批(提前实施卡批 · termsweep-game-20261026) + +- 审计对象:分支 termsweep-game-20261026 尖 ed49a7a5(基线 master 0b501743),全量 diff 52 文件 +- 审计人:独立验收审计员(未参与实现;test-conventions §8.7 流程) +- 审计输入:需求卡片 v1.1(git show ed49a7a5~1)、实现报告、逐文件 diff、worktree 内实测复跑 +- 审计日期:2026-10-26(合回前) +- **总结论:通过**(对照表 17 行全过;撤销证明抽三条复现全闭合;削弱检查机器对账零超申报;例外三件均有依据,不构成缺漏) + +## 一 · 对照表逐行核对(实现报告 §二) + +实测命令均于 worktree game/ 下执行(console 版 headless)。逐行结论: + +| 行 | 核对内容 | 结论 | 依据(实测) | +|---|---|---|---| +| a1 | battle_narrator.gd:50=「关卡完成!」;wr1 断言在 battle_narrator_test:41;套件 17 checks 全绿;直调 battle_end_text 真实入口 | 通过 | sed :50 实读;diff hunk 行号推证 :41 为条件行;套件实跑 `[battle_narrator_test] all green (17 checks)` | +| a2/a3 | :90/:92 两分支新文案与 A 表逐字一致;V1 两断言(〔口径换代 V1〕尾缀)grep 可得(battle_narrator_test:90/:93);实跑绿 | 通过 | sed :90/:92 实读;grep 尾缀命中;17 checks 内含 V1 两条 PASS | +| a4 | :156 渠道句;V2(:96)绿 | 通过 | 同上 | +| a5 | :166 完成关数行+:159 注释同步;V3(:100)绿且带负断言 `not summary.contains("通关")` | 通过 | 同上;V3 输出实值「冒险失败 · 未打穿\n完成 1 关 · 止步第 2 层 …」PASS | +| a6/a7 | career_overlay.gd:42「冒险成功局数」/:43「各关完成次数」;V4(theme_projection_test:871/:873 含正断言+零残留负断言)经 open_career 实例化+树内 label 收集 | 通过 | sed :42/:43 实读;theme_projection_test 166 checks 全绿(V4 两断言 PASS) | +| a8 | save_select_overlay.gd:87「冒险成功 %d 局 · 冒险 %d 局」;wr2=ui_struct_probe:436 条件同结构换串;探针 PASS | 通过 | sed :87 实读;diff 确认条件结构 `sum1 == null or sum1.text != "…"` 仅换期望串;`[ui_struct_probe] PASS — 全屏结构断言零红`(exit 0) | +| a9 | ui_kit.gd:403 TREASURE_REQ_LABELS["adventure_cleared"]=="冒险成功";V5(theme_projection_test:874)直读真实常量 | 通过 | sed :403 实读;V5 PASS | +| a10 | camp_overlay_view.gd:545「完成 %d 关」;V6(theme_projection_test:818)经 open_camp 最小档实例化全量重建路径 | 通过 | sed :545 实读;V6 PASS,实测输出「最近冒险:完成 · 完成 2 关 · 钥石 +5 · 种子 42」 | +| a11 | hud_presenter.gd:191「关卡完成率」;wr3=ui_tune_probe:75 同结构换串;探针真实模拟输出含「关卡完成率 100%(10/10)」 | 通过 | sed :191 实读;探针 exit 0、报告输出实值核得 | +| a12 | hud_presenter.gd:194「关卡完成剩余 HP 均」;V7(ui_tune_probe:79)真实输出核得「关卡完成剩余 HP 均 16.2 · 进 Boss HP 均 20.4」 | 通过 | 同上 | +| q2 | 13 文件 60 处随动:标签 38 处进验证集清单(1583→1591 条=38 换代+8 新增);探针 13 处;`extract_checks --diff` 零差异 | 通过 | 清单标签列基线对比:removed 38 / added 46(38 换代+V 组 8);`python tools/extract_checks.py --diff` 输出「PASS——标签/cond/计数三对齐,零差异」exit 0;各受影响套件全绿(见 §三) | +| q3 | C 面 61 条=注释同位替换,零运行时语义 | 通过 | 机器核对:core/data/sim 全部 +/- 行去注释段后代码部分逐字节相同(含 README 外全部 .gd/.tres);README 行纯文本换代 | +| q4 | S11 豁免单 7→20;S11 直跑绿 | 通过 | static_scan.sh 现有 21 条 `next` 豁免行=20 唯一 file:line(enemy.tres:653 在两段 awk 重复计一次)=既有 7+新增 13;头注「20 处」已更;`bash game/tests/static_scan.sh` → `[static_scan] S11 ok(扫描面 237 个文件,词表 23 词)` exit 0 | +| q5 | 体验验证清单恰 3 行(:107/:193/:198),:258 历史读数行未动 | 通过 | diff 实查三 hunk 位置吻合;批末回执 08 doc_term → 0 green | +| wr判①②③ | S11 零命中/「冒险终结」零输出/清单对账退出码 0 | 通过 | 三项均实测(①见 q4 行;②grep 零命中;③见 q2 行) | + +尾缀 grep 汇总:〔口径换代 V〕共 9 处=battle_narrator_test:90/:93/:96/:100(V1×2/V2/V3)+theme_projection_test:818/:871/:873/:874(V6/V4×2/V5)+ui_tune_probe:79(V7)。 + +真实入口核查:V1–V3 直调 BattleNarrator 静态装配器(curio_pick_header/node_curio_header/adventure_summary_text——产品字串唯一产生点,无旁路);V4/V5/V6 经 open_career/UiKit 常量/open_camp 实例化;V7/wr3 走批量模拟真实输出;wr2/sl2 走场景实例化喂入数据。diff 内未发现换下层直调或 mock 顶替。 + +## 二 · 撤销证明抽查复现(三条,全部临时改动已精确复原) + +| # | 复现操作 | 结果 | 与实现报告记录比对 | +|---|---|---|---| +| a1 | battle_narrator.gd:50 临时改回「关卡通关!」→跑 battle_narrator_test | 红:`[FAIL] 关卡收束态恒为「关卡完成!」(实际「关卡通关!」)`→复原后 17 checks 全绿 | 逐字吻合记录表 a1 行 | +| a8 | save_select_overlay.gd:87 临时改回「通关 %d 局 · 冒险 %d 局」→跑 ui_struct_probe | 红(exit 1):`[savesel] 槽1 摘要读数失守(got=通关 2 局 · 冒险 7 局 应=冒险成功 2 局 · 冒险 7 局)〔sl2〕`→复原后 PASS | 逐字吻合记录表 a8 行「got=通关 2 局」 | +| a12 | hud_presenter.gd:194 临时改回「通关剩余 HP 均」→跑 ui_tune_probe | 红(exit 1):`模拟输出缺关卡完成剩余 HP 行〔口径换代 V7〕`;**wr3(关卡完成率)同跑仍绿**→复原后 PASS | 吻合记录表 a12 行,并实证「wr3+V7 双红独立钉住」声明 | + +复原精度:三次复原后 `git diff` 零 hunk(a1/a8 首轮复原因编辑器换行符差异出现 autocrlf 幻影 M 态,已由 `git checkout --` 精确还原,见 §五.3)。 + +## 三 · 测试削弱检查 + +机器对账(验证集清单 cond 列基线 0b501743 vs 尖 ed49a7a5 多重集对比): + +- cond 表达式删除=**恰 1 条**:`level == "关卡通关!"`(wr1 换代,同结构等强度换串,非削弱); +- cond 新增=9 条:wr1 新串+V1–V6 八条(清单内 1583→1591)+V7(探针面,不入清单——与卡片 B5 事实一致); +- 数值阈值/比较结构:零改动;扫描面:ui_struct_probe sl3 禁项 needle 列表 `["断点","种子","继续","停点"," 关"]` 未动(:446 仅注释改写);ui_click 7 处仅注释/print 文本。 + +diff 逐文件复核(13 测试文件+3 探针全部 hunk 过目):条件表达式改动仅 wr1(battle_narrator_test:41)/wr2(ui_struct_probe:436)/wr3(ui_tune_probe:75)三处,其余全部为 Kit.check 首参标签文本或注释——**与申报完全一致,零超范围**。V3/V4/V6 负断言(`not contains("通关")`)属净收紧。 + +结论:零断言删除、零阈值放宽、零扫描面缩小、零换下层直调;V 断言净增 9 条。 + +## 四 · 附加核对 + +1. **S11 豁免单 ↔ grep 残留一一对应**:`grep -rn "通关" game/`(四扩展名)现命中 20 行,全部落位——豁免单新增 13 行(.tres 12+level_autoplay.gd:560)各恰命中一次=14 行;其余 6 行=被检字形态(验证集清单 .md 三行负断言 cond 文本〔S11 层① 自指豁免〕+battle_narrator_test:101/theme_projection_test:819/:873 代码行负断言〔非注释面不取〕+theme_projection_test:866 注释「零「通关」残留」〔层①〕)。非豁免残留=零。既有豁免 7 行本批零误伤(enemy.tres:653 等不再含本批词面,属其他退役词)。豁免行的「去豁免即红」结构性成立:上述 14 命中行现仍含退役词,豁免即 S11 红的充分条件在位(q4 撤销证明未复跑,据此采信)。 +2. **A 表 12 条逐字核对**:卡片 §1 q1 表 a1–a12 的新文案与 worktree 实码(§一行列位置)逐字一致,含 a2/a3 的全角括号与空格、a5 的 `\n` 后首词去「通关」、a8 的「冒险成功 %d 局 · 冒险 %d 局」、a9 的常量值「冒险成功」、a11/a12 的读数前缀——全部吻合。 +3. **C 面零行为改动机器核验**:core 六件/schema 两件/sim 四件/七张表全部改动行,去注释段后代码部分与基线逐字节相同。 +4. **批末回执**:`game/tests/.gates/receipt.json`=commit ed49a7a5、domain full、00–10 闸全 green;11 号 MC 对拍 NEED-APPROVAL skip——与「零数值改动=零 MC」红线一致。 +5. **随批三件套**:实现报告/代拍板追认单/反哺点清单均在 reports/ 在位;卡片与待办条目已删(git 可考)。 + +## 五 · 例外与观察(均不构成缺漏) + +1. **V 尾缀「口径换代 Vn」≠卡片原文「通关换代 Vn」**——例外成立,依据充分:断言尾缀进验证集清单 .md 整行扫描面,「通关换代」含退役词必自撞 S11;实现报告 §五.2 已记录根因与改法,且后续批次命名避退役词。卡片 §8 表用的旧尾缀名在清单里不可检索属预期形态,审计按「口径换代 V」检索全数命中。 +2. **game/README.md:15 落「非末关的关卡完成发大奖励」**——卡片 q3 README 行写作「非末关卡完成」,实施取「非末关的关卡完成」。依据:同卡 q3 换法映射表通行规则+§13 grilling 应修④(防「末关卡」连读歧义)优先于行内简写,且属代拍板白名单 1(标签/注释面两可选词)。判例外采纳,非越权。 +3. **审计会话 run_all.gd 一次异常**:统一入口跑至 49/61 套件后外层宿主进程静默退出(exit 1,无套件红)。处置:13 个受影响套件中 11 个在该次运行内 PASS,其余 2 个(battle_narrator/theme_projection)+4 个重载件(adventure_feats 138/level_shop_economy 186/meta_progression_forge 135/save_manager_domain 101)+runner 未及的 6 个尾件(hud_presenter/player_copy_sweep/minesweeper_rules/config_db_resolver/config_db_cross_validator/type_glow)全部单独实跑绿——61/61 全数覆盖;批末回执 02 闸在同 commit 全绿。判环境瞬时异常(本机资源态),非本批缺陷;留档备查。 +4. **探针不进验证集清单**(B5)——V7 与 wr2/wr3 的机器对账面缺位于清单属机制常态,本次以 diff 逐 hunk+探针实跑输出双重核对补齐。 + +## 六 · 审计过程文件声明 + +审计全程只读,唯一写入=本报告;撤销证明的三次临时改动均已精确复原(收尾 `git status` 于 game/ 与全仓(除本报告外)零改动——见下方回执行)。 + +- 收尾 git status:仅 `?? reports/iter-supplement-通关换代-验收审计-2026-10-26.md` 一个新文件,零修改零删除。 diff --git a/reports/需求卡片-通关口径换代批-2026-10-26.md b/reports/需求卡片-通关口径换代批-2026-10-26.md deleted file mode 100644 index 5f4498e9..00000000 --- a/reports/需求卡片-通关口径换代批-2026-10-26.md +++ /dev/null @@ -1,325 +0,0 @@ -# 需求卡片:通关口径换代批(game 面玩家可见字串 13 条+断言随动+注释清扫) - -- 版本:**v1.1**(v1.0 成文→grilling 一轮复核零阻断、四应修折入:q3 计数口径注明+估时对齐+映射表补帧预算语境行+「非末关的关卡完成」防连读歧义;复核记录见 §13) -- 来源:[待办清单](../待办清单.md)「game 面玩家可见字串『通关』退役换代」条目(2026-10-26 登记,状态=文档设计已闭合+待写卡)(唯一事实源:[术语表](../design/gdd/术语表.md) v1.23「关卡完成」「冒险成功」「冒险落幕」三行+退役词对照「通关」「冒险终结」两行+用户 2026-10-26 开工指令 A/B/C 三面清单——A 表 12 条措辞已核、改动即停呈报) -- 归属:`game/presentation` 六件产品字串+13 测试文件+3 探针+`game/tests/验证集清单.md`+core 六件注释+七张表头注+schema 两件+sim 四件+`game/README.md`+呈现层注释件+`game/tests/static_scan.sh`(S11 豁免单)+根件`体验验证清单.md`(目检项引语随批同步——用户 B 表指令) -- 排期:提前实施(用户 2026-10-26 开工令「写需求卡片并实施」,先例=quotaface-20261026 提前实施卡批) -- 开工门:U0 已随开工令下达;grilling 复核门过(§13);零待裁点 -- 估时:≈1.1 个工作日(T0–T5 合计 0.1+0.25+0.25+0.25+0.1+0.15) - -## 0. 前置依赖与并行性 - -- **第〇步核对(2026-10-26 写卡会话)**:来源条目设计线闭合成立——凭据=术语表 v1.23 三行(termsweep2-20261026 批落,合并提交 6af36382)+用户 2026-10-26 裁决与开工令;状态=文档设计已闭合+待写卡,放行。 -- 与迭代 38 七卡零文件交叠(levelmap/结构小件/效果引擎/明细行/奖励节点/结算行缓冲/调试入口批均不触碰本卡文件面;`battle_narrator.gd` 仅本卡触碰——奖励节点清扫批(迭代 38)动 battle_narrator.gd:15 的「节点内容待定——直通」行,本卡动 :50/:90/:92/:154/:156/:159/:166——行面不相交,先合者为准、后合者零冲突)。 -- 与 2026-10-26 在途文档批(双层 BD 条目迁移 content-archive、奇物.md 修订——工作区未提交件)零交叠:本批 worktree 内不触碰待办清单 BD 条目区与奇物.md。 - -## 1. 目标与完成定义 - -**目标**:「通关」从 game/ 面全量退役——玩家可见字串换为主体明确短语族(单关=关卡完成、整局=冒险成功)、断言与探针随动、注释面清扫、带日期历史读数注释入 S11 留档豁免单;退役后非豁免残留由 S11(注释面+.md 整行)与 doc_term_audit(文档域 .md)双闸兜住,误用即红。 - -**改动单元清单**(🔴 契约 1——A 表措辞经用户逐条核定,实施逐字照行;超出本清单的新玩家可见「通关」字串=L3 停机呈报): - -### q1 · A 面产品字串 12 条(行为改动——每条须断言钉住;任务 A 表编号至 12,标题计数「13 条」系含 :159 注释同步项,一并随 a5 落) - -| # | 位置 | 旧 → 新 | 断言 | -|---|---|---|---| -| a1 | `battle_narrator.gd:50` | 「关卡通关!」→「关卡完成!」 | 既有 battle_narrator_test:41 随动(wr1) | -| a2 | 同 `:90` | 「通关回血 +%d(生命 %d → %d)」→「关卡完成回血 +%d(生命 %d → %d)」 | 新增 V1 | -| a3 | 同 `:92` | 「生命已满——通关回血 0(合法态)」→「生命已满——关卡完成回血 0(合法态)」 | 新增 V1(同函数两分支) | -| a4 | 同 `:156` | 「与通关专长三选一同库分流」→「与关卡完成专长三选一同库分流」 | 新增 V2 | -| a5 | 同 `:166` | 「%s\n通关 %d 关 · 止步第 %d 层 · 钥石合计 %d · 主种子 %d」→「%s\n完成 %d 关 · 止步第 %d 层 · 钥石合计 %d · 主种子 %d」 | 新增 V3 | -| a6 | `career_overlay.gd:42` | 标签「通关局数」→「冒险成功局数」 | 新增 V4 | -| a7 | 同 `:43` | 标签「各关通关次数」→「各关完成次数」 | 新增 V4 | -| a8 | `save_select_overlay.gd:87` | 「通关 %d 局 · 冒险 %d 局」→「冒险成功 %d 局 · 冒险 %d 局」 | 既有 ui_struct_probe:436 随动(wr2) | -| a9 | `ui_kit.gd:403` | TREASURE_REQ_LABELS 的 `adventure_cleared` 标签「通关」→「冒险成功」 | 新增 V5 | -| a10 | `camp_overlay_view.gd:545` | 「最近冒险:%s · 通关 %d 关 · 钥石 +%d · 种子 %d」→「最近冒险:%s · 完成 %d 关 · 钥石 +%d · 种子 %d」 | 新增 V6 | -| a11 | `hud_presenter.gd:191` | 调试浮层读数「通关率 …%」→「关卡完成率 …%」 | 既有 ui_tune_probe:75 随动(wr3) | -| a12 | 同 `:194` | 「通关剩余 HP 均 x」→「关卡完成剩余 HP 均 x」 | 新增 V7(ui_tune_probe 同报告补检) | - -(同文件注释随动:battle_narrator:159「通关几关」→「完成几关」、career_overlay:11/:12/:36、save_select_overlay:2/:18、ui_kit:211——归 q3 呈现层注释清单,非独立行为改动。) - -### q2 · B 面断言随动+新增断言+探针+验证集清单 - -**必红三处**(产品字串改后断言必红,先改产品后改断言同轮落地): - -| wr | 断言位置 | 随动改法 | -|---|---|---| -| wr1 | `tests/unit/presentation/battle_narrator_test.gd:41` | 条件 `level == "关卡通关!"` 与标签/注释(:39/:41 两处引语)同换「关卡完成!」 | -| wr2 | `probe/ui_struct_probe.gd:436` | 条件 `sum1.text != "通关 2 局 · 冒险 7 局"` 与标签/注释(:434/:436/:437)同换「冒险成功 2 局 · 冒险 7 局」 | -| wr3 | `probe/ui_tune_probe.gd:75` | 条件 `out.contains("通关率")` 与标签(:75/:76)同换「关卡完成率」 | - -**13 测试文件 60 处断言/注释随动**(按 §1 换法映射逐处套用;全部为标签文本或注释换代,**断言条件表达式除 wr1 外零触碰**): - -| 文件 | 处数 | 逐处换法 | -|---|---|---| -| battle_narrator_test.gd | 2 | :39 注释+:41 标签/条件(wr1) | -| save_manager_domain_test.gd | 8 | :81「通关次数」→「关卡完成次数」、:83「随通关关卡置位」→「随关卡完成置位」、:85「通关局数」→「冒险成功局数」、:98「通关次数表」→「关卡完成次数表」、:268/:272/:324/:328「通关局」→「冒险成功局」「通关局数」→「冒险成功局数」 | -| save_slot_summary_test.gd | 1 | :49 标签「钥石/通关/总局」→「钥石/冒险成功/总局」 | -| adventure_feats_test.gd | 15 | :102/:106 注释「满配通关」→「满配冒险成功」、:132 注释同、:135「满配通关」→「满配冒险成功」、:136「通关几关 = 3」→「完成几关 = 3」、:154「通关三选一」→「关卡完成三选一」、:245/:364「通关部分回血封顶」→「关卡完成部分回血封顶」、:274「未打穿 · 通关 0 关」→「未打穿 · 完成 0 关」、:354/:355 注释「L2 通关」→「L2 关卡完成」、:409 注释「通关回血」→「关卡完成回血」、:417「满血通关回血 0」→「满血关卡完成回血 0」、:512 注释+:522「通关渠道」→「关卡完成渠道」 | -| level_shop_economy_test.gd | 12 | :3/:326 注释「满配通关」→「满配冒险成功」、:332 注释同、:334 标签「通关」→「关卡完成」(单关 victory)、:342/:343/:345/:353「通关路径」→「关卡完成路径」、:374 注释「难以通关」→「难以完成」、:491/:504「路径通关」→「路径完成」、:976 注释「快速通关档」→「快速完成档」 | -| meta_progression_forge_test.gd | 9 | :162 注释「逐通关关次」→「逐关卡完成关次」、:189「通关两关」→「完成两关」、:195「两关通关逐关归因」→「两关完成逐关归因」、:198/:203「零通关」→「零关卡完成」、:220「远程镐=通关 1 次」→「远程镐=冒险成功 1 次」(adventure_cleared 整局语境)、:223「C6:通关=打通整局冒险」→「C6:冒险成功=打通整局冒险」、:233「通关≥3」→「冒险成功≥3」(adventure_cleared 语境)、:270「通关 1 关」→「完成 1 关」 | -| theme_projection_test.gd | 3 | :840「通关局数投影」→「冒险成功局数投影」、:845「各关通关次数投影」→「各关完成次数投影」、:869「通关局数显示 0」→「冒险成功局数显示 0」 | -| reward_overlay_test.gd | 1 | :3 注释「与通关三选一共用」→「与关卡完成三选一共用」 | -| cross_system_flow_test.gd | 3 | :119「满配通关」→「满配冒险成功」、:121「集成通关次数表」→「集成关卡完成次数表」、:126「通关次数全 2」→「关卡完成次数全 2」 | -| breakpoint_resume_test.gd | 1 | :99「非末关通关三选一停点」→「非末关的关卡完成三选一停点」 | -| save_boot_no_activate_test.gd | 1 | :30「通关数全零值」→「冒险成功数全零值」(adventure_cleared 语境) | -| curio_refresh_paid_test.gd | 2 | :26 注释「白盒造通关停点」→「白盒造关卡完成停点」、:28「通关停点在途」→「关卡完成停点在途」 | -| table_structure_guard_test.gd | 2 | :96「通关部分回血比例」→「关卡完成部分回血比例」、:467「〔节点/通关〕」→「〔节点/关卡完成〕」 | - -**三探针 13 处**:ui_struct 4 处(wr2 三行+:446 注释改写——「关数形——『通关』无空格不误伤」→「关数形——摘要『冒险成功 X 局 · 冒险 Y 局』不含『关』字」);ui_tune 2 处(wr3);ui_click 7 处(:34「L2 通关收口」→「L2 关卡完成收口」、:371「保 L1 可通关」→「保 L1 可完成」、:402「常态通关远低于此」→「常态跑完远低于此」、:414「通关兑付共用面」→「关卡完成兑付共用面」、:478「非末关通关恰一次/L2 已通关」→「非末关的关卡完成恰一次/L2 已关卡完成」、:494 print「(L2 通关)」→「(L2 关卡完成)」、:642「保可通关」→「保可完成」)。 - -**验证集清单 38 处**:`python tools/extract_checks.py --extract --force` 重生成(断言标签换代自动同步)→ `--diff` 对账零差异(quotaface 先例流程)。 - -**新增断言七组**(真实入口=被测装配器/视图的公开装配函数或 open 面;全部带尾缀〔通关换代 Vn〕,进验证集清单): - -| # | 断言 | 落点 | 内容(撤销证明=回退对应产品行 hunk→断言红→复原复绿) | -|---|---|---|---| -| V1 | curio_pick_header 回血两分支文案 | battle_narrator_test(随 battle_end 断言组) | 直调 `BattleNarrator.curio_pick_header({"level_index":1,"heal_gained":5,"hp_before":10,"hp_after":15})` 断言输出含「关卡完成回血 +5(生命 10 → 15)」;`heal_gained:0` 载荷断言含「生命已满——关卡完成回血 0(合法态)」〔通关换代 V1〕 | -| V2 | node_curio_header 渠道句 | 同上 | 直调 `node_curio_header()` 断言含「与关卡完成专长三选一同库分流」〔通关换代 V2〕 | -| V3 | adventure_summary_text 完成关数行 | 同上 | 直调 `adventure_summary_text({"cleared":false,"result":"failed","levels_cleared":1,"stopped_at":2,"keystone_total":4,"master_seed":42})` 断言含「完成 1 关 · 止步第 2 层」〔通关换代 V3〕 | -| V4 | 生涯页标签换代+零残留 | theme_projection_test(career 组尾) | open_career(既有 data) 后收集树内全部 label 文本,断言含「冒险成功局数」「各关完成次数」且全集不含「通关」〔通关换代 V4〕 | -| V5 | TREASURE_REQ_LABELS 冒险成功标签 | theme_projection_test(V4 后) | 断言 `UiKit.TREASURE_REQ_LABELS["adventure_cleared"] == "冒险成功"`〔通关换代 V5〕 | -| V6 | 营地最近冒险行完成关数 | theme_projection_test(camp 组) | 实例化 camp_overlay_view → `open_camp(最小 data)`(recent=[{result:"completed",levels_cleared:2,keystone_total:5,master_seed:42}],其余键缺省)→ 断言 `_recent_list.text` 含「完成 2 关」;**T0 先验证各 _rebuild 对缺省键健壮,若不健壮改按 camp_shop_presenter 投影完整构造**〔通关换代 V6〕 | -| V7 | 模拟报告关卡完成剩余 HP 行 | ui_tune_probe(wr3 检查旁) | 报告输出断言 `out.contains("关卡完成剩余 HP")`——高加成参数下确定性有胜局(T0 验证;若该参数下胜局为零则呈报改设计)〔通关换代 V7〕 | - -### q3 · C 面注释清扫(非行为改动——同位替换,零行数变化) - -**换法映射**(语境规则——B 面标签同用): - -| 旧措辞 | 新措辞 | 语境 | -|---|---|---| -| 通关(单关语境:关/层/level/停点/兑付/回血/渠道/三选一/路径) | 关卡完成 | 主体=单关 | -| 通关(整局语境:局/冒险/cleared/满配打通三关) | 冒险成功 | 主体=整局 | -| 「通关 %d 关」 | 「完成 %d 关」 | 用户 A 表 a5 定稿形态 | -| 通关率 | 关卡完成率 | 文档面先例(难度曲线与Boss「关卡完成率带」);hud_presenter a11 同 | -| 通关几关 | 完成几关 | a5 同款 | -| 非末关通关/末关通关 | 非末关的关卡完成/末关的关卡完成 | 防「末关卡」连读歧义(grilling 一轮应修 4) | -| 通关(帧预算/流程跑完语境——非游戏术语) | 跑完 | ui_click_probe:402「常态通关远低于此」一例;白名单 1 同源 | -| 冒险终结 | 冒险落幕 | 退役词对照(game/ 面实查零命中,防御性登记) | - -**逐文件清单**(除豁免单所列 13 行外全换): - -- core 六件 29 处:adventure_runner.gd:10/:12/:269/:342/:393/:486/:501/:565/:654/:671/:782/:794/:808/:813(14)、save_manager.gd:10/:157/:288/:420/:434/:435/:561/:569/:572(9)、level_runner.gd:564/:745/:775(3)、meta_progression.gd:274、config_db.gd:257、config_db_cross_validator.gd:43——单关语境一律「关卡完成」、局语境「冒险成功」(如 save_manager:10「通关局数」→「冒险成功局数」、:434「通关局数(口径=三关全通」→「冒险成功局数(口径=三关全通」、:561「逐关通关次数合计」→「逐关完成次数合计」、level_runner:564「Boss 胜利 = 关卡通关」→「Boss 胜利 = 关卡完成」、:745「通关/倒下/放弃」→「冒险成功/倒下/放弃」(冒险落幕三态)、config_db:257「通关累加域」→「关卡完成累加域」) -- 七张表头注 17 处减豁免:hero.tres:21/:36 豁免;enemy.tres:751/:891 豁免、:768「0 加成通关 ≤40%」→「0 加成关卡完成 ≤40%」、:871「≈5 次 L1 通关锻造后」→「≈5 次 L1 关卡完成锻造后」;action_economy.tres:15/:16/:26/:27 豁免(4);status_effects.tres:91 豁免;treasure_items.tres:11「生涯通关局数(C6 裁:通关=打通整局冒险)」→「生涯冒险成功局数(C6 裁:打通整局冒险)」;adventure.tres:51「末关通关不发」→「末关的关卡完成不发」;meta.tres:48/:56/:62 豁免、:55「≈5 次 L1 通关开门」→「≈5 次 L1 关卡完成开门」 -- schema 两件 4 处:treasure_item_table.gd:12「通关口径=C6(通关=打通整局冒险)」→「解锁口径=C6(冒险成功=打通整局冒险)」、:13「生涯通关局数」→「生涯冒险成功局数」;adventure_table.gd:4「重扫通关率带」→「重扫关卡完成率带」、:39「通关部分回血(固定型,非末关通关兑付)」→「关卡完成部分回血(固定型,非末关兑付)」 -- sim 四件 12 处减豁免:auto_player.gd:36「通关率带」→「关卡完成率带」;level_autoplay.gd:2「通关结束」→「关卡完成」、:4「自动通关策略」→「自动完成策略」、:8「通关率/难度类…通关率脱节」→「关卡完成率/难度类…关卡完成率脱节」、:13「通关兑付停点」→「关卡完成兑付停点」、:306「通关停点」→「关卡完成停点」、:560 豁免;verifier_batch.gd:5/:111「逐关条件通关率」→「逐关条件关卡完成率」、:9「累计几次通关冒险后」→「累计几次冒险成功后」、:14「通关率差」→「关卡完成率差」;adventure_monte_carlo.gd:9「通关率/败因分布」→「关卡完成率/败因分布」 -- game/README.md 7 处::5/:6「通关期望」→「冒险成功期望」(整局元进度语境)、:7「通关攻击期望」→「冒险成功攻击期望」、:15「非末关通关发大奖励」→「非末关卡完成发大奖励」、:16「输出通关率」→「输出关卡完成率」、:18「满配通关」→「满配冒险成功」、:38「通关率/止步分布」→「关卡完成率/止步分布」 -- 呈现层注释 15 处(清单列全 16 个位置供实施对照——battle_narrator:159 计数归 A 面口径〔q1 注〕,q3 面实计 15):battle_narrator.gd:154(「与通关三选一共享同库」→「与关卡完成三选一共享同库」)+:159(「通关几关」→「完成几关」,计数归 q1)、career_overlay.gd:11/:12/:36(「通关局数」→「冒险成功局数」「各关通关次数」→「各关完成次数」)、save_select_overlay.gd:2/:18(「通关局数」→「冒险成功局数」「通关/冒险两值」→「冒险成功/冒险两值」)、ui_kit.gd:211(「模拟报告通关率同档」→「模拟报告关卡完成率同档」)、curio_interact_controller.gd:28/:85/:114/:180/:231(「通关停点/通关三选一/非末关通关」→「关卡完成停点/关卡完成三选一/非末关的关卡完成」)、curio_pick_overlay.gd:2、tune_sim_controller.gd:38(「通关全量 JSONL」→「关卡完成全量 JSONL」)、main_adventure_flow.gd:54 - -### q4 · S11 留档豁免单扩充(static_scan.sh,7→20 处) - -带日期历史读数注释 13 行按豁免惯例保留原文,逐行登记进 `game/tests/static_scan.sh` 两段 awk 的豁免单(.tres 段 12 行+.gd 段 1 行): - -| 文件:行 | 豁免理由(留档口径随 commit) | -|---|---| -| hero.tres:21 | 压缩前基线读数(N=30 normal 基线档通关率 3%)——历史读数 | -| hero.tres:36 | L1 条件通关 2%、0/100 出第一关——历史实测 | -| enemy.tres:751 | 基线满血全通关(模拟 80%/真人 100%)——历史试玩读数 | -| enemy.tres:891 | L1 条件通关 1-2%、0/100 出第一关——历史实测 | -| action_economy.tres:15 | AP 压速批(2026-09-16 用户拍板)无伤通关根因诊断实录——带日期历史批记录 | -| action_economy.tres:16 | 同段延续(零承伤通关实录) | -| action_economy.tres:26 | 上批 8→6 所杀退化形态叙述——历史批记录 | -| action_economy.tres:27 | 同段延续 | -| status_effects.tres:91 | 真人局 12/12 轮零承伤满血通关——历史读数 | -| meta.tres:48 | 旧「总通关次数达阈值」六行历史记载(旧文名引述) | -| meta.tres:56 | 实测 L1 通关局收入 ≈29-35 GP——历史实测读数 | -| meta.tres:62 | 通关率差实测每级带平移(bootstrap SE)——历史实测读数 | -| level_autoplay.gd:560 | 完美档 41% 通关全败实证——历史实证读数 | - -(行号=实施后实测;C 面同位替换零行数变化,预期与基线一致——不符即 L2 记录按实测定。) - -### q5 · 体验验证清单目检项引语(根件,随批同步——用户 B 表指令) - -- :193 生涯页目检项:「通关局数〔括注「三关全通」〕 / 各关通关次数」→「冒险成功局数〔括注「三关全通」〕 / 各关完成次数」、句尾「三关全通才计通关」→「三关全通才计冒险成功」 -- :198「『通关局数』口径如与体感冲突」→「『冒险成功局数』口径如与体感冲突」 -- :107「真人通关率+k 系数」→「真人关卡完成率+k 系数」 -- :258 历史读数记载行(四代锚、T19 读数等带批名日期引述)——豁免保留原文 - -**完成定义**: - -1. q1–q5 全落地;三条 grep 判据过(§8 wr 判据)+验证集清单对账零差异; -2. 计数器键名(`adventure_cleared`/`level_clear_counts`)与测量数据键、sim-data 锚文件名零触碰(wr1 读数对拍);断言条件表达式除 wr1/wr2/wr3 三处随动外零触碰; -3. 撤销证明=A 面 13 条逐条(回退产品行 hunk→对应断言红→复原复绿)记录成表;三份产出物写齐(T5)。 - -## 2. 设计事实源 - -| # | 出处 | 取用条款 | -|---|---|---| -| D1 | [术语表](../design/gdd/术语表.md) v1.23:「关卡完成」「冒险成功」「冒险落幕」三行+「退役词对照」通关/冒险终结两行 | 全部换法的第一依据 | -| D2 | 用户 2026-10-26 开工指令(本卡来源 prompt):A 表 12 条措辞逐字核定+:159 注释同步项+B/C 面清单+红线 | q1 逐字措辞、q5 随批范围、零触碰红线 | -| D3 | termsweep2-20261026 批(合并提交 6af36382):文档面 25 文件 145 行已完成 | 「通关率」→「关卡完成率」文档面先例(难度曲线与Boss「关卡完成率带」) | -| D4 | [test-conventions](../design/engineering/test-conventions.md) §8.3(验证集清单同步义务)+ quotaface-20261026 先例(S11 豁免单 4→7 处流程、清单重生成对账、卡片与条目随批删除) | q2 清单重生成、q4 豁免单、批内删卡删条目 | - -## 3. 现状事实(2026-10-26 写卡会话实查于 master 1ca76f16;开工日 T0 复核行号) - -| # | 事实 | 出处 | -|---|---|---| -| B1 | game/ 全域「通关」208 处/47 文件(A 面 13+B 面 111=13 测试 60+探针 13+验证集清单 38+C 面 84);「冒险终结」零命中 | grep 实查(任务基线 208 处一致;文件数 46→47 为本会话按现行扩展名集实测) | -| B2 | 必红断言三处=battle_narrator_test:41(条件 `level == "关卡通关!"`)/ui_struct_probe:436(条件 `sum1.text != "通关 2 局 · 冒险 7 局"`)/ui_tune_probe:75(条件 `out.contains("通关率")`);其余 57 处为标签/注释(条件位是数值判定,改产品字串不红) | 三文件 grep+条件位扫描实查 | -| B3 | A 面其余 10 条产品字串零逐字断言(theme_projection 断的是值文本「1 局(三关全通)」非行标签;TREASURE_REQ_LABELS/curio_pick_header 回血行/node_curio_header 渠道句/adventure_summary_text 关数行/camp 最近冒险行/ui_tune「通关剩余 HP」行均无断言) | theme_projection_test:840-871、grep TREASURE_REQ_LABELS/最近冒险/通关回血 实查 | -| B4 | S11 词表动态解析自术语表「退役词对照」——termsweep2 批入表后「通关」「冒险终结」已自动进入扫描;豁免三层=①闸门自指 ②显式留档豁免单 7 处 ③非注释面(字符串字面量)不取;A 面产品字串属③、注释面与 game/ 内 .md 整行属扫描面 | `game/tests/static_scan.sh:122-230` | -| B5 | 验证集清单由 extract_checks.py 机器提取冻结(标签+cond+计数三要素对账;--extract --force 重生成、--diff 对账);探针不进清单 | `tools/extract_checks.py` 头注;quotaface 先例 | -| B6 | hud_presenter:191/:194 属 tune_sim_report(调试浮层批量模拟报告——DS_DEBUG 门控玩家可见面);camp 最近冒险行装配=`camp_overlay_view._rebuild_recent`(open_camp 全量重建路径,data 键缺省走 .get 兜底);career 行标签与值 label 分体(值断言不断行标签) | hud_presenter.gd:186-195、camp_overlay_view.gd:376-382/:534-547、theme_projection_test:835-855 | -| B7 | ui_struct_probe:446 禁项检查「 关」现存形态注释引「通关」作不误伤说明——产品字串换代后摘要零「关」字,注释须改写不再引旧词(否则撞 S11) | ui_struct_probe.gd:446-451 | - -## 4. 设计契约(红线,违反 = L3 停机呈报) - -🔴 **契约 1 · A 表措辞逐字照行**:q1 的 13 条新文案逐字按 §1 表落(用户已核);实施中发现 A 表之外的玩家可见「通关」字串(含新发现文件)=停卡呈报,禁自行拟措辞。 - -🔴 **契约 2 · 零触碰面**:计数器键名 `adventure_cleared`/`level_clear_counts`、存档域键、sim-data 锚文件名与 JSONL 数据键、RNG 流名、全部数值行——逐字不动;断言条件表达式除 wr1/wr2/wr3 外零触碰(B 面只改标签文本与注释)。 - -🔴 **契约 3 · 清单跟上**:断言标签改动后 `tools/extract_checks.py --diff` 对账零差异;禁为免对账保留旧标签。 - -🔴 **契约 4 · 残留清零双闸兜底**:`grep -rn "通关" game/` 非豁免残留清零(豁免=q4 清单 13 行+S11 既有 7 行+字符串字面量位非注释面);S11 全绿。清单外新发现的注释残留按映射表同批清(非行为改动,L1 自主),**新发现的玩家可见字串仍走契约 1 停卡**。 - -🔴 **契约 5 · 撤销证明全量**:A 面 13 条逐条「回退产品行 hunk→最窄断言红→复原复绿」;禁以「代码能跑通」代替。 - -🔴 **契约 6 · 禁为机检文本保留无效成员**(req-card 第 13 条):禁为避免 S11/清单红而保留旧词文本或新增别名/无效成员;机检键与卡片契约互斥时停卡呈报。 - -## 5. 范围边界 - -**做**:q1–q5;三条 grep 判据;清单重生成对账;撤销证明 13 条;S11 豁免单扩充;产出物三份;卡片与待办条目随批删除(quotaface 先例,用户开工令内含「实施」)。 - -**不做**: -- 计数器/存档域/数据键/数值任何调整(零数值改动=零 MC,11 号对拍不补跑——quotaface 同款红线); -- design/ 面与根规则文件除体验验证清单目检项引语外的任何修订(roadmap 不动——提前实施批无迭代行;待办清单仅删本条目); -- 体验验证清单 :258 历史读数记载行(豁免保留); -- 任何未被 A/B/C 表覆盖的新措辞裁量。 - -## 6. 关联文档同步面 - -| 文档 | 关联点 | 同步义务 | -|---|---|---| -| `体验验证清单.md`(根件) | :193/:198 生涯页目检项引语随 a6/a7 换代、:107 关卡完成率口径 | **随批同步**(用户 B 表指令;q5——批内落地,全量档闸覆盖) | -| `待办清单.md`(根件) | 本条目随批删除(活干完登记即毁——quotaface 先例) | **随批同步**(批内删除) | -| [术语表](../design/gdd/术语表.md) v1.23 | 退役词对照已收两行,无需改动 | 反哺点 · 预期零改动注记(T0 核对) | -| [架构文档](../design/engineering/architecture/architecture.md)「测试与质量域」 | S11 豁免单 7→20 处的现状登记(若该节登记了豁免计数) | 反哺点 · 列清单(T0 查该节是否载计数,载则列换代行) | -| `game/tests/README.md`(测试工具手册) | 若载 S11 豁免计数/清单说明 | 反哺点 · 列清单(T0 查,载则列) | - -## 7. 任务卡 - -### 卡前 · 文件结构图 - -| 文件 | 职责 | 行为改动 | -|---|---|---| -| `game/presentation/battle_narrator.gd` | a1–a5 产品字串+:154/:159 注释(复用既有·修改) | 行为改动 → 对照表 a1–a5 | -| `game/presentation/views/career_overlay.gd` | a6/a7 标签+:11/:12/:36 注释 | 行为改动 → a6/a7 | -| `game/presentation/views/save_select_overlay.gd` | a8 摘要+:2/:18 注释 | 行为改动 → a8 | -| `game/presentation/views/ui_kit.gd` | a9 标签值+:211 注释 | 行为改动 → a9 | -| `game/presentation/views/camp_overlay_view.gd` | a10 最近冒险行 | 行为改动 → a10 | -| `game/presentation/hud_presenter.gd` | a11/a12 调试报告文案 | 行为改动 → a11/a12 | -| `game/tests/unit/presentation/battle_narrator_test.gd` | wr1 随动+V1/V2/V3 新增 | 断言随动+新增 | -| `game/tests/unit/presentation/theme_projection_test.gd` | 3 处标签随动+V4/V5/V6 新增 | 断言随动+新增 | -| 其余 11 测试文件 | 60 处减 battle_narrator_test 2 处=58 处标签/注释随动 | 非行为改动(标签文本) | -| `game/probe/ui_struct_probe.gd` | wr2+:446 注释改写 | 断言随动 | -| `game/probe/ui_tune_probe.gd` | wr3+V7 | 断言随动+新增 | -| `game/probe/ui_click_probe.gd` | 7 处注释/print | 非行为改动 | -| `game/tests/验证集清单.md` | 重生成 38 处 | 非行为改动(机器生成同步) | -| core 六件+七张表+schema 两件+sim 四件+`game/README.md`+呈现层注释件 | q3 注释同位替换 | 非行为改动(注释面) | -| `game/tests/static_scan.sh` | q4 豁免单 7→20 处 | 非行为改动(闸件豁免清单;判据口径零变化) | -| `体验验证清单.md` | q5 目检项引语 4 行 | 非行为改动(文档引语) | - -(零新增文件、零新增函数、零新增数据件。) - -### T0 · 开工核对(0.1d) - -- [ ] 建 worktree `git worktree add ../g-plan2-termsweep-game -b termsweep-game-20261026`+拷 `.godot/` 导入缓存与字体 .import 边车(坑册三件套) -- [ ] 复核 B 面行号(迭代 38 若有先合回的批改了行号则以实查为准——行面零交叠预期成立) -- [ ] V6 前置验证:camp_overlay_view.open_camp 最小 data 健壮性直跑(30 秒级孤立验证——新断言先 standalone 走通再并入套件) -- [ ] V7 前置验证:ui_tune_probe 现行参数下模拟必有胜局(读一次探针输出确认「通关剩余 HP」行恒在) -- [ ] 术语表 v1.23 三行在位核对(§6 零改动注记);架构文档/README 是否载 S11 豁免计数核对 - -### T1 · A 面产品字串+必红断言(0.25d) - -- [ ] a1–a12 十二处字串逐字落(q1 表);wr1/wr2/wr3 断言条件+标签+注释同轮换 -- [ ] V1–V3 battle_narrator_test 三组新断言落(孤立验证:单套件直跑绿) -- [ ] 撤销证明 a1–a5(回退 battle_narrator hunk→battle_narrator_test 红→复原复绿) - -**接口块**:取用=无前置卡;产出=产品字串新文案(对照表 a1–a12 文本,V 组断言引用)。 - -### T2 · B 面其余断言随动+新增断言+清单(0.25d) - -- [ ] 11 测试文件 58 处标签/注释随动(q2 逐处换法表)+theme_projection 3 处+V4/V5/V6 落位 -- [ ] 三探针随动+V7(ui_click 7 处、ui_struct wr2+:446 注释改写、ui_tune wr3+V7) -- [ ] `python tools/extract_checks.py --extract --force` 重生成 → `--diff` 对账零差异 -- [ ] 撤销证明 a6–a10、a12(theme_projection/ui_struct/ui_tune 各自最窄套件红→复绿) - -**接口块**:取用=T1 产品字串(a1–a12 文本);产出=验证集清单新基线(T4 件核对账)。 - -### T3 · C 面注释清扫+S11 豁免单(0.25d) - -- [ ] core 29+表头注 5(17−12 豁免)+schema 4+sim 11(12−1)+README 7+呈现层 15——按映射表同位替换 -- [ ] static_scan.sh 豁免单 13 行登记(.tres 段 12+.gd 段 1,行号按实施后实测)+头部豁免说明句更新 -- [ ] 撤销证明 a11 复核(wr3 已在 T1;此处 S11 直跑绿作护栏确认) - -### T4 · 件核+体验验证清单+冻结(0.1d) - -- [ ] q5 体验验证清单 4 行改(:107/:193/:198;:258 不动) -- [ ] 三条 grep 判据(§8)逐条零输出 -- [ ] 冻结:代码与断言改完即冻结,全仓件核 grep 查残留 -- [ ] 并 master(若 master 被推进——先并后闸铁律) - -### T5 · 产出物落位卡(0.15d) - -- [ ] 轻闸全绿后、合并前 `reports/` 三份写齐:`iter-supplement-通关换代-实现报告-2026-10-26.md`(各卡状态+撤销证明记录表 13 条+实机目检总清单+遗留读数义务)、代拍板追认单(§10 白名单逐条)、反哺点清单(§6 所列每条落点) -- [ ] 卡片与待办条目删除(quotaface 先例;唯一引用=条目自身) -- [ ] 批末全量域闸(改动含代码面+game/ 内 .md+根件+reports/ → 不带参数全量档)全绿、回执对齐分支尖 → 主区 `git merge --no-ff` → worktree 清理 - -## 8. 验证闸(改动—验收对照表) - -| 需求点 | 改动(文件:行) | 验收测试(名称+落点+尾缀) | 层级 | 真实入口 | 撤销证明 | -|---|---|---|---|---|---| -| a1 关卡完成文案 | battle_narrator.gd:50 | 「关卡收束态恒为「关卡完成!」」battle_narrator_test:41〔随 wr1〕 | 单元 | 直调 battle_end_text | 回退 :50 → wr1 红 → 复绿 | -| a2/a3 回血两分支 | battle_narrator.gd:90/:92 | V1 curio_pick_header 断言〔通关换代 V1〕 | 单元 | 直调 curio_pick_header | 回退 :90/:92 → V1 红 → 复绿 | -| a4 渠道句 | battle_narrator.gd:156 | V2〔通关换代 V2〕 | 单元 | 直调 node_curio_header | 回退 :156 → V2 红 | -| a5 完成关数行 | battle_narrator.gd:166 | V3〔通关换代 V3〕 | 单元 | 直调 adventure_summary_text | 回退 :166 → V3 红 | -| a6/a7 生涯标签 | career_overlay.gd:42/:43 | V4 生涯页标签零残留〔通关换代 V4〕 | 接口 | open_career+树内 label 收集 | 回退 :42/:43 → V4 红 | -| a8 槽摘要 | save_select_overlay.gd:87 | wr2 ui_struct_probe:436〔sl2 随动〕 | 探针 | 场景实例化+喂入数据 | 回退 :87 → wr2 红 | -| a9 解锁标签 | ui_kit.gd:403 | V5〔通关换代 V5〕 | 单元 | UiKit 常量直读 | 回退 :403 → V5 红 | -| a10 最近冒险行 | camp_overlay_view.gd:545 | V6〔通关换代 V6〕 | 接口 | open_camp+_recent_list 读数 | 回退 :545 → V6 红 | -| a11 完成率读数 | hud_presenter.gd:191 | wr3 ui_tune_probe:75〔随动〕 | 探针 | 场景实例化+批量模拟输出 | 回退 :191 → wr3 红 | -| a12 剩余 HP 行 | hud_presenter.gd:194 | V7〔通关换代 V7〕 | 探针 | 同上报告 | 回退 :194 → V7 红 | -| q2 断言随动 | 13 文件 60 处 | extract_checks --diff 对账零差异+各套件批末闸 | — | 机器对账 | 由 a1–a12 行撤销证明连带覆盖 | -| q3 注释清扫 | C 面 84 处 | grep 判据②③+S11 全绿 | — | 静态扫描 | 非行为改动(判断依据:注释/头注文本,无运行时语义) | -| q4 豁免单 | static_scan.sh 13 行 | S11 直跑绿且豁免行不误伤相邻残留(抽一行去豁免验证红) | — | 静态扫描 | 去豁免行 → S11 红 → 还原 | -| q5 目检项引语 | 体验验证清单 4 行 | --docs 域闸 doc_term_audit 绿 | — | 文档域闸 | 非行为改动(文档引语) | - -**grep 判据**(三条;豁免面机械判定由 S11 承载——注释面+game/ 内 .md 整行,豁免单承载 q4 13 行): - -- wr判①:S11 直跑绿(零命中)——即「game/ 注释面与 .md 非豁免残留清零」的机械形态;辅以人工抽查 `grep -rn "通关" game/` 输出逐行比对 q4 豁免单(每命中行必在豁免单或字符串字面量位) -- wr判②:`grep -rn "冒险终结" game/` → 零输出 -- wr判③:对账 `python tools/extract_checks.py --diff game/tests/验证集清单.md` → 退出码 0 - -**测试削弱申报**:本批改动的既有断言=wr1/wr2/wr3 条件文本随产品字串换代(非削弱——判据随动);其余 57 处仅标签文本;零断言删除、零阈值放宽、零扫描面缩小。 - -**独立验收审计**:合回前由未参与实现的子代理按 test-conventions §8.7 审(报告落 `reports/iter-supplement-通关换代-验收审计-2026-10-26.md`):对照表逐行核、撤销证明抽三条复现、削弱扫描。 - -**闸口径**:批末 `tools/run_all_gates.sh` 不带参数全量档(改动含代码面+文档件两类);批内回归措辞=里程碑步(T 段)出口跑一次全套闸;波内修复只做出红最小单元的最窄确认;新增断言先行孤立验证再并入全套。 - -## 9. 异常分级 - -- L1 自救(一次重试):行号漂移(迭代 38 先合回导致)——以实查重定位;豁免行号与预期不符——按实测定。 -- L2 记录继续:V6 最小 data 不健壮——改完整构造照 camp_shop_presenter 投影;V7 零胜局——呈报改设计(同轮记录)。 -- L3 停机呈报:A 表外新玩家可见「通关」字串;机检键与契约互斥;S11 豁免单机制不足以表达某豁免形态;闸红且修法超出本卡范围。 - -## 10. 代拍板白名单 - -1. B/C 面标签与注释的措辞在映射表(q3)两可时的具体选词(如「路径完成」vs「完成路径」)——限标签/注释面,产品字串不适用。 -2. 豁免单行号按实施后实测微调。 -3. V1–V7 断言的夹具数据具体取值(保持确定性即可)。 - -## 11. 待裁点 - -零待裁点,开工门=U0(用户 2026-10-26 开工令已下达)。 - -## 12. 落位与可复用性预检 - -- **复用面**:零新增文件/函数/数据件——全部为既有文件的文本替换与既有测试文件的断言追加;V4 的树内 label 收集复用 ui_struct_probe `_collect_labels` 同型写法(theme_projection 内新写四行等价物——不跨层引探针私有件,避免测试件间耦合);V6 落 theme_projection_test 延续 career_overlay 直调先例。无「不能复用既有件」的新增申报。 -- **唯一面**:产品字串唯一落点=各装配器/视图现文件(无第二处定义);「关卡完成」等新词的规范名唯一登记处=术语表(已立,本批零文档新增)。 -- **分层与交互面**:V1–V3 直调 BattleNarrator 静态装配器(单元层);V4–V6 实例化视图 open 面后读 label(接口层,theme_projection 先例同型);V7/wr3 探针走批量模拟真实输出。零 Core 改动、零数值读取新增、零 RNG 触碰。 - -## 13. 复核记录 - -- v1.0 成文,grilling 一轮对抗复核(独立子代理,2026-10-26):**零阻断**;四应修全折入——①q3 呈现层计数口径注明(:159 归 A 面)+全文统一「A 表 12 条+:159 注释同步项」②估时对齐 T 段合计 ≈1.1d ③映射表补帧预算/流程语境行(「跑完」)④「非末关通关/末关通关」→「非末关的关卡完成/末关的关卡完成」防「末关卡」连读歧义(ui_click:478、breakpoint_resume:99、adventure_runner:808、adventure.tres:51、curio_interact 注释族)。 -- 复核通过面(子代理实查证据):措辞与 A 表逐字一致;208 处全数对上(12 产品+111 随动+84 注释);豁免 13 行无漏判;V1–V7 落点全真(V6 open_camp 最小 data 全链 .get 兜底健壮性经子代理读码确认);语境抽查 8+ 处全对;契约完备;q5 恰 4 行覆盖。 -- v1.1 定稿,零待裁点。 diff --git a/体验验证清单.md b/体验验证清单.md index 9d86e54b..1604291d 100644 --- a/体验验证清单.md +++ b/体验验证清单.md @@ -104,7 +104,7 @@ **2026-10-01 数值修复批后试玩注记**(master 4b4a011 起的正式标定局):本批已落 hero 血池 20→26 / 直伤雷三行 4/5/5→6/8/8 / L1 系敌 atk 2→1(轨迹与读数见 numfix 报告(已退役,git 历史可查))。试玩时对号新增两点: 1. **踩雷疼痛感**(本批主刀):「踩很多雷还是轻松活」应是过去式——单雷 6-8 直伤、两三连雷应明显肉疼;若仍无痛感=回调信号,记一句话即可; -2. **整体难度印象**:用户 2026-10-01 已阶段性验收「令人稍微满意」——本批试玩读数作正式标定(真人通关率+k 系数),若体感偏难/偏易也照实记,不因单局顺逆回调。 +2. **整体难度印象**:用户 2026-10-01 已阶段性验收「令人稍微满意」——本批试玩读数作正式标定(真人关卡完成率+k 系数),若体感偏难/偏易也照实记,不因单局顺逆回调。 模拟侧对照读数(普通档画像 L1 13%/战役 0%;完美档 78.5%)见同报告 §四。 ### ⑩ 迭代 10 奖励重构体验项(2026-10-01 顺带登记——实机目检一轮已过 1/3/4/5/6/9/14,余项人工参与) @@ -190,12 +190,12 @@ ### ⑲ 生涯页目检(迭代 18 卡④生涯界面实装批·期一顺带登记——主菜单新增一级只读页+存档 v6) - **入口与开合**:〔入口已换代——迭代 33 卡② 撤主菜单生涯钮后无玩家可见入口,待迭代 34 卡④ 营地笔记本接入;接入前本项验到页内容即可〕点开全屏页、点「返回」回上层(开始层钮可见性随开合正确恢复)。 -- **页呈现两类六项**:组一·冒险战绩(冒险总局数 / 通关局数〔括注「三关全通」〕 / 各关通关次数〔一行三关,关名带层号〕 / Boss 首杀〔X/3 关〕 / Boss 总击杀);组二·资源(钥石余额徽)——数值与存档实况一致(对照:玩几局后总局数含放弃与失败、三关全通才计通关)。〔原「属性锻造已购合计」「天赋树已购概览」两观测项随生涯页三投影删除摘除——2026-10-12 用户裁⑧,天赋树实装批顺带〕 +- **页呈现两类六项**:组一·冒险战绩(冒险总局数 / 冒险成功局数〔括注「三关全通」〕 / 各关完成次数〔一行三关,关名带层号〕 / Boss 首杀〔X/3 关〕 / Boss 总击杀);组二·资源(钥石余额徽)——数值与存档实况一致(对照:玩几局后总局数含放弃与失败、三关全通才计冒险成功)。〔原「属性锻造已购合计」「天赋树已购概览」两观测项随生涯页三投影删除摘除——2026-10-12 用户裁⑧,天赋树实装批顺带〕 - **旧档载入**:v5 现役档(升级前存档)载入后生涯页正常显示,总局数/冒险成功局数从 0 起计(终身计数域 v6 新增,缺省补零),钥石等既有进度原样。 - **零跳转与局内零入口**:页内除「返回」外无任何前往他处的按钮;冒险进行中(战斗屏/关卡地图屏/状态面板)无生涯入口。 - **对比度与零动效**:页文字亮墨族在深棕底上可读(机检 3 对已入 ui_contrast 闸);开页/关页无过渡动画。 - **红灯信号**:计数与实玩局数对不上(收束入账重复或漏计);旧档载入返回错误或计数域显示异常;页内出现购买/跳转入口;入口在局内可点。 -- **结论回流**:呈现问题归生涯批后续修正(本批需求卡片 v1.2 在案);「通关局数」口径如与体感冲突=P1 甲裁决复核(三关全通才计 1,用户已裁);期二内容(历史回看/图鉴)缺位属分期计划非缺陷。 +- **结论回流**:呈现问题归生涯批后续修正(本批需求卡片 v1.2 在案);「冒险成功局数」口径如与体感冲突=P1 甲裁决复核(三关全通才计 1,用户已裁);期二内容(历史回看/图鉴)缺位属分期计划非缺陷。 ### ⑳ 营地统一四柜台目检(迭代 21 天赋树实装批顺带登记——V22 人闸;2026-10-12) diff --git a/待办清单.md b/待办清单.md index 8bf9d401..225c5cb6 100644 --- a/待办清单.md +++ b/待办清单.md @@ -2,19 +2,6 @@ 本清单是流水线的唯一登记处:要做的事先在此登记一条,随流水线段推进改状态,做完整条删除;各系统文档的「待办」节只留一行指路存根,不再自建条目。条目格式(标题=登记元数据含可选优先级,正文=实况/缺口/改动面/状态四属性)与状态机以 [doc-conventions §12.1](design/engineering/doc-conventions.md) 为权威。 -#### game 面玩家可见字串「通关」退役换代——A 面文案 13 条+B 面断言随动+C 面注释清扫(2026-10-26 登记,来源=批次移交) - -**实况**:文档面已由 termsweep2-20261026 批完成(合并提交 6af36382,25 文件 145 行),本条承接 game/ 面。2026-10-26 用户裁「通关」全库退役+开工令(A 表 13 条玩家可见字串措辞已核,改动即停呈报):单关=关卡完成、整局=冒险成功、一局终结统称=冒险落幕;「通关率」随文档面先例(难度曲线与Boss「关卡完成率带」)换代「关卡完成率」。写卡会话实查基线:game/ 全域「通关」208 处/47 文件(A 面产品字串 13 条=battle_narrator 6+career_overlay 2+save_select_overlay 1+ui_kit 1+camp_overlay_view 1+hud_presenter 2;B 随动面=13 测试文件 60 处+ui_click/ui_struct/ui_tune 三探针 13 处+验证集清单 38 处,其中逐字断言必红三处=battle_narrator_test:41/ui_struct_probe:436/ui_tune_probe:75;C 注释面=core 六件 29+七张表头注 17+schema 两件 4+sim 四件 12+game/README 7+呈现层注释 15);带日期历史读数注释按豁免惯例保留原文(S11 留档豁免单登记)。S11 已随术语表收词自动开始扫「通关」「冒险终结」——本条实施后非豁免残留即闸红。 - -关联文档清单: -- design/gdd/术语表.md v1.23(「关卡完成」「冒险成功」「冒险落幕」三行+退役词对照「通关」「冒险终结」两行——通关口径统一批,2026-10-26) -- 用户 2026-10-26 开工指令(A/B/C 三面清单+红线——计数器键名 adventure_cleared/level_clear_counts 与测量数据键、sim-data 锚文件名零触碰) -- 需求卡片 reports/需求卡片-通关口径换代批-2026-10-26.md(2026-10-26 v1.1 定稿,grilling 一轮复核零阻断、四应修折入,零待裁点;估时 ≈1.1d;用户开工令裁准提前实施,先例=quotaface-20261026) - -**改动面**:游戏代码 - -**状态**:文档设计已闭合+已写卡 - #### AdventureRunner 职责真拆分——三宿主共 25 条转发属性属 S13 计数迎合装置,须按变化原因重立协作件(2026-10-25 登记,来源=批次移交,优先级=P0) **实况**: