测试层合并批(用户裁 2026-11-07): 「集成测试」层级退役归并单元层——tests/integration/ 三套件(存档⇄RNG 往返/节点图确定性/跨系统流×落盘)实体迁移 tests/unit/ 同闸同协议, run_all manifest 65 套全量单元; 闸名「单元与集成测试」→「单元测试」(run_all_gates/基线键/coverage_receipts 同步); 选闸词 integration 族→save_rng/cross_system/node_map 文件名词; 测试层识别换三元组(职责×触发时间点×覆盖面积, 权威表=test-conventions §1.1 测试层三元组), 层级名降为代称; 术语表退役词对照+doc_term 收「集成测试/用例/层/侧/宿主/族」, 全仓旧字样清零(gdd/规约/README/套件头注/断言标签), 跨系统面性质归属由各套件头注承载; extract_checks 缺省遍历面收 unit/**; test-conventions §8.2 验收四层「集成」改「跨宿主」; architecture 测试层级表三级换代+65 实数; domain_route/AGENTS 字样同步。凭据: 三套件单跑 exit=0; --code 域闸验收通过(冒烟/单元全量/系统/场景探针/渲染闸/静态扫描/熵增闸全绿); --docs 域闸验收通过(文档域七闸零新增红)
This commit is contained in:
1 parent
40a3ac1281
commit
9f80609518
28 files changed
+139
-127
No files matched your search
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
## 运行与验证(工作目录 = 含 project.godot 的切片目录)
|
## 运行与验证(工作目录 = 含 project.godot 的切片目录)
|
||||||
|
|
||||||
- **合回验证 = 前置检查 + 远端 CI(前置检查 2026-11-06 用户裁)**:主区 `git merge --no-ff` 落合并提交前,pre-merge-commit 钩子(`tools/hooks/pre-merge-commit`)自动跑 `tools/run_all_gates.sh --premerge`——冒烟测试+单元与集成测试全套件(4 分片),热导入缓存约 2 分钟;红=合并提交不落(修红后 git commit 续合,或 git merge --abort 放弃),快进合并不触发钩子,`--no-verify` 可跳过且仅属用户。git merge 合回 master 落地后,post-merge 钩子(`tools/hooks/post-merge`)自动 `git push origin master` 触发远端 CI(Gitea Actions,runner=Mac 本机 host 模式,环境自举件=`tools/ci/mac_setup.sh`),工作流(`.gitea/workflows/ci.yml`)按改动域分流(分流算法单点=`tools/ci/domain_route.sh`):游戏码批=两域全量含渲染闸,文档批=文档域秒级闸,纯闸件/管线批=零触发。远端结果**按需现查**:`tools/ci_check.sh <合并提交>` 读该提交任务的 run `status`/`conclusion`,只呈报、不落盘(2026-11-04 用户裁:合回不等待、不唤醒;判据=run 落定后的终局态,且绿须坐实跑闸步真跑过——零触发批呈报「未验」不作绿证,细则=process-conventions §1 第 3 条)。**合回落地即向用户呈报本批总结并止回合**,禁前台 sleep/轮询等 CI。CI 红态不回滚合并——红项在案、修复批合回即再推再验追绿;开工先跑现查件读 CI 状态,红未修不开新批。同一份字节禁止第二次人手跑。`tools/run_all_gates.sh` 仍是全部验证闸的**唯一入口与唯一清单,域划分与选闸算法只写在它这一个地方**,文档禁另列清单;`--code`/`--docs`/`--quick` 是开发期改完即测的选档入口(细则见 process-conventions §4),全量档不替代它。**runner 依赖**:Mac 需开机在线(关机=远端任务排队延后);换机/重装按 `tools/ci/mac_setup.sh` 自举
|
- **合回验证 = 前置检查 + 远端 CI(前置检查 2026-11-06 用户裁)**:主区 `git merge --no-ff` 落合并提交前,pre-merge-commit 钩子(`tools/hooks/pre-merge-commit`)自动跑 `tools/run_all_gates.sh --premerge`——冒烟测试+单元测试全套件(4 分片),热导入缓存约 2 分钟;红=合并提交不落(修红后 git commit 续合,或 git merge --abort 放弃),快进合并不触发钩子,`--no-verify` 可跳过且仅属用户。git merge 合回 master 落地后,post-merge 钩子(`tools/hooks/post-merge`)自动 `git push origin master` 触发远端 CI(Gitea Actions,runner=Mac 本机 host 模式,环境自举件=`tools/ci/mac_setup.sh`),工作流(`.gitea/workflows/ci.yml`)按改动域分流(分流算法单点=`tools/ci/domain_route.sh`):游戏码批=两域全量含渲染闸,文档批=文档域秒级闸,纯闸件/管线批=零触发。远端结果**按需现查**:`tools/ci_check.sh <合并提交>` 读该提交任务的 run `status`/`conclusion`,只呈报、不落盘(2026-11-04 用户裁:合回不等待、不唤醒;判据=run 落定后的终局态,且绿须坐实跑闸步真跑过——零触发批呈报「未验」不作绿证,细则=process-conventions §1 第 3 条)。**合回落地即向用户呈报本批总结并止回合**,禁前台 sleep/轮询等 CI。CI 红态不回滚合并——红项在案、修复批合回即再推再验追绿;开工先跑现查件读 CI 状态,红未修不开新批。同一份字节禁止第二次人手跑。`tools/run_all_gates.sh` 仍是全部验证闸的**唯一入口与唯一清单,域划分与选闸算法只写在它这一个地方**,文档禁另列清单;`--code`/`--docs`/`--quick` 是开发期改完即测的选档入口(细则见 process-conventions §4),全量档不替代它。**runner 依赖**:Mac 需开机在线(关机=远端任务排队延后);换机/重装按 `tools/ci/mac_setup.sh` 自举
|
||||||
- 单件直跑(=改完即测的最窄确认,其读数就是那一步的凭据;跨改动面的漏网由合回后远端全量档兜):冒烟测试 `python tools/run_smoke.py`(`game/tests/smoke_boot.tscn` 极小启动场景)· 系统测试 `python tools/run_system_test.py`(宿主 `game/tests/system_test.gd`)· 场景探针 `…console.exe --headless --path . res://probe/ui_probe.tscn` · 单元与集成 `… --script res://tests/run_all.gd`
|
- 单件直跑(=改完即测的最窄确认,其读数就是那一步的凭据;跨改动面的漏网由合回后远端全量档兜):冒烟测试 `python tools/run_smoke.py`(`game/tests/smoke_boot.tscn` 极小启动场景)· 系统测试 `python tools/run_system_test.py`(宿主 `game/tests/system_test.gd`)· 场景探针 `…console.exe --headless --path . res://probe/ui_probe.tscn` · 单元测试 `… --script res://tests/run_all.gd`
|
||||||
- 调参批量:`--script res://sim/adventure_monte_carlo.gd`(全冒险期望)· `res://sim/reward_expectation.gd`(奖励期望);关卡完成率/难度类测量一律走全冒险
|
- 调参批量:`--script res://sim/adventure_monte_carlo.gd`(全冒险期望)· `res://sim/reward_expectation.gd`(奖励期望);关卡完成率/难度类测量一律走全冒险
|
||||||
- 数值验证:`python tools/balance_verifier.py`(采集端 `res://sim/verifier_batch.gd`,报告与原始数据落 `sim-data/`)
|
- 数值验证:`python tools/balance_verifier.py`(采集端 `res://sim/verifier_batch.gd`,报告与原始数据落 `sim-data/`)
|
||||||
- 熵增闸(新类别 = 同批修订 Project Layout + 白名单):`python tools/repo_structure_audit.py`
|
- 熵增闸(新类别 = 同批修订 Project Layout + 白名单):`python tools/repo_structure_audit.py`
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
- `design/content-archive/` — 退役内容留底(活文档,2026-10-20 用户裁新立:内容已退役、留底供日后重新过准入;落内文件头部写明所属线)
|
- `design/content-archive/` — 退役内容留底(活文档,2026-10-20 用户裁新立:内容已退役、留底供日后重新过准入;落内文件头部写明所属线)
|
||||||
- `design/research/` **已退役(2026-10-21 用户裁)**——`design/` 全目录只放持久化设计文档与规范,调研/提案/评估/历史验收一律落 `reports/`(熵增闸退役路径清单已收该目录,再现即判红);`design/qa/` 已退役,验证截图不进 `design/`(判据见 doc-conventions §11)
|
- `design/research/` **已退役(2026-10-21 用户裁)**——`design/` 全目录只放持久化设计文档与规范,调研/提案/评估/历史验收一律落 `reports/`(熵增闸退役路径清单已收该目录,再现即判红);`design/qa/` 已退役,验证截图不进 `design/`(判据见 doc-conventions §11)
|
||||||
- `artwork/` — 在途图像素材唯一工作区(文档归文档/在途图归一处/终稿归游戏);整目录不入 git(.gitignore 强制),收口归档 `archive/`
|
- `artwork/` — 在途图像素材唯一工作区(文档归文档/在途图归一处/终稿归游戏);整目录不入 git(.gitignore 强制),收口归档 `archive/`
|
||||||
- `game/assets/art/` — 已验收终稿(入包被游戏加载);`game/probe/` — 场景探针的场景与宿主+探针共用面(probe_gate/render_gate 在闸+人工取证探针);`game/sim/` — 测量/诊断/模拟驱动件(autoplay 策略、MC 批量、数值验证采集端);`game/` — 游戏工程本体(代码 + tests/ 冒烟/单元/集成/系统测试面)
|
- `game/assets/art/` — 已验收终稿(入包被游戏加载);`game/probe/` — 场景探针的场景与宿主+探针共用面(probe_gate/render_gate 在闸+人工取证探针);`game/sim/` — 测量/诊断/模拟驱动件(autoplay 策略、MC 批量、数值验证采集端);`game/` — 游戏工程本体(代码 + tests/ 冒烟/单元/系统测试面)
|
||||||
- `sim-data/` — 机器读数据产物;数据件不入 git(入库例外 = README+analyze.py+growth_model.py);MC 锚与读数常驻留盘,无数值调整禁重跑
|
- `sim-data/` — 机器读数据产物;数据件不入 git(入库例外 = README+analyze.py+growth_model.py);MC 锚与读数常驻留盘,无数值调整禁重跑
|
||||||
- `tools/` — python 工具脚本(含 `hooks/`=版本化 git 钩子,经 `core.hooksPath` 挂载);`archive/` — 批次完结归档 zip(gitignored)
|
- `tools/` — python 工具脚本(含 `hooks/`=版本化 git 钩子,经 `core.hooksPath` 挂载);`archive/` — 批次完结归档 zip(gitignored)
|
||||||
- `reports/` — 过程件容器:**需求卡片**(写卡段产出,实现批的输入合同)+迭代批产出物(实现报告/GDD 反哺点清单)+设计讨论段过程稿(提案/审计/需求澄清/评估);**实现批唯一可写目录**,中间文档唯一容器(`design/research/` 已退役),不是事实源(细则见 `reports/README.md`)
|
- `reports/` — 过程件容器:**需求卡片**(写卡段产出,实现批的输入合同)+迭代批产出物(实现报告/GDD 反哺点清单)+设计讨论段过程稿(提案/审计/需求澄清/评估);**实现批唯一可写目录**,中间文档唯一容器(`design/research/` 已退役),不是事实源(细则见 `reports/README.md`)
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
2. **判断挂依据**:判断=「X 是/不是/造成了/应该」类陈述;每个判断后面必须跟依据。依据只认三种:仓库文件+行号或逐字引用(给行号就必须真读过那几行);本对话的消息号或原话;外部链接。三种都拿不出的判断必须当场标「这是推测」;说不出依据就答「不知道/没查过」,禁止编造。答复形状=结论行→依据清单→细节。
|
2. **判断挂依据**:判断=「X 是/不是/造成了/应该」类陈述;每个判断后面必须跟依据。依据只认三种:仓库文件+行号或逐字引用(给行号就必须真读过那几行);本对话的消息号或原话;外部链接。三种都拿不出的判断必须当场标「这是推测」;说不出依据就答「不知道/没查过」,禁止编造。答复形状=结论行→依据清单→细节。
|
||||||
3. **简洁**:同一意思只说一遍;能用一句不说两句。硬约束、数字、前提条件不参与压缩;信息完整与简洁冲突时保信息。
|
3. **简洁**:同一意思只说一遍;能用一句不说两句。硬约束、数字、前提条件不参与压缩;信息完整与简洁冲突时保信息。
|
||||||
4. **多角度**:介绍一个物体、一个概念、一个问题,多角度讲清楚;每角度信息点 ≤3 个,禁止违背第 3 条。
|
4. **多角度**:介绍一个物体、一个概念、一个问题,多角度讲清楚;每角度信息点 ≤3 个,禁止违背第 3 条。
|
||||||
5. **闸况呈报用闸名**:对话里报验证闸的跑批结果一律用闸名(冒烟测试/系统测试/单元与集成测试/场景探针/渲染闸等),不裸报编号。
|
5. **闸况呈报用闸名**:对话里报验证闸的跑批结果一律用闸名(冒烟测试/系统测试/单元测试/场景探针/渲染闸等),不裸报编号。
|
||||||
|
|
||||||
### 简洁细则
|
### 简洁细则
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
- 评审模式:solo(`review-mode.txt`,2026-09-12 用户拍板——TD/LP 门禁按 solo 跳过,用户授权架构产出自主推进、迭代期回调)
|
- 评审模式:solo(`review-mode.txt`,2026-09-12 用户拍板——TD/LP 门禁按 solo 跳过,用户授权架构产出自主推进、迭代期回调)
|
||||||
- 覆盖 GDD:现行全集(根索引=`design/gdd/02-系统清单.md`,文档树构成以根索引为准)
|
- 覆盖 GDD:现行全集(根索引=`design/gdd/02-系统清单.md`,文档树构成以根索引为准)
|
||||||
- 事实源地位:本文是架构事实的唯一来源——分层/所有权/数据流/API 边界/测试与质量域均以本文为准;历史决策沿革查 git commit log,不另设决策文档体系
|
- 事实源地位:本文是架构事实的唯一来源——分层/所有权/数据流/API 边界/测试与质量域均以本文为准;历史决策沿革查 git commit log,不另设决策文档体系
|
||||||
- 实现实证:`game/`(2026-09-10 起开发,**现为完整游戏开发版本,已非垂直切片**;测试层级=冒烟/单元/集成/系统四级+UI 探针与渲染 golden(2026-10-22 用户裁),闸机按改动域分跑在役)——本文档的分层/所有权/数据流均经实现验证,非纯纸面设计
|
- 实现实证:`game/`(2026-09-10 起开发,**现为完整游戏开发版本,已非垂直切片**;测试层级=冒烟/单元/系统三级+UI 探针与渲染 golden(2026-10-22 用户裁立;2026-11-07 用户裁层级合并,跨系统闭环套件归单元层),闸机按改动域分跑在役)——本文档的分层/所有权/数据流均经实现验证,非纯纸面设计
|
||||||
- 主程序可行性:跳过 — solo 模式
|
- 主程序可行性:跳过 — solo 模式
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -245,7 +245,7 @@
|
|||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| **run_smoke**(冒烟测试运行器) | `tools/run_smoke.py` | 冒烟测试总入口与判定权:headless 以项目运行目标拉起 `res://tests/smoke_boot.tscn`(极小启动场景——autoload 在位、配置表全载、主屏实例化,零逻辑判定)+ 三闸判定 | 进程退出码(0=PASS / 1=FAIL) | 三闸齐备、判定无洞:①退出码 = 0;②摘要行「[smoke] 摘要:N 项检查,0 项失败」在案且失败数为 0;③输出扫 `SCRIPT ERROR` / `Parse Error` 标记行。外部 wall-clock 超时在位(超时 = FAIL) |
|
| **run_smoke**(冒烟测试运行器) | `tools/run_smoke.py` | 冒烟测试总入口与判定权:headless 以项目运行目标拉起 `res://tests/smoke_boot.tscn`(极小启动场景——autoload 在位、配置表全载、主屏实例化,零逻辑判定)+ 三闸判定 | 进程退出码(0=PASS / 1=FAIL) | 三闸齐备、判定无洞:①退出码 = 0;②摘要行「[smoke] 摘要:N 项检查,0 项失败」在案且失败数为 0;③输出扫 `SCRIPT ERROR` / `Parse Error` 标记行。外部 wall-clock 超时在位(超时 = FAIL) |
|
||||||
| **run_system_test**(系统测试运行器) | `tools/run_system_test.py` | 系统测试总入口:headless 跑真实玩法路径断言面(宿主=`res://tests/system_test.gd`)+ 三闸判定(口径同 run_smoke,摘要行兼容两种宿主格式) | 进程退出码(0=PASS / 1=FAIL) | 三闸齐备(同 run_smoke:退出码/摘要失败数/脚本错误扫描;wall-clock 超时在位) |
|
| **run_system_test**(系统测试运行器) | `tools/run_system_test.py` | 系统测试总入口:headless 跑真实玩法路径断言面(宿主=`res://tests/system_test.gd`)+ 三闸判定(口径同 run_smoke,摘要行兼容两种宿主格式) | 进程退出码(0=PASS / 1=FAIL) | 三闸齐备(同 run_smoke:退出码/摘要失败数/脚本错误扫描;wall-clock 超时在位) |
|
||||||
| **run_all**(单元与集成测试) | `game/tests/run_all.gd` | 64 套统一入口(61 单元+3 集成,2026-10-28 实数):套件 manifest 逐条「套件 → 期望退出码」,致命类 expect=1 独立子进程实跑;`negative` 字段标负面套件(仅豁免错误扫描一闸);选跑态 `--only=<词[,词…]>`(直跑形态对套件路径子串匹配只跑命中套件,零命中=用法错 quit(2),仅供开发期最窄确认——不产闸回执、不作验收凭据,批末全量闸不经选跑分支) | 逐套件结果 + 汇总退出码(任一套件失败 quit(1)) | 套件级退出码协议在位;三硬闸齐备(入口内扫子套件输出 + 编排层扫 `unit.log`;`Kit.finish` 零断言返回专用码 2)。子进程输出须经系统命令解释器重定向落盘再读——`OS.execute` 的输出管道在本机恒空 |
|
| **run_all**(单元测试) | `game/tests/run_all.gd` | 65 套统一入口(65 单元,2026-11-07 实数——跨系统真实路径闭环 3 套件归并单元层):套件 manifest 逐条「套件 → 期望退出码」,致命类 expect=1 独立子进程实跑;`negative` 字段标负面套件(仅豁免错误扫描一闸);选跑态 `--only=<词[,词…]>`(直跑形态对套件路径子串匹配只跑命中套件,零命中=用法错 quit(2),仅供开发期最窄确认——不产闸回执、不作验收凭据,批末全量闸不经选跑分支) | 逐套件结果 + 汇总退出码(任一套件失败 quit(1)) | 套件级退出码协议在位;三硬闸齐备(入口内扫子套件输出 + 编排层扫 `unit.log`;`Kit.finish` 零断言返回专用码 2)。子进程输出须经系统命令解释器重定向落盘再读——`OS.execute` 的输出管道在本机恒空 |
|
||||||
| **probe_gate**(场景探针) | `tools/probe_gate.sh` | headless 场景探针段编排(单一形态十件恒跑):ui_input_probe / ui_struct_probe / layout_probe / ui_contrast_probe / **screen_flow_probe**(屏壳切换)/ ui_click_probe(行为走查)/ ui_probe / ui_tune_probe / t17_defer_probe / fx_probe;孤儿 Godot 预清 + 批末残留清点(必须 0) | 段级 FAIL 输出 + 汇总退出码 | 每段 timeout 守卫在位(挂死 124/137 = FAIL,不静默);判定统一走 `verdict` 函数——退出码为唯一权威判据,PASS 串降级为附加判据,逐段跑 `tools/error_scan.py` |
|
| **probe_gate**(场景探针) | `tools/probe_gate.sh` | headless 场景探针段编排(单一形态十件恒跑):ui_input_probe / ui_struct_probe / layout_probe / ui_contrast_probe / **screen_flow_probe**(屏壳切换)/ ui_click_probe(行为走查)/ ui_probe / ui_tune_probe / t17_defer_probe / fx_probe;孤儿 Godot 预清 + 批末残留清点(必须 0) | 段级 FAIL 输出 + 汇总退出码 | 每段 timeout 守卫在位(挂死 124/137 = FAIL,不静默);判定统一走 `verdict` 函数——退出码为唯一权威判据,PASS 串降级为附加判据,逐段跑 `tools/error_scan.py` |
|
||||||
| **render_gate**(视觉 golden) | `tools/render_gate.sh` | 窗口化渲染闸:①shot_probe 七屏截图 → shot_checker A-D 语义断言;②fx_shot_probe / board_shot_probe 取证(超时/零字节/文件缺失任一 = FAIL);③棋盘 golden 逐像素容差比对(差 ≤16 / changed ≤2%,provisional)+ 菜单 golden;④批末孤儿残留清零;⑤三段探针日志逐段脚本错误扫描 | 段级 FAIL 输出 + 汇总退出码 | 查退出码在位(每段 timeout 守卫 + 退出码/取证文件双检);SCRIPT ERROR 扫描在位(逐段 `tools/error_scan.py`,标记与 run_smoke 同源);断言数下限不适用(判定主体 = golden 容差与取证文件存在性,非断言计数) |
|
| **render_gate**(视觉 golden) | `tools/render_gate.sh` | 窗口化渲染闸:①shot_probe 七屏截图 → shot_checker A-D 语义断言;②fx_shot_probe / board_shot_probe 取证(超时/零字节/文件缺失任一 = FAIL);③棋盘 golden 逐像素容差比对(差 ≤16 / changed ≤2%,provisional)+ 菜单 golden;④批末孤儿残留清零;⑤三段探针日志逐段脚本错误扫描 | 段级 FAIL 输出 + 汇总退出码 | 查退出码在位(每段 timeout 守卫 + 退出码/取证文件双检);SCRIPT ERROR 扫描在位(逐段 `tools/error_scan.py`,标记与 run_smoke 同源);断言数下限不适用(判定主体 = golden 容差与取证文件存在性,非断言计数) |
|
||||||
| **static_scan**(静态扫描域) | `game/tests/static_scan.sh` | 静态扫描域 S1–S10 可执行载体(grep 规则 + `tools/audit_type_hints.py`〔S9〕+ `tools/audit_file_headers.py`〔S10〕) | fail 聚合退出码(任一硬失败规则命中即 exit 1) | 查退出码在位;SCRIPT ERROR 扫描与断言数下限不适用(逐规则命中即红,无运行时错误面与断言计数);S3 现为 warning 级、不参与 fail 判定(见下表) |
|
| **static_scan**(静态扫描域) | `game/tests/static_scan.sh` | 静态扫描域 S1–S10 可执行载体(grep 规则 + `tools/audit_type_hints.py`〔S9〕+ `tools/audit_file_headers.py`〔S10〕) | fail 聚合退出码(任一硬失败规则命中即 exit 1) | 查退出码在位;SCRIPT ERROR 扫描与断言数下限不适用(逐规则命中即红,无运行时错误面与断言计数);S3 现为 warning 级、不参与 fail 判定(见下表) |
|
||||||
@@ -301,13 +301,12 @@ S11/S12 扫描面覆盖全域,故 sim/probe/tests 的术语与旧件面**在
|
|||||||
|
|
||||||
### 三层承载与判定原则
|
### 三层承载与判定原则
|
||||||
|
|
||||||
测试分标准四级+UI 探针(2026-10-22 用户裁),各有在册承载与入闸方式(细目见 `game/tests/README.md`):
|
测试分标准三级+UI 探针(2026-10-22 用户裁立;2026-11-07 用户裁层级合并——跨系统真实路径闭环套件归单元层;识别三元组归 test-conventions §1.1),各有在册承载与入闸方式(细目见 `game/tests/README.md`):
|
||||||
|
|
||||||
| 层 | 判什么 | 承载 | 入闸 |
|
| 层 | 判什么 | 承载 | 入闸 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 冒烟测试 | 这版活着吗(零逻辑判定) | `game/tests/smoke_boot.tscn/.gd` | `run_smoke.py`(冒烟测试闸) |
|
| 冒烟测试 | 这版活着吗(零逻辑判定) | `game/tests/smoke_boot.tscn/.gd` | `run_smoke.py`(冒烟测试闸) |
|
||||||
| 单元测试 | 领域类的原子行为对不对(从对外方法进、钉对外可观测面——写法判据归 test-conventions §8.2) | `game/tests/unit/` | `run_all.gd`(单元与集成测试闸) |
|
| 单元测试 | 受控裸环境断言面:领域类原子行为+跨系统真实路径闭环(从对外方法进、钉对外可观测面——写法判据归 test-conventions §8.2) | `game/tests/unit/` | `run_all.gd`(单元测试闸) |
|
||||||
| 集成测试 | 跨系统闭环对不对 | `game/tests/integration/` | 同上(同一入口同一协议) |
|
|
||||||
| 系统测试 | 真实玩法路径断言面 | `game/tests/system_test.gd` | `run_system_test.py`(系统测试闸) |
|
| 系统测试 | 真实玩法路径断言面 | `game/tests/system_test.gd` | `run_system_test.py`(系统测试闸) |
|
||||||
| UI 探针+渲染 golden | 场景切换与观感 | `game/probe/*.tscn` 探针 | `probe_gate.sh`(场景探针闸)、`render_gate.sh`(渲染闸) |
|
| UI 探针+渲染 golden | 场景切换与观感 | `game/probe/*.tscn` 探针 | `probe_gate.sh`(场景探针闸)、`render_gate.sh`(渲染闸) |
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
10. **`# rng-seed-exempt` 标记豁免通道**——S1/S2 随机函数扫描对该行豁免;限定用途=非玩法 RNG 消费面的引擎熵(现行例:组合根种子编辑框空态取 `randi()`——建种子不进玩法封闭流);非产品码三目录自建随机源的定种要求见第 13 条。
|
10. **`# rng-seed-exempt` 标记豁免通道**——S1/S2 随机函数扫描对该行豁免;限定用途=非玩法 RNG 消费面的引擎熵(现行例:组合根种子编辑框空态取 `randi()`——建种子不进玩法封闭流);非产品码三目录自建随机源的定种要求见第 13 条。
|
||||||
11. **`--script` 模式禁裸 autoload 标识符**——`ConfigDB`/`RngService` 等 autoload 名在 `--headless --script` 模式编译器不解析(parse error);产品码与测试夹具一律经节点路径取用(`get_node("/root/…")`/`AUTOLOAD_PATH_*` 常量);静态扫描域 S5 硬失败承载在位。
|
11. **`--script` 模式禁裸 autoload 标识符**——`ConfigDB`/`RngService` 等 autoload 名在 `--headless --script` 模式编译器不解析(parse error);产品码与测试夹具一律经节点路径取用(`get_node("/root/…")`/`AUTOLOAD_PATH_*` 常量);静态扫描域 S5 硬失败承载在位。
|
||||||
12. **Variant 参数化现行口径**——账本类字典/数组标注 `Dictionary[Variant, Variant]`/`Array[Variant]` 即合格(满足 R1);元素类型精化列后续事项、不入硬纪律,口径变更须用户裁决后续批次另行写入。
|
12. **Variant 参数化现行口径**——账本类字典/数组标注 `Dictionary[Variant, Variant]`/`Array[Variant]` 即合格(满足 R1);元素类型精化列后续事项、不入硬纪律,口径变更须用户裁决后续批次另行写入。
|
||||||
13. **静态扫描适用域按来源分档(2026-11-03 架构审查 P1 余项裁)**——S 系静态扫描(S1–S13)的扫描面一律止于产品码三目录,`game/tests`/`game/probe`/`game/sim` 不进任何 S 系扫描面;这三目录的可靠性由运行期通道承接,各通道是:`game/tests`=冒烟·单元与集成·系统测试三闸、`game/probe`=场景探针与渲染 golden 两闸(同目录内 `type_glow_shot_probe` 是人工取证件、`probe_ui_util` 是探针共用面,两者不入闸)、`game/sim`=不入 CI,属用户手动发起的调参与数值测量批量。三目录**允许**自建 `RandomNumberGenerator`,条件=**必须显式定种**(改前改后读数要用同种子对拍,这是全项目测量口径);三目录真正禁止的形态是不定种随机——`randomize()` 与全局 `randi()`/`randf()`/`randf_range()`,一旦命中那次运行结果不可复现,读数与取证一并失效。这条对三目录的部分目前**无机器闸**(S1/S2 扫描面不含它们):扩面需给每处合法定种挂 `rng-seed-exempt` 注记、只拦得住新增,2026-11-03 用户裁不扩,改由本条文字+批末独立验收审计的人工评审承载。术语口径:`tools/run_all_gates.sh` 里的「测量面」指 `game/tests`+`game/sim`(影响面选闸用语,`game/probe` 不在其中——改探针必须跑场景探针与渲染闸),与本条分档无关;本文不再用「测量面」统称这三个目录。
|
13. **静态扫描适用域按来源分档(2026-11-03 架构审查 P1 余项裁)**——S 系静态扫描(S1–S13)的扫描面一律止于产品码三目录,`game/tests`/`game/probe`/`game/sim` 不进任何 S 系扫描面;这三目录的可靠性由运行期通道承接,各通道是:`game/tests`=冒烟·单元·系统测试三闸、`game/probe`=场景探针与渲染 golden 两闸(同目录内 `type_glow_shot_probe` 是人工取证件、`probe_ui_util` 是探针共用面,两者不入闸)、`game/sim`=不入 CI,属用户手动发起的调参与数值测量批量。三目录**允许**自建 `RandomNumberGenerator`,条件=**必须显式定种**(改前改后读数要用同种子对拍,这是全项目测量口径);三目录真正禁止的形态是不定种随机——`randomize()` 与全局 `randi()`/`randf()`/`randf_range()`,一旦命中那次运行结果不可复现,读数与取证一并失效。这条对三目录的部分目前**无机器闸**(S1/S2 扫描面不含它们):扩面需给每处合法定种挂 `rng-seed-exempt` 注记、只拦得住新增,2026-11-03 用户裁不扩,改由本条文字+批末独立验收审计的人工评审承载。术语口径:`tools/run_all_gates.sh` 里的「测量面」指 `game/tests`+`game/sim`(影响面选闸用语,`game/probe` 不在其中——改探针必须跑场景探针与渲染闸),与本条分档无关;本文不再用「测量面」统称这三个目录。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
主工作区(master 检出)只作合并落点,一切开发/设计改动禁止直接发生在主工作区(2026-10-31 用户裁恢复;验证模型=批内按 §4 改完即测、合回后远端 CI 是唯一强制全量验证点,细则见本节第 3 条):
|
主工作区(master 检出)只作合并落点,一切开发/设计改动禁止直接发生在主工作区(2026-10-31 用户裁恢复;验证模型=批内按 §4 改完即测、合回后远端 CI 是唯一强制全量验证点,细则见本节第 3 条):
|
||||||
|
|
||||||
1. **worktree 车道(一切面)**:每回合先建独立 worktree(建区粒度=回合,会话单区细则见第 5 条):`git worktree add ../g-plan2-<任务名> -b <任务分支>`;建区后立刻跑 `tools/setup_worktree_userdir.sh`——给该区独立 Godot user 目录(测试夹具、试玩日志、截图产物不与其他区共用;主区不生成,真实档保持原位)。所有改动与提交都在 worktree 内自由进行——commit 点零钩子检查(`tools/hooks/pre-commit` 已删除)。豁免面仅 `.zcode/`(钩子与配置)与 `.qoder/`(本机 harness 配置)允许主工作区直改——两份实测均不入 git(走 worktree 反而带不进去,改动只对本机生效)
|
1. **worktree 车道(一切面)**:每回合先建独立 worktree(建区粒度=回合,会话单区细则见第 5 条):`git worktree add ../g-plan2-<任务名> -b <任务分支>`;建区后立刻跑 `tools/setup_worktree_userdir.sh`——给该区独立 Godot user 目录(测试夹具、试玩日志、截图产物不与其他区共用;主区不生成,真实档保持原位)。所有改动与提交都在 worktree 内自由进行——commit 点零钩子检查(`tools/hooks/pre-commit` 已删除)。豁免面仅 `.zcode/`(钩子与配置)与 `.qoder/`(本机 harness 配置)允许主工作区直改——两份实测均不入 git(走 worktree 反而带不进去,改动只对本机生效)
|
||||||
2. **收口顺序(固定)**:**冻结 → 件核 → 并 master → 重塑 → 主区合回 → 删区**——代码与断言改完即冻结,全仓件核 grep 查残留;master 已被别的批次推进时先在 worktree 内 `git merge master` 解冲突(必须在合回之前,合回后才并=CI 验的是中间态);**重塑**=迭代分支(iter<N> 形)合回前执行 `python tools/reshape_cards.py`,把分支线性史按卡末态快照压成一卡一笔(可选追加一笔纯文档收尾),master 台账由此每卡一行——工具自带「重塑前后树逐字节一致」断言与 backup 分支,不改任何文件内容;非迭代批免重塑;然后主工作区 `git merge --no-ff <任务分支>`(pre-merge-commit 钩子先跑前置检查——冒烟+单元与集成全套件约 2 分钟,红则停合并提交,细则见第 4 条 ③)——这是主区唯一合法写动作(合回守卫对迭代分支数卡校验,未归卡提交拦下)。**合回落地即 `git worktree remove`+删分支(合回即删,2026-09-19 原裁);post-merge 钩子已在合回落地时自动触发 CI,红态不回滚合并——新开修复 worktree(`fix-<任务名>` 分支,非 iter<N> 形免重塑免数卡)修复提交再合,落地复验追绿后删修复区**。批内的验证义务按 §4 改完即测铁规履行——改完即测自己改过的那部分,不请示、不等点名;收口顺序本身不设跑批关口。**卡片复核前置判据(2026-11-05 用户裁)**:需求卡片的 grilling 复核先于卡片提交、卡片提交先于合回——复核未跑完、缺陷清单未裁完,禁把卡片落 commit(落了也不算成立),`master` 永不落未成立卡;本条与 §2 段三出口铁律、doc-conventions §12.1「已写卡」凭据同判。
|
2. **收口顺序(固定)**:**冻结 → 件核 → 并 master → 重塑 → 主区合回 → 删区**——代码与断言改完即冻结,全仓件核 grep 查残留;master 已被别的批次推进时先在 worktree 内 `git merge master` 解冲突(必须在合回之前,合回后才并=CI 验的是中间态);**重塑**=迭代分支(iter<N> 形)合回前执行 `python tools/reshape_cards.py`,把分支线性史按卡末态快照压成一卡一笔(可选追加一笔纯文档收尾),master 台账由此每卡一行——工具自带「重塑前后树逐字节一致」断言与 backup 分支,不改任何文件内容;非迭代批免重塑;然后主工作区 `git merge --no-ff <任务分支>`(pre-merge-commit 钩子先跑前置检查——冒烟+单元全套件约 2 分钟,红则停合并提交,细则见第 4 条 ③)——这是主区唯一合法写动作(合回守卫对迭代分支数卡校验,未归卡提交拦下)。**合回落地即 `git worktree remove`+删分支(合回即删,2026-09-19 原裁);post-merge 钩子已在合回落地时自动触发 CI,红态不回滚合并——新开修复 worktree(`fix-<任务名>` 分支,非 iter<N> 形免重塑免数卡)修复提交再合,落地复验追绿后删修复区**。批内的验证义务按 §4 改完即测铁规履行——改完即测自己改过的那部分,不请示、不等点名;收口顺序本身不设跑批关口。**卡片复核前置判据(2026-11-05 用户裁)**:需求卡片的 grilling 复核先于卡片提交、卡片提交先于合回——复核未跑完、缺陷清单未裁完,禁把卡片落 commit(落了也不算成立),`master` 永不落未成立卡;本条与 §2 段三出口铁律、doc-conventions §12.1「已写卡」凭据同判。
|
||||||
3. **合回后验证(远端 CI,2026-11-03 用户裁)**:git merge 合回 master 落地后 post-merge 钩子(`tools/hooks/post-merge`)自动 `git push origin master` 触发远端 CI(Gitea Actions,runner=Mac 本机 host 模式),工作流按改动域分流(分流算法单点=`tools/ci/domain_route.sh`:游戏码批=两域全量含渲染闸,文档批=文档域秒级闸,纯闸件/管线批=零触发)——唯一强制全量验证点。远端结果用 `tools/ci_check.sh <合并提交>` 按需现查(读该提交任务的 run 自身 `status`/`conclusion`,只呈报、不落盘),agent 开工先读 CI 状态的纪律不变,红未修不开新批。**绿须坐实**:零触发批的 run 照样建、照样 conclusion=success,但跑闸步是 `skipped`(run 55 实证)——一条闸都没跑不构成验证,现查件对此呈报「未验」(退出码 4),禁当绿证用;job 列表为空、取不到步级读数或工作流里没有跑闸步时呈报「不可判」,同样禁当绿证。CI 红态不回滚合并——修复走新开修复 worktree(`fix-<任务名>` 分支,非 iter<N> 形免重塑免数卡),修复合回落地即再推再验追绿(追绿同链)。导入缓存刷新(.godot 不入 git 的在册坑)由工作流「导入缓存刷新」步接管。**合回零等待纪律(2026-11-04 用户裁,取代 2026-11-02 回执等待纪律)**:合回落地即向用户呈报本批总结并止回合——不挂后台轮询、不等回执、不被唤醒;CI 结论什么时候要看就现查一次(`tools/ci_check.sh`,run 那时早已落定,秒级)。退役缘由=原轮询件把「commit status 离开 pending」当终局判据,会把 run 未落定期的尝试级失败写成终局红(run 37 实证:开跑 36 秒写红,该 run 三分半后 `conclusion=success`),且零触发批与 runner 排队必熬满超时再写红;同 commit 的多路轮询还重复覆写同一份判定。跑闸等一切分钟级跑批的等待纪律不变——后台运行,禁前台 sleep/轮询循环。
|
3. **合回后验证(远端 CI,2026-11-03 用户裁)**:git merge 合回 master 落地后 post-merge 钩子(`tools/hooks/post-merge`)自动 `git push origin master` 触发远端 CI(Gitea Actions,runner=Mac 本机 host 模式),工作流按改动域分流(分流算法单点=`tools/ci/domain_route.sh`:游戏码批=两域全量含渲染闸,文档批=文档域秒级闸,纯闸件/管线批=零触发)——唯一强制全量验证点。远端结果用 `tools/ci_check.sh <合并提交>` 按需现查(读该提交任务的 run 自身 `status`/`conclusion`,只呈报、不落盘),agent 开工先读 CI 状态的纪律不变,红未修不开新批。**绿须坐实**:零触发批的 run 照样建、照样 conclusion=success,但跑闸步是 `skipped`(run 55 实证)——一条闸都没跑不构成验证,现查件对此呈报「未验」(退出码 4),禁当绿证用;job 列表为空、取不到步级读数或工作流里没有跑闸步时呈报「不可判」,同样禁当绿证。CI 红态不回滚合并——修复走新开修复 worktree(`fix-<任务名>` 分支,非 iter<N> 形免重塑免数卡),修复合回落地即再推再验追绿(追绿同链)。导入缓存刷新(.godot 不入 git 的在册坑)由工作流「导入缓存刷新」步接管。**合回零等待纪律(2026-11-04 用户裁,取代 2026-11-02 回执等待纪律)**:合回落地即向用户呈报本批总结并止回合——不挂后台轮询、不等回执、不被唤醒;CI 结论什么时候要看就现查一次(`tools/ci_check.sh`,run 那时早已落定,秒级)。退役缘由=原轮询件把「commit status 离开 pending」当终局判据,会把 run 未落定期的尝试级失败写成终局红(run 37 实证:开跑 36 秒写红,该 run 三分半后 `conclusion=success`),且零触发批与 runner 排队必熬满超时再写红;同 commit 的多路轮询还重复覆写同一份判定。跑闸等一切分钟级跑批的等待纪律不变——后台运行,禁前台 sleep/轮询循环。
|
||||||
4. **执法分层(全机械,零自觉依赖)**:①`.zcode/hooks/worktree-guard.sh`(PreToolUse,本机件不入 git)——agent 侧:主工作区 Edit/Write 与主区非 merge `git commit` 拦截(豁免 `.zcode/`、`.qoder/`;worktree 内目标快速放行;合并收尾提交凭 MERGE_HEAD 豁免)、`git commit --no-verify` 拦截(该旗标仅属用户)、iter<N> 分支合回的一卡一提交数卡校验、规则闸(写 design//game/ 前核对会话规约读取记录)。②post-merge 钩子——远端 CI 触发(只推送,不挂等待;仅主工作区,任务 worktree 内的合并不触发)。③git 层钩子=合回链两件:pre-merge-commit(合回前置检查,2026-11-06 用户裁:主区 merge 落合并提交前自动跑 `tools/run_all_gates.sh --premerge`=冒烟+单元与集成全套件 4 分片,热导入缓存约 2 分钟;exit≠0 拦合并提交不拦合并动作——红态仓库停 MERGE_HEAD 态,修红 git commit 续合或 git merge --abort 放弃;快进合并不触发;--no-verify 可跳过且仅属用户)+post-merge(远端 CI 触发,只推送,不挂等待);合回链之外 git 层不设车道钩子——用户手工改动不受限;ZCode 层只约束 agent(子代理不经守卫层)
|
4. **执法分层(全机械,零自觉依赖)**:①`.zcode/hooks/worktree-guard.sh`(PreToolUse,本机件不入 git)——agent 侧:主工作区 Edit/Write 与主区非 merge `git commit` 拦截(豁免 `.zcode/`、`.qoder/`;worktree 内目标快速放行;合并收尾提交凭 MERGE_HEAD 豁免)、`git commit --no-verify` 拦截(该旗标仅属用户)、iter<N> 分支合回的一卡一提交数卡校验、规则闸(写 design//game/ 前核对会话规约读取记录)。②post-merge 钩子——远端 CI 触发(只推送,不挂等待;仅主工作区,任务 worktree 内的合并不触发)。③git 层钩子=合回链两件:pre-merge-commit(合回前置检查,2026-11-06 用户裁:主区 merge 落合并提交前自动跑 `tools/run_all_gates.sh --premerge`=冒烟+单元全套件 4 分片,热导入缓存约 2 分钟;exit≠0 拦合并提交不拦合并动作——红态仓库停 MERGE_HEAD 态,修红 git commit 续合或 git merge --abort 放弃;快进合并不触发;--no-verify 可跳过且仅属用户)+post-merge(远端 CI 触发,只推送,不挂等待);合回链之外 git 层不设车道钩子——用户手工改动不受限;ZCode 层只约束 agent(子代理不经守卫层)
|
||||||
5. **会话单区(2026-11-04 用户裁)**:建区粒度=回合——同一时刻每会话至多一个 worktree 在役;合入删区之前,会话内用户追加的事项一律并入在役区推进,禁为追加事项另开新区。区内全部事项完成后只做一次合入(一次 `git merge --no-ff`、post-merge 一次推送、远端 CI 只跑一次),追加事项在合入提交信息里分列;无改动需求的事项不建区。合回删区后用户再发令的事项=新回合,另开新区(区名取该回合主任务名)。CI 红的 `fix-<任务名>` 修复区属同一回合的追绿延续,不另算新区。迭代实现批(iter<N> 形分支)独占回合——其他类事项不得并入迭代区(合回守卫数卡校验本就拦未归卡提交),待其合回后按新回合另开。
|
5. **会话单区(2026-11-04 用户裁)**:建区粒度=回合——同一时刻每会话至多一个 worktree 在役;合入删区之前,会话内用户追加的事项一律并入在役区推进,禁为追加事项另开新区。区内全部事项完成后只做一次合入(一次 `git merge --no-ff`、post-merge 一次推送、远端 CI 只跑一次),追加事项在合入提交信息里分列;无改动需求的事项不建区。合回删区后用户再发令的事项=新回合,另开新区(区名取该回合主任务名)。CI 红的 `fix-<任务名>` 修复区属同一回合的追绿延续,不另算新区。迭代实现批(iter<N> 形分支)独占回合——其他类事项不得并入迭代区(合回守卫数卡校验本就拦未归卡提交),待其合回后按新回合另开。
|
||||||
|
|
||||||
## 2. 五段流水线
|
## 2. 五段流水线
|
||||||
|
|||||||
@@ -13,6 +13,20 @@
|
|||||||
核心层验收标准通过不算有测试:GDScript 编译不查字典字段与时序,呈现层错误只在运行时暴露。
|
核心层验收标准通过不算有测试: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. 场景级探针标配
|
## 2. 场景级探针标配
|
||||||
|
|
||||||
每新增一个可交互 UI 区域(视图/覆盖层/面板),必须配套场景级 headless 探针:
|
每新增一个可交互 UI 区域(视图/覆盖层/面板),必须配套场景级 headless 探针:
|
||||||
@@ -29,7 +43,7 @@
|
|||||||
|
|
||||||
## 4. 验证时机(合回后远端 CI 制,2026-11-03 换代)
|
## 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)。同一份字节禁止第二次人手跑。该脚本是全部验证闸的唯一入口与唯一清单,域划分与选闸算法只写在脚本里,本文禁另列闸件清单。
|
开发期义务=`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. 测试函数怎么写——验收清单条目的落码规范
|
## 5. 测试函数怎么写——验收清单条目的落码规范
|
||||||
@@ -81,7 +95,7 @@
|
|||||||
|
|
||||||
- **单元**:不依赖场景树和真实宿主的纯逻辑;测试从领域类的对外方法进出,断言钉对外可观测面(返回值/信号/查询接口/落盘内容)。内部字段直查=受控例外:仅当该行为没有公开可观测面可钉时允许,对照表该行注明理由;存量不回头清扫,被批次触碰时顺带换代。探针直读视口承载子件结构(画布取视口首子件、渐隐带两片与平移提示子件按名取)属此类——断言对象即承载结构本身,无公开可观测面可钉,理由随对照表行申报。
|
- **单元**:不依赖场景树和真实宿主的纯逻辑;测试从领域类的对外方法进出,断言钉对外可观测面(返回值/信号/查询接口/落盘内容)。内部字段直查=受控例外:仅当该行为没有公开可观测面可钉时允许,对照表该行注明理由;存量不回头清扫,被批次触碰时顺带换代。探针直读视口承载子件结构(画布取视口首子件、渐隐带两片与平移提示子件按名取)属此类——断言对象即承载结构本身,无公开可观测面可钉,理由随对照表行申报。
|
||||||
- **接口**:模块边界的公开契约——数据表加载、存档与断点、事件载荷、命令接口;测试从公开入口进出。接口级断言随单元套件落(`unit/contracts/`),不另设承载目录。
|
- **接口**:模块边界的公开契约——数据表加载、存档与断点、事件载荷、命令接口;测试从公开入口进出。接口级断言随单元套件落(`unit/contracts/`),不另设承载目录。
|
||||||
- **集成**:跨宿主的接线、持久、生命周期——例如 LevelRunner 把 level_counters 传给 BattleOrchestrator、两场战斗共享同一个桶、断点续玩;测试必须实例化真实宿主链,禁止用裸 EffectEngine 代替。
|
- **跨宿主**:跨宿主的接线、持久、生命周期——例如 LevelRunner 把 level_counters 传给 BattleOrchestrator、两场战斗共享同一个桶、断点续玩;测试必须实例化真实宿主链,禁止用裸 EffectEngine 代替。断言载体归单元层跨系统闭环套件(§1.1 三元组表),验收入口不变。
|
||||||
- **探针/golden**:玩家可达性与观感;真实实例化场景、驱动真实输入。
|
- **探针/golden**:玩家可达性与观感;真实实例化场景、驱动真实输入。
|
||||||
- **golden 测试项扩项(2026-11-05 立)**:触碰画面呈现规格的需求批(新增画面要素/布局/配色/动效;判据=设计段出了预览图),实现段把该画面纳入渲染闸机器面:截图采集清单扩项+实跑截图冻结进 `game/tests/golden/`(基线属入库测试资产,render_gate.sh 在册例外)。黄金图=游戏真实渲染截屏冻结的逐像素基准,比对器与容差口径见 render_gate.sh 头注释(脚本即清单,本文不另列)。基线冻结(新建与换代同口径)=用户对照设计段预览图确认后执行,触发原因写进当批提交说明(`tools/golden_baseline_refresh.sh` 现役义务);此后渲染闸逐像素自动盯、零人工。预览图(HTML/SVG 效果图)与引擎渲染是两套管线,禁直接充当比对基线——预览图只作人审参照与验收判据句的出处(判据出处行锚指向 ux/ 内嵌预览节);缺陷修复以现行规格与在库基线为准,不触发新预览。
|
- **golden 测试项扩项(2026-11-05 立)**:触碰画面呈现规格的需求批(新增画面要素/布局/配色/动效;判据=设计段出了预览图),实现段把该画面纳入渲染闸机器面:截图采集清单扩项+实跑截图冻结进 `game/tests/golden/`(基线属入库测试资产,render_gate.sh 在册例外)。黄金图=游戏真实渲染截屏冻结的逐像素基准,比对器与容差口径见 render_gate.sh 头注释(脚本即清单,本文不另列)。基线冻结(新建与换代同口径)=用户对照设计段预览图确认后执行,触发原因写进当批提交说明(`tools/golden_baseline_refresh.sh` 现役义务);此后渲染闸逐像素自动盯、零人工。预览图(HTML/SVG 效果图)与引擎渲染是两套管线,禁直接充当比对基线——预览图只作人审参照与验收判据句的出处(判据出处行锚指向 ux/ 内嵌预览节);缺陷修复以现行规格与在库基线为准,不触发新预览。
|
||||||
|
|
||||||
|
|||||||
@@ -174,7 +174,7 @@
|
|||||||
|
|
||||||
| 优先级 | 内容 | 后置原因 |
|
| 优先级 | 内容 | 后置原因 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| P1 | 战斗级可回放集成测试(同主种子同动作序列,步骤流逐行相同) | 需战斗域载体,随[战斗结算](../战斗循环/战斗结算.md)回放验收兑现 |
|
| P1 | 战斗级可回放闭环测试(同主种子同动作序列,步骤流逐行相同) | 需战斗域载体,随[战斗结算](../战斗循环/战斗结算.md)回放验收兑现 |
|
||||||
| P1 | 难度曲线导出工具(无窗口导出行解析矩阵供比对) | 难度审计的离线载体,[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)期交付物 |
|
| P1 | 难度曲线导出工具(无窗口导出行解析矩阵供比对) | 难度审计的离线载体,[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)期交付物 |
|
||||||
| P2 | 正式包构建的致命表现验证与调试覆盖结构性不存在验证 | 挂首次正式导出检查清单 |
|
| P2 | 正式包构建的致命表现验证与调试覆盖结构性不存在验证 | 挂首次正式导出检查清单 |
|
||||||
| P2 | 进度键表的调试覆盖行寻址语法 | 调试覆盖现只支持单行全局表字段,行寻址登记为后续扩展 |
|
| P2 | 进度键表的调试覆盖行寻址语法 | 调试覆盖现只支持单行全局表字段,行寻址登记为后续扩展 |
|
||||||
|
|||||||
@@ -179,6 +179,7 @@
|
|||||||
| 罕见(档位名) | 稀有(2026-10-26 用户裁入表:旧三档档位名,现行四级第三档=稀有;散文形容词义不受限) |
|
| 罕见(档位名) | 稀有(2026-10-26 用户裁入表:旧三档档位名,现行四级第三档=稀有;散文形容词义不受限) |
|
||||||
| 通关 | 关卡完成(单关)/冒险成功(整局)——2026-10-26 用户裁:主体明确短语族替代歧义单义词 |
|
| 通关 | 关卡完成(单关)/冒险成功(整局)——2026-10-26 用户裁:主体明确短语族替代歧义单义词 |
|
||||||
| 冒险终结 | 冒险落幕——2026-10-26 通关口径统一批 |
|
| 冒险终结 | 冒险落幕——2026-10-26 通关口径统一批 |
|
||||||
|
| 集成测试 / 集成用例 / 集成层 / 集成侧 / 集成宿主 / 集成族 | 单元测试(2026-11-07 用户裁层级合并——跨系统真实路径闭环套件归单元层,三套件实体迁移 tests/unit/;测试层识别靠三元组〔职责×触发时间点×覆盖面积,权威表=test-conventions「测试层三元组」节〕,层级名只是代称;闭环套件的性质归属由各套件头注承载) |
|
||||||
|
|
||||||
## 对外命名纪律(玩家可见命名,2026-10-11 用户令)
|
## 对外命名纪律(玩家可见命名,2026-10-11 用户令)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://c40h84iqkhwep
|
||||||
@@ -57,13 +57,13 @@
|
|||||||
"exit": "0",
|
"exit": "0",
|
||||||
"fp": "green"
|
"fp": "green"
|
||||||
},
|
},
|
||||||
"单元与集成测试": {
|
"闸壳自检": {
|
||||||
"exit": "0",
|
"exit": "0",
|
||||||
"fp": "green"
|
"fp": "green"
|
||||||
},
|
},
|
||||||
"闸壳自检": {
|
"单元测试": {
|
||||||
"exit": "0",
|
"exit": "0",
|
||||||
"fp": "green"
|
"fp": "green"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+29
-34
@@ -1,7 +1,7 @@
|
|||||||
# Test Manual — Dungeon Sweeper(测试工具手册)
|
# Test Manual — Dungeon Sweeper(测试工具手册)
|
||||||
|
|
||||||
**Engine**: Godot 4.7.2-stable(GDScript 单语言)
|
**Engine**: Godot 4.7.2-stable(GDScript 单语言)
|
||||||
**Test Framework**: 标准四级测试层(冒烟/单元/集成/系统)+ headless 场景探针与渲染 golden;gdUnit4 **deferred**(D2 OQ1 关闭形态——本仓库不引第三方测试框架,需求见下「门禁」节)
|
**Test Framework**: 标准测试层(冒烟/单元/系统)+ headless 场景探针与渲染 golden——层识别三元组(职责×触发时间点×覆盖面积)的权威表=test-conventions「测试层三元组」节,层级名只是代称;gdUnit4 **deferred**(D2 OQ1 关闭形态——本仓库不引第三方测试框架,需求见下「门禁」节)
|
||||||
**门禁**: 本地闸——`tools/run_all_gates.sh`(收口唯一验收入口,按改动域选档 `--code`/`--docs`,跨两域或改闸件本身不带参数=全量;代码域 02 按关联档选套件,算法与套件族映射表只在脚本内定义)。本仓库**无远端、无 CI**(`.github/workflows/` 已删除,不建不留不参考);闸清单与域划分只在本脚本定义,文档不另列
|
**门禁**: 本地闸——`tools/run_all_gates.sh`(收口唯一验收入口,按改动域选档 `--code`/`--docs`,跨两域或改闸件本身不带参数=全量;代码域 02 按关联档选套件,算法与套件族映射表只在脚本内定义)。本仓库**无远端、无 CI**(`.github/workflows/` 已删除,不建不留不参考);闸清单与域划分只在本脚本定义,文档不另列
|
||||||
**Setup date**: 2026-09-12
|
**Setup date**: 2026-09-12
|
||||||
**参考实现**: `game/probe/`(场景探针族)· `game/sim/`(测量/诊断/模拟驱动件)(场景探针族——正式工程的活样板;系统测试断言面过渡宿主 `smoke_all.gd` 亦在此,迁移归断言迁移批)
|
**参考实现**: `game/probe/`(场景探针族)· `game/sim/`(测量/诊断/模拟驱动件)(场景探针族——正式工程的活样板;系统测试断言面过渡宿主 `smoke_all.gd` 亦在此,迁移归断言迁移批)
|
||||||
@@ -15,32 +15,28 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
tests/
|
tests/
|
||||||
unit/ # 单元测试(公式/状态机/纯逻辑,隔离断言)——extends SceneTree + quit(code)
|
unit/ # 单元测试(公式/状态机/纯逻辑隔离断言+跨系统真实路径闭环,同一环境同一协议)——extends SceneTree + quit(code)
|
||||||
integration/ # 集成测试(跨系统闭环——与 unit/ 同一入口同一协议,见下「测试层级」节)
|
|
||||||
smoke_boot.tscn/.gd # 冒烟测试——极小启动场景(真实开机路径存活检查)
|
smoke_boot.tscn/.gd # 冒烟测试——极小启动场景(真实开机路径存活检查)
|
||||||
system_test.gd # 系统测试宿主薄壳(SceneTree+构造注入;断言迁移批后承接 smoke_all.gd)
|
system_test.gd # 系统测试宿主薄壳(SceneTree+构造注入)
|
||||||
smoke/ # critical-paths.md——人工 gate 清单(/smoke-check 读取)
|
smoke/ # critical-paths.md——人工 gate 清单(/smoke-check 读取)
|
||||||
evidence/ # 截图与人工签核记录
|
evidence/ # 截图与人工签核记录
|
||||||
run_all.gd # 单元与集成测试统一入口(套件 manifest 协议,D2 AC-2b)
|
run_all.gd # 单元测试统一入口(套件 manifest 协议,D2 AC-2b)
|
||||||
static_scan.sh # 静态扫描域 S1–S12 可执行子集
|
static_scan.sh # 静态扫描域 S1–S12 可执行子集
|
||||||
```
|
```
|
||||||
|
|
||||||
## 测试层级(标准四级+UI 探针)
|
## 测试层级(标准三级+UI 探针;识别三元组见 test-conventions「测试层三元组」节)
|
||||||
|
|
||||||
| 层 | 判什么 | 承载 | 入闸方式 |
|
| 层 | 判什么 | 承载 | 入闸方式 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| **冒烟测试** | 这版活着吗——能否启动、能否加载表、能否进主屏。零逻辑判定 | `tests/smoke_boot.tscn/.gd`(以项目运行目标拉起=真实开机路径) | `run_smoke.py`(冒烟测试闸) |
|
| **冒烟测试** | 这版活着吗——能否启动、能否加载表、能否进主屏。零逻辑判定 | `tests/smoke_boot.tscn/.gd`(以项目运行目标拉起=真实开机路径) | `run_smoke.py`(冒烟测试闸) |
|
||||||
| **单元测试** | 领域类的原子行为对不对(公式/状态机/纯逻辑)——从对外方法进、断言钉对外可观测面(写法判据见 test-conventions §8.2) | `tests/unit/` | `run_all.gd` manifest(单元与集成测试闸) |
|
| **单元测试** | 受控裸环境断言面——单机制契约(公式/状态机/纯逻辑,从对外方法进、断言钉对外可观测面,写法判据见 test-conventions §8.2)+跨系统真实路径闭环(两以上真实系统手工装配×落盘/落库往返) | `tests/unit/` | `run_all.gd` manifest(单元测试闸) |
|
||||||
| **集成测试** | 跨系统的闭环对不对 | `tests/integration/` | 同上(与单元测试同一入口、同一协议) |
|
| **系统测试** | 启动真实工程走真实玩法路径 | `tests/system_test.gd` | `run_system_test.py`(系统测试闸) |
|
||||||
| **系统测试** | 启动真实工程走真实玩法路径 | 过渡期 `game/probe/smoke_all.gd`(断言迁移批后=`tests/system_test.gd`) | `run_system_test.py`(系统测试闸) |
|
|
||||||
| **UI 探针+渲染 golden** | 跑起来之后 UI 与场景切换对不对;画面基线 | `game/probe/*.tscn` 探针 | `probe_gate.sh`(场景探针闸)、`render_gate.sh`(渲染闸) |
|
| **UI 探针+渲染 golden** | 跑起来之后 UI 与场景切换对不对;画面基线 | `game/probe/*.tscn` 探针 | `probe_gate.sh`(场景探针闸)、`render_gate.sh`(渲染闸) |
|
||||||
|
|
||||||
> **integration/ 已建承载**。
|
> **分层判据(2026-11-07 用户裁层级合并)**:能不能在 `--script` 模式下不加载开机装配(autoload)就验完?
|
||||||
> 首个集成用例 = `save_rng_roundtrip_test.gd`(存档⇄RNG 快照往返)。章程登记的四类集成用例里,
|
> 能 = 单元测试——单机制契约(一个领域类+注入依赖)与跨系统真实路径闭环(两以上真实系统手工装配×落盘/落库
|
||||||
> Core-Core 与 A1×A2 端到端仍随属主批增量登记;各 GDD 登记的 deferral 集成用例以对侧登记为生效条件。
|
> 往返,如存档⇄RNG 快照往返、旧档迁移续玩、同种子重开图)都在这层;需要完整项目引导与场景树 = 冒烟/系统/UI 探针。
|
||||||
>
|
> 闭环套件的性质归属(跨系统面=哪几件协同)由各套件头注「跨系统面」句承载,不再靠层级名区分。
|
||||||
> **分层判据**:能不能在 `--script` 模式下不加载 autoload 就验完?能 = 单元测试;
|
|
||||||
> 需要两个以上真实系统协同并走落盘/落库 = 集成测试;需要完整项目引导与场景树 = 冒烟/系统/UI 探针。
|
|
||||||
|
|
||||||
**能力清单**(能力义务清单:一行=一个玩家或系统可观测的能力,只宣布「要验证什么」,不记「是否已验证/是否跑过」;定位=实现指导+阅读导航+义务声明,代表用例只给指针、不复制断言细节。七段=核心四域+排雷循环+表现与支撑+数据配置与跨系统契约,行数随清单生长不在此记账;系统文档逐篇对照见下方「覆盖域表」):
|
**能力清单**(能力义务清单:一行=一个玩家或系统可观测的能力,只宣布「要验证什么」,不记「是否已验证/是否跑过」;定位=实现指导+阅读导航+义务声明,代表用例只给指针、不复制断言细节。七段=核心四域+排雷循环+表现与支撑+数据配置与跨系统契约,行数随清单生长不在此记账;系统文档逐篇对照见下方「覆盖域表」):
|
||||||
|
|
||||||
@@ -50,7 +46,7 @@ tests/
|
|||||||
>
|
>
|
||||||
> **维护规则(写卡段维护,实现批禁写本表)**:写需求卡片时当场入表——本批新增能力当场增行(真实入口取自设计文档已定的入口;代表用例=卡内定死的计划测试 `文件:函数`,实现照单落名,名实不符=卡片没写清=停卡退回);受影响存量行(入口/用例名变更)同批更新;能力退役删行。批末收尾只核对表上名字与实际落地一致(改名则回表),不刷任何批次字段(test-conventions §8.3/§8.9)。
|
> **维护规则(写卡段维护,实现批禁写本表)**:写需求卡片时当场入表——本批新增能力当场增行(真实入口取自设计文档已定的入口;代表用例=卡内定死的计划测试 `文件:函数`,实现照单落名,名实不符=卡片没写清=停卡退回);受影响存量行(入口/用例名变更)同批更新;能力退役删行。批末收尾只核对表上名字与实际落地一致(改名则回表),不刷任何批次字段(test-conventions §8.3/§8.9)。
|
||||||
>
|
>
|
||||||
> **旅程补录方法**:新旅程=加一行,「系统」列写涉及边界;源=architecture「API 边界」表+「数据流」存档/读档路径+各 GDD 登记的 deferral 集成用例。
|
> **旅程补录方法**:新旅程=加一行,「系统」列写涉及边界;源=architecture「API 边界」表+「数据流」存档/读档路径+各 GDD 登记的 deferral 跨系统用例。
|
||||||
|
|
||||||
**旅程段一:开机与存档**
|
**旅程段一:开机与存档**
|
||||||
|
|
||||||
@@ -60,11 +56,11 @@ tests/
|
|||||||
| 三槽位隔离与激活失败回滚 | 存档序列化 | `SaveManagerCore.activate_slot()`/`create_slot()`/`delete_slot()` | `save_slot_isolation_test.gd:_test_three_slot_roundtrip_and_isolation`;`save_slot_isolation_test.gd:_test_activate_failure_restores_previous_slot` |
|
| 三槽位隔离与激活失败回滚 | 存档序列化 | `SaveManagerCore.activate_slot()`/`create_slot()`/`delete_slot()` | `save_slot_isolation_test.gd:_test_three_slot_roundtrip_and_isolation`;`save_slot_isolation_test.gd:_test_activate_failure_restores_previous_slot` |
|
||||||
| 槽位摘要窥视与坏槽三态 | 存档序列化 | `SaveManagerCore.peek_slot_summary()` | `save_slot_summary_test.gd:_test_peek_three_slots_distinct_values`;`save_slot_summary_test.gd:_test_peek_empty_and_unreadable_states`;`save_slot_summary_test.gd:_test_peek_zero_side_effect` |
|
| 槽位摘要窥视与坏槽三态 | 存档序列化 | `SaveManagerCore.peek_slot_summary()` | `save_slot_summary_test.gd:_test_peek_three_slots_distinct_values`;`save_slot_summary_test.gd:_test_peek_empty_and_unreadable_states`;`save_slot_summary_test.gd:_test_peek_zero_side_effect` |
|
||||||
| 启动态无激活不写盘 | 存档序列化 | `SaveManagerCore.has_write_target()`/`write_to_disk()` | `save_boot_no_activate_test.gd:_test_write_rejected_without_target`;`save_boot_no_activate_test.gd:_test_out_of_range_slots_rejected` |
|
| 启动态无激活不写盘 | 存档序列化 | `SaveManagerCore.has_write_target()`/`write_to_disk()` | `save_boot_no_activate_test.gd:_test_write_rejected_without_target`;`save_boot_no_activate_test.gd:_test_out_of_range_slots_rejected` |
|
||||||
| 旧档迁移链与断点续玩零跳号(集成) | 存档序列化×冒险结构 | `SaveManagerCore.load_from_disk()`(内置迁移链)× `AdventureRunner.resume_adventure()` | `save_rng_roundtrip_test.gd:_test_old_version_save_migrates_and_resumes` |
|
| 旧档迁移链与断点续玩零跳号 | 存档序列化×冒险结构 | `SaveManagerCore.load_from_disk()`(内置迁移链)× `AdventureRunner.resume_adventure()` | `save_rng_roundtrip_test.gd:_test_old_version_save_migrates_and_resumes` |
|
||||||
| 存档⇄RNG 快照往返保真(集成) | 存档序列化×RNG 服务×冒险结构 | `AdventureRunner.start_adventure()` → `SaveManagerCore.write_to_disk()`/`load_from_disk()` | `save_rng_roundtrip_test.gd:_test_disk_roundtrip_preserves_breakpoint` |
|
| 存档⇄RNG 快照往返保真 | 存档序列化×RNG 服务×冒险结构 | `AdventureRunner.start_adventure()` → `SaveManagerCore.write_to_disk()`/`load_from_disk()` | `save_rng_roundtrip_test.gd:_test_disk_roundtrip_preserves_breakpoint` |
|
||||||
| RNG 统一流派生与取号账本 | RNG 服务 | `RngServiceCore.derive_at()`/`open_stream()`/`counter()` | `rng_service_test.gd:_test_derive_determinism`;`rng_service_test.gd:_test_stream_draw_determinism`;`rng_stream_boot_test.gd:_smoke_initialize` |
|
| RNG 统一流派生与取号账本 | RNG 服务 | `RngServiceCore.derive_at()`/`open_stream()`/`counter()` | `rng_service_test.gd:_test_derive_determinism`;`rng_service_test.gd:_test_stream_draw_determinism`;`rng_stream_boot_test.gd:_smoke_initialize` |
|
||||||
| 断点片段往返与续玩幂等 | 冒险结构×关卡节点地图 | `LevelRunner.breakpoint_fragment()`/`restore_fragment()`;`AdventureRunner.resume_adventure()` | `breakpoint_resume_test.gd:_init` |
|
| 断点片段往返与续玩幂等 | 冒险结构×关卡节点地图 | `LevelRunner.breakpoint_fragment()`/`restore_fragment()`;`AdventureRunner.resume_adventure()` | `breakpoint_resume_test.gd:_init` |
|
||||||
| 跨系统附随面:事件日志落盘与断点附随件(集成) | RNG 服务×存档序列化×冒险结构 | `RngServiceCore.new_adventure()`(开事件日志会话);`SaveManagerCore.breakpoint_snapshot()`(断点附随键) | `cross_system_flow_test.gd:_rng_event_log_session`;`cross_system_flow_test.gd:_feats_breakpoint_roundtrip` |
|
| 跨系统附随面:事件日志落盘与断点附随件 | RNG 服务×存档序列化×冒险结构 | `RngServiceCore.new_adventure()`(开事件日志会话);`SaveManagerCore.breakpoint_snapshot()`(断点附随键) | `cross_system_flow_test.gd:_rng_event_log_session`;`cross_system_flow_test.gd:_feats_breakpoint_roundtrip` |
|
||||||
|
|
||||||
**旅程段二:冒险开局与选路**
|
**旅程段二:冒险开局与选路**
|
||||||
|
|
||||||
@@ -75,7 +71,7 @@ tests/
|
|||||||
| 节点图生成合法性与同种子复现 | 关卡节点图生成 | `NodeMapGenerator.generate()`/`validate_output()` | `node_map_generator_test.gd:_test_output_ok`;`node_map_generator_test.gd:_test_reproducible`;`node_map_generator_test.gd:_test_exit_structure` |
|
| 节点图生成合法性与同种子复现 | 关卡节点图生成 | `NodeMapGenerator.generate()`/`validate_output()` | `node_map_generator_test.gd:_test_output_ok`;`node_map_generator_test.gd:_test_reproducible`;`node_map_generator_test.gd:_test_exit_structure` |
|
||||||
| 节点图生长递增与无解 fail-fast | 关卡节点图生成 | `NodeMapGenerator.generate()`/`is_fatal()` | `node_map_growth_test.gd:_test_growth`;`node_map_growth_test.gd:_test_fatal_subprocess` |
|
| 节点图生长递增与无解 fail-fast | 关卡节点图生成 | `NodeMapGenerator.generate()`/`is_fatal()` | `node_map_growth_test.gd:_test_growth`;`node_map_growth_test.gd:_test_fatal_subprocess` |
|
||||||
| 节点图参数读表与域单点(三参数驱动产物/生成器侧可行性保留) | 关卡节点图生成 | `NodeMapGenerator.generate()`/`LevelGenParams.validate()` | `node_map_generator_test.gd:_test_gen_params_table_driven`;`table_structure_guard_test.gd:_test_level_gen_new_fields`;`level_gen_params_test.gd:_init`;`encapsulation_p2_sweep_test.gd:_init` |
|
| 节点图参数读表与域单点(三参数驱动产物/生成器侧可行性保留) | 关卡节点图生成 | `NodeMapGenerator.generate()`/`LevelGenParams.validate()` | `node_map_generator_test.gd:_test_gen_params_table_driven`;`table_structure_guard_test.gd:_test_level_gen_new_fields`;`level_gen_params_test.gd:_init`;`encapsulation_p2_sweep_test.gd:_init` |
|
||||||
| 起关/选路/断点重生成同图(集成) | 关卡节点地图×关卡节点图生成×冒险结构 | `LevelRunner.start_level()`/`start_level_external()`/`pick_next_node()`;`AdventureRunner.resume_adventure()` | `node_map_determinism_test.gd:_smoke_generated_map_determinism` |
|
| 起关/选路/断点重生成同图 | 关卡节点地图×关卡节点图生成×冒险结构 | `LevelRunner.start_level()`/`start_level_external()`/`pick_next_node()`;`AdventureRunner.resume_adventure()` | `node_map_determinism_test.gd:_smoke_generated_map_determinism` |
|
||||||
| 信息迷雾类型可见性 | 关卡节点地图 | `LevelRunner.type_visible_ids()` | `level_map_type_vis_test.gd:_test_layer_distance`;`level_map_type_vis_test.gd:_test_boss_exempt`;`level_map_type_vis_test.gd:_test_resume_rebuild`;`level_map_info_fog_test.gd:_initialize` |
|
| 信息迷雾类型可见性 | 关卡节点地图 | `LevelRunner.type_visible_ids()` | `level_map_type_vis_test.gd:_test_layer_distance`;`level_map_type_vis_test.gd:_test_boss_exempt`;`level_map_type_vis_test.gd:_test_resume_rebuild`;`level_map_info_fog_test.gd:_initialize` |
|
||||||
| 关卡表消费侧校验与关卡推进 | 关卡节点地图×数据配置 | `LevelTable.validate_graph()`;`LevelRunner.start_level()` | `level_table_validate_test.gd:_test_positive`;`level_table_validate_test.gd:_test_negative`;`level_shop_economy_test.gd:_smoke_level` |
|
| 关卡表消费侧校验与关卡推进 | 关卡节点地图×数据配置 | `LevelTable.validate_graph()`;`LevelRunner.start_level()` | `level_table_validate_test.gd:_test_positive`;`level_table_validate_test.gd:_test_negative`;`level_shop_economy_test.gd:_smoke_level` |
|
||||||
|
|
||||||
@@ -200,9 +196,9 @@ tests/
|
|||||||
|
|
||||||
| 域 | 系统文档 | 能力行 | 状态 | 缺口 |
|
| 域 | 系统文档 | 能力行 | 状态 | 缺口 |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| 冒险循环 | 冒险结构.md | 冒险生命周期:开局受理/三关序列/败北线;断点片段往返与续玩幂等;起关/选路/断点重生成同图(集成) | 已覆盖 | — |
|
| 冒险循环 | 冒险结构.md | 冒险生命周期:开局受理/三关序列/败北线;断点片段往返与续玩幂等;起关/选路/断点重生成同图 | 已覆盖 | — |
|
||||||
| 冒险循环 | 关卡节点图生成.md | 节点图生成合法性与同种子复现;节点图生长递增与无解 fail-fast | 已覆盖 | — |
|
| 冒险循环 | 关卡节点图生成.md | 节点图生成合法性与同种子复现;节点图生长递增与无解 fail-fast | 已覆盖 | — |
|
||||||
| 冒险循环 | 关卡节点地图.md | 起关/选路/断点重生成同图(集成);信息迷雾类型可见性;关卡表消费侧校验与关卡推进 | 已覆盖 | — |
|
| 冒险循环 | 关卡节点地图.md | 起关/选路/断点重生成同图;信息迷雾类型可见性;关卡表消费侧校验与关卡推进 | 已覆盖 | — |
|
||||||
| 冒险循环 | 奇物.md | 专长(奇物)授予与凭证保底;奖励三选一候选/刷新付费/呈现 | 已覆盖 | — |
|
| 冒险循环 | 奇物.md | 专长(奇物)授予与凭证保底;奖励三选一候选/刷新付费/呈现 | 已覆盖 | — |
|
||||||
| 冒险循环 | 难度曲线与Boss.md | Boss 半血解锁技门控;行集寻址、行序保序与难度乘数 clamp;难度修饰套乘:空表零行为/套乘生效/越域 clamp;Boss 出场门控(每区域恰一 Boss 终点/Boss 节点开战必选 Boss 行集) | 部分覆盖 | 机制面剩余缺口由「断言补齐批」承接;数值落带断言归 M4 数值批;见待办清单「能力清单覆盖缺口补齐」条 |
|
| 冒险循环 | 难度曲线与Boss.md | Boss 半血解锁技门控;行集寻址、行序保序与难度乘数 clamp;难度修饰套乘:空表零行为/套乘生效/越域 clamp;Boss 出场门控(每区域恰一 Boss 终点/Boss 节点开战必选 Boss 行集) | 部分覆盖 | 机制面剩余缺口由「断言补齐批」承接;数值落带断言归 M4 数值批;见待办清单「能力清单覆盖缺口补齐」条 |
|
||||||
| 战斗循环 | 地图战斗资源.md | 清图奖励双份与零路径;GP 钱包/escrow/商店收口/共享池;封印与极性路由/不可逆 | 已覆盖 | — |
|
| 战斗循环 | 地图战斗资源.md | 清图奖励双份与零路径;GP 钱包/escrow/商店收口/共享池;封印与极性路由/不可逆 | 已覆盖 | — |
|
||||||
@@ -215,7 +211,7 @@ tests/
|
|||||||
| 排雷循环 | 棋盘生成.md | 棋盘按参数行出图、数字恒真;同参数同种子逐位复现、异种子不退化;可推理率与清图可达(合法性先于质量分)、重试有界、降级诚实 | 已覆盖 | — |
|
| 排雷循环 | 棋盘生成.md | 棋盘按参数行出图、数字恒真;同参数同种子逐位复现、异种子不退化;可推理率与清图可达(合法性先于质量分)、重试有界、降级诚实 | 已覆盖 | — |
|
||||||
| 排雷循环 | 行动经济.md | AP 扣费、末点耗尽即收轮与战斗收束清零;停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励);下轮行动点修正排队与兑现 | 已覆盖 | — |
|
| 排雷循环 | 行动经济.md | AP 扣费、末点耗尽即收轮与战斗收束清零;停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励);下轮行动点修正排队与兑现 | 已覆盖 | — |
|
||||||
| 表现与支撑 | HUD框架.md | 拒绝反馈分面可辨与未知兜底文案;结算明细带逐行呈现与排播节奏;模态覆盖层编排与输入锁;未开格类型微光(8 邻作用集/五组色相/零玩法写入);UI 全局主题与按钮五态(含对比度锚);中文字体随包与字形覆盖;地形瓦片套与格面数字可读;战斗叙述与终局文案(数值带入/胜负互异);玩家面文案与危险格格面字形;战斗屏三区几何与棋盘格边长(分辨率两档×四档板型);B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役);模态句柄分域寻址面 | 已覆盖 | — |
|
| 表现与支撑 | HUD框架.md | 拒绝反馈分面可辨与未知兜底文案;结算明细带逐行呈现与排播节奏;模态覆盖层编排与输入锁;未开格类型微光(8 邻作用集/五组色相/零玩法写入);UI 全局主题与按钮五态(含对比度锚);中文字体随包与字形覆盖;地形瓦片套与格面数字可读;战斗叙述与终局文案(数值带入/胜负互异);玩家面文案与危险格格面字形;战斗屏三区几何与棋盘格边长(分辨率两档×四档板型);B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役);模态句柄分域寻址面 | 已覆盖 | — |
|
||||||
| 表现与支撑 | 存档序列化.md | 存档写盘⇄读回往返保真;三槽位隔离与激活失败回滚;槽位摘要窥视与坏槽三态;启动态无激活不写盘;旧档迁移链与断点续玩零跳号(集成);存档⇄RNG 快照往返保真(集成) | 已覆盖 | — |
|
| 表现与支撑 | 存档序列化.md | 存档写盘⇄读回往返保真;三槽位隔离与激活失败回滚;槽位摘要窥视与坏槽三态;启动态无激活不写盘;旧档迁移链与断点续玩零跳号;存档⇄RNG 快照往返保真 | 已覆盖 | — |
|
||||||
| 表现与支撑 | 教学引导.md | — | 未覆盖 | 教学形态与首遇时机待设计;见待办清单「教学形态未定」条 |
|
| 表现与支撑 | 教学引导.md | — | 未覆盖 | 教学形态与首遇时机待设计;见待办清单「教学形态未定」条 |
|
||||||
| 表现与支撑 | 数据配置.md | 全表装载、就绪态与表清单目录对账;进度坐标查行:精确命中/向上取整/封顶/警告去重;运行期越域致命与进程非 0 退出;加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域;表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 已覆盖 | — |
|
| 表现与支撑 | 数据配置.md | 全表装载、就绪态与表清单目录对账;进度坐标查行:精确命中/向上取整/封顶/警告去重;运行期越域致命与进程非 0 退出;加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域;表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 已覆盖 | — |
|
||||||
| 表现与支撑 | 设置与本地化.md | 减动效开关存储契约(持久化回读/缺省值/引擎动效档应用) | 已覆盖 | 存储契约三断言已落地;多语言切换面未建(P1,归设置与本地化待设计问题清单) |
|
| 表现与支撑 | 设置与本地化.md | 减动效开关存储契约(持久化回读/缺省值/引擎动效档应用) | 已覆盖 | 存储契约三断言已落地;多语言切换面未建(P1,归设置与本地化待设计问题清单) |
|
||||||
@@ -241,7 +237,7 @@ tests/
|
|||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `tools/run_smoke.py`(冒烟测试) | 这版能否启动、能否加载表、能否进主屏——零逻辑判定 | 退出码+脚本错误扫描 | 开机路径/表加载改动后的快速自检;收口由闸编排 |
|
| `tools/run_smoke.py`(冒烟测试) | 这版能否启动、能否加载表、能否进主屏——零逻辑判定 | 退出码+脚本错误扫描 | 开机路径/表加载改动后的快速自检;收口由闸编排 |
|
||||||
| `tools/run_system_test.py`(系统测试) | 真实玩法路径的行为断言面(推理→战斗→结算→进度推进) | 退出码+脚本错误扫描 | 玩法链路改动的调试期确认 |
|
| `tools/run_system_test.py`(系统测试) | 真实玩法路径的行为断言面(推理→战斗→结算→进度推进) | 退出码+脚本错误扫描 | 玩法链路改动的调试期确认 |
|
||||||
| `tests/run_all.gd`(单元与集成) | 公式/状态机/契约/跨系统闭环(65 套件 manifest) | 退出码+三硬闸(见下);每套件子进程带截止时间守护——超时先 taskkill /T 整树回收再判该套件 FAIL、批继续(默认 120s,环境变量 `RUN_ALL_SUITE_TIMEOUT_SEC` 可覆盖);连续 3 个套件超时=红树整批挂死,第 3 个即中止整轮、汇总已见失败与超时清单后非 0 退出(阈值=可调常量,不连续的超时照旧逐个回收) | 新套件单跑调试;逻辑改动的最小单元复跑;开发期选跑——追加 `-- --only=<词[,词…]>` 只跑路径命中词的套件(零命中=用法错 exit 2;此形态仅供开发期最窄确认,不产闸回执、不作验收凭据);闸机关联档选跑——同一过滤机制加 `-- --only-source=gates`,由 `tools/run_all_gates.sh` 在 02 闸传入(回执 scope=related,是验收跑批本体) |
|
| `tests/run_all.gd`(单元测试) | 公式/状态机/契约/跨系统闭环(65 套件 manifest) | 退出码+三硬闸(见下);每套件子进程带截止时间守护——超时先 taskkill /T 整树回收再判该套件 FAIL、批继续(默认 120s,环境变量 `RUN_ALL_SUITE_TIMEOUT_SEC` 可覆盖);连续 3 个套件超时=红树整批挂死,第 3 个即中止整轮、汇总已见失败与超时清单后非 0 退出(阈值=可调常量,不连续的超时照旧逐个回收) | 新套件单跑调试;逻辑改动的最小单元复跑;开发期选跑——追加 `-- --only=<词[,词…]>` 只跑路径命中词的套件(零命中=用法错 exit 2;此形态仅供开发期最窄确认,不产闸回执、不作验收凭据);闸机关联档选跑——同一过滤机制加 `-- --only-source=gates`,由 `tools/run_all_gates.sh` 在 02 闸传入(回执 scope=related,是验收跑批本体) |
|
||||||
| `tools/probe_gate.sh`(场景探针,单一形态十件恒跑) | UI 可达性、可见性、状态——真实实例化场景+真实输入路径 | 探针自检+退出码 | 新增 UI 区域的配套探针直跑与断言复核 |
|
| `tools/probe_gate.sh`(场景探针,单一形态十件恒跑) | UI 可达性、可见性、状态——真实实例化场景+真实输入路径 | 探针自检+退出码 | 新增 UI 区域的配套探针直跑与断言复核 |
|
||||||
| `tools/render_gate.sh`(渲染 golden) | 画面基线——截图与基线图逐像素容差比对 | golden 比对脚本(依赖 PIL)+退出码/取证双检/三段探针日志脚本错误扫描(`error_scan.py`) | 主题/素材/排版类改动;窗口化运行,需开显示器 |
|
| `tools/render_gate.sh`(渲染 golden) | 画面基线——截图与基线图逐像素容差比对 | golden 比对脚本(依赖 PIL)+退出码/取证双检/三段探针日志脚本错误扫描(`error_scan.py`) | 主题/素材/排版类改动;窗口化运行,需开显示器 |
|
||||||
| `game/tests/static_scan.sh`(S 域) | 项目纪律+第三方质量规则:RNG 单点/core 纯度/类型标注/文件头/注释禁词/旧符号残留;S13=gdstyle 质量规则(重复 load、循环内 await、循环内分配、不可达代码等真缺陷类;基线键=文件|规则|函数名(类/文件级=文件|规则,无数字条目带消息),数字漂移不假红,同键指标恶化超基线登记值即红) | 退出码(逐规则 FAIL 行) | 改产品码前后的快速自检;新增纪律先补扫描规则再修码 |
|
| `game/tests/static_scan.sh`(S 域) | 项目纪律+第三方质量规则:RNG 单点/core 纯度/类型标注/文件头/注释禁词/旧符号残留;S13=gdstyle 质量规则(重复 load、循环内 await、循环内分配、不可达代码等真缺陷类;基线键=文件|规则|函数名(类/文件级=文件|规则,无数字条目带消息),数字漂移不假红,同键指标恶化超基线登记值即红) | 退出码(逐规则 FAIL 行) | 改产品码前后的快速自检;新增纪律先补扫描规则再修码 |
|
||||||
@@ -255,8 +251,8 @@ tests/
|
|||||||
# 冒烟测试——极小启动场景,秒级
|
# 冒烟测试——极小启动场景,秒级
|
||||||
python tools/run_smoke.py
|
python tools/run_smoke.py
|
||||||
|
|
||||||
# 单元与集成测试——Windows 须用 console 版 exe 取 stdout;工作目录 = game/(含 project.godot 那一层)
|
# 单元测试——Windows 须用 console 版 exe 取 stdout;工作目录 = game/(含 project.godot 那一层)
|
||||||
godot --headless --script tests/run_all.gd # 统一入口(本地单元与集成测试闸调用点)
|
godot --headless --script tests/run_all.gd # 统一入口(本地单元测试闸调用点)
|
||||||
godot --headless --script tests/run_all.gd -- --only=battle_settlement # 选跑态——只跑路径含该词的套件(开发期最窄确认;零命中=用法错 exit 2,不产闸回执)
|
godot --headless --script tests/run_all.gd -- --only=battle_settlement # 选跑态——只跑路径含该词的套件(开发期最窄确认;零命中=用法错 exit 2,不产闸回执)
|
||||||
godot --headless --script tests/unit/example_test.gd
|
godot --headless --script tests/unit/example_test.gd
|
||||||
|
|
||||||
@@ -273,8 +269,8 @@ godot --headless --path . res://probe/<probe>.tscn
|
|||||||
# 不连续的超时照旧逐个回收;阈值是 run_all.gd 内可调常量
|
# 不连续的超时照旧逐个回收;阈值是 run_all.gd 内可调常量
|
||||||
```
|
```
|
||||||
|
|
||||||
> 套件 manifest 现况:`_suites()` 登记 **65 条**(62 单元+3 集成;口径=manifest 条目数,
|
> 套件 manifest 现况:`_suites()` 登记 **65 条**(口径=manifest 条目数,
|
||||||
> 随套件增减浮动)——data_config(ConfigDB 加载/进度坐标 ceil 解析/fatal 退出码/统一随机流)、core(秘宝结构冻结/断点续玩/存档槽位/结算五段等)、battle_settlement(DamageMath 纯函数/DamageController 伤害单据五配方)、contracts(系统间接口契约断言)、presentation(节奏队列/奖励浮层/字体资产/地形瓦片集/模态编排等);集成 3 条存 `tests/integration/`。致命类独立进程 `expect=1`;负面套件 `negative=true` 只豁免错误扫描一闸。期望值一律由表读值推导(零玩法数值字面量)、随机只经 RngService 统一流。
|
> 随套件增减浮动)——data_config(ConfigDB 加载/进度坐标 ceil 解析/fatal 退出码/统一随机流)、core(秘宝结构冻结/断点续玩/存档槽位/结算五段等)、battle_settlement(DamageMath 纯函数/DamageController 伤害单据五配方)、contracts(系统间接口契约断言)、presentation(节奏队列/奖励浮层/字体资产/地形瓦片集/模态编排等);跨系统真实路径闭环 3 条同住 `tests/unit/`(与单机制契约套件同环境同协议,见「测试层级」节分层判据)。致命类独立进程 `expect=1`;负面套件 `negative=true` 只豁免错误扫描一闸。期望值一律由表读值推导(零玩法数值字面量)、随机只经 RngService 统一流。
|
||||||
|
|
||||||
**协议要点**(D2 冒烟协议):
|
**协议要点**(D2 冒烟协议):
|
||||||
- `--script` 载体 `extends SceneTree` 以获得 `quit(code)`;成功 `quit(0)`、失败 `quit(1)`
|
- `--script` 载体 `extends SceneTree` 以获得 `quit(code)`;成功 `quit(0)`、失败 `quit(1)`
|
||||||
@@ -295,7 +291,7 @@ godot --headless --path . res://probe/<probe>.tscn
|
|||||||
| Story Type | Required Evidence | Location |
|
| Story Type | Required Evidence | Location |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Logic | Automated unit test — must pass | `tests/unit/[system]/` |
|
| Logic | Automated unit test — must pass | `tests/unit/[system]/` |
|
||||||
| Integration | Integration test OR playtest doc | 落地批当场建 `tests/integration/[system]/`(章程见上) |
|
| Integration | 跨系统闭环套件 OR playtest doc | 落地批当场入 `tests/unit/`(跨系统真实路径闭环套件,章程见「测试层级」节) |
|
||||||
| Visual/Feel | Screenshot + lead sign-off | `tests/evidence/` |
|
| Visual/Feel | Screenshot + lead sign-off | `tests/evidence/` |
|
||||||
| UI | Manual walkthrough OR interaction test(场景探针为首选) | `tests/evidence/` |
|
| UI | Manual walkthrough OR interaction test(场景探针为首选) | `tests/evidence/` |
|
||||||
| Config/Data | Smoke test pass | 跑批回执 `game/tests/.gates/receipt.json`(不入库)+结论随批记 `reports/` |
|
| Config/Data | Smoke test pass | 跑批回执 `game/tests/.gates/receipt.json`(不入库)+结论随批记 `reports/` |
|
||||||
@@ -363,20 +359,19 @@ S12 效果引擎无状态化旧件零残留:扫描 game/ 全域 `.gd` 与 `gam
|
|||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 00 冒烟 | O(1)——引擎启动一次+存活检查 | ~10–20 秒 | |
|
| 00 冒烟 | O(1)——引擎启动一次+存活检查 | ~10–20 秒 | |
|
||||||
| 01 系统测试 | O(屏壳装配数 × 断言面规模) | ~2–3 分钟 | 断言计数随面浮动(口径见「断言计数双口径」节) |
|
| 01 系统测试 | O(屏壳装配数 × 断言面规模) | ~2–3 分钟 | 断言计数随面浮动(口径见「断言计数双口径」节) |
|
||||||
| 02 单元与集成 | O(套件 manifest 条目数 × 单套件冷启动) | ~3–6 分钟 | 每套件独立子进程;单套件挂死守卫 120 秒 |
|
| 02 单元 | O(套件 manifest 条目数 × 单套件冷启动) | ~3–6 分钟 | 每套件独立子进程;单套件挂死守卫 120 秒 |
|
||||||
| 03 场景探针 | O(探针段数 × 引擎冷启动) | ~3–5 分钟(--full/--click 各计一次) | 耗时大头=每段一次引擎冷启动 |
|
| 03 场景探针 | O(探针段数 × 引擎冷启动) | ~3–5 分钟(--full/--click 各计一次) | 耗时大头=每段一次引擎冷启动 |
|
||||||
| 05 渲染 | O(截图段数 × 窗口化冷启动 + golden 比对) | ~8–15 分钟 | 五段串行,需显示器在位 |
|
| 05 渲染 | O(截图段数 × 窗口化冷启动 + golden 比对) | ~8–15 分钟 | 五段串行,需显示器在位 |
|
||||||
| 远端 CI 全量 | 上列各闸串联(两域全量) | ~30–35 分钟 | 2026-11-04 远端 run 实测 ≈33 分钟(单点样本) |
|
| 远端 CI 全量 | 上列各闸串联(两域全量) | ~30–35 分钟 | 2026-11-04 远端 run 实测 ≈33 分钟(单点样本) |
|
||||||
|
|
||||||
## 术语(本项目内的唯一语义)
|
## 术语(本项目内的唯一语义)
|
||||||
|
|
||||||
标准四级测试层(2026-10-22 用户裁,权威对照=design/gdd/术语表.md「退役词对照」):
|
标准测试层(2026-10-22 用户裁立;2026-11-07 用户裁层级合并——跨系统真实路径闭环套件归单元层,识别三元组见 test-conventions「测试层三元组」节;权威对照=design/gdd/术语表.md「退役词对照」):
|
||||||
|
|
||||||
| 词 | 语义 | 载体 |
|
| 词 | 语义 | 载体 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **冒烟测试** | 秒级存活检查——能否启动、能否加载表、能否进主屏。判断「这版还活着吗」,不判断「这版对不对」 | `tests/smoke_boot.tscn/.gd`、`tools/run_smoke.py` |
|
| **冒烟测试** | 秒级存活检查——能否启动、能否加载表、能否进主屏。判断「这版还活着吗」,不判断「这版对不对」 | `tests/smoke_boot.tscn/.gd`、`tools/run_smoke.py` |
|
||||||
| **单元测试** | 隔离的公式/状态机/纯逻辑断言面,逐套件独立进程实跑 | `game/tests/unit/`、`run_all.gd` |
|
| **单元测试** | 受控裸环境断言面(不加载开机装配、手工构造注入实跑,逐套件独立进程)——单机制契约与跨系统真实路径闭环(存档⇄RNG 往返、回放确定性等)都在内 | `game/tests/unit/`、`run_all.gd` |
|
||||||
| **集成测试** | 跨系统闭环断言面(存档⇄RNG 往返、回放确定性等) | `game/tests/integration/`、`run_all.gd` |
|
| **系统测试** | 启动真实工程走真实玩法路径的断言面 | `tests/system_test.gd`+`tools/run_system_test.py` |
|
||||||
| **系统测试** | 启动真实工程走真实玩法路径的断言面 | 过渡期 `game/probe/smoke_all.gd`+`tools/run_system_test.py`;迁移后 `tests/system_test.gd` |
|
|
||||||
| **场景探针** | 以探针场景为运行目标、走完整项目引导(autoload 在位)的 UI/场景断言 | `game/probe/*.tscn`、`probe_gate.sh` |
|
| **场景探针** | 以探针场景为运行目标、走完整项目引导(autoload 在位)的 UI/场景断言 | `game/probe/*.tscn`、`probe_gate.sh` |
|
||||||
| **渲染 golden** | 窗口化截图与基线图的逐像素容差比对 | `render_gate.sh`、`tests/golden/` |
|
| **渲染 golden** | 窗口化截图与基线图的逐像素容差比对 | `render_gate.sh`、`tests/golden/` |
|
||||||
@@ -179,7 +179,7 @@ func _suites() -> Array:
|
|||||||
{"path": "res://tests/unit/core/run_time_fatal_test.gd", "expect": 1, "negative": true}, # 卡② wr5/wr6/wr7 运行期违约通道(fatal 封印传导/未知标签/未播种)
|
{"path": "res://tests/unit/core/run_time_fatal_test.gd", "expect": 1, "negative": true}, # 卡② wr5/wr6/wr7 运行期违约通道(fatal 封印传导/未知标签/未播种)
|
||||||
{"path": "res://tests/unit/data_config/rng_service_test.gd", "expect": 0},
|
{"path": "res://tests/unit/data_config/rng_service_test.gd", "expect": 0},
|
||||||
{"path": "res://tests/unit/data_config/table_structure_guard_test.gd", "expect": 0}, # 表结构守卫宿主(adventure 配额与同调目录/enemy 带键行序/AC 单轨与掷点参数/variation 门控互锁/difficulty 修饰/reward 九型/meta 行族)
|
{"path": "res://tests/unit/data_config/table_structure_guard_test.gd", "expect": 0}, # 表结构守卫宿主(adventure 配额与同调目录/enemy 带键行序/AC 单轨与掷点参数/variation 门控互锁/difficulty 修饰/reward 九型/meta 行族)
|
||||||
{"path": "res://tests/unit/data_config/rng_stream_boot_test.gd", "expect": 0}, # 启动初始化与统一 RNG 流宿主(data/tables 加载链/统一流黄金向量 m=42/derive_at 恒等/open_stream 取号序/new_adventure 计数器重置——批 B 自 smoke_all 迁入;源 :70 事件日志落盘条按裁决一转办集成宿主)
|
{"path": "res://tests/unit/data_config/rng_stream_boot_test.gd", "expect": 0}, # 启动初始化与统一 RNG 流宿主(data/tables 加载链/统一流黄金向量 m=42/derive_at 恒等/open_stream 取号序/new_adventure 计数器重置——批 B 自 smoke_all 迁入;源 :70 事件日志落盘条按裁决一转办跨系统闭环宿主)
|
||||||
{"path": "res://tests/unit/core/treasure_items_test.gd", "expect": 0}, # 秘宝结构冻结断言面
|
{"path": "res://tests/unit/core/treasure_items_test.gd", "expect": 0}, # 秘宝结构冻结断言面
|
||||||
{"path": "res://tests/unit/core/node_map_generator_test.gd", "expect": 0}, # 节点图生成器产出合格/可复现/岔路取舍/恰一店/归属锁定/战斗保底/出口结构/RNG 纯流面(卡① V1·V3·V5–V7·V9·V10)
|
{"path": "res://tests/unit/core/node_map_generator_test.gd", "expect": 0}, # 节点图生成器产出合格/可复现/岔路取舍/恰一店/归属锁定/战斗保底/出口结构/RNG 纯流面(卡① V1·V3·V5–V7·V9·V10)
|
||||||
{"path": "res://tests/unit/core/node_map_growth_test.gd", "expect": 0}, # 生成图生长递增+参数无解 fail-fast 子进程通道(卡① V8/V4)
|
{"path": "res://tests/unit/core/node_map_growth_test.gd", "expect": 0}, # 生成图生长递增+参数无解 fail-fast 子进程通道(卡① V8/V4)
|
||||||
@@ -211,7 +211,7 @@ func _suites() -> Array:
|
|||||||
{"path": "res://tests/unit/battle_settlement/settlement_wiring_snapshot_test.gd", "expect": 0}, # 结算接线同种子逐项 golden 对拍主证〔封装5.1〕(架构审查 5.1 封装修复——段类束注入改造零行为变更基线)
|
{"path": "res://tests/unit/battle_settlement/settlement_wiring_snapshot_test.gd", "expect": 0}, # 结算接线同种子逐项 golden 对拍主证〔封装5.1〕(架构审查 5.1 封装修复——段类束注入改造零行为变更基线)
|
||||||
{"path": "res://tests/unit/battle_settlement/seal_polarity_test.gd", "expect": 0}, # 封印与极性宿主(末点 AP 封印/封印不可逆四情况/清图奖励双份与弱形式/刷新 provenance 守卫/极性路由与封印溢价/负向字典/格面资源资格——批 B 自 smoke_all 迁入)
|
{"path": "res://tests/unit/battle_settlement/seal_polarity_test.gd", "expect": 0}, # 封印与极性宿主(末点 AP 封印/封印不可逆四情况/清图奖励双份与弱形式/刷新 provenance 守卫/极性路由与封印溢价/负向字典/格面资源资格——批 B 自 smoke_all 迁入)
|
||||||
{"path": "res://tests/unit/battle_settlement/round_flow_skill_pool_test.gd", "expect": 0}, # 轮内流与技能池宿主(全战斗回放/轮内刷新与 V5 快照单源/遭遇区间骰/结算五段全序/技能池数据面·回放独立·EV 锚·死亡打断·校验拒绝/妨害附加/四桶计数——批 B 自 smoke_all 迁入)
|
{"path": "res://tests/unit/battle_settlement/round_flow_skill_pool_test.gd", "expect": 0}, # 轮内流与技能池宿主(全战斗回放/轮内刷新与 V5 快照单源/遭遇区间骰/结算五段全序/技能池数据面·回放独立·EV 锚·死亡打断·校验拒绝/妨害附加/四桶计数——批 B 自 smoke_all 迁入)
|
||||||
{"path": "res://tests/unit/battle_settlement/refresh_feats_test.gd", "expect": 0}, # 换图系专长七件宿主(迭代 46 卡A——基座产 RAP 与折价同源/成功事实恰一次/全局受伤四路径恰一次/石层缓冲/崩壁延迟/蓄力周转/坑道小憩/矿道红利 GP/七件数据与牌库/无专长基线;原经卡片申报走关联档选跑,卡片退役后补登记由单元与集成测试全套件承接)
|
{"path": "res://tests/unit/battle_settlement/refresh_feats_test.gd", "expect": 0}, # 换图系专长七件宿主(迭代 46 卡A——基座产 RAP 与折价同源/成功事实恰一次/全局受伤四路径恰一次/石层缓冲/崩壁延迟/蓄力周转/坑道小憩/矿道红利 GP/七件数据与牌库/无专长基线;原经卡片申报走关联档选跑,卡片退役后补登记由单元测试全套件承接)
|
||||||
{"path": "res://tests/unit/battle_settlement/variant_placement_test.gd", "expect": 0}, # 变异布置宿主(战内布置段门控与数量公式/全局变异兜底回落与资源面偏斜——批 B 自 smoke_all 迁入)
|
{"path": "res://tests/unit/battle_settlement/variant_placement_test.gd", "expect": 0}, # 变异布置宿主(战内布置段门控与数量公式/全局变异兜底回落与资源面偏斜——批 B 自 smoke_all 迁入)
|
||||||
{"path": "res://tests/unit/battle_settlement/skill_unlock_test.gd", "expect": 0}, # Boss 半血解锁技·容器机制(门谓词/闩不可逆/双面过滤/保底不逼锁定/零扰动)
|
{"path": "res://tests/unit/battle_settlement/skill_unlock_test.gd", "expect": 0}, # Boss 半血解锁技·容器机制(门谓词/闩不可逆/双面过滤/保底不逼锁定/零扰动)
|
||||||
{"path": "res://tests/unit/battle_settlement/extended_row_violation_test.gd", "expect": 1, "negative": true}, # 卡④ wr2-np 扩展行必载 effect_id 负路径(行协议运行期违约面首个负面套件——独立进程豁免错误扫描)
|
{"path": "res://tests/unit/battle_settlement/extended_row_violation_test.gd", "expect": 1, "negative": true}, # 卡④ wr2-np 扩展行必载 effect_id 负路径(行协议运行期违约面首个负面套件——独立进程豁免错误扫描)
|
||||||
@@ -235,24 +235,24 @@ func _suites() -> Array:
|
|||||||
{"path": "res://tests/unit/core/save_boot_no_activate_test.gd", "expect": 0}, # 卡① 启动态类级契约:无激活态/拒写盘面零触碰/越界拒绝(sv2/sv3)
|
{"path": "res://tests/unit/core/save_boot_no_activate_test.gd", "expect": 0}, # 卡① 启动态类级契约:无激活态/拒写盘面零触碰/越界拒绝(sv2/sv3)
|
||||||
{"path": "res://tests/unit/core/save_slot_summary_test.gd", "expect": 0}, # 卡① 摘要三项按槽窥视:异值/空槽/坏槽三态/零副作用(sv7/sv8)
|
{"path": "res://tests/unit/core/save_slot_summary_test.gd", "expect": 0}, # 卡① 摘要三项按槽窥视:异值/空槽/坏槽三态/零副作用(sv7/sv8)
|
||||||
{"path": "res://tests/unit/presentation/modal_flow_test.gd", "expect": 0}, # 模态编排纯逻辑(V6:直接 new/互斥域谓词/三例外锁/演播后排窗)
|
{"path": "res://tests/unit/presentation/modal_flow_test.gd", "expect": 0}, # 模态编排纯逻辑(V6:直接 new/互斥域谓词/三例外锁/演播后排窗)
|
||||||
# ---- L2 集成层(跨系统用例,与 unit/ 的隔离断言面分工)----
|
# ---- 跨系统真实路径闭环(受控裸环境多系统协同×落盘往返;与单机制契约套件同闸同协议)----
|
||||||
{"path": "res://tests/integration/save_rng_roundtrip_test.gd", "expect": 0}, # 存档⇄RNG 快照往返(SaveManager 迁移链 × 断点消费 × RNG 续跑 × 停点态确定性)
|
{"path": "res://tests/unit/save_rng_roundtrip_test.gd", "expect": 0}, # 存档⇄RNG 快照往返(SaveManager 迁移链 × 断点消费 × RNG 续跑 × 停点态确定性)
|
||||||
{"path": "res://tests/integration/node_map_determinism_test.gd", "expect": 0}, # 关卡节点图生成·确定性承载(生成图复现×首冒险置位落盘——批 B 自 smoke_all 迁入,裁决六整套集成不拆)
|
{"path": "res://tests/unit/node_map_determinism_test.gd", "expect": 0}, # 关卡节点图生成·确定性承载(生成图复现×首冒险置位落盘——批 B 自 smoke_all 迁入,裁决六整套不拆)
|
||||||
{"path": "res://tests/integration/cross_system_flow_test.gd", "expect": 0}, # 跨系统真实流×落盘(RNG 事件日志落盘/专长断点往返/存档摘要集成/试玩记录仪真实结算流——批 B 转办块宿主,裁决一/二/三/七)
|
{"path": "res://tests/unit/cross_system_flow_test.gd", "expect": 0}, # 跨系统真实流×落盘(RNG 事件日志落盘/专长断点往返/存档摘要跨系统块/试玩记录仪真实结算流——批 B 转办块宿主,裁决一/二/三/七)
|
||||||
# ---- core 四件与呈现层两件的直接单测 ----
|
# ---- core 四件与呈现层两件的直接单测 ----
|
||||||
{"path": "res://tests/unit/core/board_generator_test.gd", "expect": 0}, # 棋盘生成(尺寸合表/数字=八邻雷数/同种子逐位一致/可推理自洽)
|
{"path": "res://tests/unit/core/board_generator_test.gd", "expect": 0}, # 棋盘生成(尺寸合表/数字=八邻雷数/同种子逐位一致/可推理自洽)
|
||||||
{"path": "res://tests/unit/core/board_gen_reward_test.gd", "expect": 0}, # 棋盘生成与地图战斗资源宿主(格边长公式/资源身份面/生成器三分出口与 r0 闸/伤害量值区间——批 B 自 smoke_all 迁入)
|
{"path": "res://tests/unit/core/board_gen_reward_test.gd", "expect": 0}, # 棋盘生成与地图战斗资源宿主(格边长公式/资源身份面/生成器三分出口与 r0 闸/伤害量值区间——批 B 自 smoke_all 迁入)
|
||||||
{"path": "res://tests/unit/core/adventure_feats_test.gd", "expect": 0}, # 冒险结构与专长宿主(状态机受理面/三关序列与账本封闭/败北线/feat_table 四级/专长凭证保底/V3 订阅面逐件——批 B 自 smoke_all 迁入;断点往返三条按裁决二转办集成宿主)
|
{"path": "res://tests/unit/core/adventure_feats_test.gd", "expect": 0}, # 冒险结构与专长宿主(状态机受理面/三关序列与账本封闭/败北线/feat_table 四级/专长凭证保底/V3 订阅面逐件——批 B 自 smoke_all 迁入;断点往返三条按裁决二转办跨系统闭环宿主)
|
||||||
{"path": "res://tests/unit/core/level_shop_economy_test.gd", "expect": 0}, # 关卡图与 GP 商店宿主(level 图校验与推进/enemy 行集定点/钱包到账/escrow 钳制/商店三收口/共享池抽买——批 B 自 smoke_all 迁入)
|
{"path": "res://tests/unit/core/level_shop_economy_test.gd", "expect": 0}, # 关卡图与 GP 商店宿主(level 图校验与推进/enemy 行集定点/钱包到账/escrow 钳制/商店三收口/共享池抽买——批 B 自 smoke_all 迁入)
|
||||||
{"path": "res://tests/unit/core/meta_progression_forge_test.gd", "expect": 0}, # 元进度与锻造宿主(锻造两轴/树购买受理面/hero_override 注入/收束入账与工坊解锁/树六键合成——批 B 自 smoke_all 迁入)
|
{"path": "res://tests/unit/core/meta_progression_forge_test.gd", "expect": 0}, # 元进度与锻造宿主(锻造两轴/树购买受理面/hero_override 注入/收束入账与工坊解锁/树六键合成——批 B 自 smoke_all 迁入)
|
||||||
{"path": "res://tests/unit/core/save_manager_domain_test.gd", "expect": 0}, # 存档域宿主(读写往返/迁移链/损坏兜底/域界干净/摘要 cap/断点域七字段/三槽位承载——批 B 自 smoke_all 迁入;摘要集成块按裁决三转办集成宿主)
|
{"path": "res://tests/unit/core/save_manager_domain_test.gd", "expect": 0}, # 存档域宿主(读写往返/迁移链/损坏兜底/域界干净/摘要 cap/断点域七字段/三槽位承载——批 B 自 smoke_all 迁入;摘要跨系统块按裁决三转办跨系统闭环宿主)
|
||||||
{"path": "res://tests/unit/core/minesweeper_rules_test.gd", "expect": 0}, # 排雷规则(装板不变量/挖的 face 规则/揭示推进/封印/目录外拒)
|
{"path": "res://tests/unit/core/minesweeper_rules_test.gd", "expect": 0}, # 排雷规则(装板不变量/挖的 face 规则/揭示推进/封印/目录外拒)
|
||||||
{"path": "res://tests/unit/core/config_db_resolver_test.gd", "expect": 0}, # 配置解析(ceil 偏难语义/行集行序/难度 clamp)
|
{"path": "res://tests/unit/core/config_db_resolver_test.gd", "expect": 0}, # 配置解析(ceil 偏难语义/行集行序/难度 clamp)
|
||||||
{"path": "res://tests/unit/core/config_db_cross_validator_test.gd", "expect": 0}, # 跨表校验(正向零错/悬空 skill_id/side 反向)
|
{"path": "res://tests/unit/core/config_db_cross_validator_test.gd", "expect": 0}, # 跨表校验(正向零错/悬空 skill_id/side 反向)
|
||||||
{"path": "res://tests/unit/presentation/hud_presenter_test.gd", "expect": 0}, # HUD 投影文案(逐拒绝原因/兜底不空)
|
{"path": "res://tests/unit/presentation/hud_presenter_test.gd", "expect": 0}, # HUD 投影文案(逐拒绝原因/兜底不空)
|
||||||
{"path": "res://tests/unit/presentation/battle_narrator_test.gd", "expect": 0}, # 战斗叙述(数值带入/胜负互异/收束态恒定)
|
{"path": "res://tests/unit/presentation/battle_narrator_test.gd", "expect": 0}, # 战斗叙述(数值带入/胜负互异/收束态恒定)
|
||||||
{"path": "res://tests/unit/presentation/type_glow_test.gd", "expect": 0}, # 未开格类型微光数据面(九型归组封闭/清单外显式失败/冻结色相只准动明度/α170·带宽cell÷8锚定/合成空间阶梯单调+模型CR≥1.20/probe API 形状)
|
{"path": "res://tests/unit/presentation/type_glow_test.gd", "expect": 0}, # 未开格类型微光数据面(九型归组封闭/清单外显式失败/冻结色相只准动明度/α170·带宽cell÷8锚定/合成空间阶梯单调+模型CR≥1.20/probe API 形状)
|
||||||
{"path": "res://tests/unit/presentation/theme_projection_test.gd", "expect": 0}, # 呈现投影与主题宿主(微光数据面/战斗日志行协议/全局主题与按钮五态/纹理过滤白名单/对比度墨色锚/元素细节源码锚/诊断钮退役源码契约/状态面板与生涯页只读投影——批 B 自 smoke_all 迁入;试玩记录仪整套按裁决七转办集成宿主)
|
{"path": "res://tests/unit/presentation/theme_projection_test.gd", "expect": 0}, # 呈现投影与主题宿主(微光数据面/战斗日志行协议/全局主题与按钮五态/纹理过滤白名单/对比度墨色锚/元素细节源码锚/诊断钮退役源码契约/状态面板与生涯页只读投影——批 B 自 smoke_all 迁入;试玩记录仪整套按裁决七转办跨系统闭环宿主)
|
||||||
{"path": "res://tests/unit/presentation/player_copy_sweep_test.gd", "expect": 0}, # 玩家面文案清扫宿主(迭代36 卡A——钉值表换代断言①–⑧⑩+源 token 扫描两处;直建断言族,禁字「雷」族与旧术语清零钉值)
|
{"path": "res://tests/unit/presentation/player_copy_sweep_test.gd", "expect": 0}, # 玩家面文案清扫宿主(迭代36 卡A——钉值表换代断言①–⑧⑩+源 token 扫描两处;直建断言族,禁字「雷」族与旧术语清零钉值)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -659,7 +659,7 @@ func _smoke_skill_pool_data() -> void:
|
|||||||
if n_uncond < 1:
|
if n_uncond < 1:
|
||||||
uncond_ok = false
|
uncond_ok = false
|
||||||
Kit.check("每池至少一行无条件特殊技(触发条件批池构成纪律——逐池复查)〔触发器批 V7〕", uncond_ok)
|
Kit.check("每池至少一行无条件特殊技(触发条件批池构成纪律——逐池复查)〔触发器批 V7〕", uncond_ok)
|
||||||
# Boss 半血解锁技·编排集成断言(真实编排回路:半血 → 下轮开轮闩检查 → 解锁行恰一次)
|
# Boss 半血解锁技·编排回路断言(真实编排回路:半血 → 下轮开轮闩检查 → 解锁行恰一次)
|
||||||
var st_unlock: Dictionary = {"rows": []}
|
var st_unlock: Dictionary = {"rows": []}
|
||||||
var sett_u = load("res://core/battle_orchestrator.gd").new(_db, _fresh_rng(4242))
|
var sett_u = load("res://core/battle_orchestrator.gd").new(_db, _fresh_rng(4242))
|
||||||
sett_u.step_row.connect(func(row): st_unlock["rows"].append(row))
|
sett_u.step_row.connect(func(row): st_unlock["rows"].append(row))
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||||
# 触发条件机制单测(技能池情境条件触发器批——V1 出域拒绝/V2 双面过滤/V3 保底不逼/V4 闩型语义/
|
# 触发条件机制单测(技能池情境条件触发器批——V1 出域拒绝/V2 双面过滤/V3 保底不逼/V4 闩型语义/
|
||||||
# V6 事实面供给/V7 池构成纪律/V8 低血防御/V9 停手偷袭/V10 缺省零扰动;V5 对拍由 skill_unlock_test
|
# V6 事实面供给/V7 池构成纪律/V8 低血防御/V9 停手偷袭/V10 缺省零扰动;V5 对拍由 skill_unlock_test
|
||||||
# 迁移断言与 round_flow 编排集成断言承载)。
|
# 迁移断言与 round_flow 编排回路断言承载)。
|
||||||
# 运行:godot --headless --path game --script res://tests/unit/battle_settlement/trigger_cond_test.gd(expect 0)
|
# 运行:godot --headless --path game --script res://tests/unit/battle_settlement/trigger_cond_test.gd(expect 0)
|
||||||
extends SceneTree
|
extends SceneTree
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ func _init() -> void:
|
|||||||
stray += 1
|
stray += 1
|
||||||
Kit.check_quiet(stray == 0, "V10 无 trigger 行池快照零新键(快照键策略钉死——防未来给普行塞键)〔触发器批 V10〕")
|
Kit.check_quiet(stray == 0, "V10 无 trigger 行池快照零新键(快照键策略钉死——防未来给普行塞键)〔触发器批 V10〕")
|
||||||
|
|
||||||
quit(Kit.finish("trigger_cond_test", "PASS — 触发条件 V1/V2/V4/V6/V7/V8/V9/V10 全绿(V5 对拍由 skill_unlock/round_flow 编排集成承载)"))
|
quit(Kit.finish("trigger_cond_test", "PASS — 触发条件 V1/V2/V4/V6/V7/V8/V9/V10 全绿(V5 对拍由 skill_unlock/round_flow 编排回路承载)"))
|
||||||
|
|
||||||
|
|
||||||
func _rng(seed_val: int):
|
func _rng(seed_val: int):
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# 冒险结构 API 闸(状态机受理面——重复开始拒绝/入口停点/放弃两态)
|
# 冒险结构 API 闸(状态机受理面——重复开始拒绝/入口停点/放弃两态)
|
||||||
# 冒险验收断言(三关序列/大奖励三层兑付/账本封闭/败北线/恢复数学/加算区同账/共享池)
|
# 冒险验收断言(三关序列/大奖励三层兑付/账本封闭/败北线/恢复数学/加算区同账/共享池)
|
||||||
# 专长重设计实装(feat_table 四级/案D 池接线/V3 订阅面逐件三列/专长凭证保底)
|
# 专长重设计实装(feat_table 四级/案D 池接线/V3 订阅面逐件三列/专长凭证保底)
|
||||||
# 注:断点往返三条(基点 1420–1426)按主会话裁决②改判集成宿主,不在本宿主断言面内。
|
# 注:断点往返三条(基点 1420–1426)按主会话裁决②改判跨系统闭环宿主,不在本宿主断言面内。
|
||||||
# 协议照单元侧惯例:extends SceneTree+Kit.check 主通道;--script 模式无 autoload,
|
# 协议照单元侧惯例:extends SceneTree+Kit.check 主通道;--script 模式无 autoload,
|
||||||
# ConfigDB 显式实例化构造注入(_fresh_rng 同种子隔离夹具——RngService 构造注入 runner);
|
# ConfigDB 显式实例化构造注入(_fresh_rng 同种子隔离夹具——RngService 构造注入 runner);
|
||||||
# 表加载失败不中止(沿被迁断言面的源语义——承 G2–G6 同款)。
|
# 表加载失败不中止(沿被迁断言面的源语义——承 G2–G6 同款)。
|
||||||
@@ -579,8 +579,8 @@ func _smoke_feats() -> void:
|
|||||||
Kit.check("A6 概率面存在(chance=20% 200 展示内必出现——零触发=概率面失守)", offered)
|
Kit.check("A6 概率面存在(chance=20% 200 展示内必出现——零触发=概率面失守)", offered)
|
||||||
a_r.stop()._pending = {"candidates": [{"kind": "relic", "tier": "rare", "feat_id": "x3"}, {"kind": "gp", "tier": "common"}], "payload": {}}
|
a_r.stop()._pending = {"candidates": [{"kind": "relic", "tier": "rare", "feat_id": "x3"}, {"kind": "gp", "tier": "common"}], "payload": {}}
|
||||||
Kit.check("relic 兑付:入持有集 + 牌库摘牌(选中踢池——池库存 %d→%d)" % [deck_relic, deck_relic - 1], a_r.stop().pick_curio("relic", "rare", "x3") and (a_r.feats_held() as Array).has("x3") and a_r.deck().pool_stock("relic") == deck_relic - 1)
|
Kit.check("relic 兑付:入持有集 + 牌库摘牌(选中踢池——池库存 %d→%d)" % [deck_relic, deck_relic - 1], a_r.stop().pick_curio("relic", "rare", "x3") and (a_r.feats_held() as Array).has("x3") and a_r.deck().pool_stock("relic") == deck_relic - 1)
|
||||||
# 断点往返三条(基点 1420–1426:relics 快照/计数器键/余库逐枚还原)按主会话裁决②改判集成宿主——
|
# 断点往返三条(基点 1420–1426:relics 快照/计数器键/余库逐枚还原)按主会话裁决②改判跨系统闭环宿主——
|
||||||
# 驱动代码(save_manager 装配+_on_level_finished+快照取读)随三条同去,集成批落位时重建。
|
# 驱动代码(save_manager 装配+_on_level_finished+快照取读)随三条同去,跨系统闭环套件落位时重建。
|
||||||
_db.crossrun.feats = live_rows # 还原现行表(共享 _db 防污染——后续冒烟段零感知)
|
_db.crossrun.feats = live_rows # 还原现行表(共享 _db 防污染——后续冒烟段零感知)
|
||||||
# ⑤ V3 订阅面逐件(附表 A 三列——命中面=EffectEngine dispatch 直测;账本面=counter 直读;
|
# ⑤ V3 订阅面逐件(附表 A 三列——命中面=EffectEngine dispatch 直测;账本面=counter 直读;
|
||||||
# 落地行为=发射点施加面〔T1 施加段承载——本段按声明逐件钉命中与边界/反例〕)
|
# 落地行为=发射点施加面〔T1 施加段承载——本段按声明逐件钉命中与边界/反例〕)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
# ConfigDB 显式实例化构造注入(v2 断点续玩受理与收束链夹具消费 _db);表加载失败不中止
|
# ConfigDB 显式实例化构造注入(v2 断点续玩受理与收束链夹具消费 _db);表加载失败不中止
|
||||||
# (沿被迁断言面的源语义——诊断在此展开,红由具体断言落,承 G2–G5 同款)。
|
# (沿被迁断言面的源语义——诊断在此展开,红由具体断言落,承 G2–G5 同款)。
|
||||||
# 测试文件统一 user://smoke_save_*.json 隔离,段首清场+段尾清理——绝不碰 user://save.json(红线)。
|
# 测试文件统一 user://smoke_save_*.json 隔离,段首清场+段尾清理——绝不碰 user://save.json(红线)。
|
||||||
# 分宿主注记:源 `_smoke_save` ⑨ 摘要集成块(level_autoplay 真局驱动×落盘,基点 :6807–6831)
|
# 分宿主注记:源 `_smoke_save` ⑨ 摘要跨系统块(level_autoplay 真局驱动×落盘,基点 :6807–6831)
|
||||||
# 经主会话裁决三改判集成测试——不随本宿主,见迁移账本转办清单。
|
# 经主会话裁决三改判跨系统闭环套件——不随本宿主,见迁移账本转办清单。
|
||||||
# 运行:godot --headless --path game --script res://tests/unit/core/save_manager_domain_test.gd
|
# 运行:godot --headless --path game --script res://tests/unit/core/save_manager_domain_test.gd
|
||||||
extends SceneTree
|
extends SceneTree
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ func _fresh_rng(seed_val: int):
|
|||||||
|
|
||||||
|
|
||||||
# ---- 存档序列化冒烟(SaveManager——读写往返/新档合法/余额拒花/锻造出域拒/高版本拒读禁写/
|
# ---- 存档序列化冒烟(SaveManager——读写往返/新档合法/余额拒花/锻造出域拒/高版本拒读禁写/
|
||||||
# 损坏兜底/迁移链/域界干净/摘要 cap/摘要集成/生涯终身计数域 v6)。测试文件统一 user://smoke_save_*.json 隔离,
|
# 损坏兜底/迁移链/域界干净/摘要 cap/摘要跨系统块/生涯终身计数域 v6)。测试文件统一 user://smoke_save_*.json 隔离,
|
||||||
# 段首清场+段尾清理——绝不碰 user://save.json(红线)。
|
# 段首清场+段尾清理——绝不碰 user://save.json(红线)。
|
||||||
func _smoke_save() -> void:
|
func _smoke_save() -> void:
|
||||||
# oracle: design/gdd/systems/表现与支撑/存档序列化.md:176 (存档域读写往返/迁移链/损坏兜底/域界组)
|
# oracle: design/gdd/systems/表现与支撑/存档序列化.md:176 (存档域读写往返/迁移链/损坏兜底/域界组)
|
||||||
@@ -176,8 +176,8 @@ func _smoke_save() -> void:
|
|||||||
Kit.check("最新在前(头 seed 11 / 尾 seed 2)",
|
Kit.check("最新在前(头 seed 11 / 尾 seed 2)",
|
||||||
int(arr[0].get("master_seed", -1)) == 11 and int(arr[9].get("master_seed", -1)) == 2)
|
int(arr[0].get("master_seed", -1)) == 11 and int(arr[9].get("master_seed", -1)) == 2)
|
||||||
|
|
||||||
# ⑨ 摘要集成块(level_autoplay 真局驱动×落盘,基点 :6807–6831)——经主会话裁决三
|
# ⑨ 摘要跨系统块(level_autoplay 真局驱动×落盘,基点 :6807–6831)——经主会话裁决三
|
||||||
# 改判集成测试,不随本宿主(迁移账本转办清单)。
|
# 改判跨系统闭环套件,不随本宿主(迁移账本转办清单)。
|
||||||
|
|
||||||
# ⑪ 断点域:七字段写读往返逐位一致+附随件+值拷贝出户+清除+旧档迁移合法空态
|
# ⑪ 断点域:七字段写读往返逐位一致+附随件+值拷贝出户+清除+旧档迁移合法空态
|
||||||
var fbp = sm_script.new(paths[9])
|
var fbp = sm_script.new(paths[9])
|
||||||
|
|||||||
+20
-20
@@ -1,15 +1,15 @@
|
|||||||
# tests/integration/cross_system_flow_test.gd — L2 集成用例:跨系统真实流×落盘(批 B 转办块宿主)
|
# tests/unit/cross_system_flow_test.gd — 跨系统真实路径闭环套件:跨系统真实流×落盘(批 B 转办块宿主)
|
||||||
# 断言面 = 四块 22 条(批 B 断言迁移自 smoke_all.gd,主会话裁决一/二/三/七改判集成,装配批落位;
|
# 断言面 = 四块 22 条(批 B 断言迁移自 smoke_all.gd,主会话裁决一/二/三/七改判跨系统闭环承载,装配批落位;
|
||||||
# 标签与 cond 逐字搬运,宿主通道换线 Kit.check——与单元侧同一对账口径):
|
# 标签与 cond 逐字搬运,宿主通道换线 Kit.check——与单元侧同一对账口径):
|
||||||
# RNG 事件日志会话落盘 1 条(源 `_initialize` :70,裁决一——RngService 会话日志×磁盘)
|
# RNG 事件日志会话落盘 1 条(源 `_initialize` :70,裁决一——RngService 会话日志×磁盘)
|
||||||
# 专长断点往返 3 条(源 `_smoke_feats` 基点 :1420–1426,裁决二——AdventureRunner 兑付态×SaveManager 断点快照)
|
# 专长断点往返 3 条(源 `_smoke_feats` 基点 :1420–1426,裁决二——AdventureRunner 兑付态×SaveManager 断点快照)
|
||||||
# 存档摘要集成 10 条(源 `_smoke_save` ⑨ 基点 :6807–6831,裁决三——level_autoplay 真局×SaveManager 入账×写盘读回)
|
# 存档摘要跨系统块 10 条(源 `_smoke_save` ⑨ 基点 :6807–6831,裁决三——level_autoplay 真局×SaveManager 入账×写盘读回)
|
||||||
# 试玩记录仪 8 条(源 `_smoke_playtest_logger` 整套,裁决七——PlaytestLogger×BattleOrchestrator 真实结算流×JSONL 落盘)
|
# 试玩记录仪 8 条(源 `_smoke_playtest_logger` 整套,裁决七——PlaytestLogger×BattleOrchestrator 真实结算流×JSONL 落盘)
|
||||||
# 协议照集成侧惯例(与单元同入口同协议,tests/README「测试层级」):extends SceneTree+Kit.check 主通道;
|
# 协议照单元侧惯例(与单元同入口同协议,tests/README「测试层级」):extends SceneTree+Kit.check 主通道;
|
||||||
# --script 模式无 autoload,ConfigDB/RngService 显式实例化构造注入;表加载失败不中止(沿被迁断言面的
|
# --script 模式无 autoload,ConfigDB/RngService 显式实例化构造注入;表加载失败不中止(沿被迁断言面的
|
||||||
# 源语义——诊断在此展开,红由具体断言落,承 G2–G5 同款);冒烟库件迁移期按现路径 preload(账本 §五夹具前提)。
|
# 源语义——诊断在此展开,红由具体断言落,承 G2–G5 同款);冒烟库件迁移期按现路径 preload(账本 §五夹具前提)。
|
||||||
# 驱动代码随条自持、零新增断言(验证集不扩大为绝对约束——前置受理失败自然落到后续断言红)。
|
# 驱动代码随条自持、零新增断言(验证集不扩大为绝对约束——前置受理失败自然落到后续断言红)。
|
||||||
# 运行:godot --headless --path game --script res://tests/integration/cross_system_flow_test.gd
|
# 运行:godot --headless --path game --script res://tests/unit/cross_system_flow_test.gd
|
||||||
extends SceneTree
|
extends SceneTree
|
||||||
|
|
||||||
const Kit := preload("res://tests/unit/test_kit.gd")
|
const Kit := preload("res://tests/unit/test_kit.gd")
|
||||||
@@ -44,7 +44,7 @@ func _fresh_rng(seed_val: int):
|
|||||||
return rng
|
return rng
|
||||||
|
|
||||||
|
|
||||||
# ---- ① RNG 事件日志会话落盘(源 `_initialize` :70,主会话裁决一改判集成——
|
# ---- ① RNG 事件日志会话落盘(源 `_initialize` :70,主会话裁决一改判跨系统闭环承载——
|
||||||
# 驱动沿源 :60–70 取号序列自持:master 种子 42 → 前置取号 → new_adventure 开日志会话 → 会话内取号)----
|
# 驱动沿源 :60–70 取号序列自持:master 种子 42 → 前置取号 → new_adventure 开日志会话 → 会话内取号)----
|
||||||
func _rng_event_log_session() -> void:
|
func _rng_event_log_session() -> void:
|
||||||
# oracle: design/engineering/architecture/architecture.md:90 (事件日志落盘会话组)
|
# oracle: design/engineering/architecture/architecture.md:90 (事件日志落盘会话组)
|
||||||
@@ -57,7 +57,7 @@ func _rng_event_log_session() -> void:
|
|||||||
Kit.check("事件日志会话落盘(2026-09-27 统一流裁决)", FileAccess.file_exists("user://logs/rng_log_4242.jsonl"))
|
Kit.check("事件日志会话落盘(2026-09-27 统一流裁决)", FileAccess.file_exists("user://logs/rng_log_4242.jsonl"))
|
||||||
|
|
||||||
|
|
||||||
# ---- ② 专长断点往返(源 `_smoke_feats` 基点 :1420–1426 三条,主会话裁决二改判集成——
|
# ---- ② 专长断点往返(源 `_smoke_feats` 基点 :1420–1426 三条,主会话裁决二改判跨系统闭环承载——
|
||||||
# 驱动沿源 :721–797 重建:5 行临时表注入+seed 72 起局+兑付 x3+save_manager 装配+
|
# 驱动沿源 :721–797 重建:5 行临时表注入+seed 72 起局+兑付 x3+save_manager 装配+
|
||||||
# _on_level_finished(victory)+breakpoint_snapshot 取读+clear_breakpoint;
|
# _on_level_finished(victory)+breakpoint_snapshot 取读+clear_breakpoint;
|
||||||
# 起局与兑付两步的受理断言留单元宿主(adventure_feats_test),此处纯驱动——前置失败自然落红)----
|
# 起局与兑付两步的受理断言留单元宿主(adventure_feats_test),此处纯驱动——前置失败自然落红)----
|
||||||
@@ -101,44 +101,44 @@ func _feats_breakpoint_roundtrip() -> void:
|
|||||||
sm_r.clear_breakpoint()
|
sm_r.clear_breakpoint()
|
||||||
if FileAccess.file_exists(bp_path): # 段尾清理(与段首清场对称)
|
if FileAccess.file_exists(bp_path): # 段尾清理(与段首清场对称)
|
||||||
DirAccess.remove_absolute(bp_path)
|
DirAccess.remove_absolute(bp_path)
|
||||||
_db.crossrun.feats = live_rows # 还原现行表(共享 _db 防污染——后续集成块零感知)
|
_db.crossrun.feats = live_rows # 还原现行表(共享 _db 防污染——后续跨系统块零感知)
|
||||||
|
|
||||||
|
|
||||||
# ---- ③ 存档摘要集成(源 `_smoke_save` ⑨ 基点 :6807–6831 十条,主会话裁决三改判集成——
|
# ---- ③ 存档摘要跨系统块(源 `_smoke_save` ⑨ 基点 :6807–6831 十条,主会话裁决三改判跨系统闭环承载——
|
||||||
# level_autoplay 真局摘要 → apply 原语 → 域读数 → 写盘读回保持;临时档 user://smoke_save_integration.json
|
# level_autoplay 真局摘要 → apply 原语 → 域读数 → 写盘读回保持;临时档 user://smoke_save_integration.json
|
||||||
# 段首清场+段尾清理(源 _smoke_save 隔离纪律),绝不碰 user://save.json(红线))----
|
# 段首清场+段尾清理(源 _smoke_save 隔离纪律),绝不碰 user://save.json(红线))----
|
||||||
func _save_summary_integration() -> void:
|
func _save_summary_integration() -> void:
|
||||||
# oracle: design/gdd/systems/跨局循环/元进度.md:150 (摘要集成与钥石只增不减组)
|
# oracle: design/gdd/systems/跨局循环/元进度.md:150 (摘要跨系统块与钥石只增不减组)
|
||||||
var sm_script = load("res://core/save_manager.gd")
|
var sm_script = load("res://core/save_manager.gd")
|
||||||
var path9 := "user://smoke_save_integration.json" # 源 paths[8]
|
var path9 := "user://smoke_save_integration.json" # 源 paths[8]
|
||||||
if FileAccess.file_exists(path9):
|
if FileAccess.file_exists(path9):
|
||||||
DirAccess.remove_absolute(path9)
|
DirAccess.remove_absolute(path9)
|
||||||
# ⑨ 摘要集成(冒险结构批产物驱动):run_adventure 真局摘要 → apply 原语 → 域读数 → 写盘读回保持
|
# ⑨ 摘要跨系统块(冒险结构批产物驱动):run_adventure 真局摘要 → apply 原语 → 域读数 → 写盘读回保持
|
||||||
var st9: Dictionary = LevelAutoplay.run_adventure(_db, 42, 900, 400)
|
var st9: Dictionary = LevelAutoplay.run_adventure(_db, 42, 900, 400)
|
||||||
var f9 = sm_script.new(path9)
|
var f9 = sm_script.new(path9)
|
||||||
f9.meta_state.apply_adventure_summary(st9.get("summary", {}))
|
f9.meta_state.apply_adventure_summary(st9.get("summary", {}))
|
||||||
var ks_run := 0
|
var ks_run := 0
|
||||||
for li in range(1, int(_db.run.level.rows.size()) + 1):
|
for li in range(1, int(_db.run.level.rows.size()) + 1):
|
||||||
ks_run += int(_db.crossrun.meta.boss_keystone_row(li).get("first_kill", 0))
|
ks_run += int(_db.crossrun.meta.boss_keystone_row(li).get("first_kill", 0))
|
||||||
Kit.check("摘要集成:冒险驱动满配冒险成功(seed 42)", String(st9.get("result", "")) == "completed")
|
Kit.check("摘要跨系统块:冒险驱动满配冒险成功(seed 42)", String(st9.get("result", "")) == "completed")
|
||||||
Kit.check("集成钥石余额 = ΣBoss 首杀行值(%d——逐杀掉落全源)" % f9.meta_state.keystone_balance(), f9.meta_state.keystone_balance() == ks_run)
|
Kit.check("跨系统钥石余额 = ΣBoss 首杀行值(%d——逐杀掉落全源)" % f9.meta_state.keystone_balance(), f9.meta_state.keystone_balance() == ks_run)
|
||||||
Kit.check("集成关卡完成次数表全 1", f9.meta_state.career_state().clear_counts.get(str(1), 0) == 1 and f9.meta_state.career_state().clear_counts.get(str(2), 0) == 1 and f9.meta_state.career_state().clear_counts.get(str(3), 0) == 1)
|
Kit.check("跨系统关卡完成次数表全 1", f9.meta_state.career_state().clear_counts.get(str(1), 0) == 1 and f9.meta_state.career_state().clear_counts.get(str(2), 0) == 1 and f9.meta_state.career_state().clear_counts.get(str(3), 0) == 1)
|
||||||
Kit.check("集成三关首杀标记齐", f9.meta_state.career_state().boss_first_kill.has(str(1)) and f9.meta_state.career_state().boss_first_kill.has(str(2)) and f9.meta_state.career_state().boss_first_kill.has(str(3)))
|
Kit.check("跨系统三关首杀标记齐", f9.meta_state.career_state().boss_first_kill.has(str(1)) and f9.meta_state.career_state().boss_first_kill.has(str(2)) and f9.meta_state.career_state().boss_first_kill.has(str(3)))
|
||||||
Kit.check("集成 recent 1 条且 seed 42", f9.meta_state.career_state().recent_summaries.size() == 1 and int(f9.meta_state.career_state().recent_summaries[0].get("master_seed", -1)) == 42)
|
Kit.check("跨系统 recent 1 条且 seed 42", f9.meta_state.career_state().recent_summaries.size() == 1 and int(f9.meta_state.career_state().recent_summaries[0].get("master_seed", -1)) == 42)
|
||||||
var st9b: Dictionary = LevelAutoplay.run_adventure(_db, 42, 900, 400)
|
var st9b: Dictionary = LevelAutoplay.run_adventure(_db, 42, 900, 400)
|
||||||
f9.meta_state.apply_adventure_summary(st9b.get("summary", {}))
|
f9.meta_state.apply_adventure_summary(st9b.get("summary", {}))
|
||||||
Kit.check("第二局后关卡完成次数全 2", f9.meta_state.career_state().clear_counts.get(str(1), 0) == 2 and f9.meta_state.career_state().clear_counts.get(str(2), 0) == 2 and f9.meta_state.career_state().clear_counts.get(str(3), 0) == 2)
|
Kit.check("第二局后关卡完成次数全 2", f9.meta_state.career_state().clear_counts.get(str(1), 0) == 2 and f9.meta_state.career_state().clear_counts.get(str(2), 0) == 2 and f9.meta_state.career_state().clear_counts.get(str(3), 0) == 2)
|
||||||
Kit.check("第二局后余额翻倍(2 × Σ首杀——模拟驱动恒首杀口径)", f9.meta_state.keystone_balance() == 2 * ks_run)
|
Kit.check("第二局后余额翻倍(2 × Σ首杀——模拟驱动恒首杀口径)", f9.meta_state.keystone_balance() == 2 * ks_run)
|
||||||
Kit.check("集成 recent 长度 2", f9.meta_state.career_state().recent_summaries.size() == 2)
|
Kit.check("跨系统 recent 长度 2", f9.meta_state.career_state().recent_summaries.size() == 2)
|
||||||
Kit.check("集成写盘成功", f9.write_to_disk())
|
Kit.check("跨系统写盘成功", f9.write_to_disk())
|
||||||
var r9 = sm_script.new(path9)
|
var r9 = sm_script.new(path9)
|
||||||
Kit.check("集成写盘读回全量保持", r9.load_from_disk() and r9.meta_state.keystone_balance() == 2 * ks_run and r9.meta_state.career_state().clear_counts.get(str(3), 0) == 2
|
Kit.check("跨系统写盘读回全量保持", r9.load_from_disk() and r9.meta_state.keystone_balance() == 2 * ks_run and r9.meta_state.career_state().clear_counts.get(str(3), 0) == 2
|
||||||
and r9.meta_state.career_state().recent_summaries.size() == 2 and r9.meta_state.career_state().boss_first_kill.has(str(3)))
|
and r9.meta_state.career_state().recent_summaries.size() == 2 and r9.meta_state.career_state().boss_first_kill.has(str(3)))
|
||||||
if FileAccess.file_exists(path9): # 段尾清理(与段首清场对称——源 _smoke_save 同款)
|
if FileAccess.file_exists(path9): # 段尾清理(与段首清场对称——源 _smoke_save 同款)
|
||||||
DirAccess.remove_absolute(path9)
|
DirAccess.remove_absolute(path9)
|
||||||
|
|
||||||
|
|
||||||
# ---- ④ 试玩记录仪(源 `_smoke_playtest_logger` 整套八条,主会话裁决七改判集成——
|
# ---- ④ 试玩记录仪(源 `_smoke_playtest_logger` 整套八条,主会话裁决七改判跨系统闭环承载——
|
||||||
# PlaytestLogger 挂真实结算流:会话文件/逐结算快照/字段齐备/spawn_count 回归/诊断转储/JSONL 回读)----
|
# PlaytestLogger 挂真实结算流:会话文件/逐结算快照/字段齐备/spawn_count 回归/诊断转储/JSONL 回读)----
|
||||||
func _smoke_playtest_logger() -> void:
|
func _smoke_playtest_logger() -> void:
|
||||||
# oracle: design/engineering/code-conventions.md:40 (试玩日志器跨系统接线组)
|
# oracle: design/engineering/code-conventions.md:40 (试玩日志器跨系统接线组)
|
||||||
File renamed without changes.
@@ -20,7 +20,7 @@ func _init() -> void:
|
|||||||
|
|
||||||
# ---- 启动初始化断言面(宿主接线注记:源函数名 `_initialize` 是 MainLoop 虚拟入口,
|
# ---- 启动初始化断言面(宿主接线注记:源函数名 `_initialize` 是 MainLoop 虚拟入口,
|
||||||
# 单元宿主改由 `_init` 显式调用,断言逐字未动;源 :70 事件日志落盘条经主会话裁决一
|
# 单元宿主改由 `_init` 显式调用,断言逐字未动;源 :70 事件日志落盘条经主会话裁决一
|
||||||
# 改判集成测试——不随本宿主,见迁移账本转办清单)----
|
# 改判跨系统闭环套件——不随本宿主,见迁移账本转办清单)----
|
||||||
func _smoke_initialize() -> void:
|
func _smoke_initialize() -> void:
|
||||||
# oracle: design/engineering/architecture/architecture.md:90 RngService autoload:open_stream 有状态门面与启动初始化(启动流组)
|
# oracle: design/engineering/architecture/architecture.md:90 RngService autoload:open_stream 有状态门面与启动初始化(启动流组)
|
||||||
print("=== Dungeon Sweeper 垂直切片冒烟 ===")
|
print("=== Dungeon Sweeper 垂直切片冒烟 ===")
|
||||||
|
|||||||
+3
-3
@@ -1,13 +1,13 @@
|
|||||||
# tests/integration/node_map_determinism_test.gd — L2 集成用例:关卡节点图生成·确定性承载
|
# tests/unit/node_map_determinism_test.gd — 跨系统真实路径闭环套件:关卡节点图生成·确定性承载
|
||||||
# 断言面 = 生成图确定性套(批 B 断言迁移自 smoke_all.gd,G12 施工组;
|
# 断言面 = 生成图确定性套(批 B 断言迁移自 smoke_all.gd,G12 施工组;
|
||||||
# 主会话裁决六整套集成不拆——跨四系统且走落盘)。
|
# 主会话裁决六整套不拆——跨四系统且走落盘)。
|
||||||
# 跨系统面 = RngService(纯派生流零计数器占用)×
|
# 跨系统面 = RngService(纯派生流零计数器占用)×
|
||||||
# LevelRunner(start_level/start_level_external 受理·生成图装配·单一图源)×
|
# LevelRunner(start_level/start_level_external 受理·生成图装配·单一图源)×
|
||||||
# AdventureRunner(开局种子承载·断点写读后同图)×
|
# AdventureRunner(开局种子承载·断点写读后同图)×
|
||||||
# SaveManager+MetaProgression(首次冒险布尔位收束置位落盘——真实档写盘)。
|
# SaveManager+MetaProgression(首次冒险布尔位收束置位落盘——真实档写盘)。
|
||||||
# 与单元侧同入口同协议:extends SceneTree+Kit.check 主通道;--script 模式无 autoload,
|
# 与单元侧同入口同协议:extends SceneTree+Kit.check 主通道;--script 模式无 autoload,
|
||||||
# ConfigDB 显式实例化构造注入;表加载失败不中止(沿被迁断言面的源语义——诊断展开,红由具体断言落)。
|
# ConfigDB 显式实例化构造注入;表加载失败不中止(沿被迁断言面的源语义——诊断展开,红由具体断言落)。
|
||||||
# 运行:godot --headless --path game --script res://tests/integration/node_map_determinism_test.gd
|
# 运行:godot --headless --path game --script res://tests/unit/node_map_determinism_test.gd
|
||||||
extends SceneTree
|
extends SceneTree
|
||||||
|
|
||||||
const Kit := preload("res://tests/unit/test_kit.gd")
|
const Kit := preload("res://tests/unit/test_kit.gd")
|
||||||
File renamed without changes.
@@ -15,7 +15,7 @@
|
|||||||
# ConfigDB/RngService 显式实例化构造注入(统一流 master 种子 42 沿源);表加载失败不中止
|
# ConfigDB/RngService 显式实例化构造注入(统一流 master 种子 42 沿源);表加载失败不中止
|
||||||
# (沿被迁断言面的源语义——诊断在此展开,红由具体断言落,承 G2–G5 同款);全局 class_name
|
# (沿被迁断言面的源语义——诊断在此展开,红由具体断言落,承 G2–G5 同款);全局 class_name
|
||||||
# (UiKit)裸用(--script 模式全局类在册,G3 先例)。
|
# (UiKit)裸用(--script 模式全局类在册,G3 先例)。
|
||||||
# 分宿主注记:源 `_smoke_playtest_logger`(挂真实结算流跨系统)经主会话裁决七改判集成测试,
|
# 分宿主注记:源 `_smoke_playtest_logger`(挂真实结算流跨系统)经主会话裁决七改判跨系统闭环套件,
|
||||||
# 不随本宿主——见迁移账本转办清单;`_smoke_global_theme` 依赖 ThemeDB 项目主题在座,
|
# 不随本宿主——见迁移账本转办清单;`_smoke_global_theme` 依赖 ThemeDB 项目主题在座,
|
||||||
# 裁决四要求实跑验证(本批零测试运行,验证归装配验证轮)。
|
# 裁决四要求实跑验证(本批零测试运行,验证归装配验证轮)。
|
||||||
# 运行:godot --headless --path game --script res://tests/unit/presentation/theme_projection_test.gd
|
# 运行:godot --headless --path game --script res://tests/unit/presentation/theme_projection_test.gd
|
||||||
|
|||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
# tests/integration/save_rng_roundtrip_test.gd — L2 集成用例:存档 ⇄ RNG 快照往返
|
# tests/unit/save_rng_roundtrip_test.gd — 跨系统真实路径闭环套件:存档 ⇄ RNG 快照往返
|
||||||
# 跨系统面 = SaveManager(落盘 + 版本迁移链)× AdventureRunner(断点消费)×
|
# 跨系统面 = SaveManager(落盘 + 版本迁移链)× AdventureRunner(断点消费)×
|
||||||
# RngService(种子/取数号位续跑)× BoardGenerator(开板确定性)。
|
# RngService(种子/取数号位续跑)× BoardGenerator(开板确定性)。
|
||||||
# 与 tests/unit/core/breakpoint_resume_test.gd 的分工:那件是单测,只验「断点写读 + 首战开板一致」;
|
# 与 tests/unit/core/breakpoint_resume_test.gd 的分工:那件是单测,只验「断点写读 + 首战开板一致」;
|
||||||
# 本件验的是**跨系统闭环**——盘上往返(含旧版本档经迁移链)之后,断点仍能被冒险层消费且 RNG 续跑
|
# 本件验的是**跨系统闭环**——盘上往返(含旧版本档经迁移链)之后,断点仍能被冒险层消费且 RNG 续跑
|
||||||
# 零跳号,是「玩家的旧存档还能不能接着打」这条真实路径。
|
# 零跳号,是「玩家的旧存档还能不能接着打」这条真实路径。
|
||||||
# 运行:godot --headless --path game --script res://tests/integration/save_rng_roundtrip_test.gd
|
# 运行:godot --headless --path game --script res://tests/unit/save_rng_roundtrip_test.gd
|
||||||
extends SceneTree
|
extends SceneTree
|
||||||
|
|
||||||
const SaveManagerScript := preload("res://core/save_manager.gd")
|
const SaveManagerScript := preload("res://core/save_manager.gd")
|
||||||
@@ -65,7 +65,7 @@ func _test_disk_roundtrip_preserves_breakpoint() -> void:
|
|||||||
"往返用例:生命账本往返保真")
|
"往返用例:生命账本往返保真")
|
||||||
|
|
||||||
|
|
||||||
# ---- 用例二:旧版本档经迁移链后仍可续玩(单测不覆盖的跨系统集成面)----
|
# ---- 用例二:旧版本档经迁移链后仍可续玩(单测不覆盖的跨系统闭环面)----
|
||||||
func _test_old_version_save_migrates_and_resumes() -> void:
|
func _test_old_version_save_migrates_and_resumes() -> void:
|
||||||
# oracle: design/gdd/systems/表现与支撑/存档序列化.md:179 (旧档迁移链读回续玩组)
|
# oracle: design/gdd/systems/表现与支撑/存档序列化.md:179 (旧档迁移链读回续玩组)
|
||||||
var rng := RngServiceScript.new()
|
var rng := RngServiceScript.new()
|
||||||
File renamed without changes.
@@ -11,7 +11,7 @@
|
|||||||
# --gates),闸件改动不再零触发,也不在远端重复烧引擎。
|
# --gates),闸件改动不再零触发,也不在远端重复烧引擎。
|
||||||
# 3. diff 空 → skip。
|
# 3. diff 空 → skip。
|
||||||
# 判定面说明:game/tests/** 与 game/sim/** 属 game/ 行为载体(.md 除外)→ full,
|
# 判定面说明:game/tests/** 与 game/sim/** 属 game/ 行为载体(.md 除外)→ full,
|
||||||
# 与 run_all_gates.sh 关联档口径一致(测量面批单元与集成测试照跑全套件)。
|
# 与 run_all_gates.sh 关联档口径一致(测量面批单元测试照跑全套件)。
|
||||||
set -u
|
set -u
|
||||||
base="${1:-}"
|
base="${1:-}"
|
||||||
head="${2:-HEAD}"
|
head="${2:-HEAD}"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ tools/coverage_report.html 经 <script src> 直载。
|
|||||||
|
|
||||||
六层与日志源(层键=面板消费键,层名=呈现名):
|
六层与日志源(层键=面板消费键,层名=呈现名):
|
||||||
smoke 冒烟测试 smoke_boot.log 摘要「N 项检查,M 项失败」
|
smoke 冒烟测试 smoke_boot.log 摘要「N 项检查,M 项失败」
|
||||||
unit 单元与集成测试 unit.log 每套件「[run_all] PASS/FAIL res://…(exit=N)」
|
unit 单元测试 unit.log 每套件「[run_all] PASS/FAIL res://…(exit=N)」
|
||||||
system 系统测试 system_test.log 摘要「N 项检查,M 项失败」
|
system 系统测试 system_test.log 摘要「N 项检查,M 项失败」
|
||||||
probe 场景探针 probe.log 每探针段「======== 名(段)========」+该段 PASS/FAIL 行
|
probe 场景探针 probe.log 每探针段「======== 名(段)========」+该段 PASS/FAIL 行
|
||||||
render 渲染闸 render.log golden 清单与对比结果
|
render 渲染闸 render.log golden 清单与对比结果
|
||||||
@@ -123,7 +123,7 @@ def parse_static(log: str) -> dict:
|
|||||||
|
|
||||||
LAYERS = [
|
LAYERS = [
|
||||||
("smoke", "冒烟测试", "smoke_boot.log", parse_summary_layer),
|
("smoke", "冒烟测试", "smoke_boot.log", parse_summary_layer),
|
||||||
("unit", "单元与集成测试", "unit.log", parse_unit),
|
("unit", "单元测试", "unit.log", parse_unit),
|
||||||
("system", "系统测试", "system_test.log", parse_summary_layer),
|
("system", "系统测试", "system_test.log", parse_summary_layer),
|
||||||
("probe", "场景探针", "probe.log", parse_probe),
|
("probe", "场景探针", "probe.log", parse_probe),
|
||||||
("render", "渲染闸", "render.log", parse_render),
|
("render", "渲染闸", "render.log", parse_render),
|
||||||
|
|||||||
@@ -70,12 +70,15 @@ RETIRED_TERMS = [
|
|||||||
("插旗|标旗", "2026-10-18", "封印(正式动作名,全库统一)", "术语刷新批——「旗」概念退役"),
|
("插旗|标旗", "2026-10-18", "封印(正式动作名,全库统一)", "术语刷新批——「旗」概念退役"),
|
||||||
("完美排雷", "2026-10-19", "完美封印(正式名见 design/gdd/术语表.md 退役词对照)", "迭代 32 卡①反哺批 2026-10-21 用户裁入表——代码注释面由 S11 承接,文档正文面由此条承接"),
|
("完美排雷", "2026-10-19", "完美封印(正式名见 design/gdd/术语表.md 退役词对照)", "迭代 32 卡①反哺批 2026-10-21 用户裁入表——代码注释面由 S11 承接,文档正文面由此条承接"),
|
||||||
# —— 测试术语与层级重构批(2026-10-22 用户裁):权威=design/gdd/术语表.md「退役词对照」——
|
# —— 测试术语与层级重构批(2026-10-22 用户裁):权威=design/gdd/术语表.md「退役词对照」——
|
||||||
# 标准四级测试层(冒烟/单元/集成/系统)+UI 探针与 golden;闸档用语随三条频率规则消亡。
|
# 标准测试层(冒烟/单元/系统)+UI 探针与 golden;闸档用语随三条频率规则消亡。
|
||||||
# 「重闸」用负向后行断言排除机制词「去重闸」(封印重判去重判别器,在役非退役)。
|
# 「重闸」用负向后行断言排除机制词「去重闸」(封印重判去重判别器,在役非退役)。
|
||||||
("系统级断言套件|冒烟全量", "2026-10-22", "系统测试", "测试术语重构批——标准四级层命名(裁决录=提案 §二——提案已退役,考古=git 历史——删除批 53075baa,删除前全稿见历史版本 b4da36a8)"),
|
("系统级断言套件|冒烟全量", "2026-10-22", "系统测试", "测试术语重构批——标准四级层命名(裁决录=提案 §二——提案已退役,考古=git 历史——删除批 53075baa,删除前全稿见历史版本 b4da36a8)"),
|
||||||
("单元套件", "2026-10-22", "单元测试", "测试术语重构批——标准四级层命名"),
|
("单元套件", "2026-10-22", "单元测试", "测试术语重构批——标准四级层命名"),
|
||||||
("启动探针|秒级冒烟探针|L0[–-]L3", "2026-10-22", "冒烟测试", "测试术语重构批——极小启动场景"),
|
("启动探针|秒级冒烟探针|L0[–-]L3", "2026-10-22", "冒烟测试", "测试术语重构批——极小启动场景"),
|
||||||
(r"(?<!去)重闸|轻闸|三查", "2026-10-22", "(随频率规则消亡:检出工作区零测试;卡内只测自己改的东西;全量只有批末+合回两个时机)", "测试术语重构批——闸档用语退役;代码注释面由 S11 承接(S11 设「去重闸」同形异义豁免)"),
|
(r"(?<!去)重闸|轻闸|三查", "2026-10-22", "(随频率规则消亡:检出工作区零测试;卡内只测自己改的东西;全量只有批末+合回两个时机)", "测试术语重构批——闸档用语退役;代码注释面由 S11 承接(S11 设「去重闸」同形异义豁免)"),
|
||||||
|
# —— 测试层合并批(2026-11-07 用户裁):跨系统真实路径闭环套件归单元层,三套件实体迁移 tests/unit/;
|
||||||
|
# 测试层识别三元组=职责×触发时间点×覆盖面积(test-conventions「测试层三元组」节),层级名只是代称。
|
||||||
|
("集成测试|集成用例|集成层|集成侧|集成宿主|集成族", "2026-11-07", "单元测试(跨系统真实路径闭环套件归单元层,性质归属由套件头注承载)", "测试层合并批——「集成」层级词退役,文档正文面由此条承接,代码注释面由 S11 承接"),
|
||||||
# —— 旧词残留清扫批(2026-10-26 用户裁):权威=design/gdd/术语表.md「退役词对照」——
|
# —— 旧词残留清扫批(2026-10-26 用户裁):权威=design/gdd/术语表.md「退役词对照」——
|
||||||
# 魔法道具=秘宝旧中文规范名(2026-10-05 消歧更名);罕见=旧三档档位名,现行四级第三档=稀有
|
# 魔法道具=秘宝旧中文规范名(2026-10-05 消歧更名);罕见=旧三档档位名,现行四级第三档=稀有
|
||||||
# (档名映射见 adventure_table.gd 头注)——散文形容词义的「罕见」人工判读,不算档位名残留。
|
# (档名映射见 adventure_table.gd 头注)——散文形容词义的「罕见」人工判读,不算档位名残留。
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ r"""extract_checks.py — 断言静态提取器(验证集清单生成与出口
|
|||||||
python tools/extract_checks.py --list-funcs [--src <源文件>...]
|
python tools/extract_checks.py --list-funcs [--src <源文件>...]
|
||||||
只打印函数清单与各函数条数(编账本辅助,不写文件)
|
只打印函数清单与各函数条数(编账本辅助,不写文件)
|
||||||
|
|
||||||
断言源(--src 可多个;缺省=三宿主遍历):
|
断言源(--src 可多个;缺省=单元层遍历):
|
||||||
game/tests/unit/**/*.gd + game/tests/integration/**/*.gd + game/tests/system_test.gd
|
game/tests/unit/**/*.gd + game/tests/system_test.gd
|
||||||
批 B 出口对账用显式模式(--src 列全本批宿主文件)——缺省遍历含既有套件的 Kit.check
|
批 B 出口对账用显式模式(--src 列全本批宿主文件)——缺省遍历含既有套件的 Kit.check
|
||||||
断言,对账时以「新增」出现(非迁移面),出口判定以显式模式为准。
|
断言,对账时以「新增」出现(非迁移面),出口判定以显式模式为准。
|
||||||
|
|
||||||
提取口径:
|
提取口径:
|
||||||
- 静态断言调用点,三通道都认:smoke/系统宿主的 check(cond, label)(cond 在前)、
|
- 静态断言调用点,三通道都认:smoke/系统宿主的 check(cond, label)(cond 在前)、
|
||||||
单元/集成宿主的 Kit.check("label", cond)(点前缀=标签在前)、静默收集通道
|
单元宿主的 Kit.check("label", cond)(点前缀=标签在前)、静默收集通道
|
||||||
Kit.check_quiet(cond, label)(cond 在前,条目 quiet 列记 channel:check_quiet);
|
Kit.check_quiet(cond, label)(cond 在前,条目 quiet 列记 channel:check_quiet);
|
||||||
`_check(` 等同名前缀调用非标准通道,不取。
|
`_check(` 等同名前缀调用非标准通道,不取。
|
||||||
- 调用点可跨行:从调用名起括号配平归集完整实参文本(() [] {} 三种括号都计深度);
|
- 调用点可跨行:从调用名起括号配平归集完整实参文本(() [] {} 三种括号都计深度);
|
||||||
@@ -45,18 +45,17 @@ from datetime import date
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parent.parent
|
ROOT = Path(__file__).resolve().parent.parent
|
||||||
# 断言源缺省=三宿主遍历:unit/**+integration/** 两目录递归 + 系统宿主单文件。
|
# 断言源缺省=单元层目录递归 + 系统宿主单文件(跨系统闭环套件同住 unit/,随目录递归收进来)。
|
||||||
# 遍历面含既有套件的 Kit.check 断言(非本批迁移面,对账呈「新增」)——出口对账用 --src 显式列宿主。
|
# 遍历面含既有套件的 Kit.check 断言(非本批迁移面,对账呈「新增」)——出口对账用 --src 显式列宿主。
|
||||||
DEFAULT_TREES = (
|
DEFAULT_TREES = (
|
||||||
ROOT / "game" / "tests" / "unit",
|
ROOT / "game" / "tests" / "unit",
|
||||||
ROOT / "game" / "tests" / "integration",
|
|
||||||
ROOT / "game" / "tests" / "system_test.gd",
|
ROOT / "game" / "tests" / "system_test.gd",
|
||||||
)
|
)
|
||||||
DEFAULT_OUT = ROOT / "game" / "tests" / "验证集清单.md"
|
DEFAULT_OUT = ROOT / "game" / "tests" / "验证集清单.md"
|
||||||
|
|
||||||
|
|
||||||
def default_sources():
|
def default_sources():
|
||||||
"""三宿主遍历:两目录递归 *.gd + 系统宿主单文件,路径排序定序。"""
|
"""单元层遍历:unit 目录递归 *.gd + 系统宿主单文件,路径排序定序。"""
|
||||||
files = []
|
files = []
|
||||||
for p in DEFAULT_TREES:
|
for p in DEFAULT_TREES:
|
||||||
if p.is_file():
|
if p.is_file():
|
||||||
@@ -342,7 +341,7 @@ def render_list(entries, funcs_by_src, src_names, carry=None) -> str:
|
|||||||
out.append("")
|
out.append("")
|
||||||
out.append("> 生成日期:%s · 基点 commit:`%s` · 源:%s" % (date.today().isoformat(), base_commit(), "、".join(src_names)))
|
out.append("> 生成日期:%s · 基点 commit:`%s` · 源:%s" % (date.today().isoformat(), base_commit(), "、".join(src_names)))
|
||||||
out.append("> 提取口径:静态 `check(`/`check_quiet(` 调用点,括号配平归集(可跨行);缺省源=三宿主遍历")
|
out.append("> 提取口径:静态 `check(`/`check_quiet(` 调用点,括号配平归集(可跨行);缺省源=三宿主遍历")
|
||||||
out.append("> (unit/**+integration/**+system_test.gd)。本基点实测 %d 个静态调用点;行级" % len(entries))
|
out.append("> (unit/**+system_test.gd)。本基点实测 %d 个静态调用点;行级" % len(entries))
|
||||||
out.append("> `grep -c \"check(\"` 是另一口径(含 `func check(` 定义行与注释行),两口径各自浮动,")
|
out.append("> `grep -c \"check(\"` 是另一口径(含 `func check(` 定义行与注释行),两口径各自浮动,")
|
||||||
out.append("> 禁互相换算(tests/README「断言计数双口径」)。运行时计数大于静态计数=循环展开条目。")
|
out.append("> 禁互相换算(tests/README「断言计数双口径」)。运行时计数大于静态计数=循环展开条目。")
|
||||||
out.append("> 生成命令:`python tools/extract_checks.py --extract`(可复现;重新生成须 --force;")
|
out.append("> 生成命令:`python tools/extract_checks.py --extract`(可复现;重新生成须 --force;")
|
||||||
@@ -558,7 +557,7 @@ def main() -> int:
|
|||||||
ap.add_argument("--diff", metavar="清单文件", help="与清单逐条对账(批 B 出口机检)")
|
ap.add_argument("--diff", metavar="清单文件", help="与清单逐条对账(批 B 出口机检)")
|
||||||
ap.add_argument("--list-funcs", action="store_true", help="打印函数清单与条数(编账本辅助)")
|
ap.add_argument("--list-funcs", action="store_true", help="打印函数清单与条数(编账本辅助)")
|
||||||
ap.add_argument("--src", nargs="+", default=None,
|
ap.add_argument("--src", nargs="+", default=None,
|
||||||
help="断言源文件(可多个;缺省=三宿主遍历 unit/**+integration/**+system_test.gd)")
|
help="断言源文件(可多个;缺省=单元层遍历 unit/**+system_test.gd)")
|
||||||
ap.add_argument("--out", default=str(DEFAULT_OUT), help="--extract 输出路径")
|
ap.add_argument("--out", default=str(DEFAULT_OUT), help="--extract 输出路径")
|
||||||
ap.add_argument("--force", action="store_true", help="输出文件已存在时允许覆盖")
|
ap.add_argument("--force", action="store_true", help="输出文件已存在时允许覆盖")
|
||||||
ap.add_argument("--carry-from", default=None, metavar="旧清单",
|
ap.add_argument("--carry-from", default=None, metavar="旧清单",
|
||||||
|
|||||||
+15
-15
@@ -10,16 +10,16 @@
|
|||||||
# 跑闸时代码面带着未提交改动,回执会标 dirty_game(验的不是 HEAD 字节)。
|
# 跑闸时代码面带着未提交改动,回执会标 dirty_game(验的不是 HEAD 字节)。
|
||||||
#
|
#
|
||||||
# 用法:tools/run_all_gates.sh [--code|--docs|--gates|--premerge|--quick]
|
# 用法:tools/run_all_gates.sh [--code|--docs|--gates|--premerge|--quick]
|
||||||
# --premerge 合回前置检查档(2026-11-06 用户裁):只跑冒烟测试+单元与集成测试全套件(4 分片,
|
# --premerge 合回前置检查档(2026-11-06 用户裁):只跑冒烟测试+单元测试全套件(4 分片,
|
||||||
# 热导入缓存约 2 分钟)——主工作区 git merge --no-ff 落合并提交前由 pre-merge-commit
|
# 热导入缓存约 2 分钟)——主工作区 git merge --no-ff 落合并提交前由 pre-merge-commit
|
||||||
# 钩子自动调用的拦截面。退出码聚合即判定(三硬闸口径),不落回执、不比基线——
|
# 钩子自动调用的拦截面。退出码聚合即判定(三硬闸口径),不落回执、不比基线——
|
||||||
# 验证台账归合回后远端 CI,本档只做当场拦截。快进合并不触发钩子;--no-verify 仅属用户。
|
# 验证台账归合回后远端 CI,本档只做当场拦截。快进合并不触发钩子;--no-verify 仅属用户。
|
||||||
# --code 只跑代码域闸(冒烟测试/系统测试/单元与集成测试/场景探针/
|
# --code 只跑代码域闸(冒烟测试/系统测试/单元测试/场景探针/
|
||||||
# 渲染闸/静态扫描+熵增闸)
|
# 渲染闸/静态扫描+熵增闸)
|
||||||
# ——本批改动含 game/ 下非 .md 的行为载体(代码/测试脚本/探针/场景/数据表/素材)时用。
|
# ——本批改动含 game/ 下非 .md 的行为载体(代码/测试脚本/探针/场景/数据表/素材)时用。
|
||||||
# 关联档选闸(2026-10-29 用户裁,推广自 2026-10-28 影响面选闸):冒烟测试/系统测试/
|
# 关联档选闸(2026-10-29 用户裁,推广自 2026-10-28 影响面选闸):冒烟测试/系统测试/
|
||||||
# 静态扫描三件保险恒跑不降;场景探针与渲染闸维持影响面口径(本批 game/ 改动
|
# 静态扫描三件保险恒跑不降;场景探针与渲染闸维持影响面口径(本批 game/ 改动
|
||||||
# 全在测量面 game/tests、game/sim 时记 SKIP);单元与集成测试改「选套件跑」——套件集=
|
# 全在测量面 game/tests、game/sim 时记 SKIP);单元测试改「选套件跑」——套件集=
|
||||||
# 需求卡片申报 ∪ diff 推导并集(算法与套件族映射表见脚本中部),横切面(公共件/数据表/
|
# 需求卡片申报 ∪ diff 推导并集(算法与套件族映射表见脚本中部),横切面(公共件/数据表/
|
||||||
# autoload/数值·存档·RNG·结算触面)回落全套件;回执 scope 字段记 full|related。
|
# autoload/数值·存档·RNG·结算触面)回落全套件;回执 scope 字段记 full|related。
|
||||||
# --docs 只跑文档域闸(gdd_lint/doc_link/doc_term/流水线闸/引用可核/
|
# --docs 只跑文档域闸(gdd_lint/doc_link/doc_term/流水线闸/引用可核/
|
||||||
@@ -198,9 +198,9 @@ suite_terms_for() { # suite_terms_for <仓库相对路径> → stdout: 套件
|
|||||||
game/core/meta_state_store.gd|game/core/slot_store.gd|game/core/gp_wallet.gd|\
|
game/core/meta_state_store.gd|game/core/slot_store.gd|game/core/gp_wallet.gd|\
|
||||||
game/core/shop_session.gd)
|
game/core/shop_session.gd)
|
||||||
echo "core" ;;
|
echo "core" ;;
|
||||||
# 冒险结构×存档断点×关卡推进(core 族+跨系统集成族)
|
# 冒险结构×存档断点×关卡推进(core 族+跨系统闭环族——三套件按文件名词选)
|
||||||
game/core/adventure_runner.gd|game/core/level_runner.gd)
|
game/core/adventure_runner.gd|game/core/level_runner.gd)
|
||||||
echo "core integration" ;;
|
echo "core save_rng cross_system node_map" ;;
|
||||||
# 配置域表类(autoload 本体与解析器/跨表校验器走横切,不入本表)
|
# 配置域表类(autoload 本体与解析器/跨表校验器走横切,不入本表)
|
||||||
game/core/config_domain_*.gd)
|
game/core/config_domain_*.gd)
|
||||||
echo "data_config core" ;;
|
echo "data_config core" ;;
|
||||||
@@ -222,7 +222,7 @@ suite_terms_for() { # suite_terms_for <仓库相对路径> → stdout: 套件
|
|||||||
# 三件保险恒跑不降:冒烟测试/系统测试/静态扫描(熵增闸照旧两域都跑)。
|
# 三件保险恒跑不降:冒烟测试/系统测试/静态扫描(熵增闸照旧两域都跑)。
|
||||||
# 场景探针与渲染闸维持影响面口径:本批 diff 相对 master 分叉点的 game/ 改动若全部落在
|
# 场景探针与渲染闸维持影响面口径:本批 diff 相对 master 分叉点的 game/ 改动若全部落在
|
||||||
# 测量面(game/tests/**、game/sim/**——测试与模拟驱动件,不触场景树与渲染输出)则记 SKIP。
|
# 测量面(game/tests/**、game/sim/**——测试与模拟驱动件,不触场景树与渲染输出)则记 SKIP。
|
||||||
# 单元与集成测试改「选套件跑」:套件集=申报 ∪ 推导 取并集——
|
# 单元测试改「选套件跑」:套件集=申报 ∪ 推导 取并集——
|
||||||
# 申报:在册需求卡片(本批 diff 触及的 reports/需求卡片*.md ∪ roadmap「进行中」迭代行登记的
|
# 申报:在册需求卡片(本批 diff 触及的 reports/需求卡片*.md ∪ roadmap「进行中」迭代行登记的
|
||||||
# 卡片)对照表「验收测试」列提到的测试文件名,按文件名作为 --only 子串词归套件;
|
# 卡片)对照表「验收测试」列提到的测试文件名,按文件名作为 --only 子串词归套件;
|
||||||
# 找不到在册卡片则申报集为空并输出注明。
|
# 找不到在册卡片则申报集为空并输出注明。
|
||||||
@@ -230,9 +230,9 @@ suite_terms_for() { # suite_terms_for <仓库相对路径> → stdout: 套件
|
|||||||
# 映射不到的文件一律按横切处理。
|
# 映射不到的文件一律按横切处理。
|
||||||
# 横切回落全量:diff 命中 game/data/tables/**、公共件前缀(config_db*/rng_service*/
|
# 横切回落全量:diff 命中 game/data/tables/**、公共件前缀(config_db*/rng_service*/
|
||||||
# save_manager*/meta_progression*/main*——main* 覆盖组合根拆件与主场景)、
|
# save_manager*/meta_progression*/main*——main* 覆盖组合根拆件与主场景)、
|
||||||
# autoload 注册面(game/project.godot)、或下方横切触面表任一 → 单元与集成测试跑全部套件。
|
# autoload 注册面(game/project.godot)、或下方横切触面表任一 → 单元测试跑全部套件。
|
||||||
# 测量面批(game/ 改动全在 tests/sim):单元与集成测试照旧全套件跑(不加过滤)。
|
# 测量面批(game/ 改动全在 tests/sim):单元测试照旧全套件跑(不加过滤)。
|
||||||
# 回执 scope 字段:full|related(单元与集成测试跑子集=related);映射表只在本脚本一处定义。
|
# 回执 scope 字段:full|related(单元测试跑子集=related);映射表只在本脚本一处定义。
|
||||||
NONBEHAVIOR=0
|
NONBEHAVIOR=0
|
||||||
SCOPE="full"
|
SCOPE="full"
|
||||||
ONLY_TERMS=""
|
ONLY_TERMS=""
|
||||||
@@ -245,7 +245,7 @@ if in_domain code; then
|
|||||||
NONBEHAVIOR=1
|
NONBEHAVIOR=1
|
||||||
echo "[gates] 影响面选闸:game/ 改动全在测量面(tests/sim)——场景探针/渲染闸 → SKIP(冒烟测试/系统测试/静态扫描三件保险恒跑)"
|
echo "[gates] 影响面选闸:game/ 改动全在测量面(tests/sim)——场景探针/渲染闸 → SKIP(冒烟测试/系统测试/静态扫描三件保险恒跑)"
|
||||||
fi
|
fi
|
||||||
# ── 选套件推导(只对行为面代码文件做——测量面文件不进推导,其验证就是单元与集成测试/静态扫描自身)──
|
# ── 选套件推导(只对行为面代码文件做——测量面文件不进推导,其验证就是单元测试/静态扫描自身)──
|
||||||
_codefiles="$(echo "$_gfiles" | grep -viE '\.md$' | grep -vE '^(game/tests/|game/sim/)' || true)"
|
_codefiles="$(echo "$_gfiles" | grep -viE '\.md$' | grep -vE '^(game/tests/|game/sim/)' || true)"
|
||||||
if [ -n "$_codefiles" ]; then
|
if [ -n "$_codefiles" ]; then
|
||||||
CROSSCUT=0
|
CROSSCUT=0
|
||||||
@@ -281,7 +281,7 @@ if in_domain code; then
|
|||||||
done
|
done
|
||||||
if [ "$CROSSCUT" -eq 1 ]; then
|
if [ "$CROSSCUT" -eq 1 ]; then
|
||||||
SCOPE="full"
|
SCOPE="full"
|
||||||
echo "[gates] 关联档选闸:diff 命中横切面(公共件/数据表/autoload/数值·存档·RNG·结算触面)——单元与集成测试回落全部套件"
|
echo "[gates] 关联档选闸:diff 命中横切面(公共件/数据表/autoload/数值·存档·RNG·结算触面)——单元测试回落全部套件"
|
||||||
else
|
else
|
||||||
# 并集去重:推导族词 ∪ 申报测试文件名;并集非空才过滤(映射表保证族词非空,此处双保险)。
|
# 并集去重:推导族词 ∪ 申报测试文件名;并集非空才过滤(映射表保证族词非空,此处双保险)。
|
||||||
_union="$(printf '%s\n' $_family_terms $_declared_names | sed '/^$/d' | sort -u | tr '\n' ' ' || true)"
|
_union="$(printf '%s\n' $_family_terms $_declared_names | sed '/^$/d' | sort -u | tr '\n' ' ' || true)"
|
||||||
@@ -297,7 +297,7 @@ if in_domain code; then
|
|||||||
echo "[gates] 关联档选闸·申报:未找到在册需求卡片(diff 与 roadmap 进行中行均无),申报集为空——仅按 diff 推导"
|
echo "[gates] 关联档选闸·申报:未找到在册需求卡片(diff 与 roadmap 进行中行均无),申报集为空——仅按 diff 推导"
|
||||||
fi
|
fi
|
||||||
if [ "$SCOPE" = related ]; then
|
if [ "$SCOPE" = related ]; then
|
||||||
echo "[gates] 关联档选闸:单元与集成测试选套件跑(--only=${ONLY_TERMS})"
|
echo "[gates] 关联档选闸:单元测试选套件跑(--only=${ONLY_TERMS})"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -344,7 +344,7 @@ gate() { # gate <名称> <日志名> <命令...>
|
|||||||
}
|
}
|
||||||
|
|
||||||
gate_unit() { # run_all 是 --script 模式,退出码为唯一判据;分片态=多 Godot 进程各跑一片
|
gate_unit() { # run_all 是 --script 模式,退出码为唯一判据;分片态=多 Godot 进程各跑一片
|
||||||
local name="单元与集成测试"
|
local name="单元测试"
|
||||||
# 关联档选跑:把套件词列表经 --only= 传给 run_all(闸机来源标记 --only-source=gates,
|
# 关联档选跑:把套件词列表经 --only= 传给 run_all(闸机来源标记 --only-source=gates,
|
||||||
# 入口据此打关联档横幅、不落「仅供开发期」免责句);全量态不传任何选跑参数。
|
# 入口据此打关联档横幅、不落「仅供开发期」免责句);全量态不传任何选跑参数。
|
||||||
local -a _user_args=()
|
local -a _user_args=()
|
||||||
@@ -448,7 +448,7 @@ gate_shell_selfcheck() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ══ 合回前置检查档(premerge,2026-11-06 用户裁)══
|
# ══ 合回前置检查档(premerge,2026-11-06 用户裁)══
|
||||||
# 冒烟+单元与集成全套件(4 分片)——合回 merge 点的最小人工拦截面;不是全量、不替代远端 CI。
|
# 冒烟+单元全套件(4 分片)——合回 merge 点的最小人工拦截面;不是全量、不替代远端 CI。
|
||||||
# 选闸推导整段跳过(本档不按 diff 选闸——合回是最后拦截点,恒全套件);退出码聚合即判定,
|
# 选闸推导整段跳过(本档不按 diff 选闸——合回是最后拦截点,恒全套件);退出码聚合即判定,
|
||||||
# 不落回执不比基线(回执与基线面归远端 CI,本档读数只进合并现场)。
|
# 不落回执不比基线(回执与基线面归远端 CI,本档读数只进合并现场)。
|
||||||
if [ "$DOMAIN" = "premerge" ]; then
|
if [ "$DOMAIN" = "premerge" ]; then
|
||||||
@@ -463,7 +463,7 @@ if in_domain code; then
|
|||||||
gate "冒烟测试" "smoke_boot.log" "$PY" "$REPO/tools/run_smoke.py"
|
gate "冒烟测试" "smoke_boot.log" "$PY" "$REPO/tools/run_smoke.py"
|
||||||
# ── 系统测试(真实玩法路径断言面;宿主=game/tests/system_test.gd,缺省 --script 由 run_system_test.py 持有)──
|
# ── 系统测试(真实玩法路径断言面;宿主=game/tests/system_test.gd,缺省 --script 由 run_system_test.py 持有)──
|
||||||
gate "系统测试" "system_test.log" "$PY" "$REPO/tools/run_system_test.py"
|
gate "系统测试" "system_test.log" "$PY" "$REPO/tools/run_system_test.py"
|
||||||
# ── 单元与集成测试 ──
|
# ── 单元测试 ──
|
||||||
gate_unit
|
gate_unit
|
||||||
# ── 场景探针(走查+断言十件一次跑齐;iter27 漏跑断言段事故后固化为无条件整闸)──
|
# ── 场景探针(走查+断言十件一次跑齐;iter27 漏跑断言段事故后固化为无条件整闸)──
|
||||||
if [ $NONBEHAVIOR -eq 1 ]; then
|
if [ $NONBEHAVIOR -eq 1 ]; then
|
||||||
|
|||||||
Reference in new issue
Block a user