fix(app-iced): M100 r2 p3-b —— 采样回不来时红着退出,不再挂死

r1 的一次性闸门把「每帧重试」换成了「只试一次」,于是若 `window::screenshot` 的 Task 根本
产不出 `Captured`(窗口消失 / 后端报错),harness 既不再采样也不 `exit()` ⇒ CI 上表现成
**超时**而不是红灯。超时会被当成基础设施抖动重跑过去,红才会被人看。

- 新增 `CAPTURE_GIVE_UP_FRAMES = 30`(实测 ~120ms/帧 ⇒ 约 3~4 秒,远大于正常路径
  「第 3 帧派发 → 第 4~5 帧落盘」)。
- 新增纯判据 `capture_stalled(frames, writes) = writes == 0 && frames > CAPTURE_AT_FRAME + N`:
  不区分「一直没派发」与「派发了没回来」——两者对使用者的表现都是「没有图」,都该红着退出。
- 触发时打一行具名错误并用 `std::process::exit(1)` 退出:iced 0.14 没有「带退出码结束」的入口
  (`iced::exit()` 恒 0),而这条的全部意义就是让 CI 看到红。

实测:
- 正常路径 ×5:exit 0、`落盘次数=1`、`passthrough_ext=on`、sha `0d7b4f5b`,`采样超时` 行 0 次。
- 变异(N 改 0):两条新单测红(399 passed / 2 failed),真二进制跑出
  `[harness] 采样超时:已过 CAPTURE_AT_FRAME+0 帧(当前 4 帧)仍未收到 Captured,放弃并红着退出`
  且 **exit=1**(×3)。改回 30 后单测 401 passed、二进制 exit 0。
This commit is contained in:
AskaEth committed 2026-11-03 16:23:13 +08:00
1 parent 839a142db0
commit 95530a5311
2 files changed
+80 -1

No files matched your search

+29
View File
@@ -84,6 +84,24 @@ fn should_request_capture(frames: u32, dispatched: bool, capture_mode: bool) ->
capture_mode && !dispatched && frames >= CAPTURE_AT_FRAME
}
/// 采样「派发了却回不来」的宽限帧数(M100 r2 p3-b)。
///
/// 为什么需要它:一次性闸门(上面那条)把「每帧重试」换成了「只试一次」,于是若
/// `window::screenshot` 的 Task **根本产不出 `Captured`**(窗口消失 / 后端报错),harness
/// 既不再采样也不 `exit()` ⇒ CI 上表现成**超时**,而不是红灯。超时会被当成基础设施抖动重跑
/// 过去,红才会被人看 —— 所以宁可在超过宽限后**具名红着退出**。
///
/// 30 帧在取证窗口里约 3~4 秒(实测 ~120ms/帧),远大于正常路径「第 3 帧派发 → 第 4~5 帧落盘」。
const CAPTURE_GIVE_UP_FRAMES: u32 = 30;
/// 采样是不是**卡住了**:过了宽限帧数,一次都没落盘。
///
/// 不区分「一直没派发」(窗口始终没就绪)与「派发了没回来」——两者对使用者的表现都是
/// 「没有图」,都该红着退出而不是挂死。
fn capture_stalled(frames: u32, writes: u32) -> bool {
writes == 0 && frames > CAPTURE_AT_FRAME + CAPTURE_GIVE_UP_FRAMES
}
struct Harness {
request: Request,
ui: Ui,
@@ -180,6 +198,17 @@ impl Harness {
self.first_frame = Some(self.started.elapsed());
}
self.frames += 1;
// 兜底(M100 r2 p3-b):采样派发了却回不来时,不许挂死也不许 exit 0。
// 这里用 `std::process::exit(1)` 而不是 `iced::exit()`:iced 0.14 没有「带退出码
// 结束」的入口,`exit()` 恒 0 —— 而这条的全部意义就是让 CI 看到**红**而不是超时。
if capture_stalled(self.frames, self.writes) {
eprintln!(
"[harness] 采样超时:已过 CAPTURE_AT_FRAME+{CAPTURE_GIVE_UP_FRAMES} 帧\
(当前 {} 帧)仍未收到 Captured,放弃并红着退出",
self.frames
);
std::process::exit(1);
}
// **一次一采样**(M100 r1 P2-1):以前这里是 `frames >= CAPTURE_AT_FRAME`,于是第 3 帧
// 之后**每一帧**都发一次 `window::screenshot`,而 `Captured` 每次都覆盖同一文件才
// `exit()`——已派发的采样不会因为 exit 被撤回 ⇒ **最后写入者说了算**。复审实测 12 次里