docs(提案 v2): 测试术语与层级重构方案定稿——吸收独立审查 12 条修正(技能副本指针实测更正/09 存量红处置/测量件去向/按条变异回归现行§6/引用普查必改点在案/计数标口径);裁决全闭合:特批免卡直改 game/、按条变异、验证集清单机制(机器生成+只剪切禁改写+出口逐条 diff+常驻参照);待裁点清零,批 A 0.5–1 天、批 B 约 1.5–2 周,待用户安排开工

This commit is contained in:
DKChan committed 2026-10-22 20:25:13 +08:00
1 parent 66df776fae
commit fe9d2c11b0
1 file changed
+88 -58
@@ -1,30 +1,34 @@
# 测试术语与层级重构方案
# 测试术语与层级重构方案(v2)
> 状态:提案(设计讨论段过程稿)· 2026-10-22 · 用户已裁 Q1–Q5,待安排执行
> 死期:结论落进权威文档后即删(吸收即死,doc-conventions §11;删它不需要再裁)
> 本文档是后续改动的合同与账本骨架;终态规则只进权威文档,本文只记「怎么改过去」
> 状态:提案 v2 · 2026-10-22 · 独立审查 12 条修正已吸收,用户裁决全部闭合,**待裁点清零**,待用户安排批 A 开工
> 生命周期:本文件的批计划部分批末退役(吸收即死);§五验证集清单是常驻参照物,不随批死
> v1→v2 沿革查 git log,正文不设变更记录节
## 一、背景与问题(证据附行号)
## 一、背景与问题(证据附行号,计数标口径与日期)
**① 名实分离**:`game/tests/README.md:137–148` 术语表定义冒烟=秒级存活检查(能否启动、能否加载表、能否进主屏),但名叫 smoke 的载体 `tools/run_smoke.py` 跑的是 `res://smoke/smoke_all.gd`——7151 行、140 个函数、1211 项检查、90–110 秒(2026-10-22 实测)。它断言的是逻辑正确性:随机数流具体数值(`derive_at(0)==8672514112661456564`,:53–60)、格子尺寸公式(:1691)、奖励恒等式(`_smoke_reward_identity_unit`,:1977)、封印耗尽行动点进第 2 轮(:2027)。README:146–148 靠一段「别被字面骗了」的警告维持名实分离——需要警告才能防误读的命名,就是失败的命名。
**① 名实分离**:`game/tests/README.md:137–148` 术语表定义冒烟=秒级存活检查,但名叫 smoke 的载体 `tools/run_smoke.py` 跑的是 `res://smoke/smoke_all.gd`——7151 行、140 函数;检查计数:**运行时 1211**(2026-10-22 跑批读数)/**静态 check( 调用点 1067**(2026-10-22 实测),单次 90–110 秒。断言内容举例:随机数流具体数值(`derive_at(0)==8672514112661456564`,:53–60)、格子尺寸公式(:1691)、奖励恒等式(`_smoke_reward_identity_unit`,:1977)、封印耗尽行动点进第 2 轮(:2027)。README:146–148 靠一段警告维持名实分离——需要警告才能防误读的命名,就是失败的命名。
**② 频率三处冲突**:迭代技能写每轮跑 `run_smoke.py`+`probe_gate.sh`;`roadmap.md` 批次 loop 规范第 4 条写每轮跑 `--quick`;`process-conventions.md` §3 第 5 条写 T0 开工三查含冒烟全绿数目。而 `--quick` 档内含 01(冒烟全量)与 02(单元)两道分钟级闸——「每轮轻闸」实际是每轮全量。一次 2 卡×3 轮的迭代,分钟级套件要跑 6–8 次。
**② 频率三处冲突**:迭代技能写每轮跑 `run_smoke.py`+`probe_gate.sh`;`roadmap.md` 批次 loop 规范第 4 条写每轮跑 `--quick`;`process-conventions.md` §3 第 5 条写开工三查。而 `--quick` 内含 01(冒烟全量)与 02(单元)两道分钟级闸——「每轮轻闸」实际是每轮全量。一次 2 卡×3 轮迭代要跑 6–8 次分钟级套件。
**③ 金字塔倒挂**:按标准测试层级,单元测试应最多(每个函数细节有对应单测),系统测试按功能面组织、相对最少。现状:单元测试 39 套 367 项,系统级杂烩 1211 项,本该承接跨系统用例的 `tests/integration/` 只有 1 件。成因是历史:`run_smoke.py` 是历届迭代每轮必跑的闸,哪个文件被跑得最勤,验收断言就往哪个文件堆;`unit/` 目录成型晚,早期断言一直没搬。证据在函数名里:`_smoke_reward_identity_unit`(名字自带 unit)、`_smoke_layout_cell_formula`(纯公式验算)、`_smoke_adventure_table`(表结构校验)。
**③ 金字塔倒挂**:标准层级应单元最多、系统测试少。现状:单元测试 40 条 manifest(39 单元+1 集成;检查数:运行时 367/静态 322)对 smoke_all 静态 1067 点;本该承接跨系统用例的 `tests/integration/` 仅 1 件。成因:`run_smoke.py` 是历届每轮必跑的闸,断言全往里堆;`unit/` 成型晚,早期断言未搬。证据在函数名里:`_smoke_reward_identity_unit`、`_smoke_layout_cell_formula`、`_smoke_adventure_table`。
**④ 词汇自造**:讨论过程中出现「系统级断言套件」「单元套件」「启动探针」「L0–L3」「轻闸/重闸」等自造词,与通用工程用语不符。
**④ 词汇自造**:讨论中出现「系统级断言套件」「单元套件」「启动探针」「L0–L3」「轻闸/重闸」等自造词。
## 二、用户裁决记录(2026-10-22)
## 二、裁决记录(2026-10-22,全部闭合)
早前三项:① 系统级断言面只在批末质量门跑一次;② 新增专用秒级冒烟测试作为「冒烟」这个名字的实体;③ 正名到文档文本+工具文件名+日志输出行。
当日 Q1–Q5 答复(覆盖前述冲突处,以此为准):
- **Q1**:T0 检出工作区零测试。master 经合回闸保证可用,谁检出谁直接开工,不重复验证。三查整条删除。
- **Q2**:那个实体不叫探针,它的标准名字就是冒烟测试,一词一义,不再造第二个词。
- **Q3**:卡内只测自己改的东西,没改的不测。全量测试只有两个时机:迭代批次结束+合回 master。
- **Q4**:`smoke_all.gd` 同属命名错位,按层级重构方案拆解。**此答复覆盖裁决③中「smoke_all.gd 文件名与 `game/smoke/` 目录名保留不动」一条**——拆空后删文件,目录随内容改名。
- **Q5**:命名用标准工程用语,名称定为**系统测试**;废弃一切自造词,本会话词汇已逐个对权威出处自查(见 §三)。
| 事项 | 裁决 |
|---|---|
| 早三裁 | ①系统级断言面只在批末质量门跑一次;②新建专用冒烟测试实体;③正名到文档+工具文件名+日志行 |
| Q1 | 检出工作区零测试,三查整条删除——master 经合回闸保证可用 |
| Q2 | 实体标准名=**冒烟测试**,不造第二词 |
| Q3 | 卡内只测自己改的东西;全量只有批末+合回两个时机 |
| Q4 | smoke_all.gd 按层级重构拆解。**覆盖裁决③中「smoke_all.gd 与 game/smoke/ 保留旧名」一条** |
| Q5 | 命名用标准工程用语,定名**系统测试**;废弃一切自造词 |
| 批 A 批类 | 非迭代批(规则与闸件批,用户开工定性);用户直接下开工令,跑全量域闸 |
| 批 B 载体 | **用户特批:免写需求卡片,直改 game/**(证据义务保留:清单+按条变异+全量域闸) |
| 变异粒度 | **按条**(用户知悉约 4–6 工作日代价后裁定,不许一点纰漏)。现行 test-conventions §6 本就是断言级条文,原样适用,无需修文 |
| 软项确认 | 冒烟形态=极小启动场景;测量件=`game/sim/`;系统宿主=`game/tests/system_test.gd` |
| 验证集清单 | 采纳:机器生成、冻结参照、只剪切禁改写、出口逐条 diff、常驻不随批死 |
## 三、词汇修正对照
@@ -34,66 +38,92 @@
| 保留 | 单元测试、集成测试、系统测试、验收测试 | 软件工程标准测试层级(ISTQB 及通用教材) |
| 保留 | 回归测试、质量门(gate)、探针(probe)、golden 基线 | CI 通用;k8s liveness/readiness probe;golden master |
| 废弃→系统测试 | 系统级断言套件、冒烟全量 | 自造词 |
| 废弃→单元测试 | 单元套件 | 「套件」单独成词拗口且非必要 |
| 废弃→冒烟测试 | 启动探针、秒级冒烟探针、L0–L3 | 自造词;那东西的标准名就是冒烟测试 |
| 废弃→消灭 | 轻闸、重闸、三查 | 随新频率规则失去指称对象(见 §五) |
| 废弃→单元测试 | 单元套件 | 「套件」单独成词非必要 |
| 废弃→冒烟测试 | 启动探针、秒级冒烟探针、L0–L3 | 自造词 |
| 废弃→消灭 | 轻闸、重闸、三查 | 随新频率规则失去指称对象;消亡口径=**活文档正文消失**(reports/ 历史件留痕不算) |
**机检承接**:批 A 把上表废弃词登记进 `design/gdd/术语表.md` 退役词对照,08 闸自动拦截复发。
## 四、目标架构
| 层级 | 载体 | 职责 | 规模 | 单次耗时 |
|---|---|---|---|---|
| 冒烟测试 | `tools/run_smoke.py`(名字改配给新冒烟)+ 新文件 `game/tests/smoke_test.gd` | 这版活着吗:启动、载表、进主屏,零逻辑判定 | 新建 10–20 项 | 10–15 秒 |
| 单元测试 | `game/tests/unit/`(现役不动)+ 迁入 | 函数/公式/状态机,隔离断言 | 现役 39 套 367 项+迁入 | 76 秒 |
| 集成测试 | `game/tests/integration/`(现役不动)+ 迁入 | 跨系统:存档⇄RNG 往返、回放确定性 | 现役 1 件+迁入 | 秒级 |
| 系统测试 | 新 `tools/run_system_test.py` + 系统测试宿主 | 启动真实工程走真实玩法路径 | smoke_all 拆余部分 | 拆后变短 |
| UI 探针+渲染 golden | `probe_gate.sh`、`render_gate.sh`(名字含标准词,不动) | 真实 UI 走查(含模拟点击)、画面基线 | 14 个探针场景 | 现状不变 |
| 冒烟测试 | `tools/run_smoke.py`(重写)+ `game/tests/smoke_boot.tscn/.gd`(极小启动场景,以项目运行目标拉起=真实开机路径:autoload 注册、配置表加载、主屏实例化;断言后 quit(0/1) 出退出码) | 这版活着吗,零逻辑判定 | 新建 10–20 项 | 10–15 秒 |
| 单元测试 | `game/tests/unit/`(现役不动)+ 迁入 | 函数/公式/状态机,隔离断言 | 现役静态 322 点+迁入 | 76 秒 |
| 集成测试 | `game/tests/integration/`(现役 1 件)+ 迁入 | 跨系统:存档⇄RNG 往返、回放确定性 | 现役 1 件+迁入 | 秒级 |
| 系统测试 | `tools/run_system_test.py` + `game/tests/system_test.gd`(SceneTree+构造注入机制保留,迁移期宿主行为零变,红绿归因不混噪声) | 启动真实工程走真实玩法路径 | smoke_all 拆余部分 | 拆后变短 |
| UI 探针+渲染 golden | `probe_gate.sh`、`render_gate.sh`(名含标准词,不动;批 B 随目录改名改路径) | 真实 UI 走查(含模拟点击)、画面基线 | 14 个探针场景 | 现状不变 |
关键命名决定:`run_smoke.py` 这个名字不废弃,改配给新冒烟测试——名字与内容终于一致;旧杂烩搬空后 `smoke_all.gd` 删除,`game/smoke/` 目录只剩探针场景,改名 `game/probe/`。
命名决定:`run_smoke.py` 名改配新冒烟(名字与内容终于一致);`smoke_all.gd` 拆空后删除;`game/smoke/` 拆分——探针场景与宿主 → `game/probe/`,测量诊断件 → `game/sim/`。
## 五、频率规则(三条,无例外)
## 五、验证集清单机制(四重保证)
1. **检出工作区:零测试**。建 worktree、拷素材与导入缓存、`git status` 归属核对,然后直接开工。
2. **卡内:只测自己改的东西**。本卡新增/改动的验收测试自己跑绿即收口;没改的东西不测。既有「验收测试随卡落地」「调试期只重跑红件最小单元」两条纪律与此一致,保留。
3. **全量只有两个时机:迭代批次结束+合回 master**。跑 `tools/run_all_gates.sh` 按改动域选档,回执机制不变。
**验证集**=迁移对象全体断言(smoke_all.gd 全部);**清单**=其登记文书 `game/tests/验证集清单.md`,**常驻参照物**。
「轻闸/重闸」两个词随第三条失去对象,从全部文档消失。
1. **结构**:套=章节(源函数、行段、去向);条=行——标签原文、白话释义、处置列(每条各自的去向/处理)。
2. **生成**:`tools/extract_checks.py` 机器提取(静态调用点口径;运行时与静态差=循环展开条目,在册标注),禁手写。批 B 第 0 步生成并冻结(基点 commit 在案)。
3. **搬运纪律**:只剪切禁改写——标签与条件式逐字原样搬;任何改写=新断言改动,走单独流程另配变异证明。
4. **出口机检**:迁移后再提取,与清单逐条 diff——标签/条件式/计数三对齐才算完。
5. **活性证明**:按条变异(§七批 B)。
6. **维护义务**:此后断言新增/删除/改判必须同步清单——批 A 在 test-conventions §9 加一句锚,挂现有改动—验收对照表纪律。
7. **范围**:本批只收录迁移对象;unit/integration 现役断言的收录列为后续可选项,不在本批承诺。
## 六、执行方案(一个设计,两批落地,批 B 依赖批 A)
四重保证各管一段:①冻结参照(清单)→保真有据;②只剪切禁改写→语义漂移在源头杜绝;③出口逐条 diff→漏搬/重搬/字面变更;④按条变异→搬过去哑了的断言。前三重保证「不缩小不改变」,第四重保证「还活着」。
### 批 A:命名+频率+新冒烟测试(估半天到一天)
## 六、频率规则(三条,无例外)
- 工具:重写 `tools/run_smoke.py`(跑新冒烟);新建 `tools/run_system_test.py`(过渡期暂指向现有 `smoke_all.gd`);新建 `game/tests/smoke_test.gd`。
- 闸机 `run_all_gates.sh` 闸键映射(其余 11 键不动,零 churn):
1. **检出工作区:零测试**。建 worktree、拷素材与导入缓存、git status 归属核对,直接开工。
2. **卡内:只测自己改的东西**。本卡新增/改动的验收测试自己跑绿即收口;没改的不测。既有「验收测试随卡落地」「调试期只重跑红件最小单元」保留。
3. **全量只有批末+合回两个时机**,跑闸机按域选档,回执机制不变。
## 七、执行方案(一个设计,两批落地,批 B 依赖批 A)
### 批 A:命名+频率+新冒烟测试(非迭代批;估 0.5–1 天)
1. **登记**:待办清单立条目(第一动作)。
2. **工具**:重写 `tools/run_smoke.py`(跑新冒烟);新建 `tools/run_system_test.py`(过渡期指向 smoke_all.gd);新建 `game/tests/smoke_boot.tscn/.gd`。
3. **闸键映射**(闸机执行顺序=冒烟最先,秒级失败快停):
| 旧键 | 新键 | 说明 |
|---|---|---|
| 01 冒烟全量 | 01 系统测试 | 同一道闸换内容指向 |
| (新增) | 01a 冒烟测试 | 秒级,排最前 |
| (新增) | 00 冒烟测试 | 秒级,排最前 |
| 02 单元套件 | 02 单元测试 | 仅改名 |
- `baseline.json` 同步改键,照 08c 先例人工确认一次(全部闸现绿,重生成低风险)。
- 文档与规则:`AGENTS.md`(单件直跑行、验收行)、`process-conventions.md`(删三查、删轻闸重闸表述、§3.4 环境准备保留)、`roadmap.md` loop 规范第 2/3/4 条、`game/tests/README.md`(术语表改标准四级;删除「别被字面骗了」警告节——名字对了警告就死了)、`architecture.md` 测试架构节、迭代技能现行两副本(`.workbuddy`+`.qoder-cn`)改写并覆盖同步过期两副本(`.zcode`→`.qoder`),改技能重启会话生效。
- 实现期核对项:`tests/run_all.gd` 对 `integration/` 的扫描归属——若已并入 02 一起跑,闸名用「02 单元与集成测试」或增设独立键,按最简处理。
- 验证:全量域 `tools/run_all_gates.sh`(不带参数,本批混触 game/+tools/+文档)跑绿;新冒烟测试变异验证(改坏启动→冒烟红→还原→复绿);闸机改动按 test-conventions §6 做变异验证。
其余 12 键不动。`baseline.json` 同步改键;**重生成前先单跑 09 静态扫描核实现绿**(基线记 exit=1 已滞后,2026-10-22 16:20 回执为 exit=0);届时若红→停、查、禁带红重生成。
4. **文档与规则**:
- `process-conventions.md`:删三查条;§3 重编号+全仓「§3.N」式指针核对(AGENTS.md:19 在案);§3.4 环境准备保留;§9 加验证集清单维护锚。
- `AGENTS.md`:单件直跑行、验收行、运行与验证小节路径更新。
- `roadmap.md` loop 规范第 2/3/4 条重写(T0 零测试、轮内无闸、批末+合回全量)。
- `game/tests/README.md`:术语表改标准四级;删「别被字面骗了」警告节(名字对了警告就死);订正滞后读数(「35 套」「29 个 .gd」);计数原则=挥发读数能删则删(以闸回执为准),必留的标口径+取数日。
- `architecture.md`:测试架构节+:11 文档头实证行。
- 轻闸/重闸词面清扫:`体验验证清单.md`、`待办清单.md`、`tools/probe_gate.sh` 注释、`tools/run_all_gates.sh` 注释(:2、:119)、`design/gdd/术语表.md` 退役词登记。
- 实现期核对:`tests/run_all.gd` 对 integration/ 的扫描归属→闸 02 定名(单元测试,或单元与集成测试)。
5. **技能副本**(实测更正):库外现行=`C:/Users/DK/.workbuddy/skills/iter/SKILL.md`;库内 `.zcode` 与 `.qoder` 两份改写并保持逐字一致(实测现一致);`.qoder-cn` 无技能副本。改技能重启会话生效。
6. **验证**:全量域 `tools/run_all_gates.sh`(不带参数)跑绿;新冒烟变异验证(改坏启动→红→还原→复绿);闸机改动按 §6 变异验证。
### 批 B:断言迁移(估 2–4 天)
### 批 B:断言迁移(用户特批免卡直改 game/;估 1.5–2 周)
- `smoke_all.gd` 的 1211 项按性质三向分流:纯逻辑→单元测试;跨系统→集成测试;真实系统路径→新系统测试宿主。
- 迁移以套为单位:每迁一套,在新宿主做一次变异验证(改坏对应被测件→新宿主红→还原→复绿),不做 1211 次逐条证明——test-conventions §6 的合规读法,按套证明。
- 拆完删 `smoke_all.gd`,`game/smoke/`→`game/probe/` 连同全部路径引用(`probe_gate.sh`、`error_scan.py`、golden 脚本、闸机注释)。
- 收益:金字塔摆正(单元最多、系统测试变薄)、失败定位变准、7151 行单文件消失。
- **Step 0**:`extract_checks.py` 生成验证集清单并冻结(基点 commit 在案);`smoke_all.gd` 冻结,批 B 期间不接受任何新增断言。
- **迁移**:套=最小提交单元——迁一套、新宿主实跑该套、提交,红当套暴露;原子提交(新宿主落函数+源文件同 commit 删函数,无双重窗口)。迁移 2–4 天。
- **按条变异**:约 1067 个静态断言点,每轮=改坏该断言守的生产代码→跑该断言→验红→`git checkout` 还原→`git status` 清洁确认→账本留痕(变异点文件:行、红输出摘要、还原确认);约 4–6 工作日;每约 200 轮抽点自查防疲劳失误。
- **出口对账**:再提取与清单逐条 diff(标签/条件式/计数三对齐);全仓 grep `game/smoke`、`res://smoke`、`smoke_all` 清零(reports/ 历史件除外)。在案必改点:`run_all_gates.sh:206` PARITY_TOUCH_FACES(11 号闸触面判定逻辑,非注释)、`AGENTS.md` 在册入口、`tools/parity_anchor.py`、`tools/balance_verifier.py`、`sim-data/analyze.py`、`architecture.md`、`design/gdd/术语表.md` 豁免行、08d 闸在册行号指针重核。
- **目录收尾**:删 `smoke_all.gd`;探针场景与宿主 `game/smoke/`→`game/probe/`;测量诊断件→`game/sim/`;熵增闸白名单+Project Layout 同批修订(硬性红线现成要求)。1–2 天。
- **验收判据**:金字塔摆正(单元静态检查数>系统测试静态检查数);全量域闸绿;四重保证记录齐全。
### 执行注意事项
## 八、时间汇总
- 两批均走独立 worktree;主区禁直改直提。
- 并行跑闸会假红:`user://save.json` 全 worktree 共用,闸机串行跑。
- 本批测试执行依据=用户点名(两入口铁规第二入口)。
- MC/模拟:无数值改动,零跑。
- 跨会话记忆文件(`.qoder-cn` memory 的 smoke-terminology 条目)在用户批准本方案后更新为最终裁决。
批 A 0.5–1 天;批 B 约 1.5–2 周(迁移 2–4 天+按条变异 4–6 天+收尾 1–2 天,串行)。两批之间停机等用户发令。
## 七、待裁点(全案并列,禁代裁)
## 九、执行注意事项
1. **批 B 开工载体**:案 1=本方案当合同直接开工(迁移是等价搬移非行为改动,账本+逐套变异证明即对照表;建议);案 2=走正式写卡段(req-card),多一道工序换标准对照表结构。
2. **新冒烟测试判据面**:引擎能起、autoload 全在位、配置表全载零错、主屏场景实例化、无 SCRIPT ERROR,约 10–20 项。已按最简定,批 A 开工前可推翻。
3. **探针目录新名**:`game/probe/`。已定,批 B 开工前可推翻。
4. **过渡态接受**:批 A 落地后到批 B 之间,闸键已叫「01 系统测试」但内容还是未拆的 smoke_all.gd 全量——名字先到位、内容批 B 拆纯。已定可接受,不设临时名。
- 两批均走独立 worktree(本分支 `test-term-reform` 可续用);主区禁直改直提。
- 串行跑闸:`user://save.json` 全 worktree 共用,并行必假红。
- 测试执行依据=用户点名(两入口铁规第二入口);MC 零跑(无数值改动)。
- 跨会话记忆文件已随本 v2 更新。
## 十、微决策已定项(可否决)
00 键名「冒烟测试」排最前;冒烟场景落 `game/tests/smoke_boot.tscn`;清单文件名 `game/tests/验证集清单.md`;提取脚本 `tools/extract_checks.py`;清单不收录 unit/integration 现役断言(后续可选)。
**待裁点:无——全部闭合。**