From cd3618c066119e0877a813993bbe9befb50d6f47 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Fri, 31 Jul 2026 10:53:17 +0800 Subject: [PATCH] =?UTF-8?q?docs(plan):=20=E8=A1=A5=20Step3b=20=E6=96=AD?= =?UTF-8?q?=E8=A8=80=20push=5Ferror=20+=20=E8=AE=A2=E6=AD=A3=E7=BB=95?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=B3=95=E5=9C=A8=E7=B1=BB=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E5=90=8E=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task 1 评审实测发现两处计划缺陷: ① 断言 ④ 的数字部分对「add_int 拒 pct」是空的——删掉整个拒绝块 ④ 仍返回 13.0, 因为 ADD_INT 的 match 分支不读 pct_prod。拒绝行为唯一可观测证据是 push_error, 补 Step 3b 用唯一标记值 + get_editor_errors 单独断言。 ② GDScript.new()+source_code+reload() 在该类被注册为全局类之后同样报 hides a global script class——Task 1 首次运行因尚未注册才侥幸通过, 后续任务照抄会失败。改为先剥离 class_name 行,或直接调已注册的全局类。 Co-Authored-By: Claude Opus 5 --- .../plans/2026-07-31-player-attributes.md | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/docs_dev/plans/2026-07-31-player-attributes.md b/docs_dev/plans/2026-07-31-player-attributes.md index 857800b..518f48e 100644 --- a/docs_dev/plans/2026-07-31-player-attributes.md +++ b/docs_dev/plans/2026-07-31-player-attributes.md @@ -9,7 +9,14 @@ **Tech Stack:** Godot 4.7.1 Mono / GDScript / 纯 JSON 数据驱动 / godot-mcp-pro(公式为纯函数 → `execute_editor_script` 单元断言;接线为运行时 `execute_game_script` 实测)。 > **规范**:提交中文;纯数据驱动,文件缺失 `push_error` 不静默回退。spec:`docs_dev/specs/2026-07-31-player-attributes-design.md`。 -> **已知工具坑**:① `validate_script` 对任何带 `class_name` 的脚本必然假阴性(报 `hides a global script class`)—— `attribute_formula.gd` 属此类,验证改用 `GDScript.new()` + 从磁盘读 `source_code` + `reload()`;`player_stats.gd` / `player_manager.gd` / `spell_evaluator.gd` / `combat_manager.gd` 无 `class_name`,可正常 `validate_script`。② `@tool` 编辑器类在 dock 里被缓存,`load(...).new()` 拿到旧类,绕法同上。③ `execute_editor_script` 静默阻止运行时 `FileAccess.WRITE`。 +> **已知工具坑**: +> ① `validate_script` 对任何带 `class_name` 的脚本必然假阴性(报 `hides a global script class`)—— `attribute_formula.gd` 属此类;`player_stats.gd` / `player_manager.gd` / `spell_evaluator.gd` / `combat_manager.gd` / `attribute_tab.gd` / `designer_panel.gd` 无 `class_name`,可正常 `validate_script`。 +> ② **`GDScript.new()` + `source_code` + `reload()` 这个绕法,在该类被引擎注册为全局类之后同样会失败**(同一条 `hides a global script class`)。Task 1 首次运行时因尚未注册而侥幸通过,**后续任务不能照抄**。正确做法二选一: +> - **剥离 `class_name` 行再 `reload()`**:`S.source_code = src.replace("class_name AttributeFormula\n", "")`(`@tool` 编辑器类同理剥自己的 `class_name`); +> - 或**直接调用已注册的全局类**:`AttributeFormula.compute(...)`(只验证已落盘版本时更省事)。 +> ③ `@tool` 编辑器类在 dock 里被缓存,`load(...).new()` 拿到旧类,绕法同 ②。 +> ④ `execute_editor_script` 静默阻止运行时 `FileAccess.WRITE`。 +> ⑤ 新增 `.gd` 后 `.gd.uid` 不会自动出现,需 `EditorInterface.get_resource_filesystem().scan()` 触发扫描才生成;项目约定二者一并提交。 > **关键既有事实**:`spell_evaluator.gd:332` `var max_ops: int = MAX_OPS_PER_CPU * 5`(`MAX_OPS_PER_CPU = 40`,`:8`)。`player_manager.gd:7` `const MOVE_SPEED: float = 200.0`,`:45` 消费,`:88` `_cast_interval = core.cast_interval if core else 0.5`。`combat_manager.gd:257` `_rebuild_wand()`,`:267-271` 为 `mana_leech` 重算段。`player_stats.gd`:`hp_max` :10、`cpu_limit` :21、`armor` :22、`resistance` :23、`_ready()` :33、`reset_for_run()` :125、`get_save_data()` :135、`load_save_data()` :138。`CompiledDeck` **没有** `cpu_limit` 字段(只有 `feature_tags`),故 `spell_evaluator` 侧不需要新增字段。 --- @@ -147,7 +154,34 @@ for c in cases: _mcp_print("FAILS=%d %s" % [fails, str(bad)]) ``` Expected: `FAILS=0 []` -> 预期输出中会伴随两条 `push_error` 文本(④ 的 add_int 拒 pct、⑥b 的未知 combine)—— **那是被断言的正确行为**,不是错误。 + +> ⚠️ **断言 ④ 的数字部分对「拒绝 `pct`」是空的**(Task 1 评审实测发现):把整个拒绝块删掉,④ 仍返回 13.0 —— 因为 `ADD_INT` 的 match 分支根本不读 `pct_prod`。数字只证明了「`pct` 之后的 `flat` 仍能累加」。**拒绝行为唯一的可观测证据是 `push_error`**,必须单独断言,否则意图②无人守卫。 + +- [ ] **Step 3b: 断言 `push_error` 真的发出(补 ④ 的空缺)** + +用**唯一标记值**发起调用,再从编辑器错误日志里找它 —— 标记值确保读到的不是历史遗留日志。 + +Run: godot-mcp-pro `clear_output`,然后 `execute_editor_script`: +```gdscript +var S := GDScript.new() +# ⚠️ 必须剥掉 class_name:该类此时已被引擎注册为全局类,带 class_name 的内存副本会报 +# "hides a global script class"(Task 1 首次运行时尚未注册才侥幸通过) +S.source_code = FileAccess.get_file_as_string("res://scripts/domain/attribute_formula.gd") \ + .replace("class_name AttributeFormula\n", "") +if S.reload() != OK: + _mcp_print("PARSE_FAIL"); return +# 三条各带唯一标记,逐一触发报错路径 +S.compute(0.0, [{"mode":"pct","value":0.123456}], {"combine":"add_int","hard":50.0}) +S.compute(1.0, [], {"combine":"zzzprobe9182","hard":0.0}) +S.compute(1.0, [{"mode":"zzzmode9182","value":1.0}], {"combine":"hybrid","hard":0.0}) +_mcp_print("probes_fired") +``` +再 Run: godot-mcp-pro `get_editor_errors`,断言三条标记均出现: +- `add_int 属性不接受 pct 加成(value=0.123456` +- `未知 combine「zzzprobe9182」` +- `未知 mode「zzzmode9182」` + +Expected: 三条全部命中。**任一缺失即说明对应的报错路径未执行** —— 那是真缺陷,不是日志问题。 - [ ] **Step 4: 提交**