From 5189e9539ce88db56bcc20ba42426e550617fdf4 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Wed, 4 Nov 2026 01:22:40 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=8D=E6=A0=B8(=E5=8F=8C=E5=AE=A1):=20grill?= =?UTF-8?q?ing=EF=BC=8Bgodot-master=20=E4=B8=A4=E4=BC=9A=E8=AF=9D=E7=8B=AC?= =?UTF-8?q?=E7=AB=8B=E5=8F=AA=E8=AF=BB=E5=A4=8D=E6=A0=B8=E5=8D=A1=E7=89=87?= =?UTF-8?q?=20v1.0=EF=BC=8C=E5=87=BA=E6=8A=A5=E5=91=8A=20reports/=E5=A4=8D?= =?UTF-8?q?=E6=A0=B8-=E5=8F=8C=E5=AE=A1-grilling=E4=B8=8Egodot-master-L1?= =?UTF-8?q?=E6=B7=B1=E5=BA=A63=E6=B7=B7=E7=BC=96=E6=89=B9-2026-11-04.md?= =?UTF-8?q?=E2=80=94=E2=80=94=E9=98=BB=E6=96=AD=2010=20=E6=9D=A1(=E6=BC=8F?= =?UTF-8?q?=E4=B8=89=E5=A4=84=E5=BC=95=E7=94=A8=E7=82=B9=20level=5Fshop:72?= =?UTF-8?q?7/guard:4/round=5Fflow:1108+711=E3=80=81=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E5=8F=A5=E3=80=8C=E6=B7=B1=E5=BA=A63-5=E3=80=8D=E4=B8=8E?= =?UTF-8?q?=E8=90=BD=E5=B8=A6=E6=9C=BA=E5=88=B6=E7=9B=B8=E6=82=96=E3=80=81?= =?UTF-8?q?=E8=A1=8C=E5=BA=8F=E4=BE=9D=E6=8D=AE=E5=BC=95=E9=94=99=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E3=80=81=E7=9C=9F=E5=AE=9E=E5=85=A5=E5=8F=A3=E5=90=8D?= =?UTF-8?q?=20resolve=5Fenemy=5Frowset=20=E5=86=99=E9=94=99=E3=80=81?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84=20T0?= =?UTF-8?q?=E3=80=81round=5Fflow:295-317=20=E5=85=A8=E5=9F=9F=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E6=8C=89=E9=A6=96=E8=A1=8C=E5=88=A4=E9=87=8F=E5=8F=8C?= =?UTF-8?q?=E8=A1=8C=E5=BF=85=E7=BA=A2)=EF=BC=9B=E5=8D=A1=E7=89=87?= =?UTF-8?q?=E5=8D=87=20v1.1=20=E9=80=90=E6=9D=A1=E5=A4=84=E7=BD=AE(?= =?UTF-8?q?=E7=9B=AE=E6=A0=87=E6=94=B6=E7=AA=84=E8=87=B3=E6=B7=B1=E5=BA=A6?= =?UTF-8?q?=203=EF=BC=8B=E6=96=B0=E5=A2=9E=20R9=20=E9=92=89=204/5=20?= =?UTF-8?q?=E8=90=BD=E5=B8=A6=E3=80=81T1=20=E6=94=B9=E6=9B=BF=E6=8D=A2=208?= =?UTF-8?q?1-106=20=E6=95=B4=E6=AE=B5=EF=BC=8B=E8=A1=A8=E6=B3=A8=E6=94=B9?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E9=94=9A=E7=82=B9=E3=80=81T2=20=E8=A1=A5?= =?UTF-8?q?=E4=B8=83=E6=AD=A5=E3=80=81R3=20=E6=94=B9=20=3D=3D3=E3=80=81R6?= =?UTF-8?q?=20=E9=99=8D=E4=B8=BA=E5=9B=9E=E5=BD=92=E6=8A=A4=E6=A0=8F?= =?UTF-8?q?=E3=80=81R8=20=E7=BC=A9=E9=9D=A2=E6=8E=92=E9=99=A4=20override.c?= =?UTF-8?q?fg=E3=80=81=E5=A4=B9=E5=85=B7=E6=8D=A2=20giant=5Fspider)?= =?UTF-8?q?=EF=BC=9B=E9=9A=BE=E5=BA=A6=E6=9B=B2=E7=BA=BF=20v1.3=E2=86=92v1?= =?UTF-8?q?.4=20=E8=AE=A2=E6=AD=A3=E8=A1=8C=E5=BA=8F=E8=A1=A8=E8=BF=B0?= =?UTF-8?q?=E4=B8=BA=E3=80=8C=E7=86=8A=E5=9C=B0=E7=B2=BE=20+=20=E5=9C=B0?= =?UTF-8?q?=E7=B2=BE=E3=80=8D=E3=80=82=E9=AA=8C=E8=AF=81:=20pipeline=5Fgat?= =?UTF-8?q?e=20PASS(28=20=E6=9D=A1=E7=9B=AE/=E5=8D=A1=E7=89=87=E5=8F=A3?= =?UTF-8?q?=E5=BE=84=203=20=E5=BC=A0=E5=85=A8=E8=BF=87)=EF=BC=8C--docs=20?= =?UTF-8?q?=E9=AA=8C=E6=94=B6=E9=80=9A=E8=BF=87=E6=97=A0=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=BA=A2=E3=80=82=E6=9C=AA=E8=B7=91:=20=E6=B8=B8=E6=88=8F?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=B8=8E=20MC(=E5=86=99=E5=8D=A1=E6=AE=B5?= =?UTF-8?q?=E9=9B=B6=E6=B5=8B=E8=AF=95=EF=BC=9BAlpha=20=E9=9B=B6=E8=AF=BB?= =?UTF-8?q?=E6=95=B0)=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/gdd/systems/冒险循环/难度曲线与Boss.md | 4 +- ...ling与godot-master-L1深度3混编批-2026-11-04.md | 58 ++++++ reports/需求卡片-L1深度3混编-2026-11-04.md | 192 ++++++++++-------- 3 files changed, 168 insertions(+), 86 deletions(-) create mode 100644 reports/复核-双审-grilling与godot-master-L1深度3混编批-2026-11-04.md diff --git a/design/gdd/systems/冒险循环/难度曲线与Boss.md b/design/gdd/systems/冒险循环/难度曲线与Boss.md index 0c3ad45d..abbc1e66 100644 --- a/design/gdd/systems/冒险循环/难度曲线与Boss.md +++ b/design/gdd/systems/冒险循环/难度曲线与Boss.md @@ -1,7 +1,7 @@ # 难度曲线与Boss > 一句话:难度曲线、期望值带与 Boss 设计 -> 状态:已定稿(自旧体系迁移);现行为 v1.3 +> 状态:已定稿(自旧体系迁移);现行为 v1.4 ## 设计目的 @@ -276,7 +276,7 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板 敌人表行值(行集与坐标覆盖随后续批次扩展,行值读 `enemy.tres`——本文只登记行模板与坐标语义): -**混编行集难度归属注记(2026-10-07 行集多行批——机制放开、本批零投放)**:敌人表同一坐标允许多行混编多种敌种后,混编遭遇的难度 = 行集内各行值按既有口径独立生效再叠加(数量区间各行各掷、行集实例总数 ≤ 4),不引入新的难度轴或乘区;投时行值 provisional 归本文调参的既有口径不变。**投放记录**:第一行 = (2, 5) 熊地精重击手 + 巨蜘蛛巢群(2026-10-07 迭代 18 卡⑤);第二行 = (1, 3) 地精 + 熊地精(2026-11-04 用户裁,随大地精数据行退役改混编,行值整行复用既有地精 / 熊地精行——零数值新增);Boss 多行第二批仍挂后置。**读数义务(2026-11-04 用户裁)**:Alpha 阶段数值层统一修正殿后,本阶段投放批零读数、零 MC 取证,难度带读数义务后移到数值统一修正批(本行与后续 Alpha 投放批同此口径)。机制批次(2026-10-07 本批)零内容投放、零数值变更。 +**混编行集难度归属注记(2026-10-07 行集多行批——机制放开、本批零投放)**:敌人表同一坐标允许多行混编多种敌种后,混编遭遇的难度 = 行集内各行值按既有口径独立生效再叠加(数量区间各行各掷、行集实例总数 ≤ 4),不引入新的难度轴或乘区;投时行值 provisional 归本文调参的既有口径不变。**投放记录**:第一行 = (2, 5) 熊地精重击手 + 巨蜘蛛巢群(2026-10-07 迭代 18 卡⑤);第二行 = (1, 3) 熊地精 + 地精(2026-11-04 用户裁,随大地精数据行退役改混编,行序熊地精在前——默认单体目标与开战叙述取首行,行值整行复用既有地精 / 熊地精行——零数值新增);Boss 多行第二批仍挂后置。**读数义务(2026-11-04 用户裁)**:Alpha 阶段数值层统一修正殿后,本阶段投放批零读数、零 MC 取证,难度带读数义务后移到数值统一修正批(本行与后续 Alpha 投放批同此口径)。机制批次(2026-10-07 本批)零内容投放、零数值变更。 | 坐标 | 敌种(数据键) | 生命 | 攻击(浮动区间) | 数量 | 技能池(权重) | 护甲 | |---|---|---|---|---|---|---| diff --git a/reports/复核-双审-grilling与godot-master-L1深度3混编批-2026-11-04.md b/reports/复核-双审-grilling与godot-master-L1深度3混编批-2026-11-04.md new file mode 100644 index 00000000..9d49e7da --- /dev/null +++ b/reports/复核-双审-grilling与godot-master-L1深度3混编批-2026-11-04.md @@ -0,0 +1,58 @@ +# 双审复核 · L1 深度 3 改混编批(grilling + godot-master,2026-11-04) + +> **性质**:需求卡片 v1.0 的独立复核产出物(req-card 纪律「grilling 复核门」+迭代 47 双审先例)。两个未参与撰写的会话各自只读复核,本报告记发现、处置与去向。 +> **被审对象**:`reports/需求卡片-L1深度3混编-2026-11-04.md` v1.0。 +> **复核面**:卡片自洽性、规格缺口、验收有效性(grilling);`.tres` 语义、加载与校验链、随机流、测试夹具与闸面(godot-master)。 +> **总判**:改动本体成立,卡片改后可开工——十条阻断全部属「漏引用点/口径写错/入口名写错」级,不动设计定值。已出卡片 v1.1 逐条处置。 + +--- + +## 一、阻断(10 条,双审合计;v1.1 全部处置) + +| # | 发现 | 证据 | 处置 | +|---|---|---|---| +| B1 | 漏第七个引用点:混编注入段还原后硬编码「表回 28 行」,加一行后必红 | `game/tests/unit/core/level_shop_economy_test.gd:727`(`== 28`,文案写「基线 20 行+覆盖 8 行」) | v1.1 新增现状事实 #13、T2 步骤、R8 行;文案改「基线 21 行」 | +| B2 | 漏第八个引用点:表结构守卫文件头注写「20 行带键行序/hobgoblin 留任」 | `game/tests/unit/data_config/table_structure_guard_test.gd:4` | T2 补步并顺带把「20 行」改「29 行」 | +| B3 | 漏第九、第十个引用点:同文件另两处 hobgoblin 前提注释 | `round_flow_skill_pool_test.gd:1108`;`:711,:722`「D3 大地精,多实例同种」「敌 hp 低(表值 6)」 | T2 补步改述 | +| B4 | 目标句「深度 3–5 的战斗」与落带机制相悖:寻址是「取首个 ≥ 深度的带」,L1 battle 带键只有 0/1/2/3/6,band 3 只覆盖深度 3;深度 4/5 落 band 6 | `game/data/schemas/enemy_table.gd:196-204`;`game/core/config_db_resolver.gd:57-67`;`enemy.tres:10,35,60,84,109` | §一 目标句改「只说深度 3」;新增契约 4「不碰深度 4/5」;新增 R9 钉住 4/5 仍落 band 6 | +| B5 | 行序依据引错文件:难度曲线 v1.3 投放记录写「地精 + 熊地精」(地精在前),与真正钉行序的 ⑱「熊地精在前」相反,卡片却把行序归给难度曲线 | `难度曲线与Boss.md:279`(原文);`体验验证清单.md:183-184` | §二 行序与行值依据改指 ⑱;难度曲线只作机制与投放记录;同批把文档那半句订正为「熊地精 + 地精」(v1.3→v1.4,本提交) | +| B6 | 真实入口写成不存在的函数:卡片写 `ConfigDbResolver.resolve_rowset`,仓库里叫 `resolve_enemy_rowset` | `game/core/config_db_resolver.gd:33`;`game/data/schemas/enemy_table.gd:216` | R2/R9 与 §八 统一改为 `EnemyTable.resolve_rowset()` → `ConfigDbResolver.resolve_enemy_rowset()` | +| B7 | 引用不存在的任务卡:「S13 键在 T0 读数步骤核对」,卡内只有 T1–T3,且与 Alpha 零读数自相矛盾 | 卡片 v1.0 §九;§四.5 | 改「零新增件,阈值不适用;S13 只降不升随 T2 声明」,删掉任何读数步骤 | +| B8 | **全深度 × 12 种子扫描只按「行集首行」判数量区间**:单行恒等成立,双行下 `n = 1 + 地精(1..2)`、首行(熊地精)区间是 `[1,1]`,必判越界 | `round_flow_skill_pool_test.gd:295-317`(`:310-317` 取 `[0]` 后比较);行值 `enemy.tres:58-67`、`:7-18` | T2 新增口径改造步(逐行求和 `[Σunit_count, Σunit_count_max]`,与 spawn 守卫同口径);R6 行;计入测试削弱申报 | + +## 二、建议(v1.1 采纳 11 条、判定不改 1 条) + +| # | 发现 | 证据 | 处置 | +|---|---|---|---| +| S1 | R6 原为「≥2 敌」,旧单行行集同样为真,对「是否混编」零判别力;且与结构图标「非行为改动」矛盾 | `damage_controller_test.gd:417`;`battle_narrator_test.gd:120` | 改为 R10「回归护栏」,明示不是混编判别;混编判别归 R2 | +| S2 | T3 缺法定产出「实际对照表(测试文件:行+结果)」;「变了回表」与实现批禁写 README 冲突 | `process-conventions.md:57`(§3 第 14 条)、`:54`(第 11 条) | T3 补实际对照表;README 改为「名字不符即停卡退回写卡段」 | +| S3 | 池模板断言文案写死「二十八行九种」 | `round_flow_skill_pool_test.gd:611` | T2 补步改「二十九行十种」 | +| S4 | 「大地精」第 4 处在 N1 修批括注 | `enemy.tres:920` | **判定不改**:该段是带日期的历史裁决记录,只含中文「大地精」、不含 `hobgoblin` 字面,R10 口径不覆盖 | +| S5 | §二 写「四条纪律」与 GDD「三条」及卡内 §四.1 互斥 | `敌人系统.md:74`;卡片 §四 | 改「三条」 | +| S6 | R8「全仓零残留」口径过宽且不可执行:worktree 目录名生成的 `game/override.cfg` 里就有 hobgoblin | `game/override.cfg:4`;`.gitignore:11` | R10 缩面为「数据面 + `game/` 代码目录 + `tools/*.py`」,回读命令显式排除 `override.cfg` | +| S7 | 现状事实 #11 与 §八 行号错位:`unit_container.gd:34-45` 是注释(且重复两遍),`spawn` 在 :46、默认目标在 :358 | `unit_container.gd:34-45,46,358-363`;`battle_narrator.gd:69-78` | 两条事实分别改指正确位置 | +| S8 | R3 文案写「= 3」判据写「≤ 4」,且 3 是设计定值 | 卡片 R3 | 断言改 `== 3`(由两行行值推导后判等) | +| S9 | R7 挂了不受影响的用例 | `config_db_resolver_test.gd:65-71` | 从 R7 摘掉 `_test_rowset_order_preserved` | +| S10 | 定点断言段行号偏大 | `level_shop_economy_test.gd:623-636` | 改 623-636 | +| S11 | T1「删 82-105」会丢一对 `}, {`,落成空字典 | `enemy.tres:81,82-105,106` | T1 改为「替换 81-106 整段」 | +| S12 | 表注步骤按改前行号写,删行插行后行号漂移,后两步会切错内容 | `enemy.tres:81-106` 与被替换区净增 19 行 | T1 改用文本锚点定位;`906-918` 改为段尾追加一行(沿 899-905 的追加体例),不改原文 | +| S13 | 夹具换 `bugbear` 会与同表 band 0 的 `bugbear` 重名,削弱「按敌种可辨」;且 R7 写的「合成表 → `validate()`」不成立(该用例不调 validate) | `config_db_resolver_test.gd:14-28,40-46` | 改换 `giant_spider`;R7 真实入口改「合成行注入 → `resolve_enemy_rowset`」 | +| S14 | `_smoke_enemy_buff_targets_self` 是种子搜索型用例(找「恰一次 charge 施放」),混编后只有熊地精带 charge,命中面必变 | `round_flow_skill_pool_test.gd:1096-1136`;池差 `enemy.tres:93-102` vs `:19-28` | 列入 T2 最后一步:跑不通即按 L3 呈报,禁放宽判据 | +| S15 | 删 `enemy.tres:886-891` 后 `static_scan.sh` 的 `FNR==891` 豁免指向别的行 | `game/tests/static_scan.sh:145,194,218,221-222` | T2 补步:删该条失效豁免(口径只删豁免、不改扫描规则) | + +## 三、观察(记录在案,不改卡) + +- **随机流作用域不位移**:遭遇骰每战只 `open_stream("encounter")` 一次(`battle_orchestrator.gd:307`),全局计数器 +1(`rng_service.gd:103-122`),后续 `behavior_roll`/`armor_roll` 号位不变;变的是流内取号(单行 2 次 → 双行 3 次)。`game/tests/golden/` 只有关卡地图片与调色板基线,无敌人数值 golden,**无逐位断言风险**。 +- **spawn 守卫不误触发**:`1 + [1,2] = 2..3 ≤ 4`(`unit_container.gd:86-92`、`enemy_table.gd:30-33`);容器零随机,取号全在结算层。 +- **池顺序无关**:池模板断言收成字典比对(`round_flow_skill_pool_test.gd:606-609`),抽签本体顺序敏感但整行复制保序。 +- **加载校验链全通**:同带键两行相邻 → `_validate_rowset_closed` 只在键「重现」时报错(`enemy_table.gd:57-61,178-182`);`dup_key` 键含 `enemy_id`(`:81-84`)不误报;跨表池纪律逐行逐池检查(`config_db_cross_validator.gd:191-214`),新行池与既有行逐字相同。 +- **`tools/doc_term_audit.py` 零行为影响**:只扫 `*.md`/`*.yaml`,且跳过 `#;` 注释行(`:166,214-219`)。 +- **`enemy.tres:653`/`:751` 两处行号豁免**:均为数据行(无 `;` 注释),行号漂移后不会误伤;这类豁免按行号维护是既有技术债,建议另批改文本锚(非本批)。 +- **深度 4/5 原本无任何断言钉住**(仓库无 `resolve_rowset(1,4/5,"battle")` 构成断言),本批新增 R9 补上,防未来加 band 4/5 时静默改变内容。 +- **能力清单零动作成立**:README 按函数名引用,本批不改函数名;`_smoke_encounter_roll`/`_smoke_level_graph` 两个被触碰用例本就未在能力表列名,属既有登记缺口,非本批引入。 + +## 四、呈用户裁决项 + +1. **表注 886-891 整段删除 vs 静态闸「带日期历史原文不改」惯例**:卡片按你的指令「文档与代码中的大地精描述要去掉」取删除,代价是一条命名沿革注只留 git 历史。若你要保原文,则完成定义④须放宽为「非注释面零残留」。 +2. **`static_scan.sh` 行号豁免改文本锚**(`enemy.tres:653/751` 两处):属闸件维护,建议另立小批,本批只删已失效的 891 那条。 +3. **深度 4/5 是否也该换内容**:本批按「只做深度 3」写;若你要 L1 后半段也混编,属设计增量,需另立条目。 diff --git a/reports/需求卡片-L1深度3混编-2026-11-04.md b/reports/需求卡片-L1深度3混编-2026-11-04.md index 3f94624e..234fbb6f 100644 --- a/reports/需求卡片-L1深度3混编-2026-11-04.md +++ b/reports/需求卡片-L1深度3混编-2026-11-04.md @@ -1,91 +1,104 @@ # 需求卡片 · L1 深度 3 改地精+熊地精混编(大地精数据行退役) -来源:待办清单「L1 深度 3 改地精+熊地精混编(大地精数据行退役)」(2026-11-04 登记,文档设计已闭合+待写卡)(唯一事实源:`design/gdd/systems/冒险循环/难度曲线与Boss.md` v1.3「混编行集难度归属注记」投放记录段 + `design/gdd/systems/战斗循环/敌人系统.md` v1.6 核心规则「开战生成」「技能池」前的敌种表段与「行集构成纪律」条) +来源:待办清单「L1 深度 3 改地精+熊地精混编(大地精数据行退役)」(2026-11-04 登记,文档设计已闭合+已写卡)(唯一事实源:`体验验证清单.md` ⑱「投放内容」段第 (1,3) 行条目——行序、行值取定与静态骰和在该段钉死;机制合法性见 `design/gdd/systems/战斗循环/敌人系统.md` v1.6 核心规则「行集构成纪律」条;投放记录与读数义务见 `design/gdd/systems/冒险循环/难度曲线与Boss.md` v1.3 混编注记段) -日期 2026-11-04 | 段位=写卡(第三段)| 开工门=用户发令 U0 +日期 2026-11-04 | 第 2 版(v1.1,2026-11-04 双审复核后改写)| 段位=写卡(第三段)| 开工门=用户发令 U0 ## 一、目标与完成定义 -把敌人表里未经过设计的大地精数据行(`hobgoblin`)退役,同一坐标改为「熊地精 + 地精」两行混编,让第一关深度 3–5 的战斗由「2–3 只同种」变成「一只前排熊地精 + 一到两只地精」。 +把敌人表里未经过设计的大地精数据行(`hobgoblin`,坐标 `(1, battle, 3)`)退役,同一坐标改为「熊地精 + 地精」两行混编:一只前排熊地精、一到两只地精。 -完成定义(四条全中才算完):① 敌人表不再有 `hobgoblin`,该坐标是两行混编且行序为「熊地精在前」;② 两行行值逐字等于既有 `(1,battle,2)` 与 `(1,battle,0)` 行值(零数值新增);③ 全仓代码与表注再无 `hobgoblin` 残留;④ 冒烟与单元闸全绿。 +**覆盖面只说深度 3**:深度带寻址是「取首个 ≥ 深度的带」,L1 的战斗带键只有 0/1/2/3/6(`enemy.tres:10,35,60,84,109`),所以 band 3 只覆盖深度 3;深度 4、5 落 band 6(单行熊地精 1–2 只 hp30/ac4),**本批不碰也不该碰**。 + +完成定义(五条全中才算完):① 敌人表不再有 `hobgoblin` 数据行,`(1,battle,3)` 是两行混编且行序为「熊地精在前」;② 两行行值逐字段等于既有 `(1,battle,2)` 与 `(1,battle,0)` 行;③ 深度 4/5 的落带结果与改动前一致(仍落 `(1,battle,6)`);④ 全仓非历史面的 `hobgoblin` 残留清零(口径见 R10);⑤ 冒烟与单元闸全绿。 ## 二、设计事实源 -- 投放决定与行序、数量、行值取定:`design/gdd/systems/冒险循环/难度曲线与Boss.md` v1.3「混编行集难度归属注记」的投放记录段(第二行 = (1,3) 地精 + 熊地精,2026-11-04 用户裁) -- 混编合法性四条纪律:`design/gdd/systems/战斗循环/敌人系统.md` v1.6 核心规则「行集构成纪律」条 -- 读数义务口径(Alpha 零读数):`design/engineering/process-conventions.md` §3 第 5 条 Alpha 阶段口径段 +- **行序 + 行值 + 数量取定**:`体验验证清单.md` ⑱ 投放内容段第 (1,3) 条(「行值整行复用 (1,2) 熊地精(1 只 / hp22 / ac2)与 (1,0) 地精(1–2 只 / hp8 / ac0),零数值新增;静态最坏骰和 1+2=3;行序 = 熊地精在前」) +- **混编合法性三条纪律**:`design/gdd/systems/战斗循环/敌人系统.md` v1.6 核心规则「行集构成纪律」条 +- **投放记录与读数义务**:`design/gdd/systems/冒险循环/难度曲线与Boss.md` v1.3 混编注记段(只给机制与义务,不给行序) +- **Alpha 零读数**:`design/engineering/process-conventions.md` §3 第 5 条 Alpha 阶段口径段 - 待办清单条目:`待办清单.md`「L1 深度 3 改地精+熊地精混编(大地精数据行退役)」条 ## 三、现状事实(代码级,开工自行复核) | # | 事实 | 位置 | |---|---|---| -| 1 | 大地精行在役:`(1,battle,3)`、2–3 只、hp14、atk 1 区间 [0,2]、池 attack6/charge2/heavy2、light、ac2 | `game/data/tables/enemy.tres:82-105` | -| 2 | 前排取用行:熊地精 `(1,battle,2)` 1 只定值、hp22、ac2、池 attack6/charge2/heavy2 | `game/data/tables/enemy.tres:58-80` | +| 1 | 大地精行在役:`(1,battle,3)`、2–3 只、hp14、池 attack6/charge2/heavy2、light、ac2 | `game/data/tables/enemy.tres:82-105`(行由 `:81` 的 `}, {` 打开、`:106` 的 `}, {` 收尾——删改必须连分隔符一起算) | +| 2 | 前排取用行:熊地精 `(1,battle,2)` 1 只定值(无 `unit_count_max`)、hp22、ac2、池 attack6/charge2/heavy2 | `game/data/tables/enemy.tres:58-80` | | 3 | 后排取用行:地精 `(1,battle,0)` 1–2 只、hp8、ac0、池 attack9/lunge1/desperate_guard1 | `game/data/tables/enemy.tres:7-31` | -| 4 | 另一条熊地精行 `(1,battle,6)` 1–2 只、hp30、ac4 —— 本卡不取用(深档,第三战放它偏硬) | `game/data/tables/enemy.tres:107-131` | -| 5 | 敌人表共 28 行,键序被逐行钉死 | `game/tests/unit/data_config/table_structure_guard_test.gd:209-231` | -| 6 | 现有断言「hobgoblin 行在 (1,battle,3) 留任随迁」 | `game/tests/unit/data_config/table_structure_guard_test.gd:234-239` | -| 7 | 池模板断言表逐键写死,含 `1_battle_3_hobgoblin` | `game/tests/unit/battle_settlement/round_flow_skill_pool_test.gd:567-578`(函数 `_smoke_skill_pool_data`) | -| 8 | 个体池/个体 AC 对照用例以 depth 3 为「≥2 敌」夹具 | `game/tests/unit/battle_settlement/damage_controller_test.gd:412-440`;`game/tests/unit/presentation/battle_narrator_test.gd:108-118` | -| 9 | 行序/落带夹具用 hobgoblin 作合成行 | `game/tests/unit/core/config_db_resolver_test.gd:40-46`;断言在 `:56-78` | -| 10 | 行集纪律用例用 hobgoblin 作「不相邻」样本 | `game/tests/unit/data_config/config_db_test.gd:220-230`(函数 `_test_rowset_discipline`) | -| 11 | 首行即默认单体目标与开战叙述取首行 | `design/gdd/systems/战斗循环/敌人系统.md` v1.6「开战生成」节;实现侧 `game/core/unit_container.gd:34-45` | -| 12 | 混编定点断言先例(L2)写法可直接照抄 | `game/tests/unit/core/level_shop_economy_test.gd:623-640` | -| 13 | 术语审计注释里列了 hobgoblin | `tools/doc_term_audit.py:144` | +| 4 | 深层熊地精 `(1,battle,6)` 1–2 只、hp30、ac4——深度 4/5 落这里,本批不取用 | `game/data/tables/enemy.tres:107-131` | +| 5 | 行集取首个 ≥ 深度的带 | `game/data/schemas/enemy_table.gd:196-204`;`game/core/config_db_resolver.gd:57-67` | +| 6 | 行集返回序 = 表文件行序 | `game/core/config_db_resolver.gd:92-98` | +| 7 | 默认单体目标取生成序最前;开战叙述取行集首行 | `game/core/unit_container.gd:358-363`;`game/core/battle_narrator.gd:69-78` | +| 8 | 敌人表共 28 行,键序逐行钉死;文件头注释也写「20 行带键行序/hobgoblin 留任」 | `game/tests/unit/data_config/table_structure_guard_test.gd:4`;键序断言 `:212-233`;留任断言 `:234-239` | +| 9 | 全深度 × 12 种子 spawn 扫描**只按行集首行判定数量区间**——单行成立,双行必红 | `game/tests/unit/battle_settlement/round_flow_skill_pool_test.gd:295-317`(关键 `:310-317`:`resolve_rowset(...)[0]` 取首行后比较 `[unit_count, unit_count_max]`) | +| 10 | 池模板断言表逐键写死,含 `1_battle_3_hobgoblin`;同函数断言文案写「二十八行九种」 | `round_flow_skill_pool_test.gd:567-578`、`:611`(函数 `_smoke_skill_pool_data`) | +| 11 | 同文件另两处 hobgoblin 前提:注释 `:1108`「L1 depth 3(hobgoblin 行集 2-3 只)」、`:711`/`:722`「D3 大地精,多实例同种」「敌 hp 低(表值 6)」(后者已随表值失真) | `round_flow_skill_pool_test.gd:711,722,1108` | +| 12 | `_smoke_enemy_buff_targets_self` 是**种子搜索型**用例:搜 1..N 号种子找「恰一次 charge 施放」,混编后只有熊地精带 charge | `round_flow_skill_pool_test.gd:1096-1136` | +| 13 | 混编注入段还原后硬编码「表回 28 行」 | `game/tests/unit/core/level_shop_economy_test.gd:727` | +| 14 | 混编定点断言先例(L2)写法可照抄 | `level_shop_economy_test.gd:623-636` | +| 15 | 个体池/个体 AC 对照用例以 depth 3 为「≥2 敌」夹具 | `game/tests/unit/battle_settlement/damage_controller_test.gd:412-440`;`game/tests/unit/presentation/battle_narrator_test.gd:108-121` | +| 16 | 行序/落带夹具用 hobgoblin 作合成行;该夹具**不调 `validate()`**,只注入 resolver | `game/tests/unit/core/config_db_resolver_test.gd:14-28`、`:40-46`、`:56-78` | +| 17 | 行集纪律用例用 hobgoblin 作「不相邻」样本 | `game/tests/unit/data_config/config_db_test.gd:220-230`(`_test_rowset_discipline`) | +| 18 | 表注四处含退役键:`886-891`(2026-09-24 实体名修正批整段)、`906-918`(2026-10-07 混编首批投放批)、`920`(N1 修批括注「改名大地精」)、`929`(hobgoblin 行为缺口行) | `game/data/tables/enemy.tres:886-891,906-918,920,929` | +| 19 | 静态闸按**行号**豁免 `enemy.tres` 三处,其中 `FNR==891` 落在上述 886-891 段内——删段后该豁免指向别的行,必须同步清 | `game/tests/static_scan.sh:145`、豁免执行点 `:194,218,221-222` | +| 20 | 术语审计注释里列了 hobgoblin,但该文件只扫 `.md`/`.yaml`、且跳过 `#;` 注释行,改动零行为影响 | `tools/doc_term_audit.py:144`(匹配与扫描面 `:146-147,166,214-219`) | ## 四、设计契约(🔴 违反=停机呈报) -1. 🔴 **行集构成纪律三条**:行集内 `enemy_id` 唯一;同带键多行必须文件内相邻且行序=声明序=生成序;行集实例总数 ≤ 4、单行数量域 [1,3]。本卡静态最坏骰和 = 熊地精 1 + 地精 2 = 3。 -2. 🔴 **行值零新增**:两行行值必须整行复制既有行(第 2、3 条现状事实),不得顺手改 hp/atk/池权重/ac;若实施中发现必须改数值,停卡退回写卡段。 -3. 🔴 **行序固定**:熊地精行在前、地精行在后。行序变更会改默认单体目标与开战叙述首行,属设计面变更,不在本卡授权内。 -4. 🔴 **Alpha 零读数**:本卡不跑 MC、不采改前改后读数,实现报告注明「未取证」,读数义务归数值统一修正批(`process-conventions` §3 第 5 条)。 -5. 🔴 **禁碰敌种表与技能表**:`敌人系统.md` 敌种表维持八种;`skills.tres` 零改动——地精与熊地精的池已存在。 -6. 🔴 **禁改闸件口径**:`standee_asset_check`/`path_check` 的 `ENEMY_KEYS` 是美术侧键集,与本卡无关,禁顺手改。 +1. 🔴 **行集构成纪律三条**:行集内 `enemy_id` 唯一;同带键多行必须文件内相邻且行序=声明序=生成序;行集实例总数 ≤ 4、单行数量域 [1,3]。本批静态最坏骰和 = 熊地精 1 + 地精 2 = 3。 +2. 🔴 **行值零新增**:两行行值必须整行复制第 2、3 条现状事实里的行,不得改 hp/atk/池权重/ac;改了就是设计变更,停卡退回写卡段。 +3. 🔴 **行序固定**:熊地精行在前、地精行在后(依据 §二 第一条)。行序影响默认单体目标与开战叙述首行,不属实现面可调项。 +4. 🔴 **不碰深度 4/5**:`(1,battle,6)` 行一字段都不许动;目标句里没有「深度 3–5」这回事。 +5. 🔴 **Alpha 零读数**:本批不跑 MC、不采改前改后读数;实现报告注明「未取证」,读数义务归数值统一修正批。 +6. 🔴 **禁碰敌种表与技能表**:`敌人系统.md` 敌种表维持八种;`skills.tres` 零改动。 +7. 🔴 **禁改美术侧键集**:`tools/standee_asset_check.py` 与 `tools/path_check.py` 的 `ENEMY_KEYS` 与本批无关,禁顺手改。 ## 五、范围边界 -**做**:敌人表删一行加两行+表注三处改写;六处测试换锚与补断言;`tools/doc_term_audit.py` 注释一行。 +**做**:敌人表删一行加两行+表注四处;七个测试文件换锚与补断言;`tools/doc_term_audit.py` 注释;`static_scan.sh` 一条失效豁免清理。 -**不做**:任何数值调整(hp/atk/池权重/ac);敌种表或技能表改动;立绘与美术面(不做该敌种,无素材需求);L1 其余四行;Boss 多行第二批;读数与模拟。 +**不做**:任何数值调整;敌种表/技能表;深度 4/5 的带位;立绘与美术面;Boss 多行第二批;读数与模拟;`enemy.tres:920` 的 N1 修批括注(见 §十一 T1 第 6 步说明)。 -**不收件去向**:数值带位移读数 → 数值统一修正批;L1 实机混编目检 → `体验验证清单.md` ⑱(本卡只登记,不阻塞合并)。 +**不收件去向**:数值带位移读数 → 数值统一修正批;实机混编目检 → `体验验证清单.md` ⑱(只登记,不阻塞合并)。 ## 六、关联文档同步面(实现批禁写文档) | 文档 | 关联点 | 同步义务 | |---|---|---| -| `design/gdd/systems/冒险循环/难度曲线与Boss.md` v1.3 | 「混编行集难度归属注记」已写入 (1,3) 投放记录 | 零动作(文档批已落文,commit 4aaa154e) | -| `design/gdd/systems/战斗循环/敌人系统.md` v1.6 | 大地精缺口登记已删除、敌种表维持八种 | 零动作(文档批已落文,commit 4aaa154e) | -| `体验验证清单.md` ⑱ | 已扩为 L1 节点 3 + L2 节点 5 双点目检 | 零动作(文档批已落文);实现批只把目检项抄进实现报告 | -| `design/gdd/08-Alpha版本标准.md` v1.26 | 混编遭遇行集状态行已补 (1,3) | 零动作(文档批已落文) | -| `game/tests/README.md` 能力表 | 本批不新增能力、不改既有用例函数名(改的是既有函数体内的断言与夹具) | 零动作;若实现期不得不改函数名,按反哺点列出 | +| `design/gdd/systems/冒险循环/难度曲线与Boss.md` v1.3 | 混编注记段已写 (1,3) 投放记录 | 零动作(文档批已落文,commit 4aaa154e;行序表述由本批前置修复提交更正) | +| `design/gdd/systems/战斗循环/敌人系统.md` v1.6 | 缺口登记已删、敌种表维持八种 | 零动作(同上) | +| `体验验证清单.md` ⑱ | L1 节点 3 目检三项 + 读数义务 | 零动作;实现报告抄录目检项 | +| `design/gdd/08-Alpha版本标准.md` v1.26 | 混编行集状态行已补 (1,3) | 零动作 | +| `game/tests/README.md` 能力表 | 本批不改任何用例函数名,只改函数体内断言与夹具 | 零动作;若实现期必须改名,停卡退回写卡段(实现批禁写该文件) | ## 七、文件结构图 | 路径 | 职责 | 改动类型 | 对照表行 | |---|---|---|---| -| `game/data/tables/enemy.tres` | 删 (1,3) 大地精行、原位起两行混编、改三处表注 | 行为改动 | R1–R5 | -| `game/tests/unit/data_config/table_structure_guard_test.gd` | 行数与键序换 29 行、留任断言换混编构成断言、补骰和与行值复用断言、补零残留断言 | 行为改动(测试面) | R1–R4、R8 | -| `game/tests/unit/battle_settlement/round_flow_skill_pool_test.gd` | 池模板表两键换原一键 | 行为改动(测试面) | R6 | -| `game/tests/unit/core/config_db_resolver_test.gd` | 合成夹具 enemy_id 换成既有键(行序/落带语义不变) | 非行为改动(夹具) | R7 | -| `game/tests/unit/data_config/config_db_test.gd` | 行集纪律样本 enemy_id 换既有键 | 非行为改动(夹具) | R7 | -| `game/tests/unit/battle_settlement/damage_controller_test.gd` | depth 3 夹具注释改述(前提「≥2 敌」仍成立) | 非行为改动(注释) | R7 | -| `game/tests/unit/presentation/battle_narrator_test.gd` | 同上 | 非行为改动(注释) | R7 | -| `tools/doc_term_audit.py` | 第 144 行注释里的敌种枚举去掉 hobgoblin | 非行为改动(注释) | R8 | +| `game/data/tables/enemy.tres` | (1,3) 一行换两行;表注四处处置 | 行为改动 | R1–R4、R9 | +| `game/tests/unit/data_config/table_structure_guard_test.gd` | 29 行键序、混编构成断言、骰和与行值复用断言、零残留断言、文件头注 | 行为改动(测试面) | R1–R5、R10 | +| `game/tests/unit/battle_settlement/round_flow_skill_pool_test.gd` | 全域扫描口径改逐行求和;池模板两键;四处注释与文案 | 行为改动(测试面) | R6、R7、R10 | +| `game/tests/unit/core/level_shop_economy_test.gd` | 混编注入段还原行数 28→29 | 行为改动(测试面) | R8 | +| `game/tests/unit/core/config_db_resolver_test.gd` | 合成行换 `giant_spider`(不换 bugbear,避免与 band 0 同名) | 非行为改动(夹具) | R7 | +| `game/tests/unit/data_config/config_db_test.gd` | 「不相邻」样本换 `giant_spider` | 非行为改动(夹具) | R7 | +| `game/tests/unit/battle_settlement/damage_controller_test.gd` | depth 3 夹具注释改述 | 非行为改动(注释) | — | +| `game/tests/unit/presentation/battle_narrator_test.gd` | 同上 | 非行为改动(注释) | — | +| `game/tests/static_scan.sh` | 删失效的 `FNR==891` 豁免条目(对象已随表注删除) | 非行为改动(闸件豁免维护) | — | +| `tools/doc_term_audit.py` | 注释里的敌种枚举 | 非行为改动(注释) | — | -无新增文件、无新增类、无新增公开方法。 +无新增文件、类、公开方法。 ## 八、落位与可复用性预检 -- **复用面**:本批零新增文件/函数/数据件。新增的两条表行不是新结构——`pool`、`armor_class`、`attack_type` 等字段全部沿用既有行字段集,直接整行复制既有行(第 2、3 条现状事实),不引入任何新字段或新默认值。 -- **唯一面**:混编构成的事实只有两处——表的行序(`enemy.tres`)与钉住它的断言(`table_structure_guard_test.gd`)。行值不在测试里复写:断言比对「(1,3) 两行 == (1,2) 与 (1,0) 行」而不是写死 22/8/权重,防双写漂移。 -- **分层与交互面**:本批不新增调用路径。运行时读取仍走 `ConfigDb` → `ConfigDbResolver.resolve_rowset(1, depth, "battle")` → `UnitContainer.spawn()`(`game/core/unit_container.gd:34-45`),分层与红线(Core 零 UI、数值只读表)不变。 +- **复用面**:零新增文件/函数/数据件。两条新表行沿用既有字段集,整行复制既有行,不引入新字段或新默认值。 +- **唯一面**:混编构成的事实只在两处——表行序与钉住它的断言;行值不在测试里复写(R4 比对两行相等,不写 22/8/权重字面量)。全域扫描的数量判据改为「逐行求和」,与 `unit_container.gd:86-92` 的 spawn 守卫同口径,不另立第二套口径。 +- **分层与交互面**:零新增调用路径。运行时仍走 `ConfigDb` → `EnemyTable.resolve_rowset()` → `ConfigDbResolver.resolve_enemy_rowset()` → `UnitContainer.spawn()`(`game/core/unit_container.gd:46`),Core 零 UI、数值只读表、随机只在结算层(`game/core/battle_orchestrator.gd:293-324`)三条红线不变。 ## 九、实现规范预算 -零新增文件与新增成员,`gdstyle` 阈值不适用。存量触面一查:本卡触碰的六个测试文件不新增成员变量与公开方法(只在既有函数体内改断言与夹具),S13 键「较登记值只降不升」在 T0 读数步骤核对。 +零新增文件与新增成员,`gdstyle` 阈值不适用;本批触碰的测试文件不新增成员变量与公开方法。存量触面一查:`static_scan.sh` 只删一条豁免、不改扫描规则;S13 键在三处测试文件内均只降不升(只改断言文本,不增函数)。 ## 十、拆分边界纪律 @@ -93,57 +106,68 @@ ## 十一、任务卡 -### T1 · 敌人表换行(估时 0.5 日) +### T1 · 敌人表换行与表注(估时 0.5 日) -取用:无(本卡首卡)。产出:`enemy.tres` 的 (1,3) 两行 —— 供 R1–R4 断言读取。 +取用:无(首卡)。产出:`(1,battle,3)` 两行 + 清理后的表注,供 R1–R5、R9 读取。 -- [ ] 删 `game/data/tables/enemy.tres:82-105` 的整行(`enemy_id: hobgoblin`) -- [ ] 原位按序插入两行:第一行 `enemy_id: "bugbear"`/`display_name: "熊地精"`/`depth_band: 3`/`unit_count: 1`/无 `unit_count_max`/`hp: 22`/`atk: 1`/`atk_min: 0`/`atk_max: 2`/`pool: [attack 6, charge 2, heavy 2]`/`attack_type: "normal"`/`armor_type: "light"`/`armor_class: 2` -- [ ] 第二行 `enemy_id: "goblin"`/`display_name: "地精"`/`depth_band: 3`/`unit_count: 1`/`unit_count_max: 2`/`hp: 8`/`atk: 1`/`atk_min: 0`/`atk_max: 2`/`pool: [attack 9, lunge 1, desperate_guard 1]`/`attack_type: "normal"`/`armor_type: "light"`/`armor_class: 0` -- [ ] 改表注 `enemy.tres:886-891`:把「(1,3) 熊地精双雄 → 大地精」那段沿革注改为一行留痕「(1,3) 大地精行已于 2026-11-04 用户裁退役,改地精+熊地精混编——沿革见 git 提交史」 -- [ ] 改表注 `enemy.tres:906-918`:把「首个混编行落表 = (2,5)」改为「混编投放两行:(2,5) 2026-10-07、(1,3) 2026-11-04」,并把句末「随 Alpha 收官 M4 数值批统一执行」改为「随数值统一修正批统一执行」 -- [ ] 删表注 `enemy.tres:929` 整句(hobgoblin 行为缺口行) +- [ ] 把 `enemy.tres:81-106` 整段(`}, {` + 大地精字段块 + `}, {`)替换为:`}, {` + 熊地精字段块 + `}, {` + 地精字段块 + `}, {` +- [ ] 熊地精块字段:`level_index: 1`/`row_kind: "battle"`/`depth_band: 3`/`enemy_id: "bugbear"`/`display_name: "熊地精"`/`unit_count: 1`/(不写 `unit_count_max`)/`hp: 22`/`atk: 1`/`atk_min: 0`/`atk_max: 2`/`pool: [attack 6, charge 2, heavy 2]`/`attack_type: "normal"`/`armor_type: "light"`/`armor_class: 2` +- [ ] 地精块字段:`depth_band: 3`/`enemy_id: "goblin"`/`display_name: "地精"`/`unit_count: 1`/`unit_count_max: 2`/`hp: 8`/`atk: 1`/`atk_min: 0`/`atk_max: 2`/`pool: [attack 9, lunge 1, desperate_guard 1]`/`attack_type: "normal"`/`armor_type: "light"`/`armor_class: 0` +- [ ] 删表注段「实体名修正批(2026-09-24…)」整段(按文本锚点定位,不按行号)——该段全篇在讲大地精改名沿革,内容 git log 可考 +- [ ] 删表注句「hobgoblin 行为缺口行:无立绘、不在敌种表——留任在役,补齐三件套…」整句 +- [ ] 在下一行追加新注(`;` 顶格):「; (1,3) 大地精行 2026-11-04 用户裁退役,改地精+熊地精混编(行序熊地精在前、行值整行复用 (1,2)/(1,0)、静态骰和 3);沿革见 git 提交史」 +- [ ] 在「混编遭遇首批投放批(2026-10-07…)」段尾追加一行(不改原文):「; 2026-11-04 追加第二行:(1,3) 地精+熊地精(行序熊地精在前)」 +- [ ] 保留 `:920` 的 N1 修批括注原文(属带日期的历史裁决记录,且只含中文「大地精」、不含 `hobgoblin` 字面;R10 口径不覆盖它) - [ ] 回读:`grep -n "hobgoblin" game/data/tables/enemy.tres` 输出为空 -### T2 · 测试面换锚与补断言(估时 1 日) +### T2 · 测试面换锚与补断言(估时 1.5 日) -取用:T1 产出的两行。产出:八条断言(R1–R8)落地,供 T3 收口核对。 +取用:T1 的两行。产出:R1–R10 全绿。 -- [ ] `table_structure_guard_test.gd:209-231`:行数 28→29;`expect_keys` 里 `"1|battle|3|hobgoblin"` 换成相邻两键 `"1|battle|3|bugbear", "1|battle|3|goblin"`;函数头与 `print` 的「28 行键序 · hobgoblin 留任」文案同步改 -- [ ] `table_structure_guard_test.gd:234-239`:删除「hobgoblin 留任随迁」断言块,替换为混编构成断言(R1–R4 四条,判据写在对照表) -- [ ] `round_flow_skill_pool_test.gd:567-578`:删 `"1_battle_3_hobgoblin": {"attack": 6, "charge": 2, "heavy": 2}`,改为 `"1_battle_3_bugbear": {"attack": 6, "charge": 2, "heavy": 2}` + `"1_battle_3_goblin": {"attack": 9, "lunge": 1, "desperate_guard": 1}`,行序按上表顺序 -- [ ] `config_db_resolver_test.gd:40-46`:`_enemy_rows()` 里的 `"hobgoblin"` 换为 `"bugbear"`;`:56-78` 三条断言的期望串同步改(行序与落带语义不变) -- [ ] `config_db_test.gd:220-230`:`_test_rowset_discipline()` 的「不相邻」样本 `"hobgoblin"` 换为 `"giant_spider"` -- [ ] `damage_controller_test.gd:413` 与 `battle_narrator_test.gd:114`:注释由「depth 3 = hobgoblin 行集」改为「depth 3 = 混编行集(熊地精 1 + 地精 1–2,最少 2 只)」;断言逻辑零改动 +- [ ] `table_structure_guard_test.gd:212-233`:`expect_keys` 里 `"1|battle|3|hobgoblin"` 换成相邻两键 `"1|battle|3|bugbear", "1|battle|3|goblin"`;行数 28→29(断言与文案同步) +- [ ] `table_structure_guard_test.gd:234-239`:删「hobgoblin 留任随迁」断言块,替换为混编构成断言(R1–R4) +- [ ] `table_structure_guard_test.gd:4`:文件头注「enemy 敌人表(20 行带键行序/hobgoblin 留任/三 Boss 行)」改为「(29 行带键行序/混编行集/三 Boss 行)」 +- [ ] `round_flow_skill_pool_test.gd:310-317`:把「`resolve_rowset(...)[0]` 取首行 + 比较 `[unit_count, unit_count_max]`」改为**逐行求和**:`lo = Σ unit_count`、`hi = Σ unit_count_max`,判 `n ∈ [lo, hi]` 且 `n ≥ 1`(与 `unit_container.gd:86-92` 守卫同口径) +- [ ] `round_flow_skill_pool_test.gd:567-578`:`"1_battle_3_hobgoblin": {"attack": 6, "charge": 2, "heavy": 2}` 换成 `"1_battle_3_bugbear": {"attack": 6, "charge": 2, "heavy": 2}` + `"1_battle_3_goblin": {"attack": 9, "lunge": 1, "desperate_guard": 1}`(顺序按表行序) +- [ ] `round_flow_skill_pool_test.gd:611`:断言文案「二十八行九种池模板」改「二十九行十种池模板」,其余描述不动 +- [ ] `round_flow_skill_pool_test.gd:711,722,1108`:注释改述为「depth 3 = 混编行集(熊地精 1 + 地精 1–2)」,删掉「多实例同种」「表值 6」两处已失真描述 +- [ ] `level_shop_economy_test.gd:727`:断言 28→29,文案「基线 20 行+覆盖 8 行」改「基线 21 行+覆盖 8 行」 +- [ ] `config_db_resolver_test.gd:40-46`:合成行 `"hobgoblin"` 换 `"giant_spider"`;`:56-78` 三条断言的期望串同步(不改成 `bugbear`——该合成表 band 0 已有 bugbear,同名会削弱「按敌种可辨」的可读性) +- [ ] `config_db_test.gd:220-230`:`_test_rowset_discipline()` 的「不相邻」样本 `"hobgoblin"` 换 `"giant_spider"` +- [ ] `damage_controller_test.gd:413` 与 `battle_narrator_test.gd:114`:注释改「depth 3 = 混编行集(熊地精 1 + 地精 1–2,最少 2 只)」,断言零改动 +- [ ] `static_scan.sh:145`:删掉豁免条目里的 `enemy.tres:891`(该行已随表注删除;留着会误放别的行) - [ ] `tools/doc_term_audit.py:144`:注释里的敌种枚举去掉 hobgoblin -- [ ] 回读:`grep -rn "hobgoblin" game/ tools/` 输出为空 +- [ ] 回读:`grep -rn "hobgoblin" game/data game/core game/presentation game/probe game/sim game/tests tools --include=*.gd --include=*.tres --include=*.py --include=*.sh` 输出为空(不含 `game/override.cfg`,该文件是 worktree 派生的 gitignored 文件,路径里带本区目录名) +- [ ] 跑 `_smoke_enemy_buff_targets_self`:种子搜索面随池构成变化,若 1..N 无命中 → 按 §十三 L3 呈报,禁放宽判据 ### T3 · 产出物落位(估时 0.5 日) -取用:T2 的八条断言全绿。产出:两份报告。 +取用:T2 全绿。产出:两份报告。 -- [ ] 写 `reports/iter-实现报告-<日期>.md`:各卡状态、实机目检总清单(L1 节点 3 混编三项,抄自 `体验验证清单.md` ⑱)、遗留读数义务(Alpha 零读数、读数归数值统一修正批)、实现决定记录 -- [ ] 写 `reports/iter-反哺点-<日期>.md`:按第六节同步面逐条落点(预计零条,也写「零条」) -- [ ] 核对 `game/tests/README.md` 能力表:用例函数名未变则可零动作;变了回表 +- [ ] 写 `reports/iter-实现报告-<日期>.md`:各卡状态;实机目检总清单(抄 `体验验证清单.md` ⑱ 的 L1 节点 3 三项);**实际对照表**(R1–R10 逐行写测试文件:行+结果,`process-conventions` §3 第 14 条);遗留读数义务(Alpha 零读数、归数值统一修正批);实现决定记录 +- [ ] 写 `reports/iter-反哺点-<日期>.md`:按 §六 逐条落点(预计零条,也写「零条」) +- [ ] 核对 `game/tests/README.md` 能力表:用例函数名未变则零动作;若实现期不得不改名,停卡退回写卡段 -估时合计 2 个工作日。 +估时合计 2.5 个工作日。 ## 十二、验证闸(改动—验收对照表) | 行 | 需求点 | 改动(文件:行/行为) | 验收测试(名称+落点+尾缀) | 层级 | 真实入口 | 判据绑定面 | 能力行 | |---|---|---|---|---|---|---|---| -| R1 | 行数与键序 | `enemy.tres:82-105` 一行换两行 | `table_structure_guard_test.gd:_smoke_enemy_bands`「敌人表 29 行且键序 = 覆盖表序((1,3) 两行相邻、熊地精在前)」〔L1混编 v1〕 | 单元 | `ConfigDb.load_tables()` → `EnemyTable.rows` | 遍历 rows 拼「关卡、行类、深度带、敌种」四段串逐行比对期望串 | 既有:表结构守卫:域校验/行序键/跨字段互锁/配额锚 | -| R2 | 混编构成(两行同带键、敌种唯一) | 同上 | 同函数「(1,3) 行集恰两行且 enemy_id = {bugbear, goblin} 无重复」〔L1混编 v2〕 | 单元 | `ConfigDbResolver.resolve_rowset(1,3,"battle")` | 返回数组长度与 enemy_id 序列 | 既有:行集寻址、行序保序与难度乘数 clamp | -| R3 | 静态最坏骰和 ≤ 4 | 同上 | 同函数「(1,3) Σ(unit_count_max,固定行缺省 unit_count) = 3 ≤ 4」〔L1混编 v3〕 | 单元 | 同上 | 求和值与上限常量比较 | 既有:表结构守卫:域校验/行序键/跨字段互锁/配额锚 | -| R4 | 行值整行复用(零数值新增) | 同上 | 同函数「(1,3) 两行行值逐字段 == (1,2) 与 (1,0) 行(hp/atk 区间/池/ac/armor_type/attack_type)」〔L1混编 v4〕 | 单元 | `EnemyTable.rows` | 两行字段逐项比对,不写死数值字面量 | 既有:表结构守卫:域校验/行序键/跨字段互锁/配额锚 | -| R5 | 双池各自独立 | 同上 | `round_flow_skill_pool_test.gd:_smoke_skill_pool_data`「(1,3) 两行池模板 = 熊地精池 attack6/charge2/heavy2 与地精池 attack9/lunge1/desperate_guard1」 | 单元 | 同上 | 断言表的键与权重逐项 | 既有:技能池数据面与回放独立 | -| R6 | depth 3 落到混编且最少 2 敌 | 同上 | `damage_controller_test.gd:_test_pool_consumption_per_unit` 前置「行集 ≥2 敌」+ `battle_narrator_test.gd:_test_snapshot_effects_per_unit` 前置「≥2 敌」在混编下仍绿 | 单元 | `UnitContainer.spawn({"level_index":1,"node_depth":3})` | 生成后 `all_enemies().size() ≥ 2` | 既有:敌方增益自体落点与乘区池按个体 | -| R7 | 夹具不依赖已退役 id | 三个夹具文件改 id | `config_db_resolver_test.gd:_test_band_hit` / `_test_rowset_order_preserved` / `_test_top_band_clamp` / `config_db_test.gd:_test_rowset_discipline` 全绿 | 单元 | 合成表 → `validate()` / `resolve_*()` | 错误类别与返回序列 | 既有:行集寻址、行序保序与难度乘数 clamp;既有:表结构守卫:域校验/行序键/跨字段互锁/配额锚 | -| R8 | 全仓零 hobgoblin 残留 | 表与六处测试与注释 | `table_structure_guard_test.gd` 补「表内 enemy_id 无 hobgoblin」断言(并入 `_smoke_enemy_bands`)+ T1/T2 的 grep 回读 | 单元 | `EnemyTable.rows` 遍历 | 集合不含该字符串 | 既有:表结构守卫:域校验/行序键/跨字段互锁/配额锚 | +| R1 | 行数与键序 | `enemy.tres:81-106` 一行换两行 | `table_structure_guard_test.gd:_smoke_enemy_bands`「敌人表 29 行且键序 = 覆盖表序((1,3) 两行相邻、熊地精在前)」〔L1混编 v1〕 | 单元 | `ConfigDb.load_tables()` → `EnemyTable.rows` | 遍历 rows 拼「关卡、行类、深度带、敌种」四段串逐行比对期望串 | 既有:表结构守卫:域校验/行序键/跨字段互锁/配额锚 | +| R2 | 混编构成与行序 | 同上 | 同函数「(1,3) 行集恰两行、enemy_id 序列 == [bugbear, goblin]、首行即默认目标」〔L1混编 v2〕 | 单元 | `EnemyTable.resolve_rowset(1,3,"battle")` → `ConfigDbResolver.resolve_enemy_rowset(1,3,"battle")` | 返回数组长度与逐项 enemy_id 序列 | 既有:行集寻址、行序保序与难度乘数 clamp | +| R3 | 静态最坏骰和 | 同上 | 同函数「(1,3) Σ(unit_count_max,固定行缺省 unit_count) == 3」〔L1混编 v3〕 | 单元 | 同上 | 求和值与 4 比较(等于 3,不用 ≤) | 既有:表结构守卫:域校验/行序键/跨字段互锁/配额锚 | +| R4 | 行值整行复用 | 同上 | 同函数「(1,3) 两行逐字段 == (1,2) 与 (1,0) 行(hp/atk 区间/pool/ac/armor_type/attack_type)」〔L1混编 v4〕 | 单元 | `EnemyTable.rows` | 两行字段逐项比对,不写死数值字面量 | 既有:表结构守卫:域校验/行序键/跨字段互锁/配额锚 | +| R5 | 零残留(数据与代码面) | 表与七文件 | 同函数「表内 enemy_id 集合不含 hobgoblin」〔L1混编 v5〕+ T2 回读命令 | 单元 | `EnemyTable.rows` 遍历 | 集合不含该字符串 | 既有:表结构守卫:域校验/行序键/跨字段互锁/配额锚 | +| R6 | 混编下 spawn 数量全域内 | `round_flow_skill_pool_test.gd:310-317` 口径改造 | `round_flow_skill_pool_test.gd:_smoke_encounter_roll`(全深度×种子扫描段)「全深度 × 12 种子 spawn 数量 ∈ [Σunit_count, Σunit_count_max] 且 ≥1」 | 单元 | `BattleOrchestrator.begin_battle({"level_index":1,"node_depth":d})` → `presentation_snapshot().enemies.size()` | 逐场数量与逐行求和区间比较 | 既有:行集寻址、行序保序与难度乘数 clamp | +| R7 | 双池各自独立 | 表两行 | `round_flow_skill_pool_test.gd:_smoke_skill_pool_data`「(1,3) 两行池模板 == 熊地精池 attack6/charge2/heavy2 与地精池 attack9/lunge1/desperate_guard1」 | 单元 | 同上 | 断言表的键与权重逐项 | 既有:技能池数据面与回放独立 | +| R8 | 注入段还原行数 | `level_shop_economy_test.gd:727` | `level_shop_economy_test.gd:_smoke_level_graph`「混编断言段注入行全量还原(表回 29 行)」 | 单元 | 同套件既有注入/还原流程 | `rows.size()` 与期望值比较 | 既有:关卡表消费侧校验与关卡推进 | +| R9 | 深度 4/5 落带不变 | 表(不应改变) | `table_structure_guard_test.gd` 补「(1,4) 与 (1,5) 的 battle 行集 == 单行 bugbear(band 6)」〔L1混编 v6〕 | 单元 | `EnemyTable.resolve_rowset(1,4/5,"battle")` | 返回数组长度与 enemy_id 序列、band 归属 | 既有:行集寻址、行序保序与难度乘数 clamp | +| R10 | 深度 3 最少 2 敌(回归护栏) | 两处夹具注释 | `damage_controller_test.gd:_test_pool_consumption_per_unit` 与 `battle_narrator_test.gd:_test_snapshot_effects_per_unit` 在混编行集下仍绿 | 单元 | `UnitContainer.spawn({"level_index":1,"node_depth":3})` | 生成后 `all_enemies().size() ≥ 2` | 既有:敌方增益自体落点与乘区池按个体 | -**测试削弱申报**:R8 删除了一条旧断言(`table_structure_guard_test.gd:234-239`「hobgoblin 留任随迁」)——该断言钉的是一个已退役事实,删除理由=对象不存在。除此外本批不删任何断言、不放宽阈值、不缩小扫描面。 +**测试削弱申报**:①`table_structure_guard_test.gd:234-239` 删除「hobgoblin 留任随迁」断言——钉的是已退役事实;②`round_flow_skill_pool_test.gd:310-317` 由「首行区间」改为「逐行求和区间」——原口径在双行行集下必红,新口径与 spawn 守卫同口径,不是放宽;③`round_flow_skill_pool_test.gd:611` 只改文案不改判据;④`static_scan.sh` 删一条针对已不存在行的豁免。除此外不删断言、不放宽阈值、不缩小扫描面。 -**判据绑定面说明**:本批全部判据绑在表数据与解析返回序列上(数据改动的可观测提交面),不做注入破坏或回退取证(`process-conventions` §3 第 14 条口径);R1–R4 的期望值从同表既有行推导,不写死字面量,避免与表双写。 +**判据绑定面说明**:全部判据绑在表数据与解析返回序列上(数据改动的可观测提交面);R1–R4 的期望值从同表既有行推导,不写死字面量;不做注入破坏或回退取证(`process-conventions` §3 第 14 条口径)。 **独立验收审计**:入口=未参与本卡实现的会话或子代理,按上表逐行复核(判据是否绑在被改动的表数据与解析序列上、真实入口是否绕过改动点);报告文件 `reports/iter-验收审计-<日期>.md`;未过不得合并。 @@ -152,17 +176,17 @@ ## 十三、异常分级 - L1 自救:缩进/格式/语法类错误,直接改到绿。 -- L2 记录继续:某条断言在不改设计的前提下换写法仍能表达同一判据(例如求和断言改写循环形式),记入实现报告「实现决定记录」。 -- L3 停机呈报:① 混编后 `spawn` 抛行集越域警告(静态骰和算错或别处也改了表);② 需要改数值才能过闸;③ 出现卡内没写的第七个引用点;④ 机检预算互斥(本批零新增件,若出现即判上游缺陷,停卡退回写卡段)。 +- L2 记录继续:断言写法等价改写(如求和改用循环)、注释措辞微调,记入实现报告「实现决定记录」。 +- L3 停机呈报:① spawn 抛行集越域警告;② 需要改数值才能过闸;③ 出现卡外第九个引用点;④ `_smoke_enemy_buff_targets_self` 种子搜索落空;⑤ 需要改 `game/tests/README.md` 或任何 `design/` 文件;⑥ 机检预算互斥(本批零新增件,出现即判上游缺陷,停卡退回写卡段)。 ## 十四、代拍板白名单 1. 断言函数内的循环写法、局部变量命名、断言文案措辞。 -2. 表注改写后的行文措辞(须保留日期 2026-11-04 与「用户裁」字样)。 -3. `expect_keys` 数组的换行排版。 -4. 注释改述的字面(不改语义)。 +2. 注释改述的字面(不改语义)。 +3. `expect_keys` 与 `expect_pools` 数组的换行排版。 +4. 新表注的措辞(须含日期 2026-11-04 与「用户裁」字样)。 超清单必呈报。 ## 十五、待裁点 -**零待裁点**,开工门=用户发令 U0。已裁记录:① 数量与行值(1/2/3 项)用户 2026-11-04 委托取定,本卡按「地精 1–2 + 熊地精 1、行值整行复用、熊地精在前」写入;② L1 首见混编用户 2026-11-04 判「无阻碍、可接受」;③ Alpha 零读数用户 2026-11-04 裁「先机制与内容填充,数值统一后修」,已落 `process-conventions` §3 第 5 条。 +**零待裁点**,开工门=用户发令 U0。已裁记录:① 数量、行值、行序(用户 2026-11-04 委托取定,落在 `体验验证清单.md` ⑱);② L1 首见混编可接受(用户 2026-11-04 判「无阻碍」);③ Alpha 零读数(用户 2026-11-04 裁,已落 `process-conventions` §3 第 5 条);④ 表注 886-891 整段删除(用户 2026-11-04 指令「文档与代码中的大地精描述要去掉」,与静态闸「历史原文不改」惯例冲突时以用户指令为准,代价=一条命名沿革注进 git log);⑤ 深度 4/5 不纳入本批(本次双审后订正目标句,不带设计增量)。