# 可恢复的案例验收工具 入口复用 B1 的真实 Playwright 用例、原生 session、Vite 隔离头和候选 WASM。它不编译、不下载浏览器、不推进队列。运行环境需要 Linux `flock`、本机 Chromium、现有 Node 依赖;B1 还需要 Blender 可执行文件。 ```bash node tools/web/run-workflow-case.mjs --plan tools/web/workflow-cases/B1.json --candidate build_web_main_desktop/b1-context-readback-20261023 --out tests/golden/WBV2-P1424-001/my-b1-case --port 5288 --packaged ``` - `--check` 只检查本地构件、可执行程序和两个 fixture;不启动服务,不代表 HTTP 或业务通过。 - `--production ` 替换生产片段;`--blender `、`CHROME_PATH` 指定本机程序。 - `--packaged` 验证候选的实际 `app` 页面;不加此参数时使用当前前端源码和指定原生构件。两种模式及打包文件分别绑定输入身份,不互相冒充验收证据。 - 原命令可直接续跑:输入、浏览器版本和产物 hash 一致的 PASS 自动复用;失败后的相同输入必须先查看原因,再显式使用 `--retry-failed`。 - 每个 fixture 使用独立 `attempt-*` 目录,保存命令、状态、HTTP hash、Playwright JSON、日志、截图、trace 和下载文件。不要把需长期保留的数据放在 `web/test-results`。 - 旧进程仍活着时拒绝重复运行;进程已经退出的中断案例保留旧文件,从新浏览器和原始 fixture 开始该案例。成功的前置案例不会随之重跑。 - 顺序固定为 candidate/资源 → 本机运行环境 → 服务/HTTP 隔离与真实 JS/WASM hash → fixture 操作;最小案例失败即停止生产案例。 - `PASS_SELECTED_TESTS` 仅表示配置选中的断言通过。`remainingGates` 保留未覆盖项目,`acceptance` 始终是 `NOT_CLAIMED`;仍由项目评估器和完整案例门禁裁定验收。 - 实际案例批次结束后会自动调用 `evaluate-wbv2-completion.mjs --case-manifest <本批manifest>`;失败也会记录,日志在 `evaluation.log`。评估失败时保留案例产物并返回失败码,不能当作进度已发布。 ## 扩展 B2–B6 B2 已提供 `tools/web/workflow-cases/B2.json`,覆盖现有 Canvas 确认/取消断言,其余门禁保持显式未覆盖。B3–B6 复制此配置,设置批次、业务描述、实际 operator/RNA/Main 源码路径与当前用例选择器;保留一份最小 fixture 和一份真实生产片段。 用例必须从 `process.env.WBV2_CASE_FIXTURE` 读取输入,以 `testInfo.outputPath()` 保存输出。复用 `web/tests/fixtures/native-ui-workflow.ts` 观察 Worker 请求、读回和操作耗时;用源码定义的业务字段做断言。新增配置不会自动扩大验收范围,也不能用 `scope` 文案代替断言。 重开脏工程时使用 `resolveProjectReplacement(page, 'cancel' | 'discard' | 'save')` 操作真实 React 对话框;浏览器 `dialog` 事件不能代替此步骤。重开后必须等到新的 Worker snapshot,再比较 Main 值,不能仅匹配原本就存在的 `SceneIR` 文本。 Console 使用 `console-main-workflow.ts` 的最新结构化回执和递增序号;避免在累积输出中搜索旧坐标。对象名来自实际 fixture,先检查 location/translation 为有限数值三元组,再按明确容差比较 native/WASM 读回。 原生 WASM Console 复用 `wasm-console-workflow.ts`:先等新 `pythonExec` 请求(10 秒),再按同一 requestId 等结构化返回(60 秒);前端明确报错立即失败。`switchNativeWorkspace` 验证实际 Main 的 workspaceId 后才继续操作,禁止把按钮 click 完成当作原生切换完成。失败时用 `captureNativeWorkflowState` 保存最近请求、响应、编辑器上下文及 Console 输入/状态,不重放失败命令。 属性读回先用 `showNativeObjectProperties` 准备对象上下文,再用 `expectUILocation` 检查实际 HTML 数字输入的 `valueAsNumber`、有限性和容差;Worker 坐标或 UI revision 不能替代可见字段。`performNativeAction` 按动作/操作/上下文匹配新请求并绑定回复,失败直接报告原生错误;观察器保留有界 `errorDetail` 堆栈,避免只剩笼统错误码。 评估器输出 `currentCasesEligible` 表示本次案例的当前 hash 绑定通过数量;`workflow` 是原有整体工作流评估,不能把本次两案例通过等同于全局通过。 计划可用 `sourceReview` 绑定经阅读确认的 operator/RNA/Main 契约。执行前检查每个源码/用例绑定 hash、契约来源和数据类型,漂移立即阻断;评审文件及绑定文件一并进入案例输入摘要。该记录只覆盖声明的案例行为,`verifiedUnitDelta` 固定为 0,不能据此增加整单元 parity 数量。数值 UI 断言使用 `spinbutton` 定位真实输入,预期值对应 RNA 的局部 location。 原生 Canvas 案例继承共享 Chromium 的 WebGPU 参数;画布出现重试告警即停止依赖步骤。`native-modeling-workflow.ts` 观察真实模态起止并读取 bpy/BMesh;取消比较数据和撤销历史,帧 revision 可以因预览/回滚递增。`captureNativeWorkflowState` 同时保存有界浏览器错误。 序列化差异可用 `compare-blend-id-fields.py before.blend after.blend --output report.json`;依赖 Blender 自带读取器及 python3-zstandard,可用 `--dependency-path` 指向本地依赖。工具按实际 DNAStruct 解析 ID 字段,报告块数量及输入 hash;DATA 地址不作为语义身份,结果不等于完整 Main 相等证明。 fixture、源码、公共资源、用例、共享辅助代码、依赖锁、工具、浏览器版本任一变化,旧 PASS 不复用。需要新增外部依赖时,把相应实现/数据路径加入 `sourcePaths`。服务使用新实例和严格端口,避免连接旧候选。 ## 先确认真实类型,再比较 Playwright 的 `stats.expected` 等字段是非负整数,`results[].status` 是字符串,`suites/specs/tests/results` 是数组。工具逐层检查类型;`"1"` 不会被当成 `1`,空报告、跳过、预期失败和重试不能算通过。 Main 坐标先检查 `number` 与有限值,再按源码行为选择精确比较或明确容差;不能对所有浮点结果默认四舍五入。DOM 属性返回 `string | null`,版本号保持字符串比较,缺失属性应报错。字节数据识别为 Buffer/ArrayBuffer 后按字节或 SHA-256 比较。结构化状态使用深严格比较或显式业务字段比较,不用字符串包含关系判断 Main 是否恢复。 工具测试:`node --test web/tests/unit/workflow-case.test.mjs`。这组测试验证工具的失败边界,不替代 Blender 功能验收。