From e575de2344cce6bb26aba0eef51fd5d4c792c719 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Mon, 2 Nov 2026 01:47:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=99=E5=8D=A1(=E6=A8=A1=E6=80=81=E5=8F=A5?= =?UTF-8?q?=E6=9F=84=E5=88=86=E5=9F=9F=E6=89=B9=C2=B7=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BB=A4):=20=E9=9C=80=E6=B1=82=E5=8D=A1=E7=89=87v1.0=20?= =?UTF-8?q?=E9=9B=B6=E5=BE=85=E8=A3=81=E7=82=B9=E2=80=94=E2=80=9412?= =?UTF-8?q?=E5=B9=B3=E9=93=BA=E5=8F=A5=E6=9F=84=E5=88=86=E5=9F=9F=E6=8A=BD?= =?UTF-8?q?=E5=AE=B9=E5=99=A8(run/menu)+ModalFlow=E5=8D=87=E6=A0=BC?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E9=9D=A2=E7=9B=B4=E9=A9=BB+register=5Flayer?= =?UTF-8?q?=E9=9A=8F=E8=BF=81,=20=E8=A1=8C=E4=B8=BA=E9=9B=B6=E5=8F=98?= =?UTF-8?q?=E5=8C=96=E7=BA=AF=E5=8F=A5=E6=9F=84=E6=90=AC=E5=AE=B6,=20?= =?UTF-8?q?=E5=85=A8=E4=BB=93=E5=AF=BB=E5=9D=80=E6=8D=A2=E4=BB=A3=E9=9D=A2?= =?UTF-8?q?529=E8=A1=8C=E5=AE=9E=E6=B5=8B=E9=92=89file:line;=20T0-T2?= =?UTF-8?q?=E4=BC=B01.9=E5=B7=A5=E4=BD=9C=E6=97=A5;=20=E5=AF=B9=E7=85=A7?= =?UTF-8?q?=E8=A1=A8=E5=85=AD=E8=A1=8C=E4=B8=83=E6=A0=BC(=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=83=BD=E5=8A=9B=E8=A1=8C=3D=E6=A8=A1=E6=80=81?= =?UTF-8?q?=E5=8F=A5=E6=9F=84=E5=88=86=E5=9F=9F=E5=AF=BB=E5=9D=80=E9=9D=A2?= =?UTF-8?q?=E5=B7=B2=E5=85=A5README+=E8=A6=86=E7=9B=96=E5=9F=9F=E8=A1=A8HU?= =?UTF-8?q?D=E6=A1=86=E6=9E=B6=E8=A1=8C);=20grilling=E5=9B=9B=E8=BD=AE?= =?UTF-8?q?=E8=A3=81=E5=86=B3=E5=85=A8=E8=90=BD(.uid=E8=90=BD=E5=BA=93+?= =?UTF-8?q?=E5=90=88=E5=90=8C=E8=A1=A8=E9=9B=B6=E6=94=B9=E5=8A=A8=E9=9D=99?= =?UTF-8?q?=E6=80=81=E5=88=A4=E6=8D=AE=E7=94=B3=E6=8A=A5);=20pipeline=5Fga?= =?UTF-8?q?te=20PASS+capability=5Faudit=E9=9B=B6=E7=BA=A2;=20=E5=BE=85?= =?UTF-8?q?=E5=8A=9E=E6=9D=A1=E7=9B=AE=E6=8E=A8=E8=BF=9B=E5=B7=B2=E5=86=99?= =?UTF-8?q?=E5=8D=A1(=E5=8D=A1=E7=89=87=E8=B7=AF=E5=BE=84=E5=85=A5?= =?UTF-8?q?=E5=AE=9E=E5=86=B5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/tests/README.md | 5 +- reports/需求卡片-模态句柄分域批-2026-11-02.md | 253 ++++++++++++++++++ 待办清单.md | 4 +- 3 files changed, 258 insertions(+), 4 deletions(-) create mode 100644 reports/需求卡片-模态句柄分域批-2026-11-02.md diff --git a/game/tests/README.md b/game/tests/README.md index 6fef180b..cf7169d1 100644 --- a/game/tests/README.md +++ b/game/tests/README.md @@ -127,6 +127,7 @@ tests/ | 拒绝反馈分面可辨与未知兜底文案 | HUD框架 | `HudPresenter.outcome_text()` | `hud_presenter_test.gd:_test_reject_text_by_reason`;`hud_presenter_test.gd:_test_unknown_reason_fallback`;`hud_presenter_test.gd:_test_accepted_text` | | 结算明细带逐行呈现与排播节奏 | HUD框架 | `BattleLogView.append_row()`/`RowPacer.pace_delay_for()` | `theme_projection_test.gd:_smoke_battle_log_view`;`player_copy_sweep_test.gd:_sweep_source_names`;`pacing_queue_test.gd:_init` | | 模态覆盖层编排与输入锁 | HUD框架 | `ModalFlow.locks_input()`/`ModalFlow.open_after_playback()` | `modal_flow_test.gd:_init`;`reward_overlay_test.gd:_run` | +| 模态句柄分域寻址面 | HUD框架 | 局内/菜单/营地三子容器句柄经注册面合同寻址(`UiRegistry.node()` 逐键取层)+模态编排口开合(`ModalFlow.open()`/`ModalFlow.close()`) | `ui_struct_probe.gd:_modal_registry_contract`(registry 合同序段+分域句柄段)〔句柄分域批 V1〕 | | 未开格类型微光(8 邻作用集/五组色相/零玩法写入) | HUD框架 | `BoardView.type_glow_probe()`/`UiKit.glow_group_for_cell_type()` | `theme_projection_test.gd:_smoke_type_glow`;`type_glow_test.gd:_test_grouping_closed`;`type_glow_test.gd:_test_frozen_hue_face` | | 棋盘悬停反馈(三语义光标/目标格边框/路径预览点迹) | HUD框架 | `ui_input_probe` 合成鼠标事件→`BoardView._gui_input()`;读面 `BoardView.hover_probe()` | `ui_input_probe.gd:_ready`(case①到达②禁入③路径预览三语义) | | UI 全局主题与按钮五态(含对比度锚) | HUD框架 | `UiKit.button()`/`UiKit.primary_button()` | `theme_projection_test.gd:_smoke_global_theme`;`theme_projection_test.gd:_smoke_button_five_states`;`theme_projection_test.gd:_smoke_contrast_inks` | @@ -147,7 +148,7 @@ tests/ | 营地篝火回主菜单与笔记本改挂动线 | 营地交互流 | 笔记本命中区 → `CareerOverlay.open()`;篝火命中区 → ConfirmDialog 二次确认 → 主菜单 | `ui_struct_probe.gd:_ready`(career 段)〔营地图批 V5〕;`screen_flow_probe.gd:_ready`(篝火/开合段)〔营地图批 V7〕 | | 营地图鉴占位挂起态与反参照结构纪律 | 营地场景视图 | 布告板命中区 → `CampSceneView._gui_input()`(object_pressed 信号) → 图鉴占位视图;营地根态场景树审计 | `ui_struct_probe.gd:_ready`(占位禁词/禁行段)〔营地图批 V6〕;`ui_struct_probe.gd:_ready`(结构禁词段)〔营地图批 V9〕 | | 营地刷新单口与场景根 HUD 同步 | 营地刷新总线 | 写口尾 → `CampRefreshBus.refresh()` → 现开界面刷新+场景根 HUD 刷新 | `ui_struct_probe.gd:_ready`(顶栏位段)〔营地图批 V8〕;`ui_click_probe.gd:_ready`(写口尾刷新段) | -| Esc 浮窗唤起与三出口动线 | 营地 Esc 流 | 营地场景根态合成 Esc 键事件→ `main_esc_flow.on_esc_input()` → `ui.modals.flow.open/close`;浮窗三钮 `pressed` → 三出口 | `screen_flow_probe.gd:_ready`(Esc 唤起/子界面开态不唤起/再按关窗/非营地不唤起段)〔ESC批 V1〕;`screen_flow_probe.gd:_ready`(返回动线/设置双路径段)〔ESC批 V3/V4〕 | +| Esc 浮窗唤起与三出口动线 | 营地 Esc 流 | 营地场景根态合成 Esc 键事件→ `main_esc_flow.on_esc_input()` → `ui.flow.open/close`;浮窗三钮 `pressed` → 三出口 | `screen_flow_probe.gd:_ready`(Esc 唤起/子界面开态不唤起/再按关窗/非营地不唤起段)〔ESC批 V1〕;`screen_flow_probe.gd:_ready`(返回动线/设置双路径段)〔ESC批 V3/V4〕 | | 营地顶栏 HUD 钥石读数与刷新单口同步 | 营地 HUD 栏 | 隔离存档实例 `meta_state._add_keystone()`→ 显式触发 `CampRefreshBus.refresh(camp_data)` → `camp_hud_band.refresh()` → `keystone_badge` 读数 | `screen_flow_probe.gd:_ready`(HUD 余额读数/刷新段)〔ESC批 V6〕;`ui_struct_probe.gd:_ready`(顶栏位结构段) | **旅程段七:数据配置与跨系统契约** @@ -184,7 +185,7 @@ tests/ | 排雷循环 | 排雷玩法.md | 装板与开局免费展开(封锁格无资源、计入清图);挖/封印合法性与可辨拒绝(拒绝零副作用);封印不可逆与挖开封印格放行(兑付改判四情况) | 已覆盖 | — | | 排雷循环 | 棋盘生成.md | 棋盘按参数行出图、数字恒真;同参数同种子逐位复现、异种子不退化;可推理率与清图可达(合法性先于质量分)、重试有界、降级诚实 | 已覆盖 | — | | 排雷循环 | 行动经济.md | AP 扣费、末点耗尽即收轮与战斗收束清零;停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励);下轮行动点修正排队与兑现 | 已覆盖 | — | -| 表现与支撑 | HUD框架.md | 拒绝反馈分面可辨与未知兜底文案;结算明细带逐行呈现与排播节奏;模态覆盖层编排与输入锁;未开格类型微光(8 邻作用集/五组色相/零玩法写入);UI 全局主题与按钮五态(含对比度锚);中文字体随包与字形覆盖;地形瓦片套与格面数字可读;战斗叙述与终局文案(数值带入/胜负互异);玩家面文案与危险格格面字形;战斗屏三区几何与棋盘格边长(分辨率两档×四档板型);B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役) | 已覆盖 | — | +| 表现与支撑 | HUD框架.md | 拒绝反馈分面可辨与未知兜底文案;结算明细带逐行呈现与排播节奏;模态覆盖层编排与输入锁;未开格类型微光(8 邻作用集/五组色相/零玩法写入);UI 全局主题与按钮五态(含对比度锚);中文字体随包与字形覆盖;地形瓦片套与格面数字可读;战斗叙述与终局文案(数值带入/胜负互异);玩家面文案与危险格格面字形;战斗屏三区几何与棋盘格边长(分辨率两档×四档板型);B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役);模态句柄分域寻址面 | 已覆盖 | — | | 表现与支撑 | 存档序列化.md | 存档写盘⇄读回往返保真;三槽位隔离与激活失败回滚;槽位摘要窥视与坏槽三态;启动态无激活不写盘;旧档迁移链与断点续玩零跳号(集成);存档⇄RNG 快照往返保真(集成) | 已覆盖 | — | | 表现与支撑 | 教学引导.md | — | 未覆盖 | 教学形态与首遇时机待设计;见待办清单「教学形态未定」条 | | 表现与支撑 | 数据配置.md | 全表装载、就绪态与表清单目录对账;进度坐标查行:精确命中/向上取整/封顶/警告去重;运行期越域致命与进程非 0 退出;加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域;表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 已覆盖 | — | diff --git a/reports/需求卡片-模态句柄分域批-2026-11-02.md b/reports/需求卡片-模态句柄分域批-2026-11-02.md new file mode 100644 index 00000000..b5dc1c98 --- /dev/null +++ b/reports/需求卡片-模态句柄分域批-2026-11-02.md @@ -0,0 +1,253 @@ +# 需求卡片——模态句柄分域批 + +> v1.0 · 2026-11-02 · 零待裁点(开工门=U0) +> 来源=待办清单条目「[模态句柄册分域重构](../待办清单.md)(2026-11-01 登记,来源=会话提及)」,状态已到「待写卡」 +> 批性质=重构类需求性工程条目(行为零变化、纯句柄搬家);改动面=游戏代码 + +## 1. 目标与完成定义 + +**做什么**:把模态句柄册(`UiModals`)里按技术角色平铺的 12 个模态句柄按域分组抽成两只子容器——局内冒险域六件、菜单与跨语境域六件(营地六件已随迭代 47 卡⑥先例落 `UiCampModals`,不动);`ModalFlow` 编排件自 `UiModals` 升格为注册面(`UiRegistry`)直驻字段;模态登记口 `register_layer` 随登记职责迁驻注册面。全仓探针深员寻址、`ui_registry.gd node()` 合同寻址与 `main_ui_build.gd` 装配面随迁。 + +**什么状态算完**(逐条可核): + +1. `UiModals` 类变量面=`run`/`menu`/`camp` 三只子容器,类变量 14→3,零平铺句柄残留; +2. `ModalFlow` 实例由 `UiRegistry` 构造并直驻(`ui.flow`),`UiModals` 无 `flow` 成员;`register_layer` 在 `UiRegistry`(函数体逐字迁移); +3. 全仓旧寻址形(`modals.flow.*` 与 `modals.<12 个平铺名>`)grep 零命中;营地二段式 `modals.camp.*` 与 `LAYER_CONTRACT` 合同表逐字不变; +4. 行为零变化成立——既有模态开合、输入锁、登记合同序断言全部保留原判据,仅寻址字面换代,改址后照跑全绿; +5. 新结构断言〔句柄分域批 V1〕落码(`ui_struct_probe` registry 段扩展)并在当轮真实跑批执行且通过; +6. `game/tests/README.md` 能力行两处落位(存量行入口字面换代+新增分域寻址行); +7. 实现报告与反哺点清单落 `reports/`(末卡 T2);合回 master 后由本地 CI 按改动域跑闸判定(非卡内人手义务)。 + +## 2. 设计事实源 + +三选一之第③种——跳过设计线的证据指认(重构类需求性工程条目,凭代码证据+在册条目): + +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)。 + +## 3. 现状事实(代码级实测,2026-11-02) + +| # | 事实 | 证据(file:line) | +|---|---|---| +| 1 | `UiModals` 类变量 14:`flow`+12 平铺句柄+`camp` 子容器;`_init` 建 `flow` 与 `camp` | `ui_modals.gd:7-20,23-25` | +| 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) | +| 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` 命中行数,含注释行) | +| 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` | + +## 4. 目标结构与域归组 + +``` +main.ui(UiRegistry,类变量 3→4) +├─ screens: UiScreens(9,不动) +├─ battle: UiBattle(5,不动) +├─ modals: UiModals(类变量 14→3,转纯字段容器) +│ ├─ run: UiRunModals(新件,6 句柄=局内冒险域) +│ ├─ menu: UiMenuModals(新件,6 句柄=菜单与跨语境域) +│ └─ camp: UiCampModals(6,不动) +└─ flow: ModalFlow(升格直驻注册面;register_layer 随迁) +``` + +12 只平铺句柄的域归属与判据(每句柄以真实入口证据归域,非按数量凑袋): + +| 句柄 | 现寻址(平铺) | 目标寻址 | 域归属判据(真实入口) | +|---|---|---|---| +| legend_overlay | `modals.legend_overlay` | `modals.run.legend_overlay` | 局内——战斗中图例,棋盘角标触发(`main_ui_build.gd:77` → `main_overlay_flow.gd:184-187`) | +| node_overlay | `modals.node_overlay` | `modals.run.node_overlay` | 局内——节点结算窗(`main_adventure_flow.gd:73-74`) | +| level_screen | `modals.level_screen` | `modals.run.level_screen` | 局内——关卡地图屏(`main_adventure_flow.gd:206`;tags=screen_state `ui_registry.gd:21`) | +| curio_overlay | `modals.curio_overlay` | `modals.run.curio_overlay` | 局内——奖励三选一(`main_ui_build.gd:157,172-174`) | +| end_overlay | `modals.end_overlay` | `modals.run.end_overlay` | 局内——终局面板(`main.gd:290-299`) | +| status_panel | `modals.status_panel` | `modals.run.status_panel` | 局内——状态面板,地图/棋盘两角标入口(`main_ui_build.gd:126`、`main_overlay_flow.gd:32`) | +| shop_overlay | `modals.shop_overlay` | `modals.menu.shop_overlay` | 跨语境——冒险商店节点(`main_adventure_flow.gd:80-87`)+营地商店(`camp_shop_presenter.gd:10`) | +| settings_overlay | `modals.settings_overlay` | `modals.menu.settings_overlay` | 跨语境——开始层(`main_overlay_flow.gd:9`)+营地 Esc 双路径(`main_esc_flow.gd:51`) | +| career_overlay | `modals.career_overlay` | `modals.menu.career_overlay` | 跨语境——开始层笔记本+营地语境(`main_overlay_flow.gd:42,47`) | +| save_select_overlay | `modals.save_select_overlay` | `modals.menu.save_select_overlay` | 跨语境——开始层+营地大门流(`main_overlay_flow.gd:73,96,128`) | +| confirm_dialog | `modals.confirm_dialog` | `modals.menu.confirm_dialog` | 全语境——确认框(`main.gd:129,147,156`、`main_overlay_flow.gd:73,79,83,128`) | +| debug_overlay | `modals.debug_overlay` | `modals.menu.debug_overlay` | 全语境——调试浮窗(non_locking,`ui_registry.gd:37`;`main_debug_flow.gd` 全件) | + +寻址合同换代三形:`ui.modals.flow.X` → `ui.flow.X`;`ui.modals.<平铺名>` → `ui.modals.run.<名>` 或 `ui.modals.menu.<名>`;`ui.modals.camp.*` 不变。 + +## 5. 设计契约(红线条款,违反即返工;🔴=触碰即 L3 停机呈报) + +1. 🔴 **行为零变化**:装配序、登记序、树序、模态开合语义、输入锁谓词、遮挡记账、T17 演播后排窗挂起逐位不变;`LAYER_CONTRACT` 合同表零改动;`ModalFlow`/`ModalStack` 类本体零改动(搬家不改性)。判据=§10 对照表 R4/R5 行既有断言原判据照跑全绿。 +2. 🔴 **分域纪律册级化**:任何模态句柄禁平铺回 `UiModals`(营地先例条款 `ui_camp_modals.gd:3` 推广为全册纪律);`UiModals` 终态=三子容器纯字段,与 `UiScreens`/`UiBattle` 同型。 +3. 🔴 **拆分边界纪律**(条款在卡,判据权威=`code-conventions.md` §1.1 拆分判据,不复制定文):①每个拆出单元须有可陈述的职责语句与单一变化原因(本卡两新件的职责语句见 §8 结构图,实现报告逐件一行承载);②拆出单元须有集体身份——命不出名字、只能说「剩下的成员」的打包=凑计数袋,禁;③「过阈值」(S13 类变量 14 顶格 15)只许作为发现信号,作为拆分动机即违规——本卡动机=域归组(营地先例的册级推广),阈值顶格是发现信号;④按纪律拆不出内聚单元→停卡呈报走豁免/还债通道,禁硬拆凑绿(进 §11 L3)。 +4. 🔴 **Core 层零 UI 依赖不因新容器破坏**:两新件=RefCounted 纯句柄容器,不挂树、零信号连接、零核心写调用(与既有四容器同型);`--headless --script` 全链不受影响。 +5. **构造时序不变**:`flow` 改由 `UiRegistry._init` 构造——注册面构造点 `main.gd:94` 先于 `_build_ui`,装配早期注入点(`main_ui_build.gd:60` 取 `flow.pump_ended`)依赖其先在座的时序前提逐位保持。 +6. **数值纪律**:本卡零数值面;禁数值字面量进代码方案。 +7. **命名随仓库法**:新件类名对齐 `UiCampModals` 命名法;子容器成员名沿用原平铺名逐字(12 个句柄零改名——纯句柄搬家)。 + +## 6. 范围边界 + +**做**:§4 目标结构全部;全仓寻址换代(探针 11 件+测试 4 件+产品码 8 件);新结构断言落码;README 能力行两处。 + +**不做(明示去向)**: + +| 不收件 | 去向 | +|---|---| +| CAMP_HEADER_BAND 令牌退役 | 另一待办条目(归 ui_kit 令牌批顺带),本卡不收 | +| 任何行为变化(开合时序/遮挡/锁语义/登记序/树序/文案/交互) | 本卡范围外;发现即 L3 停机呈报 | +| `UiCampModals` 再拆分或营地六句柄改名 | 先例已立且职责单一,不动 | +| `ModalFlow`/`ModalStack` 职责重划或类体改写 | 本卡只搬家;重划属新需求 | +| 测量件(`game/sim/`)适配 | 实测零 `modals.` 寻址(§3 表#10 复核命令可验),零触碰 | +| `architecture.md` ui_registry/UiCampModals/模态编排三处记述换代 | 反哺点清单(§7),文档批落文 | + +## 7. 关联文档同步面 + +| 文档 | 关联点(本批实现会改变它的哪条陈述) | 同步义务 | +|---|---|---| +| 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/) | +| game/tests/README.md | 能力行两处:存量行「Esc 浮窗唤起与三出口动线」真实入口字面 `ui.modals.flow.open/close`→`ui.flow.open/close`;新增「模态句柄分域寻址面」行+覆盖域表 HUD框架 行随补 | 写卡段同批落位(本卡随批写入,非实现批义务) | +| design/gdd/术语表.md | 无新术语——「分域」「子容器」「注册面」均为仓库既有说法 | 无关联文档 | + +## 8. 文件结构图(卡前) + +| 文件 | 新建/修改 | 职责(职责语句) | 行为改动 | +|---|---|---|---| +| game/presentation/ui_run_modals.gd | 新建 | 局内冒险域六句柄唯一容器——冒险会话内开合的模态呈现面句柄册(纯字段 RefCounted) | 行为改动(寻址合同换代)→对照表 R1 | +| game/presentation/ui_menu_modals.gd | 新建 | 菜单与跨语境域六句柄唯一容器——菜单层与多语境共用模态的句柄册(纯字段 RefCounted) | 行为改动(寻址合同换代)→对照表 R2 | +| game/presentation/ui_modals.gd | 修改 | 模态层域句柄册转纯字段容器:三子容器 run/menu/camp;`register_layer` 与 `flow` 成员迁出 | 行为改动→对照表 R3 | +| 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/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 | +| game/probe/ 下 11 件(fx_shot/layout/probe_ui_util/screen_flow/shot/t17_defer/ui_click/ui_input/ui_probe/ui_struct/ui_tune) | 修改 | 探针深员寻址换代;ui_struct_probe registry 段增结构断言 | 非行为改动+结构断言新增→对照表 R1/R2/R3/R5 | +| game/tests/README.md | 修改 | 能力行两处落位(存量行换代+新增行+覆盖域表 HUD框架 行补名) | 非行为改动(写卡段义务,随本卡入库) | + +分文件寻址计数表(2026-11-02 实测,`grep -c` 命中行数、含注释行;实现复核用同一命令):main.gd flow=10 flat=17;main_adventure_flow flow=9 flat=29;main_debug_flow flow=4 flat=9;main_esc_flow flow=5 flat=3;main_overlay_flow flow=16 flat=27;main_ui_build flow=14 flat=50;ui_registry flat=12(node() 键行);ui_modals flow=1(头注);探针 11 件 flat=271 flow=27;测试 4 件 flat=24 flow=1。合计换代命中行=flat 442+flow 87=529(唯一行 482)。 + +## 9. 任务卡 T0–T2 + +估时:T0 0.5–1.0 工作日;T1 0.5–1.0 工作日;T2 0.25–0.5 工作日;合计中值 ≈1.9 个工作日(编排段汇总用)。 + +### T0 抽容器与注册面换代(产品码+冒烟测试件) + +**取用**:无(本卡首卡)。**产出**(T1 起引用,名字逐字):寻址合同三形 `ui.flow.<编排口>`(open/close/open_after_playback/locks_input/badge_greyed_map/badge_greyed_battle/register 入 stack 不变)、`ui.modals.run.<六名>`、`ui.modals.menu.<六名>`;新类名 `UiRunModals`/`UiMenuModals`。 + +- [ ] 新建 `game/presentation/ui_run_modals.gd`:`class_name UiRunModals extends RefCounted`,纯字段六枚全类型标注 `var legend_overlay: LegendOverlay`/`var node_overlay: NodeOverlay`/`var level_screen: LevelMapScreen`/`var curio_overlay: CurioPickOverlay`/`var end_overlay: BattleEndOverlay`/`var status_panel: StatusPanel`;头注=职责语句(局内冒险域六句柄唯一容器——与 §8 结构图逐字同句) +- [ ] 新建 `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.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 +- [ ] 验证②(真实开机路径):`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,同法) + +### T1 测试与探针面换代+结构断言落码 + +**取用**:T0 的寻址合同三形与 12 句柄归属表(§4)。**产出**:结构断言〔句柄分域批 V1〕;测试面全量新寻址。 + +- [ ] 探针 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) +- [ ] `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` 绿(开发期窄测形态,不产闸回执) +- [ ] 里程碑步出口跑一次代码域闸(`bash tools/run_all_gates.sh --code`);波内修复只做出红最小单元的最窄确认 + +### T2 产出物落位卡 + +**取用**:T0/T1 全部落地事实。**产出**:批收口两件+收尾核对。 + +- [ ] 写 `reports/iter-实现报告-<日期>.md`:各卡状态+实机目检总清单(本批行为零变化,零新增目检项——登记「模态开合走查由既有探针族覆盖」一句)+实现决定记录(零拍板或逐条:决了什么/为什么/代价/撤销方式)+实际改动—验收对照表(逐行补测试文件:行) +- [ ] 写 `reports/iter-反哺点清单-<日期>.md`:§7 同步面所列 architecture.md 三处(:168/:169/:200)逐条写清哪一节、改成什么、依据是什么 +- [ ] 收尾核对:`game/tests/README.md` 能力行名字与实际落地一致(新增行代表用例 `ui_struct_probe.gd:_modal_registry_contract` 实名核对;改名则回表) +- [ ] 合回后由 post-merge 钩子自动跑本地 CI 按域闸(非卡内人手义务);红项走修复 worktree 追绿 + +## 10. 验证闸(改动—验收对照表) + +判据口径:每行断言从真实入口进入、绑被测改动特有的可观测提交面、在当轮真实跑批中执行并通过;禁变异类测试与撤销类取证。断言尾缀新增统一〔句柄分域批 V1〕;既有断言尾缀保留原样(装配生命批 V1/ESC批 V1/注册面 V2 等)。 + +| # | 需求点 | 改动(文件:行/行为) | 验收测试(名称+落点+尾缀) | 层级 | 真实入口 | 判据绑定面 | 能力行 | +|---|---|---|---|---|---|---|---| +| R1 | 局内冒险域六件抽容器 | `ui_run_modals.gd` 新建;`ui_modals.gd:7-20` 六件成员迁出;`ui_registry.gd:59-64,72-78` 中六键换代;装配面六件赋值换代 | `ui_struct_probe.gd:_modal_registry_contract` V1a run 六件逐件非 null〔句柄分域批 V1〕 | 探针 | 真实实例化主场景 `_ready` 装配→registry 合同段 | 注册面新寻址取值面(`modals.run.*` 六句柄在座) | 新增:模态句柄分域寻址面 | +| R2 | 菜单与跨语境域六件抽容器 | `ui_menu_modals.gd` 新建;`ui_modals.gd` 六件成员迁出;`ui_registry.gd` 六键换代;装配面六件赋值/接线换代 | 同段 V1a menu 六件逐件非 null〔句柄分域批 V1〕 | 探针 | 同上 | 注册面新寻址取值面(`modals.menu.*` 六句柄在座) | 新增:模态句柄分域寻址面 | +| 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`) | 组合根接线源码字面(既有源码锚定断言形态) | 既有:模态覆盖层编排与输入锁 | + +非行为改动覆盖注记:各文件头注/注释随址换代、README 能力行两处=非行为改动,其装配与开合后果由 R4 行断言从真实入口承载;R6 为测试侧字面换代(判据语义不变),单独列行申报。合同表零改动(红线 1)的判据为静态——`LAYER_CONTRACT` 表常量无运行期可观测面(登记册序断言以表为参照系,表随登记同动时不互证),由独立验收审计核对 diff 中该数据块零行变更(观测面局限申报,非撤销类取证)。 + +**测试削弱申报**(允许的旧断言改动,全部为字面换代、零判据削弱):①`theme_projection_test.gd:719` 期望串换代(R6);②全部既有模态断言的寻址字面换代(R4/R5 所列段)——判据、阈值、真实入口全部保留;零删除断言、零放宽阈值。除上述外任何断言削弱=上游缺陷,停卡退回写卡段。 + +**闸口径**:本批改动含 `game/` 行为载体→代码域闸;合回后本地 CI 为唯一强制验证点(判读归 CI 回执,卡内不重复人手跑)。回归措辞按模板:里程碑步(T 段)出口跑一次全套闸;波内修复只做出红最小单元的最窄确认;新增断言先行孤立验证再并入全套(T1 验证①已含)。 + +**测试方式两分法**:本批全部归能力验证(自动化断言);零新体验面,用户目检零新增项(T2 登记句即了结义务,登记不阻塞)。 + +**独立验收审计**:合回前由未参与实现的会话或子代理执行,报告落 `reports/iter-验收审计-<日期>.md`;审计至少核对对照表六行两端对上、真实入口未绕过改动点、判据绑定面钉在寻址合同与开合面上;未过不得合并。 + +## 11. 异常分级 + +- **L1 自救**:改址漏点(编译/寻址报错指名文件行)——按 §8 计数表补点后重跑该件所在最窄验证。 +- **L2 记录继续**:注释/头注换代引发的 S11 注释禁词误报——按扫描面豁免通道核对后记录实现报告;探针偶发超时——单件重跑一次并记录。 +- **L3 停机写报告等用户**(逐条):①行为零变化破口(任何开合/锁/序差异);②拆不出内聚单元(契约 3④);③**机检预算互斥=上游缺陷停卡退回写卡段**——S13/S9 键与卡片契约互斥、或需保留无效成员才能过闸时,禁自造第三条路;④判据绑不上(R3 结构断言若造不出可观测面)=静态判据+评审注记申报观测面局限,禁自造注入破坏或回退 hunk 取证。 + +## 12. 代拍板白名单(授权 agent 实现期自行拍板的微决策) + +1. 分组命名:子容器字段名 `run`/`menu`,类名 `UiRunModals`/`UiMenuModals`(对齐 `UiCampModals` 命名法;「局内冒险域」「菜单与跨语境域」两职责语句随件入头注)。 +2. 子容器成员名沿用原平铺名逐字(12 个句柄零改名)。 +3. `ModalFlow` 独立持有的落点=`UiRegistry` 直驻字段 `flow`:注册面是寻址与登记的单点宿主,构造时点与今等价;备选「main 直持」被否——破坏 `main.ui.<域容器>.<句柄>` 单点寻址面与注册面门面定位。 +4. `register_layer` 随登记职责迁驻 `UiRegistry`(`UiModals` 转纯字段容器,与 `UiScreens`/`UiBattle` 同型;登记口语义逐字不变)。 +5. 注释与头注随寻址换代等长改写(零语义新增,禁变更叙事)。 + +超白名单事项记入实现报告「实现决定记录」节备案,不另立追认单。 + +## 13. 待裁点 + +**零待裁点,开工门=U0。** 目标形态(分组抽容器+flow 升格独立持有+行为零变化)已在待办条目实况定稿;命名与落点微决策已授权(§12);本卡不触碰用户设计权保留面(无玩法、无文案、无数值、无美术)。 + +## 14. 落位与可复用性预检 + +**新增文件两枚**(`ui_run_modals.gd`/`ui_menu_modals.gd`): + +- **复用面**:grep 全仓无同职责件——`UiCampModals` 只收营地域六句柄(句柄集不相交,`ui_camp_modals.gd:1-12`),`UiScreens` 收屏壳与全屏态、`UiBattle` 收战区视图(`ui_screens.gd`/`ui_battle.gd` 头注自陈域界)——把 run/menu 域句柄塞进任何一只既有容器=域错位,直接违反分域纪律(§5 契约 2);确需新增的理由成立。 +- **唯一面**:类名 `UiRunModals`/`UiMenuModals` 与字段名 `run`/`menu` 全仓 grep 零命中(盘上无第二处同名/同义件);12 只句柄各自唯一落点=自 `ui_modals.gd` 迁入而非复制(迁移后旧成员已删,`get()` 判 null 有断言钉住——R3)。 +- **分层与交互面**:两新件被 `UiModals._init` 构造、被 `main_ui_build` 装配赋值、被 `ui_registry.node()` 寻址——调用路径与既有三容器同型(`UiRegistry._init` → 容器构造;装配写句柄;寻址读句柄);RefCounted 不挂树、零信号、零核心触碰,Core 层零 UI 依赖与 RngService/ConfigDB 红线零接触(本批零随机、零数值)。 + +**新增函数一件**:`UiRegistry.register_layer`——自存量逐字迁移(非新逻辑),对账见 §15。 + +**新增数据件**:无。 + +## 15. 实现规范预算 + +对照 `tools/gdstyle.toml` 默认口径(gdstyle v0.4.0:公开方法 ≤20、类变量 ≤15、单函数分支 ≤8、返回 ≤6;基线=`tools/gdstyle_baseline.txt`): + +**新件三查**: + +| 新件 | 公开方法 | 类变量 | 迁移函数对账 | +|---|---|---|---| +| ui_run_modals.gd | 0(纯字段,≤20 ✓) | 6(≤15 ✓) | 无迁入函数 | +| ui_menu_modals.gd | 0(纯字段,≤20 ✓) | 6(≤15 ✓) | 无迁入函数 | + +**存量触面一查**(预期与手段): + +| 存量件 | 键现状 | 预期 | 手段 | +|---|---|---|---| +| ui_modals.gd | 基线无键(14 未越限) | 类变量 14→3、公开方法 1→0——只降不升 | 成员迁出后即删,禁留别名(§16) | +| ui_registry.gd | 基线无键(3 未越限) | 类变量 3→4、公开方法 2→3——均在上限内不产新键 | register_layer 迁入为唯一增量 | +| main_ui_build.gd | 基线无键 | 行数 ±0(改址等长)、函数面零增 | 只换代址字面与随迁注释 | +| main.gd 与四拆件 | 基线无键 | 零新成员、零新函数 | 只换代址字面 | + +**迁移函数对账**:`register_layer`(源=`ui_modals.gd:28-33`,函数体 5 行、零分支、单返回)——`gdstyle_baseline.txt` 无源函数键,branches/returns 均在默认值内,迁移即原样、无需拆函数。 + +**指标例外申报**:无。 + +## 16. 禁为机检文本保留无效成员(重构类卡必填条款) + +禁止为迎合机检消息文本(含计数)而保留或新增无效成员/别名——`UiModals` 迁出的 13 个成员(12 句柄+flow)不设转发属性、不设 get 兜底、不保留空壳 var;`ui_registry.node()` 十二键直接指向新两段式寻址,不留旧键双轨。机检键与卡片契约互斥时,实现段一律停卡呈报(§11 L3③),不得自造第三条路。 diff --git a/待办清单.md b/待办清单.md index 3dcaa763..ab45d942 100644 --- a/待办清单.md +++ b/待办清单.md @@ -439,8 +439,8 @@ #### 模态句柄册分域重构(2026-11-01 登记,来源=会话提及) -**实况**:重构证据=`game/presentation/ui_modals.gd:7-20`(类变量 14 实测)+停机呈报-迭代47机检预算互斥-2026-11-01.md(卡④⑤ 平铺合计 19>S13 上限 15)——按技术角色平铺 13 模态句柄+flow,迭代 47 营地域新增六句柄顶格 S13 类变量上限 15(2026-11-01 用户裁:最小改动先走——营地六句柄落 `ui_camp_modals.gd` 子容器,随迭代 47 卡⑥/卡④/卡⑤ 落地,本条只登记**全量分家**)。目标形态=存量句柄按域分组抽容器(局内 run 六件/菜单与跨语境归组)+ModalFlow 自 UiModals 升格独立持有;行为零变化、纯句柄搬家;返工面=全仓探针深员寻址+`ui_registry.gd node()` 寻址+`main_ui_build.gd` 装配。拆分判据权威=code-conventions §1.1(沿职责轴;营地子容器先例=`ui_camp_modals.gd`,随迭代 47 落地后为准)。 +**实况**:重构证据=`game/presentation/ui_modals.gd:7-20`(类变量 14 实测)+停机呈报-迭代47机检预算互斥-2026-11-01.md(卡④⑤ 平铺合计 19>S13 上限 15)——按技术角色平铺 13 模态句柄+flow,迭代 47 营地域新增六句柄顶格 S13 类变量上限 15(2026-11-01 用户裁:最小改动先走——营地六句柄落 `ui_camp_modals.gd` 子容器,随迭代 47 卡⑥/卡④/卡⑤ 落地,本条只登记**全量分家**)。目标形态=存量句柄按域分组抽容器(局内 run 六件/菜单与跨语境归组)+ModalFlow 自 UiModals 升格独立持有;行为零变化、纯句柄搬家;返工面=全仓探针深员寻址+`ui_registry.gd node()` 寻址+`main_ui_build.gd` 装配。拆分判据权威=code-conventions §1.1(沿职责轴;营地子容器先例=`ui_camp_modals.gd`,随迭代 47 落地后为准)。需求卡片:reports/需求卡片-模态句柄分域批-2026-11-02.md(2026-11-02 写卡会话落位,零待裁点,开工门=U0)。 **改动面**:游戏代码 -**状态**:待写卡 +**状态**:已写卡