From 089cf6ad066fa8caa13b71a34b52e8590f9cfd48 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Sat, 24 Oct 2026 20:04:24 +0800 Subject: [PATCH] =?UTF-8?q?docs(=E4=BB=A3=E7=A0=81=E5=AE=A1=E6=9F=A5):=20g?= =?UTF-8?q?ame/=20=E5=85=A8=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84=E5=AE=A1?= =?UTF-8?q?=E6=9F=A5=E5=AE=A1=E8=AE=A1=E6=8A=A5=E5=91=8A=EF=BC=8B=E5=BE=85?= =?UTF-8?q?=E5=8A=9E=E6=B8=85=E5=8D=95=E7=99=BB=E8=AE=B0=E5=9B=9B=E6=9D=A1?= =?UTF-8?q?=E2=80=94=E2=80=94=E8=A1=8C=E4=B8=BA=E7=BC=BA=E9=99=B7=E4=B9=9D?= =?UTF-8?q?=E4=BB=B6/=E7=BB=93=E6=9E=84=E9=87=8D=E6=9E=84=E5=80=99?= =?UTF-8?q?=E9=80=89=EF=BC=88=E5=B7=A5=E7=A8=8B=E7=9B=B4=E5=85=A5=C2=B7?= =?UTF-8?q?=E5=BE=85=E5=86=99=E5=8D=A1=EF=BC=89=E3=80=81S9=20=E6=AD=A3?= =?UTF-8?q?=E5=88=99=E5=A4=B1=E7=81=B5=EF=BC=88=E5=B7=A5=E7=A8=8B=E7=9B=B4?= =?UTF-8?q?=E5=85=A5=C2=B7=E5=BE=85=E5=86=99=E5=8D=A1=EF=BC=89=E3=80=81S6/?= =?UTF-8?q?S7/S8=20=E8=90=BD=E5=9C=B0=EF=BC=88=E5=B7=A5=E7=A8=8B=E7=9B=B4?= =?UTF-8?q?=E5=85=A5=C2=B7=E5=BE=85=E5=86=99=E5=8D=A1=EF=BC=89=E3=80=81?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E8=A7=84=E8=8C=83=E5=AF=B9=E9=BD=90=E6=89=B9?= =?UTF-8?q?=EF=BC=88=E6=96=87=E6=A1=A3=E8=BD=A8=C2=B7=E5=BE=85=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E8=AE=BE=E8=AE=A1=EF=BC=89=E3=80=82=E9=9B=B6=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=89=A7=E8=A1=8C=EF=BC=88=E4=B8=A4=E5=85=A5=E5=8F=A3?= =?UTF-8?q?=E9=93=81=E8=A7=84=EF=BC=89=EF=BC=8C=E7=BB=93=E8=AE=BA=E5=85=A8?= =?UTF-8?q?=E9=83=A8=E9=9D=99=E6=80=81=E9=98=85=E8=AF=BB=EF=BC=9B=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E5=9F=9F=E9=97=B8=E7=BB=BF=EF=BC=88=E5=9B=9E=E6=89=A7?= =?UTF-8?q?=20docs=20=E6=A1=A3=EF=BC=8C07=20doc=5Flink=20=E8=BE=83?= =?UTF-8?q?=E5=9F=BA=E7=BA=BF=E6=94=B9=E5=96=84=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- reports/审计-game代码结构审查-2026-10-24.md | 116 ++++++++++++++++++++ 待办清单.md | 34 ++++++ 2 files changed, 150 insertions(+) create mode 100644 reports/审计-game代码结构审查-2026-10-24.md diff --git a/reports/审计-game代码结构审查-2026-10-24.md b/reports/审计-game代码结构审查-2026-10-24.md new file mode 100644 index 00000000..1db957fd --- /dev/null +++ b/reports/审计-game代码结构审查-2026-10-24.md @@ -0,0 +1,116 @@ +# 审计:game 代码结构审查(2026-10-24) + +> **性质**:设计讨论段过程稿(审计读数)。`game/` 全目录只读结构审查的发现清单与证据,作为写卡段与非迭代批的输入材料;结论被吸收进代码修复与权威文档后按吸收即死退役。 +> **范围**:`game/` 全目录 194 个 .gd、约 4.5 万行(tests/probe/sim 不在产品码判定面)。基准双轨:项目自有规范(`design/engineering/architecture/architecture.md` 事实源 v1.9 + `design/engineering/code-conventions.md`)+ Godot 4.7 最佳实践。 +> **方式**:核心玩法域/组合根层/views 层三路深读+战斗结算域与数据基础设施层逐行通读+机械 grep 验证。**零测试执行**(测试两入口铁规),全部结论来自静态阅读;S9 正则失灵结论经独立复现(python 逐条对拍)。 + +--- + +## 一、总评 + +架构质量在同类个人项目里属罕见的高水位:五层分层(core 纯逻辑 headless 可跑/presentation 组合根)、B1 编排唯一性、RNG 封闭流、数值单一事实源、效果引擎四词表封闭、可回放确定性——这些约定不仅写在文档里,代码里也确实兑现(逐条 grep 验证:core 层零 `await`、零裸随机、`load()` 只在 config_db 单点、无 get_parent 链、views 层零核心写调用)。设计模式选型全部贴合领域:组合根、门面(ConfigDb)、发布订阅解释器(EffectEngine)、单据管线(DamageController)、快照/备忘录(断点续玩)、令牌池。 + +**真正的风险不在玩法代码本身,而在三处:保障层有洞(S9 类型闸正则失灵、S6/S7/S8 未落地)、规范与实现之间漂移累积(写调用位置、行类型词表、模块归属表)、以及一批真实但低频的行为缺陷。** 另有约 10 个文件超过项目自设的 ~400 行审视线,其中 main.gd(1508 行)已超过架构文档自记的 1100 行上帝对象反面案例。 + +--- + +## 二、Critical——会出 bug 或违反硬性契约 + +### 保障层(2 件) + +**C1. S9 类型闸正则两处失灵,R2 从上线起恒零命中**(`tools/audit_type_hints.py:29`,经独立复现) + +- `FUNC_DECL` 正则 `^(\s*)func\s+(_?\w+)\s*\((.*)\)\s*(->\s*.+)?\s*(#.*)?$` 两个洞:① 无返回类型的声明按 GDScript 语法必然以 `:` 结尾,正则要求 `)` 后只能跟 `->`/注释/行尾——**R2 的目标形态 100% 失配跳过,R2 恒零命中恒绿**;② 不认 `static ` 前缀,static 函数的 R2/R3 整体漏网。 +- 实证存量(闸当前退出码 0 全绿):`game/core/level_runner.gd:632`(`current_battle()` 返回 BattleOrchestrator 无 `->`)、`game/core/attunement.gd:10`(`static func slots(db, save)` 两参无类型)、`game/presentation/main.gd:565`(build_adventure_params 两参)、`game/presentation/views/hud_presenter.gd:10-11`(refresh 三参)、`game/core/reward_economy.gd:104/119/131/146`、`game/core/unit_container.gd:275`。 +- 这正是架构文档测试域自警的「规则扫描面为空=恒零命中恒绿」静默失效模式;零命中自检没拦住(因 R1/R3 仍有命中能力,整体不空)。修复义务按 test-conventions §6:正则修后先跑出存量红,补注解或 `# type-hint: ignore` 归零,闸改动配变异验证。 + +**C2. S6/S7/S8 三条静态规则未落地**(static_scan.sh TODO 在案,架构文档静态扫描表自认):B1 编排唯一性(B2/B3/B4 API 符号命中 ⊆ B1 文件集)、结算路径禁 await、core↔core 信号禁 lambda 捕获。本次人工 grep 结论干净(core 零 await、A2/B3/B4 零相互直调),但防线缺位=回归无闸;S7 落地前须先在架构文档成文 B1 文件集边界(含 `game/core/settlement/` 五段类与 damage_controller——现归属表零条目)。 + +### 架构契约(3 件) + +**C3. 基础层 A3 反向依赖核心层 EffectEngine**(`game/core/action_economy.gd:43-49,105,166,193` 经 `set_fx` 持 EffectEngine 并 dispatch;B4 `game/core/reward_economy.gd:24-31` 同款但属同层调用)。架构原则 6「依赖单向、上层可消费下层禁止反向」,且架构文档 A3 行消费依赖列未登记 EffectEngine——**真违约与事实源失真二选一,需裁决**:a) effect_engine 降登记为基础层(零状态纯判定,形态本就近基础层服务);b) A3 的 dig_paid/dig_stop/charge_full 发射改由 B1 调用前后代发,A3 回归纯账本;c) 最低限度先把消费依赖登记进架构文档消掉漂移。 + +**C4. 核心写调用外迁三控制器,code-conventions §1.3 字面已漂移**(spec-AC 冲突)。规范写「核心写接口(settle_batch/submit_window_selection/runner 推进)只允许在组合根出现」,实况:`game/presentation/curio_interact_controller.gd:76-244`(continue_after_node/pick_curio/apply_node_curio 等 6 口)、`game/presentation/camp_shop_presenter.gd:175-212`(buy_pool_item/shop_refresh 等 4 口)、`game/presentation/treasure_interact_controller.gd:89`(use_treasure)。视图层本身干净(views/ 零写调用,grep 实证)——漂移发生在「组合根构造注入的拆件控制器」这个**未成文层**,三控制器头注各自把「组合根唯一」重定义成「零直写」,与 §1.3 是两套口径。修法二选一:改规范成文「组合根家族=main.gd+三拆件控制器(组合根构造注入、禁视图层直连)」;或推进/购买调用经回调收口回 main 执行。顺带:§1.3 例举的 `submit_window_selection` 符号在 presentation 已不存在(现行面经 settle_batch/player_request_refresh 承载),例举已过时。 + +**C5. 明细行类型封闭枚举漂移**:编排器头注列 9 类(`game/core/battle_orchestrator.gd:15-19`),core 侧实际发射 13 类(grep 实证多出 `fx_reveal`/`mine_neutralized`/`insurance_used`/`fx_preview_area` 四类),架构文档 B1→D1 行又写 15 类——三处三个数。头注自称「清单改动须同步 battle_log_view 的 _format_row 与本头注」的同步义务已失效。 + +### 行为缺陷(4 件+1 件半 Critical) + +**C6. `game/core/damage_controller.gd:215` 用 `==` 比较单位字典**——Godot 4 的 Dictionary `==` 是逐键内容比较而非引用比较。两个内容全同的敌人(同种同拍生成、同待发技能、同池状态),其一死亡会经 `_on_unit_died` 误作废对方的排队单据(「死亡即不动手」误伤存活敌)。修法:`is_same(t.source_unit, u)`。该路径无测试覆盖同名敌作废面。 + +**C7. standee 蓄力意图动画档永不触发(常量错配死代码)**:`game/presentation/views/standee_body.gd:172` `set_pending` 落 `UiKit.GOLD_INK`(116,80,11),`:188` `_play_intent_motion` 判 `UiKit.GOLD_DEEP`(176,122,20)——③「蓄力缓推+定格微顿+回落」分支恒不可达,三档运动签名互异的设计失效;`game/presentation/views/ui_kit.gd:28` 注释「GOLD_DEEP 语义岗在役不动」已随换墨漂移成错误陈述。修法:判档不靠颜色相等(本身脆弱),set_pending 落 `_intent_charge` 布尔按其分档;修后补「charge 意图触发蓄力档」断言(现测试面未覆盖此档)。 + +**C8. `game/presentation/views/battle_end_overlay.gd:281-287` 庆祝浮动 tween 无限叠加泄漏**:`set_loops()` 无限循环 tween,`close()` 只隐藏不 kill——每次胜利 open 都新增一个永不停止的 tween,多 tween 争夺同一 position 目标值产生视觉抖动且随局数无限累积。全库其余 tween 均有先 kill 惯例(board_view:362-364 先例),此件唯一漏网。修法:存 tween 句柄,close() 与 open_victory 开头 kill。 + +**C9. 批量模拟与两层调试互斥未闭合**:`game/presentation/views/debug_overlay.gd:84`(调试钮不看 `_sim_running`)+`game/presentation/main.gd:712-715`(`_start_debug_levels` 守卫漏模拟运行态,且 :717 reset_sliders 会作废在跑测量的滑条读数)+`game/presentation/main.gd:1489`(`_on_tune_simulate` 守卫漏 `is_adventure`)+`game/presentation/tune_sim_controller.gd:46-58`(逐帧整关同步跑、与在跑战斗并存=帧时长尖峰扭曲 RowPacer 排播与 Tween 演出)。已核实缓解面:autoplay 自建局部 RngService(`game/sim/level_autoplay.gd:44`),无全局 RNG 竞态。修法:调试钮 disabled 并入 `_sim_running`;两守卫互查运行态(TuneSimController 补 `is_running()`);后者补 `or run_scope.is_adventure`。 + +**C10(半). `game/presentation/modal_stack.gd:23-29` 对未登记层与重复开层静默降级**:`_list.find(m)` 为 -1 时 range(0,size) 会隐藏全部已开层后显示未登记层;同层重复 open 时 `_occluded[m]` 被空表覆盖,原被隐藏层永久卡隐。当前调用面无违规者(badge 置灰+is_open 检查守住),属埋雷,但「层必须先 register 方可 open/close」只写在头注、未机器强制——违 fail-fast 原则 5。修法:open() 首行 find<0 即 push_error 且 return;同层已 visible 幂等直返;close() 对未登记层同样 push_error。 + +### 已核实的其余缺陷定点(写卡面) + +- `game/core/minesweeper_rules.gd:8-9` 两条核心信号(cell_revealed/seal_judged)零契约成文,违 code-conventions §2.1;同类已成文的(round_end_board 等)用的是 `#` 而非规范要求的 `##`(不进编辑器 F1 帮助)——全库信号注释载体普遍 `#`。 +- `game/core/level_runner.gd:895`(relic 基价 15.0)与 `:779`(散折 0.8)是玩法数值字面量,各自注明 provisional/待追认——仍违数值单一事实源红线,应入表。 +- `game/presentation/views/battle_stage_view.gd:332-338` 以 display_name 子串匹配解析受击站桩(`_card_by_name` 的 contains)——同名敌人或名字互为前缀会错配,弹道/闪白/击杀打到错误立绘。修法:结算行携带 enemy_id 或槽位 index 按键解析。 +- `game/core/treasure_items.gd:56-65` 孤儿注释指向已删函数(三段「持有数/持有件记录/丢弃」描述的函数连空壳都不在)。 +- `game/core/board_generator.gd:97/334` 目标雷数公式两处手抄;`:281` legality 的 db 参数未用。 +- `game/core/action_economy.gd:191-192` 蓄力层上限 3 硬编码两处字面量。 +- `game/core/unit_container.gd:55` 英雄名「探险者」硬编码绕开 HeroTable(敌人名走 row.display_name)。 +- §4.2 Dictionary 取值 Variant 裸算术漏包 int():`game/core/unit_container.gd:257/270`、`game/core/status_container.gd:58-61/102/114`。 +- `game/presentation/views/settlement_fx_view.gd:94-95` await process_frame 后无 is_instance_valid 守卫(与全库守卫惯例不一致)。 +- `game/presentation/views/board_view.gd:998` `lumas_out` 参数缺类型且无豁免注记(S9 R3 面存量)。 + +--- + +## 三、Improvements——结构与可维护性 + +### 大文件职责评估(均超 ~400 行审视线) + +| 文件 | 行数 | 判读 | +|---|---|---| +| `game/presentation/main.gd` | 1508 | 拆件真实发生(13+ 控制器/装配器),但数据投影族(L1059-1205,~135 行)、只读解析回调(L755-798)、文案拼装三件可判离合计 ~440 行;拆后回 ~1070 行。已超架构文档自记的 1100 行上帝对象反面案例 | +| `game/core/battle_orchestrator.gd` | 1301 | 段类拆出后仍持同调管理(~150 行)、变异布置算法(L516-574)、授予路由族(~200 行)、双快照面。「B1 退为段序编排+接线」文档目标只兑现一半 | +| `game/presentation/views/board_view.gd` | 1219 | 至少五职责混装(格面渲染/输入翻译/英雄动画/瓦片算法/探针面);最划算两刀:瓦片静态算法+哈希查表(~230 行无状态,拆 TilePalette 静态装配器)+英雄精灵状态机(~110 行) | +| `game/core/adventure_runner.gd` | 1049 | 令牌池子系统(构建/抽签/cap/凭证,~500 行)自成一体可拆 CurioDeck 类;**断点 schema 三处重复登记**(_snapshot_breakpoint 写/resume_adventure 读/save 默认值),每加一字段改三处,散弹式修改热点 | +| `game/core/level_runner.gd` | 1012 | 商店子系统(legacy+pool 双模式,~260 行)可拆;pool_price 字面量见上节 | +| 其余超线件 | 612-848 | ui_kit.gd 848 行属 §1.2 明文允许的静态装配器宿主(内聚成立);level_map_screen 612/camp_overlay_view 555/standee_body 491/save_manager 698/damage_controller 628/meta_progression 563/node_map_generator 539 各有内聚理由,未见上帝对象 | + +### 结算五段模式的形态说明(设计观察,非违约) + +段类是「宿主引用+直访宿主私有成员」的拆函数形态——`game/core/settlement/grant_segment.gd` 对 `oc._facts_reveals`/`oc._fx_bonus_delta`/`oc._defer_board_damage` 等私有成员访问达数十处。架构文档「段类可直接 new() 单测」技术上成立(settle_segments_test 在役),但段不是独立单元而是编排器的显式分部;这是有意权衡(零行为变更契约、行发射/开单单点归编排器),文档与代码一致,呈报确认即可。附带小件:`battle_orchestrator.gd:314-321`「遭遇骰」注释整段重复两遍;hp_ratio 公式三处手抄(grant_segment:91/145、orchestrator:188);`_place_variants`(L516-574,region 布置算法)住编排器,生成期逻辑归 A1/A4 域更顺——是否搬迁留重构批裁决。 + +### 文档-实现漂移清单(走文档轨对齐批) + +1. 架构文档「模块归属」多行 API 清单与实现不符:A2 行 try_dig/try_flag_place/try_flag_pull/try_move 不存在;A3 行 request_flag_place/request_flag_pull 不存在(实为 try_spend 通道),实有 grant_reserve_ap/finish_round_stop 未登记(:226 注释自称「第 9 API 接口漂移预授权」——registry 有授权、架构文档没跟);B2 行 ambush_grant_plan 不存在、实有 check_skill_unlocks 未登记;B4 行 equivalence_supply 不存在;damage_controller 与 settlement/ 五段类在归属表零条目。 +2. 架构文档 :149/151 层合同计数写死「17 项」,main.gd LAYER_CONTRACT 实为 18 项(文档明令「清单不复制」却把计数写死——双写失同步变体)。 +3. 明细行协议三处三个数(见 C5)。 +4. code-conventions §1.3 例举 submit_window_selection 已退役(见 C4)。 +5. `game/core/effect_engine.gd:360` 校验报错文案「事实词汇封闭 9 项」实为 18 项。 +6. A3/B4 消费 EffectEngine 未登记(见 C3)。 + +### 其余小件 + +- `game/presentation/main.gd:1215` `_sync_status_entry` 死变量 battle_live+四句重复(注释自认);:1194/498/507 confirm_dialog 旁路 `_open_modal/_close_modal` 单口(违 main.gd 自身头注 L4),confirm_dialog.gd:40-41「树序由构建序保证」注释已失真。 +- `game/presentation/views/level_map_screen.gd:326-353` 视图直读 LevelRunner 拼文案(§1.3 唯一越界者——「读核心状态→拼展示文案应集中装配器」);:362-387/520-529 每次鼠标移动全图 BFS 重算+O(V×E) 线性扫(当前图规模无实感影响);:502/507/515 绘制循环内重复取主题字体。 +- `game/presentation/main.gd:1276/1303` settle_batch 前置空判隐式依赖 `_input_locked` 锁谓词第三例外——入口显式 null 防护零成本双保险。 +- `game/presentation/row_pacer.gd:11` 待播队列住 main 级常驻节点(架构 L145「局态一律住 RunScope」),会话更替零残留靠时序约定兜底——`_begin_session` 内 flush 一行变机制保证。 +- core 域 `_fatal` 的 `assert(false)` 在 release 模板剥离后退化为软回退(orchestrator 有 battle_result 封印兜底、`game/core/board_generator.gd:391-393` 与 `game/core/reward_economy.gd:366-368` 无)——出包前需换真中止(可经宿主注入 fatal 回调)。 +- `game/core/rng_service.gd` open_stream 未知标签 push_error 后未 early-return(release 剥 assert 后静默继续发号)——补 return 即闭合。 + +--- + +## 四、Positive——做得好的,应当保持 + +- **分层纪律全兑现**:core 全域 RefCounted/Node 零 Control/场景引用、零 await、headless 可跑;views 零核心写调用、信号单向外发、接线集中在 main.gd 一处;A2/B3/B4 零相互直调(grep 实证)。 +- **RngService 是全库最好的设计**:单一 master_seed+派生混淆(splitmix64 finalizer 抗窄种子窗)+全局计数器快照契约+封闭用途词表+事件日志+pure_stream 纯函数面(结构生成与号位解耦)——断点续玩「从断点号位精确续接原时间线」由此成立。 +- **EffectEngine 无状态化干净**:四词表封闭+加载期校验+计数器四桶全经 EffectContext 引用束由宿主持有,dispatch 内 round_start 整桶就地 clear 而非重赋值断引用——架构原则 8 的教科书式落地。 +- **DamageMath 零状态纯算术+DamageController 单据管线**(双结账政策开关、A/B 模式同管线)——「何时开单归编排、怎么算归控制器」切分清晰,伤害序(主角先手→逐敌还手→地图账殿后)有显式承载。 +- **save_manager 工程质量高**:tmp+rename 原子写、v1→v7 迁移链自注册、损坏兜底改名留痕、高版本拒读禁写、三态回滚的槽激活原语、值拷贝进出户纪律(注:_rename_overwrite 先删后改在 Windows 上有极小的双失窗,已注释自知,出包前可换引擎级原子替换)。 +- **LAYER_CONTRACT 层序单口、RunScope 会话生命周期、ModalFlow 纯逻辑可单测**——呈现层装配是全库最成熟的部分;run_scope 23 行纯状态与架构文档逐句一致。 +- **views 层工程惯例全面铺开**:_process 早退守卫、tween 先 kill 后建、is_instance_valid 守卫、探针只读快照模式(duplicate 防外泄)、无深节点路径(全代码构建 UI)。 +- **schema 类模式统一**:Resource+@export 带值域注释+validate() 错误数组,19 个 schema 零例外。 + +--- + +## 五、结论与后续 + +架构设计本身没有需要推翻的东西,模式选型与领域匹配;当前债务集中在三步可收敛:**闸机补洞(S9 正则修复+S6/S7/S8 落地)→ 规范对齐(§1.3/模块归属/行类型词表一次对齐批)→ 行为缺陷定点修(C6-C10+定点清单)**。已按四条登记待办清单:game 行为缺陷与结构重构候选(工程直入·待写卡)/S9 正则修复(工程直入·待写卡)/S6/S7/S8 落地(工程直入·待写卡)/架构与规范对齐批(文档轨·待文档设计)。结构重构候选(§三 大文件表)非缺陷,是否立项由写卡段呈报用户裁决。 diff --git a/待办清单.md b/待办清单.md index a8442b5f..f486eda2 100644 --- a/待办清单.md +++ b/待办清单.md @@ -2,6 +2,40 @@ 本清单是流水线的唯一登记处:要做的事先在此登记一条,随流水线段推进改状态,做完整条删除;各系统文档的「待办」节只留一行指路存根,不再自建条目。条目格式(标题=登记元数据,正文=现状/缺口/归属/状态四属性)与状态机以 [doc-conventions §12.1](design/engineering/doc-conventions.md) 为权威。 +#### game 代码结构审查批——行为缺陷定点修+结构重构候选(2026-10-24 登记,来源=审计发现,设计面=工程直入) + +**现状**:审计报告=reports/审计-game代码结构审查-2026-10-24.md(2026-10-24,全目录只读审查,零测试执行、结论全部静态阅读)。缺陷证据(报告 §二 Critical 行为缺陷段+定点清单,含行号)九件:①core/damage_controller.gd:215 用 `==` 比较单位字典(Godot 4 语义=逐键内容比较)——内容全同双敌其一死亡误作废对方单据,应 `is_same()`;②presentation/views/standee_body.gd:172/188 蓄力意图档常量错配(GOLD_INK vs GOLD_DEEP)死代码,三档运动签名设计失效且无测试覆盖;③presentation/views/battle_end_overlay.gd:281-287 庆祝 tween set_loops 无限叠加泄漏(close 只隐藏不 kill);④批量模拟×两层调试并发互斥缺口(presentation/views/debug_overlay.gd:84+presentation/main.gd:712-715/1489+presentation/tune_sim_controller.gd:46-58——用户两击可并触发,演出扭曲+测量作废);⑤presentation/modal_stack.gd:23-29 未登记层/重复开层静默降级(违 fail-fast,当前调用面无违规者属埋雷);⑥core/minesweeper_rules.gd:8-9 两条核心信号零契约成文(违 code-conventions §2.1)+全库信号注释载体普遍 `#` 非 `##`;⑦明细行类型封闭枚举漂移(core 实发 13 类 vs battle_orchestrator.gd 头注 9 类);⑧core/level_runner.gd:895/779 玩法数值字面量(relic 基价 15.0、散折 0.8,自注 provisional);⑨presentation/views/battle_stage_view.gd:332-338 以 display_name 子串匹配解析受击目标(同名敌错位,应携带 enemy_id)。另有定点小件与结构重构候选(报告 §三):main.gd 1508 行可判离块 ~440 行/board_view.gd 1219 行瓦片算法+英雄精灵可拆/adventure_runner 令牌池子系统 ~500 行可拆 CurioDeck/level_runner 商店子系统 ~260 行可拆/断点 schema 三处重复登记可单点化——重构候选非缺陷,是否立项由写卡段呈报用户裁决。 + +**归属**:game/ 呈现层与 core 域(缺陷定点修,迭代批);结构重构候选另立批次由用户裁决。切卡输入=审计报告 §二/§三 + +**状态**:待写卡 + +#### S9 类型闸正则失灵修复——R2 恒零命中+static 函数漏网(2026-10-24 登记,来源=审计发现,设计面=工程直入) + +**现状**:工程债证据=reports/审计-game代码结构审查-2026-10-24.md §二 C1(已独立复现):tools/audit_type_hints.py:29 的 FUNC_DECL 正则两洞——①无返回类型声明按 GDScript 语法必然以 `:` 结尾,正则要求 `)` 后只跟 `->`/注释/行尾,R2 目标形态 100% 失配(R2 从上线起恒零命中恒绿);②`^(\s*)func` 不认 `static ` 前缀,static 函数对 R2/R3 整体漏网。实证存量(闸当前退出码 0):core/level_runner.gd:632、core/attunement.gd:10、presentation/main.gd:565、presentation/views/hud_presenter.gd:10-11、core/reward_economy.gd:104/119/131/146、core/unit_container.gd:275。属架构文档测试域自警的「规则扫描面为空=恒绿」静默失效模式(零命中自检因 R1/R3 仍有命中能力未拦住)。 + +**归属**:tools/ 静态扫描域(闸件批,非迭代批——gdstyle 条目同款执行形态:正则修后先跑出存量红、补注解或 `# type-hint: ignore` 归零、闸改动配变异验证) + +**状态**:待写卡 + +#### S6/S7/S8 静态规则落地——编排唯一性/禁 await/信号纪律三闸(2026-10-24 登记,来源=审计发现,设计面=工程直入) + +**现状**:工程债证据=reports/审计-game代码结构审查-2026-10-24.md §二 C2:三规则 static_scan.sh TODO 在案(架构文档静态扫描表自认未落地)——S6 core↔core 信号禁 lambda 捕获 self、S7 B2/B3/B4 API 符号命中文件 ⊆ B1 文件集、S8 结算路径 await 零命中。2026-10-24 审查人工 grep 结论干净(core 零 await、A2/B3/B4 零相互直调),但防线缺位=回归无闸。S7 前置:须先在架构文档成文 B1 文件集边界(含 core/settlement/ 五段类与 damage_controller——现归属表零条目,见「架构与规范对齐批」条目①)。 + +**归属**:tools/ 静态扫描域(非迭代批);S7 依赖「架构与规范对齐批」先裁 B1 文件集 + +**状态**:待写卡 + +#### 架构与规范对齐批——代码结构审查发现的文档-实现漂移(2026-10-24 登记,来源=审计发现,设计面=文档轨) + +**现状**:审计报告=reports/审计-game代码结构审查-2026-10-24.md(§二 C3/C4/C5+§三 漂移清单)。漂移与待裁件七件:①架构文档「模块归属」多行 API 清单与实现不符(A2 try_* 便捷形/B2 ambush_grant_plan/B4 equivalence_supply 不存在;实有 grant_reserve_ap/finish_round_stop/check_skill_unlocks 未登记;damage_controller 与 settlement/ 五段类零条目——S7 落地的前置);②code-conventions §1.3 核心写调用位置——三拆件控制器(presentation/curio_interact_controller.gd、camp_shop_presenter.gd、treasure_interact_controller.gd)持写调用 vs 规范「只允许在组合根出现」的 spec-AC 冲突,须裁「改规范成文组合根家族」vs「调用收回 main」;③A3→EffectEngine 反向依赖(core/action_economy.gd:43-49)——真违约或事实源失真二选一(effect_engine 降层登记基础层 vs B1 代发 vs 仅补登记);④架构文档 :149/151 层合同计数写死 17 项 vs LAYER_CONTRACT 实 18 项;⑤明细行协议三处三个数(头注 9/实发 13/架构文档 15);⑥§1.3 例举 submit_window_selection 符号已退役;⑦core/effect_engine.gd:360 校验文案「9 项」实为 18 项。 + +**缺口**:一次 doc-design 会话逐点裁决(②③有方案取舍须用户拍板,①④⑤⑥⑦为机械对齐);裁决后走非迭代批落文 design/engineering/。 + +**归属**:design/engineering/(architecture.md「模块归属」节+「呈现层装配」节、code-conventions §1.3) + +**状态**:待文档设计 + #### gdstyle 引入——GDScript 第三方 linter 接入检查面(2026-10-24 登记,来源=会话提及,设计面=工程直入) **现状**:工程债证据=2026-10-24 会话实测三件:①本机已装 gdtoolkit 4.5.0(gdlint/gdparse,PyPI 最新即此版)对 3 个在役文件解析假红(presentation/curio_interact_controller.gd、tests/system_test.gd、probe/ui_click_probe.gd——不认 Godot 4.7 新语法,Godot 自家解析器对三者全过);②候选 gdstyle v0.4.0(github.com/atelico/gdstyle,Rust 单二进制)对上述 3 文件全过、全工程 194 个 .gd 仅 1 处解析误报(core/rng_service.gd 头部 INT64_MIN 负字面量,Godot 特判放行,单条可豁免);③gdck v0.8.0 同测 3 文件挂 2,出局。价值面=质量类规则(duplicated-load/await-in-loop/allocation-in-loop)是自建 grep 闸查不到的补充信号;格式类规则与 S9/S10 重叠、应全关。用户 2026-10-24 立项引入。