|
| 1 | +# ADR-031: 采集暂停来源状态机与前台自动暂停 |
| 2 | + |
| 3 | +## 状态 |
| 4 | + |
| 5 | +已接受(2026-09-09 用户逐项授权;v0.20.7 批 2a/2b 交付) |
| 6 | + |
| 7 | +## 日期 |
| 8 | + |
| 9 | +2026-09-09 |
| 10 | + |
| 11 | +## 背景 |
| 12 | + |
| 13 | +ADR-013 决策 2(播放暂停驱动 = 复用 A1 共享暂停标志;手动暂停全冻结 vs 自动暂停轻量轮询)落地后,用户实测暴露三类问题: |
| 14 | + |
| 15 | +1. **暂停延迟**:`pause` 只置共享布尔,`live:paused` 事件与引擎 reset 全在主循环 500ms 轮询边沿执行,边沿 flush 内**同步跑 SenseVoice 整句重打分(有界 3s/句)**——点击后 UI 数百 ms~3s+ 才翻转; |
| 16 | +2. **快速恢复丢内容**:暂停-恢复落入轮询间隙时边沿不可见(引擎不 reset、无事件记录);恢复侧无 flush/边界处理,`pending_merge` 链式合并无暂停边界判断,会跨暂停错误合并——半句切碎/尾音丢失; |
| 17 | +3. **UI 状态回退**:媒体自动暂停(worker 直写标志 + `live:media-paused`)与手动暂停(主循环 `live:paused/resumed`)双轨并存、无来源区分;前端课堂页/浮窗/徽标各自维护状态且挂载拉取曾忽略 `paused` 字段——事件丢失/重挂后 UI 显示空闲。 |
| 18 | + |
| 19 | +另有用户新需求:被采集目标窗口离开前台时自动暂停、回前台自动恢复(区别于仅键盘失焦;熵减自身窗口与软件内切页不触发)。 |
| 20 | + |
| 21 | +## 决策 |
| 22 | + |
| 23 | +1. **暂停状态升级为带来源的单状态机**(`pause_state.rs`):`PauseSource = Manual | Media | Foreground`;manual 为锁存层(持锁期间 auto 提议只记条件不动作,手动解除瞬间重评估 auto 条件),auto 层各条件互不解除、只解自己;`PauseShared{paused, total_paused_ms, seq, edge 槽, reason}`,request API 单写入点;`total_paused_ms` 写纪律不变(仅捕获线程补偿时长)。 |
| 24 | +2. **暂停边沿语义修订**(取代 ADR-013 决策 2 中"边沿 flush 尾句 + 引擎 reset 共用停止路径 flush"的重打分行为):暂停边沿用 **`flush_no_rescore()`**(跳过 SenseVoice,质量由恢复侧去重与边界保护兜底;停止路径保留重打分);恢复边沿 flush + 去重边界保护 + 按暂停边界切断链式合并状态。 |
| 25 | +3. **漏边沿代数补偿**:`seq` 每完成一个物理暂停区间 +1;主循环按 seq 跳跃检测漏边沿,`plan_edge_observation` 纯函数判定(own_pending 吸收已可见暂停的完成增量),补偿 = no-rescore flush + reset + 合成 Pause/Resume 事件对(时刻取 edge 槽实测冻结点、恢复时刻 clamp 保 DB 单调),每次观察至多一对——消除"引擎不 reset、事件无记录"的全部路径。 |
| 26 | +4. **前台自动暂停**(`foreground_pause.rs`):启用门 = 窗口锚定(`hwnd.is_some()`,全屏/纯音频档案停摆);`ForegroundGate` 滞回(250ms 节拍 ×2 拍确认,fa1647aa SUSPECT 先例);**自窗中性**——经 `GetAncestor(GA_ROOT)` 进程比对排除主窗/浮窗/overlay/对话框,防"一点浮窗即误暂停";触发/解除均走 request(Foreground)。 |
| 27 | +5. **契约 reason 化**:`live:paused/resumed` 载荷 `{"reason": kebab}`;DB pause/resume payload `{"source"}`;`LiveSessionStatus.paused_reason`;`live:media-paused/resumed` 保留但前端零订阅(清理候选)。 |
| 28 | +6. **前端每窗口单一数据源**:`CaptureStatusProvider`(挂载查询含 paused_reason + 事件 + 5s 看门狗 + 守卫错误自愈),课堂页/浮窗/徽标/右栏收口到同一实例(浮窗为独立 webview,各窗一实例),删除全部二级监听与本地双状态。 |
| 29 | + |
| 30 | +## 备选方案 |
| 31 | + |
| 32 | +- **方案 A(选定)**:来源状态机 + seq 补偿 + 前端单一数据源。优点:手动/自动语义机器化(根治 fa1647aa 类多写者漂移)、丢内容路径结构性消除、UI 不再依赖单点事件。代价:REQ-291 媒体暂停相关直写点全部收敛(frame worker 语义面改动,需真机走查)。 |
| 33 | +- **方案 B**:确认式跨线程回执(命令等捕获端点 Stop 回执再返回)。否决理由:命令置位 µs 级、端点停采 10ms 级,UI 无可感知收益;需跨线程回执通道与超时降级,复杂度不成比例。 |
| 34 | +- **方案 C**:仅补丁(暂停边沿跳过重打分 + 挂载补读 paused 字段)。否决理由:轮询间隙漏边沿、链式合并跨暂停、多窗状态分裂等结构性缺陷未除——不符合"优先彻底方案"的用户原则。 |
| 35 | + |
| 36 | +## 选择理由 |
| 37 | + |
| 38 | +- 暂停是采集正确性的核心语义:延迟、丢内容、状态回退三条线共享同一根因(无来源布尔 + 轮询边沿 + 重打分阻塞 + 前端多写者),单点收敛收益最大; |
| 39 | +- 自动暂停(前台)与既有媒体随播随停共用同一状态机底座,未来任何新自动源(静音/失焦/可见性门控)只加一个条件源,不再触碰驱动端; |
| 40 | +- 前端单一数据源顺带修复"刷新后徽标空白"旧债,且为后续更多窗口(如后续收件箱/复习域页)提供同一模式先例。 |
| 41 | + |
| 42 | +## 影响 |
| 43 | + |
| 44 | +### 正面影响 |
| 45 | + |
| 46 | +- 暂停生效确定性:点击后 UI 在 ≤1 个主循环节拍 + 无重打分(数十 ms~500ms)内翻转; |
| 47 | +- 快速暂停-恢复不再丢段/碎句/漏事件;DB 事件成对且时刻单调; |
| 48 | +- 徽标/浮窗/课堂卡 reason 三态文案,自动暂停原因可见; |
| 49 | +- 前台切走自动停、切回自动续(窗口锚定采集),手动暂停期间自动条件不越权。 |
| 50 | + |
| 51 | +### 负面/代价 |
| 52 | + |
| 53 | +- REQ-291 媒体暂停链路面改动:auto_paused 局部标记删除、全部直写点收敛 request(Media),需真机样例走查(手动恢复后视频仍暂停→重锁存链路); |
| 54 | +- 事件载荷变化:旧前端监听忽略载荷即安全;旧后端(无此版本)对旧前端发空载荷 → UI 回落"已暂停"不崩; |
| 55 | +- 前台判定真机标定项:alt-tab 快速往返、全屏游戏抢前台、置顶弹窗;双屏并排场景(目标可见但前台在另一屏)会暂停——可见性门控留作可选项待用户裁决。 |
| 56 | + |
| 57 | +### 风险 |
| 58 | + |
| 59 | +- 浮窗 always-on-top 点击被误判前台切换(最高风险)——自窗中性已覆盖,仍需真机验证; |
| 60 | +- media 恢复语义变更回归——fa1647aa 修复链路(800-807 兜底重锁存)已机器化并保留 worker 侧兜底; |
| 61 | +- 无窗口锚定采集的前台规则停摆属设计口径(用户已确认),不得静默启用。 |
| 62 | + |
| 63 | +## 合规性验证 |
| 64 | + |
| 65 | +- `cargo test --test app_lib_tests`:2287 通过 / 0 失败 / 6 ignored(全量,隔离运行); |
| 66 | +- 前端:全量 vitest 597/597、`tsc --noEmit` 0 错误; |
| 67 | +- 新文件 ≤300 行(pause_state.rs 250 / live_session_pause.rs 258 / foreground_pause.rs 180); |
| 68 | +- 真机验收清单 8 条登记于 v0.20.7 交付记录(前台阈值标定待真机)。 |
| 69 | + |
| 70 | +## 相关决策 |
| 71 | + |
| 72 | +- ADR-007(live-session 生命周期)、ADR-013(引擎预热与播放暂停驱动——本 ADR 修订其决策 2 的边沿 flush 语义与同标志/同事件表述)、ADR-030(ASR 质量批,flush/重打分参数化先例) |
| 73 | +- 需求:REQ-308/309/310(requirements-pool,2026-09-09 备注) |
| 74 | +- 设计:docs/superpowers/specs/2026-09-09-capture-pause-autopause-design.md |
0 commit comments