@@ -136,9 +136,24 @@ fn media_sound_recent(slot: &Arc<Mutex<Option<Instant>>>) -> bool {
136136 last. is_some_and ( |t| t. elapsed ( ) . as_millis ( ) as u64 <= crate :: media_state:: SOUND_RECENT_MS )
137137}
138138
139+ /// 暂停分支轻量轮询门控(纯函数;P2-4 审查修复抽离以便单测)。
140+ ///
141+ /// @ai-context(Why):manual 锁存期语义=用户冻结,worker 不跟随任何自动源
142+ /// (全冻结不轮询);media **或 fg** 任一 auto 条件持有时维持
143+ /// 1s 取帧 + 媒体检测拍——fg 暂停期媒体条件照常锁存:用户离开
144+ /// 期间视频暂停/结束即锁存 media(否则回位 fg 解除即"恢复采集",
145+ /// 主路径需 ~3-4s 滞回才重锁存 media,期间环境声混入/UI 闪采集
146+ /// 中/时间轴伪运行段);回位链条 = fg 解除 → media 仍 held →
147+ /// 不真恢复 → 视频恢复播放 → 自动真恢复。
148+ fn light_poll_enabled ( cond : crate :: pause_state:: PauseConditions ) -> bool {
149+ !cond. manual && ( cond. media || cond. foreground )
150+ }
151+
139152/// 审查 F3:自动暂停期 watchdog 探针(无提示无心跳——暂停语义下停更提示无
140153/// 意义;仅做观测 + WGC 自愈)。防复合卡死:暂停期间 WGC 会话失活(REQ-281
141154/// 原场景)→ 恢复检测读不到新帧 → 永久卡自动暂停;此处探针周期性复活会话。
155+ /// P2-4:轻量轮询扩到 fg 暂停期后探针随之覆盖 fg 期(视频暂停/画面停更期间
156+ /// 同样需要 WGC 自愈;探针只观测 + 复活,任意暂停期无提示副作用)。
142157fn watchdog_paused_probe (
143158 mut screen : Option < & mut ScreenCaptureSampler > ,
144159 liveness : & mut crate :: frame_liveness:: FrameLiveness ,
@@ -311,8 +326,9 @@ pub fn run_screen_worker(
311326 // 2026-08 A1:暂停边沿跟踪(暂停期画面链整体冻结:采样/前台监控/播放器
312327 // 检测全部跳过——"会话时间"在暂停期间不前进)
313328 // 批 2a:auto_paused 局部 bool 删除——暂停来源收敛在 pause_state 单状态机
314- // (reason/条件锁存);本 worker 只按自身来源行动:media 条件持有时轻量
315- // 轮询找恢复信号、manual 锁存期全冻结(不跟随任何自动源)
329+ // (reason/条件锁存);本 worker 只按自身来源行动:auto 条件(media/fg,
330+ // P2-4 起 fg 期同样)持有时轻量轮询找恢复信号、manual 锁存期全冻结
331+ // (不跟随任何自动源)
316332 let mut worker_paused = pause. paused . load ( Ordering :: SeqCst ) ;
317333 // 前台自动暂停门控(批 2a):250ms 节拍独立于采样拍;锚定资格=有目标
318334 // 窗口(本 worker 存在 ⇔ 画面链开启,anchor_eligible 第二参装配侧已隐含)
@@ -365,9 +381,11 @@ pub fn run_screen_worker(
365381 worker_paused = true ;
366382 eprintln ! ( "[ScreenWorker] 会话暂停,画面链冻结(等恢复/来源解除)" ) ;
367383 }
368- // 非 manual 锁存:media 条件持有时轻量轮询找恢复信号
369- // (fg 条件的回位检测由上方门控节拍负责——互不解除只解自己)
370- if pause. media_held ( ) && !pause. manual_held ( ) {
384+ // 非 manual 锁存:auto 条件(media/fg)持有时轻量轮询找恢复信号。
385+ // P2-4:门控扩到 fg 期——fg 暂停期也维持媒体检测(视频暂停/结束即
386+ // 锁存 media;否则回位 fg 解除即伪恢复采集,见 light_poll_enabled
387+ // 注释);fg 条件的解除仍由上方门控节拍负责(互不解除只解自己)
388+ if light_poll_enabled ( pause. conditions ( ) ) {
371389 // P2 自动暂停:轻量轮询——仅取帧刷新 latest_frame + 播放检测。
372390 // 检测读的就是 latest_frame,不刷新则永远看到暂停帧 → 无法发现
373391 // 恢复;1s 一拍仅取帧(零分析),5s 一拍检测(沿用 REQ-125 节流)
@@ -384,7 +402,10 @@ pub fn run_screen_worker(
384402 & mut got_frame,
385403 ) ;
386404 // 审查 F3:暂停期 watchdog 探针(无提示)——WGC 会话失活时
387- // 恢复检测永远读不到新帧 → 自动暂停永久卡死;此处定期自愈
405+ // 恢复检测永远读不到新帧 → 自动暂停永久卡死;此处定期自愈。
406+ // P2-4:轻量轮询扩到 fg 期后探针随之覆盖 fg 期(fg 期视频
407+ // 暂停/画面停更同样会饿死媒体恢复检测,需同款 WGC 自愈;
408+ // 探针只观测 + 复活,任意暂停期无提示副作用)
388409 watchdog_paused_probe (
389410 screen. as_mut ( ) ,
390411 & mut liveness,
@@ -418,7 +439,13 @@ pub fn run_screen_worker(
418439 eprintln ! ( "[ScreenWorker] 随播随停:声画恢复 → 自动解除暂停" ) ;
419440 }
420441 }
421- if last_player_check_at. elapsed ( ) >= Duration :: from_secs ( 5 ) {
442+ // P2-4:OCR 恢复判定只在 media 条件持有时有意义——fg-only
443+ // 暂停期视频正常播放(帧无暂停图标),裸跑会把"播放中"误当
444+ // 恢复沿,每 5s 落一次伪 Play/伪 live:media-resumed(时间轴
445+ // 伪运行段);media 持有时仍是 REQ-125 恢复兜底(5s 判定)
446+ if pause. media_held ( )
447+ && last_player_check_at. elapsed ( ) >= Duration :: from_secs ( 5 )
448+ {
422449 last_player_check_at = Instant :: now ( ) ;
423450 let check_now_ms = comp_epoch. elapsed ( ) . as_millis ( ) as u64 ;
424451 if let Some ( f) = latest_frame. lock ( ) . ok ( ) . and_then ( |g| g. clone ( ) ) {
@@ -473,7 +500,8 @@ pub fn run_screen_worker(
473500 + Duration :: from_millis ( pause. total_paused_ms . load ( Ordering :: SeqCst ) ) ;
474501 // REQ-291(v0.19.7):随播随停 1s 拍(独立于采样——idle 静默期仍判暂停;
475502 // 手动暂停不判:manual 锁存期语义是用户冻结,不跟随视频——批 2a 起
476- // 主路径只在未暂停时运行,暂停期恢复检测在暂停分支按媒体条件轮询)
503+ // 主路径只在未暂停时运行,暂停期恢复检测在暂停分支按 auto 条件
504+ // (media/fg)轮询)
477505 if !paused_now && last_media_tick. elapsed ( ) >= Duration :: from_secs ( 1 ) {
478506 last_media_tick = Instant :: now ( ) ;
479507 let sound_recent = media_sound_recent ( & media_sound) ;
0 commit comments