修卡(模态句柄分域批·godot-master终审折入): v1.0→v1.1——阻断两处(①T1期望串漏modals.段:ui.menu.debug_overlay→ui.modals.menu.debug_overlay,R6同改;②T0验证①grep排程不可满足:收窄game/presentation当步域,全仓零残留grep移T1新增验证④)+建议六处(node()24键与平铺区间剔76行/§8补ui_camp_modals头注两句随批/flow枚举补:123:251/营地混行概括句口径/architecture行号换代v1.30现行:169:170:201/正检grep拆三条各限include); 审裁决=修毕可直接开工; grilling四轮在案零待裁点

This commit is contained in:
DKChan committed 2026-11-02 04:53:35 +08:00
1 parent 4b5e311d1d
commit 881f96f56b
1 file changed
+11 -9
@@ -1,6 +1,6 @@
# 需求卡片——模态句柄分域批
> v1.0 · 2026-11-02 · 零待裁点(开工门=U0)
> v1.1 · 2026-11-02 · 零待裁点(开工门=U0)· godot-master 终审折入(阻断两处+建议六处,裁决=修毕可直接开工;grilling 四轮在案)
> 来源=待办清单条目「[模态句柄册分域重构](../待办清单.md)(2026-11-01 登记,来源=会话提及)」,状态已到「待写卡」
> 批性质=重构类需求性工程条目(行为零变化、纯句柄搬家);改动面=游戏代码
@@ -25,7 +25,7 @@
1. **在册条目**:`待办清单.md`「模态句柄册分域重构(2026-11-01 登记,来源=会话提及)」,状态段「待写卡」,改动面=游戏代码;目标形态已在条目实况定稿(按域分组抽容器+ModalFlow 升格独立持有+行为零变化)。
2. **代码证据(2026-11-02 实测复核)**:`game/presentation/ui_modals.gd:7-20`——类变量 14(`flow`+12 平铺句柄+`camp` 子容器),与条目所记一致;迭代 47 卡⑥后营地域六句柄已迁 `game/presentation/ui_camp_modals.gd:4-12`,平铺面余 12 件。
3. **工程债事件沿革**:迭代 47 卡④⑤平铺句柄合计 19 越过 S13 类变量上限 15(停机呈报件已按「吸收即死」退役,`reports/` 现无此件;事件沿革见待办条目实况与 git 提交 a5c89d67)。阈值顶格只作发现信号,本卡的拆分动机是域归组(见 §5 契约 3)。
4. **拆分判据权威**:`design/engineering/code-conventions.md` §1.1 拆分判据;容器先例=`ui_camp_modals.gd`(迭代 47 卡⑥);注册面归属=`design/engineering/architecture/architecture.md:168`(ui_registry 行,v1.28)。
4. **拆分判据权威**:`design/engineering/code-conventions.md` §1.1 拆分判据;容器先例=`ui_camp_modals.gd`(迭代 47 卡⑥);注册面归属=`design/engineering/architecture/architecture.md:169`(ui_registry 行,v1.30 现行——行号随文档换代漂移,T2 反哺落文以内容锚为准)。
## 3. 现状事实(代码级实测,2026-11-02)
@@ -35,12 +35,12 @@
| 2 | 模态登记唯一口 `register_layer` 在 `UiModals`(锚预设撑满+`flow.register`) | `ui_modals.gd:28-33` |
| 3 | 营地域子容器先例:`UiCampModals` 纯字段六句柄;头注带「禁平铺回 ui_modals」分域纪律 | `ui_camp_modals.gd:1-12` |
| 4 | 注册面持三域容器(screens/battle/modals),`_init` 逐只构造 | `ui_registry.gd:42-50` |
| 5 | `node()` 合同寻址 22 键:12 平铺键直指 `modals.<名>`,营地六键两段式 `modals.camp.*` | `ui_registry.gd:54-80`(平铺 59-64,72-78;营地 66-71) |
| 5 | `node()` 合同寻址 24 键:12 平铺键直指 `modals.<名>`,营地六键两段式 `modals.camp.*`,另 6 键 screens/node/flow 域 | `ui_registry.gd:54-80`(平铺 59-64,72-75,77-78;营地 66-71) |
| 6 | `apply_layer_contract` 三处调 `modals.register_layer`;`LAYER_CONTRACT` 合同表 24 项(含 tags/host/shell 特例) | `ui_registry.gd:15-40,86-111`(调用点 97/106/111) |
| 7 | `ModalFlow` 纯逻辑类:依赖仅 ModalStack+查询 Callable,零节点构建零信号连接;类本体与本批无关 | `modal_flow.gd:1-15` |
| 8 | 装配面寻址:12 平铺句柄命中 50 行+`flow` 注入 14 行(Callable 注入段与 early 取 `flow.pump_ended`);营地二段式 28 行不动 | `main_ui_build.gd:49,60,89-92,99-158,168-174,189-218,232-253,269-286` |
| 9 | 组合根与四拆件寻址(命中行含注释):main 27;四拆件 38/43/13/8 | `main.gd:94,107-765`;`main_adventure_flow.gd`/`main_overlay_flow.gd`/`main_debug_flow.gd`/`main_esc_flow.gd` |
| 10 | 全仓 `modals.` 寻址 25 文件 595 行:营地二段式 116 行(本批不动);`flow` 87 行;12 平铺句柄 442 行(两者去重唯一行 482) | 复核命令与分文件计数表见 §8 结构图注(口径=`grep -c` 命中行数,含注释行) |
| 10 | 全仓 `modals.` 寻址 25 文件 595 行:营地二段式 116 行(约 10 混行含 flow/flat 旧形随换代、camp 部分不动);`flow` 87 行;12 平铺句柄 442 行(两者去重唯一行 482) | 复核命令与分文件计数表见 §8 结构图注(口径=`grep -c` 命中行数,含注释行) |
| 11 | 测试与探针消费面 15 件:探针 11+系统测试+冒烟 2 行+单元 2 行;registry 合同断言段钉登记册序 | `ui_struct_probe.gd:562-580,584-606`;`system_test.gd:108-122,316,384-387,491`;`smoke_boot.gd:74-75`;`pacing_queue_test.gd:61`;`theme_projection_test.gd:719` |
| 12 | S13 类变量默认上限 15;基线文件 12 行无本批触碰文件键(14 与 3 均未越限) | `tools/gdstyle.toml`(阈值取默认);`tools/gdstyle_baseline.txt:1-12` |
@@ -105,7 +105,7 @@ main.ui(UiRegistry,类变量 3→4)
| 文档 | 关联点(本批实现会改变它的哪条陈述) | 同步义务 |
|---|---|---|
| design/engineering/architecture/architecture.md | :168 ui_registry 行——「三域句柄容器…+ModalFlow」「四件类变量 3/9/5/14,ModalFlow 随 UiModals 容器构造即建」→ 换代为三域容器+两新子容器+flow 直驻注册面+类变量实数(UiRegistry 3→4、UiModals 14→3);:169 UiCampModals 行——「ui_modals 平铺面收窄」可现状化为平铺面清零;:200——「ModalFlow 实例随 UiModals 容器构造建立」→ 随 UiRegistry 构造建立 | 列反哺点清单由文档批落文(实现批禁写 design/) |
| design/engineering/architecture/architecture.md | :169 ui_registry 行(v1.30 现行行号)——「三域句柄容器…+ModalFlow」「四件类变量 3/9/5/14,ModalFlow 随 UiModals 容器构造即建」→ 换代为三域容器+两新子容器+flow 直驻注册面+类变量实数(UiRegistry 3→4、UiModals 14→3);:170 UiCampModals 行——「ui_modals 平铺面收窄」可现状化为平铺面清零;:201——「ModalFlow 实例随 UiModals 容器构造建立」→ 随 UiRegistry 构造建立 | 列反哺点清单由文档批落文(实现批禁写 design/) |
| game/tests/README.md | 能力行两处:存量行「Esc 浮窗唤起与三出口动线」真实入口字面 `ui.modals.flow.open/close`→`ui.flow.open/close`;新增「模态句柄分域寻址面」行+覆盖域表 HUD框架 行随补 | 写卡段同批落位(本卡随批写入,非实现批义务) |
| design/gdd/术语表.md | 无新术语——「分域」「子容器」「注册面」均为仓库既有说法 | 无关联文档 |
@@ -119,6 +119,7 @@ main.ui(UiRegistry,类变量 3→4)
| game/presentation/ui_registry.gd | 修改 | 注册面增持 `flow` 编排件与 `register_layer` 登记口;`node()` 十二键换代两段式 | 行为改动→对照表 R3/R5 |
| game/presentation/main_ui_build.gd | 修改 | 装配面寻址换代(句柄赋值/接线两段式 50 行;`flow` 取 `ui.flow` 14 行);装配序零变化 | 行为改动→对照表 R4 |
| game/presentation/main.gd | 修改 | 组合根寻址换代(27 行,含头注) | 行为改动→对照表 R4 |
| game/presentation/ui_camp_modals.gd | 修改 | 头注两句随 flow 升格失真等长改写(:2「与 flow 同拍」句——flow 改由 UiRegistry._init 建;:3「全量分家另立批」句——本批即分家) | 非行为改动(注释漂移随批消化)——由 R3 覆盖 |
| game/presentation/main_adventure_flow.gd / main_overlay_flow.gd / main_esc_flow.gd / main_debug_flow.gd | 修改 | 四拆件寻址换代(38/43/8/13 行) | 行为改动→对照表 R4 |
| game/tests/smoke_boot.gd | 修改 | 装配检查两行寻址换代 | 非行为改动(测试面同步)——由 R4 覆盖 |
| game/tests/system_test.gd / unit/presentation/pacing_queue_test.gd / unit/presentation/theme_projection_test.gd | 修改 | 测试面寻址换代;theme_projection 源码字面断言期望串换代(判据语义不变) | 非行为改动(测试面同步)——由 R4 覆盖,字面换代申报见 §10 |
@@ -139,11 +140,11 @@ main.ui(UiRegistry,类变量 3→4)
- [ ] 新建 `game/presentation/ui_menu_modals.gd`:`class_name UiMenuModals extends RefCounted`,纯字段六枚全类型标注 `var shop_overlay: ShopOverlay`/`var settings_overlay: SettingsOverlay`/`var career_overlay: CareerOverlay`/`var save_select_overlay: SaveSelectOverlay`/`var confirm_dialog: ConfirmDialog`/`var debug_overlay: DebugOverlay`;头注=职责语句(菜单与跨语境域六句柄唯一容器)
- [ ] 改 `game/presentation/ui_modals.gd`:删 `flow` 与 12 平铺句柄成员,增 `var run: UiRunModals`/`var menu: UiMenuModals`(`camp` 保留);`_init` 改建 run/menu/camp 三容器;`register_layer` 函数体(含锚预设纪律注释)迁出;头注换代为纯字段容器+三子容器+分域纪律全册化句
- [ ] 改 `game/presentation/ui_registry.gd`:增 `var flow: ModalFlow`,`_init` 增建(构造时点与今等价——注册面先于装配);`register_layer` 自 `ui_modals.gd:28-33` 逐字迁入(含注释);`apply_layer_contract` 三处 `modals.register_layer` 改直调;`node()` 十二平铺键换代 `modals.run.*`/`modals.menu.*`(营地六键不动);头注「三域容器」句换代
- [ ] 改 `game/presentation/main_ui_build.gd`:句柄赋值与接线换代两段式(计数表 flat=50);`flow` 注入与取用改 `root.ui.flow.*`(flow=14::60、:168-169、:201、:269-286);:273 注释「实例随 ui.modals 容器构造建立」句随迁
- [ ] 改 `game/presentation/main_ui_build.gd`:句柄赋值与接线换代两段式(计数表 flat=50);`flow` 注入与取用改 `root.ui.flow.*`(flow=14::60、:123、:168-169、:201、:251、:269-286);:273 注释「实例随 ui.modals 容器构造建立」句随迁
- [ ] 改 `game/presentation/main.gd`:寻址换代(计数表 flat 17+flow 10,含 :4 头注「模态开合只走 ui.modals.flow」句改 `ui.flow`);:46 持有面注释核对(注册面单点宿主句仍成立,不改)
- [ ] 改四拆件 `main_adventure_flow.gd`/`main_overlay_flow.gd`/`main_esc_flow.gd`/`main_debug_flow.gd`:寻址换代 38/43/8/13 行(flat+flow 合计,逐件 grep 该文件旧形零命中)
- [ ] 改 `game/tests/smoke_boot.gd:74-75`:`modals.legend_overlay`→`modals.run.legend_overlay`;`modals.status_panel`→`modals.run.status_panel`
- [ ] 验证①(旧形零残留):`grep -rnE "modals\.flow|modals\.(legend_overlay|node_overlay|level_screen|curio_overlay|end_overlay|shop_overlay|settings_overlay|status_panel|career_overlay|save_select_overlay|confirm_dialog|debug_overlay)" --include="*.gd" game` =零命中;正检三形在用:`grep -rc "modals\.run\.\|modals\.menu\.\|ui\.flow\."` 各 >0
- [ ] 验证①(产品码旧形零残留——当步换代域):`grep -rnE "modals\.flow|modals\.(legend_overlay|node_overlay|level_screen|curio_overlay|end_overlay|shop_overlay|settings_overlay|status_panel|career_overlay|save_select_overlay|confirm_dialog|debug_overlay)" --include="*.gd" game/presentation` =零命中;正检三形各 >0:`grep -rc "modals\.run\." --include="*.gd" game/presentation`/`grep -rc "modals\.menu\." --include="*.gd" game/presentation`/`grep -rc "ui\.flow\." --include="*.gd" game/presentation`
- [ ] 验证②(真实开机路径):`python tools/run_smoke.py` PASS(真实装配走新寻址——闸 00 最窄确认)
- [ ] 验证③(静态纪律):`bash game/tests/static_scan.sh` 零 FAIL(S9 新件全类型标注;S13 无新键——预期 `ui_modals` 类变量 14→3、`ui_registry` 3→4 均在上限内不产键);跑闸前先 `--editor --quit` 刷类名缓存(新 class_name 生效前提);新件 `.uid` 边车随扫描生成、随批入库(存量 80 件 presentation `.uid` 均在 git,同法)
@@ -153,11 +154,12 @@ main.ui(UiRegistry,类变量 3→4)
- [ ] 探针 11 件机械改址(分文件计数表:fx_shot flat=3;layout flat=2;probe_ui_util flat=1;screen_flow flat=19 flow=0;shot flat=20;t17_defer flat=6 flow=1;ui_click flat=109 flow=14;ui_input flat=13 flow=4;ui_probe flat=12 flow=1;ui_struct flat=54 flow=2;ui_tune flat=32 flow=5)——判据零改动,只换代址字面
- [ ] `game/tests/system_test.gd` 改址(flat=20 flow=1::108-122 句柄清单数组、:316 `var mf = main.ui.flow`、:384-387、:491 终局弹起等);`pacing_queue_test.gd:61` 改址
- [ ] `game/tests/unit/presentation/theme_projection_test.gd` 改址+:719 源码字面断言期望串换代:`"ui.modals.debug_overlay.diagnose_requested.connect(_on_diagnose_pressed)"` → `"ui.menu.debug_overlay.diagnose_requested.connect(_on_diagnose_pressed)"`(判据语义不变——申报见 §10)
- [ ] `game/tests/unit/presentation/theme_projection_test.gd` 改址+:719 源码字面断言期望串换代:`"ui.modals.debug_overlay.diagnose_requested.connect(_on_diagnose_pressed)"` → `"ui.modals.menu.debug_overlay.diagnose_requested.connect(_on_diagnose_pressed)"`(判据语义不变——申报见 §10)
- [ ] `ui_struct_probe.gd` `_modal_registry_contract` 段尾增结构断言块,尾缀〔句柄分域批 V1〕,三条判据:**V1a 分域在座**——run 六件经 `main.ui.modals.run.<名>` 逐件非 null、menu 六件经 `main.ui.modals.menu.<名>` 逐件非 null(12 检);**V1b 平铺面清零**——`main.ui.modals.get(<旧平铺名>)` 12 件逐件为 null(旧寻址成员不存在);**V1c 编排口独立**——`main.ui.flow` 非 null 且 `main.ui.modals.get("flow")` 为 null
- [ ] 验证①(探针层):`godot --headless --path game res://probe/ui_struct_probe.tscn` 单跑零 problems(先孤立验证新断言);`bash tools/probe_gate.sh --full` 探针族绿
- [ ] 验证②(系统层):`python tools/run_system_test.py` PASS
- [ ] 验证③(单元层):工作目录 game/ 跑 `godot --headless --script tests/run_all.gd -- --only=presentation` 绿(开发期窄测形态,不产闸回执)
- [ ] 验证④(全仓旧形零残留——§1 完成定义 #3):`grep -rnE "modals\.flow|modals\.(legend_overlay|node_overlay|level_screen|curio_overlay|end_overlay|shop_overlay|settings_overlay|status_panel|career_overlay|save_select_overlay|confirm_dialog|debug_overlay)" --include="*.gd" game` =零命中(探针与测试面 T1 换代后的全仓口径)
- [ ] 里程碑步出口跑一次代码域闸(`bash tools/run_all_gates.sh --code`);波内修复只做出红最小单元的最窄确认
### T2 产出物落位卡
@@ -180,7 +182,7 @@ main.ui(UiRegistry,类变量 3→4)
| R3 | 平铺面清零+编排口升格独立持有+登记口迁驻 | `ui_modals.gd:7,23-33`(flow/register_layer 迁出);`ui_registry.gd:42-50`(增 flow+_init 建)、:28-33 迁入 register_layer | 同段 V1b 12 件 get() 逐件 null+V1c flow 在注册面且 modals 无 flow〔句柄分域批 V1〕;S13 静态判据(类变量 14→3 无新键,`bash game/tests/static_scan.sh`) | 探针+静态 | 同上 | 旧平铺成员缺位+`ui.flow` 在座(被测改动的特有提交面) | 新增:模态句柄分域寻址面 |
| R4 | 全仓寻址换代行为零变化 | 装配面 `main_ui_build.gd`(flat=50/flow=14)+`main.gd` 27 行+四拆件 102 行+`ui_registry.gd node()` 12 键;测试探针 15 件改址 | 既有断言群改址照跑(原判据):`system_test.gd` V3 终局面板弹起(:491)与模态锁段(:316 `locks_input` 矩阵);`ui_struct_probe.gd` node_overlay 开合段(:251-262);`screen_flow_probe.gd` Esc 三动线段;`ui_click_probe.gd` 各模态交互段;`ui_tune_probe.gd` 调试浮窗段;`smoke_boot.gd:74-75` 装配两检 | 探针+系统+冒烟 | 真实开机路径→真实输入/信号路径(模态经 `ui.flow.open/close` 开合) | 模态可见性与信号开合面(既有断言原样保留,见保留声明) | 既有:模态覆盖层编排与输入锁 |
| R5 | 登记册合同序不破 | `ui_registry.gd:86-111` apply_layer_contract 直调 register_layer;登记序/树序数据零改动 | `ui_struct_probe.gd:_modal_registry_contract` ①②③④段(登记册序==合同序逐位、树序邻接对、宿住/同槽特例)改址照跑〔装配生命批 V1〕 | 探针 | 同上 | 登记册栈序==LAYER_CONTRACT 序逐位 | 新增:模态句柄分域寻址面 |
| R6 | 诊断转储入口接线断言字面换代 | `theme_projection_test.gd:719` 期望串换代(`ui.modals.debug_overlay.`→`ui.menu.debug_overlay.`) | 该断言照跑绿(V6 段,`run_all` presentation 套件;由 R4 之系统与单元跑批同轮执行) | 单元 | 套件直跑(`tests/run_all.gd`) | 组合根接线源码字面(既有源码锚定断言形态) | 既有:模态覆盖层编排与输入锁 |
| R6 | 诊断转储入口接线断言字面换代 | `theme_projection_test.gd:719` 期望串换代(`ui.modals.debug_overlay.`→`ui.modals.menu.debug_overlay.`) | 该断言照跑绿(V6 段,`run_all` presentation 套件;由 R4 之系统与单元跑批同轮执行) | 单元 | 套件直跑(`tests/run_all.gd`) | 组合根接线源码字面(既有源码锚定断言形态) | 既有:模态覆盖层编排与输入锁 |
非行为改动覆盖注记:各文件头注/注释随址换代、README 能力行两处=非行为改动,其装配与开合后果由 R4 行断言从真实入口承载;R6 为测试侧字面换代(判据语义不变),单独列行申报。合同表零改动(红线 1)的判据为静态——`LAYER_CONTRACT` 表常量无运行期可观测面(登记册序断言以表为参照系,表随登记同动时不互证),由独立验收审计核对 diff 中该数据块零行变更(观测面局限申报,非撤销类取证)。