81e39ca868
- What: `SessionController.ensure_workers` 现在把 `on_reset_applied=self.note_reset_applied` 交给两个 worker,并在控制器上补回 `note_reset_applied()`(转发给记录通道的 `recording.note_reset`)。窗口侧保留 `_on_reset_applied` 作为一层转发——tests 通过它 模拟设备确认。 - Fix: 这是一个真实缺陷,不是重构副作用。请求路径一直是通的(`_on_reset` → worker.reset()),确认路径却从来没有人接:worker 的 `on_reset_applied` 默认 None, 于是设备回报的 frame_id / mono_t 被丢掉,`recording.note_reset` 不会执行, `_drain_reset_events()` 也永远没有事件可发。后果是真机上按「清零」只会看到「指令已发出」, 录制里不会留下 zeroing 事件(`session.json` 的 events 少一条),而 test_ui_smoke 里那条 `test_a_zeroing_is_recorded_only_after_the_worker_confirms_it` 之所以一直是绿的,是因为 它自己把 `stuck.on_reset_applied = window._on_reset_applied` 手工接上了——测试补上了 产品缺的那根线。 - What: 新增 apps/studio/tests/test_session_controller.py:8 个用例直接驱动控制器 (假 worker、假记录通道)——清零确认与标定确认都会到达记录、两个 worker 都挂上记录 sink 与三维 sink、detach_sinks 会摘掉、一次运行从 connecting 到 running 到 idle 的 相位与遥测(结束后旧遥测不可读、session id 递增)、connecting 时停止会被如实告知、 慢连接提示只说一次、丢帧批次只报一次、采集率短少必须有实测值才判定且一会话只说一次。 - Why: 记录要说真话。清零在实验里是一个事件("这一刻起力被归零"),设备既然回报了 它就应当进入记录;把接线补在控制器(A2 搬进来的那个所有者)而不是窗口里,也让 "谁在跑、报了什么"这条链路只有一个所有者。 - Verification: pytest shared/tests apps/studio/tests(offscreen)644 passed / 0 failed / 15 skipped(原 636 + 新增 8);apps/studio/tools/ui_check.py 587 项检查 0 失败; .repro/locale_check.py 0 缺失。真机上的验收仍未做(本机没有设备), 已知边界:SDK worker 的 `_on_reset_applied` 只在 `sensor.reset()` 返回后调用, 异常路径本来就不会报告确认——这一点没有改动。 - Not in this change: 不改变 `_on_reset` 的请求语义与状态栏文案;`_drain_reset_events` 仍在窗口(它只是把事件变成一行状态)。