diff --git a/design/gdd/06-待办清单.md b/design/gdd/06-待办清单.md index e8c0e717..b9b271e1 100644 --- a/design/gdd/06-待办清单.md +++ b/design/gdd/06-待办清单.md @@ -627,6 +627,14 @@ --- +#### 技术债观察登记——长函数余量与 lambda 连接防回归(2026-10-15 迭代 27 卡片义务补登) + +**现状**:迭代 27 需求卡片两项「登记 06 观察」义务随批漏登,卡片核对时补登——①**长函数 17 个**中非结算段的装配/校验函数(`level_map_screen.gd` 选路装配 155 行/`camp_overlay_view.gd` 152 行/`debug_overlay.gd` 114 行/`treasure_item_table.gd` schema 校验群等;`main._build_ui` 已随场景拆分自然解体、`_settle`/`_resolve_hero_attack` 已随波二拆段=17 中 3 件已消解,余 14 件);②**lambda 连接 76 处**(presentation 6/smoke 62/tests 8——实读无泄漏,登记防回归)。 + +**归属**:工程债观察备忘(不阻塞,不排期;新增此类代码沿现役规范评审盯) + +**状态**:备忘(长函数拆分无独立需求驱动不动;lambda 连接数若有审计工具化需求归类型闸后续) + #### 迭代 27 代码架构技术债修复批——GDD 反哺点两条(2026-10-14 随批登记,待用户逐点裁决另批落文) **现状**:五波全量入库(单会话交付;逐位一致对拍三变体五跑全同;实现报告=design/qa/iter27-实现报告-2026-10-14.md)。实现与设计权威文档的差异/缺口如下,经裁决后另批落文——**机械面随批已动的只有本条与 07/roadmap**。 diff --git a/design/qa/iter27-实现报告-2026-10-14.md b/design/qa/iter27-实现报告-2026-10-14.md index 46876bbf..e19e319c 100644 --- a/design/qa/iter27-实现报告-2026-10-14.md +++ b/design/qa/iter27-实现报告-2026-10-14.md @@ -87,6 +87,7 @@ ## 六、残留与去向 - 残留人闸:07 ㉖ 五件(登记不阻塞)。 +- **卡片核对补登(2026-10-15)**:逐条核对卡片 §2/§4/§6/§7 兑现面,补齐三项——①V8 卫生 grep 断言落地(smoke `_smoke_hygiene_gates`:字符串 Callable 产品码零命中/FeatsEngine 文件退役/死代码抽查/GP 影子账零残留);②卡片 §4「长函数 17 个登记 06 观察」+§2.3「lambda 连接 76 处登记防回归」两条义务补登 06(17 中 3 件已随波一/二消解,余 14 件备忘);③漏网字符串 Callable×2 补装(config_db resolver 通道——T6 新增位点,追认单#15 换装面覆盖)+main 头注死引用清理。核对结论:§1 五波/§3 六契约/§6 T0-T7/§7 V1-V9 其余条目全部兑现(详见各波闸记录)。 - 代拍板追认单十五项(上表)待用户逐项追认。 - GDD 反哺点两条(06 在册)待裁决另批落文。 - 审计报告本体已按退役规则 git rm(吸收即死;修正后计数已由需求卡片 v1.2 承载)。 diff --git a/game/core/config_db.gd b/game/core/config_db.gd index 5153622e..d80d672f 100644 --- a/game/core/config_db.gd +++ b/game/core/config_db.gd @@ -60,7 +60,7 @@ var _reload_gate := false # 数据配置 EC8——战斗结 func _init() -> void: - _resolver = ConfigDbResolver.new(Callable(self, "push_diag"), Callable(self, "reset_warn_dedup"), + _resolver = ConfigDbResolver.new(push_diag, func() -> Variant: return board_gen.rows, func() -> Variant: return enemy.rows, func() -> Variant: return difficulty) # 协作类持门面引用(诊断/致命通道回呼) @@ -90,7 +90,7 @@ func is_fatal() -> bool: func reset_diagnostics() -> void: _diagnostics.clear() - _resolver._reset_warn.call() # R1 告警去重注册表(协作类持钥——清空时点与拆分前一致;通道 Callable 化随 T6) + _resolver.reset_warn_dedup() # R1 告警去重注册表(协作类持钥——清空时点与拆分前一致) func diagnostics() -> Array: diff --git a/game/core/config_db_cross_validator.gd b/game/core/config_db_cross_validator.gd index 252c3c58..585acf0b 100644 --- a/game/core/config_db_cross_validator.gd +++ b/game/core/config_db_cross_validator.gd @@ -3,7 +3,7 @@ # 职责单一化(Rule 6 校验双通道的跨表一侧):_cross_validate 全域(悬空引用/池护栏/节点精确行/ # 技能池构成)+ validate_skill_pool_links(冒烟直验独立入口)。ConfigDb autoload 门面保持—— # load_tables 调用点与冒烟直验经门面同名方法,公有签名零变化。 -# 诊断通道注入:跨表校验的行级错误经 push_diag: Callable 外发(门面传 Callable(self, "push_diag"))—— +# 诊断通道注入:跨表校验的行级错误经 push_diag: Callable 外发(门面传方法引用 push_diag——迭代 27 T6 Callable 换装)—— # 本类零 ConfigDb 依赖(无状态纯校验器,装载序上先于成员赋值执行的前提保持)。 # 迁移注记:validate_skill_pool_links 的 status_table 显式入参纪律照抄(装载通道传 loaded 表, # 冒烟直验传门面 status_effects;null 时 side 守卫跳过)——返回错误列表不进诊断通道,消费面归调用方。 diff --git a/game/core/config_db_resolver.gd b/game/core/config_db_resolver.gd index 15e81c87..b1c9911f 100644 --- a/game/core/config_db_resolver.gd +++ b/game/core/config_db_resolver.gd @@ -12,17 +12,15 @@ class_name ConfigDbResolver extends RefCounted var _diag: Callable # 诊断/致命通道(迭代 27 T6——门面类型反持解耦,validator 先例:签名 (level, category, message)) -var _reset_warn: Callable # 去重注册表清空通道(reset_diagnostics 时点由门面驱动) var _board_gen_rows_get: Callable # () -> Array——board_gen 行集活读(数据面经 Callable 注入,ConfigDb 类型环断根) var _enemy_rows_get: Callable # () -> Array——enemy 行集活读 var _difficulty_get: Callable # () -> DifficultyTable(可空——表缺省合法态) var _warn_dedup: Dictionary[String, bool] = {} # R1 四元组去重注册表(自 ConfigDb 迁入) -func _init(diag_cb: Callable, reset_warn_cb: Callable, board_gen_rows_cb: Callable, +func _init(diag_cb: Callable, board_gen_rows_cb: Callable, enemy_rows_cb: Callable, difficulty_cb: Callable) -> void: _diag = diag_cb - _reset_warn = reset_warn_cb _board_gen_rows_get = board_gen_rows_cb _enemy_rows_get = enemy_rows_cb _difficulty_get = difficulty_cb diff --git a/game/presentation/main.gd b/game/presentation/main.gd index 4b219c02..7159b281 100644 --- a/game/presentation/main.gd +++ b/game/presentation/main.gd @@ -22,7 +22,7 @@ # T3 拆件批(2026-10-02,规范 1.1 单一职责):结算行排播泵迁 row_pacer.gd(本类只入队/排空/读队列, # 探针/测试委托面 _row_queue/pace_delay_for/_flush_row_queue 原位保留);秘宝两步交互迁 # treasure_interact_controller.gd(本类只接线与转发意图,无目标使用显式化——哨兵坐标不出控制器); -# GP 冒险钱包影子账迁 gp_shadow_ledger.gd(本类留探针同名读写委托面)。模态开合全量走 +# (GP 影子账已随迭代 27 T3 退役——summary gp_final 键取代)。模态开合全量走 # _open_modal/_close_modal 单口,输入锁=modal_stack.has_open_excluding(debug_overlay) 排除式 # 开态查询+三例外(迭代 18 卡⑦——浮窗开态不计入锁);battle 收尾反馈与 # 结算视觉 setter 收敛 hud_presenter 单通道(时序敏感演出触发留本类并注释);settlement 相位读取改经 diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index ccb0e191..40fd8bf0 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -83,6 +83,7 @@ func _split_tail() -> void: await process_frame var autoload_ok: bool = get_root().get_node_or_null("/root/ConfigDB") != null and get_root().get_node_or_null("/root/SaveManager") != null _smoke_type_gate() + _smoke_hygiene_gates() if autoload_ok: await _smoke_scene_split() # 协程函数必须 await(无 await=发射后不管,首个 await 后即被 quit 截断) await _smoke_run_lifecycle() @@ -103,6 +104,45 @@ func _smoke_type_gate() -> void: "V7 类型审计器闸机在位(static_scan S9 → tools/audit_type_hints.py)〔迭代27 T5〕") +# ---- 卫生件 grep 闸(迭代 27 T6 V8——死代码/字符串 Callable/影子账残留零命中;源码扫描面)---- +func _smoke_hygiene_gates() -> void: + var callables := 0 + for d in ["res://core", "res://presentation", "res://data"]: + var dir := DirAccess.open(d) + if dir == null: + continue + dir.list_dir_begin() + var f := dir.get_next() + while f != "": + if dir.current_is_dir() and not f.begins_with("."): + var sub := DirAccess.open(d + "/" + f) + if sub != null: + sub.list_dir_begin() + var g := sub.get_next() + while g != "": + if g.ends_with(".gd"): + var t: String = FileAccess.get_file_as_string(d + "/" + f + "/" + g) + callables += t.count("Callable(self, \"") + g = sub.get_next() + elif f.ends_with(".gd"): + var t2: String = FileAccess.get_file_as_string(d + "/" + f) + callables += t2.count("Callable(self, \"") + f = dir.get_next() + check(callables == 0, + "V8 字符串 Callable 产品码零命中(实测 %d——方法引用换装闸)〔迭代27 T6〕") + check(not FileAccess.file_exists("res://core/feats_engine.gd"), + "V8 FeatsEngine 整文件退役(class_name 注销=文件删除)〔迭代27 T6〕") + var bo: String = FileAccess.get_file_as_string("res://core/battle_orchestrator.gd") + check(not bo.contains("func _attune_row"), + "V8 死代码抽查·_attune_row 零残留〔迭代27 T6〕") + var sm: String = FileAccess.get_file_as_string("res://core/save_manager.gd") + check(not sm.contains("func attunement_counters"), + "V8 死代码抽查·attunement_counters 零残留〔迭代27 T6〕") + var mv: String = FileAccess.get_file_as_string("res://presentation/main.gd") + check(not mv.contains("gp_shadow_ledger") and not mv.contains("_gp_ledger"), + "V8 GP 影子账残留零命中(main 源码面——文件已删+委托缝已拆)〔迭代27 T3〕") + + # ---- 三屏场景化断言(迭代 27 T1 V2——独立实例化+关键节点在位+组合根树序/z 序保序)---- func _smoke_scene_split() -> void: print("--- 迭代27 T1 三屏场景化(V2:屏壳独立实例化+组合根装配保序)---")