docs(效果引擎无状态化·写卡): 需求卡片成文(reports/需求卡片-效果引擎无状态化批-2026-10-20.md,零待裁点开工门=U0)——T0–T8 九卡带签名/断言/落点、验收 V1–V14 三问逐条可答、变异验证五条、V12 具名锚+锚新鲜度核对步;06 条目推进「已写卡(本卡路径)」;提案 §10.1 补行号再漂移注记(c5200b6b 注释清偿后以卡片开工前实查为准);卡片经独立会话对抗复核五项回炉全落(行号群订正/V9 assert 侧闭环/判定函数名落定/估时对齐/裸引擎段实数 53 处)——--docs 闸全绿
This commit is contained in:
1 parent
f513463d27
commit
f2bb587170
3 files changed
+295
-1
No files matched your search
@@ -636,7 +636,7 @@
|
||||
|
||||
**归属**:architecture.md 与 game/core/effect_engine.gd(待立独立批)
|
||||
|
||||
**状态**:待裁决(是否统一寿命域口径——2026-10-19 已裁:统一口径方案作废,改走无状态化重构)+文档设计已闭合(design/research/提案-效果引擎无状态化-2026-10-19.md v1.2——2026-10-20 §7.10 闭合)+待写卡
|
||||
**状态**:待裁决(是否统一寿命域口径——2026-10-19 已裁:统一口径方案作废,改走无状态化重构)+文档设计已闭合(design/research/提案-效果引擎无状态化-2026-10-19.md v1.2——2026-10-20 §7.10 闭合)+待写卡+已写卡(reports/需求卡片-效果引擎无状态化批-2026-10-20.md)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -550,6 +550,8 @@ func counters_merge_export(exported):
|
||||
|
||||
### 10.1 行号订正汇总
|
||||
|
||||
> 🔴 **2026-10-20 再漂移注记**:本表「实际」列的行号以提案复核时点为准;其后的 `c5200b6b`(禁写变更记录批·代码注释清偿)已使本文件部分行号再度漂移(如引擎成员块现役 :83-88、`counters_seed` :255、`EffectEngine.new` :271、树合成行 :136-155)。行号时效以需求卡片 `reports/需求卡片-效果引擎无状态化批-2026-10-20.md`(开工前实查)为准,本节数字仅作沿革参考。
|
||||
|
||||
| 草案初版写法 | 实际 | 说明 |
|
||||
|---|---|---|
|
||||
| `effect_engine.gd` :83/84/85/86/88 | :86/87/88/89/91 | 整体 +3——迭代 31 卡② 在 `:42-44` 插入 `forgive_seal_miss` 三行注释 |
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
# 需求卡片:效果引擎无状态化批(计数器外置·分桶)
|
||||
|
||||
- **日期**:2026-10-20
|
||||
- **来源**:06-待办清单「计数器寿命域未统一」条目(2026-10-18 登记,来源=会话提及,设计面=文档轨),设计已闭合推进至待写卡(唯一事实源:`design/research/提案-效果引擎无状态化-2026-10-19.md` v1.2——§3 目标形态、§7 N1–N6 定值、§7.7 采集定值、§7.10 缺口闭合定值)
|
||||
- **批性质**:工程直入类·架构重构(restructure)——代码域批,禁写 `design/` 整个目录与根规则文件,产出物只落 `reports/`
|
||||
- **估时**:≈3.75–5.75d(T0–T8 单卡;超盒切分预案=T7 拆「断言新增/迁移」与「复放比对」两波先后挂,T3 与 T7 测试迁移互不阻塞可并行切)
|
||||
- **状态**:成文待审——零待裁点,开工门=U0(用户发令)
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标与完成定义
|
||||
|
||||
把 `EffectEngine` 从「解释器+自带状态计数器容器」改为**纯计算引擎(零运行时状态)**:效果侧计数器按 round/battle/level/adventure 四只桶外置、由各生命周期的宿主对象持有(寿命随宿主生灭,不需要寿命字段),事件触发时经 ctx 参数传入,引擎只做判定;计数器归属用 id 前缀表达并加载期强校验。
|
||||
|
||||
**完成定义**(全部满足才算完):
|
||||
|
||||
1. `EffectEngine` 实例内无任何运行时可变数据(仅剩编译产物 `_triggers` 与只读依赖 `db`);
|
||||
2. 计数器四桶外置:round/battle 桶挂 `BattleOrchestrator`、level 桶挂 `LevelRunner`、adventure 桶挂 `run_ledger.adventure_counters`,桶随宿主生灭;
|
||||
3. 搬运链整段删除:`counters_export`/`counters_seed`(引擎)与 `counters_seed_snapshot`/`counters_merge_export`(RunLedger)零残留;
|
||||
4. `adventure_runner.gd:838-841` 硬编码清除名单(`_reset_tree_limited_counters`)删除,按关清零由 LevelRunner 每关 new 天然承载;
|
||||
5. 计数器归属机器可读且加载期可校验:`.tres` 行(errs→加载致命)与树合成行(`_push_trigger` assert)双落点,写错前缀即致命;
|
||||
6. 同种子复放比对按分组判读通过(V12):未受影响局 RUNSUM 全字段逐位一致;受影响局输入面字段恒等+`levels_cleared` 分布不得上行——**不声称零漂移**(adventure 桶跨战持久与天赋树每关限次是已定性预期差异,提案 §7.7/§7.8);
|
||||
7. `dig_combo` 死读数连同 combo 分支删除,零行为差(§7.10.14);
|
||||
8. 旧档断点含旧计数键加载不崩(V13,无迁移——2026-10-18 代码术语刷新批先例)。
|
||||
|
||||
## 2. 设计事实源
|
||||
|
||||
`design/research/提案-效果引擎无状态化-2026-10-19.md` **v1.2**(2026-10-20 设计闭合版)——本卡全部设计定值的唯一出处:
|
||||
|
||||
- 目标形态与四桶表=提案 §3(3.1 宿主定值/3.2 接口定稿/3.3 前缀归属);
|
||||
- N1–N6 定值=提案 §7;不发起全冒险模拟采集=提案 §7.7(零数值改动=零采集,本批一个数值表值都不改);搬运链缺陷全解=提案 §7.8;
|
||||
- 写卡前缺口闭合定值=提案 §7.10(ctx 结构/容器类型与测试接口/前缀校验双落点/写口静态化/施加面补列/改名传播面/保险双账不改面/A1 注入口径/level 桶接口/复放分组判读/mine_hit 构造/dig_combo 删除/H1 补条)。
|
||||
|
||||
与 06 条目状态里的闭合凭据一致(v1.2)。
|
||||
|
||||
## 3. 现状事实(2026-10-20 代码级实查,开工自行复核)
|
||||
|
||||
**引擎侧**:
|
||||
|
||||
- `game/core/effect_engine.gd:83-88` 五成员:`_triggers`(:83,编译产物,留)、`_counters`(:84,运行时容器,搬走)、`_reset_on_round_start`(:85)/`_adventure_counter_ids`(:86-87 含续行,编译名单,随分桶删除)、`db`(:88,只读,留)。
|
||||
- 接口与调用点:`rebuild()` :98;`dispatch()` :208(调用点 6 处——`battle_orchestrator.gd:91` `_fx_emit` 汇聚面/`damage_controller.gd:78` `_fx_hits` 汇聚面/`action_economy.gd:103/:164/:191`/`reward_economy.gd:65`);`counter()` :224(外部读 4 处:`battle_orchestrator.gd:638`、`damage_controller.gd:345`、`grant_segment.gd:103/:205`);`counter_add()` :228(写 6 面:`action_economy.gd:108/:111/:169`、`damage_controller.gd:351/:464`、`grant_segment.gd:327`);`counter_spend()` :237(`battle_orchestrator.gd:714` 受理闸);`counters_export()`/`counters_seed()` :246/:255;`validate_trigger_row()` :351(静态,`data/schemas/feat_table.gd:44`、`treasure_item_table.gd:104` 消费)。
|
||||
- round_start 清零在 `dispatch` 特判内(:210-212 按名单清零);真实发射点=`battle_orchestrator.gd:97 _emit_round_start()`(调用点 `:425` 首轮/`:1077` 续轮)。
|
||||
- `DO_KEYS` :72-75 含 `domain`/`reset_at` 两键;树合成行 `:136-155` 硬编码 `tree_sense_sharp_used`/`tree_sense_guard_used`(走 `_push_trigger`,现仅 assert 事件域——前缀零校验)。
|
||||
|
||||
**搬运链与自锁**:`run_ledger.gd:40-45` `counters_merge_export` 判空早退(:42)⇒ 全新开局 adventure 域四枚整局不写入(断点回填 :206-208 是唯一解锁路径);战末导出在 `battle_orchestrator.gd:1122-1123`,战首回灌 `:390`。
|
||||
|
||||
**宿主侧**:`battle_orchestrator.gd:271` `_fx = EffectEngine.new`(_init :268-292 段内 `set_fx` 三处注入 :280-282);`begin_battle` :372-373 `_ledger = enc["ledger"]` 或缺省新账;`level_runner.gd:450-482` `_start_battle` 每战 new 编排器、enc 装配(:471 `"ledger"` 下传行);`adventure_runner.gd:843-845` 每关 new LevelRunner+调 `_reset_tree_limited_counters`;`:255` 新冒险置空 `run_ledger.adventure_counters = {}`;断点写键 `:1033`/回填 `:206-208`。
|
||||
|
||||
**保险双账**:`grant_segment.gd:311-317` 同一标错分支内 `_perfect_forgiven` 加一(:314)与 `_apply_counter_hit` 落 `insurance_used`(:315→:327)**同点双记各司其职**——前者供判定段两账相减、后者供 when `lt 1` 限次闸;本批不改面(V25 迁移保绿即证)。
|
||||
|
||||
**死路**:`battle_orchestrator.gd:635-647` `_feat_yield_adjust` 读 `dig_combo`(全仓无数据行声明——feats.tres/treasure_items.tres/树合成行三源零命中;feats.tres 唯一 `"cap"` 行属石肤 ac_bonus `:576-583`,yield_mult 带 cap 行零个)⇒ `combo_val` 恒 0、`combo_cap` 恒 ≤0,分支恒短路。
|
||||
|
||||
**数据行**:`feats.tres` 计数 id 共 14 枚+树合成 2 枚=16 枚;`reset_at: round_start` 恰 4 行(`round_blast_spent` :212/`instinct_atk` :494/`round_mines` :518/`round_digs` :723——全带 round_ 前缀或随改名获得前缀,分桶后「整桶清空」与现役名单清零逐键等价);`domain` 键行:`twin_digs` :31/`pain_layers` :377/:535/:628(另 :407 附近 set 行)/`insurance_used` :877(battle)。
|
||||
|
||||
**测试面**:`tests/run_all.gd` manifest(负面套件协议 `expect:1`+`negative:true`,先例 `reward_dangling_treasure_test.gd` 夹具注入);`tests/README.md:58` 记套件数 26;`game/presentation/` 全目录 counter_id 与 16 枚 id 字面零命中(呈现层不入改名传播)。
|
||||
|
||||
## 4. 设计契约(违反即返工;🔴 触碰=L3 停机呈报)
|
||||
|
||||
1. 🔴 **确定性**:除 V12 已定性的两处行为变更(adventure 桶真跨战持久、天赋树锋/守真每关限 2)外,同种子复放必须逐位一致——读写时序、装载序、命中序零变化;命中序=装载声明序写死不碰。
|
||||
2. 🔴 **数值零改动**:本批不改任何数值表值;天赋树锋/守「每战 2→每关 2」是回到设计意图(`effect_engine.gd:137` 注释),不是平衡调整;禁顺手调任何 provisional 值。
|
||||
3. 🔴 **round 桶就地清空**:轮始清零必须 `.clear()`(或等效就地清空),**禁 `= {}` 重赋值**——重赋值会切断 ctx 持有的引用。
|
||||
4. 🔴 **搬运链删除后禁留任何副本同步时点**:战末导出/战首回灌/判空守卫三类代码不得以任何形态复活(含「防御性保留」)。
|
||||
5. 🔴 **保险双账不改面**:`_perfect_forgiven` 与 `insurance_used` 同点双记关系原样保持(§3 现状事实),禁合并、禁迁账、禁改判定段两账相减语义(N6 定值)。
|
||||
6. 🔴 **两落点同源**:前缀校验的判定函数唯一(静态单点),`validate_trigger_row` 与 `_push_trigger` 共用;禁两处各写一份前缀表。
|
||||
7. 🔴 **容器与接口逐字锁定**:`EffectContext` 四字段名 `round_bucket`/`battle_bucket`/`level_bucket`/`adventure_bucket`;编排器成员 `fx_counters_round`/`fx_counters_battle`/`counters_ctx`;LevelRunner 成员 `level_counters`;enc 下传键 `"level_counters"`;改名 4 枚新 id `adv_twin_digs`/`lvl_tree_sense_sharp_used`/`lvl_tree_sense_guard_used`/`round_instinct_atk`。实现期不得另起名。
|
||||
8. 🔴 **pain_layers 归 battle 零语义变更**:只改归属(删 `domain` 键),「攒层→下次攻击附加→用后清零」行为逐位不变(N4)。
|
||||
9. 🔴 **旧档不迁移**:改名后旧档断点旧键成死键属预期(H1 只断言不崩);禁加迁移体、禁动 `SAVE_FORMAT_VERSION`。
|
||||
10. 🔴 **实现批禁写 `design/` 与根规则文件**;`sim-data/` 零采集零重跑(§7.7 定值——本批零数值改动,锚与读数不动)。
|
||||
11. 🔴 **同名成员禁遮蔽内建**:ctx 字段名已避讳(`round_bucket` 非 `round`),实现期引入新成员时同规。
|
||||
|
||||
## 5. 范围边界
|
||||
|
||||
**做**:§1 完成定义 1–8 全部;`EffectContext` 新类;引擎接口 ctx 化与写口静态化;7 个施加点迁移;前缀校验双落点;4 枚 id 改名+`domain`/`reset_at` 键删除;`dig_combo` 死路删除;测试新增/迁移/变异验证;同种子复放比对(零局新采集,锚内子集 20 种子);`static_scan.sh` 新增 S 段+`run_all.gd` manifest 登记。
|
||||
|
||||
**不做**(去向已定):
|
||||
|
||||
| 不做项 | 去向 |
|
||||
|---|---|
|
||||
| `charge_reset`(秘宝充能周期)、凭证件裸标量、SaveManager meta 域 | 提案 §9 已排除,不动 |
|
||||
| 断点快照结构(level 桶不进断点——N3:写入时刻恒空,「进」是空操作) | 不动;「退菜单续玩可刷新每关限次」属既有行为,登记真人检测面(V14 目检项) |
|
||||
| 编排器 5 个效果运行态(`_fx_ac_round`/`_fx_ac_battle`/`_fx_new_resource_types`/`_fx_bonus_delta`/`_perfect_forgiven`) | N6 定值:只归计数器,留编排器 |
|
||||
| 天赋树锋/守重新定价 | 独立议题,不进本批(§4.5 B3) |
|
||||
| architecture.md「系统无状态」原则补条 | 已登记 06 新条目(文档轨·待文档设计),归文档批;本批反哺点带依据 |
|
||||
| `roadmap.md` 当前位 stale | 已呈报在案,归并行会话 |
|
||||
| MC 采集(任何档位) | §7.7 定值:零数值改动=零采集 |
|
||||
| 元素类型精化(`Dictionary[String, int]`) | S9 现行口径 `Dictionary[Variant, Variant]` 合格,精化另走裁决 |
|
||||
|
||||
## 6. 关联文档同步面(实现批禁写本表所列文档——义务全部走 `reports/iter<N>-反哺点-<日期>.md`)
|
||||
|
||||
| 文档 | 关联点(本批实现改变它的哪条陈述) | 同步义务 |
|
||||
|---|---|---|
|
||||
| `design/engineering/architecture/architecture.md` | ①模块归属表 effect_engine 行「对外暴露」列记 `counters_export·counters_seed` 与「domain=adventure 跨战斗持久」(:116)——改后均不存在;②战斗域装配现状节「战末 export/开局 seed 时点语义不变」(:125)随搬运链删除失义;③「架构原则」节缺「系统无状态」条目(立项判据补条) | 反哺点清单逐条列出(①②改写成 ctx 形态描述、③指向 06 在册条目「效果引擎系统无状态原则缺架构文档条目」),用户裁决后归文档批 |
|
||||
| `game/tests/README.md` | :58 记「manifest 已登记实跑 26 套件」——本批新增 1 负面套件 | 反哺点(机械面文档,批后由文档批更新套件数与段描述) |
|
||||
| `design/gdd/06-待办清单.md` | 上游条目「计数器寿命域未统一」随批完成整条删除(收口=batch-closure 技能);条目现状内引用的行号(:838-841 等)随实现漂移 | 批内不动;收口时整条删除(行号订正随之消亡) |
|
||||
| `design/gdd/07-体验验证清单.md` | 天赋树锋/守第二次后无减免=玩家可感知削弱,需真人目检入册 | 反哺点(登记项见 §9 真人目检面) |
|
||||
| `design/gdd/术语表.md` | 零关联(本批不造新术语;四桶/前缀均为代码标识符非玩家术语) | 无 |
|
||||
|
||||
## 7. 卡前文件结构图
|
||||
|
||||
**新建**:
|
||||
|
||||
| 文件 | 职责 |
|
||||
|---|---|
|
||||
| `game/core/effect_context.gd` | `EffectContext`——四桶引用束(RefCounted,四公开类型化字段,零方法) |
|
||||
| `game/tests/unit/data_config/counter_prefix_fatal_test.gd` | E1 负面套件:坏前缀 counter_id 行 → load_tables 拒绝(expect 1) |
|
||||
|
||||
**修改**:
|
||||
|
||||
| 文件 | 改动 |
|
||||
|---|---|
|
||||
| `game/core/effect_engine.gd` | 删三状态成员与搬运接口;dispatch/counter 带 ctx;写口改静态纯函数+`bucket_of`;`_push_trigger` 前缀校验;DO_KEYS 删两键;合成行(:136-155)id 改名 |
|
||||
| `game/core/battle_orchestrator.gd` | 两桶公开成员+ctx 构造挂载;set_fx 扩参;`dig_combo` 死路删除;战末导出两行删除 |
|
||||
| `game/core/action_economy.gd` | set_fx 扩参;3 dispatch 面+3 写口静态化 |
|
||||
| `game/core/damage_controller.gd` | set_fx 扩参;dispatch 汇聚面+1 读 2 写静态化 |
|
||||
| `game/core/reward_economy.gd` | set_fx 扩参;dispatch 面加 ctx |
|
||||
| `game/core/settlement/grant_segment.gd` | `_apply_counter_hit` 静态化;2 读口 ctx 化;`combo_cap` 收集与实参删除 |
|
||||
| `game/core/run_ledger.gd` | 删 `counters_seed_snapshot`/`counters_merge_export` |
|
||||
| `game/core/adventure_runner.gd` | 删 `_reset_tree_limited_counters` 及调用点 |
|
||||
| `game/core/level_runner.gd` | `level_counters` 公开成员+enc `"level_counters"` 下传 |
|
||||
| `game/data/tables/feats.tres` | 4 枚 id 改名;`domain`/`reset_at` 键逐行删除 |
|
||||
| `game/tests/static_scan.sh` | 新增 S 段:旧件符号+带引号旧 id 字面零命中 |
|
||||
| `game/tests/run_all.gd` | manifest 登记负面套件 |
|
||||
| `game/tests/unit/core/effect_words_t1_test.gd` | ⑥ export/seed 块、⑦ reset_at/spend 块重写为桶语义;裸 dispatch/写口 ctx 化 |
|
||||
| `game/tests/unit/core/tree_rules_v11_test.gd` | :29-39 合成行字面 id 随改名 |
|
||||
| `game/tests/unit/core/feat_vouchers_test.gd` | V16 键名随前缀;V25 迁移保绿;新增 H1 旧档不崩断言 |
|
||||
| `game/tests/unit/core/settle_segments_test.gd` | `:32-33` 样本 id 换活 id+ctx 形态 |
|
||||
| `game/tests/unit/core/treasure_effects_test.gd` | 裸 dispatch 面 ctx 化(:34/:45/:53-56) |
|
||||
| `game/smoke/smoke_all.gd` | 新增 V1–V6/V8/V12 冒烟断言段;`:6076-6083`/`:6124-6128` 旧链删除;`:1419-1602` 裸引擎段 53 处 dispatch+8 处写口改 ctx 形态;各 rig enc `"adventure_counters"` 死键清除;`:1610` rebuild 调用零迁移 |
|
||||
|
||||
## 8. 任务卡 T0–T8
|
||||
|
||||
### T0 基线(0.25d)
|
||||
|
||||
- [ ] worktree/分支开工(process-conventions §1);拷主区 `.godot/` 与字体 `.import` 边车
|
||||
- [ ] 基线三查记档:冒烟全绿数目、单元 26 套件全绿、探针基线;记录 `sim-data/` 现行锚文件名与 sha1(**只记录不跑**——零数值改动禁采集)
|
||||
- [ ] `git log --oneline -1` 与 `tools/run_all_gates.sh --code` 基线档记档(起点绿态)
|
||||
|
||||
**产出**:基线档(实现报告 T0 节)。
|
||||
|
||||
### T1 `EffectContext` 新建+四宿主接线(0.5–1d)
|
||||
|
||||
**取用**:无。**产出**:`EffectContext`(字段名见契约 7)——T2–T7 全部引用。
|
||||
|
||||
- [ ] 新建 `game/core/effect_context.gd`:`class_name EffectContext extends RefCounted`;四字段 `var round_bucket: Dictionary[Variant, Variant] = {}`(battle_bucket/level_bucket/adventure_bucket 同型);文件头注 ≤8 行两类白名单;跑一次编辑器扫描刷新全局类缓存(code-conventions §4.5)
|
||||
- [ ] `BattleOrchestrator` 增三公开成员:`fx_counters_round`/`fx_counters_battle`(`Dictionary[Variant, Variant]`)+`counters_ctx: EffectContext`;`_init` 内构造 ctx 并挂自有两桶引用
|
||||
- [ ] `LevelRunner` 增公开成员 `level_counters: Dictionary[Variant, Variant]`;`_start_battle` enc 增 `"level_counters": level_counters`(`"ledger"` 行 :471 后)
|
||||
- [ ] `begin_battle` :373 后挂载:`counters_ctx.adventure_bucket = _ledger.adventure_counters`;`enc.get("level_counters")` 为 Dictionary 时 `counters_ctx.level_bucket = enc["level_counters"]`(缺省=调试/单场空桶,与 `_ledger` 缺省新账同式)
|
||||
- [ ] `set_fx` 三处扩参:`func set_fx(fx: EffectEngine, ctx: EffectContext) -> void`(action_economy.gd:48/damage_controller.gd:70/reward_economy.gd:23),三协同件各增 `_ctx` 成员;`battle_orchestrator.gd:280-282` 调用点同步
|
||||
- [ ] 删 `adventure_runner.gd:838-841` `_reset_tree_limited_counters` 与 `:845` 调用点(同批摘除冒烟 `:6125` 直呼——F2 面随 T7 断言同轮)
|
||||
- [ ] 孤立验证:`--headless --script` 最小驱动 `EffectContext.new()`+编排器 `_init` 构造 ctx 成功(新码先行孤立验证纪律)
|
||||
|
||||
### T2 引擎删状态+ctx 接口+静态写口(0.5–1d)
|
||||
|
||||
**取用**:T1 的 `EffectContext`。**产出**:引擎新接口面——`dispatch(ctx, event, payload, facts)`/`counter(ctx, id)`/`static bucket_of(ctx, id)`/`static counter_add(ctx, id, value, set_mode=false)`/`static counter_spend(ctx, id, value) -> bool`。
|
||||
|
||||
- [ ] 删成员 `_counters`/`_reset_on_round_start`/`_adventure_counter_ids`(:84-87 含续行)与 rebuild 内三处清零/收集(:100-101/:156-157/:181-190)
|
||||
- [ ] `rebuild()` 签名不变(`feat_ids, item_ids, tree_rules`)——冒烟 `:1610` 调用面零迁移
|
||||
- [ ] `dispatch(ctx: EffectContext, event: String, payload: Dictionary, facts: Callable = Callable()) -> Array`;round_start 特判(:210-212)改 `ctx.round_bucket.clear()`——**就地清空**(契约 3)
|
||||
- [ ] `counter(ctx: EffectContext, counter_id: String) -> int`(读 `bucket_of(ctx, counter_id)`)
|
||||
- [ ] 新增 `static func bucket_of(ctx: EffectContext, counter_id: String) -> Dictionary[Variant, Variant]`:`round_`→round_bucket/`lvl_`→level_bucket/`adv_`→adventure_bucket/其余→battle_bucket(前缀规则唯一出处)
|
||||
- [ ] 新增静态 `counter_add`/`counter_spend`(签名见产出块;算术与阈值闸语义从现役 :228-242 逐字保留);删实例版两方法与 `counters_export`/`counters_seed`(:246-257)
|
||||
- [ ] `run_ledger.gd` 删 `counters_seed_snapshot`(:36-37)与 `counters_merge_export`(:40-45)
|
||||
- [ ] `DO_KEYS` 删 `"domain"`/`"reset_at"`(:72-75)
|
||||
- [ ] 孤立验证:裸引擎 rig `EffectEngine.new(null)`+自建 ctx,合成一行 counter_add 行 dispatch→静态写口→counter 读回一致
|
||||
|
||||
### T3 施加点改写+dig_combo 死路删除(0.5–1d)
|
||||
|
||||
**取用**:T2 全部接口。**产出**:生产侧零 `_fx.counter_add(`/`_fx.counter_spend(`/`counters_export` 残留(V10 静态扫描可证)。
|
||||
|
||||
- [ ] `action_economy.gd`::103/:164/:191 dispatch 加 `_ctx`;:108/:111/:169 写口改 `EffectEngine.counter_add(_ctx, ...)`——:103-108「counter_spend 订阅→加收对价+积计数」读-判-写序列逐字保留(§7.10.6)
|
||||
- [ ] `damage_controller.gd`::78 dispatch 加 ctx;:345 读改 `EffectEngine.counter(_ctx, ...)`;:351/:464 写口静态化
|
||||
- [ ] `reward_economy.gd`::65 dispatch 加 ctx
|
||||
- [ ] `grant_segment.gd`::103/:205 读口 ctx 化(经 `oc.counters_ctx`);:327 `_apply_counter_hit` 内写口改静态(调用点 :66/:122/:156/:215/:264 零改动);:54/:61/:62 `combo_cap` 收集与实参删除
|
||||
- [ ] `battle_orchestrator.gd`::88 `_fx_emit` 加 `counters_ctx`;:714 受理闸改 `EffectEngine.counter_spend(counters_ctx, ...)`;:635-647 删 `dig_combo` 死读数+combo 加成分支+`_feat_yield_adjust` 第五参(§7.10.14,零行为差);:1122-1123 战末导出两行删除(:1118-1121 bonus_delta 汇入保留——那是 N6 留编排器的运行态,不是计数器)
|
||||
- [ ] 孤立验证:单场编排 rig begin_battle→request_dig 一次→`run_ledger.adventure_counters` 立即可见写入(无战末时点依赖)
|
||||
|
||||
### T4 round 泛化+宿主清零确认(0.25d)
|
||||
|
||||
**取用**:T2 的 round_start 特判、T1 的宿主成员。**产出**:三清零点在位(轮始一处+宿主 new 两处)。
|
||||
|
||||
- [ ] 确认轮始清零唯一入口=引擎 dispatch 特判(T2 已改);编排器侧零新增清零代码
|
||||
- [ ] 确认 battle/level 桶零显式清零代码(宿主 new 天然空);全仓 grep `_reset_on_round_start`/`_adventure_counter_ids`/`_reset_tree_limited_counters` 零命中
|
||||
- [ ] 孤立验证:round 桶写非零→dispatch("round_start")→整桶空;battle 前缀键同一 dispatch 下不动
|
||||
|
||||
### T5 前缀校验双落点(0.25d)
|
||||
|
||||
**取用**:T2 的 `bucket_of` 前缀规则。**产出**:加载期前缀致命通道(V9)。
|
||||
|
||||
- [ ] 新增静态判定函数 `static func counter_id_legal(counter_id: String) -> bool`(名字锁定):无前缀=true(battle);`round_`/`lvl_`/`adv_` 前缀=true;其余带前缀形态(`meta_` 等)=false——前缀规则与 `bucket_of` 同源(bucket_of 解析为 battle 而 id 首段含 `_` 即非法,单一规则表)
|
||||
- [ ] `validate_trigger_row` 增分支:`do` 含 `counter_id` 时校验,非法→errs 追加 `{"category": "enum", ...}` 违例
|
||||
- [ ] `_push_trigger` 增 assert:`do` 含 `counter_id` 时同规则 assert(树合成行路径,写错调试期致命;assert 消息以 `[效果引擎]` 前缀起头,供孤立验证扫描)
|
||||
- [ ] 孤立验证(V9 assert 侧):`--headless --script` 最小驱动 rebuild 带「counter_id 带非法前缀」的合成行——输出扫到 `[效果引擎]` assert 签名=拦截在位(debug 通道;assert 不改退出码,判据=输出签名扫描)
|
||||
- [ ] 新建 `game/tests/unit/data_config/counter_prefix_fatal_test.gd`:copy_tables 夹具→向 feats.tres 注入 `"counter_id": "meta_probe"` 行→`load_tables` 必须拒绝→quit(1);违规放行 quit(2)(reward_dangling_treasure_test.gd 同构,退出码协议同款)
|
||||
- [ ] `tests/run_all.gd` manifest 登记:`{"path": "res://tests/unit/data_config/counter_prefix_fatal_test.gd", "expect": 1, "negative": true}`
|
||||
|
||||
### T6 数据行与合成行改名(0.25d)
|
||||
|
||||
**取用**:契约 7 的 4 枚新 id。**产出**:16 枚 id 全部合规(前缀即归属)。
|
||||
|
||||
- [ ] `feats.tres`:`"twin_digs"`→`"adv_twin_digs"`(:29);`"instinct_atk"`→`"round_instinct_atk"`(:492);`pain_layers` 各行删 `"domain": "adventure"` 键(:375-377/:407 邻近/:533-535/:626-628——归 battle,N4);`twin_digs` 行删 domain 键、`insurance_used` 行删 `domain: battle` 键(:875-877);全部 `reset_at` 键删除(:209-212/:490-494/:514-518/:719-723)
|
||||
- [ ] `effect_engine.gd` 合成行(:136-155):`tree_sense_sharp_used`→`lvl_tree_sense_sharp_used`、`tree_sense_guard_used`→`lvl_tree_sense_guard_used`(when id 与 counter_id 共六处字面:锋/守各 when 两行+do counter_id 一行);:116-122 注释内「domain=adventure」叙述同步改前缀口径
|
||||
- [ ] 全仓 grep 确认零 `domain`/`reset_at` 键残留于 feats.tres;`pain_layers`/`geo_types` 等 12 枚无前缀 id 零改名(无前缀=battle 即归属)
|
||||
|
||||
### T7 验收断言+旧测试迁移+变异验证+同种子复放比对(1–1.5d)
|
||||
|
||||
**取用**:T1–T6 全部产物;§9 验证闸清单(V1–V14 断言内容以本卡为唯一规格)。**产出**:V1–V13 全绿+变异验证记录表+G1 判读记录。
|
||||
|
||||
- [ ] **新增单测断言**(套件内新增,断言尾缀〔无状态化 Vn〕):V2/V3/V7/V13 落 `feat_vouchers_test.gd`(V16 键名 `pain_layers:3, twin_digs:5`→`adv_twin_digs:5` 等活键改写;V25 全组保绿不改断言内容;新增 H1:bp_legacy 注入 `"tree_sense_sharp_used": 2` 旧键 resume 受理零崩溃);V9 落 `counter_prefix_fatal_test.gd`(T5)
|
||||
- [ ] **新增冒烟断言段**(`smoke_all.gd` 树规则段近旁):V1(两编排器共享 RunLedger,第 1 战 `request_dig(0, false)` 一次无返还+桶值 1,第 2 战一次返还成立+桶值 2);V4/V5(两编排器经 enc["level_counters"] 共享同字典:第 1 战两次 `_fx.dispatch(counters_ctx, "mine_hit", {})` 命中桶值 2,第 2 战同 dispatch 返回空且桶值不动;新 LevelRunner 新桶为空);V6(第 1 战经 `_judge_seal` 置 `insurance_used=1`,第 2 战读 0);V8(round 桶直写非零→`orch._emit_round_start()`→全零,battle 前缀键不动)
|
||||
- [ ] **旧断言迁移/摘除**(F2——同批同轮):`effect_words_t1_test.gd` ⑥(:77-94 export/seed 往返)改桶语义断言(共享 adventure 桶字典往返)、⑦(:96-124 reset_at/spend)重写(round 桶轮始清空语义+静态 spend);`smoke_all.gd` `:6076-6083`(counter_add+export/seed 链)改共享桶形态、`:6124-6128`(`_reset_tree_limited_counters` 直呼)删除;`:1419-1602` 裸引擎段 53 处 dispatch+8 处写口改 ctx 形态(逐行扫尽,rig 顶自建 ctx 或取 `orch.counters_ctx`);`tree_rules_v11_test.gd:29-39` 字面随 T6 新 id;`settle_segments_test.gd:32-33` 样本 id `dig_combo`→`geo_types`+ctx 形态;`treasure_effects_test.gd:34/:45/:53-56` dispatch 加 ctx;各 rig enc `"adventure_counters": {}` 死键删除(编排器只读 `enc["ledger"]`,:372 实证)
|
||||
- [ ] **静态扫描 S 段**(`static_scan.sh`):新增规则组——`counters_export`/`counters_seed`/`counters_merge_export`/`counters_seed_snapshot`/`_reset_tree_limited_counters` 零命中+带引号旧 id 字面 `"tree_sense_sharp_used"`/`"tree_sense_guard_used"`/`"twin_digs"`/`"instinct_atk"` 零命中(带引号匹配防新名误伤);`run_all_gates.sh` 域内已有 static_scan,无闸件清单改动
|
||||
- [ ] **变异验证**(§9 变异表 4 条逐条:注入→最窄闸见红→`git checkout -- <文件>` 还原→复跑回绿→记录)
|
||||
- [ ] **同种子复放比对**(V12):先做**锚新鲜度核对**——用批前基线码(T0 记录的起点 commit)重放种子 81000–81001 两局,与现行锚 `sim-data/runsum_m3iter9exit_81000_n400_20261003.jsonl` 对应行逐位比对,一致方判锚可用(不一致=锚与 HEAD 玩法口径脱钩,L3 停机呈报,禁带病判读);核对通过后重放锚内 normal 档种子 81000–81019(20 局,零局新采集),按 §7.10.12 分组判读(未受影响局=feat_mode off 或装备集不含双管镐/sense 两组→全字段逐位一致;受影响局→输入面恒等+`levels_cleared` 分布不得上行);逐位差异明细记实现报告
|
||||
- [ ] 里程碑步出口:`tools/run_all_gates.sh --code`(代码域闸全绿);波内修复只做出红最小单元的最窄确认
|
||||
|
||||
### T8 产出物落位卡(0.25d)
|
||||
|
||||
**取用**:T0–T7 全部记录。**产出**:`reports/` 三份齐+06 状态就绪。
|
||||
|
||||
- [ ] 实现报告 `reports/iter<N>-实现报告-<日期>.md`:各 T 卡状态+变异验证记录表(注入点 file:line/跑的闸/红输出摘要/还原结论)+G1 判读记录+实机目检总清单(V14 登记)
|
||||
- [ ] 代拍板追认单 `reports/iter<N>-代拍板-<日期>.md`(§11 白名单内微决策逐条备案)
|
||||
- [ ] 反哺点清单 `reports/iter<N>-反哺点-<日期>.md`:§6 同步面五条逐条落点(architecture.md 三处改写文案与依据、tests/README 套件数、07 目检入册项)
|
||||
- [ ] 轻闸全绿后合并前自查:`game/` 与 `tools/` 改动全在案、`design/` 与根规则文件零触碰(`git diff --stat` 核对)
|
||||
|
||||
## 9. 验证闸(逐需求点验收清单)
|
||||
|
||||
**闸口径**:批末=代码域闸全绿(冒烟+单元+探针+渲染/静态,`tools/run_all_gates.sh --code`)+同种子复放比对(V12,零局新采集)。里程碑步(波/T 段)出口跑一次全套闸;波内修复只做出红最小单元的最窄确认;新增测试/工具先行孤立验证再并入全套。本批无数值改动,改前改后读数对比由 V12 分组判读承载。
|
||||
|
||||
**逐需求点清单**(断言尾缀〔无状态化 Vn〕;「测什么/怎么测/谁验」三问逐条可答):
|
||||
|
||||
| # | 需求点 | 测什么 | 怎么测(注入粒度) | 落点 | 谁验 |
|
||||
|---|---|---|---|---|---|
|
||||
| V1 | adventure 桶跨战持久(`run_ledger.gd:42` 缺陷消解回归钉面) | 第 1 战写入第 2 战可读、读写走真实事件面 | 两编排器共享 `RunLedger`:第 1 战 `orch1.action_economy.request_dig(0, false)`(无返还,`adv_twin_digs`=1)→第 2 战(同 ledger)一次挖返还成立+桶值 2 | 冒烟新段 | 自动 |
|
||||
| V2 | adventure 桶新冒险置空 | `start_adventure` 后桶空 | `start_adventure(301,...)` 后 `run_ledger.adventure_counters` 为空 | `feat_vouchers_test.gd` | 自动 |
|
||||
| V3 | adventure 桶随断点往返 | 快照/回填逐位相等 | 写桶→`_on_level_finished`→`breakpoint_snapshot`→`resume_adventure`→逐键比对(键随新 id) | `feat_vouchers_test.gd`(V16 改写) | 自动 |
|
||||
| V4 | level 桶同关跨战保持、进关清零 | 共享桶第 2 战保值;新 LevelRunner 新桶空 | 两编排器 enc["level_counters"] 同引用:第 2 战读 `lvl_tree_sense_*` 保持;再 new LevelRunner 断言 `level_counters` 空 | 冒烟新段 | 自动 |
|
||||
| V5 | tree_sense 每关限 2 次(削弱正面确认) | 第 1 战用满→第 2 战 lt 2 闸关零命中 | V4 同款共享桶:第 1 战两次 dispatch mine_hit 命中(桶值 2)→第 2 战同 dispatch 返回空且桶值不动 | 冒烟新段 | 自动 |
|
||||
| V6 | battle 桶随宿主销毁 | 第 2 战读 `insurance_used`==0 | 第 1 战 `_judge_seal` 置 1→新编排器 begin_battle 后读 0 | 冒烟新段 | 自动 |
|
||||
| V7 | 完美保险每战限次一次(卡② V25 迁移保绿) | V25 全组断言原样绿 | 沿用 V25 注入口径零改写——双账同点双记不改面(契约 5) | `feat_vouchers_test.gd:130-188` | 自动 |
|
||||
| V8 | round 桶轮始清空 | 轮始后 round 桶全零、他桶不动 | round 桶直写非零→`orch._emit_round_start()`→全零;`fx_counters_battle` 内键不动 | 冒烟新段 | 自动 |
|
||||
| V9 | counter_id 非法前缀加载致命(.tres 行+树合成行双落点) | 坏前缀行 load_tables 拒绝;合成行 assert 触发有据 | 夹具注入 `"counter_id": "meta_probe"`→load_tables false→expect 1;assert 侧=T5 孤立验证(最小驱动 rebuild 坏前缀合成行,输出扫 `[效果引擎]` assert 签名)+变异表第 4 行证明拦截 | `counter_prefix_fatal_test.gd`(expect 1, negative)+T5 孤立验证 | 自动 |
|
||||
| V10 | 旧件零残留 | 五符号+四带引号旧 id 字面全仓零命中 | static_scan 新 S 段(规则见 T7) | `static_scan.sh` | 自动 |
|
||||
| V11 | 旧断言同批摘除 | 冒烟/单测无旧件断言残留 | V10 扫描面覆盖测试文件+F2 清单逐项核对(`effect_words_t1` ⑥⑦/`smoke :6076-6083`/`:6124-6128`/`:1419-1602`) | 冒烟+单测迁移轮 | 自动+实现报告核对表 |
|
||||
| V12 | 同种子复放分组判读 | 锚新鲜度核对通过后:未受影响局逐位一致;受影响局输入面恒等+`levels_cleared` 不上行 | 批前基线码先重放 81000–81001 两局与现行锚 `runsum_m3iter9exit_81000_n400_20261003.jsonl` 逐位比对(新鲜度闸);通过后批后码重放锚内 normal 档 81000–81019(20 局);分组判读按提案 §7.10.12 | 复放脚本+实现报告判读记录 | 自动+人工判读 |
|
||||
| V13 | 旧档断点加载不崩 | 旧键 resume 受理零崩溃 | bp_legacy 注入 `"tree_sense_sharp_used": 2`→`resume_adventure` 受理、旧键留桶 | `feat_vouchers_test.gd`(V16 同构) | 自动 |
|
||||
| V14 | 天赋树锋/守削弱玩家可感知(登记不阻塞) | 每关第 3 次起无减免/无返还 | 用户实战目检:同关第 3 次踩雷不再减半、第 3 次标错不再返 AP | 实机目检总清单+07 入册(反哺点) | 用户目检 |
|
||||
|
||||
**变异验证必做**(无变异红记录只写「已实现,拦截能力未证」):
|
||||
|
||||
| 断言 | 注入形态 | 跑的最窄闸 | 期望 |
|
||||
|---|---|---|---|
|
||||
| V1 | T1 挂载行改 `counters_ctx.adventure_bucket = {}`(丢共享引用——复刻副本不同步缺陷类) | 跑 `smoke_all.gd` 单脚本,核对 V1 断言红 | V1 红 |
|
||||
| V5 | V4/V5 两编排器改传各自新建 level 字典(复刻 :838-841 旧形态跨战不共享) | 跑 `smoke_all.gd` 单脚本,核对 V5 断言红 | V5 红 |
|
||||
| V9(.tres 侧) | 注释 `validate_trigger_row` 前缀校验分支 | `counter_prefix_fatal_test.gd` 单跑 | 套件转「违规放行」态判红 |
|
||||
| V9(合成行侧) | 注释 `_push_trigger` 内前缀 assert 行 | T5 孤立验证驱动单跑(输出签名扫描) | assert 签名消失=拦截失效判红 |
|
||||
| V10 | 任一源文件临时写回一处 `"counters_export"` 引用 | `static_scan.sh` 单跑该 S 段 | 扫描红 |
|
||||
|
||||
**测试方式两分法**:V1–V13 全部=调试接口直改/直调核心层(共享字典注入、`request_dig`/`_judge_seal`/`_emit_round_start` 核心写口直调),不经 UI;V14=用户目检(登记不阻塞,验收时间用户自定)。
|
||||
|
||||
## 10. 异常分级
|
||||
|
||||
- **L1 自救**:编译错/笔误级红;孤立验证失败(新类/新函数首跑);复放脚本参数错重跑。
|
||||
- **L2 记录继续**:V12 受影响局保守超集判定边界个案(某局归类存疑)——按受影响组从严判读并记录;负面套件在 release 模式 assert 剥离致假绿——换 debug 通道验证并记录(配置问题非代码缺陷)。
|
||||
- **L3 停机呈报**:V12 未受影响局出现任何逐位差异(确定性破约);V7/V25 任何一条红(契约 5 破);V13 崩溃;`pain_layers` 行为漂移(契约 8 破);写口语义与现役不一致导致 V1–V8 连带红且无法归因单点。
|
||||
- 环境故障(worktree 缓存/资源导入/console exe)按 process-conventions 异常分级自救清单处理。
|
||||
|
||||
## 11. 代拍板白名单(超清单必呈报)
|
||||
|
||||
1. 新测试函数/夹具变量命名、断言消息文案(编号尾缀〔无状态化 Vn〕已锁)。
|
||||
2. 冒烟新段的段落插入位置与段名(须紧邻现役树规则段)。
|
||||
3. 静态 `counter_add`/`counter_spend`/`bucket_of` 内部语句序(签名与语义已锁,实现体自由)。
|
||||
4. `feats.tres` 行内键序调整(键集与值已锁)。
|
||||
5. `effect_engine.gd` 合成行注释的措辞更新(口径已锁:前缀表述)。
|
||||
6. 负面套件内诊断文案措辞(退出码协议已锁)。
|
||||
|
||||
## 12. 待裁点
|
||||
|
||||
**零待裁点,开工门=U0。**
|
||||
|
||||
本卡全部设计定值承自提案 §7(N1–N6)、§7.7(零采集)、§7.10(缺口闭合),均为「已生效裁定+硬纪律」推导所得并写明依据;其中以下各项带「可否决」标注(提案 §7.9/§7.10.14 同口径),用户审卡时可单独推翻、推翻即回改卡:§7.9 五条(立项判据载体/domain+reset_at 删键/`adventure_counters` 容器名不改/旧档不迁移/两编译名单删除)与 B6(dig_combo 死路删除)。卡片成立还需 grilling 复核通过(零待裁点+验收三问逐条可答已自查,见下)。
|
||||
|
||||
---
|
||||
|
||||
## 附:任务卡自审五查记录(2026-10-20 成文自检)
|
||||
|
||||
**grilling 复核轮**:成文后经独立会话对抗复核(新会话视角、不带写卡人假设),五项回炉点已全落——①行号群订正(成员块 :83-88/:84-87、`counters_seed` :255、`EffectEngine.new` :271、合成行 :136-155、注释 :137、rebuild :1610、裸引擎段实数 53 处、合成行字面六处);②V12 具名锚+T7 增锚新鲜度核对步(批前基线码两局配对在先);③V9 assert 侧补孤立验证与变异行;④T5 判定函数名落定 `counter_id_legal`;⑤估时头对齐 T 表加总+超盒切分预案。复核结论「定点回炉后可交用户审」已执行。
|
||||
|
||||
1. **规格覆盖**:完成定义 1–8 ↔ T 卡映射——1→T2;2→T1;3→T2/T3;4→T1;5→T5;6→T7(V12);7→T3;8→T7(V13)。验收 V1–V14 逐条有落点。✓
|
||||
2. **步骤扫描**:各步一动作一核查结果;实现体未写(签名+断言已锁);无「TBD/酌情」句式。✓
|
||||
3. **类型一致性**:`EffectContext` 字段名、编排器/LevelRunner 成员名、enc 键名、静态函数签名在 T1/T2/T3/T7 引用处逐字一致(契约 7 锁定)。✓
|
||||
4. **审查焦点**:规格暗示的失败模式对照——确定性漂移(V12 未受影响组+锚新鲜度闸)、引用切断(契约 3+V1 变异)、限次失效回退(V5 变异)、加载致命旁路(V9 双侧变异)、死路复活(V10)——均有承载;「同轮 dispatch 内 round 桶清空与订阅行命中并存」的时序语义由 V8+现役特判位置保持承载。✓
|
||||
5. **篇幅比例**:本卡以签名/断言/落点为主,无函数体代码块。✓
|
||||
Reference in new issue
Block a user