From f9486083e3d299c2a24f7d18fec07c162dcb864a Mon Sep 17 00:00:00 2001 From: Joywayer Date: Mon, 3 Aug 2026 11:34:07 +0800 Subject: [PATCH] =?UTF-8?q?docs(plan):=20=E8=AE=A2=E6=AD=A3=20Task3=20?= =?UTF-8?q?=E5=90=9E=E8=A1=80=E6=88=90=E5=9B=A0=E2=80=94=E2=80=94=E8=A1=A5?= =?UTF-8?q?=E6=AD=A3=E6=8F=90=E4=BA=A4=20900eaea=20=E8=AF=B4=E6=98=8E?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=A4=B1=E5=AE=9E=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 900eaea 的提交信息照抄了简报里「hp_max 买到 180 后即可复现」的说法,而 Task 3 实测 + 评审独立复现证明该路径不触发:_modifiers 为空时 remove_modifiers_from 提前返回,单次合并的 add_modifier 一步算出最终值, 中间没有可观察的陈旧 hp_max。 真实风险窗口是同进程内二次 apply_run(_modifiers 已有 shop_c 加成时)。 计划里补了三行复现数据与「写回归测试必须用场景 B 前提」的告诫—— 按失实说法写的断言恒绿。 Co-Authored-By: Claude Opus 5 --- .../plans/2026-07-31-shelf-c-attribute-shop.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md b/docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md index caddae7..3c1260a 100644 --- a/docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md +++ b/docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md @@ -476,7 +476,17 @@ const SCHEMA_VERSION: int = 3 # v3:新增 attr_purchases(货架 C 属性购 - [ ] **Step 3: 回读 —— 顺序至关重要** -`apply_run()`(:63)当前**第一步**就是 `PlayerStats.load_save_data(...)`(设 `hp`)。货架 C 能把 `hp_max` 买到 180 后,若属性加成在此之后才恢复,回读的 `hp=180` 会被尚未加成的 `hp_max=100` 钳掉 —— **静默吞 80 血**(E3-① 在 `player_stats.gd` 注释里记录过这个陷阱)。 +`apply_run()`(:63)当前**第一步**就是 `PlayerStats.load_save_data(...)`(设 `hp`)。若属性加成在此之后才恢复,回读的 `hp` 会被尚未加成的 `hp_max` 钳掉 —— **静默吞血**(E3-① 在 `player_stats.gd` 注释里记录过这个陷阱)。 + +> 📌 **成因订正(Task 3 实测 + 评审独立复现)**:本步初稿称「全新启动、`hp_max` 买到 180 后即可复现」—— **该路径实际不触发**。`remove_modifiers_from` 在 `_modifiers` 为空时提前返回、不触发 `_recompute_attrs`,随后单次合并的 `add_modifier` 一步算出最终 `hp_max`,中间从未出现「陈旧 `hp_max`」的可观察状态。 +> +> **真实风险窗口**:同一进程内 `_modifiers` 里**已有**一条 `shop_c` 加成时再次 `apply_run`(如「主菜单 → 继续 → 死亡 → 主菜单 → 再次继续」)。此时 `remove_modifiers_from` 真正命中旧加成、触发一次 `_recompute_attrs`,而 `hp` 已被颠倒的顺序设为 130、`hp_max` 尚未回升 → 钳到 100,吞 30 血。评审复现数据: +> ``` +> 场景A(无历史加成,即初稿描述):颠倒顺序 → hp=130 hp_max=133.1 未吞血 +> 场景B(已有一条 shop_c 加成): 颠倒顺序 → hp=100 hp_max=133.1 吞 30 血 +> 场景B + 实际交付的 apply_run(): hp=130 hp_max=133.1 正确 +> ``` +> **写回归测试必须用场景 B 的前提**(预置一条同源加成),否则断言恒绿、证明不了任何事。 故 `attr_purchases` 必须在 `load_save_data` **之前**恢复。把 `apply_run` 的前两行改为: ```gdscript @@ -516,7 +526,8 @@ feat(shop): 货架 C 购买次数进局内存档(schema 2→3) 回读顺序:attr_purchases 必须早于 load_save_data。后者设 hp,而重建加成会经 _recompute_attrs 触发 hp = minf(hp, hp_max);顺序颠倒会拿未加成的 hp_max 去钳, -静默吞血(hp_max 可买到 180 后即可复现)。 +静默吞血。触发前提是 _modifiers 里已有同源加成(同进程内二次 apply_run), +此时 remove_modifiers_from 才真正命中并触发一次中间态重算。 Co-Authored-By: Claude Opus 5 EOF