Files

197 lines
30 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 测试规范(Dungeon Sweeper)
> 约束范围:`game/probe/ 与 game/sim/`、`game/tests/` 与一切场景探针的编写与验收。
> 分工:测试**执行义务**(改完必须测什么)归 AGENTS.md「硬性红线·改完即测铁规」与 `process-conventions.md` §4;**跑什么闸、什么顺序**归 `tools/run_all_gates.sh`(脚本即清单,本文与 AGENTS.md 均不另列);本文管测试怎么写、怎么算合格。每件测试工具**是什么、判什么、怎么单独跑、什么时候适合单独用**——见 `game/tests/README.md`(测试工具手册),本文不重复工具介绍。
> 归属:随游戏逻辑写/改的测试=需求改动的一部分(随需求卡片同批落地);不伴随逻辑改动的纯测试维护=工程改动(不写卡,用户发令直改)。
**定测试方案前必须通读本文。**
---
## 1. 测试总纲——"存在"必须证明"可达且正确"
核心层验收标准通过不算有测试:GDScript 编译不查字典字段与时序,呈现层错误只在运行时暴露。
测试必须证明功能可达(用户真的能用到)且行为正确(结果符合验收标准)。
### 1.1 测试层三元组(2026-11-07 用户裁——测试层识别权威表)
识别一个测试层靠三元组,不靠名字——**层级名只是代称**;名称与定义的登记面=`design/gdd/术语表.md`,本表是识别判据的单点:
| 层(代称) | 职责 | 触发时间点 | 覆盖面积 |
|---|---|---|---|
| 冒烟测试 | 真实开机路径存活检查——启动/加载表/进主屏,零逻辑判定 | 每次代码域跑批+合回前置检查+远端 CI(三件保险恒跑不降) | 最小:一条真实开机路径 |
| 单元测试 | 受控裸环境断言面:单机制契约+跨系统真实路径闭环——不加载开机装配、手工构造注入实跑;闭环套件=两以上真实系统手工装配×落盘往返,性质归属由各套件头注「跨系统面」句承载 | 同冒烟(恒跑;关联档选套件=需求卡片申报∪diff 推导并集,横切回落全量) | 领域类原子行为+跨系统接缝——不含开机装配与画面 |
| 系统测试 | 真实开机+真实玩法路径行为断言(推理→战斗→结算→推进) | 同冒烟(恒跑) | 完整装配下的玩法旅程 |
| 场景探针 | 真实实例化场景+真输入管线(合成输入事件走输入管线)的 UI 可达性/可见性/状态 | 代码域跑批(测量面批记 SKIP)+远端 CI | 逐 UI 区域交互动线 |
| 渲染闸 | 窗口化真实渲染截图 vs 冻结基线图逐像素容差比对 | 代码域跑批(测量面批与 --quick 记 SKIP)+远端 CI | 像素呈现(主题/素材/排版) |
层级合并说明(2026-11-07 用户裁):跨系统真实路径闭环套件归单元层承载,三套件实体在 `game/tests/unit/`;「集成测试/集成用例/集成层/集成侧/集成宿主/集成族」为退役词(术语表「退役词对照」;S11 注释面+用语审计文档面双承接)。
## 2. 场景级探针标配
每新增一个可交互 UI 区域(视图/覆盖层/面板),必须配套场景级 headless 探针:
真实实例化场景 → 驱动真实输入路径 → 断言可见性与状态。
凡模态覆盖层,探针必须断言:打开后自身 visible 且遮挡物已隐藏(模态被遮挡 = 功能存在但不可达)。
**UI 驱动断言须走真输入管线(2026-11-06 立)**:探针里「点按钮/点场景物件」类驱动断言,一律经引擎输入管线承载(合成 InputEvent 走 `push_input`,press+release 成对;合成滚轮同样必须 press+release 成对——只发 press 会把鼠标焦点钉死在按下点控件上,后续点击全部失效);信号直发(`pressed.emit()` 等)绕过命中测试,保不了「玩家点击可达」,只许用于真输入到不了的面并当场标〔接线断言〕(现役例:置灰态穿透钉处理器兜底)。折叠区控件先以真输入滚轮滚入可视区再点。每个动线断言钉「落点」判定(点了之后到哪个屏/哪层可见),防驱动中断后的空转假绿。真输入命中控件时自动登记控件覆盖(探针共用面登记件落 `.gates/` 观测产物),覆盖面生长不靠人记。
## 3. 缺陷修复必须沉淀回归断言
每个缺陷修复必须在探针或冒烟中留下能抓住该缺陷的断言(例:封印动作耗尽 AP → 必须进入第 2 轮;
选用道具 → 库存态必须变 Used)。没有回归断言的修复视为未完成。
## 4. 验证时机(合回后远端 CI 制,2026-11-03 换代)
开发期义务=`process-conventions.md` §4 改完即测铁规:本批新增/改动的验收测试自己跑绿、读数写进该步提交信息才算完成(卡内只测自己改的东西)。合回 merge 提交落笔前另有 pre-merge-commit 前置检查(2026-11-06 用户裁:冒烟+单元全套件 4 分片,约 2 分钟——当场拦截面,不落回执;细则见 process-conventions §1 第 4 条 ③)。全量验证归合回后的远端 CI:git merge 合回 master 落地后 post-merge 钩子推送 origin master,远端按改动域分流跑 `tools/run_all_gates.sh`(游戏码批=不带参数档两域全量、单元测试全套件——跨卡触面与关联档选测的盲区由全量兜底;文档批=文档域秒级闸;分流算法单点=`tools/ci/domain_route.sh`),远端结果用 `tools/ci_check.sh <合并提交>` 按需现查(读 run 自身 `status`/`conclusion`,只呈报、不落盘——合回不等待、不唤醒,process-conventions §1 第 3 条);CI 红态下修复合回落地即再推再验追绿(修复走新开 `fix-<任务名>` 修复 worktree,process-conventions §1)。同一份字节禁止第二次人手跑。该脚本是全部验证闸的唯一入口与唯一清单,域划分与选闸算法只写在脚本里,本文禁另列闸件清单。
行为探针使用随机化玩家行为(封印/停手/刷新/无效点击)——自动玩家不做的动作就是测试盲区。
## 5. 测试函数怎么写——验收清单条目的落码规范
需求卡片 §8「改动—验收对照表」每一条都要落成可执行的验证;本文定统一写法,卡里定每批的具体内容(测什么/注入哪里)。写卡期查不出执行载体的条目=不可测,当场呈报,禁拖到实现期。
1. **执行载体五选一,逐条声明**:单元测试(`tests/run_all`)/系统测试断言(`tests/system_test.gd`)/场景探针(`probe/` 下 `*_probe`)/MC 同种子逐项比对/人工核对(仅限无法自动化的纪律类需求点,如命名锁定、数值占位)。行为类条目以自动化载体为主。
2. **粒度与对应关系**:每条清单条目至少一个自动断言,且断言必须从该条目的真实入口进入;多条条目可合用一个测试函数,但每条都要有自己单独可判红的判据(取证口径见 §8.4 唯一口径——禁变异/禁撤销)。断言失败消息末尾带编号尾缀〔卡短名 Vn〕(如〔秘宝批 V3〕)——断言与卡片清单可互相 grep 查找。`Kit.check_quiet` 静默收集形态(计数不入判定即打印、失败消息进 problems 汇总)的断言已入 `tools/extract_checks.py` 扫描面(2026-11-02 提取器改版:三通道同口径提取,静默通道条目 quiet 列记 `channel:check_quiet`),验收尾缀 grep 对该通道有效。
3. **断言词汇按验证对象五选一**:
| 词汇 | 适用场景 |
|---|---|
| 逐位相等 | 同种子下确定性公式与结算的精确逐项比对 |
| 区间/差值带 | 概率与平衡读数(MC 同种子配对比较,出带即红) |
| 快照比对 | 存档域结构、配置表行结构 |
| 重放 | 同种子断点回放、改前改后配对 |
| 状态/计数器断言 | 条件解锁、限次、充能——置数据→走路径→断计数值 |
4. **调试注入两层(能力测试与流程体验两分法的落码面)**:自动化测试=测试代码直调核心层写口构造状态(直改数据表行/计数器/存档域,不经 UI、不走正常资源积累流程——冒烟现役做法);人工体验=DebugOverlay/DS_DEBUG 调试面,服务用户目检(发布态该面恒隐、无 UI 开启口,开发期临时启用=本地改 `_debug_entry` 缺省、不提交;能力测试不经 UI,本条口径不受影响)。清单条目的「怎么测」必须写到数据面粒度:改哪张表哪行、置哪个计数、调哪个核心写口。
5. **换代批旧验证约束同生死**:删除旧数据行/旧实现代码的批次,必须同批摘除只验证旧实现的断言与护栏校验,由新断言替代——旧件断言残留=冒烟假绿来源;合并后冒烟全绿且全仓无旧件残留引用为证。
6. **违约通道类需求点必须落独立负面套件(2026-10-28 立)**:预期运行期违约/致命路径的需求点(handler 通道、fail-fast 分支)一律落独立负面套件并按 manifest 登记 `expect=1, negative=true`,禁落现役非负面套件——headless 下 assert 失败必产不可捕获的 SCRIPT ERROR,非负面套件的输出被错误扫描命中即假红(先例=reward_dangling_treasure/counter_prefix_fatal/extended_row_violation/run_time_fatal 四件)。
## 6. 判定三硬闸——闸承载的构造义务
任何**新增或改写的闸承载**(闸脚本/批跑编排/探针入口)必须三闸齐备;现行各闸状态登记归架构文档「测试与质量域」节(本文不另列闸件清单):
1. **退出码为唯一权威判据**——输出里的 PASS 串只作附加判据不作判据主体;打印 PASS 后 `quit(1)` 必须判红。
2. **SCRIPT ERROR / Parse Error 扫描面在位**——GDScript 脚本错误不改进程退出码、不计失败数(机制事实见 §7),错误标记必须扫输出,且判据必须覆盖「跑了但半途脚本错误」态——退出码 0 但输出缺预期签名同样判红(防静默退出)。
3. **断言数下限**——零断言的正常返回与断言失败必须区分开(现行做法:`Kit.finish` 零断言返回专用退出码 2,不与「断言失败=1」混用,否则致命类套件的期望码协议会放过空跑)。
- 负面套件(测试目标就是产生错误输出)仅可豁免第 2 闸,且须在 manifest 显式标记,其余两闸照判。
- 子进程输出须经系统命令解释器重定向落盘再读——`OS.execute` 的输出管道在本机恒空。
**新写测试件全类型标注**——新写的测试件(冒烟断言/探针/单测)参数、返回值、容器一律带类型标注,与 S9 对产品码的要求同型;存量不强制清扫,被批次触碰时顺带换代。暂不机器闸(S9 扫描面=产品码,probe/sim/tests 不在扫描面是测量面直构惯例的既有裁量)。
## 7. 判定可靠性优先于覆盖率
- 「跑一遍没崩=通过」无效:测试绿只证明**当前代码没犯这个错**,不证明**犯了这个错会被抓住**;断言存在不等于断言执行。
- **脚本错误会静默中断所在函数的剩余断言,而套件仍报全绿**(机制事实):GDScript 无脚本错误陷阱 API,错误不改进程退出码、不计失败数。三处实证:①「309 项 0 失败」实为断言未跑全;②敌人表行集纪律 10 条断言因定型数组赋值错误从未执行(修复后两条正向见红=夹具本缺锚行);③`Callable` 形参类型写错致解析函数返回 null、后续断言整段蒸发。
- 由此产生两条义务:**写闸件**按 §6 配三硬闸;**写验收函数**必须自证断言全数执行——真实入口断言在当轮执行并通过(§8.4)为主证,零命中自检(扫描面为空即判红)为辅证。
- **覆盖率不是目标**:不引入行覆盖率度量(Godot 无内建,第三方属新基建);现行补洞=能力清单覆盖域表+人工判定,判定可靠性靠上列自证手段,不靠覆盖率数字。
## 8. 改动级验收闭合(2026-10-21 立)
### 8.1 验收单位是行为改动
一个行为改动 = 新增或修改一条函数、一条数据、一处接线、一个生命周期行为、一条玩家可见文案。纯改名、注释、格式化不算行为改动,但必须在对照表里单独列一行写「非行为改动」及判断依据。禁止用「重构」两个字把行为改动藏起来。
### 8.2 四层与真实入口
- **单元**:不依赖场景树和真实宿主的纯逻辑;测试从领域类的对外方法进出,断言钉对外可观测面(返回值/信号/查询接口/落盘内容)。内部字段直查=受控例外:仅当该行为没有公开可观测面可钉时允许,对照表该行注明理由;存量不回头清扫,被批次触碰时顺带换代。探针直读视口承载子件结构(画布取视口首子件、渐隐带两片与平移提示子件按名取)属此类——断言对象即承载结构本身,无公开可观测面可钉,理由随对照表行申报。
- **接口**:模块边界的公开契约——数据表加载、存档与断点、事件载荷、命令接口;测试从公开入口进出。接口级断言随单元套件落(`unit/contracts/`),不另设承载目录。
- **跨宿主**:跨宿主的接线、持久、生命周期——例如 LevelRunner 把 level_counters 传给 BattleOrchestrator、两场战斗共享同一个桶、断点续玩;测试必须实例化真实宿主链,禁止用裸 EffectEngine 代替。断言载体归单元层跨系统闭环套件(§1.1 三元组表),验收入口不变。
- **探针/golden**:玩家可达性与观感;真实实例化场景、驱动真实输入。
- **golden 测试项扩项(2026-11-05 立)**:触碰画面呈现规格的需求批(新增画面要素/布局/配色/动效;判据=设计段出了预览图),实现段把该画面纳入渲染闸机器面:截图采集清单扩项+实跑截图冻结进 `game/tests/golden/`(基线属入库测试资产,render_gate.sh 在册例外)。黄金图=游戏真实渲染截屏冻结的逐像素基准,比对器与容差口径见 render_gate.sh 头注释(脚本即清单,本文不另列)。基线冻结(新建与换代同口径)=用户对照设计段预览图确认后执行,触发原因写进当批提交说明(`tools/golden_baseline_refresh.sh` 现役义务);此后渲染闸逐像素自动盯、零人工。预览图(HTML/SVG 效果图)与引擎渲染是两套管线,禁直接充当比对基线——预览图只作人审参照与验收判据句的出处(判据出处行锚指向 ux/ 内嵌预览节);缺陷修复以现行规格与在库基线为准,不触发新预览。
分层不是形式。改动发生在哪一层,验收就必须从那一层的真实入口进入。测试绕过了改动点,就不算这个改动的验收——这正是「断言存在、接线坏了却不红」的来源。
### 8.3 改动—验收对照表
需求卡片列需求侧对照表;实现报告列实际对照表。每行至少六格:
| 需求点 | 改动(文件:行/行为) | 验收测试(名称+文件:行+尾缀) | 层级 | 真实入口 | 判据绑定面 |
|---|---|---|---|---|---|
实现报告另加「结果」格(绿/红/未过及依据)。两端都要对上:
- **正向**:每个需求点至少一行;每行必须有真实入口和判据绑定面。缺任一项=该需求点未验收。
- **反向**:diff 里每个行为改动至少一行;没有对应行的改动,必须写明「非行为改动」或「由第 X 行覆盖」。
- **测试侧**:新增或改写的每条断言至少挂一行;挂不上的孤儿断言删掉或补挂到需求点。
**判据出处行锚(2026-11-05 立,自 2026-11-05 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改,被编入迭代开工前由写卡段按本粒度补挂)**:对照表「需求点」列每行必须带**判据出处行锚**——该行验收判据所依据的现行文档句子,格式「`<文档相对路径>:<行号>`」。现行文档=`design/` 全域现行文档(含 `ux/` 交互规格与 art-bible 的判据行);已退役的需求卡片不是现行文档,不得充当判据出处。作用=断言预期值从规格句抄出,不从实现反推:实现行为与规格句冲突时断言红;规格缺席的行写不出锚,即停卡退回写卡段(那是需求澄清缺口,不是测试缺口)。机检=`tools/pipeline_gate.py` 判据 C5(锚格式与指向存在性,按卡文件名日期分流)+`tools/capability_audit.py` 链式锚检查(断言→套件→能力行→系统文档,见 §8.9)。
**测试函数的判据出处注记(2026-11-06 立)**:`game/tests/**` 与 `game/probe/**` 内每个**验证函数**(函数体含 `check(`/`check_quiet(`/`_problems.append(`/`push_error(` 判定调用的函数——定义行与 `_check(` 前缀不作判定计)必须带至少一条**判据出处注记**,格式「`# oracle: <design/相对路径>:<行号> <判据一句>`」——指针在前、判据摘要句在后,断言预期值的出处随断言走:断言红时读注记即达出处文档句,零查表。指针空间=`design/` 全域现行文档(行为测试锚 owner 系统文档「验收标准」句或 `ux/` 规格句;惯例类测试〔封装扫描、判定通道纪律、驱动契约〕锚规约条款行);`game/sim/` 不进扫描面(测量面直构惯例)。与链式锚的分工:链式锚(断言→套件→能力行→系统文档)不变、属义务清单层;本注记属执行证据层、写在断言文件内,非独立账本(§8.9 法则 4 不变)。写新测试函数时当场挂注记;被指规格句改行号时随批维护指针——死指针即红。局限如实声明:注记是被动文本,句内容改而行数不变时机检抓不到(与卡片判据 C5 同限)。机检=`tools/capability_audit.py` 判据出处注记道(覆盖检查+指针存在性;扫描面零文件自检红)。规格缺席写不出锚=发现规格缺口:记发现不造锚、收尾呈报,禁锚到非现行文档凑数。
**验收档申报(2026-11-04 立,自 2026-11-05 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改)**:每张需求卡片在头部信息区(与设计事实源声明同区)申报一个验收档,三档:高/中/低。判据=失败代价单维——这条改动做错了,后果随存档或结算传播的(存档写读与迁移、RNG 流、战斗结算公式与乘区、经济入账、数值表结构校验)=高;后果玩家可见但不损持久状态的(常规玩法逻辑、门控、交互逻辑、呈现数据面)=中;后果即看即知且无状态残留的(文案、纯呈现样式、布局微调)=低。一张卡触多档按最高档申报;申报由写卡段落笔,用户批卡(U0)时确认或改判。档位只调节 §8.7 审计深度——闸机与 CI 的域划分、选闸算法、全量强制档一概不因档位变化,真实入口、判据绑定面、禁削弱等验收闭合判据全部照旧。未申报档位的卡一律按高档全量审计。机检=`tools/pipeline_gate.py` 判据 C4:卡内须含「验收档:高/中/低」申报行。
**能力清单维护锚(2026-10-29 用户裁改版定稿)**:`game/tests/README.md`「能力清单」是**实现指导+阅读导航+义务声明**——只宣布「要验证什么」,不记「是否已验证/是否跑过」;落地账归现行验收闭合链(改动—验收对照表逐条挂断言+合回前独立验收审计),本清单不承载验证状态。表为四列:能力|系统|真实入口|代表用例(`文件:函数`)。**维护归写卡段,当场入表**:写需求卡片时,本批新增能力当场写入能力行——真实入口取自设计文档已定的入口,代表用例=卡里定死的计划测试(`文件:函数`);受影响存量行(入口/用例名变更)同批更新;能力退役删行。**实现照单落名**:测试函数名以清单为唯一依据,名实不符=卡片没写清=停卡退回。**收尾核对**:批末收尾只核对表上名字与实际落地一致(改名则回表),不刷任何批次字段;实现批禁写该文件的现行红线不变(process-conventions §3 第 11 条),核对义务归收尾提交。三层模型见 §8.9。改动—验收对照表纪律不变:新增或改写的每条断言仍须挂一行(上文「测试侧」);断言改判仍受 §8.4 真实入口口径约束。
**「真实入口」判定口径(2026-11-05 收窄)**:真实入口只认经引擎输入管线(合成 InputEvent 走 `push_input`)或真实渲染路径(截图/golden)的承载;信号直发(`pressed.emit()` 等合成信号)承载一律标「接线验证」,不得充当能力行的真实入口——接线验证保「信号已接线」,保不了「玩家点击可达」(hitbox/命中面在信号上游,emit 全部绕过)。既有能力行若以 emit 承载充当真实入口,随批触碰时订正;暂未触碰的行,缺口显式登记(残险模式),禁静默豁免。
**新增 core 件的覆盖登记义务(2026-11-03 架构审查 P1 余项裁)**:拆件或重构产出的新 core 文件不触发 process-conventions §3 第 6 条「新功能必配新测试」(那条只管新增玩法/机制),因此单由本条承接——新 core 件要么被 `game/tests/` 某套件按文件名或 `class_name` 点名,要么在承接它的能力行「代表用例」里申报「经宿主链覆盖(宿主=<件>)」;两者都无=批末收尾核对时补登。本条**不是覆盖率要求**,与 §7「覆盖率不是目标」同轨:登记的是能力义务的归属,不做文件计数——「每个 core 件必须被点名一次」的机器闸已裁否(它逼出为点名而点名的空套件,且与 §7 正面冲突)。落笔面沿用现行分工:申报行由写卡段入能力清单(实现批禁写该文件),核对归批末收尾提交。
**退役对账义务(2026-11-05 立)**:需求卡片退役(吸收即死)时,其对照表每行的验收意图必须已被承接——承接形态=能力清单行(能力+真实入口+代表用例)或已落地的断言;退役后无承接=该能力的规格判据断链,收尾核对判红。机检=`tools/capability_audit.py`(套件→能力行反向覆盖+断言链核验)。先例教训:营地图批卡片退役后,大门判据(`design/gdd/ux/camp.md:16`)无任何活面承接,探针 emit 断言悬空假绿——规格在、链接断。
### 8.4 真实入口断言(验收闭合的主判据)
- **唯一口径(2026-10-24/2026-10-28 用户两裁)**:每个需求点与每个行为改动的验收=一条从真实入口进入的断言,可 grep 定位、在当轮真实跑批中执行并通过。**禁变异类测试**(把生产码或数据表改成错值看断言抓不抓得到);**禁撤销类取证**(回退本批改动或该 hunk 看断言红不红)——两者都是人为制造红,属伪造证据,一律禁止。
- **判据绑可观测提交面**:断言判据要绑「被测改动特有的可观测提交面」(信号发射、事件、入参、绘制记录、状态源取值),不绑多层防御之后的终态——否则改动被下游兜底吸收时终态不变、断言假绿。例:探针「雾不扩可点域」首版只看屏/选路态终态,命中面放宽后断言仍绿;改绑 `route_chosen` 发射面后即红。
- **判据绑不上的出口=停卡呈报**:某改动确实造不出可观测提交面(纯防御分支、release 独有位)时,走静态判据+代码评审注记并在对照表申报观测面局限;不得自造替代证明。
- **正面效力自检**:精确等式优于不等式与非空即过;扫描类断言带「扫描面 > 0」非空前置,防扫描面为空静默绿。
- 持久化、生命周期、存档、跨战共享这类接线逐条配断言;判定可靠性细则见 §7。
### 8.5 禁止削弱测试
实现期不得为了让测试变绿而删除断言、放宽阈值、缩小扫描面、把真实入口换成下层直调。确需改判据=需求卡片没写清=上游缺陷:停该卡、呈报退回写卡段,不在实现期自行决定。卡片可预先声明允许改动的旧断言及理由;未声明的削弱由独立审计判红。
### 8.6 测试时机
不要求 TDD,不要求先红后绿。允许实现后补测试;但补的测试必须满足 §8.4 的真实入口断言口径。实现完再补、补完就绿,不算验收。
### 8.7 独立验收审计
合并前由没有参与实现的会话或子代理做一次审计。审计只读需求卡片、实际对照表、diff、测试文件和实现报告,自己跑最窄测试抽查,不采信报告里的「已全绿」。审计至少做四件事:
1. 逐行核对对照表:测试存在、真的执行、尾缀能 grep 到、真实入口没有绕过改动点;
2. 抽查判据绑定面:断言从真实入口进入、钉在被测改动的特有可观测提交面上,且当轮真实跑批执行过;
3. 检查测试削弱:删除断言、放宽阈值、缩小扫描面、换下层直调,逐处要卡片申报或用户批准。
4. 核对内部字段直查的受控例外:直查行是否已在对照表注明理由(该行为无公开可观测面可钉)。
5. 核对判据出处:抽查断言的预期值能否从其判据出处行锚(§8.3)的规格句独立写出——预期值只在实现里有的(同义反复,oracle 镜像实现),判红。
**审计深度分级(2026-11-04 立)**:审计按卡内申报的验收档(§8.3)逐卡定深度;梯度只落在昂贵的判断件上,机械且堵造假向量的两件(削弱检查、例外核对)三档全保留不抽。中/低档省略的测试复跑以远端 CI 读数为执行证据——`tools/ci_check.sh <合并提交>` 的现查输出(commit+run 号+conclusion)是机器产物,run 号在远端永久可复核,审计报告照抄该行即可;照抄前先核对读数必须是「绿」——「未验」(零触发批跑闸步全跳过)与「不可判」不作证据,那种批的回补办法是等一次含代码面的合回或用户自发全量回归(2026-11-04 用户裁:回执等待件退役,证据由落盘文件改为现查读数;「不采信实现者自述已全绿」的口径不变):
| 审计动作 | 高 | 中 | 低 |
|---|---|---|---|
| 对照表逐行核对 | 全量 | 全量 | 抽查 ≥1/3 行;新增行与改判行必抽 |
| 判据绑定面核对 | 抽查(现行口径) | 抽查(现行口径) | 抽 1 行 |
| 测试削弱检查 | 逐处 | 逐处 | 逐处 |
| 直查例外核对 | 逐条 | 逐条 | 逐条 |
| 最窄测试复跑 | 抽查(现行口径) | 省略——以远端 CI 现查读数代证 | 省略——以远端 CI 现查读数代证 |
低档的抽查面与抽中依据照写审计报告;「每批必有审计、禁零审计批」不变;档位存疑按高档执行。
审计报告落 `reports/iter<N>-验收审计-<日期>.md`,逐行写「通过/缺漏/例外及依据」,逐卡标注验收档与实际执行深度。未通过不得合并。审计核的是 §4 那一步留下的跑批读数(回执与测试输出),对已跑绿的同一份字节不另起跨域跑批——读数对不上才复跑。
### 8.8 生效与旧卡
本规自 2026-10-21 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改。旧卡在开工前缺对照表的,由写卡段补,补完再开工。
### 8.9 三层模型(验收意图·义务清单·执行证据,2026-10-29 定稿)
验收体系分三层,各层各管一件事,互不代行:
| 层 | 载体 | 切分轴 | 一行是什么 |
|---|---|---|---|
| 验收意图 | 系统文档「验收标准」节 | 按 owner 文档 | 一条玩家或系统可观测的判据 |
| 义务清单 | `game/tests/README.md`「能力清单」 | 按玩家旅程与系统归属 | 一条待验证义务:能力+真实入口+代表用例(`文件:函数`) |
| 执行证据 | 测试套件断言 | 按代码归属 | 一条从真实入口进入的断言 |
四条法则:
1. **每格非空**:每个系统文档有验收标准节;每个能力行有真实入口与至少一个代表用例;每条断言挂在某个需求点或能力行上。
2. **每条断言有归属**:孤儿断言删掉或补挂;不建无归属断言。
3. **数量不守恒、承接守恒**:三层条数天然不等——一条验收意图可由多个能力承接,一条能力义务由多条断言覆盖。要守的是两个满射:每条验收意图至少有一条能力义务承接,每条能力义务至少有一条真实入口断言落地。数量对账只在批内做,见第 4 条。
4. **无全局对账总账**:不建逐断言账本,不做跨层条数对账;对账只在每批的改动—验收对照表里做(§8.3)。历史教训:阶段 2 退役的逐断言账本正因把义务清单层与证据层压成一本账而失修。
**维护时序(2026-10-29 改版)**:能力清单归写卡段维护——写需求卡片时当场入表:本批新增能力当场增行(真实入口取自设计文档已定的入口,代表用例=卡内定死的计划测试 `文件:函数`),受影响存量行(入口/用例名变更)同批更新,能力退役删行;实现批禁写该文件(process-conventions §3 第 11 条)。实现照单落名:测试函数名以清单为唯一依据,名实不符=卡片没写清=停卡退回。批末收尾只核对表上名字与实际落地一致(改名则回表),不刷任何批次字段——清单不记「是否已验证/是否跑过」,落地账在改动—验收对照表(§8.3)与独立验收审计(§8.7)。
**文档纯度**:验收意图与能力描述只写玩家或系统可观测面,禁写代码路径(`.gd`/`.py`/`.sh`)、测试文件名、断言名;唯一例外=配置文件索引(`game/data/tables/*.tres` 这类表路径与表名)。规则正文见 doc-conventions §5「禁实现内容」。
**机器闸**:本节的结构由文档域闸「能力审计」机检——GDD 纯度(同款禁实现内容口径)、系统文档验收标准节非空、能力行四列与非空、代表用例(`文件:函数`)与真实入口可核(双通道:代码在或卡在——计划中的用例与入口由需求卡片锚定)、覆盖域表与能力行对得上、判据出处注记覆盖与指针可核(§8.3 测试函数的判据出处注记);红项按新增红处理。闸件清单与域划分的唯一出处=`tools/run_all_gates.sh` 头部。