写卡(架构审查5.1封装修复批·v1.1终审折入): godot-master终审七项折入——①golden封印步改封未揭示相邻格(封印子链进主证,拒绝路径归既有回归)②三schema bind_resolver解析冒烟义务(类型环当轮即炸,禁type-hint:ignore)③T3两签名补S9注解④成员账两笔订正(damage 9→12/decay 1→2——终审实核)⑤harmful_adjacent自呼随更名+:280-281注释同步⑥现值交付=注入形态之一口径注(落卡§2,防T1与处置记录机械比对误停卡)⑦SlotStore→SaveManagerCore反向私取终审补查21处/21行并入T3(save_manager+5公开方法+两更名公开化7→14); T3估时0.5→0.625合计2.875; pipeline_gate PASS(30条目/50总表行/交叉核3链/卡片6张全过)

This commit is contained in:
DKChan committed 2026-11-03 06:48:32 +08:00
1 parent 057ccc672b
commit b5f2bfb7e7
1 file changed
+26 -23
@@ -1,7 +1,7 @@
# 需求卡片:架构审查 5.1 封装修复批(2026-11-03)
来源:待办清单「架构审查优化讨论——全库架构审计读数的逐项裁决与整改分批(2026-10-29 登记,来源=审计发现)」条目 5.1 部分(**唯一事实源**:reports/处置-架构审查5.1封装修复-2026-11-03.md——处置记录与本卡并行成文,本卡开工时该件尚未落盘;T1 首步核其已落盘且与本卡第 3 节逐条一致,冲突即 L3 停卡。设计闭合凭据=2026-11-03 设计讨论会话裁决+审计报告 §5.1+architecture.md:119/:124/:137-146)。
状态:已写卡(v1.0,2026-11-03 成文)。改动面:游戏代码(含随逻辑写/改的测试代码)。
状态:已写卡(v1.1,2026-11-03 修订——godot-master 终审两中等发现与四低项折入+SlotStore→SaveManagerCore 反向私取终审补查并入 T3;处置记录已落盘并与本卡第 3 节核过一致)。改动面:游戏代码(含随逻辑写/改的测试代码)。
## 1. 目标与完成定义
@@ -12,7 +12,7 @@
| 1 | settlement 七段 → 编排器 | 七文件对编排器 `oc._` 私取 105 行/107 处/19 符号(本卡第 3 节 grep 实核) | 段类构造收引用束(六子对象+编排器公开协作件引用)+七个编排器方法回调(Callable 交付)+公开读数注入;段类对编排器引用归零 |
| 2 | 编排器五个放错位置的方法 | `_hero_atk`/`_feat_yield_adjust`/`_harmful_variants`/`_harmful_adjacent`/`_hits_of` 留宿主、段类经宿主引用直调(architecture.md:145「现状形态」) | 各归领域宿主(伤害域/奖励域/地形棋盘域),宿主原方法删除禁留壳 |
| 3 | adventure_runner → BreakpointStore | `_bp_store._` 直读写 37 处(32 行;adventure_runner.gd:37 注释自述「宿主读写经件」未落实) | BreakpointStore 公开方法面承接,宿主私取清零 |
| 4 | save_manager → SlotStore | `slots._path` ×8+`slots._migrate_legacy_save` 私有方法调用 ×1(save_manager.gd:51/66/69/105/111/118-119/285-286) | SlotStore 公开读投影 `active_path()`+迁移方法公开化承接 |
| 4 | save_manager ↔ SlotStore | save_manager→SlotStore:`slots._path` ×8+`slots._migrate_legacy_save` 私有方法调用 ×1(save_manager.gd:51/66/69/105/111/118-119/285-286);SlotStore→SaveManagerCore 反向私取约 13 处(slot_store.gd:26-28/38-39/61-76/92-97/119/129/134/159-162——直用 `_save._read_only`/`_reset_to_default`/`_data`/`_rename_overwrite`/`_peek_summary_at`,godot-master 终审补查) | save_manager 侧=SlotStore 公开读投影 `active_path()`+迁移方法公开化承接;SlotStore 侧=SaveManagerCore 补公开方法面承接(T3 定死) |
| 5 | grant_segment → BattleFxHost;config_db → 三表容器 | grant 直写 `fx_host._fx_new_resource_types`(:82/:84)与 `fx_host._fx_bonus_delta`(:169-170/:378-379)共 6 行;config_db.gd:157-159 三行装配直写三表 `_resolver` | BattleFxHost 两个公开累积方法;三表 schema 各加公开挂载方法 `bind_resolver` |
**什么状态算完**:五处的每一条改动都落码、都有第 8 节对照表配对的验收断言在当轮真实跑批中通过;主证=同种子逐项比对(改前改后动作序列快照逐位同,T1 固化、全程保持绿)+battle_settlement 套件全绿;结构性证据=core 五处跨对象私取 grep 恒零(扫描面非空前置+零命中);代码域闸全绿(冒烟+单元+探针+渲染/静态);两份 reports/ 产出物(实现报告+反哺点清单)写齐。
@@ -21,7 +21,7 @@
## 2. 设计事实源
- **处置记录(输入合同,逐条一致)**:`reports/处置-架构审查5.1封装修复-2026-11-03.md`——五处裁决方案、段类终态、出卡边界。本卡第 3 节现状实查与第 4/7 节签名设计是其机械承载;T1 复核两件一致(冲突=上游缺陷,L3 停卡)。
- **处置记录(输入合同,逐条一致)**:`reports/处置-架构审查5.1封装修复-2026-11-03.md`——五处裁决方案、段类终态、出卡边界。本卡第 3 节现状实查与第 4/7 节签名设计是其机械承载;T1 复核两件一致(冲突=上游缺陷,L3 停卡)。**口径注**:处置记录「公开读数一并改注入」=形态族措辞,涵盖本卡第 4 节「调用参数现值交付」(round_index/battle_result 两变值标量构造期注入必陈旧——现值交付即注入的形态之一),T1 核对不按字面机械比对、按此口径核。
- **审计背景**:`reports/审计-全库架构审查-2026-10-29.md` §5.1(settlement 五段类直读写编排器私有成员 20+ 处;行号已漂移,以本卡第 3 节实查为准)。
- **架构登记**:`design/engineering/architecture/architecture.md`——:119(battle_orchestrator 保留面与 B1 域文件集)、:124(BoardInstaller 引用束注入先例——「构造=引用束注入(……防 _init max-parameters 新键)」)、:137-146(战斗编排域拆件定稿::140 轴丙、:141 编排器保留面登记、:143 跨件单向接线、:145 段类随动现状句)。
@@ -43,7 +43,7 @@
**处 3·adventure_runner → BreakpointStore**:`grep -o "_bp_store\._[a-z_]*" | wc -l`=**37 处**(32 行)=`_resume_bp`×8、`_pending_next_level`×7、`_save_manager`×6、`_bp_read`×5、`_loadout_seeded`×5、`_last_level_payload`×4、`_last_treasure_cleared`×2。分布:adventure_runner.gd:107/:115/:157/:168/:180/:185/:189/:191/:201/:220/:235/:241/:300-302/:325-326/:376-378/:388/:412/:421/:430/:438/:456/:464/:467-468/:474-476。BreakpointStore(breakpoint_store.gd)类变量 15(:48-63——**贴顶禁再增**,architecture.md:113 同款登记);公开方法现 5(snapshot/restore_ledger/restore_curio_state/apply_resume_params/restore_stop_bank_fragments);`_bp_read`(:196-202)内部消费点 :160。测试面:feat_vouchers_test.gd 与 meta_progression_forge_test.gd 等 12 处 `orch._rounds._grant_seg._judge_seal(...)` 直调与 `orch._rounds.mines_hits` 7 处——`_grant_seg`/`mines_hits` 成员名与归属不变,零波及。
**处 4·save_manager → SlotStore**:save_manager.gd:51(`slots._migrate_legacy_save(LEGACY_SAVE_PATH, slots.slot_path(1), ...)`)+:66/:69/:105/:111/:118/:119/:285/:286(`slots._path` ×8)。SlotStore(slot_store.gd)`_path` :9;`_migrate_legacy_save` :150-163(唯一外部调用方=save_manager:51;件内零调用);公开读投影先例=`has_write_target()` :53-54(`_path != ""`)。SlotStore 类变量 4、公开方法 10。
**处 4·save_manager ↔ SlotStore(双向)**:save_manager→SlotStore=save_manager.gd:51(`slots._migrate_legacy_save(LEGACY_SAVE_PATH, slots.slot_path(1), ...)`)+:66/:69/:105/:111/:118/:119/:285/:286(`slots._path` ×8)。SlotStore→SaveManagerCore 反向私取(godot-master 终审补查,2026-11-03 本会话 grep 精确实数)=**21 处/21 行**:`_save._read_only`×8(:26/:38/:65/:69/:74/:87/:91/:96)、`_save._reset_to_default`×5(:28/:39/:70/:92/:119)、`_save._data`×4(:66/:75/:88/:97)、`_save._peek_summary_at`×2(:129/:134)、`_save._rename_overwrite`×2(:159/:162)。SlotStore(slot_store.gd)`_path` :9;`_migrate_legacy_save` :150-163(唯一外部调用方=save_manager:51;件内零调用);公开读投影先例=`has_write_target()` :53-54(`_path != ""`)。SlotStore 类变量 4、公开方法 10。SaveManagerCore 私有被用面五成员=`_read_only` :23、`_data` :24、`_reset_to_default` :279、`_peek_summary_at` :217(save_manager 件内调用方 :217 定义、slot_store 两处外部)、`_rename_overwrite` :317(件内调用方 :118/:286);公开方法现 7、类变量 5。
**处 5·grant_segment → BattleFxHost+config_db → 三表容器**:grant_segment.gd:82-84(`fx_host._fx_new_resource_types.has(ctype)` 读+`[ctype] = true` 写——空串短路边界在 :82)与 :169-170、:378-379(`fx_host._fx_bonus_delta.has(axis)` 守卫+`[axis] += delta`)。BattleFxHost 类变量 15(battle_fx_host.gd:23-37——**贴顶禁再增**,头注 :10-16 自封)、公开方法 16、两私 members 无成员外读者(grep 全库仅 grant 四处)。config_db.gd:157-159 三行 `combat.board_gen._resolver = _resolver`/`combat.enemy._resolver = _resolver`/`run.difficulty._resolver = _resolver`;三表 `_resolver` 声明=board_gen_table.gd:113、enemy_table.gd:212、difficulty_table.gd:33(均无类型注解;消费点 :118/:217/:38)。表实例经 `load()` 出 .tres、无法带构造参,装配期注入是唯一时点(config_db.gd:131-159 `_assign_loaded`)。
@@ -77,7 +77,7 @@
## 5. 范围边界
**收件**=第 1 节表五行全部(settlement 七段解耦+搬家五方法+breakpoint_store 公开面+slot_store 公开面+battle_fx_host 两累积方法+三 schema 挂载方法,及各自的调用点改址与测试适配)。
**收件**=第 1 节表五行全部(settlement 七段解耦+搬家五方法+breakpoint_store 公开面+存档双向公开面〔save_manager↔SlotStore 两方向〕+battle_fx_host 两累积方法+三 schema 挂载方法,及各自的调用点改址与测试适配)。
**不收件**(去向已指认):
- presentation 层约 227 行私取面——**另开设计讨论**(本卡裁决范围外;去向=待办清单本条目实况,非本批)。
@@ -92,7 +92,7 @@
| 文档 | 关联点(本批实现会改变它的哪条陈述) | 同步义务(反哺点清单逐条承载) |
|---|---|---|
| design/engineering/architecture/architecture.md | :125 RoundCycle 行「三参直构(host/fx_host_ref/reward_grant_ref——五段构造透传不落成员)」→ 束注入+持有 BattleRefreshFlow+公开方法 3→4+类变量 8→15(贴顶);:123 BattleRefreshFlow 行 static 两入口收 oc → 实例束注入、宿主改经 RoundCycle 交接 grant_seg、类变量 0→8;:127 settlement/ 五段段类行构造形态句 → 束注入、对编排器零引用;:122 damage_controller 行实测类变量 12→13+公开面净增(hero_atk/hits_of/emit_hero_damage_taken);:121 RewardGrant 行 +feat_yield_adjust;:120 BattleFxHost 行 +两累积方法(类变量 15 不变);核心层表 A2 minesweeper_rules 行公开面 18→20(贴顶);核心层表 breakpoint_store 行公开方法面 5→18 | 反哺点清单逐条列行号与改后登记内容——**机械面文档禁直改** |
| design/engineering/architecture/architecture.md | :125 RoundCycle 行「三参直构(host/fx_host_ref/reward_grant_ref——五段构造透传不落成员)」→ 束注入+持有 BattleRefreshFlow+公开方法 3→4+类变量 8→15(贴顶);:123 BattleRefreshFlow 行 static 两入口收 oc → 实例束注入、宿主改经 RoundCycle 交接 grant_seg、类变量 0→8;:127 settlement/ 五段段类行构造形态句 → 束注入、对编排器零引用;:122 damage_controller 行实测类变量 12→13+公开面净增(hero_atk/hits_of/emit_hero_damage_taken);:121 RewardGrant 行 +feat_yield_adjust;:120 BattleFxHost 行 +两累积方法(类变量 15 不变);核心层表 A2 minesweeper_rules 行公开面 18→20(贴顶);核心层表 breakpoint_store 行公开方法面 5→18;核心层表 save_manager 行公开面 7→14(+5 承接方法+peek_summary_at/rename_overwrite 两更名公开化)+slot_store 行「双向公开面」(21 处反向私取清零) | 反哺点清单逐条列行号与改后登记内容——**机械面文档禁直改** |
| design/gdd/systems/战斗循环/战斗结算.md | 无陈述变化(明细流水词表、五段段序、段边界全部零触碰——零行为变更批) | 反哺点清单写「零反哺」确认行 |
| 术语表 | 无新术语(引用束注入/读投影/公开方法面均仓库现行词) | 确认行「零新增术语」 |
@@ -121,8 +121,8 @@ core 层(编排域)
core 层(冒险/存档域)
game/core/breakpoint_store.gd 【非行为 R4】+13 公开读写方法面(成员 15 不变;_bp_read 更名 bp_read 公开化——:160 内部调用点随改)
game/core/adventure_runner.gd 【非行为 R4】37 处改址(:107..:476 逐处)
game/core/save_manager.gd 【非行为 R5】:51/:66/:69/:105/:111/:118-119/:285-286 九行改址
game/core/slot_store.gd 【非行为 R5】+active_path();_migrate_legacy_save 更名 migrate_legacy_save 公开化
game/core/save_manager.gd 【非行为 R5】+5 公开方法(set_read_only/read_only/reset_to_default/data_snapshot/restore_data)+_peek_summary_at/_rename_overwrite 更名公开化(件内调用点随改);:51/:66/:69/:105/:111/:118-119/:285-286 九行改址
game/core/slot_store.gd 【非行为 R5】+active_path();_migrate_legacy_save 更名 migrate_legacy_save 公开化;反向私取 21 处改址(_save._ → save_manager 公开面)
game/core/config_db.gd 【非行为 R6】:157-159 三行改经 bind_resolver()
game/data/schemas/board_gen_table.gd 【非行为 R6】+bind_resolver(resolver: ConfigDbResolver)
game/data/schemas/enemy_table.gd 【非行为 R6】同上
@@ -144,10 +144,10 @@ core 层(冒险/存档域)
- [ ] 核对实现排序在案:3.1+3.2 卡(迭代 50)未合回则本批不开工(第 1 节排序义务);combat_segment.gd 现址复核(甲案 :59-70 分支已删则以 grep 符号锚定位,行号漂移即记录进实现报告,禁改判据)
- [ ] 核对处置记录 `reports/处置-架构审查5.1封装修复-2026-11-03.md` 已落盘且与本卡第 3 节逐条一致(冲突=L3 停卡)
- [ ] 新增 tests/unit/battle_settlement/settlement_wiring_snapshot_test.gd(extends SceneTree+Kit.check 主通道,全类型标注):手搭驱动=`ConfigDbScript.new()`+`load_tables("res://data/tables", true)`→`RngServiceCore` set_master_seed(4242)→`BattleOrchestrator.new(db, rng)`;捕获面=`step_row` 全量行数组+`settlement_snapshot` 全量载荷数组+`battle_finished` 载荷+收束时 `presentation_snapshot()` 关键键(round/battle_result/hero.hp/enemies.size())。驱动序(逐字定死):①`begin_battle({"level_index": 1, "node_depth": 1, "hero_hp": int(db.combat.hero.max_hp), "voucher_rap": 20})`;②轮 1:`AutoPlayer.choose_dig(minesweeper)` 返 `{dig_cell, hero_cell}` 非空则 `settle_batch([{"action": "move", "cell": hero_cell}])`→`settle_batch([{"action": "dig", "cell": dig_cell}])`→对首个已揭示安全格 `settle_batch([{"action": "seal_place", "cell": c}])`→`settle_batch([{"action": "stop"}])`;③轮 1 结算后 `player_request_refresh()`(voucher_rap=20 保证 RAP 抵折后价——覆盖换图刷新链:can_refresh/execute/install_cb/grant_seg 成功事实);④轮 2:choose_dig 一挖一停;⑤轮 3:径直 `settle_batch([{"action": "stop"}])`。断言=捕获序列与 `const GOLDEN`(行字典逐位含 type/source_class/origin_cell/round_index/display_name/value/其余载荷键)逐位相等〔封装5.1 V1〕
- [ ] 新增 tests/unit/battle_settlement/settlement_wiring_snapshot_test.gd(extends SceneTree+Kit.check 主通道,全类型标注):手搭驱动=`ConfigDbScript.new()`+`load_tables("res://data/tables", true)`→`RngServiceCore` set_master_seed(4242)→`BattleOrchestrator.new(db, rng)`;捕获面=`step_row` 全量行数组+`settlement_snapshot` 全量载荷数组+`battle_finished` 载荷+收束时 `presentation_snapshot()` 关键键(round/battle_result/hero.hp/enemies.size())。驱动序(逐字定死):①`begin_battle({"level_index": 1, "node_depth": 1, "hero_hp": int(db.combat.hero.max_hp), "voucher_rap": 20})`;②轮 1:`AutoPlayer.choose_dig(minesweeper)` 返 `{dig_cell, hero_cell}` 非空则 `settle_batch([{"action": "move", "cell": hero_cell}])`→`settle_batch([{"action": "dig", "cell": dig_cell}])`→对首个未揭示且与主角相邻的格 c `settle_batch([{"action": "seal_place", "cell": c}])`(封印已揭示格在棋盘面必拒〔target_revealed〕——封印子链 _judge_seal_hit/_seal_hit_effects/_judge_seal_miss 及封印匠/示警烟火/完美保险扩展行必须真实进入 golden 行流;「封已揭示安全格」的拒绝路径由 seal_polarity_test 既有回归兜底,不入 golden 主证)→`settle_batch([{"action": "stop"}])`;③轮 1 结算后 `player_request_refresh()`(voucher_rap=20 保证 RAP 抵折后价——覆盖换图刷新链:can_refresh/execute/install_cb/grant_seg 成功事实);④轮 2:choose_dig 一挖一停;⑤轮 3:径直 `settle_batch([{"action": "stop"}])`。断言=捕获序列与 `const GOLDEN`(行字典逐位含 type/source_class/origin_cell/round_index/display_name/value/其余载荷键)逐位相等〔封装5.1 V1〕
- [ ] **改前取数**:本步骤在任何生产码改动之前执行——先写测试与空跑转储通道(GOLDEN 为空时打印捕获序列 JSON 后按预期码退出),在未改树上跑出 golden、填入 GOLDEN 常量、复跑全绿;golden 即改前基线读数(不构成验收,验收=改后全程保持绿)
- [ ] S13 对账基线:对本卡全部 core/data 存量触件(第 14 节清单 15 件)现场跑 gdstyle 记读数为基线(既有登记仅 adventure_runner 类变量 23 一件照登对账);跑 `python tools/run_smoke.py` 冒烟基线全绿读数落实现报告
- [ ] grep 底账四件落实现报告:`oc\._`(settlement 七文件)、`_bp_store\._`(adventure_runner)、`slots\._`(save_manager)、`_fx_new_resource_types|_fx_bonus_delta`(grant)与 `\._resolver =`(config_db)——命中行号清单=T5 sweep 的改前底账
- [ ] grep 底账五件落实现报告:`oc\._`(settlement 七文件)、`_bp_store\._`(adventure_runner)、`slots\._`(save_manager)、`_save\._`(slot_store——反向私取 21 处)、`_fx_new_resource_types|_fx_bonus_delta`(grant)与 `\._resolver =`(config_db)——命中行号清单=T5 sweep 的改前底账
**T2 settlement 七段解耦+搬家五方法**(估时 1.25 工作日;区间 1–1.5)
取用:T1 golden 基线。产出:处 1+处 2 清零——段类对编排器引用归零、五方法归位。
@@ -156,7 +156,7 @@ core 层(冒险/存档域)
- [ ] 搬家五方法落位(宿主体逐字迁移、注解逐字保持):
- damage_controller.gd:`_init` 加第五参 `facts_ref`(成员 `var facts: BattleFacts`,:49 构造体加行);新增 `func hero_atk() -> int`(体=battle_orchestrator.gd:70-71 逐字,`_facts`→`facts`);新增 `static func hits_of(hits: Array, kind: String) -> Array`(体=:489-494 逐字);`_emit_hero_damage_taken` 更名 `emit_hero_damage_taken` 公开化(体逐字;内部调用点 :449/:561 随改)
- reward_grant.gd:新增 `func feat_yield_adjust(snap: Dictionary, positive: bool, pos_m: int, neg_m: int) -> Dictionary`(体=:452-461 逐字——reward_economy 为本件既有成员 :22)
- minesweeper_rules.gd:新增 `func harmful_variants(vids: Array) -> Array` 与 `func harmful_adjacent(cell: Vector2i) -> Array`(体=:466-473/:478-485 逐字——db 为本件构造参、current_board() 自有)
- minesweeper_rules.gd:新增 `func harmful_variants(vids: Array) -> Array` 与 `func harmful_adjacent(cell: Vector2i) -> Array`(体=:466-473/:478-485 逐字——db 为本件构造参、current_board() 自有;**:484 内部自呼 `_harmful_variants(board.variant_ids(n))` 随更名改 `harmful_variants(board.variant_ids(n))`,禁留旧名**)
- battle_orchestrator.gd:五方法整段删除(:70-71/:452-461/:466-473/:478-485/:489-494);:282 `hero_atk_override: _hero_atk()` → `_damage.hero_atk()`
- [ ] round_cycle.gd 重写:`_init(bundle: Dictionary)`——断言 7 必需键(facts/units/fx_host/db/action_economy/rng/emit_row_cb)后解包为同名成员;五段构造改 `XxxSegment.new(bundle)`;复制束写入 `"grant_seg": _grant_seg` 后构建 `BattleRefreshFlow.new(束副本)`;`settle_if_due(battle_result: String, ri: int)`(:35→参数、:40 删、段驱动用 ri);`roll_round_actions(ri: int)`(:67/:80 用 ri);新增 `func refresh_flow() -> BattleRefreshFlow`;全文 `oc.` 改址(映射表=`oc._facts`→`facts`、`oc._enemy_system`→`units`、`oc._emit_row`→`emit_row_cb.call`、`oc._fx_host`→`fx_host`、`oc.db`→`db`、`oc.action_economy`→`action_economy`、`oc.rng`→`rng`);头注「耦合边界」段改写(束注入+签名扩展+随编排器每战新建同灭语义不变)
- [ ] grant_segment.gd 重写:`_init(bundle: Dictionary)` 断言 12 键解包 12 成员(第 4 节分配表);54 处改址——除上表映射外加:`oc._reward_economy`→`reward_economy`、`oc.minesweeper`→`minesweeper`、`oc._hero_atk()`→(无此调用)、`oc._feat_yield_adjust(...)`→`reward_grant.feat_yield_adjust(...)`(:99/:140)、`oc._harmful_variants`→`minesweeper.harmful_variants`(:87)、`oc._harmful_adjacent`→`minesweeper.harmful_adjacent`(:339)、`oc._hits_of`→`DamageController.hits_of`(:110/:115/:138/:356)、`oc.attune_param_sum("rap_transfer_mult")`→`int(attune_param_sum_cb.call("rap_transfer_mult"))`(:280)、`oc.perfect_sweep_earned()`→`bool(perfect_sweep_cb.call())`(:284)、`oc._damage._emit_hero_damage_taken(...)`→`damage.emit_hero_damage_taken(...)`(:197);:82-84 改 `var is_new_type := fx_host.mark_new_resource_type(ctype)`;:169-170 与 :378-379 改 `fx_host.add_bonus_delta(String(h.get("axis", "")), int(h.get("delta", 0)))`;头注改写
@@ -164,16 +164,17 @@ core 层(冒险/存档域)
- [ ] combat_segment.gd 重写:`_init(bundle)` 断言 10 键解包;23 处改址(映射同上+`oc._fatal`→`fatal_cb.call`、`oc._status_effects`→`status_effects`、`oc._hero_atk()`→`damage.hero_atk()`);`oc._hits_of` 行随 3.1+3.2 批已删——复核以 grep 为准;头注改写
- [ ] aura_segment.gd(成员 `var emit_composition_cb: Callable`,:15-16 改 `emit_composition_cb.call("hero", ri)`/`("enemy", ri)`)、decay_segment.gd(成员 status_effects+emit_row_cb)、verdict_segment.gd(成员 units+四回调,:18/:20 `units.hero_unit()`/`units.query_alive("enemy")`、:22 `emit_snapshot_cb.call(verdict)`、:25/:29 `battle_over_cb.call(...)`、:32 `exit_distribution_cb.call()`)三件重写+头注改写
- [ ] battle_refresh_flow.gd 重写:去 static——`_init(bundle: Dictionary)` 断言 8 键(facts/db/action_economy/fx_host/reward_economy/minesweeper/install_cb/grant_seg)解包;`_effective_refresh_cost()` 无参实例方法(:15-20 体逐字,`oc.db`→`db`、`oc.fx_host().fx_emit`→`fx_host.fx_emit`);`can_refresh(battle_result: String) -> bool`(:24-28 体逐字,`oc.battle_result`→参数、`oc._facts.refresh_used`→`facts.refresh_used`);`execute(battle_result: String, round_index: int) -> bool`(:32-43 体逐字——`oc._facts.refresh_used += 1`→`facts.refresh_used += 1`、`oc._reward_economy.retire_mapping()`→`reward_economy.retire_mapping()`、`oc.minesweeper.retire_board(true)`→`minesweeper.retire_board(true)`、`oc._install_and_reset(true)`→`bool(install_cb.call(true))`、`oc._rounds._grant_seg.apply_board_refreshed(oc.round_index)`→`grant_seg.apply_board_refreshed(round_index)`);头注「调用路径」句改写(编排器单行转发形态不变)
- [ ] battle_orchestrator.gd 收口::598-599 `return BattleRefreshFlow.can_refresh(self)`→`return _rounds.refresh_flow().can_refresh(battle_result)`;:606-607 →`return _rounds.refresh_flow().execute(battle_result, round_index)`;:262 `roll_round_actions()`→`roll_round_actions(round_index)`;:447 `settle_if_due()`→`settle_if_due(battle_result, round_index)`;:593 →`roll_round_actions(round_index)`;`can_refresh`/`player_request_refresh`/`_on_round_end`/`begin_battle`/`_exit_distribution` 五处体注释同步
- [ ] battle_orchestrator.gd 收口::598-599 `return BattleRefreshFlow.can_refresh(self)`→`return _rounds.refresh_flow().can_refresh(battle_result)`;:606-607 →`return _rounds.refresh_flow().execute(battle_result, round_index)`;:262 `roll_round_actions()`→`roll_round_actions(round_index)`;:447 `settle_if_due()`→`settle_if_due(battle_result, round_index)`;:593 →`roll_round_actions(round_index)`;`can_refresh`/`player_request_refresh`/`_on_round_end`/`begin_battle`/`_exit_distribution` 五处体注释同步+:280-281 注释(「`_hero_atk` 派生读=受理后不变量」句引用将删除的方法名)随 :282 改指一并改写
- [ ] 测试适配:settle_segments_test.gd :20-24 五段直构断言改束形态(以真实编排器协作件组装束逐段 `new(bundle)` 成功断言);:28-34 宿主回指断言 6 条改同一性断言(`oc._rounds._grant_seg.facts == oc._facts`、`oc._rounds._combat_seg.fx_host == oc.fx_host()` 等——同一性强度对应回指,削减弱化申报 1);adventure_feats_test.gd :671/:691/:727 `orch._hits_of(...)` → `DamageController.hits_of(...)`(削减弱化申报 2)
- [ ] 孤立验证新增段 → 出红只跑红件最小单元 → 并入全套(回归措辞:里程碑卡出口跑一次全套闸;卡内修复只做出红最小单元的最窄确认);本卡出口=golden 快照绿+battle_settlement 套件全绿+冒烟全绿
**T3 断点与存档公开面**(估时 0.5 工作日;区间 0.5–0.75)
取用:T1 底账。产出:处 3+处 4 清零。
**T3 断点与存档公开面**(估时 0.625 工作日;区间 0.5–0.75)
取用:T1 底账。产出:处 3+处 4 双向清零。
- [ ] breakpoint_store.gd 新增公开方法面(13 个,成员零增——类变量 15 贴顶):`func bind_save_manager(sm) -> void`、`func save_manager()`(读投影,可 null)、`func set_pending_next_level(v: bool) -> void`/`func pending_next_level() -> bool`、`func set_loadout_seeded(v: bool) -> void`/`func loadout_seeded() -> bool`、`func set_resume_bp(bp: Dictionary) -> void`/`func clear_resume_bp() -> void`/`func resume_bp() -> Dictionary`(返引用零拷贝——宿主读侧只读)、`func bp_read(key: String, bp: Dictionary, fallback: Variant = null) -> Variant`(=_bp_read 更名公开化,:160 内部调用点随改)、`func set_last_level_payload(payload: Dictionary) -> void`/`func last_level_payload() -> Dictionary`、`func set_last_treasure_cleared(v: int) -> void`/`func last_treasure_cleared() -> int`(方法体一律一行转发自有成员,零逻辑增量)
- [ ] breakpoint_store.gd 新增公开方法面(13 个,成员零增——类变量 15 贴顶):`func bind_save_manager(sm: SaveManagerCore) -> void`、`func save_manager() -> Variant`(读投影,可 null)、`func set_pending_next_level(v: bool) -> void`/`func pending_next_level() -> bool`、`func set_loadout_seeded(v: bool) -> void`/`func loadout_seeded() -> bool`、`func set_resume_bp(bp: Dictionary) -> void`/`func clear_resume_bp() -> void`/`func resume_bp() -> Dictionary`(返引用零拷贝——宿主读侧只读)、`func bp_read(key: String, bp: Dictionary, fallback: Variant = null) -> Variant`(=_bp_read 更名公开化,:160 内部调用点随改)、`func set_last_level_payload(payload: Dictionary) -> void`/`func last_level_payload() -> Dictionary`、`func set_last_treasure_cleared(v: int) -> void`/`func last_treasure_cleared() -> int`(方法体一律一行转发自有成员,零逻辑增量)
- [ ] adventure_runner.gd 37 处改址(逐处)::107/:157/:180/:185/:241/:438 → `set_pending_next_level(...)`;:235 → `pending_next_level()`;:115/:191/:201 → `set_loadout_seeded(false)`;:300-301 → `loadout_seeded()`/`set_loadout_seeded(true)`;:189 → `set_resume_bp(bp.duplicate(true))`;:388 → `clear_resume_bp()`;:302/:376/:377/:378 → `resume_bp()`(读侧零拷贝语义不变);:168/:302/:377/:378/:412 `_bp_read` → `bp_read`;:220 → `bind_save_manager(sm)`;:325-326 → `var sm = _bp_store.save_manager()` 后 `if sm != null: first = not sm.meta_state.career_state()...`;:421 → `set_last_level_payload(payload.duplicate(true))`;:464/:467-468 → `last_level_payload()`;:430 → `set_last_treasure_cleared(...)`;:456 → `last_treasure_cleared()`;:474-476 → `var sm = _bp_store.save_manager()` 后 `sm.clear_breakpoint()`/`sm.write_to_disk()`;:37 头注自述句核改(「宿主读写经件」落实后注释与实态一致)
- [ ] slot_store.gd:新增 `func active_path() -> String: return _path`(读投影——has_write_target :53 同族);`_migrate_legacy_save` 更名 `migrate_legacy_save` 公开化(:150 体逐字;禁留旧名壳)
- [ ] slot_store.gd:新增 `func active_path() -> String: return _path`(读投影——has_write_target :53 同族);`_migrate_legacy_save` 更名 `migrate_legacy_save` 公开化(:150 体逐字;禁留旧名壳);**反向私取 21 处改址**(第 3.1 节处 4 清单):`_save._read_only` 写 4 处(:26/:38/:69/:91)→ `_save.set_read_only(false)`、读 2 处(:65/:87)→ `var prev_ro: bool = _save.read_only()`、恢复写 2 处(:74/:96)→ `_save.set_read_only(prev_ro)`;`_save._reset_to_default` ×5(:28/:39/:70/:92/:119)→ `_save.reset_to_default()`;`_save._data` 读 2 处(:66/:88)→ `var prev_data = _save.data_snapshot()`、恢复写 2 处(:75/:97)→ `_save.restore_data(prev_data)`(引用零拷贝语义不变——snapshot 返 `_data` 本引用);`_save._peek_summary_at` ×2(:129/:134)→ `_save.peek_summary_at(...)`;`_save._rename_overwrite` ×2(:159/:162)→ `_save.rename_overwrite(...)`
- [ ] save_manager.gd 新增公开方法面承接 SlotStore 反向私取(类变量零增;公开 7→14):`func set_read_only(v: bool) -> void`/`func read_only() -> bool`(体一行转发 `_read_only`)、`func reset_to_default() -> void`(体=:279 逐字公开化——件内调用点零改,同名);`func data_snapshot() -> Dictionary[String, Variant]: return _data`/`func restore_data(data: Dictionary[String, Variant]) -> void: _data = data`(零拷贝——还原引用);`_peek_summary_at` 更名 `peek_summary_at` 公开化(:217 体逐字;**件内调用点复核**——slot_store :129/:134 为外部消费,件内若另有调用随改);`_rename_overwrite` 更名 `rename_overwrite` 公开化(:317 体逐字;件内调用点 :118/:286 随改)
- [ ] save_manager.gd 九行改址::51 → `slots.migrate_legacy_save(...)`;:66/:69/:105/:111/:118/:119/:285/:286 `slots._path` → `slots.active_path()`(:118-119 两处同名调用间 `_path` 无变更窗口——单线程同步段,逐位等价)
**T4 效果宿主累积面与配置挂载面**(估时 0.375 工作日;区间 0.25–0.5)
@@ -182,6 +183,7 @@ core 层(冒险/存档域)
- [ ] 复核 T2 步骤中 battle_fx_host.gd 两方法与 grant_segment.gd 四处改址已落(T2 内联实装——本卡不重复列);孤立验证:grant_segment 相关套件(seal_polarity/round_flow)出红最小单元
- [ ] board_gen_table.gd / enemy_table.gd / difficulty_table.gd 各新增 `func bind_resolver(resolver: ConfigDbResolver) -> void`(体一行 `_resolver = resolver`;三件注解同型)
- [ ] config_db.gd:157-159 三行改 `combat.board_gen.bind_resolver(_resolver)` / `combat.enemy.bind_resolver(_resolver)` / `run.difficulty.bind_resolver(_resolver)`(_assign_loaded 装配序零变化)
- [ ] **三 schema 解析冒烟(类型环验证义务)**:bind_resolver 引入 schema→ConfigDbResolver 参数类型注解,与 resolver 既有反向引用(config_db_resolver.gd:41/:61 引 EnemyTable.ROW_KINDS/band_of——:3-8 头注「类型环断根」先例)构成类型引用环——孤立验证必含 config_db_resolver_test 全套当轮真实跑(三 schema 经 `load()` 实例化+resolver 注入+resolve_row/resolve_rowset/resolve_modifiers 真实解析,类型环若引入解析失败当轮即炸);出红即 L3 停卡(禁改走 type-hint: ignore 通道——保 schema 类型注解完整)
**T5 结构性扫描与批收口**(估时 0.375 工作日;区间 0.25–0.5)
取用:全部前卡。产出:五处结构性恒零证据+批收口两件。
@@ -190,7 +192,7 @@ core 层(冒险/存档域)
①七段文件集(settlement/ 七 .gd)逐件:文件存在且非空+含对应 `class_name` 正锚+`\boc\b` 全文零命中〔封装5.1 V2〕
②battle_orchestrator.gd:非空+`func _hero_atk|func _feat_yield_adjust|func _harmful_variants|func _harmful_adjacent|func _hits_of` 零命中(五方法零残留)〔封装5.1 V3〕
③adventure_runner.gd:非空+`_bp_store\._` 零命中+`_bp_store.bp_read(` 正锚(新面在用)〔封装5.1 V4〕
④save_manager.gd:非空+`slots\._` 零命中+`slots.active_path()` 正锚〔封装5.1 V5〕
④save_manager.gd:非空+`slots\._` 零命中+`slots.active_path()` 正锚;slot_store.gd:非空+`_save\._` 零命中+`_save\.(set_read_only|read_only|reset_to_default|data_snapshot|restore_data|peek_summary_at|rename_overwrite)` 正锚〔封装5.1 V5〕
⑤grant_segment.gd:非空+`_fx_new_resource_types|_fx_bonus_delta` 零命中+`mark_new_resource_type(` 正锚〔封装5.1 V6〕
⑥config_db.gd:非空+`\._resolver\s*=` 零命中+`bind_resolver(_resolver)` 正锚〔封装5.1 V7〕
- [ ] run_all.gd manifest 追加 2 行:settlement_wiring_snapshot_test(expect 0,注记「R1 同种子逐项 golden 对拍主证〔封装5.1〕」)+encapsulation_sweep_test(expect 0,注记「R1–R6 结构性零命中扫描〔封装5.1〕」)
@@ -200,8 +202,8 @@ core 层(冒险/存档域)
### 估时汇总
T1 0.25|T2 1.25|T3 0.5|T4 0.375|T5 0.375。
区间合计 2.25–3.75 工作日;**精确汇总 2.75 工作日**(切分预案:若 T2 超 1.5 工日,把 T3 切出为独立半日卡顺延,其余不动;合计超 3 工作日=超卡面估时域,须用户确认后方可续批)。
T1 0.25|T2 1.25|T3 0.625|T4 0.375|T5 0.375。
区间合计 2.25–3.75 工作日;**精确汇总 2.875 工作日**(切分预案:若 T2 超 1.5 工日,把 T3 切出为独立半日卡顺延,其余不动;合计超 3 工作日=超卡面估时域,须用户确认后方可续批)。
## 8. 验证闸(改动—验收对照表)
@@ -213,7 +215,7 @@ T1 0.25|T2 1.25|T3 0.5|T4 0.375|T5 0.375。
| R2 搬家五方法归位 | damage_controller +hero_atk/hits_of/emit_hero_damage_taken 公开化+facts 成员;reward_grant +feat_yield_adjust;minesweeper_rules +harmful_variants/harmful_adjacent;编排器五方法删除+:282 改指 | settlement_wiring_snapshot_test〔封装5.1 V1〕(五方法消费路径全在行流内——主角攻击 base_value/奖励乘区/terrain_kind 事实/奥术矢开单);roll_multiplier_test.gd:_smoke_hero_atk_derived 既有回归;adventure_feats_test hits_of 面回归;encapsulation_sweep_test 编排器五方法定义零命中〔封装5.1 V3〕 | 单元 | `begin_battle()`(enc hero_atk override→spawn→攻击单)/授予段真实结算链 | 攻击单基值随 enc override 走(派生读贯通);行流逐位同;五方法宿主定义唯一(编排器零残留) | 既有:伤害公式与掷点乘区 |
| R3 grant→BattleFxHost 累积方法 | battle_fx_host +mark_new_resource_type/+add_bonus_delta;grant :82-84/:169-170/:378-379 改址 | seal_polarity_test/round_flow_skill_pool_test 既有全套回归(血税 bonus_delta 与地质学家 new_resource_type 两订阅行行为面);encapsulation_sweep_test grant 私键零命中+正锚〔封装5.1 V6〕 | 单元 | 授予段真实结算链(mine_hit/seal_hit fx 发射→施加面) | bonus_delta 轴累积值与 new_resource_type 首见判定逐位同;grant 源零私键直写 | 既有:封印与极性路由/不可逆 |
| R4 adventure_runner→BreakpointStore | breakpoint_store +13 公开方法面(_bp_read 更名 bp_read);adventure_runner 37 处改址 | save_rng_roundtrip_test.gd:_test_old_version_save_migrates_and_resumes+:_test_disk_roundtrip_preserves_breakpoint 既有回归(断点组装/回放/续玩全链真实入口);encapsulation_sweep_test `_bp_store\._` 零命中〔封装5.1 V4〕 | 单元+集成 | `AdventureRunner.resume_adventure()`/`start_adventure()`→`write_to_disk()`/`load_from_disk()` | 断点续玩逐位同(27 键冻结);adventure_runner 源零 `_bp_store._` 直读写 | 既有:旧档迁移链与断点续玩零跳号(集成) |
| R5 save_manager→SlotStore | slot_store +active_path/_migrate 更名公开化;save_manager 九行改址 | save_manager_domain_test.gd:_smoke_save+save_slot_isolation_test 既有回归;encapsulation_sweep_test `slots\._` 零命中〔封装5.1 V5〕 | 单元 | `SaveManagerCore.write_to_disk()`/`load_from_disk()`/`_ready()` 迁移口 | 写盘/读回/迁移路径逐位同(tmp+rename 原子序不变);save_manager 源零 `slots._` | 既有:存档写盘⇄读回往返保真 |
| R5 save_manager↔SlotStore 双向公开面 | save_manager→SlotStore=slot_store +active_path/_migrate 更名公开化+save_manager 九行改址;SlotStore→SaveManagerCore=save_manager +5 公开方法/2 更名公开化+slot_store 21 处改址 | save_manager_domain_test.gd:_smoke_save+save_slot_isolation_test 既有回归;encapsulation_sweep_test `slots\._` 与 `_save\._` 双向零命中+双正锚〔封装5.1 V5〕 | 单元 | `SaveManagerCore.write_to_disk()`/`load_from_disk()`/`_ready()` 迁移口/`SlotStore.activate_slot()`(三态恢复路径——read_only/data 快照还原)/`peek_slot_summary()`(窥视委托) | 写盘/读回/迁移/激活-恢复/窥视路径逐位同(tmp+rename 原子序、零拷贝还原语义不变);save_manager 源零 `slots._`+slot_store 源零 `_save._` | 既有:存档写盘⇄读回往返保真 |
| R6 config_db→三表挂载 | 三 schema +bind_resolver;config_db :157-159 改址 | config_db_resolver_test.gd 既有全套回归(_test_rowset_order_preserved/_test_row_kind_routing/_test_difficulty_clamp——resolver 注入后解析面逐位同);encapsulation_sweep_test `\._resolver =` 零命中+正锚〔封装5.1 V7〕 | 单元 | `ConfigDB.load_tables()`(装配段)→`ConfigDbResolver.resolve_*()` | 行集解析/难度 clamp 逐位同;config_db 源零 `_resolver` 直写 | 既有:行集寻址、行序保序与难度乘数 clamp |
**零行为改动面的证据义务**:本卡全部六行均为非行为改动(零行为变更批)——不设「行为改动」行;每行的零变更证明=T1 golden 同种子逐项比对(改前固化、改后全程绿)+既有套件零转红+结构性 sweep 恒零。能力行全部「既有」、零新增——判断依据:本批零行为变更=玩家可观测能力面零变化,无新能力可登记;受影响存量行的真实入口与代表用例名零变化(settle_segments_test/adventure_feats_test 文件名与其在册引用不变),故能力清单零编辑(批末核对义务在 T5)。
@@ -260,6 +262,7 @@ T1 0.25|T2 1.25|T3 0.5|T4 0.375|T5 0.375。
- `MinesweeperRules.harmful_variants`/`harmful_adjacent`——改名迁移;db 为构造参(:44 既有)。grep 唯一。
- `BattleFxHost.mark_new_resource_type`/`add_bonus_delta`——新方法旧账面(成员零增);grep 同名零命中,命名与既有 apply_ac_bonus/counter_add 动词族同型。
- `SlotStore.active_path`——grep 全库零同名;has_write_target 同族读投影。
- SaveManagerCore 五公开面(承接 slot_store 反向私取)——`set_read_only`/`read_only`/`reset_to_default`/`data_snapshot`/`restore_data` grep 作方法名全库零第二处(现仅为成员名或私有方法);`peek_summary_at`/`rename_overwrite` 为私有方法更名公开化非并存(禁别名,第 13 节适用);`reset_to_default` 件内既有调用点同名零改。
- `BreakpointStore` 13 方法——grep `pending_next_level|loadout_seeded|resume_bp|last_level_payload|last_treasure_cleared|bp_read|bind_save_manager` 作为**方法名**全库零命中(现仅为成员名);成员到方法一一对应,无第二落点。
- 三 schema `bind_resolver`——grep 零同名;参数类型 ConfigDbResolver 与 config_db.gd:43 既有协作类同一实例。
- `RoundCycle.refresh_flow`——grep 零同名;读出口与 stats()/wallet() 组件出口先例同型(adventure_runner.gd:60-82)。
@@ -277,9 +280,9 @@ T1 0.25|T2 1.25|T3 0.5|T4 0.375|T5 0.375。
新增 .gd 文件仅 2 个测试件(SceneTree 测试脚本,全类型标注、零公开生产面——接口块预算余量充足)。生产代码全部落既有件,按「存量触面一查」逐件对账(S13 默认阈值:公开方法 ≤20/类变量 ≤15/分支 ≤8/返回 ≤6):
- **贴顶四件(禁再增成员,T1 读数锁定)**:battle_orchestrator.gd 15(本批成员零净增——五方法删除不涉成员);round_cycle.gd 8→15(束解包 7+_refresh_flow 1+既有 7——贴顶,头注记「贴顶禁再增」);battle_fx_host.gd 15(零增,方法-only);breakpoint_store.gd 15(零增,方法-only)。
- **类变量净增件**:grant_segment 3→12、combat_segment 3→10、verdict 1→5、aura 1→1、decay 0→2(aura/decay 按 1/2 计——现各持 oc 一员)、battle_refresh_flow 0→8、damage_controller 12→13——全部 ≤15。
- **公开方法净增件**:minesweeper_rules 18→**20 贴顶**(+2)、damage_controller 10→13(+hero_atk/hits_of/emit_hero_damage_taken 公开化)、reward_grant 9→10、battle_fx_host 16→18、slot_store 10→11、breakpoint_store 5→18、RoundCycle 3→4、三 schema 各 +1——全部 ≤20。
- **迁移函数对账**:搬家五方法+`_migrate_legacy_save`+`_bp_read`+`_emit_hero_damage_taken` 逐个查 `tools/gdstyle_baseline.txt` 源键——基线无此 8 键(默认阈值内),迁移即原体;若 T1 读数发现任一源函数 branches/returns 超默认登记值,迁移即拆函数(拆分不改语义,不算迎合机检——与第 13 节区分)。
- **类变量净增件**:grant_segment 3→12、combat_segment 3→10、verdict 1→5、aura 1→1、decay 1→2(两件现各持 oc 一员——aura 换单回调成员 1→1、decay 换两成员 1→2)、battle_refresh_flow 0→8、damage_controller 12→13——全部 ≤15。
- **公开方法净增件**:minesweeper_rules 18→**20 贴顶**(+2)、damage_controller 9→12(+hero_atk/hits_of+emit_hero_damage_taken 公开化——2026-11-03 终审实核现值 9)、reward_grant 9→10、battle_fx_host 16→18、slot_store 10→11、breakpoint_store 5→18、save_manager 7→14(+5 承接方法+peek_summary_at/rename_overwrite 两更名公开化)、RoundCycle 3→4、三 schema 各 +1——全部 ≤20。
- **迁移函数对账**:搬家五方法+`_migrate_legacy_save`+`_bp_read`+`_emit_hero_damage_taken`+`_peek_summary_at`+`_rename_overwrite` 逐个查 `tools/gdstyle_baseline.txt` 源键——基线无此 10 键(默认阈值内),迁移即原体;若 T1 读数发现任一源函数 branches/returns 超默认登记值,迁移即拆函数(拆分不改语义,不算迎合机检——与第 13 节区分)。
- **存量触面 S13 预期**:本卡触件 15 件(第 3.2 节清单)S13 键较 T1 现场基线**只降不升**(净删为主:五方法约 45 行迁出、107 处 oc._ 改址不增行数;净增面=两累积方法+13 bp 方法面+束解包成员行);adventure_runner 既有登记键(类变量 23)照登对账零变化。降不达即检查是否夹带超预算成员,L3 ③兜底。
- **指标例外申报**:无(零新件、零超默认阈值新增面;若实现中发现例外,走本卡异常分级 L3 ③停卡,禁就地豁免)。