# 真实验证 CI

`npm run verify` 负责检查仓库中已生成的证据和静态门禁；它不应被误解为重新启动浏览器、FreeCAD 或 WASM。真实验证入口是：

```bash
./npmw run ci:real -- --lane=chrome
./npmw run ci:real -- --lane=oracle
./npmw run ci:real -- --lane=wasm
```

Chrome 还提供显式的两阶段入口：`./npmw run ci:real:chrome` 只启动真实 Chrome harness 并生成报告，`./npmw run ci:check:chrome` 只读取并校验这些报告。CI 会按这两个步骤执行并上传 JSON/截图证据；因此历史报告检查不会被误认为重新执行了浏览器。随后 `test:browser-matrix` / `check:browser-matrix` 会用 Playwright 的 Firefox 和 WebKit 对生产构建执行 shell、OCCT canvas、COOP/COEP、SharedArrayBuffer 和持久化能力 smoke gate；Firefox 强制 OPFS，WebKit 缺少 OPFS 时必须明确报告 `memory-fallback`。

`--lane=all` 会按 oracle、WASM、Chrome 顺序执行全部 lane。任一命令退出非零都会使整个 lane 失败；完整运行摘要写入 `.cache/ci/real-verification.json`，分阶段运行分别写入 `real-verification-execute.json` 和 `real-verification-check.json`，这些文件不作为仓库基线证据提交。

oracle lane 默认会重新抓取锁定的 FreeCAD commit 并初始化子模块。仅在本机已经具备该 commit、且需要离线复现时，才可显式使用 `FREECAD_SOURCE_OFFLINE=1`；该模式会拒绝未锁定的 checkout，并跳过网络相关子模块更新，不会替代 CI 的真实 fetch。

## Runner 要求

工作流使用标签为 `self-hosted, linux, cad` 的 runner，因为 FreeCAD 原生编译和外围 CAM harness 需要较大的本地工具链。runner 必须提供：

- Node `22.23.2`、CMake、Ninja、C/C++ 编译器和 Python；
- Chrome/Chromium（通过 `CHROME_BIN` 指定）、Firefox 和 WebKit（缓存版本不匹配时分别通过 `FIREFOX_BIN`、`WEBKIT_BIN` 指定）以及可用的无头模式；
- Emscripten（通过 `EMSDK` 指定）和 OCCT 源码目录（通过 `OCCT_SOURCE_DIR` 指定）；
- `CAMotics/`、`OpenCAMLib/`、`cnc_wams_gpt6/`、`working_ocl/` 外部工作树。它们不进入 Git，版本由 `config/` 中的锁定清单和 drift check 校验；
- FreeCAD 构建所需的系统开发包。`ci:real -- --lane=oracle` 会重新抓取锁定的 FreeCAD 源码、配置、编译、安装并执行 oracle，不接受旧报告代替。

工作流中的 `actions/checkout` 不会恢复被 `.gitignore` 忽略的外部工作树；runner 镜像或预热步骤必须提前准备它们。缺少任一依赖时，harness 应失败并暴露缺失项，而不是降级为读取历史 JSON。
