From a55fdf004cba54771bb11f764406879062708537 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Mon, 9 Nov 2026 02:20:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=99=E5=8D=A1(=E8=B7=A8=E8=A1=A8=E9=87=8F?= =?UTF-8?q?=E7=BA=A7=E6=8A=A4=E6=A0=8F=E6=89=B9=C2=B7QQ-12=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=8D=A1=E6=88=90=E7=AB=8B):=20=E9=9C=80=E6=B1=82?= =?UTF-8?q?=E5=8D=A1=E7=89=87=E6=88=90=E6=96=87=EF=BC=8B=E5=A4=8D=E6=A0=B8?= =?UTF-8?q?=E5=85=A8=E8=90=BD=E2=80=94=E2=80=94=E9=AA=8C=E6=94=B6=E6=A1=A3?= =?UTF-8?q?=E9=AB=98(=E6=95=B0=E5=80=BC=E8=A1=A8=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C),=E4=BC=B0=E6=97=B60.5=E2=80=931=E6=97=A5(?= =?UTF-8?q?=E4=B8=AD=E5=80=BC0.75),=E9=9B=B6=E5=BE=85=E8=A3=81=E7=82=B9?= =?UTF-8?q?=E5=BC=80=E5=B7=A5=E9=97=A8U0=E3=80=82=E6=94=B9=E5=8A=A8?= =?UTF-8?q?=E9=9D=A2=E9=92=89=E6=AD=BB:=20=E6=A0=A1=E9=AA=8C=E5=99=A8?= =?UTF-8?q?=E7=AC=AC=E2=91=A7=E9=A1=B9validate=5Fattack=5Fmagnitude(loaded?= =?UTF-8?q?,push=5Fdiag)=E7=BB=8Fcross=5Fvalidate=E6=97=A2=E6=9C=89?= =?UTF-8?q?=E9=93=BE=E7=94=9F=E6=95=88=EF=BC=8BHeroTable.MAX=5FHP=5FDOMAIN?= =?UTF-8?q?=5FMAX=3D999=E5=9F=9F=E5=B8=B8=E9=87=8F=E5=8D=95=E7=82=B9?= =?UTF-8?q?=EF=BC=8B=E5=8D=95=E5=85=83=E4=BA=94=E5=87=BD=E6=95=B0(V1?= =?UTF-8?q?=E8=B6=8A=E7=95=8C/V2=E5=90=88=E6=B3=95=E4=B8=8E=E8=BE=B9?= =?UTF-8?q?=E7=95=8C=E7=AD=89=E5=80=BC=E5=90=ABboss=E8=B1=81=E5=85=8D?= =?UTF-8?q?=E9=9D=9E=E7=A9=BA=E9=9A=BE=E5=BA=A6=E9=98=B2=E7=A9=BA=E8=BD=AC?= =?UTF-8?q?/V3=E7=A9=BA=E8=A1=A8=E8=B7=B3=E8=BF=87/V4=E5=8C=BA=E9=97=B4?= =?UTF-8?q?=E5=8F=96=E4=B8=8A=E9=99=90=E5=A4=B9=E5=85=B7=E6=BB=A1=E8=B6=B3?= =?UTF-8?q?=E4=B8=AD=E7=82=B9=E9=94=9A/V5=E8=B6=8A=E5=9F=9F=E4=B9=98?= =?UTF-8?q?=E6=95=B0=E9=92=B3=E5=88=B6)=EF=BC=8B=E8=87=B4=E5=91=BD?= =?UTF-8?q?=E5=85=A5=E5=8F=A3cross=5Fmagnitude=5Ffatal=5Ftest.gd(=E9=A6=96?= =?UTF-8?q?=E8=A1=8C=E4=B8=89=E6=94=B9500/500/500=EF=BC=8B=E9=9A=BE?= =?UTF-8?q?=E5=BA=A6=E8=A1=8Cmult3.0,=E9=A6=96=E7=8E=B0find+substr?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=E7=A6=81replace,=E9=80=80=E5=87=BA=E7=A0=811?= =?UTF-8?q?/2=E5=8D=8F=E8=AE=AE)=EF=BC=8Brun=5Fall=E7=99=BB=E8=AE=B0expect?= =?UTF-8?q?=3D1=20negative=3Dtrue=E3=80=82=E5=A4=8D=E6=A0=B8:=20=E8=87=AA?= =?UTF-8?q?=E5=AE=A1=E4=B8=83=E6=9F=A5=E5=B0=B1=E5=9C=B0=E4=BF=AE(?= =?UTF-8?q?=E5=A4=B9=E5=85=B7=E9=92=89=E5=80=BC/V6=E9=94=9A:214=E2=86=92:2?= =?UTF-8?q?15/T1=E4=B8=89=E6=94=B9=E9=98=B2=E4=B8=8A=E7=95=8C=E8=AF=BBatk?= =?UTF-8?q?=5Fmax=3D2=E4=B8=8D=E8=A7=A6=E5=8F=91/F6=E7=B2=BE=E8=8B=B1?= =?UTF-8?q?=E8=A1=8Catk=E4=BA=8B=E5=AE=9E)=EF=BC=8B=E5=8F=AA=E8=AF=BB?= =?UTF-8?q?=E5=AD=90=E4=BB=A3=E7=90=86=E5=AF=B9=E6=8A=97=E5=A4=8D=E6=A0=B8?= =?UTF-8?q?=E4=B8=80=E8=BD=AE10=E5=8F=91=E7=8E=B0=E5=85=A8=E5=A4=84?= =?UTF-8?q?=E7=BD=AE(7=E8=A1=A5=E5=86=99=E5=9B=9E=E5=A1=AB:=20settlement?= =?UTF-8?q?=E5=A4=B9=E5=85=B7core=E4=B8=8E=E4=B8=83=E9=94=AE=E9=98=B2null?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E9=94=99=E8=AF=AF=E4=B8=8Esegorder=E6=B1=A1?= =?UTF-8?q?=E6=9F=93/mult=5Foor=5Fwarning=E8=A3=85=E8=BD=BD=E9=80=9A?= =?UTF-8?q?=E9=81=93=E5=B7=B2=E6=8B=92=E8=BD=BD=E8=A1=A8=E8=BF=B0=E6=AD=A3?= =?UTF-8?q?=E5=90=8D/=E6=B3=A8=E5=85=A5=E6=9C=BA=E5=88=B6=E9=92=89?= =?UTF-8?q?=E6=AD=BB/README=E9=94=9A:230=E2=86=92:231/atk=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE{1,3}/G=E9=81=93=E5=87=BD=E6=95=B0=E4=BD=93=E6=B3=A8?= =?UTF-8?q?=E8=AE=B0/=E5=A4=8D=E6=A0=B8=E5=87=AD=E6=8D=AE=E8=8A=82?= =?UTF-8?q?=E8=87=AA=E8=BA=AB;=203=E8=87=AA=E5=88=A4=E4=B8=8D=E6=94=B9:=20?= =?UTF-8?q?V3=E8=A7=82=E6=B5=8B=E7=AD=89=E4=BB=B7/F1=E4=B8=80=E8=A1=8C?= =?UTF-8?q?=E5=81=8F=E5=B7=AE/=E5=8E=86=E5=8F=B2=E6=B3=A8=E8=AE=B0?= =?UTF-8?q?=E6=BC=82=E7=A7=BB)=E3=80=82=E8=83=BD=E5=8A=9B=E8=A1=8C?= =?UTF-8?q?=E5=BD=93=E5=9C=BA=E5=85=A5=E8=A1=A8(README:207=E8=B7=A8?= =?UTF-8?q?=E8=A1=A8=E9=87=8F=E7=BA=A7=E6=A0=A1=E9=AA=8C,=E8=AE=A1?= =?UTF-8?q?=E5=88=92=E7=94=A8=E4=BE=8B=E5=8F=8C=E9=80=9A=E9=81=93=E5=87=AD?= =?UTF-8?q?=E5=8D=A1=E9=94=9A=E5=AE=9A);=20=E5=BE=85=E5=8A=9EQQ-12?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=8E=A8=E8=BF=9B=E6=96=87=E6=A1=A3=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=B7=B2=E9=97=AD=E5=90=88=EF=BC=8B=E5=B7=B2=E5=86=99?= =?UTF-8?q?=E5=8D=A1=E3=80=82=E5=87=AD=E6=8D=AE:=20=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E5=9F=9F=E9=97=B8=E3=80=90=E9=AA=8C=E6=94=B6=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E3=80=91=E6=97=A0=E6=96=B0=E5=A2=9E=E7=BA=A2=E2=80=94=E2=80=94?= =?UTF-8?q?=E6=B5=81=E6=B0=B4=E7=BA=BF=E9=97=B8PASS(36=E6=9D=A1=E7=9B=AE/5?= =?UTF-8?q?7=E6=95=B0=E6=8D=AE=E8=A1=8C/4=E9=93=BE/5=E5=8D=A1=E5=85=A8?= =?UTF-8?q?=E8=BF=87=E5=90=ABC6=E5=A4=8D=E6=A0=B8=E8=AE=B0=E5=BD=95)+?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=E5=AE=A1=E8=AE=A1(25=E7=AF=87/124=E8=A1=8C/9?= =?UTF-8?q?0=E5=A5=97=E4=BB=B6/=E9=93=BE=E6=96=AD0/=E7=BA=A20)=E3=80=82?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=BD=92=E8=BF=AD=E4=BB=A3=E6=AE=B5(/iter?= =?UTF-8?q?=E5=8F=91=E4=BB=A4),=E7=BC=96=E6=8E=92=E5=BE=85=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=82=B9=E5=90=8D=E8=BF=AD=E4=BB=A3=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/tests/README.md | 1 + reports/需求卡片-跨表量级护栏批-2026-11-09.md | 174 ++++++++++++++++++ 待办清单.md | 4 +- 3 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 reports/需求卡片-跨表量级护栏批-2026-11-09.md diff --git a/game/tests/README.md b/game/tests/README.md index b5eb8dee..3a5b4e49 100644 --- a/game/tests/README.md +++ b/game/tests/README.md @@ -204,6 +204,7 @@ tests/ | 状态实例按个体归属:个体隔离/全体授予逐体发/死亡即清/同体合并照旧 | 增益状态 | `StatusContainer.apply_effect()`(个体键)/`purge_owner()` | `system_contracts_test.gd:_test_status_individual_isolation`;`system_contracts_test.gd:_test_status_grant_all_per_unit`;`system_contracts_test.gd:_test_status_death_clears`;`system_contracts_test.gd:_test_status_merge_per_unit` | | 敌方增益自体落点与乘区池按个体 | 敌人系统×战斗结算×增益状态 | 技能兑付编排链/`DamageController.clamped_pool()` | `round_flow_skill_pool_test.gd:_smoke_enemy_buff_targets_self`;`damage_controller_test.gd:_test_pool_consumption_per_unit`;`damage_controller_test.gd:_test_defender_ac_per_unit`;`battle_narrator_test.gd:_test_snapshot_effects_per_unit` | | 敌人技能池跨表链接校验 | 数据配置×敌人系统 | `ConfigDbCrossValidator.validate_skill_pool_links()` | `config_db_cross_validator_test.gd:_test_all_links_valid`;`config_db_cross_validator_test.gd:_test_dangling_skill_id`;`config_db_cross_validator_test.gd:_test_cast_side_mismatch` | +| 跨表量级校验 | 数据配置×敌人系统×难度曲线与Boss | `ConfigDbCrossValidator.cross_validate()`/`ConfigDB.load_tables()` | `config_db_cross_validator_test.gd:_test_magnitude_over_limit`(计划——需求卡片「跨表量级护栏批」2026-11-09 锚定);`cross_magnitude_fatal_test.gd:_init`(计划——同卡锚定) | | 精英行:池继承合并、加载期校验与暂不接线 | 敌人系统×数据配置 | `ConfigDB.load_tables()`/`EnemyTable.validate()`/`EnemyTable.effective_pool()`/`ConfigDbCrossValidator.validate_skill_pool_links()`/`EnemyTable.resolve_rowset()` | `elite_row_test.gd:_test_elite_validation_rejects`;`elite_row_test.gd:_test_effective_pool_merge`;`elite_row_test.gd:_test_base_pool_change_propagates`;`elite_row_test.gd:_test_merged_pool_composition`;`elite_row_test.gd:_test_elite_unreachable_by_encounter`;`elite_row_test.gd:_test_production_goblin_elite` | **覆盖域表**(`design/gdd/systems/` 逐篇对照——状态三档:已覆盖/部分覆盖/未覆盖;部分与未覆盖行的缺口指待办清单条目,覆盖面提升时同批改本表): diff --git a/reports/需求卡片-跨表量级护栏批-2026-11-09.md b/reports/需求卡片-跨表量级护栏批-2026-11-09.md new file mode 100644 index 00000000..e6920aaf --- /dev/null +++ b/reports/需求卡片-跨表量级护栏批-2026-11-09.md @@ -0,0 +1,174 @@ +# 需求卡片——跨表量级护栏批 + +> 来源:待办清单「未决问题迁移——零伤害死局跨字段跨表护栏落点」条目(唯一事实源:design/gdd/systems/表现与支撑/数据配置.md v1.4 §核心规则「跨表量级校验」节,:122-134) +> 验收档:高(数值表结构校验——失败代价随加载期放行传播进全部战斗) +> 估时:0.5–1 个工作日(中值 0.75);超 1 日软盒预挂=T1 夹具注入锚点失效时停机呈报,不扩面自救 + +## 1. 目标与完成定义 + +在加载期跨表校验通道新增一条量级检查:敌人表每行攻击上界 × 难度表全行攻击乘数最大值,不得超过主角表生命上限字段的取值域上界;越界=加载期校验错误,致命中止。只查取值域之间的量级相容性,不查玩法平衡。 + +完成定义: +- V1–V6 验收行全部在真实跑批中执行并通过(单元经 cross_validate 真实通道,致命经 ConfigDB.load_tables 正式通道独立进程退出码 1)。 +- 生产表零误报:现行敌人表 battle/boss 行 atk∈{1,3}(atk_max≤4)、elite 行 atk=2(atk_max=3)、难度表空表,加载诊断零新增 error。 +- 代码域闸全绿;独立验收审计(高档)通过;reports/ 两份产出物落齐。 + +## 2. 设计事实源 + +design/gdd/systems/表现与支撑/数据配置.md v1.4: +- :122-134 「跨表量级校验:组合数值的上界不得突破目标字段的取值域」节(组合式、上界、越界处置、空表跳过、Boss 不另查、域值归 schemas)。 +- :104 fail-fast 错误类别表(跨表量级越界在列,加载期收集后致命中止)。 +- :213-215 验收标准(夹具类别全覆盖+专条判据+致命真的会死)。 + +会话裁决沿革查 git 提交 6bfd8009(案A域级判据,用户裁「最底层防护不防玩法内容」)。 + +## 3. 现状事实(开工自行复核) + +- F1 跨表校验器七项检查全是引用完整性/池构成类,无量级检查:game/core/config_db_cross_validator.gd:17-24(①–⑦调用链);cross_validate 入口 :8,开头 :12-13 对 status_effects/reward/settlement 缺表早退(单表校验已报错不连锁)。 +- F2 装载通道:game/core/config_db.gd:102-128 load_tables——逐表 validate 后经 :120 _cross_validate(loaded),:121-124 error 计数 >0 且非 collect_only 即返回 false(游戏通道致命);_cross_validate 门面 :164-165 委托 _validator.cross_validate(loaded, push_diag)。 +- F3 英雄表域:game/data/schemas/hero_table.gd:16 max_hp 域 [1,999] 以字面量写在 validate 内,无域上界常量。 +- F4 敌人表攻击字段:game/data/schemas/enemy_table.gd:114-116 atk 基值域 [0,999];:122-135 atk_min/atk_max 可省略配对、区间中点恒等锚。行类字段 row_kind(battle/boss/elite,生产表 game/data/tables/enemy.tres:9/:157/:211 实证)。 +- F5 难度表:game/data/schemas/difficulty_table.gd:9-10 MULT_MIN=0.1/MULT_MAX=10.0 常量;:26-29 乘数越域产 mult_oor_warning 类别条目;config_db.gd:117-118 将 validate() 条目一律按 error 级外发,故经正式通道越域乘数已拒载,「告警」仅类别名口径;生产表 game/data/tables/difficulty.tres rows=[] 空表。头注 :3「组合事故不作配置事故拒载」——本批把量级组合这一种升格为拒载,头注随批改写(行为载体注释,非 design/ 文档)。 +- F6 生产表安全余量:enemy.tres battle/boss 行 atk∈{1,3}(atk_max≤4,:16/:309 等)、elite 行 atk=2/atk_max=3(:217-219)、hero.tres:7 max_hp=26——新检查对生产表恒过(空难度表跳过)。 +- F7 单测先例:game/tests/unit/core/config_db_cross_validator_test.gd:49-87——夹具直构表对象、ValidatorScript.new() 直调、Kit.check 断言、每函数带「判据出处」注记;套件登记 game/tests/run_all.gd:259 expect=0。 +- F8 致命类先例:game/tests/unit/data_config/reward_dangling_treasure_test.gd:39-56——Kit.copy_tables 复制生产表到 user:// 夹具目录、文本注入违规、ConfigDBScript.new().load_tables(BAD_DIR,false) 正式通道、退出码协议 1=正确拒绝/2=放行回归;登记形态 run_all.gd:178 expect=1 negative=true。 +- F9 能力清单:game/tests/README.md:206 有「敌人技能池跨表链接校验」行(本批 :207 新增「跨表量级校验」行);:231 数据配置覆盖矩阵行不含跨表量级校验。 +- F10 gdstyle 基线:tools/gdstyle_baseline.txt 无 config_db_cross_validator.gd 与 hero_table.gd 键(均在默认阈值内);校验器现行 func 总数 14(公开 2:cross_validate/validate_skill_pool_links)。 + +## 4. 设计契约(违反即返工,🔴 触碰=L3 停机呈报) + +- 🔴 C1 检查只挂 ConfigDbCrossValidator 跨表通道(经 config_db.gd:120 既有调用链生效);禁另设校验入口、禁在 schema 单表 validate 内做跨表读取。 +- 🔴 C2 上界取值单点:生命上限域上界常量落 hero_table.gd(schema 是域的唯一声明处),校验器引用该常量;禁在校验器或测试内第二处定义 999 这一域值(测试断言引用同一常量)。 +- 🔴 C3 只查域相容不查玩法平衡:判据不得引用 max_hp 现行值(26)、不得含任何平衡系数;不得在运行期新增任何行为。 +- 🔴 C4 Core 零 UI 依赖、无新增随机源、无数值字面量入玩法代码(域常量属 schema 声明面,不属玩法数值)。 +- 🔴 C5 禁删既有断言、禁放宽阈值;本卡测试削弱申报=无。 + +## 5. 范围边界 + +做:校验器第⑧项+域上界常量+单元五函数+致命入口测试一件+套件登记+能力表增行。 +不做(明示去向): +- 运行期战斗轮数异常遥测——旧体系备选案,未裁启用,不属本卡;如日后要做另行登记。 +- 玩法级红线(案B,对比基线现行值×K)——用户已裁淘汰(2026-11-09 会话:最底层防护不防玩法内容)。 +- difficulty_table.gd 的 mult_oor_warning 行为不动(单乘数越域经装载通道已拒载、类别名不变、使用时 clamp;本批只升格「组合量级」这一种)。 +- 文档面改动一律走反哺点(见第 6 节),实现批禁写 design/ 与根规则文件。 + +## 6. 关联文档同步面 + +| 文档 | 关联点 | 同步义务 | +|---|---|---| +| design/gdd/systems/表现与支撑/数据配置.md v1.4 | 本卡实现其 :122-134 条款,条文无需改动 | 无同步义务(实现核对条文一致即可) | +| game/tests/README.md 能力表 | 新增能力行「跨表量级校验」(写卡段同批已增 :207,见本批提交);:231 数据配置覆盖矩阵行补「跨表量级校验」面 | 覆盖矩阵行更新列反哺点,由文档批落 | +| design/gdd/systems/冒险循环/难度曲线与Boss.md | 无条文冲突(乘数表空表零行为句与本检查空表跳过一致) | 无关联文档改动 | + +## 7. 文件结构图(卡前定分解) + +| 文件 | 职责 |新增/复用| 行为改动→验收行 | +|---|---|---|---| +| game/data/schemas/hero_table.gd | 生命上限域上界常量 MAX_HP_DOMAIN_MAX=999+validate 引用 | 复用既有(扩常量) | 是→V1/V2(域值单点) | +| game/core/config_db_cross_validator.gd | 第⑧项 validate_attack_magnitude+接线 cross_validate | 复用既有(扩展) | 是→V1–V5 | +| game/core/config_db.gd | 零改动(:120 调用链已覆盖新检查) | 复用既有 | 否 | +| game/data/schemas/difficulty_table.gd | 头注 :3 改写(量级组合升格拒载);MULT_MIN/MAX 常量被引用,零逻辑改动 | 复用既有 | 否(注释面) | +| game/tests/unit/core/config_db_cross_validator_test.gd | 新增五测试函数(V1–V5 单元面) | 复用既有(扩展) | 测试件 | +| game/tests/unit/data_config/cross_magnitude_fatal_test.gd | 致命入口测试(V6) | 新增(先例=F8,为什么新增见预检节) | 测试件 | +| game/tests/run_all.gd | 登记新致命套件 expect=1 negative=true | 复用既有(增行) | 否 | +| game/tests/README.md | 能力表增行(写卡段落,非实现批) | 复用既有 | 否 | + +## 8. 任务卡 T0..Tn + +### T0 域常量与校验器第⑧项(估时 0.25–0.5 日) + +取用:无(首卡)。产出:`HeroTable.MAX_HP_DOMAIN_MAX: int`、`ConfigDbCrossValidator.validate_attack_magnitude(loaded: Dictionary, push_diag: Callable) -> void`(T1/T2 引用逐字一致)。 + +- [ ] S13 读数:直跑 gdstyle 对 config_db_cross_validator.gd 与 hero_table.gd 记改前读数(两文件基线无键=默认阈值内;预期改后公开方法 2→3、func 14→≤17,仍阈值内,基线零增键)。 +- [ ] hero_table.gd 增常量 `const MAX_HP_DOMAIN_MAX := 999`,:16 域检查上界改引常量(语义不变);跑 hero 相关单测最窄确认(config_db_test.gd 全套件直跑,命令见验证闸节)。 +- [ ] 校验器新增 `func validate_attack_magnitude(loaded: Dictionary, push_diag: Callable) -> void`:取 enemy/difficulty/hero 三表,任一 null 早退(单表已报错不连锁,同 :12-13 先例);难度表 rows 为空早退(数据配置.md:132);乘数上界=全行 atk_mult(缺省 1.0)逐个钳制到 DifficultyTable.MULT_MIN/MULT_MAX 后取最大;逐敌行——row_kind="boss" 跳过(:132),攻击上界=有 atk_max 取 atk_max 否则 atk(:130);乘积 > HeroTable.MAX_HP_DOMAIN_MAX 即 push_diag.call("error", "cross_magnitude", 消息含 enemy_id/行键、乘积值、域上界)。 +- [ ] cross_validate 在 ⑦(:24)后接线 `_cv_attack_magnitude` 私有包装(缺表早退语义与 ⑤⑥⑦ 同款),第⑧项注释编号沿用既有圈码形态。 +- [ ] 单测五函数落地(签名与断言见验证闸 V1–V5),经 cross_validate 真实通道驱动(夹具 loaded 字典含三被测表+status_effects/reward 用 new() 空行+settlement 夹具=SettlementTable.new() 且 core=SettlementCoreTable.new(),source_label_map 填齐七必需键 safe_cell/seal_hit/mine_hit/clear_reward/hero_attack/enemy_action/seal_miss(值任意)、effect_pool_map 留空——否则②读 null core 脚本错误、③报 7 条 segorder_violation 污染零错断言,config_db_cross_validator.gd:68/:74-78;此三表过 :12-13 早退门);难度夹具行键=level_index/node_depth/hp_mult/atk_mult(difficulty_table.gd:7 声明面),英雄夹具=HeroTable.new()(检查只读域常量不读现行值);每函数带「判据出处」注记指向数据配置.md 行锚。 +- [ ] 直跑该单测套件绿(命令见验证闸节),读数写进本步提交。 +- [ ] difficulty_table.gd 头注 :3 改写:单乘数越域经装载通道按错误拒载(mult_oor_warning 类别)、使用时 clamp;敌攻击×乘数量级组合经跨表校验拒载(指向数据配置 GDD 节名,不写代码路径)。 + +### T1 致命入口测试与套件登记(估时 0.25–0.5 日) + +取用:T0 的 `validate_attack_magnitude`(经 load_tables 间接消费,无直调)。产出:`cross_magnitude_fatal_test.gd`(run_all.gd 登记行)。 + +- [ ] 新建 game/tests/unit/data_config/cross_magnitude_fatal_test.gd,形态照 F8 先例:Kit.copy_tables("res://data/tables", "user://cross_magnitude_fixture") → 双表注入:enemy.tres 首行三改 `"atk": 1`→`"atk": 500`、`"atk_min": 0`→`"atk_min": 500`、`"atk_max": 2`→`"atk_max": 500`(首个 goblin battle 行锚 :16-18;该行带攻击区间,中点恒等锚 enemy_table.gd:134 要求 atk=(min+max)/2——只改 atk 则单表中点锚报错且跨表检查读上界=atk_max=2 不触发,三改保单表自洽+跨表上界 500)。注入取首现位置:find 定位+substr 拼接(照 F8 先例 substr 形态,reward_dangling_treasure_test.gd:27-30);禁 String.replace 全量替换——同值串遍布全表,且 :334-336/:362-364 行 atk_min=1 会被打破中点锚。difficulty.tres `rows = []` 改 `rows = [{ "level_index": 1, "node_depth": 0, "hp_mult": 1.0, "atk_mult": 3.0 }]`(500×3=1500>999 必触发)。 +- [ ] 断言协议:ConfigDBScript.new().load_tables(BAD_DIR,false) 返回 false 且 diagnostics 含 category="cross_magnitude" → quit(1);放行或无该诊断 → quit(2);夹具准备失败 → quit(2)。_init 函数体内首行写 `# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:215 …` 注记(照 F8 :40 形态;G 道按函数扫,文件头注不计,capability_audit.py:347-410);文件头注另写明退出码协议。 +- [ ] run_all.gd 致命类区(:178 邻域)增登记行 `{"path": "res://tests/unit/data_config/cross_magnitude_fatal_test.gd", "expect": 1, "negative": true}`。 +- [ ] 孤立直跑新套件确认退出码 1,再跑单元测试全套件确认登记生效且既有套件零回归,读数写进本步提交。 + +### T2 产出物落位卡(估时含于上两卡,批末执行) + +- [ ] 代码域闸全绿(按 tools/run_all_gates.sh 本批改动域选档)+改前改后 S13 读数对拍(只降不升)。 +- [ ] reports/iter-实现报告-<日期>.md 写齐:各卡状态+实机目检总清单(本批无玩家可见面,写明「无目检项」)+遗留读数义务+实现决定记录。 +- [ ] reports/iter-反哺点-<日期>.md:第 6 节覆盖矩阵行更新一条落点写明。 +- [ ] 独立验收审计(高档,test-conventions §8.7 梯度):没参与实现的会话或子代理执行,报告 reports/iter-验收审计-<日期>.md;未过不得合并。 + +## 9. 验证闸(改动—验收对照表) + +| # | 需求点(判据出处行锚) | 改动 | 验收测试(名称+落点+尾缀) | 层级 | 真实入口 | 判据绑定面 | 能力行 | +|---|---|---|---|---|---|---|---| +| V1 | 越界组合加载期报错(design/gdd/systems/表现与支撑/数据配置.md:130) | 校验器第⑧项 | _test_magnitude_over_limit报cross_magnitude(夹具敌行 atk=500×难度行 atk_mult=3.0→1500>999;config_db_cross_validator_test.gd,_test_ 尾缀) | 单元 | ConfigDbCrossValidator.cross_validate(loaded,push_diag) | push_diag 收到 severity=error ∧ category="cross_magnitude" ∧ 消息含越界敌行键 | 新增:跨表量级校验 | +| V2 | 合法组合与边界等值零误报(design/gdd/systems/表现与支撑/数据配置.md:214) | 同上 | _test_magnitude_legal_and_boundary_zero_error(三组:999×1.0 边界等值/100×2.0 域下/boss 行 atk=999×mult 3.0 豁免) | 单元 | 同 V1 | 三组各零 error;boss 组难度行 atk_mult=3.0 非空(若不跳过 boss 则 2997>999 必报——防空表跳过使豁免断言空转) | 新增:跨表量级校验 | +| V3 | 空难度表跳过(design/gdd/systems/表现与支撑/数据配置.md:132) | 同上 | _test_magnitude_empty_difficulty_skipped | 单元 | 同 V1 | 敌 atk=999+难度 rows=[] 零 error | 新增:跨表量级校验 | +| V4 | 区间取上限(design/gdd/systems/表现与支撑/数据配置.md:130) | 同上 | _test_magnitude_range_uses_atk_max | 单元 | 同 V1 | atk=350/atk_min=100/atk_max=600+乘数 2.0 → 报(600×2=1200>999);atk=250/atk_min=100/atk_max=400 → 零错(400×2=800);两组 atk 均满足区间中点恒等锚(enemy_table.gd:134) | 新增:跨表量级校验 | +| V5 | 越域乘数按域边界值计(design/gdd/systems/表现与支撑/数据配置.md:130) | 同上 | _test_magnitude_mult_clamped_to_domain | 单元 | 同 V1 | atk=100+atk_mult=50.0(钳制 10.0)→ 报(100×10=1000>999);atk=99+同乘数 → 零错(990) | 新增:跨表量级校验 | +| V6 | 致命真的会死(design/gdd/systems/表现与支撑/数据配置.md:215+:104) | 第⑧项经装载通道 | cross_magnitude_fatal_test.gd:_init(独立进程,expect=1 negative=true) | 单元(致命协议) | ConfigDB.load_tables(BAD_DIR,false) 正式通道 | 进程退出码 1 ∧ load_tables 返回 false ∧ diagnostics 含 cross_magnitude | 新增:跨表量级校验 | + +- 验证命令:单元套件直跑 `D:\code\godot\Godot_v4.7.2-stable_win64_console.exe --headless --path game --script res://tests/unit/core/config_db_cross_validator_test.gd`;致命套件同形换路径;全套件 `--script res://tests/run_all.gd`。 +- 测试方式两分法:V1–V6 全归调试夹具直构/夹具注入(能力验证);本批无玩家可见面,用户目检项=无。 +- 回归措辞:T 段出口跑一次覆盖改动面的套件;修复只做出红最小单元的最窄确认;新增测试先行孤立验证再并入全套。 +- 测试削弱申报:无(不删不改既有断言)。 +- 独立验收审计:入口=T2 第三步;报告 reports/iter-验收审计-<日期>.md;高档梯度(test-conventions §8.7)。 + +## 10. 异常分级 + +- L1 自救:夹具注入锚点失配一次重试(换次处 battle 行块,三改随该行实际区间值对齐中点锚)。 +- L2 记录继续:导入缓存类在册环境坑按坑册处置。 +- L3 停机写报告等用户:🔴 契约触碰;机检预算互斥=上游缺陷停卡退回写卡段;夹具双注入仍无法触发(生产表面貌漂移)停卡呈报。 + +## 11. 代拍板白名单 + +- 错误消息文案措辞(须含行键/乘积/域上界三要素)。 +- 夹具 user:// 目录名与私有包装函数名(_cv_attack_magnitude 形态)。 +- 超清单事项记实现报告「实现决定记录」节。 + +## 12. 待裁点 + +零待裁点,开工门=U0。(落点/判据/处置三裁已在 2026-11-09 会话闭合,git 6bfd8009 可考。) + +## 13. 落位与可复用性预检 + +| 新增件 | 复用面核查 | 唯一面 | 分层与交互 | +|---|---|---|---| +| validate_attack_magnitude(校验器新公开方法) | grep 全库无量级组合检查(跨表校验器七项全引用/池类,F1);量级检查职责归跨表校验器唯一宿主,不在 schema 单表层做跨表读取 | 检查逻辑只此一处;域上界常量只在 hero_table.gd | ConfigDB.load_tables→_cross_validate→cross_validate→第⑧项;push_diag 外发诊断,Core 零 UI | +| MAX_HP_DOMAIN_MAX(hero_table.gd 常量) | 现行域上界 999 只存在于 validate 字面量(F3),提常量即收编单点,非第二处定义 | validate 与校验器同引一常量 | schema 声明面,供校验器只读 | +| cross_magnitude_fatal_test.gd(新文件) | 既有致命套件各钉一类违规(reward_dangling_treasure/counter_prefix 等,F8/F9),无「量级组合」套件可扩展;致命协议要求独立进程独立文件(run_all.gd:15 协议注) | 退出码协议与 Kit.copy_tables 复用 test_kit,不复制其实现 | 经 ConfigDB.load_tables 正式通道,与生产加载同路径 | +| 单测五函数 | 扩展既有 config_db_cross_validator_test.gd(F7),不另立新文件 | 夹具直构形态沿用该件 _skill/_enemy 先例,新增 _difficulty/_hero 夹具协函数同文件内 | 经 cross_validate 真实通道 | + +## 14. 实现规范预算 + +- config_db_cross_validator.gd:无新文件;公开方法 2→3(≤20);类变量 0 新增(≤15);新函数 validate_attack_magnitude 分支预算 ≤8(缺表早退/空表早退/boss 跳过/区间取值/越界判定,实装超 8 即拆私有协函数)、返回 ≤6;func 总数 14→≤17。基线无键(F10),改后仍阈值内=零增键。 +- hero_table.gd:增一常量,validate 逻辑分支不变;基线无键,零增键。 +- 新文件 cross_magnitude_fatal_test.gd:公开方法 ≤1(_init)、类变量 ≤6(常量preload与目录名)、分支 ≤8(照 F8 先例四出口)——全在默认阈值内,无指标例外申报。 +- 存量触面一查:T0 S1 步骤记改前读数,S13 键较登记值只降不升(本批无基线键变动预期)。 + +## 15. 拆分边界纪律 + +本批非拆分/重构类(扩展既有件+一新测试件),无拆出单元;第 13/14 节条款照列备查:禁为机检文本保留无效成员;机检键与卡片契约互斥=停卡呈报。 + +## 16. 复核记录 + +复核形态:第 1 轮=未参与本卡撰写的只读子代理对抗复核(2026-11-09,审点按 req-card 技能 grilling 门全清单:三问/对照表两端/真实入口/绑定面、夹具钉值与空转、落位预检×结构图互指、预算实数、判据出处行锚逐行实读、引擎技术面三查〔godot-master hub NEVER/Gotchas/预算表已加载,领域 reference 未加载——Resource 面为 F8 先例同形〕、T 卡粒度/接口逐字/禁行句式、范围边界与两道机检相容)。复核前作者已跑自审七查,就地修复已并入卡正文:V1/V2/V4 夹具取值钉死、V2 boss 组难度非空防豁免空转、V4 夹具满足中点恒等锚、T1 首行三改(只改 atk 则上界读 atk_max=2 不触发)、V6/T1 判据锚 :214→:215、F6 生产表 atk 枚举修正。复核者总结论:无待裁类、无退回上游类;七条补写全部回填后可进入提交流程。复核凭据=本节自身,不另设报告文件(2026-11-06 用户裁)。 + +| 轮次 | 复核者身份 | 发现 | 去向 | 处置结果 | +|---|---|---|---|---| +| 1 | 只读子代理(未参与本卡撰写) | T0 S5 settlement「空表对象」按字面直构:core=null 致②null 访问脚本错误;core 补齐后③缺七必需键报 7 条 segorder_violation 污染零错断言 | 补写 | T0 S5 已改写:settlement 夹具 core=SettlementCoreTable.new()、source_label_map 填齐七键、effect_pool_map 留空(依据 config_db_cross_validator.gd:68/:74-78、settlement_table.gd:10、settlement_core_table.gd:8) | +| 1 | 只读子代理(未参与本卡撰写) | F5/§5/T0 S7「乘数越域仅告警」表述失准——装载通道把 validate() 条目一律按 error 级外发,越域乘数已拒载 | 补写 | 三处已改写为「经装载通道按错误拒载、类别名 mult_oor_warning 不变、使用时 clamp」(依据 config_db.gd:117-118/:121-124);V5 走 cross_validate 直调不受影响 | +| 1 | 只读子代理(未参与本卡撰写) | T1 注入机制未钉死:String.replace 全量替换会打破他行中点锚(:334-336/:362-364 行 atk_min=1) | 补写 | T1 S1 已增「首现位置 find+substr 拼接、禁 String.replace 全量替换」(依据 enemy.tres:334-336/:362-364 实读;F8 先例 reward_dangling_treasure_test.gd:27-30 substr 形态) | +| 1 | 只读子代理(未参与本卡撰写) | F9/§6 覆盖矩阵行锚 :230 失位——本批 :207 插入新能力行后数据配置行实为 :231 | 补写 | 两处已改 :231(README 实读核位) | +| 1 | 只读子代理(未参与本卡撰写) | §1/F6「battle/boss 行 atk=1」枚举不全——后段行 atk=3/atk_max=4 | 补写 | 两处已改 atk∈{1,3}(atk_max≤4)(依据 enemy.tres:309/:445/:505 等实读);零误报结论不变(空难度表跳过) | +| 1 | 只读子代理(未参与本卡撰写) | T1 S2 判据出处只写文件头注不计——G 道按函数体扫描,_init 含 push_error 属验证函数 | 补写 | 已改「_init 函数体内首行写判据出处注记、文件头注另写退出码协议」(依据 capability_audit.py:347-410;F8 :40 先例形态) | +| 1 | 只读子代理(未参与本卡撰写) | §16 占位句「节末申报复核报告落盘路径」为过期指令(2026-11-06 已裁不另设报告文件) | 补写 | 回填本节时已删该句;凭据=本节自身(req-card 必备结构第 17 节;pipeline_gate.py check_review :650-687 不查报告文件) | +| 1 | 只读子代理(未参与本卡撰写) | V3 零错判据不能区分「空表跳过」与「缺省乘数 1.0」两种实现 | 自判 | 不改:敌 atk 域 [0,999]×1.0 恒 ≤999,两实现可观测面等价;V3 绑可观测契约仍抓空最大值崩溃与错误缺省 >1(依据 enemy_table.gd:115;req-card 判据绑定面口径只要求绑可观测提交面) | +| 1 | 只读子代理(未参与本卡撰写) | F1 锚 :17-24 含一行 helper 调用(①–⑦链实在 :18-24) | 自判 | 不改::17 为 _effect_ids_of 调用,范围覆盖调用链、内容匹配,一行偏差不影响核对(config_db_cross_validator.gd:17-24 实读) | +| 1 | 只读子代理(未参与本卡撰写) | 既有单测件判据注记锚指 数据配置.md:195 已漂移(历史遗留,非本批改动面) | 自判 | 不改:本批只增函数不触既有注记;G 道只查行号越界不查内容(capability_audit.py:401-403);日后触及该件另登记 | \ No newline at end of file diff --git a/待办清单.md b/待办清单.md index cd3574e9..dd9976b8 100644 --- a/待办清单.md +++ b/待办清单.md @@ -25,9 +25,9 @@ #### 未决问题迁移——零伤害死局跨字段跨表护栏落点(2026-11-07 登记,来源=批次移交) -**实况**:原 architecture.md「未决问题」QQ-12(git 历史可考,架构收窄批迁出)。设计定稿:design/gdd/systems/表现与支撑/数据配置.md v1.4(2026-11-09,跨表量级校验节——域级判据,加载期致命)。 +**实况**:原 architecture.md「未决问题」QQ-12(git 历史可考,架构收窄批迁出)。设计定稿:design/gdd/systems/表现与支撑/数据配置.md v1.4(2026-11-09,跨表量级校验节——域级判据,加载期致命)。需求卡片:reports/需求卡片-跨表量级护栏批-2026-11-09.md(复核记录节在卡,对抗复核一轮 10 发现全处置:7 补写回填+3 自判不改)。 **改动面**:文档+游戏代码 -**状态**:文档设计已闭合 +**状态**:文档设计已闭合+已写卡 #### 未决问题迁移——A1 EC5 运行期熔断(2026-11-07 登记,来源=批次移交)