Răsfoiți Sursa

docs(d2-02): 补真机门控关键坑——最终整体审查发现第二阶段无心跳致预览10s超时自断(非bug,心跳归第三阶段),真机须curl每5s打/debug/heartbeat续命

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
huangjie 1 zi în urmă
părinte
comite
e80864b284

+ 1 - 0
项目文档/开发计划/2026-06-24-D2-02-第二阶段-MJPEG实时预览-实现计划.md

@@ -906,6 +906,7 @@ git commit -m "docs(d2-02): 第二阶段 MJPEG 预览代码完成回写——断
 
 本计划交付**代码完成 + 纯逻辑单测全绿 + Release 双编译 0 错**。下列需真机/真 UI:
 - **★预览启动前置(Task7 审查 M-1)**:第二阶段 `CurrentSessionId` 无 UI 赋值点(第三阶段 acquire 才赋值)。真机验证预览**必须先 curl `/debug/acquire` 拿 sid → 把 sid 赋给 `vm.CurrentSessionId`**(调试入口/临时赋值),否则 OpenVideo 走"未借用会话,无法预览"分支、预览点不开(这是阶段边界,非 bug)。
+- **★★会话 10s 无心跳自断(最终整体审查发现,真机必踩)**:第二阶段 operate 端**不发心跳**(心跳归第三阶段)。开预览后若不操作、无外部心跳,`LastSeen` 停在 acquire 时刻,**TTL 10s(Program.cs ttlMs=10000,看门狗每3s扫)到点 → SweepExpired 回收会话 → 推流线程下轮 TryGet 失败自停 → 预览自断**,operate 弹"调试会话已超时"。**这不是预览 bug,是 spec 已知设计缺口**(推流端点 TryGet 只读不刷新 LastSeen,心跳归第三阶段)。真机验证第二阶段预览**必须制造心跳续命**:开预览后用 curl 每 ~5s 打一次 `POST /debug/heartbeat {sessionId}`,观察预览能否稳定持续 >30s。第三阶段接入 DebugSessionClient 周期心跳后此坑自然消失,**无需改第二阶段代码**。
 - MJPEG 真机出图:acquire 某舱 → operate 端 `<Image>` 看到该舱实时画面。
 - **关预览/返回后画面干净无残帧(Task7 审查 I-1 已代码根治"当值实例"闸)**:真机确认关预览后画面立即清空、不闪残帧。
 - **画面方向核查(Task1 代码审查提出)**:旧 `Camera.SaveBmpPic` 落盘前有 `RotateNoneFlipY`(相机原始 buffer 可能是 bottom-up)。MjpegStreamWriter 不做翻转 → 真机预览可能上下倒置。**若倒置,在推流调用层(Task3 抓帧后)补一次 Y 翻转**,勿改纯逻辑类 MjpegStreamWriter。

+ 1 - 1
项目文档/进度/待验证清单.md

@@ -42,7 +42,7 @@
 |------|--------|------|------|
 | D2-01 | 监控页跨进程显示完整(/status 三块:活动/阀态/借用让路 + 心跳/磁盘/链路) | 运行 | ☑ 真机验证 |
 | D2-02 | 调试借串口:control 让路(暂停该舱采集)→ 恢复(原 V-012) | **真机** | ◑ 让路契约已验/调试页完整驱动=大改面待设计(D3-04 删死栈被其阻塞,见交接卡 2026-06-23 评估段) |
-| D2-04 | **[MJPEG]** 预览真机出图:先 curl /debug/acquire 拿 sid 赋 vm.CurrentSessionId → 开预览 → operate `<Image>` 看到该舱实时画面 | **真机** | ☐ 代码完成待验(归 V-012/第三阶段;第二阶段无 UI 赋 sid 点) |
+| D2-04 | **[MJPEG]** 预览真机出图:先 curl /debug/acquire 拿 sid 赋 vm.CurrentSessionId → 开预览 → operate `<Image>` 看到该舱实时画面 | **真机** | ☐ 代码完成待验(归 V-012/第三阶段;第二阶段无 UI 赋 sid 点;**★第二阶段无心跳,开预览后须 curl 每5s打 /debug/heartbeat 续命,否则 TTL 10s 会话超时回收致预览自断——非bug,心跳归第三阶段**) |
 | D2-05 | **[MJPEG]** 画面方向:旧 SaveBmpPic 有 RotateNoneFlipY(buffer 或 bottom-up),确认预览不倒置;倒置则推流层(抓帧后)补 Y 翻转 | **真机** | ☐ 待验 |
 | D2-06 | **[MJPEG·★重点压测]** 预览中反复 release/超时回收同舱:推流抓帧 vs 回收 Dispose 相机 use-after-free 窗口(底层 UnInit 不置 IsStart=false,IsStart 护栏拦不住已 Dispose 相机),全局相机锁串行+native HPCSE 兜底,确认 control 不偶发崩溃 | **真机** | ☐ 待压测(崩则底层 Camera.UnInit 补置 IsStart=false) |
 | D2-07 | **[MJPEG]** 崩溃自愈+关预览无残帧:断预览/杀 operate→推流线程自停标记 StreamBroken→心跳TTL看门狗回收→该舱采集恢复(/status反映);关预览画面立即清空不闪残帧(已代码根治当值实例闸) | **真机** | ☐ 待验 |