diff --git a/design/research/需求卡片-代码注释禁用词清扫批-2026-10-20.md b/design/research/需求卡片-代码注释禁用词清扫批-2026-10-20.md index 5ea88db3..1168059c 100644 --- a/design/research/需求卡片-代码注释禁用词清扫批-2026-10-20.md +++ b/design/research/需求卡片-代码注释禁用词清扫批-2026-10-20.md @@ -4,7 +4,8 @@ - **日期**:2026-10-20 - **批次性质**:工程债/重构 + 缺陷修复(两类均属工程直入四类,凭 06 在册条目与代码级证据直接写卡) - **设计事实源**(唯一事实源:`design/gdd/术语表.md`「退役词对照」+「用语规范 A 表」+「对外命名纪律」节;`design/gdd/systems/战斗循环/战斗结算.md`「完美排雷」规则节;req-card 三选一之③工程直入证据指认):扫描读数=`game/` 下 195 个文件(.gd/.tres/.md/.json/.sh/.txt)逐处实测,落点带 file:line(见 §2);复现命令见 §2 末。 -- **版本**:**v1.1**(2026-10-20:grilling 复核门查出 N7 概念冲突,新增需求点与 T7 卡;T2 的对外文案由「机械换词」改为「按概念两态改写」) +- **版本**:**v1.2**(2026-10-20:开工前自检查出四处会卡住施工方的未定口径——S11 词表范围/「雷」字面误伤面/N7 修法可行性与限次重复消费/A10·A11 断言落点——全部钉死;T7 修法由「上移豁免」改为「后移 `_emit_row`」,已核实 `_fx_emit` 有状态不可重复调用) +- 历史:v1.1(2026-10-20:grilling 复核门查出 N7 概念冲突,新增需求点与 T7 卡;T2 的对外文案由「机械换词」改为「按概念两态改写」) - **迭代归属**:待编入 roadmap 迭代 32(本卡不自行编入;编排归 iter-plan 段) - **上游依据**:2026-10-19 用户裁——「完美排雷」**全库统一**换代为「完美封印」,含代码内部注释 @@ -54,7 +55,7 @@ 1. `game/` 内 `完美排雷`/`板级`/`门票`(注释面)/`正主`/`落籍` 五词,**疑似现行计数全部为 0**(豁免=含对照/历史信号的行)。 2. 对外文案三处不含「雷」字面,读作「完美封印」。 -3. **N7**:装备「完美保险」专长时本战首次标错 → 日志**不**出现「已破」字样,改出现豁免态文案;未装备时首次标错 → 出现「已破」态文案。两态各有正向断言。 +3. **N7**:装备「完美保险」专长时本战首次标错 → `seal_miss` 行的 `highlight` 字段为 `""`(豁免态,无金框),且 `perfect_sweep_earned() == true`;未装备时首次标错 → `highlight` 为 `"perfect_broken"`(已破态,金框),且 `perfect_sweep_earned() == false`。两态各有正向断言(A10/A11)。 4. 冒烟绿数与改前基线一致(现行 1151 项 0 失败)、单元测试 34 套全绿、探针段绿。 5. S11 规则在位:注入一次禁用词 → `game/tests/static_scan.sh` 判红;还原后绿;变异验证记录进实现报告。 6. 代码域闸按域选档跑通,回执 `game/tests/.gates/receipt.json` 的 commit = 分支 tip 且 `all_green=true`。 @@ -139,8 +140,9 @@ 4. 🔴 **完美封印判据单点**——「是否已破」只允许由 `battle_orchestrator.perfect_sweep_earned()` 的有效误标口径派生,禁在 `grant_segment.gd` 另立 RAW 计数判据;两处口径不一致即为缺陷。 5. 🔴 **游戏行为零变化**(N1–N5、N7 判据修正前)——纯中文文本替换,禁止改动逻辑、数值、权重、条件判断。N7 判据修正是**本批唯一允许的逻辑改动**,其验收为「日志文案与真值一致」,不改奖励兑付结果。 6. 🔴 **S11 规则先落、后修码**——先把规则写进 `game/tests/static_scan.sh` 并跑出红,再动注释(code-conventions 缺陷-规范对照表纪律)。 -7. 🔴 **S11 词表不内联第二份**——规则脚本从 `design/gdd/术语表.md`(「退役词对照」+「用语规范 A 表」两节)解析词面;禁止在脚本里另抄一份词表(单一事实源红线,ADR 漂移教训同类)。 -8. 🔴 **S11 必须带扫描面零命中自检**——先数一遍扫描面文件数,为零即判红(沿 S3 教训:路径写歪时自检一起歪、一起红,不会静默恒绿)。 +7. 🔴 **S11 词表范围=本批清理范围,且从术语表解析不内联**——词表面=`design/gdd/术语表.md`「退役词对照」节第一列全部词面(去括号注),**显式追加 `完美排雷` 完整短语**(该词受「对外命名纪律」约束,不在退役词对照表里,故需显式列入)。**明确不收**:①术语表「用语规范」A 表词面(`不得`/`报错`/`对标`/`若干`/`buff`)——§4 已列「不做」,收进来批末必然红;②单字「雷」——会误伤 26 处保留词「排雷玩法/排雷规则」(内部机制名,§10 明定不扩大禁词面)。**禁止在脚本里另抄一份词表**(单一事实源红线,ADR 漂移教训同类)。A 表词将来若被裁决纳入,另行扩词表并单独立批清扫。 +8. 🔴 **S11 必须带两道零命中自检**——①扫描面文件数为零即判红;②从术语表解析出的词面数为零即判红(沿 S3 教训:路径写歪或表格结构变了时,自检一起歪、一起红,不会静默恒绿)。 +9. 🔴 **S11 闸门自指豁免**——命中行若属「检查禁用词本身」的闸门形态(行内含 `contains(`/`find(`/`grep`/`has_char(`/`禁「`/`禁『`/`零「`/`零『` 等检查或禁令表述),或含 `doc_term_audit.py` 同源的对照/历史信号,一律豁免、不判红。现存受此豁免的两处:`game/smoke/smoke_all.gd:1319`(禁字面检查逻辑)与 `game/tests/unit/presentation/ui_font_asset_test.gd:18`/`:19`(字形覆盖夹具)。 9. 🔴 **禁碰并行会话在改的文件**——`AGENTS.md` 与 `design/dev/code-conventions.md`(分支 `changelog-retire-20261019` 在盘未合回)。S11 规则说明自持于 `game/tests/static_scan.sh` 头注与 `game/tests/README.md`。 10. 🔴 **对照性文本豁免**——含退役/更名/禁令等信号的行不改写(术语表用语规范 B 类豁免条款)。 @@ -155,11 +157,10 @@ 3. `game/` 内注释面 `门票`→`专长凭证`(35 处,剔除移交 3 处) 4. `game/` 内注释面 `正主`→`现行事实源`(11 处,剔除误报 1 处) 5. `game/` 内注释面 `落籍`→`已入库`(9 处,剔除历史注记 1 处) -6. `game/` 内 `完美排雷`→`完美封印`(16 处) -7. **N7**:封印未中行归因锚改用有效误标判据,文案按两态改写 -8. 代码域静态扫描闸新增 S11 规则(含零命中自检) -9. `game/README.md`/`game/tests/README.md` 同步 -10. 全量冒烟+单元+探针验证,绿数与基线一致 +6. **N7**:封印未中行归因锚改用有效误标判据,文案按两态改写 +7. 代码域静态扫描闸新增 S11 规则(词表=退役词对照+`完美排雷`;含两道零命中自检与闸门自指豁免) +8. `game/README.md`/`game/tests/README.md` 同步 +9. 全量冒烟+单元+探针验证,绿数与基线一致 **不做**(去向): @@ -225,13 +226,17 @@ ### T1 · S11 规则落闸并见红(≈1.0–1.5h) -- [ ] 在 `game/tests/static_scan.sh` 头部注释补 S11 一行说明(规则名+权威出处+扫描面) +- [ ] 在 `game/tests/static_scan.sh` 头部注释补 S11 一行说明(规则名+权威出处+扫描面+词表来源) - [ ] 新增 S11 段:扫描面=`game/` 全域(.gd/.tres/.md/.json),与迭代 31 V4 判据同口径 - [ ] 逐行取注释文本段(`#`/`;` 前缀),剔除含对照/历史信号的行 -- [ ] 词表面从 `design/gdd/术语表.md` 解析:「退役词对照」表第一列全部词面(去括号注)+「用语规范」A 表「禁用」列全部词面 -- [ ] 规则先数扫描面文件数,为零即 `echo "[static_scan] S11 FAIL: 扫描面为空"` 并 `fail=1` +- [ ] 词表面从 `design/gdd/术语表.md`「退役词对照」节解析第一列全部词面(去括号注),**显式追加 `完美排雷` 完整短语**;不收 A 表词、不收单字「雷」(契约 7) +- [ ] 命中行先过闸门自指豁免(行内含 `contains(`/`find(`/`grep`/`has_char(`/`禁「`/`禁『`/`零「`/`零『` 即跳过),再判红(契约 9) +- [ ] 自检一:扫描面文件数为零即 `echo "[static_scan] S11 FAIL: 扫描面为空"` 并 `fail=1` +- [ ] 自检二:解析出的词面数为零即 `echo "[static_scan] S11 FAIL: 词表解析为空"` 并 `fail=1` - [ ] 命中即打印 `file:line + 命中词`,段末 `fail=1` +- [ ] 在 `game/tests/README.md` 的静态扫描登记处补 S11 一行(规则名/扫描面/词表来源/豁免条款) - [ ] 注入验证:在 `game/core/battle_orchestrator.gd` 某注释里临时写回「板级」一词 → 跑 `bash game/tests/static_scan.sh` 见红并记输出摘要 → `git checkout -- game/core/battle_orchestrator.gd` 精确还原 → 记录进实现报告变异验证表 +- [ ] 反向验证:在 `game/smoke/smoke_all.gd:1319`(禁字面检查行)写回原句 → 跑闸**仍为绿**(验证自指豁免生效)→ 还原 **取用**:无。 **产出**:`game/tests/static_scan.sh` 的 `S11` 段(退出码语义=任一硬失败规则命中即 `exit 1`,与现役同段同规)。 @@ -261,7 +266,7 @@ ### T4 · 门票 → 专长凭证(注释面,≈1.0h) -- [ ] `game/core/adventure_runner.gd` 11 处注释换代(67/68/69/477/664/751/788/796/1033/1034) +- [ ] `game/core/adventure_runner.gd` 11 处注释换代(67/68/69/477/664/751/771/788/796/1033/1034) - [ ] `game/core/level_runner.gd` 4 处(51/781/826/831) - [ ] `game/data/schemas/adventure_table.gd` 3 处(92/96/97)+ `shop_table.gd:18` - [ ] `game/data/tables/shop.tres:104` 注释换代 @@ -288,9 +293,13 @@ ### T7 · N7 归因锚判据修正(≈1.5h) -- [ ] 把 `core/settlement/grant_segment.gd:300` 的判据由 RAW 计数 `oc._perfect_hit_false == 1` 改为**有效误标**口径 `_perfect_hit_false - _perfect_forgiven == 1` -- [ ] 把豁免累加 `_perfect_forgiven += 1`(:314)上移到 `_emit_row`(:302)**之前**,使归因锚与谓词口径同源 -- [ ] 文案两态:未豁免 → `(本图完美封印已破——清图奖励不再加倍)`;已豁免 → `(首次封印落空已豁免——不计入完美封印判定)` +**修法(已核实可行,禁另选他法)**:`_fx_emit`(`battle_orchestrator.gd:90-93`)是 `_fx.dispatch` 的**有状态派发**——`forgive_seal_miss` 行走 `when lt 1` 限次并由 `_apply_counter_hit` 记账,**重复调用会重复消费限次**。因此**禁止**"先跑一次 `_fx_emit` 算 `hl` 再在原位置跑一次"的做法。 + +- [ ] 把 `core/settlement/grant_segment.gd:302` 的 `oc._emit_row("seal_miss", ...)` **后移**到 `for h in oc._fx_emit("seal_missed", ...)` 循环(:308-317)**之后**——循环结束后 `_perfect_forgiven` 已就位,判据才有真值可用 +- [ ] 判据改有效误标:`var hl := "perfect_broken" if oc._perfect_hit_false - oc._perfect_forgiven == 1 else ""`(替代原 :300 的 RAW 计数 `oc._perfect_hit_false == 1`) +- [ ] 确认行序调换的零影响:`grep -n "insurance_used\|perfect_insurance" game/smoke/smoke_all.gd` 已实测**零命中**——冒烟未断言这两行的相对顺序,调换不涉断言 +- [ ] 文案两态:未豁免(`hl == "perfect_broken"`)→ `(本图完美封印已破——清图奖励不再加倍)`;已豁免(`hl == ""`)→ `(首次封印落空已豁免——不计入完美封印判定)` +- [ ] 豁免态**不加金框**——`hl == ""` 时 `battle_log_view.gd:195` 走普通色分支;金框语义=强调负面事件,豁免是正向事件,靠同批已存在的 `insurance_used` 行(:316-317)承载反馈即可。不新增高光标记 - [ ] 正向断言 A10/A11(见 §7) **取用**:T2 的对外文案换代结果。 @@ -326,8 +335,9 @@ | A7 | N6 | S11 规则在位:注入禁用词 → 退出码 1 且输出含 `S11 FAIL`/命中行 | 注入实验,落点 `game/tests/static_scan.sh` | 自动(人工执行一次取证) | | A8 | 全域 | 冒烟绿数 == 基线 1151、单元 34 套全绿、探针段绿 | 跑所选域档 | 自动 | | A9 | 全域 | 回执 commit == 分支 tip 且 `all_green=true`,零新增红 | 跑闸后读 `game/tests/.gates/receipt.json` | 自动(合回闸) | -| **A10** | **N7** | **未装备完美保险:首次标错 → 日志出现「完美封印已破」,且 `perfect_sweep_earned() == false`** | 新增断言,落点 `tests/unit/core/feat_vouchers_test.gd`(现有专长套件) | 自动 | -| **A11** | **N7** | **装备完美保险:首次标错 → 日志出现豁免态文案,且不出现「已破」;`perfect_sweep_earned() == true`(加倍仍发)** | 同上 | 自动 | +| **A10** | **N7** | **未装备完美保险:本战首次标错 → `seal_miss` 行的 `highlight` 字段 == `"perfect_broken"`,且 `perfect_sweep_earned() == false`** | 新增断言,落点 `tests/unit/core/feat_vouchers_test.gd`(现有专长套件,core 层可直取行字段) | 自动 | +| **A11** | **N7** | **装备完美保险:本战首次标错 → `seal_miss` 行的 `highlight` 字段 == `""`,且 `perfect_sweep_earned() == true`(加倍仍发)** | 同上 | 自动 | +| **A12** | **N7** | 两态文案常量与 `battle_log_view.gd` 呈现一致:`_format_row` 对 `hl=="perfect_broken"` 输出「已破」态、对 `hl==""` 输出豁免态,两态均不含「雷」字面 | 断言落点 `tests/unit/core/feat_vouchers_test.gd`(取行字段后按同一分支规则格式化比对) | 自动 | **测试方式两分法**:A1–A7、A10–A11 属能力验证(静态扫描/断言直取数据)与取证实验;A8–A9 为运行期验证。玩家可见文案的最终观感归**用户目检**(登记不阻塞):结算明细中封印未中行的两态文案可读性。 @@ -342,8 +352,9 @@ | `game/core/battle_orchestrator.gd:265` 注释 | 写回「板级完美排雷」原措辞 | `bash game/tests/static_scan.sh` | `S11 FAIL` + 命中行输出 | | 同上对外文案 | `game/core/battle_orchestrator.gd:925` 写回「完美排雷!…」 | 冒烟清图段 | 断言 A2 红 | | S11 扫描面 | 临时把 `DIR_CORE` 改成不存在目录 | `bash game/tests/static_scan.sh` | `S11 FAIL: 扫描面为空` | -| **N7 判据(反)** | 把 `grant_segment.gd:300` 改回 `_perfect_hit_false == 1`(RAW) | `tests/unit/core/feat_vouchers_test.gd` | 断言 A11 红(豁免态应无「已破」却出现) | -| **N7 判据(正)** | 把 :300 改成 `_perfect_hit_false - _perfect_forgiven <= 0`(恒真) | 同上 | 断言 A10 红(未豁免态应「已破」却缺失) | +| **N7 判据(反)** | `grant_segment.gd` 判据改回 `_perfect_hit_false == 1`(RAW 计数) | `tests/unit/core/feat_vouchers_test.gd` | 断言 A11 红(装备专长时 `highlight` 应为 `""` 却得 `"perfect_broken"`) | +| **N7 判据(正)** | 判据改成 `_perfect_hit_false + _perfect_forgiven == 1`(符号写反) | 同上 | 断言 A10 红(未装备专长时 `highlight` 应为 `"perfect_broken"` 却得 `""`) | +| **S11 自指豁免** | 去掉 S11 的闸门自指豁免分支 | `bash game/tests/static_scan.sh` | `smoke_all.gd:1319` 与 `ui_font_asset_test.gd:18` 判红 | 注入后一律 `git checkout -- ` 精确还原,四件(变异点 file:行/跑的闸/红输出摘要/还原结论)记进实现报告变异验证记录表。