diff --git a/reports/需求卡片-战斗编排归约批-2026-10-29.md b/reports/需求卡片-战斗编排归约批-2026-10-29.md new file mode 100644 index 00000000..e1b42172 --- /dev/null +++ b/reports/需求卡片-战斗编排归约批-2026-10-29.md @@ -0,0 +1,208 @@ +# 需求卡片——战斗编排归约批(battle_orchestrator 类变量 38→15) + +> **版本状态**:v1.0 定稿——零待裁点(2026-10-29 用户裁:RoundCycle/BattleFacts 两件形态、encounter 归 BattleFacts、attune 改判、treasure_inventory 改址追认、完美账写口升级可裁量)。 +> **接收方**:待办清单条目「战斗域结构深拆批——效果发射端口+宿主瘦身+掷格/受理分件(2026-10-27 登记,来源=批次移交)」——本卡承接其中 battle_orchestrator 瘦身面(architecture 轴丁);该条目的效果发射端口与 reward_economy 分件两子项不在本卡。 +> **来源**:`reports/设计-战斗编排类变量归约-2026-10-29.md`(设计讨论段定稿,五待裁点 2026-10-29 用户裁全闭合)。**唯一事实源**:该设计文档全文 + `design/engineering/architecture/architecture.md` v1.25「战斗编排域拆件定稿」节轴丁与「模块归属·功能层」RoundCycle/BattleFacts 两行。 + +## 1. 目标与完成定义 + +这批做什么:把战斗结算编排宿主 `game/core/battle_orchestrator.gd` 的 38 个类变量收敛到 15(=gdstyle 阈值,合规)。手段=按变化原因拆两枚新件收编 22 个成员——**RoundCycle**(轮循环驱动件:五段段件持有、段序执行、结算重入门闸、开轮摇号、踩雷计数账)与 **BattleFacts**(战斗事实件:受理事实 encounter、轮 facts 缓冲、封印判定账、装板溯源、条件计数、同调快照;attune 状态两成员随件、行为函数留宿主)——外加两项单点处置:treasure_inventory 注入改址(level_runner 经 RewardGrant 出口直注,原「外部赋值路径零改址」句经用户追认失效)与 _hero_atk 转派生读。 + +什么状态算完: + +1. 宿主类变量实测 15、两新件零 gdstyle 键、battle_orchestrator 全文件零超标键(第 9 节键账)。 +2. 游戏行为零变化:同种子完整局步骤流、事件流、两快照载荷逐位一致(第 4 节红线;第 11 节 V0 行)。 +3. 批末代码域闸全绿(冒烟+系统测试+单元集成关联档+探针+静态扫描),键账对账完成(第 12 节)。 +4. 实现报告与反哺点清单落 `reports/`(T4 产出物落位卡)。 + +## 2. 设计事实源 + +- `reports/设计-战斗编排类变量归约-2026-10-29.md`——设计讨论段定稿全文。逐成员去向(38 项五去向)、两新件形态与耦合边界、attune 重裁决、已否决切法、随迁键义务、行为零变化风险点、键账预期、改址盘点,全部以该文档对应节为唯一合同;本卡不复制其表格,T0 逐名对账时引用。 +- `design/engineering/architecture/architecture.md` v1.25——「战斗编排域拆件定稿」节轴丁两件(RoundCycle/BattleFacts,跨件单向接线、段类随动、attune 改判、S13 键账收敛义务、验收红线)与「模块归属·功能层」两行、「测试与质量域」S13 豁免第三条注销句——实现照册施工。 +- 五待裁点裁决(2026-10-29 用户裁,对应设计文档 §13):①encounter 归战斗事实件=采纳;②treasure_inventory 注入改址=追认(「外部赋值路径零改址」句失效);③attune 重裁决=采纳「状态归 facts、行为留宿主」;④完美账写口升级=采纳(grant_segment 三处直写改经 facts 三方法);⑤PARITY 对拍批准=批内实跑须用户点头、不重锚。 + +## 3. 现状事实(代码级,2026-10-29 实查;开工 T0 按当轮 master 重测复核) + +- `tools/gdstyle_baseline.txt:9-10`——battle_orchestrator.gd 现登记两条类级键:`quality/max-class-variables = 38`、`quality/max-file-length = 1035`;**该文件零函数级键**(59 个函数全部在默认阈值内——设计文档 §7 前提成立,T0 复核)。 +- 宿主 38 类变量声明区=`battle_orchestrator.gd:37-85` 与 `:223-227`(逐名清单见设计文档 §2 表)。宿主改后保留 15:db、rng、minesweeper、action_economy、_enemy_system、_status_effects、_reward_economy、_damage、_fx_host、_reward_grant、round_index、battle_result、nest_preview_count、_rounds、_facts。 +- **编队前置实态**:迭代 42(gdstyle 尾波清偿批,roadmap 在册)合回后轴丙 BoardInstaller 已建——`_board_generator` 成员随件退役(38→37)、装板域六函数迁出、宿主复位块留薄壳 `_install_and_reset`、文件长键归绿;届时宿主约 890 行/37 成员,本卡叠加其上。**本卡在迭代 42 合回之前禁开工**;T0 按当轮 master 重测对账。 +- 段驱动现态:五段构造 `battle_orchestrator.gd:256-260`(授予/战斗两段三引用形,aura/decay/verdict 单引用形);三闸 `_maybe_settle` :592-597;段序体 `_settle` :602-613(终局早退不回置 _settling);开轮摇号 `_roll_round_actions` :677-721(behavior_roll 流 :717,mines_hits 转存 :720-721);`_on_round_end` 末行 :589 调 `_maybe_settle`。 +- 事实族写读点:缓冲追加 `_on_cell_revealed` :554-580(身份快照捕获 :576 留宿主);`_on_seal_judged` :583;`_facts_path` 写 `_on_round_end` :588;轮复位 `_reset_round_facts` :976-979(三调用点 :273/:810/:862);封印/完美/标错/板序/溯源清零在装板复位块 :442-446(迭代 42 后归宿主薄壳);`_refresh_used_this_round` 复位点 `_exit_distribution` :811;完美谓词 `perfect_sweep_earned` :1033-1035。 +- treasure_inventory:宿主声明+setter 转发块 `battle_orchestrator.gd:48-52`;唯一外部注入点 `level_runner.gd:520`;宿主读 :111/:203/:450/:858;`grant_segment.gd:370-371` 读 `oc.treasure_inventory`。 +- _hero_atk:声明 `battle_orchestrator.gd:227`、受理写入 :304、spawn 消费 :305、`combat_segment.gd:56` 消费 `oc._hero_atk`。 +- attune 外部三面(零改址标的):`attune_has` 公有面消费=table_structure_guard_test 起战断言(:162/:166)与 breakpoint_resume_test;`attune_param_sum`=main.gd:567 与 treasure_effects_test;`attune_convert_state`=treasure_interact_controller.gd:125。三面全部留宿主公有面。 +- 冻结面:`nest_preview_count` 外部直读=main.gd:536-537+treasure_effects_test:153;`round_index` 公有直读=system_test.gd:447-462(st.round_index)等四套件约 15 处。 +- **设计文档 §11 漏列一处(T0 实查补入)**:`settle_segments_test.gd:27` 接线断言 `oc._grant_seg != null and oc._grant_seg.oc == oc`——段件迁 RoundCycle 后必红,须改指 `oc._rounds._grant_seg`。 +- `tools/run_all_gates.sh` PARITY_TOUCH_FACES(:161 定义区)含 `game/core/battle_orchestrator.gd`——本批必触面。 +- `game/tests/static_scan.sh`——S8 await 文件集(:317,9 文件)与 S7 B1 域文件集(:359,9 文件)均未含两新件路径;round_cycle.gd 经 oc 调 B2 符号(`_enemy_system` 族)须随批增行,battle_facts.gd 零协作调用不入清单。 + +## 4. 设计契约(违反即返工的红线条款) + +- 🔴 **行为零变化(本批总判据)**:同种子下事件流/步骤流/两快照载荷/存档往返逐位一致;玩家可见面零变化;`design/gdd/systems/` 零修订预期。 +- 🔴 **RNG 取号序零漂移(封闭流随件迁移先例句)**:behavior_roll 随 `roll_round_actions` 迁 RoundCycle——流名、开流时点、取号序逐字(先例句=「fx_reveal 封闭流随件迁移取号序不变」同款);encounter/gp_drop/board_gen/variant_place/fx_reveal 五流留原地零触碰;零 `randomize()`/自建随机。 +- 🔴 **信号顺序契约冻结**:五信号(step_row/battle_finished/round_started/board_changed/settlement_snapshot)留宿主;发射语句零迁移、发射时序零变化;A2 三 connect(:251-254)逐字。 +- 🔴 **两快照出口签名与载荷逐字不变**:presentation_snapshot/diagnostic_snapshot 字段名、嵌套结构、值口径逐字——内部读数改指两件投影后值恒等(round_index/attune_safe_seen/完美三账/hero_atk 派生读均受理后不变量)。 +- 🔴 **明细行协议词表零触碰**:基础 9 类+扩展行词表、SOURCE_EXEMPT_TYPES/SOURCE_EXEMPT_CLASSES 两常量、`_emit_row`/`_assert_row_source` 行发射基建留宿主零迁移。 +- 🔴 **PARITY 触面**:battle_orchestrator.gd 触 PARITY_TOUCH_FACES——实跑对拍须经用户批准、不得借机重锚。 +- 🔴 **拆分边界纪律**(判据权威=code-conventions §1.1,此处立卡内执行条款):①每个拆出单元须有可陈述的职责语句与单一变化原因(实现报告逐件一行承载);②拆出单元须有集体身份——命不出名字、只能说「剩下的成员」的打包=凑计数袋,禁;③「过阈值」只许作为发现信号,作为拆分或收拢的动机即违规;④按纪律拆不出内聚单元 → 停卡呈报走豁免/还债通道,禁硬拆凑绿;⑤拆分沿职责轴不沿阈值轴。两新件职责语句见第 8 节(RoundCycle=轮结算周期的推进结构;BattleFacts=战斗事实的记录与查询口径)。 +- 🔴 **禁为机检文本保留无效成员**:已迁 22 成员声明随迁即删(21 迁两件+treasure_inventory 退役+_hero_atk 退役),禁保留别名、别名转发属性或空壳;机检键与卡片契约互斥时,实现段一律停卡呈报,不得自造第三条路。 +- 🔴 **随迁键收敛义务**:迁移函数逐字纪律——`roll_round_actions`(45 行/分支≈8 贴线)、`settle_if_due`、`reset_round`、三 mark 方法迁移与改指**禁顺手增分支/局部**;函数迁入新文件若出超标键=卡内同步收敛(拆助手函数,拆分不改语义;先例=迭代 40 卡① 12 随迁键收敛),禁带新键进批末闸。 +- 🔴 **段类接线改形守 Middle Man 禁壳**:段类对宿主的直调形态不变(段类经宿主引用直调,现状形态);段内改指一律调用点改指(`oc._X` → `oc._facts.X`/`reward_grant.treasure_inventory`),宿主与新件禁留转发壳。 +- 🔴 **_fatal 与 battle_result 状态机唯一写点留宿主**:RoundCycle/段类经 oc 直调 fatal 面零改形;BoardInstaller(迭代 42 建件)fatal Callable 零触碰。 +- 🔴 **BattleFacts 成员冻结**:15/15 贴顶——实现期禁增员,增员即停卡;扩容阀=下一张要加事实成员的卡先把封印判定账五成员二次拆出(SealLedger,−5)再落新账,禁硬挤。 +- 🔴 **reset_round 复位边界**:只清 reveals/seals/path 三项、**不碰 refresh_used**——_battle_over 后快照读到的 refresh_used 必须保持末轮值(设计文档 §8.5 险点,对照表 V2 行断言钉住)。 + +## 5. 范围边界 + +做什么:设计文档 §2 逐成员去向表的全部迁移与改址、两新件建件、treasure_inventory 改址、_hero_atk 派生读、随迁键收敛、S7/S8 静态扫描随动、对照表新增断言四条。 + +不做什么: + +- 轴丙 BoardInstaller 建件——迭代 42 在册卡执行,本卡前置、不重复。 +- 五段段类职责与段序语义零改写(只改指);`_exit_distribution` 留宿主(设计文档 §6.5 已否决迁驱动件——判定段直调宿主,零新引用环)。 +- attune 行为函数留宿主(attune_has/attune_param_sum/attune_convert_state/积点自动兑付体/充能重置零迁——设计文档 §5 重裁决);AttuneLoadout 零触碰。 +- nest_preview_count 冻结面、round_index 公有直读面、A2 三事件订阅面——零变化。 +- 数值表、RNG 流词表、信号载荷 schema、明细行词表——零触碰;本批零数值改动,MC 零跑(第 13 节)。 +- `game/tests/README.md`、`design/` 全目录、根规则文件——实现批禁写(反哺点通道,第 6 节)。 +- 效果发射端口定形与 reward_economy 分件——归接收方条目其余子项,另行设计讨论。 + +## 6. 关联文档同步面 + +| 文档 | 关联点(本批实现会改变它的哪条陈述) | 同步义务 | +|---|---|---| +| design/engineering/architecture/architecture.md | 轴丁两行与功能层 RoundCycle/BattleFacts 行——设计已闭合落文 v1.25,实现照册施工;「测试与质量域」S13 豁免第三条注销句已预写注销(本批键账达成即生效,未达成=停卡非落文);两行「构造=引用束注入」句与本卡三参直构/零参直构实态的口径差;批末成员数/行数/公开方法数实测值与在册数字出入 | 设计权威文档——实现批禁直改;出入逐条列进 `reports/iter-反哺点-<日期>.md`,用户裁决后归文档批落文 | +| game/tests/README.md | 本批零新增能力、零入口与代表用例名变更(测试改指只动成员寻址;新增断言四条全部内嵌既有函数);能力清单零增删改 | 机械面文档——实现批禁写;批末收尾核对表上名字与实际落地一致(改名则回表) | +| design/gdd/systems/(全树) | 无关联文档——结构整改不改游戏规则与玩家可见行为 | 无修订预期;若实现中发现契约句被触碰,停卡呈报走反哺点通道 | + +## 7. 卡前文件结构图 + +| 文件 | 职责 | 改动性质 | +|---|---|---| +| game/core/battle_facts.gd | 战斗事实件(新增,architecture v1.25 功能层在册)——受理事实/轮 facts 缓冲/封印判定账/溯源/条件计数/同调快照,自带轮复位与完美账写口 | 新增(非行为改动——成员迁移;验收=对照表 V1/V2/V6 行) | +| game/core/settlement/round_cycle.gd | 轮循环驱动件(新增,同在册)——五段段件持有与段序执行、结算重入门闸、开轮摇号、踩雷计数账 | 新增(非行为改动;验收=V1/V3 行) | +| game/core/battle_orchestrator.gd | 战斗结算编排中枢——宿主 15 成员定着、行发射基建、状态机、两快照出口、attune 行为读数与触发面 | 修改(非行为改动——成员改指、三函数迁出、派生读、注入改址;验收=V0–V5 行) | +| game/core/settlement/grant_segment.gd | 授予段——事实族改指约 23 处+完美三处直写改经三 mark 方法 | 修改(非行为改动) | +| game/core/settlement/combat_segment.gd | 战斗段——2 处改指(oc._facts_reveals 扫描、oc._hero_atk 派生调) | 修改(非行为改动) | +| game/core/level_runner.gd | 关卡域生命周期——库存注入 1 行改经 `reward_grant()` 出口直注 | 修改(非行为改动——注入路径改址,注入时序与消费面零变化;验收=V5) | +| game/tests/static_scan.sh | 静态扫描域承载——S7 B1 域文件集与 S8 await 文件集增行 round_cycle.gd | 修改(工程随动,architecture 拆件定稿节 S7/S8 随动条在册) | +| game/tests/unit/battle_settlement/seal_polarity_test.gd · unit/core/feat_vouchers_test.gd · unit/battle_settlement/trigger_cond_test.gd · unit/battle_settlement/round_flow_skill_pool_test.gd · unit/core/settle_segments_test.gd · unit/core/treasure_effects_test.gd · unit/core/adventure_feats_test.gd · unit/core/meta_progression_forge_test.gd · unit/battle_settlement/roll_multiplier_test.gd | 成员寻址改指(断言条件与期望值零变化)+新增断言内嵌既有函数(V1/V2/V4/V5) | 修改(改指=非行为改动;新增断言行=对照表对应行) | + +aura/decay/verdict 三段、battle_fx_host、reward_grant、damage_controller、main.gd、treasure_interact_controller、board_installer——零改动(设计文档 §11 盘点)。新增件「为什么不能复用」理由与唯一落点核查见第 8 节;对不上即卡片不成立。 + +## 8. 落位与可复用性预检 + +- **battle_facts.gd(新增)**:复用面核查——战斗事实记录面现行只摊在 battle_orchestrator 成员区(全仓 grep 同名与同义标识符:`_facts_reveals`/`_seal_consumed`/`_perfect_*` 等无第二实现),无既有件可复用。不能并入 BattleFxHost(效果引擎宿主域——变化原因是效果发射与施加,不是事实记录)、不能并入 RewardGrant(授予管线域——事实账不是授予物)、不能并入五段段类(段类只搬运时序零持有账——缓冲写读跨段跨界,归宿主编排面)、不能并入 AttuneLoadout(营地/冒险域充能物化单源,迭代 39 已闭合契约——重开已闭合边界=设计文档 §5 理由 4 否决)。落点唯一:`game/core/battle_facts.gd`。分层:core 层 RefCounted,零注入引用、零信号、零协作对象调用——纯数据+谓词+写口;身份快照捕获(query_full_snapshot)留宿主 `_on_cell_revealed`,防它变成第二编排面。 +- **round_cycle.gd(新增)**:复用面核查——轮结算周期推进机构(段件持有/重入闸/摇号/踩雷账)现行只存在于宿主三函数+五成员,无第二实现。不能并入 BattleFxHost/RewardGrant(变化原因不同,同上)、不能并入任一段类(它是段件的序主人——持段件者不能是被持者)。落点唯一:`game/core/settlement/round_cycle.gd`(与五段段件同目录)。分层:core 层 RefCounted、零 await;随机只经 `oc.rng` 的 behavior_roll 封闭流。 +- **引用束注入构成**:引用束先例(BattleFxHost/RewardGrant 的字典束)防的是 `_init` max-parameters 新键——本批两新件参数均未触发:RoundCycle `_init(host, fx_host, reward_grant)` 三参直构(fx_host/reward_grant 仅作段构造透传,不落成员);BattleFacts 零参直构。architecture 两行「构造=引用束注入」句按设计文档 §3/§4 实态执行(三参直构无需束),出入随反哺点申报。 +- **依赖方向**:宿主→两新件单向(宿主 `_init` 建件并接线,每战新建同灭);RoundCycle 持 `oc`=五段段类既定同款形态(段类已持宿主引用直调——非新增反向引用),除 `oc` 外禁持宿主其他成员、禁回调宿主私有族;BattleFacts 不持任何对象引用——宿主与段类经注入引用直读写(fx_host._fx_bonus_delta 跨件直读写同款现状形态)。新件之间零互引。 +- **新增函数**:宿主 `_hero_atk()` 派生读=`_journal()`「读面即引用、无第二账」同款先例(encounter 受理后只读,派生值恒等);`reset_round`=原 `_reset_round_facts` 逐字;三 mark 方法=新写口(升级采纳案)。零新增数据件、零新增常量表。 + +## 9. 实现规范预算(新件对照 gdstyle 默认阈值;写码前对账,超预算面=停卡退回写卡段) + +| 新件 | 公开方法 ≤20 | 类变量 ≤15 | 迁移函数对账(基线源函数键) | +|---|---|---|---| +| battle_facts.gd | 预算 4(reset_round+mark 三方法;设计文档 §10 表载 5 属含 `_init` 宽口径计数差,两口径均 ≤20 零键风险) | 15(贴顶——实现期禁增员,增员即停卡;扩容阀=SealLedger 二次拆出) | `reset_round`=原 `_reset_round_facts` 逐字(基线无其函数级键);三 mark 新增小函数远在阈值内 | +| round_cycle.gd | 预算 3(settle_if_due/roll_round_actions/is_settling) | 8(oc+五段段件+_settling+mines_hits) | `settle_if_due`=`_maybe_settle`+`_settle` 合体(两源函数基线零键;闸序与段序逐字);`roll_round_actions` 45 行/分支≈8 贴线——迁移禁增分支/局部,确需增条件即停手核对 gdstyle;`is_settling` 新增小函数 | + +存量触面一查:battle_orchestrator 类变量 37(轴丙后实测)→15 只降、文件长约 890→约 830 只降(均阈值内,S13 键较登记值只降不升——达成手段=本卡迁移,无豁免申报);grant_segment/combat_segment 改指零新增键(`_judge_seal` 等函数体只换成员寻址);level_runner 改 1 行零新增键。两新件与改址后宿主、段类落地后先跑 `python tools/gdstyle_gate.py` 预检一次再进批末闸(T4 步骤)。`_init` 形态:RoundCycle 三参/BattleFacts 零参(max-parameters 阈值 5 未触发)。新增文件全类型标注(S9——容器参数化走 `Dictionary[Variant, Variant]` 现行口径);头注按 code-conventions §1.4.1(职责语句+封闭面声明,禁变更叙事、禁文档反链)。 + +## 10. 任务卡 T0..T4(估时为区间;工作量限制只属迭代层) + +**T0 重测对账(0.25–0.5 工作日)**(前置:迭代 42 合回——BoardInstaller 在库;产出:逐成员对账结论与改址点名清单,后续各卡取用) + +- [ ] 以当轮 master 重测 battle_orchestrator.gd 类变量逐名清单,对账设计文档 §2 表五去向(留宿主/RoundCycle/BattleFacts/退役改址/派生读;轴丙后实态 37 项,`_board_generator` 行应已消失)——对不上即停卡呈报 +- [ ] 复核 gdstyle 基线:battle_orchestrator 函数级键数(预期零——漂移即停卡呈报);类变量键现值与文件长键现状(应已随轴丙归绿或基线已 refresh) +- [ ] 复核第 3/7/9 节全部 file:line 引用与设计文档 §11 改址盘点实数(grant_segment 约 23–25 处、测试各套件逐处点名——含 settle_segments_test:27 补入项);漂移处就地改卡并记录 + +**T1 BattleFacts 建件与事实成员迁移(0.75–1 工作日)**(取用:T0 对账清单;产出:`_facts` 在座、事实族 15 成员归件——T2/T3 引用其成员名) + +- [ ] 建 `game/core/battle_facts.gd`:class_name BattleFacts,extends RefCounted;15 类变量初值逐字承原宿主声明(encounter/reveals/seals/path/refresh_used/board_seq/board_from_midround/seal_consumed/seal_miss_seen/perfect_hit_true/perfect_hit_false/perfect_forgiven/feat_first_dig_used/attunement/attune_safe_seen);公开方法 4:`reset_round()`(原 `_reset_round_facts` 逐字——只清 reveals/seals/path 三项,不碰 refresh_used)、`mark_perfect_hit()`、`mark_perfect_miss()`、`mark_perfect_forgiven()`;头注写职责语句+成员封闭面+零注入零信号零协作调用 +- [ ] 宿主 `_init` 建 `_facts = BattleFacts.new()`;事实族成员全量改指:宿主声明删 15 项、读写点改 `_facts.X`(encounter 全部读点——_journal/_attune_loadout/_fx_host_fact/受理段/fx_state/两快照/gp_drop,按 T0 点名清单逐处;缓冲追加/复位/装板清零/perfect 谓词同批);`_reset_round_facts` 函数删除,三调用点改调 `_facts.reset_round()`(时序位置逐字) +- [ ] grant_segment 事实族改指(`oc._facts_reveals/_facts_seals/_facts_path/_seal_consumed/_seal_miss_seen/_feat_first_dig_used/_perfect_*` → `oc._facts.X`);完美三处直写改经三 mark 方法(:311/:379/:394——写口升级采纳案;:397 forgiven 读数直读 `_facts.perfect_forgiven` 零变化) +- [ ] 测试改指:seal_polarity_test 8 处(_perfect 直写→_facts.perfect_*)、feat_vouchers_test facts 族、treasure_effects_test:309(ob14.attunement→ob14._facts.attunement)、adventure_feats_test 1 处(encounter 读→_facts.encounter)——断言条件与期望值零变化 +- [ ] 新增断言 round_flow_skill_pool_test.gd:_smoke_full_battle 内嵌〔编排归约 V2〕:终局后 `presentation_snapshot()["refresh_used"]` 等于末轮结算 snapshot 的 economy.refresh_used(复位边界险点,规格见对照表) +- [ ] 孤立验证:`godot --headless --script res://tests/run_all.gd -- --only=seal_polarity,feat_vouchers,treasure_effects,adventure_feats,table_structure_guard,round_flow_skill_pool,variant_placement` 全绿+`python tools/run_smoke.py`(出红只跑红件最小单元) + +**T2 RoundCycle 建件与段驱动迁移(0.75–1 工作日)**(取用:T1 的 `_facts`;产出:`_rounds` 在座、段驱动三入口——T3 引用其方法名) + +- [ ] 建 `game/core/settlement/round_cycle.gd`:class_name RoundCycle,extends RefCounted;类变量 8(oc/mines_hits 公有+_grant_seg/_aura_seg/_combat_seg/_decay_seg/_verdict_seg/_settling 私有);`_init(host, fx_host_ref, reward_grant_ref)` 三参——五段构造五行从宿主 `_init` 逐字搬入(构造参数与持有形态不变);公开方法 3:`settle_if_due()`(原 `_maybe_settle` 三闸+`_settle` 段序体合体——闸序 settling→battle_result→phase 逐字,终局早退不回置 _settling)、`roll_round_actions()`(原函数逐字迁入——behavior_roll 流名/开流时点/取号序逐字,宿主引用经 oc 改指,禁增分支/局部)、`is_settling()`;头注写职责语句与单一变化原因 +- [ ] 宿主 `_init`:五段构造五行迁出,改 `_rounds = RoundCycle.new(self, _fx_host, _reward_grant)`(置于两件建齐与 bind 接线之后——构造序禁环不变);五段成员声明删除;`_maybe_settle`/`_settle`/`_roll_round_actions` 三函数删除 +- [ ] 宿主调用点改址:`_on_round_end` 末行→`_rounds.settle_if_due()`;begin_battle 与 `_exit_distribution` 的 `_roll_round_actions()`→`_rounds.roll_round_actions()`;diagnostic_snapshot settling 读→`_rounds.is_settling()`;`_begin_battle_fx_state` 踩雷清零→`_rounds.mines_hits = {"total": 0, "last": 0, "round": 0}`(赋值复位——语句时点逐字);`_book_negative_blast` 两写→`_rounds.mines_hits` +- [ ] 测试改指:trigger_cond_test :119/:126/:131(orch._mines_hits→orch._rounds.mines_hits);settle_segments_test :27(→oc._rounds._grant_seg);round_flow_skill_pool_test:1022 与 feat_vouchers_test 5 处(_grant_seg→_rounds._grant_seg) +- [ ] 新增断言 settle_segments_test.gd(接线检查段内嵌)〔编排归约 V1〕:oc._rounds 非空且 `_rounds.oc == oc`、五段段件齐在 _rounds、oc._facts 非空(规格见对照表) +- [ ] `game/tests/static_scan.sh` S8_FILES(:317)与 S7_B1_SET(:359)增行 `game/core/settlement/round_cycle.gd`(battle_facts.gd 零协作调用不入两清单) +- [ ] 孤立验证:`-- --only=round_flow_skill_pool,settle_segments,trigger_cond,seal_polarity,skill_unlock,roll_multiplier,variant_placement` 全绿+冒烟 + +**T3 宿主改形收束(0.5–0.75 工作日)**(取用:T1/T2 两件与成员名;产出:宿主 15 成员定着) + +- [ ] 宿主 `_rounds`/`_facts` 成员声明落位;已迁成员声明复核清零——类变量实测 15(第 3 节名单),禁无效成员 +- [ ] treasure_inventory 改址:宿主成员与 setter 转发块(:48-52)删除;四处读改指 `_reward_grant.treasure_inventory`(_hook_attune_consume/_reseed_attune_charges/装板薄壳叠加层退役/_battle_over 叠加层退役);`level_runner.gd:520` 改 `_settlement.reward_grant().treasure_inventory = treasure_inventory`(注入时序在宿主构造之后不变) +- [ ] _hero_atk 派生读:宿主新增私有函数 `_hero_atk() -> int`(返回 `int(_facts.encounter.get("hero_atk", int(db.combat.hero.atk)))`);受理段写入与 spawn override 改调;`combat_segment.gd:56` oc._hero_atk→oc._hero_atk();_hero_atk 成员删除 +- [ ] attune 读数出口核验:attune_has/attune_param_sum/attune_convert_state/_attune_charge_safe_row/_attune_safe_seen_read 读源改 `_facts.attunement`/`_facts.attune_safe_seen`——三个外部消费面(main.gd:567、treasure_interact_controller.gd:125、table_structure_guard_test/breakpoint_resume_test 起战断言)零改址零触碰 +- [ ] 新增断言 roll_multiplier_test〔编排归约 V4〕与 treasure_effects_test〔编排归约 V5〕(规格见对照表) +- [ ] 孤立验证:`-- --only=roll_multiplier,treasure_effects,breakpoint_resume,level_shop_economy,round_flow_skill_pool` 全绿+`python tools/run_system_test.py` + +**T4 键账对账与收口(0.25–0.5 工作日)**(取用:T0–T3 全部产出;产出:本批交付物) + +- [ ] `python tools/gdstyle_gate.py` 预检一次——宿主类变量 15、round_cycle 8、battle_facts 15、文件长 ≤1000(预期约 830)、零基线外新键;出超标键→按第 4 节随迁键收敛义务卡内拆助手后复检 +- [ ] 里程碑步出口跑全套闸:`bash tools/run_all_gates.sh --code` 全绿(改动全为代码面);闸 11 PARITY 触面按第 4 节条款——实跑对拍须用户批准发起、不得借机重锚,NEED-APPROVAL 时停步呈用户裁决 +- [ ] 键账对账:第 9 节预期逐键核;基线 refresh 由用户发令人工 `python tools/gdstyle_gate.py --refresh`(须 --force——全基线 16 键消失 ≥2 条触发骤降守卫;与姊妹卡同批编队时一次 refresh 合并执行) +- [ ] 产出物落位卡:`reports/iter-实现报告-<日期>.md`(各卡状态+实机目检总清单+实现决定记录+逐拆出单元职责语句一行)与 `reports/iter-反哺点-<日期>.md`(第 6 节同步面逐条落点)写齐方算收口 + +合计估时约 2.5–3.75 工作日(设计文档 §12 载 2–3 日;上探余量=测试改址逐处点名与 PARITY 批跑配合;PARITY 实跑须用户在场批准,不占卡估时)。切分预案:T1/T2 迁移函数出超标键需卡内拆助手时,超软盒预挂改由 T3 并 T4 吸收。 + +## 11. 验证闸——改动—验收对照表 + +域口径:本批改动全为 `game/` 下非 .md 行为载体——批末跑代码域闸(`tools/run_all_gates.sh --code`);里程碑步(T 段)出口跑一次全套闸,波内修复只做出红最小单元的最窄确认,新增测试先行孤立验证再并入全套。测试执行两入口铁规不破。三件保险(冒烟/系统测试/静态扫描)恒跑;02 单元与集成按关联档选套件(上表落点套件并集)。能力清单:本批零新增能力、零入口与代表用例名变更——能力行全部为既有名,零增删改(第 6 节)。**静态判据申报(不入对照表)**:键账收敛与静态随动(宿主 38→15、round_cycle 8/battle_facts 15、零基线外新键、static_scan.sh S7/S8 两清单增行)无运行时可观测提交面——判据=`python tools/gdstyle_gate.py` 与 `game/tests/static_scan.sh` 退出码(T4 执行),属静态判据+评审注记申报观测面局限(test-conventions §8.4 出口)。 + +| 行 | 需求点 | 改动(文件:行/行为) | 验收测试(名称+落点+尾缀) | 层级 | 真实入口 | 判据绑定面 | 能力行 | +|---|---|---|---|---|---|---|---| +| V0 | 行为零变化(本批总判据) | 全部结构改动(第 7 节清单) | PARITY 同种子完整局对拍(`tools/parity_anchor.py`,用户批准后实跑、禁重锚);关联套件零改址应绿 | 集成+对拍 | 真实局 begin_battle→挖掘→结算→终局 | step_row/settlement_snapshot 逐位一致——差异非零即停机呈报 | 既有:回放确定性(同种子三变体逐位) | +| V1 | 两新件建件接线(T1/T2) | battle_facts.gd/round_cycle.gd 新建;宿主 _init 建件接线;五段构造迁 round_cycle | 新增 settle_segments_test.gd 接线检查段内嵌〔编排归约 V1〕:`oc._rounds` 非空且 `_rounds.oc == oc`;五段段件齐在 `_rounds`;`oc._facts` 非空 | 单元 | BattleOrchestrator 直构(settle_segments_test 现行夹具同款) | 编排器接线面(新件在座与宿主回指——接线断言本体) | 既有:轮内流与结算五段全序 | +| V2 | reset_round 复位边界(险点) | battle_facts.reset_round 只清三缓冲;宿主三调用点改调 | 新增 round_flow_skill_pool_test.gd:_smoke_full_battle 内嵌〔编排归约 V2〕:终局后 `presentation_snapshot()["refresh_used"]` == 末轮结算 snapshot `economy.refresh_used` | 单元 | begin_battle→轮内刷新→停手→结算→终局 | 两快照同键值恒等(复位不碰 refresh_used 的可观测提交面) | 既有:轮内流与结算五段全序;既有:停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励) | +| V3 | 段驱动与摇号迁移(重入门闸/settle_if_due/roll_round_actions/mines_hits 账) | 三函数迁出宿主;宿主调用点改址;trigger_cond_test 3 处改指 | 复用 round_flow_skill_pool_test 全套(_smoke_full_battle/_smoke_settlement_segments/_smoke_skill_pool_replay_independence)、settle_segments_test V4-3 真实一轮、skill_unlock_test、trigger_cond_test(改指后应绿)——零新增断言 | 单元 | begin_battle;stop→WAITING→settle_if_due | 五段裁定行序+settling 闸+终局早退+同种子摇定逐位(behavior_roll 流随件零漂移由既有回放断言钉住)+mines_hits 转存读数 | 既有:轮内流与结算五段全序;既有:技能池数据面与回放独立;既有:Boss 半血解锁技门控 | +| V4 | _hero_atk 派生读 | 成员删→私有函数;combat_segment.gd:56 改调 | 新增 roll_multiplier_test.gd(既有主角攻击链函数内嵌)〔编排归约 V4〕:enc 携 `hero_atk` override 起战→主角攻击单 base_value==override;缺省→base_value==hero 表值 | 单元 | begin_battle(enc)→战斗段主角先手 | 主角攻击单基值(受理后派生值恒等的判据本体) | 既有:伤害公式与掷点乘区 | +| V5 | treasure_inventory 注入改址 | level_runner.gd:520 改经 reward_grant() 出口;宿主四处读改指;宿主 setter 转发块删 | 新增 treasure_effects_test.gd(秘宝使用链内嵌)〔编排归约 V5〕:注入后 `current_battle().reward_grant().treasure_inventory` 与关卡库存同一引用,且 use_treasure 受理走通 | 单元 | LevelRunner 建战注入→use_treasure 四步 | 注入引用同一性+受理面走通(改址后消费面不断链) | 既有:秘宝结构冻结与 12 件效果 | +| V6 | 封印判定账/装板溯源/受理事实迁移(完美写口升级、attune 状态随件) | 事实族改指(grant_segment 约 23 处+测试);三 mark 写口;attune 读源改 _facts | 复用 seal_polarity_test 全套、feat_vouchers_test(契约 2 计数纯净 R2)、variant_placement_test、meta_progression_forge_test、adventure_feats_test、table_structure_guard_test(attune 面零改址应绿——本批最硬的外部面零变化证)——零新增断言 | 单元 | 封印动作→结算;begin/refresh/exit 装板;begin_battle(enc) | 完美三账读数+去重闸+契约 2 计数纯净;刷新图零清图奖励+board_seq;enc 携带键贯通;attune_has/param_sum/convert_state 外部面零变化 | 既有:封印与极性路由/不可逆;既有:清图奖励双份与零路径;既有:变异布置门控;既有:专长(奇物)授予与凭证保底;既有:元进度入账与锻造两轴;既有:装板与开局免费展开(封锁格无资源、计入清图) | + +反向核对:diff 中每个行为载体改动均有行——本批申报**行为改动零条**(全部为非行为改动:成员迁移与调用点改指,判断依据=V0 同种子逐位一致证明+既有断言面零改址应绿;完美写口升级=同一时点同一增量改经方法单点,语义逐字)。新增断言四条(V1/V2/V4/V5)全部挂行;孤儿断言零条。测试削弱申报见第 15 节。 + +## 12. 基线纪律(S13 键账) + +1. 本卡键账目标=battle_orchestrator 类变量键归绿(实测 15 后随 refresh 消失);文件长键已由轴丙(迭代 42)归绿,本卡保持文件长 ≤1000(预期约 830)。 +2. 禁为过闸 refresh 换绿:基线重生成只由用户发令,批末键账对账后人工 `python tools/gdstyle_gate.py --refresh` 一次执行(禁闸内自动重生成、禁实现批中途 refresh)。 +3. 重锚守卫:新基线键数较旧基线少逾 10% 须 `--force` 显式确认——本批与轴丙预期合计消失 ≥2 条(16 键基线),须带 `--force` 由用户执行。 +4. 还债=数值下降自然绿:迁移后同键数值下降不判红;出现恶化(同键数值较登记值上升、基线外新键)=停卡呈报,禁自行消化。 +5. S13 豁免第三条(battle_orchestrator max-class-variables,architecture v1.25 已预写注销句)随本批达成生效——未达成=停卡呈报,非落文事项。 + +## 13. MC/数值与 RNG 零触碰声明 + +本批零数值改动、零数据表改动、零 RNG 流词表改动、零玩法字面量引入——结构整改不改数值与 RNG 消费序。behavior_roll 封闭流随件迁移取号序不变(流名、开流时点、取号序逐字)。数值与 RNG 零触碰则 MC 零跑;battle_orchestrator.gd 触 PARITY_TOUCH_FACES——实跑对拍须经用户批准、不得借机重锚(批末闸 11 判 NEED-APPROVAL 时由用户裁决:批准实跑或裁跳过,卡内不定案)。 + +## 14. 异常分级 + +- **L1 自救**:改指漏改编译错、测试寻址漏改——就地修复重跑最窄确认。 +- **L2 记录继续**:实测行数/改指处数与设计文档「约」值区间偏离、头注指址微调——记入实现报告「实现决定记录」。 +- **L3 停机写报告等用户**:①机检预算互斥——两新件实数超第 9 节预算、BattleFacts 需增员、或迁移函数现出超标键=上游缺陷停卡退回写卡段(禁自造第三条路);②encounter 归属被实现期证伪——受理事实与轮 facts 复位节奏冲突实锤、且设计文档 §6.3 两条砍路均破冻结面(宿主 16 不可达)=停卡呈报走判据④通道;③T0 对账不符(成员去向对不上、基线出现函数级键、file:line 漂移过大);④V0 对拍差异非零(行为零变化被证伪);⑤PARITY 触面处置分歧;⑥断言面被下游兜底吸收致判据绑不上(按 test-conventions §8.4 出口呈报);⑦S13 键恶化或基线外新键。 + +## 15. 测试削弱申报(允许改动的旧断言及理由) + +零申报——本批不删任何断言、不改判据阈值、不缩扫描面、不把真实入口换成下层直调;测试改指只动成员寻址(断言条件与期望值零变化);新增断言四条(V1/V2/V4/V5,全部内嵌既有函数)。未申报的削弱由独立验收审计判红。 + +## 16. 独立验收审计 + +合并前由未参与实现的会话或子代理执行;报告落 `reports/iter-验收审计-<日期>.md`。审计至少做四件事(test-conventions §8.7):逐行核对第 11 节对照表(测试存在、真执行、尾缀可 grep、真实入口未绕过改动点);抽查判据绑定面(V2 两快照同键、V4 攻击单基值、V5 引用同一性——当轮真实跑批执行过);检查测试削弱(对照第 15 节零申报);核对全部「非行为改动」判定依据(零漂移证明是否在当轮真实跑批中成立、PARITY 批准凭据在案)。未过不得合并。 + +## 17. 代拍板白名单(允许 agent 自行拍板的微决策) + +1. 迁移函数与改指处头注/行注的指址微调(词表与语义不动——「指址须真」纪律)。 +2. 调用面改指的机械改写(排版、注释同步、行内换行)。 +3. 断言失败消息尾缀编号分配与措辞(〔编排归约 Vn〕系列)。 +4. 新件私有成员与小函数命名微调(职责语义不变、公有面契约名逐字不动)。 +5. 宿主 _init 内两新件建件语句的次序微调(约束不变:_facts 无依赖先建、_rounds 在两件建齐与 bind 接线之后)。 + +超清单决策记入实现报告「实现决定记录」节。 + +## 18. 待裁点 + +零待裁点——五项待裁点(设计文档 §13)已由用户 2026-10-29 全裁闭合(第 2 节裁决记录),完美账写口升级已按推荐案采纳落卡。**零待裁点,开工门=U0**。编队前置:迭代 42(gdstyle 尾波清偿批,含轴丙 BoardInstaller)合回之后开工;T0 按当轮 master 重测对账。 diff --git a/reports/需求卡片-组合根注册面批-2026-10-29.md b/reports/需求卡片-组合根注册面批-2026-10-29.md new file mode 100644 index 00000000..d93b748b --- /dev/null +++ b/reports/需求卡片-组合根注册面批-2026-10-29.md @@ -0,0 +1,336 @@ +# 需求卡片——组合根注册面批(main.gd 类变量归 15:界面注册面+三域句柄容器) + +状态行:v1.0 定稿——零待裁点(2026-10-29 用户裁:注册面拓扑一门面+三域容器、合同机器迁入、别名消灭清单整体确认;实现层细目授权 agent 按设计文档执行) + +接收方:待办清单条目「零豁免五键清偿批——S13 余量五键真修四卡(2026-10-29 登记,来源=会话提及)」——本卡为其四卡之首(组合根注册面批)。 + +来源:reports/设计-组合根注册面-2026-10-29.md(2026-10-29 设计闭合,**唯一事实源**);architecture 权威=design/engineering/architecture/architecture.md v1.25(2026-10-29——「模块归属·呈现层」表 ui_registry 行、「呈现层装配与会话生命周期」节屏成员寻址迁注册面句=原 S13 豁免登记注销、RunScope 节)。 + +## 1. 目标与完成定义 + +这批做什么:把 main.gd(组合根)里散着的屏壳、覆盖层一级句柄与视觉层合同表收进一个「界面注册面」——一个不挂树的 RefCounted 门面件(ui_registry.gd)加三个按领域分的句柄容器(ui_screens/ui_battle/ui_modals),探针和系统测试对界面元素的引用从 `main.X` 一级地址改成 `main.ui.<域容器>.<句柄>` 三段式地址。同时消灭 7 个探针兼容别名/转发成员、退役 6 个 main 纯转发模态方法。main.gd 类变量从 49 降到 15,S13 基线键真实还债,architecture 在册的 S13 豁免登记随批注销。 + +**行为零变化**:装配序、信号接线、层序(树序=登记序=z 序)、RunScope 会话生命周期、RNG 消费序全部零变化;探针断言只换地址、不换判据。 + +完成定义(全部满足才算完): +1. 五闸主证全绿——probe_gate 默认段+`--click`+`--full`、render_gate golden 零差异、run_smoke、run_system_test、run_all 02 单元与集成(main.gd 触组合根=横切面,按 AGENTS.md 关联档口径回落全部套件)。 +2. static_scan 过——四新文件零新基线键(S9 全类型标注、S10 头注);main.gd 类变量实测 15(键账对账批末申报,基线 refresh 由用户发令)。 +3. 改址完整性自检——按 49 名逐名 grep,`game/` 下旧一级路径 `main.<旧名>`/`root.<旧名>`/`self.<旧名>` 残留=0,报告留档。 +4. 产出物落 `reports/`——实现报告、反哺点清单、验收审计报告(独立审计未过不合并)。 + +**编队注记与估时**:本卡与「战斗编排归约批」(battle_orchestrator 拆 RoundCycle/BattleFacts 两件——architecture v1.25 轴丁设计闭合、待写卡)和「测速循环批」(tune_sim_controller 步进状态机——architecture v1.25 S13 测量面豁免注销设计闭合、待写卡)同代待编排;三批无同文件交叠(本批触面=main.gd+main_ui_build+三流程件+探针/测试面)。与迭代 42(在飞:gdstyle 尾波清偿批+level_runner 商店委托层拆除)无文件交叠(main.gd 与探针不在其触面),**T0 复核义务照写**。估时区间 **3–4 个工作日**(设计文档 §8),低于迭代冻结线(5 个工作日),可编批;编入哪个迭代由迭代编排段定。 + +## 2. 现状事实 + +全部行号为 **2026-10-29 实查——本批编入在 gdstyle 尾波补件批相关迭代之前/之后均须 T0 按 T0 时点 master 重测重锚**。 + +1. `game/presentation/main.gd`(915 行)共 **49 个类变量**(逐名清点 main.gd:61–148,含 3 个委托属性);S13 基线键 `game/presentation/main.gd|quality/max-class-variables = 49`(阈值 15)在 tools/gdstyle_baseline.txt 在册,architecture v1.25 在册 S13 豁免登记〔2026-10-27「组合根类变量面即探针契约面」〕已随 v1.25 注销、待本批真实还债。 +2. 视觉层合同机器四样全在 main.gd:`LAYER_CONTRACT` 常量(main.gd:39–59,19 项含 host/shell/tags 标注)、`_apply_layer_contract()`(main.gd:254–279,全仓唯一 move_child 落位点)、`_layer_node(key)`(main.gd:227–248,19 键 match)、`_register_modal(m, tags)`(main.gd:218–224,anchors preset+flow.register)。 +3. 探针兼容别名/接缝成员 7 个:`board_view`(main.gd:95)、`ap_bar`(main.gd:96)——赋值点 main_ui_build.gd:48–49;`_modals`(main.gd:129,赋值 main_ui_build.gd:245);`_row_queue`(main.gd:111–113,委托属性读 `_row_pacer.pending_rows()`);`_seed_edit`(main.gd:74,赋值 main_ui_build.gd:208);`_settlement_stop_pending`(main.gd:134–143,读=is_armed()/写=arm()/disarm());`_deferred_modal`(main.gd:148–150,读 `_modal_flow._deferred`)。 +4. main 纯转发模态方法 6 个:`_open_modal_after_playback`(main.gd:156–158)、`_on_pump_ended`(main.gd:161–163)、`_open_modal`(main.gd:282–284)、`_close_modal`(main.gd:285–287)、`_on_modal_closed`(main.gd:288–290)、`_input_locked`(main.gd:292–295)——各自一行转呼 `_modal_flow` 真方法。 +5. 装配承接件 main_ui_build.gd:`build(root)` 八步(main_ui_build.gd:21–29),赋值目标全走 `root.X` 一级成员(main_ui_build.gd:38–51 等);`pump_ended` 注入点 main_ui_build.gd:62;context 束注入 `open_modal/close_modal`(main_ui_build.gd:144、168);`_apply_layer_contract()` 末位调用 main_ui_build.gd:247。 +6. 消费面引用量(设计文档 §0 机械统计,T0 实跑重计):探针+系统测试 `main.X` 成员引用约 **867 处**;四个流程承接件(main_adventure_flow/main_overlay_flow/main_debug_flow/main_ui_build)`root.X` 引用约 200–350 处(设计文档 §0 与 §3.2 两处统计口径不一,以 T0 映射表脚本实跑计数为准)。抽查实证:ui_input_probe.gd:34–43(seed_edit/level_screen)、system_test.gd:94–109(LAYER_CONTRACT、_layer_node、V2 句柄等价五连比)、smoke_boot.gd:68–75(`main.get()` 6 处)、pacing_queue_test.gd:108/132/147/149(`_row_queue` 3 处+`board_view` 1 处)、source_guard_test.gd:69–77(V1d 层序单口断言,现扫 main.gd 单文件)、theme_projection_test.gd:724–725(V6 断言 main.gd 含 `debug_overlay.diagnose_requested.connect(_on_diagnose_pressed)` 串)。 +7. 留 main 的 14 成员(对账见表 B)全部是组合根自身状态、组合根拆件引用、autoload 读视图;`run_scope` 引用(探针约 173 处)零迁移。 +8. 探针段构成(architecture「测试与质量域」probe_gate 行):默认段 ui_input_probe/ui_struct_probe/layout_probe/ui_contrast_probe/screen_flow_probe,`--click` 加 ui_click_probe,`--full` 加 ui_probe/ui_tune_probe/t17_defer_probe/fx_probe。 +9. meta_progression_forge_test 经 `load("res://presentation/main.gd")` 直呼 static `build_adventure_params`——留 main,零迁移(main.gd:366–376)。 +10. 本批不涉 RNG/数值/存档触面;PARITY 触面(battle_orchestrator.gd)不在 diff,无 MC 义务。 + +## 3. 设计契约(违反即返工,标 🔴 触碰=L3 停机呈报) + +- 🔴 **行为零变化**:装配序与 add_child 顺序、信号连接语句逐条不变;层序合同表条目、顺序、tags、host/shell 标注**逐字零变化**只换宿主文件;`_begin_session`/闲时会话/整节点 queue_free 机制一字不动;RNG 消费序零触碰;呈现层订阅禁令与核心写调用唯一出口纪律零触碰。 +- 🔴 **探针断言语义零变化**:改址只换地址不换判据——断言条件、尾缀(既有〔装配生命批 V1〕〔装配生命批 V3〕等保留)、消息语义不动;禁借改址删断言、放宽阈值、缩小扫描面。 +- 🔴 **拆分边界纪律五条**(判据权威=code-conventions §1.1,此处写红线不复制定义):①每个拆出单元须有可陈述的职责语句与单一变化原因(四件各一句,见 §12 表,实现报告逐件一行承载);②拆出单元须有集体身份——命不出名字、只能说「剩下的成员」的打包=凑计数袋,禁;③「过阈值(49→15)」只许作发现信号,作拆分或收拢动机即违规;④按纪律拆不出内聚单元→停卡呈报走豁免通道,禁硬拆凑绿;⑤禁保留/新增无效成员与别名凑数——本批方向是净消灭(7 成员+6 方法),实现期发现任何「为保地址兼容」新增的转发壳即违契约。 +- 🔴 **禁为机检文本保留无效成员**:禁止为迎合机检消息文本(含计数)而保留或新增无效成员/别名;机检键与本卡契约互斥时(如实测出新基线键 NEW 红)一律停卡呈报,不得自造第三条路(详见 §13 条款节)。 +- 🔴 **测试削弱申报制**:允许改动的旧断言全集见 §8「测试削弱申报」,未申报的删改由独立验收审计判红。 + +## 4. 范围边界 + +做:ui_registry+三域容器建件;合同机器四样迁驻;main.gd 49→15 改形;main_ui_build 与三流程件改址;探针九件+probe_ui_util+smoke_boot+system_test+pacing_queue_test 改址;V1d/V6 源码断言重锚;七别名与六转发方法消灭。 + +不做(明示去向): +1. architecture.md 直改——实现批禁写 `design/`,ui_registry 行现状化与 main_ui_build 行层序句改指走反哺点通道(§6)。 +2. game/tests/README.md 改动——实现批禁写;写卡段义务已核=零增删零改行(§6)。 +3. modal_stack.gd/modal_flow.gd 语义改动——两件零触碰,本批只改它们的消费方地址。 +4. RunScope/会话生命周期机制、row_pacer 排播时序、T17 挂起编排——零触碰。 +5. S13 豁免登记第二/三条(tune_sim_controller、battle_orchestrator)——原文不动,归「战斗编排归约批」「测速循环批」。 +6. board_cell_unit/standee_body/board_view 悬停域等结构债——归迭代 42 尾波清偿批,不收件。 +7. 基线 refresh——`python tools/gdstyle_gate.py --refresh` 由用户发令人工跑(净减 1 键,低于 10% 骤降守卫,无需 --force);实现批只做键账对账申报。 +8. MC/数值验证——无数值改动零跑。 + +## 5. 关联文档同步面 + +| 文档 | 关联点(本批实现会改变它的哪条陈述) | 同步义务 | +|---|---|---| +| design/engineering/architecture/architecture.md(设计权威——实现批禁直改) | ①「模块归属·呈现层」ui_registry 行现登记「实现批建件」态,实现后应现状化;②同表 main_ui_build 行「层序逻辑不在此件——唯一事实源仍是 `main.LAYER_CONTRACT` + `_apply_layer_contract()`」句在实现后失效(唯一事实源迁 ui_registry.LAYER_CONTRACT+ui.apply_layer_contract());③「呈现层装配与会话生命周期」节屏成员寻址迁注册面句 v1.25 已落、实现后核对措辞与实况一致 | 反哺点通道:把上列 ①②③ 逐条列进 `reports/iter-反哺点-<日期>.md`(改哪一节、改成什么、依据=设计文档 §3.3 建议句),用户在会话中裁决后归文档批落文 | +| game/tests/README.md(机械面——实现批禁写) | 本批零新增能力(改址只换地址,能力集不变);受影响存量行核对:「模态覆盖层编排与输入锁」行真实入口(ModalFlow 两个公开方法)与代表用例(modal_flow_test.gd:_init 等)不变;「结算明细带逐行呈现与排播节奏」行代表用例 pacing_queue_test.gd:_init 不变(`文件:函数` 锚不受成员改址影响) | 写卡段义务已当场核完=**零增行、零删行、零改行**;批末收尾只核对表上名字与实际落地一致(改名则回表) | +| design/gdd/ 无关联文档 | 行为零变化,任何系统文档陈述不受影响;层序唯一事实源属 architecture 不属 GDD | 无(本行占位——按规约查不出也要写明) | + +## 6. 卡前文件结构图(本批新建/修改文件全列) + +| 文件 | 职责 | 新增/复用 | 行为改动? | +|---|---|---|---| +| game/presentation/ui_registry.gd | 界面注册面门面:三容器属性+LAYER_CONTRACT+node(key) 合同寻址+apply_layer_contract(root) 唯一落位口 | 新增(预检 §12) | 非行为改动(新建件承载既有合同——落点变化,对照表行 1/2) | +| game/presentation/ui_screens.gd | 屏壳与全屏容器域句柄册(9 成员) | 新增(预检 §12) | 非行为改动(对照表行 3) | +| game/presentation/ui_battle.gd | 战区视图域句柄册(5 成员) | 新增(预检 §12) | 非行为改动(对照表行 3/4) | +| game/presentation/ui_modals.gd | 模态层域句柄册+ModalFlow 持有+register_layer(14 成员) | 新增(预检 §12) | 非行为改动(对照表行 3/7) | +| game/presentation/main.gd | 组合根改形:49→15;合同机器与转发方法迁出;内部取址改 ui.*;头注追加注册面句 | 修改 | 非行为改动(纯结构——装配/接线/层序/RNG 零变化,四闸主证;对照表行 2/6/7) | +| game/presentation/main_ui_build.gd | 八步赋值目标改 root.ui.*;context 束与 pump_ended 注入改址;_seed_edit/_modals 赋值行退役 | 修改 | 非行为改动(八步顺序/add_child 序/连接语句逐条不变;对照表行 3) | +| game/presentation/main_adventure_flow.gd/main_overlay_flow.gd/main_debug_flow.gd | root.X 同表映射(模态口改指 root.ui.modals.flow;句柄读改 root.ui.*) | 修改 | 非行为改动(对照表行 3/7) | +| game/probe/ 九探针+probe_ui_util.gd(凡 T0 映射表命中的 main.X 引用件) | 旧地址→main.ui.* 机械改写 | 修改 | 非行为改动(断言语义零变化;对照表行 4/6) | +| game/tests/smoke_boot.gd | get() 键改址(4 改 2 留) | 修改 | 非行为改动(对照表行 3) | +| game/tests/system_test.gd | main.X 改址(V1a/V1c/V2 句柄等价/V3 矩阵取址两处) | 修改 | 非行为改动(判据零变化;对照表行 1/5) | +| game/tests/unit/contracts/source_guard_test.gd | V1d 重锚(单文件扫描→全目录扫描,判据强化) | 修改 | 非行为改动(断言改写已申报;对照表行 8) | +| game/tests/unit/presentation/theme_projection_test.gd | V6 断言串改新连接串 | 修改 | 非行为改动(断言改写已申报;对照表行 9) | +| game/tests/unit/presentation/pacing_queue_test.gd | board_view/_row_queue 改址(3+1 处) | 修改 | 非行为改动(对照表行 6) | + +不触碰:modal_flow.gd/modal_stack.gd/row_pacer.gd/ui_assembler.gd/run_scope.gd/meta_progression_forge_test.gd(static 入口零迁移)/全部 core 与 data。 + +## 7. 任务卡 T0..T4 + +### 7.1 地址契约(全批唯一映射依据——表 A/B/C/D 与设计文档 §1.2 对账表同源) + +**表 A:迁入注册面的 28 个 main 成员**(容器内成员名去下划线=公共地址面): + +| 现成员(2026-10-29 行号) | 新地址 | 现成员 | 新地址 | +|---|---|---|---| +| `_menu_screen`(:100) | ui.screens.menu_screen | `legend_overlay`(:116) | ui.modals.legend_overlay | +| `_camp_screen`(:101) | ui.screens.camp_screen | `node_overlay`(:117) | ui.modals.node_overlay | +| `_adventure_screen`(:102) | ui.screens.adventure_screen | `level_screen`(:83) | ui.modals.level_screen | +| `_start_overlay`(:79) | ui.screens.start_overlay | `curio_overlay`(:78) | ui.modals.curio_overlay | +| `_battle_root`(:84) | ui.screens.battle_root | `_end_overlay`(:80) | ui.modals.end_overlay | +| `_inter_overlay`(:81) | ui.screens.inter_overlay | `shop_overlay`(:118) | ui.modals.shop_overlay | +| `_inter_label`(:82) | ui.screens.inter_label | `camp_overlay`(:119) | ui.modals.camp_overlay | +| `debug_badge`(:126) | ui.screens.debug_badge | `settings_overlay`(:121) | ui.modals.settings_overlay | +| `_row_pacer`(:105) | ui.screens.row_pacer | `status_panel`(:122) | ui.modals.status_panel | +| `stage`(:91) | ui.battle.stage | `career_overlay`(:123) | ui.modals.career_overlay | +| `log_view`(:92) | ui.battle.log_view | `save_select_overlay`(:124) | ui.modals.save_select_overlay | +| `info_panel`(:93) | ui.battle.info_panel | `confirm_dialog`(:75) | ui.modals.confirm_dialog | +| `board_zone`(:94) | ui.battle.board_zone | `debug_overlay`(:125) | ui.modals.debug_overlay | +| `settlement_fx`(:97) | ui.battle.settlement_fx | `_modal_flow`(:128) | ui.modals.flow | + +**表 B:留 main 的 14+1**:db、run_scope、save_manager、meta、settings_store、logger、_debug_entry、_confirm_consumer、_confirm_consumer_slot、_debug、_treasure_ui、_bonus、_camp_pres、_tune_sim(保留理由逐个=组合根自身状态/拆件引用/autoload 读视图,见设计文档 §1.2 第二表)+新增 `ui: UiRegistry`。改后 15,恰在阈内。 + +**表 C:消灭的 7 个别名/接缝成员**: + +| 成员 | 本体 | 消灭后地址 | +|---|---|---| +| board_view(:95) | =board_zone.board_view | ui.battle.board_zone.board_view | +| ap_bar(:96) | =board_zone.ap_bar | ui.battle.board_zone.ap_bar | +| _modals(:129) | =_modal_flow.stack | ui.modals.flow.stack | +| _row_queue(:111) | 委托属性=_row_pacer.pending_rows() | ui.screens.row_pacer.pending_rows()(同一 Array 引用,语义不变) | +| _seed_edit(:74) | =debug_overlay.seed_edit | ui.modals.debug_overlay.seed_edit.text(main._seed_value 唯一消费点) | +| _settlement_stop_pending(:134) | 委托属性读=is_armed()写=arm()/disarm() | run_scope.settlement_stop_timer 直呼同名面 | +| _deferred_modal(:148) | 委托属性=_modal_flow._deferred | ui.modals.flow._deferred | + +**表 D:方法/函数级改址**: + +| 旧地址 | 新地址 | 消费方 | +|---|---|---| +| main._layer_node(key) | main.ui.node(key) | system_test V1c(实查 source 点 system_test.gd:97;设计文档记 3 处——T0 重计) | +| main._register_modal(m, tags) | ui_modals.register_layer(m, tags)(逐字迁入:anchors preset+flow.register) | 仅 _apply_layer_contract 内部消费,随迁 | +| main._apply_layer_contract() | main.ui.apply_layer_contract(root)(root 作参传入,main_ui_build.gd:247 调用点改) | 装配尾唯一调用点 | +| main._open_modal(m) | main.ui.modals.flow.open(m) | 探针各 1 处+流程件 root. 共约 23 处(T0 重计);main 内部调用点(_on_confirm_accepted 等)同改 | +| main._close_modal(m)/main._on_modal_closed(m) | main.ui.modals.flow.close(m)(信号 bind 目标 main_ui_build.gd:99/209 改 flow.close.bind) | 同上 | +| main._input_locked() | main.ui.modals.flow.locks_input() | 探针 18 处(T0 重计)+main._on_board_action/_on_stop_pressed/_on_refresh_confirmed 内部 | +| main._open_modal_after_playback(m) | main.ui.modals.flow.open_after_playback(m) | 流程件 root. 2 处+探针(T0 重计) | +| main._on_pump_ended | main.ui.modals.flow.pump_ended | row_pacer.pump_ended 注入点 main_ui_build.gd:62 | +| smoke_boot `main.get("_start_overlay"/"debug_badge"/"legend_overlay"/"status_panel")` | `main.get("ui").<域>.<名′>`(get 只解析一层,后续走公共字段) | smoke_boot.gd:70/73/74/75;`get("run_scope")`/`get("settings_store")` 零迁移 | +| source_guard V1d 串 | 重锚:扫全 `game/presentation/*.gd`,`move_child(` 只允许出现在 ui_registry.gd 的 apply_layer_contract 函数体内(从扫单文件变扫全目录——判据强化) | source_guard_test.gd:69–77 | +| theme_projection V6 串 | 改断言新串 `ui.modals.debug_overlay.diagnose_requested.connect(_on_diagnose_pressed)`(连接语句本体随 T2 改写 main.gd:209) | theme_projection_test.gd:724–725 | + +### 7.2 新件接口块(T1 定义,T2 起逐字取用;类型标注义务=S9 过) + +``` +# game/presentation/ui_registry.gd —— 界面注册面(RefCounted,不挂树,零信号连接,零会话期引用) +class_name UiRegistry +extends RefCounted +const ModalStack := preload("res://presentation/modal_stack.gd") +const LAYER_CONTRACT: Array[Dictionary] = [ …main.gd:39-59 内容逐字迁入,一项不增不减不改… ] +var screens: UiScreens +var battle: UiBattle +var modals: UiModals +func node(key: String) -> Node # 合同寻址:_layer_node 的 19 键 match 逐字迁入 +func apply_layer_contract(root: Control) -> void # 落位算法逐字搬运(move_child 单口;登记经 modals.register_layer) + +# game/presentation/ui_screens.gd —— 屏壳与全屏容器域(RefCounted,纯字段无方法) +class_name UiScreens +extends RefCounted +var menu_screen: Control +var camp_screen: Control +var adventure_screen: Control +var start_overlay: Control +var battle_root: Control +var inter_overlay: Control +var inter_label: Label +var debug_badge: Button +var row_pacer: RowPacer # 经 preload 常量取型(res://presentation/row_pacer.gd 非 class_name 全局) + +# game/presentation/ui_battle.gd —— 战区视图域(RefCounted,纯字段无方法) +class_name UiBattle +extends RefCounted +var stage: BattleStageView +var log_view: BattleLogView +var info_panel: HeroInfoPanelView +var board_zone: BoardZoneView +var settlement_fx: SettlementFxView + +# game/presentation/ui_modals.gd —— 模态层域(RefCounted) +class_name UiModals +extends RefCounted +var flow: ModalFlow +var legend_overlay: LegendOverlay +var node_overlay: NodeOverlay +var level_screen: LevelMapScreen +var curio_overlay: CurioPickOverlay +var end_overlay: BattleEndOverlay +var shop_overlay: ShopOverlay +var camp_overlay: CampOverlay +var settings_overlay: SettingsOverlay +var status_panel: StatusPanel +var career_overlay: CareerOverlay +var save_select_overlay: SaveSelectOverlay +var confirm_dialog: ConfirmDialog +var debug_overlay: DebugOverlay +func register_layer(m: Control, tags: Array = []) -> void # _register_modal 逐字迁入 +``` + +(main.gd 现有类型标注逐字沿用:ui_battle/ui_modals 十八句柄的类型名=main.gd:78–125 在用全局类名;ui_screens 三屏壳标 Control,若 T1 实测场景根基类不符,按代拍板白名单第 6 条取实际基类。) + +### 7.3 T0——读数重锚与对账(估时 0.5 个工作日) + +- [ ] 按 T0 时点 master 重测重锚本卡全部行号与计数:main.gd 类变量实数(gdstyle 读数)、合同机器四样行位、七别名与六转发方法行位、六转发方法的全部调用点清单(main 内部+流程件+探针+system_test 分文件计数)。 +- [ ] 49 成员逐一对账:对照本卡表 A/B/C 逐名核对仍在位、仍归该档(迁移 28/留 14/消灭 7)——任何一名对不上=L3 停卡呈报(设计文档 §1.2 对账表为第二依据)。 +- [ ] 映射表脚本生成+对账:探针九件+probe_ui_util+smoke_boot+system_test+四流程件的 `main.X`/`root.X` 全量计数与旧→新映射(机械生成+人工复核语义位——属性读写约 750 处、方法调用四类、字符串键 6 处、源码断言 2 条);设计文档 867/350/200 三处统计口径以本次实跑为准并在实现报告记数。 +- [ ] 未登记源码断言排查:grep `presentation/main.gd` 于 game/tests+game/probe 全部源码断言面——只许 V1d/V6 两条命中;新发现=L3 停卡补申报,禁自行改判。 +- [ ] 迁移函数对账:查 tools/gdstyle_baseline.txt 中 main.gd 的 `_apply_layer_contract`/`_layer_node`/`_register_modal` 源函数键——branches/returns/函数长有超默认登记值的,迁移即拆函数(拆分不改语义)。 +- [ ] 孤立验证(改前基线读数):`python tools/gdstyle_gate.py`(采集 main.gd=49 读数)+`godot --headless --path game --script res://tests/run_all.gd -- --only=source_guard`(绿)。 +- 取用:本卡 §7.1 四表。产出:重锚后的映射表与对账表(实现报告附件节,T2/T3/T4 消费)。 + +### 7.4 T1——注册面与三域容器建件(估时 1 个工作日) + +- [ ] 按 §7.2 接口块建 ui_registry.gd:LAYER_CONTRACT 自 main.gd:39–59 逐字迁入(ModalStack 常量引用随迁);`node(key)` 19 键 match 逐字;`apply_layer_contract(root)` 落位算法逐字搬运(move_child 单口语义不变)。 +- [ ] 建 ui_screens/ui_battle/ui_modals(成员与类型按 §7.2;ui_modals.register_layer 自 main.gd:218–224 逐字迁入);四件全类型标注、`_init` 不收参(容器由门面构造)。 +- [ ] 四件 class_name(UiRegistry/UiScreens/UiBattle/UiModals)+跑一次编辑器扫描刷新全局类缓存+同步 .uid(code-conventions 语言纪律 5——T2 main.gd 类型标注 UiRegistry 在 --script 模式可解析的前置);文件头 `##` 注释介绍模块(禁变更叙事、禁文档反向链接)。 +- [ ] 孤立验证:`game/tests/static_scan.sh`(S9 四新件零红+S10 头注过+S13 四新件零新键)+`godot --headless --path game --script res://tests/run_all.gd -- --only=source_guard`(V8 全库扫描仍绿——新件零字符串 Callable)。 +- 取用:T0 映射表。产出:四件公开面(UiRegistry.new()/.screens/.battle/.modals/.node(key)/.apply_layer_contract(root)/modals.register_layer(m, tags)——T2 逐字消费)。 + +### 7.5 T2——main.gd 改形与装配/流程件改址(估时 1–1.5 个工作日) + +- [ ] main.gd 新增 `var ui: UiRegistry`;`_ready` 在 `_build_ui()` 之前 `ui = UiRegistry.new()`(容器随门面构造;装配在 _ready 建闲时会话之前完成——时序零变化)。 +- [ ] 表 A 28 成员迁出:main 内部全部取址同步改 `ui.*`(含 main.gd:199–200 启动态两行、_seed_value:911、_on_confirm_accepted/_start_adventure/_resume_from_menu/_replay_locked_click 等内部调用点改指 ui.modals.flow.*/ui.screens.row_pacer.pending_rows());合同机器四样自 main 删除(随 T1 迁驻)。 +- [ ] main_ui_build.gd:八步赋值目标改 `root.ui.<域>.<名′>`(八步顺序、add_child 顺序、连接语句逐条不变);`root._seed_edit` 赋值行(:208)删除;`pump_ended` 注入改 `root.ui.modals.flow.pump_ended`(:62);`root._modals` 赋值行(:245)保留至 T4;context 束 overlay/toast/start_overlay/board_view 键值改址(:137–147、:163–169,注入时点与值不变);`_apply_layer_contract` 调用改 `root.ui.apply_layer_contract(root)`(:247)。 +- [ ] 三流程件 root.X 按表 A/D 同表映射(root._open_modal/_close_modal/_open_modal_after_playback/_input_locked → root.ui.modals.flow.*;`_settlement_stop_pending` 写点改 `run_scope.settlement_stop_timer.arm()/disarm()`——写点计数 T0 对账)。 +- [ ] smoke_boot.gd get() 改址(4 改 2 留,§7.1 表 D)。 +- [ ] source_guard_test.gd V1d 重锚为全目录扫描(尾缀〔注册面 V1〕);theme_projection_test.gd V6 改断言新串(尾缀〔注册面 V2〕)——两条改写即 §8 申报的测试改动全集。 +- [ ] 孤立验证:`python tools/run_smoke.py`(冒烟绿=装配链完整)+`godot --headless --path game --script res://tests/run_all.gd -- --only=source_guard,theme_projection,meta_progression_forge`(三套件绿——V1d/V6 重锚后绿、static 入口零变化)+`python tools/gdstyle_gate.py`(main.gd 类变量读数记录——此轮含 7 别名=22,基线键 49 内不红,读数进实现报告)。系统测试与探针此轮预期红(消费面未改址——T3 收口),不构成本卡验证面。 +- 取用:T1 四件公开面。产出:main.ui.* 地址面全量生效的组合根(T3 消费)。 + +### 7.6 T3——探针/系统测试/单元批量改址(估时 1 个工作日) + +- [ ] 探针九件+probe_ui_util 按 T0 映射表机械改写:属性读/写改 `main.ui.<域>.<名′>`;四类方法调用按表 D;`var bv = main.board_view` 型局部承接改 `var bv = main.ui.battle.board_zone.board_view`(每文件 1–2 处)。 +- [ ] 接缝三件:ui_struct_probe 的 `main._modals` → `main.ui.modals.flow.stack`(登记序断言);t17_defer_probe 的 `main._deferred_modal` → `main.ui.modals.flow._deferred`(挂起态断言);ui_click_probe 的 `_settlement_stop_pending` 读点 → `main.run_scope.settlement_stop_timer.is_armed()`。 +- [ ] system_test.gd 改址:V1c 的 `main.LAYER_CONTRACT`→`main.ui.LAYER_CONTRACT`、`main._layer_node`→`main.ui.node`;V2 句柄等价断言(:107–109)改 ui 地址(等价语义不变:ui.battle.board_zone.board_view == ui.screens.adventure_screen.board_view 型);V1a 候选清单与全件 main.X 逐表映射;V3 矩阵 `_face_snapshot` 的 `main._modal_flow`→`main.ui.modals.flow`、`main._row_pacer`→`main.ui.screens.row_pacer`(其余四持件取址不变)。 +- [ ] pacing_queue_test.gd:`main.board_view`→`main.ui.battle.board_zone.board_view`(:132);`main._row_queue`→`main.ui.screens.row_pacer.pending_rows()`(:108/:147/:149,实查 3 处)。 +- [ ] 改址完整性自检:映射表驱动 49 名逐名 grep——`game/` 下(探针/tests/流程件/main 自身)旧一级路径 `main.<旧名>`/`root.<旧名>`/`self.<旧名>` 残留=0,报告留档(实现报告对照表挂行)。 +- [ ] 孤立验证:`tools/probe_gate.sh --click --full`(全段退出码 0)+`python tools/run_system_test.py`(V1–V9 摘要 0 失败)+`python tools/run_smoke.py`+`godot --headless --path game --script res://tests/run_all.gd -- --only=pacing_queue,source_guard`。 +- 取用:T2 地址面。产出:全部消费面新地址(T4 前提——别名/转发方法零消费方)。 + +### 7.7 T4——别名与转发方法消灭+批末收口(估时 0.5–1 个工作日) + +- [ ] 删 main.gd 七别名/接缝成员(表 C——此点已零消费方)与六转发方法(§2 第 4 条清单);删 main_ui_build.gd:245 `root._modals` 赋值行;main.gd 类变量终态 **15**。 +- [ ] 文件头注随迁改写:main.gd 头注追加一句「界面句柄与层清单在 ui 注册面(ui_registry.gd)」;main_ui_build.gd 头注「层序唯一事实源」句改指 ui_registry(指址改写、词面语义不变)。 +- [ ] 逐卡扫尾孤立验证:`tools/render_gate.sh`(golden 零差异)+`tools/probe_gate.sh --click --full`+`python tools/run_smoke.py`+`python tools/run_system_test.py`+`godot --headless --path game --script res://tests/run_all.gd -- --only=pacing_queue,modal_flow,source_guard,theme_projection,meta_progression_forge`。 +- [ ] 批末全量:`tools/run_all_gates.sh --code` 全绿(main.gd 触组合根=横切面——02 单元与集成按 AGENTS.md 横切面口径回落全部套件;冒烟/系统测试/静态扫描三件保险恒跑)。里程碑步出口跑一次全套闸;波内修复只做出红最小单元的最窄确认;新增测试先行孤立验证再并入全套。 +- [ ] S13 键账对账申报:main.gd 键 49→15 只降不升、四新件零新键;基线 refresh 由用户发令人工跑(--refresh,净减 1 键低于骤降守卫)。 +- [ ] **产出物落位卡**(轻闸全绿后、合并前写齐,方算收口):`reports/iter-实现报告-<日期>.md`——各卡状态+实机目检总清单(登记不阻塞:注册面改址后实机过一遍三屏切换与模态开合)+遗留读数义务(基线 refresh)+实现决定记录+改址计数与 grep 自检留档;`reports/iter-反哺点-<日期>.md`——§5 同步面所列 architecture 三条逐条有落点;`reports/iter-验收审计-<日期>.md`——独立验收审计(未参与实现的会话或子代理执行,未过不得合并)。 +- 取用:T3 零消费方清单。产出:终态 main.gd(15 var)+三份 reports/ 产出物。 + +## 8. 验证闸(改动—验收对照表) + +本批全部改动为**非行为改动**(结构与地址重构):每行判断依据=改前改后在同一输入上行为一致,由探针/系统测试/冒烟/渲染 golden 四闸主证(真实入口全绿),静态 grep 只作完整性辅证。调试接口/目检两分法:本批无新玩法能力,验证全走自动化载体;用户目检仅一条登记项(T4 实机过三屏与模态开合),登记不阻塞。 + +| # | 需求点 | 改动(文件:行/行为) | 验收测试(名称+落点+尾缀) | 层级 | 真实入口 | 判据绑定面 | 能力行 | +|---|---|---|---|---|---|---|---| +| 1 | 注册面建件+合同机器迁驻(层序零变化) | 新建 ui_registry.gd(LAYER_CONTRACT main.gd:39–59 逐字迁入);ui_screens/ui_battle/ui_modals 建件 | 系统测试 V1c「合同树序链逐对保序」(system_test.gd:94–106 改址 main.ui.LAYER_CONTRACT/main.ui.node,尾缀〔装配生命批 V1〕保留) | 系统测试 | `python tools/run_system_test.py` | 运行期树序逐对保序=LAYER_CONTRACT 序(get_index 链——层序零变化的运行期提交面) | 既有:模态覆盖层编排与输入锁 | +| 2 | main.gd 类变量 49→15 | main.gd:61–148 改形(28 迁出+7 消灭+1 新增);六转发方法退役 | static_scan S13 键账对账(main.gd 实测 15、四新件零新键)+批末 run_smoke/run_system_test 全绿(静态判据+评审注记:结构点无独立运行期提交面,观测面局限申报=以四闸行为主证) | 静态扫描+冒烟+系统测试 | `game/tests/static_scan.sh`;`python tools/run_smoke.py`;`python tools/run_system_test.py` | gdstyle 键账读数(main.gd 类变量=15)+双宿主摘要 0 失败 | 既有:模态覆盖层编排与输入锁 | +| 3 | 装配与流程件改址(root.ui.*) | main_ui_build.gd 八步赋值目标;三流程件+context 束+pump_ended 注入点;smoke_boot.gd:70/73/74/75 | 冒烟主屏存活面六断言(smoke_boot.gd:64–75 改址后全绿)+系统测试 V2「组合根句柄指向屏壳成员」等价断言(system_test.gd:107–109 改址,五连比同指) | 冒烟+系统测试 | `python tools/run_smoke.py`;`python tools/run_system_test.py` | 启动态装配句柄在座且等价断言两侧同指一对象(多一跳取到同一引用) | 既有:模态覆盖层编排与输入锁 | +| 4 | 探针面批量改址(约 867 处) | 探针九件+probe_ui_util 旧地址→main.ui.*(只换地址不换判据) | probe_gate 全段退出码 0(ui_input_probe 全 case/ui_struct_probe/layout_probe/ui_contrast_probe/screen_flow_probe+--click ui_click_probe+--full ui_probe/ui_tune_probe/t17_defer_probe/fx_probe) | 探针 | `tools/probe_gate.sh --click --full`(单件形态:`godot --headless --path game res://probe/ui_input_probe.tscn` 等) | 探针经新地址取到同一节点并驱动真实输入路径(改址完整性的第一消费方主证) | 既有:棋盘悬停反馈(三语义光标/目标格边框/路径预览点迹) | +| 5 | 系统测试面改址+RunScope 生命周期零变化 | system_test.gd main.X 改址;V3 矩阵取址两处(_modal_flow→main.ui.modals.flow、_row_pacer→main.ui.screens.row_pacer) | 系统测试 V1–V9 全绿(含 V3a–V3i 九阶段×五引用面矩阵,尾缀〔装配生命批 V3〕保留) | 系统测试 | `python tools/run_system_test.py` | 第五引用面逐面同源比对(回调悬挂=红——存活性矩阵判据零变化) | 既有:模态覆盖层编排与输入锁 | +| 6 | 别名/接缝成员消灭(7 个) | main.gd:74/95/96/111/129/134/148 消灭;消费方改址(pacing_queue_test.gd:108/132/147/149、ui_struct_probe、t17_defer_probe、ui_click_probe、main 自身 4 处 _row_queue) | run_all 选跑 pacing_queue 绿(排空零分叉/零丢行/延迟双态/会话清队断言改址后判据不变)+ui_struct_probe 登记序断言+t17_defer_probe 挂起态断言 | 单元+探针 | `godot --headless --path game --script res://tests/run_all.gd -- --only=pacing_queue`;`tools/probe_gate.sh --full` | 属性链与别名取到同一对象引用(断言逐条等价——同一 Array/同一节点的可观测面) | 既有:结算明细带逐行呈现与排播节奏 | +| 7 | 六个 main 纯转发模态方法退役 | main.gd:156/161/282/285/288/292 退役;调用方改指 ui.modals.flow 五个真方法+注入点 main_ui_build.gd:62 | modal_flow 单元套件绿+系统测试 V3g 模态开合段+ui_click_probe 模态开合路径 | 单元+系统测试+探针 | `godot --headless --path game --script res://tests/run_all.gd -- --only=modal_flow`;`python tools/run_system_test.py`;`tools/probe_gate.sh --click` | 经真方法开合编排(遮挡互斥/锁谓词/挂起兜底行为面零变化——开合后可见性与锁态提交面) | 既有:模态覆盖层编排与输入锁 | +| 8 | V1d 源码断言重锚 | source_guard_test.gd:69–77 重锚为全目录扫描(move_child 只许在 ui_registry.gd apply_layer_contract 体内) | 「V1d 层序落位单口」重锚断言,尾缀〔注册面 V1〕 | 单元 | `godot --headless --path game --script res://tests/run_all.gd -- --only=source_guard` | 源码契约扫描面(扫描面>0 前置——全 presentation 目录零第二落位点) | 既有:模态覆盖层编排与输入锁 | +| 9 | V6 源码断言改串 | theme_projection_test.gd:724–725 改断言新连接串 | 「V6 转储入口连接随迁」新串断言,尾缀〔注册面 V2〕 | 单元 | `godot --headless --path game --script res://tests/run_all.gd -- --only=theme_projection` | main.gd 源码含新连接串(同一连接的宿主面改写) | 既有:UI 全局主题与按钮五态(含对比度锚) | +| 10 | 视觉零变化主证 | 全批呈现层地址重构(像素面零改动) | render_gate golden 零差异(shot_probe 七屏+菜单 golden+棋盘 golden) | 探针/golden | `tools/render_gate.sh` | 截图与基线图逐像素容差零差异(视觉零变化的独立主证——出现任何此前不存在的差异即 L3) | 既有:站桩敌人呈现与结算演出落点 | +| 11 | 改址完整性收口 | 全批改址面(49 名逐名) | 映射表驱动 grep 残留=0(静态判据+实现报告留档——辅证)+批末代码域闸全绿(02 横切面回落全量套件) | 静态判据+全量闸 | `tools/run_all_gates.sh --code` | 旧一级路径全仓残留 0(扫描面>0 前置)+所选域全绿回执 | 既有:模态覆盖层编排与输入锁 | + +**测试削弱申报**(实现期允许的旧断言改动全集,超出即审计判红): +1. V1d:扫描面从「main.gd 单文件」扩为「全 game/presentation/*.gd」——判据强化,非削弱。 +2. V6:断言串从 main.gd 旧连接串改为新连接串——同一连接的宿主面改写,断言不删除。 +3. 冒烟/系统测试/探针/pacing 各断言:只改地址字面,判据与既有尾缀不动——零删除、零放宽、零换下层直调。 +4. 七别名+六转发方法随批退役=test-conventions §5.5 同生死条款的执行:消费方断言已全部改指新地址,旧地址无断言残留(T3 grep 自检为证)。 + +**独立验收审计**:入口与报告=`reports/iter-验收审计-<日期>.md`;审计方=未参与实现的会话或子代理,逐行核对对照表、抽查判据绑定面、检查测试削弱、核对静态判据行的观测面局限注记;未过不得合并。 + +## 9. 异常分级 + +- **L1 自救**:单点漏改址→grep 定位补改后重跑该闸段;`--only` 选跑零命中(用法错 exit 2)→修正选词重跑;探针段超时→孤立复跑该段定位。 +- **L2 记录继续**:同一红闸连续 3 次同因→升级记录并在实现报告「实现决定记录」节记因后继续最窄确认。 +- **L3 停机写报告等用户**: + 1. **行为零变化契约触探**——任一闸出现改前不存在的红且定位为层序/时序/接线行为变化;render golden 出现任何此前不存在的差异。 + 2. **机检预算互斥=上游缺陷停卡退回写卡段**——四新件或 main 终态实测超 §14 预算、或 static_scan 出基线外 NEW 红键;禁开豁免、禁自造第三条路。 + 3. T0 对账失败——49 名逐一对账与表 A/B/C 任一名对不上,或发现未登记的 main.gd 源码字符串断言。 + 4. 拆分边界④触发——按纪律拆不出内聚单元(本设计已拆出,若实现期发现表 A 归档错误的成员强行迁入会破集体身份时适用)。 + +## 10. 代拍板白名单(逐条列,超清单记实现报告「实现决定记录」) + +1. 改址机械改写:映射表内旧→新地址的行内改写、被改行注释内旧地址字面同步更新(判据不动)。 +2. 重锚断言的消息文字措辞(V1d/V6 两条——尾缀〔注册面 V1〕〔注册面 V2〕与判据不变)。 +3. 迁移函数/成员头注按新宿主改写指址(词面随迁、语义不改)。 +4. 探针内局部承接变量名保留或内联(`var bv` 型——判据不变)。 +5. grep 自检留档在实现报告内的节名与格式。 +6. ui_screens 三屏壳句柄静态类型在 Control 与实测场景根实际基类之间取(判据=S9 过+赋值编译过;成员名与地址面不变)。 +7. main 内部调用点在 T2 先改真方法、转发方法留至 T4 删除的批内中间态时序(终态零转发壳)。 + +## 11. 待裁点 + +**零待裁点,开工门=U0。** 设计文档 §8 五项待裁点已于 2026-10-29 用户全裁:①注册面拓扑=一门面+三域容器;②合同机器随批迁入注册面;③七别名消灭+六转发方法退役+容器内成员去下划线——清单整体确认;④run_all 关联档口径=main.gd 触组合根按横切面回落全部套件;⑤编批归迭代编排段定(本卡估时 3–4 个工作日在冻结线内)。 + +## 12. 落位与可复用性预检 + +**复用面**(逐个排除既有件——为什么不能复用): +- **modal_flow.gd(ModalFlow)**:模态编排纯逻辑——开合编排、输入锁谓词、T17 挂起。它管行为不管地址;注册面管「元素清单、层序、寻址」,是它的宿主容器(flow 挂在 ui_modals 里)。职责语句不同,不能拿它当注册面。 +- **modal_stack.gd(ModalStack)**:登记册数据结构(遮挡记账),被 ModalFlow 持有;层序合同表与三域寻址不归它。非候选。 +- **ui_assembler.gd**:无态静态装配工厂——装配期造控件用完即弃,不持任何句柄;注册面是随 main 常驻的句柄容器。把「造」和「持」并进一件会让静态工厂变有态,破坏现行职责。 +- **run_scope.gd**:局态节点——装的是会话状态不是界面元素清单;173 处探针引用零迁移义务已核。非候选。 +- 形态先例(非复用对象):ConfigDB 迭代 41 三张域容器(config_domain_combat/run/crossrun.gd)解决过同构的成员数超标问题——本批三容器即同一形态在呈现层的落法。 + +**唯一面**:层序合同唯一事实源随迁 ui_registry.LAYER_CONTRACT(main.gd 侧删除,不双写);合同寻址唯一口=ui_registry.node();模态登记唯一口=ui_modals.register_layer()。2026-10-29 实查 game/presentation/ 下无 ui_registry/ui_screens/ui_battle/ui_modals 同名或同义件(architecture v1.25 登记「实现批建件」即此四名,盘上未建)——新增无第二落点。 + +**分层与交互面**(调用路径显式): +- 读地址路径:views/探针/流程件 → `main.ui.<域容器>.<句柄>` → 容器字段 → 节点。三段式每段有领域含义(组合根→注册面→域→元素),与 ConfigDB 的 `db.<域容器>.<成员>` 两段式同构。 +- 注册面禁反向持有:不持 main、不持 run_scope、零信号连接、零核心写调用、零 `_process`——依赖单向(views→信号→组合根→core)零触碰;组合根单点装配不变(信号连接仍在组合根与 main_ui_build)。 +- 构造路径:main._ready 建 `ui = UiRegistry.new()`(门面自建三容器),main_ui_build 八步向容器登记;四件全 RefCounted 不挂树(节点本体树位与 add_child 归属零变化——row_pacer 仍 add_child 到 main,注册面只持引用)。 +- Core 零 UI 红线零触碰:本批改动全部在 game/presentation/ 与测试面。 + +## 13. 禁为机检文本保留无效成员(重构类卡必填条款) + +禁止为迎合机检消息文本(含计数)而保留或新增无效成员/别名:main.gd 终态 15 个类变量必须个个有 §7.1 表 B 的职责理由,禁留空占位或替身成员凑计数;四新件的字段必须个个是表 A 在册句柄或 flow,禁加「以防万一」的空槽。机检键与本卡契约互斥时(如实测出新基线键 NEW 红、或键账与申报不符),实现段一律停卡呈报走 L3,不得自造第三条路。判据权威=code-conventions §1.1⑤。 + +## 14. 实现规范预算(gdstyle 默认阈值:公开方法 ≤20、类变量 ≤15、单函数分支 ≤8、返回 ≤6) + +| 新件 | 公开方法 | 类变量 | 阈值判定 | +|---|---|---|---| +| ui_registry.gd | 2(node/apply_layer_contract) | 3(三容器属性;LAYER_CONTRACT 为常量不占 var) | 双达 | +| ui_screens.gd | 0 | 9 | 双达 | +| ui_battle.gd | 0 | 5 | 双达 | +| ui_modals.gd | 1(register_layer) | 14(13 句柄+flow) | 双达(余量 1——第 14 个模态句柄出现即触发拆分审视,作发现信号用) | + +- 迁移函数对账:`_apply_layer_contract`/`_layer_node`/`_register_modal` 自 main.gd 迁入,T0 查 gdstyle_baseline.txt 源函数键——超默认登记值的迁移即拆函数(拆分不改语义);node(key) 的 19 键 match 与合同落位循环预期在默认分支阈内(设计文档 §7 同判断),实测出新键=基线外 NEW 红=L3 停卡(禁开豁免)。 +- 存量触面一查:本批触碰的 presentation 存量件(main.gd/main_ui_build.gd/三流程件)预期「S13 键较登记值只降不升」——main.gd 49→15;main_ui_build 与三流程件零成员变化(仅语句内地址改写);达成手段=表 A/C 全量迁移+别名净消灭。 +- 指标例外申报:无(本批不需要任何超默认面;main.gd 改后 15 在阈内,S13 豁免登记注销后不留新例外)。 + +## 15. 源码级断言与探针契约面的随批义务(防漏项清单) + +1. V1d(source_guard_test.gd:69–77)与 V6(theme_projection_test.gd:724–725)随批重锚——本卡已全量排查 main.gd 源码断言面仅此两条(T0 复核义务不豁免)。 +2. 探针段覆盖义务:probe_gate 必须 `--click`+`--full` 全跑——ui_click_probe 是最大改址户,只跑默认段会漏最深的改址面。 +3. 冒烟 V1 族 get() 键、系统测试 V1c/V2/V3 取址、pacing `_row_queue` 三处——都在 §7.1 表 D 与 T3 清单内,T0 映射表生成后逐条打钩对账。 diff --git a/待办清单.md b/待办清单.md index 04d74030..62921139 100644 --- a/待办清单.md +++ b/待办清单.md @@ -109,7 +109,7 @@ **实况**:三条同病根的结构债,需先一次设计讨论定端口形态,再谈切卡;`RewardEconomy` 的最小缝拆样本已由迭代 40 卡② 落卡。 - 效果发射端口(设计题本体):`game/core/damage_controller.gd:46/47/71` 与 `game/core/action_economy.gd:44/45/50` 仍直持 `EffectEngine`+`EffectContext`——前者用 attack_commit/armor_roll/clamp_check/kill/damage_taken 五枚事件并带计数器读写回写(:348/:354),后者用 dig_paid/dig_stop/charge_full 三枚事件。`RewardEconomy` 同款直连已由迭代 40 卡② p5 缝拆实装合回(单枚查询口 `luck_bias_query`——成员 −2+2、类变量净 15、判定归 `BattleFxHost.luck_bias_for`),最小样本在库可考;另两处事件多且带计数器回写,缝拆不成立,必须先设计「业务类只持一个回调、取回命中批」的端口形态。 -- battle_orchestrator 瘦身:迭代 40 卡① 拆出 `BattleFxHost`/`RewardGrant` 后宿主实测 38 类变量(阈值 15;豁免第三条已顺带落 architecture v1.22 S13 豁免登记——豁免不等于了结),`tools/gdstyle_baseline.txt` 在册 `game/core/battle_orchestrator.gd|quality/max-class-variables = 38` 与 `|quality/max-file-length = 1037` 两键(已随 2026-10-28 波 0 刷新按实测重锚)。 +- battle_orchestrator 瘦身:迭代 40 卡① 拆出 `BattleFxHost`/`RewardGrant` 后宿主实测 38 类变量(阈值 15;豁免第三条已顺带落 architecture v1.22 S13 豁免登记——豁免不等于了结),`tools/gdstyle_baseline.txt` 在册 `game/core/battle_orchestrator.gd|quality/max-class-variables = 38` 与 `|quality/max-file-length = 1037` 两键(已随 2026-10-28 波 0 刷新按实测重锚)。**2026-10-29 承接更新(本子项已写卡)**:设计闭合=architecture.md v1.25 轴丁(RoundCycle/BattleFacts 两新件,S13 豁免第三条注销——零豁免裁)+reports/设计-战斗编排类变量归约-2026-10-29.md;需求卡片:reports/需求卡片-战斗编排归约批-2026-10-29.md(v1.0 定稿零待裁点,编队前置=迭代 42 合回);本子项子目标=38→15,文件长键已由轴丙归绿。本条目其余两子项(效果发射端口/reward_economy 分件)仍待文档设计,条目状态不变。 - reward_economy 分件:`RewardEconomy` 现 15 类变量恰在阈值线上(加第 16 枚即出闸 09 新增红——迭代 40 卡② 施工实测撞见,正是本条登记起因),掷格面(install 期 roll/池行装配/权重合成)与受理账面(grant/身份查询/快照/retire)两职责同居一件。 - 相关文档:design/engineering/architecture/architecture.md(系统分层图与功能层 B1/B4 行、「战斗编排域拆件定稿」节须随端口定稿改写)· reports/审计-gdstyle存量债清点与清偿方案-2026-10-26.md(216 键波次方案与残留债口径;在册「尾波」只覆盖迭代 39 三宿主,不含本条)· 结构小件定点修批卡已随迭代 40 合回退役(git 历史可考,合并提交 514457d1;缝拆样本与 2026-10-27 用户裁史见该卡 git 版本)