29bf672475
按代理交接约定限定首轮为阶段 0–1,写明范围、影响面、停止条件与授权来源。
13 KiB
13 KiB
Studio / shared 测试修复与门禁计划
状态:待实施。日期:2026-10-18。基线:orisys-app main 的 85d0b39。执行者:一个代理(DeepSeek),按顺序完成,
每个阶段结束时向用户汇报。本计划补充 分层测试执行计划,不替代它。
1. 为什么要做
在 85d0b39 上,studio 测试在 Windows 上有 23 项失败或错误(Linux 上 24 项),shared 有 2 项,没有人察觉。原因不是单个缺陷,而是流程本身:
| 问题 | 证据 | 后果 |
|---|---|---|
| 没有强制执行的门禁 | 仓库没有 CI 或 pre-commit;规则只写在 AGENTS 里 | 10-05 至 10-08 至少 6 个提交改了行为但没改测试(第 3 节逐项列出) |
| 只跑定向测试,从不定期全量 | 分层计划写明"定向测试通过后结束验证" | 其他分组里的测试悄悄变红,没有人发现 |
| 文档里的门禁命令无效 | -m "not timing" 是文档写的门禁命令,但 timing 标记从未注册,也没有测试使用 |
已知不稳定的计时测试每次都失败,大家习惯无视红色 |
| 测试依赖未跟踪的数据 | 回放和裸视频测试读取 dist/OrisysStudio/outputs/recordings/…;10-14 重新打包后这份录像消失 |
换机器或重新打包,11 项测试报错,4 项失败 |
| 从仓库根目录无法运行 studio 测试 | from tests.conftest import … 在根目录找不到 tests;studio 与 autocal 的 test_binding_purity.py 同名冲突 |
文档写的"根目录 pytest"跑不起来,每个人自己找运行方式 |
ui_check.py 不在任何门禁里 |
它的模拟 worker 从 10-08 起与 start() 签名不符,脚本中途崩溃,并连带约 15 项冒烟测试失败(已在 85d0b39 修复) |
3700 行的检查静默失效 |
| 跳过的测试无人计数 | studio 有 35 项跳过,原因没有汇总 | 环境坏了也可能显示为通过 |
结论:分层选择测试的思路是对的,但缺少两样东西——一个任何人都绕不过去的全量门禁,以及一份必须为空的已知失败清单。
2. 规则(执行者必须遵守)
- 遵守
D:\orisys_ws\AGENTS.md:scratch 放在orisys-app/.scratch/test-repair/,带.active标记;pytest 使用--basetemp=<scratch>/pytest-<run>和-p no:cacheprovider;改动不暂存、不提交;向用户汇报用中文。 - 解释器固定为
D:\orisys_ws\orisys-app\.venv-build\Scripts\python.exe,用 Windows PowerShell 5.1 语法。 - 不得通过删除断言、放宽断言、加 skip 或 xfail 让测试变绿。改测试只有一个理由:测试与已确认的产品行为不一致,并且要写明是哪个提交确认了该行为。
- 每修一项,记录它在修复前失败、修复后通过的证据(命令和输出摘要)。
apps/autocal/目前有另一个任务在改。不要编辑 autocal 的源码或测试;如果第 4 节的收集问题必须改 autocal 文件,停下来问用户。- 遇到第 3 节标为"需决定"的项,先准备好证据和建议,再停下来问用户,不要自己决定。
3. 逐项诊断(执行者先复核,再动手)
以下诊断来自 2026-10-18 在 Linux 离屏环境与 Windows 上的两次运行;"引入提交"由 git log -S 查得。执行者须用 git show <提交> 确认诊断后再修。
| # | 测试 | 现象 | 判断 | 处理 |
|---|---|---|---|---|
| 1 | test_bare_video_analysis.py 全部 11 项 |
找不到 dist/…/20260930T015028Z_session0002_…/raw_0001.mp4 |
测试数据缺失 | 见第 4 节阶段 2 |
| 2 | test_replay_wiring.py 4 项(_open 报 the recording did not open;declined prompt 报 FileNotFoundError) |
同一份录像缺失;_copy_recording 静默跳过缺失文件,而模块级的 skip 只在部分路径生效 |
测试数据缺失,加上 fixture 行为不一致 | 阶段 2;同时让缺数据时一律明确失败 |
| 3 | test_replay_analysis.py::test_a_stitch_grid_is_not_painted_onto_the_camera_frame |
测试桩 _Reader 没有 provenance 属性 |
测试过时(replay_analysis.py:245,401 读取 reader.provenance,引入于 829d2c1,10-06) |
给测试桩补上 provenance,取值仿照真实 reader,不得改产品代码 |
| 4 | test_ui_smoke.py::test_old_result_depth_is_not_sent_to_the_new_sensor_scene |
调用已删除的 _show_analysis_frame |
测试过时(cf49b08、28e955a 改为 show_analysis_packet) |
改用公共入口,保留原断言意图:旧结果的深度不得送进新传感器的场景 |
| 5 | test_scene3d_view.py::test_the_replay_view_shows_the_pane_and_says_where_the_field_comes_from |
断言文案含"重算",现在是"分析结果:非录制时的测量值" | 测试过时(c0a10e6 改了文案) |
改为对比 locale 键 source_recompute,不再硬编码字面词 |
| 6 | test_ui_elements.py::test_every_declared_condition_is_used_and_reaches_a_window |
liveCalibrationCombo、sensorProfileScroll 未登记 |
登记表过时(3d2fb0c 新增控件) |
用 apps/studio/tools/ui_elements_dump.py 生成条目,补进 apps/studio/docs/ui-elements.json,逐条写明用途 |
| 7 | test_ui_smoke.py::test_run_tooltip_explains_disabled_reason |
期望选了视频文件后「运行」可用 | 测试过时:实时视图不再用视频运行(test_live_run_refuses_a_video_source 断言的正是相反行为) |
改为断言:视频源时按钮禁用、提示文字和顶栏 run_hint 都是 toolbar.run_video_in_replay |
| 8 | test_ui_smoke.py::test_the_sensor_summary_opens_the_dialog |
没有导出系数时「应用到设备」仍可用 | 很可能是测试过时(3d2fb0c 让该按钮应用对话框里选中的实时标定) |
读 sensor_dialog.py:324 一带确认行为后改断言;若该按钮在什么都没选时也可用并会出错,按产品缺陷处理 |
| 9 | test_pause_controls.py::test_the_transport_says_which_way_it_goes |
暂停提示不再提到录制会留空档 | 需决定:f2bbab7(10-08)为缩短文案删掉了这句,但修复计划 A 要求提示写明空档 |
建议恢复一句短的"录制会留空档",测试保持不变;须用户确认 |
| 10 | test_ui_smoke.py::test_the_replay_view_is_the_live_view_with_a_video_source,以及 ui_check 的同名检查 |
回放与实时的分栏宽度不同(589/825 对 643/771) | 需决定:可能是 321e52f(10-06,改善回放布局)有意改变,也可能是回归 |
用 git bisect 在测试上定位引入提交,向用户说明那次改动的意图,再决定改测试还是改代码 |
| 11 | test_ui_smoke.py::test_the_rail_puts_result_identity_before_a_long_video_name |
仅 Linux 失败(字体宽度不同),Windows 通过 | 环境差异 | 不改;在门禁说明里写明门禁平台是 Windows |
| 12 | shared/tests/test_worker_frame_rate.py 2 项 |
"30 fps 设备只消费到 21 fps",取决于机器负载 | 计时测试,本身不稳定 | 注册并标记为 timing,移出合入门禁;另开任务把它改成确定性测试 |
| 13 | shared/tests/test_scene3d_protect.py::test_the_release_gate_fails_an_unsigned_package |
仅 Linux 失败 | 环境差异 | 不改;记录在案 |
4. 实施阶段
| 阶段 | 内容 | 验收 | 估时 |
|---|---|---|---|
| 0 基线 | 记录 HEAD、解释器、PySide6 与 pyqtgraph 版本;分别在 apps/studio、shared 下跑全量(-m "not timing"),并运行 ui_check.py,产出 JUnit XML |
scratch 下有失败清单,与第 3 节逐项对上;对不上的项先报告用户 | 0.5 h |
| 1 让门禁能跑 | 在根 pyproject.toml 注册 timing 标记,并加 --strict-markers;标记第 3 节 12 号的两项;解决根目录收集问题(建议:把 studio 测试从 tests.conftest 导入的辅助函数移到 apps/studio/tests/_studio_helpers.py,并在 studio 的 conftest 里把该目录加入 sys.path;同名测试文件用 --import-mode=importlib 或改名解决,不改 autocal 文件) |
在仓库根目录执行 python -m pytest --collect-only -q 时收集错误为 0;-m "not timing" 确实排除了 2 项 |
2–3 h |
| 2 测试数据 | 第 3 节 1、2 号:新建 apps/studio/tests/data/,放一段真实的 box 短录像(raw_0001.mp4、frames.csv、forces.csv、events.csv、session.json),约 30 帧;所有测试改为从这里读取;只需要回放接线的测试,优先用 ExperimentRecorder(shared/.../record/experiment.py)在 fixture 里生成合成录像,写法参考 ui_snapshot.py --scene replay;数据缺失时一律明确失败,不跳过 |
两个文件的全部用例在干净的检出上可运行;dist/ 不再出现在任何测试路径中(grep -r "dist" apps/studio/tests 只剩注释) |
2–3 h,另需用户录一段 |
| 3 逐项修复 | 第 3 节 3–8 号直接修;9、10 号先问用户再修 | 每项记录修前失败、修后通过;断言数量不减少(列出每个改动测试的断言前后对比) | 3–4 h |
| 4 门禁脚本 | 新增 tools/gate.ps1:依次运行 tools/lint_gate.py(改动文件)、studio 全量、shared 全量、ui_check.py;全部输出写进 scratch 并汇总为一页;读取 tools/known_failures.txt,该文件必须为空,有内容就让门禁失败;记录跳过数,超过 tools/skip_budget.txt 中的上限就失败;收集数低于下限也失败(防止整个模块被静默跳过) |
在当前状态运行 gate.ps1 退出码为 0;故意改坏一个断言后退出码非 0;故意删掉测试数据后退出码非 0 |
3–4 h |
| 5 接入流程 | 在 orisys-app 提供可选的 pre-push 钩子(调用 gate.ps1,安装方式写进 README,不自动安装);修订 test-execution-plan.zh.md:定向测试用于开发中,提交前跑一次 gate.ps1;第 4 节表格里加"门禁平台:Windows" |
文档门禁通过;README 写有安装钩子的一条命令 | 1 h |
| 6 收尾 | 以最终状态跑一次 gate.ps1;写 commit-message.txt;用中文汇报 |
汇报区分:已修、需用户决定、移出门禁的(含理由)、仍未解决的 | 0.5 h |
阶段 1 必须先于其他阶段完成;阶段 2 和 3 可以交错进行;阶段 4 依赖前三个阶段全部变绿。总计约 12–16 小时,外加用户录制测试数据的时间。
5. 需要用户先决定的事
- 测试录像放在哪里。 建议放进 git(
apps/studio/tests/data/,控制在 5 MB 以内);如果不想让仓库变大,就改用环境变量ORISYS_TEST_DATA指向 NAS 上的目录,但缺失时测试必须失败,不能跳过。还需要用户用 box 传感器录一段约 1 秒的短录像。 - 第 3 节 9 号:暂停提示是否恢复"录制会留空档"。
- 第 3 节 10 号:回放与实时布局不一致,属于有意改动还是回归(执行者 bisect 之后再问)。
- 以后是否搭 Gitea runner(Windows 自托管)自动跑
gate.ps1。本计划只做到本地钩子;runner 另开任务。
6. 不在本计划内
计时测试改为确定性测试;GL 真机冒烟测试;autocal 测试树的问题;测试目录重排。这些都在门禁稳定之后另行安排。
交接记录
按 代理交接约定 维护;只保留当前状态和每轮一行摘要。
- task_id:test-repair;round:1;updated_at:2026-10-18 17:45 +08:00
- status:ready;owner:Claude(定义);next_agent:DeepSeek(执行)
- 目标与完成条件:本轮只做第 4 节阶段 0 和 1,验收以该两行为准;阶段 2 起留待下一轮
- 范围:
pyproject.toml、apps/studio/tests/**、shared/tests/**的标记与收集修复,新增apps/studio/tests/_studio_helpers.py;排除apps/autocal/**、产品源码、locale 与docs/以外的文档 - 停止条件:交接约定的默认条件;收集问题必须改 autocal 文件时停止
- 时间预算:按阶段分别计算,取第 4 节估时区间的上限(阶段 0 为 0.5 h,阶段 1 为 3 h), 不含等待用户或数据的时间;超出 50% 即触发停止条件
- 影响面:根
pyproject.toml同时影响 autocal 测试树;记录受影响的 autocal 测试并在汇报中提醒用户, 不直接联系 autocal 任务(.scratch/autocal-*中带.active的目录) - 授权:用户 2026-10-18 17:17 要求制定计划交 DeepSeek 执行、17:40 确认启动;仅授权本地修改与测试,提交、推送、安装依赖仍需用户另行授权
基准与输入
| 仓库/checkout | 分支、HEAD | 起始暂存/未暂存/未跟踪变化 | 本轮修改 |
|---|---|---|---|
D:\orisys_ws\orisys-app |
main、e268a9d(studio/shared 与 85d0b39 相同) |
autocal 有其他任务的改动,不属本任务 | 待填 |
- 环境:
D:\orisys_ws\orisys-app\.venv-build\Scripts\python.exe - 输入:不适用(阶段 2 的测试录像尚待用户提供)
执行结果
| 验收项与预期 | 实际命令及 run_id | 实际结果 | 证据路径 |
|---|---|---|---|
| 阶段 0:失败清单与第 3 节对上 | 待填 | 待填 | 待填 |
阶段 1:根目录收集错误为 0;timing 排除 2 项 |
待填 | 待填 | 待填 |
验收与下一步
- 轮次摘要:(执行后填写)
- 验收者:Claude 或 GPT;决定:待验收
- 下一步:DeepSeek 执行阶段 0–1,交付 review