Files
SpineWallpaper/tools/checks/README.md
T
Shuery 3f11426964 feat: TS 构建管线、Spine 抓取器与 wallpapers/ 唯一真相来源
把项目从「手写 dist/」改成「wallpapers/ 是唯一真相来源,dist/ 由 pnpm build 生成」,
并补上配套的类型、门禁与抓取器。一次提交落地整条管线,因为拆开会留下不能构建的中间态。

- src/:运行时与模拟器源码(TS,strict),编译到 build/ 再拷进各分发
- tools/:build / dev / check-{syntax,paths,dist},以及抓取器与回归门禁 tools/checks/
  (.scratch/ 下那批一次性脚本移入 tools/checks/ 并入库为长期门禁)
- wallpapers/:七档壁纸的源数据 + README.md(id/音频/预设的完整规范)
- docs/adr/0005-0008:构建管线与分发拓扑、模拟器契约、自包含 sim、每骨架资源布局
- .gitignore:排除 .scratch/ 的参考资料副本(上游 spine 整仓克隆 ~1.2 GB、
  抓取侦查数据 ~680 MB)与调试转储;这些是本地调查材料,补偿会让仓库无法克隆
- 归一化 .gitignore/CONTEXT.md 行尾(工作区 CRLF、索引 LF 造成的整文件假 diff)

同时修掉三档卡住构建的未完工壁纸:
- kv45 的 meta.json 里 id 还是抓取期场景名 scene_main,经 downloader promote 正名为 kv45
- shajin / zhigengniao_juheye 的 meta.json 误用了骨架描述文件(name/spine/animations/pages)、
  且都缺 preset.template.json;现按规范重建:骨架沉到 spines/<名>/(spine-ts 按 atlas 所在
  目录解析贴图页)、补上元数据与单骨架预设,并清掉 zhigengniao 骨架里指向作者机的绝对路径
- 顺带 promote 已在 sources.yml 里的 kv46(月升之前,与兽共舞)

pnpm check 五道门全绿:10 个分发 / 7 档壁纸 / 141 处引用自包含。
2026-10-02 01:27:02 +08:00

101 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `tools/checks/` — 验收套件
跑一遍就相当于"这次改动没把东西弄坏"的全部证据。它原来是散在 `.scratch/` 里的,
而 `.scratch/` 按 `AGENTS.md` 是**问题与规格**的存放处——这些脚本不是某条 issue 的产物,
issue 关掉之后还要一直跑,所以搬到了这里。
---
## 怎么跑
它们的前置条件不一样,**不能一条命令全跑完**。按下面三组来:
### ① 不需要服务器
```bash
pnpm check # 类型 + 构建 + 语法 + 路径 + 产物自包含 + 游戏合集文案归属
pnpm build sim # 下面几项要 sim 产物
node tools/checks/test-sim-gate.mts # 门禁真的会拦(往页面注入四种外部依赖)
node tools/checks/test-inline-guard.mts # 内联 </script 守卫真的会拦
node tools/checks/test-transform-module.mts # 模块合成的 export 改写
node tools/checks/diff-project.mts # 产物 project.json vs 已发布基线
node tools/checks/check-collection-copy.mts # 游戏合集的文案是"它自己那个游戏"的(先 pnpm build)
node tools/checks/verify-sim-page.mts <分发名> # 自包含包 file:// 可用(含"零 http 请求")
node tools/checks/verify-static-preview.mts <分发名> # 静态托管子路径可用(自带服务器)
node tools/checks/read-audio-tags.mts # 读音频文件自带标签(核对歌名用)
node tools/checks/check-sim-scripts.mts [页面] # 抽出自包含页的每个内联 script 单独语法检查
node tools/checks/check-downloader.mts # 抓取器:能编译 + 夹具绿 + 四处破坏必红(不联网)
node tools/checks/verify-scene-player.mts # 场景播放器:多骨架+平面合成、画面非空、atlas 指错必红
```
`verify-scene-player` 自己跑 `tsc -p tsconfig.runtime.json` 并自造夹具(用抓取器 staged 的
`kv45/scene_main` 与 `nico-tea/scene_main`——staging 是"一个场景一个壁纸目录"),
**不碰 `wallpapers/`、不需要 `pnpm build`**;前置只有 `python -m tools.downloader fetch --page kv45`。
`verify-static-preview` 需要 `pnpm build --with-sim`(面板要随产物走)。
### ② 需要 `serve.mjs`(对拍驱动 `window.__test` 只有它注入)
> ⚠ **跑 `test-inline-guard` 之前必须先停掉 `pnpm dev`。** 它会故意把 `src/vendor/spine-player.js`
> 改坏来验证守卫,而调试服的热更新正在监听 `src/`——两者会抢构建,结果随机失败。
> 同理,任何会写 `dist/` 的构建都别和 watcher 同时跑(`pnpm build sim` 与 watcher 也会抢 `dist/`)。
```bash
node tools/serve.mjs 8190 --root dist/releases/collection-all # 另开一个终端
node tools/checks/test-props.mjs # bgm 选择/回落 + fps 限流
node tools/checks/test-resize.mjs # 改窗口尺寸不泄漏、不跑偏
node tools/checks/test-acceptance.mjs # 体积/文案/音源/构图总验收
node tools/checks/verify-fitter.mjs # viewport-fitter 的纯函数
```
### ③ 需要 `pnpm dev`(模拟器面板)
```bash
node tools/dev.ts --port 5173 --no-build # 另开一个终端
node tools/checks/smoke-dev.mts 5173 # 路由、注入、越界 404
node tools/checks/smoke-sim.mts http://127.0.0.1:5173 # 面板真的挂上、属性真的下发
node tools/checks/verify-panel.mts http://127.0.0.1:5173 # 面板还原度(12 组)
node tools/checks/verify-hot-reload.mts http://127.0.0.1:5173 # 改 CSS 只换样式表、改 runtime 整页刷新
node tools/checks/check-single-bgm.mts http://127.0.0.1:5173 # 单档分发里切歌真的换音源
node tools/checks/shot-panel.mts http://127.0.0.1:5173 [输出目录] # 给面板出图(不是断言)
```
`verify-dev-flags.mts` 要**另一个模式**:先 `node tools/build.ts --with-sim`,
再 `node tools/dev.ts --port 5173 --no-build --with-sim`,然后
`node tools/checks/verify-dev-flags.mts`。它验的是"热更新重建后 `--with-sim` 还在"。
`verify-visual-equivalence.mts` 要两步:先用 `tools/capture.mjs` 拍到
`tools/shots/visual-current/`,再跑它。基线在 `tools/shots/baseline-pre-refactor/`,
**不能重新生成**。
---
## 两层,以及为什么
| 后缀 | 是否被 `pnpm typecheck` 检查 | 说明 |
| --- | --- | --- |
| `.mts` | ✅ 走 `tsconfig.checks.json` | 后来写的验收脚本 |
| `.mjs` | ❌ | 四个早期的运行时测试:`test-acceptance` / `test-props` / `test-resize` / `verify-fitter` |
`tsconfig.checks.json` 只关掉 `noImplicitAny` 一项,其余严格模式照旧——
正是严格模式翻出了 28 处真问题(可能 undefined、`[]` 推成 `never[]`、`catch` 里 `error` 是 unknown、
参数个数不符),其中一条是"文件头声明了 ⑤ 但从未实现的断言"。
**往 `.mjs` 里写类型注解会让它运行时崩。** `.mjs` 是纯 JS,`(x: string) => …` 是 SyntaxError,
而 `tsc` 不管 `.mjs`,所以这个错在类型检查里完全看不见——踩过一次。
要写类型就先改成 `.mts`。
> 把那四个 `.mjs` 也并进受检层是一件独立的、该单独做的事:实测会立刻多出约 80 处既有问题。
> 别在别的改动的尾巴上顺手做。
---
## 约定
- **一个从不失败的检查等于没有检查。** 门禁类的脚本(`test-sim-gate` / `test-inline-guard`)
都要"先证明它会红"——注入一个坏东西,确认它报错,再还原。
- **验证要先检查前置条件。** `verify-dev-flags.mts` 第一件事是 `fetch("/")` 断言服务活着;
否则"服务没起来"会被当成"验证通过"——这是真实发生过的一次空验证。
- **区分"选项在"和"能生效"。** `verify-panel.mts` 断言面板上有那个下拉;
`check-single-bgm.mts` 断言选了之后 `<audio>.src` 真的变了。两者缺一不可。