Skip to content

Commit 37874c6

Browse files
committed
docs(versions): v0.20.7 采集暂停批交付记录(REQ-308~310+ADR-031+spec 落档)
1 parent 3c4867f commit 37874c6

5 files changed

Lines changed: 171 additions & 0 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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

‎docs/adr/README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
| ADR-028 | [AI 目标规划师——建议制规划 + 体系深度联动](./ADR-028-ai-goal-planner.md) | 已接受(v0.18.2) | 2026-09-02 |
3535
| ADR-029 | [检索与发现层(RAG 接层)——派生索引 + 双读路径 + 人工裁决闸门](./ADR-029-rag-retrieval-discovery-layer.md) | 已接受(v0.19 系列) | 2026-09-03 |
3636
| ADR-030 | [ASR 质量增强批——自验证路线 + 参数治理 + 全量精修 + 混淆画像闭环](./ADR-030-asr-quality-batch.md) | 已接受(v0.20 系列) | 2026-09-03 |
37+
| ADR-031 | [采集暂停来源状态机与前台自动暂停(修订 ADR-013 决策 2 边沿语义)](./ADR-031-capture-pause-source-state-machine.md) | 已接受(v0.20.7 批 2a/2b) | 2026-09-09 |
3738

3839
## 编号规则
3940

‎docs/product/requirements-pool.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,9 @@
588588
| REQ-305 | web 采集阶段 3 整页快照:隐藏 wry 窗口 DOM+子资源内联(自研 core.js,规避 SingleFile AGPL)+ monolith(CC0)静态降级 + 截图兜底链 | P2 | 已实施(2026-09-06 v0.20.4 批:c47e394~1f0bace 提交链——URL 内核/扩展收件薄壳/整页快照静态档;渲染型快照与截图兜底登记后置,见 v0.20.md 与协议文档) | v0.20 系列 | 富格式/整页快照;WebView2 无 MHTML API 已否决 |
589589
| REQ-306 | AI 任务 id 数据安全(重启防复用顶替历史行):启动恢复的 id 序列基准由「恢复集(succeeded 且未采纳)max」改为「ai_tasks 表全表 max」——已采纳/failed/proofread/goal_plan 等 id 更大的行不再被重启后新任务复用(insert_ai_task 的 INSERT OR REPLACE 曾静默顶替含已采纳的历史行——结果/成本/轨迹丢失) | P1 | 已实施(2026-09-09 批 1 审查修复:db_ai_tasks max_ai_task_id + commands_ai_refine task_seq_lower_bound 纯函数(配单测)+ app_setup 恢复块基准改造,提交见 v0.20.md v0.20.6 交付记录) | v0.20 系列 | 审查清单批 1 项 1(数据安全);查询失败降级为旧恢复集口径不放大风险 |
590590
| REQ-307 | AI 任务视图刷新与标题/采纳口径:ChatPage active 门控切回重同步 + ai:task-update 终态事件订阅(保活挂载下别页完成的任务侧栏即时新增);任务标题按 target_kind 分发(笔记级精修查笔记标题、enrich 恒笔记级、target_kind=NULL 旧数据 session 兜底——entityLabel.taskRefLabel 单一来源);AiTaskPanel 精修采纳按 target_kind 分发(笔记级走 ai_note_refine_apply,原恒传 sessionId 报「会话不存在」);AI 任务段补「非聊天会话」语义说明 | P1 | 已实施(2026-09-09 批 1 审查修复:entityLabel 纯函数 + 三处调用方 + ChatPage/App + AiTaskPanel + ChatSidebar,提交见 v0.20.md v0.20.6 交付记录) | v0.20 系列 | 审查清单批 1 项 2~5(刷新缺口/标题错位/采纳链/UI 语义) |
591+
| REQ-308 | 暂停语义修复(延迟与快速恢复丢内容):暂停来源单状态机(manual/media/foreground——manual 锁存、auto 条件互不解除、解除瞬间重评估)+ 暂停边沿 flush 跳过 SenseVoice 整句重打分(flush_no_rescore,停止路径保留)+ seq 代数补偿漏边沿(合成 Pause/Resume 事件对 + 按暂停边界切断链式合并,恢复时刻 clamp 保 DB 单调)+ 事件/DB 载荷 reason 化 | P1 | 已实施(2026-09-09 批 2a:pause_state/live_session_pause 纯函数(25 例单测)+ streaming_asr 参数化 + persist rescore 参数,提交见 v0.20.md v0.20.7 交付记录) | v0.20 系列 | 用户 11 项问题 1;ADR-013 决策 2 语义由 ADR-031 修订 |
592+
| REQ-309 | 前台离开自动暂停(定制语义):被采集锚定窗口离开前台→自动暂停(reason=foreground)、回前台→自动恢复;仅键盘失焦/熵减自身失前台/软件内切页不触发;手动暂停不被自动解除(manual 锁存);无窗口锚定采集(全屏/纯音频档案)规则停摆并文档写明 | P1 | 已实施(2026-09-09 批 2a:foreground_pause.rs ForegroundGate 250ms×2 滞回 + windows.rs is_self_hwnd 自窗中性 + frame worker 全部直写点收敛 request API,提交见 v0.20.md v0.20.7 交付记录) | v0.20 系列 | 用户 11 项问题 2;前台判定阈值真机标定开放项 |
593+
| REQ-310 | 采集控制状态单一来源(切页/事件丢失后 UI 回退修复):每窗口 CaptureStatusProvider(挂载查询含 paused_reason + 事件订阅 + 5s 看门狗回查 + 守卫错误自愈),课堂页/浮窗/导航徽标/右栏收口同一事实源;徽标/浮窗 reason 三态文案;移除 media-* 与 live:paused/resumed 的全部二级订阅(grep 收口仅剩 provider);顺带修复刷新后徽标空白旧债 | P1 | 已实施(2026-09-09 批 2b:liveCaptureState 纯 reducer(16 例单测)+ useLiveCaptureControl provider + 三窗接入(App/ClassroomPage/CaptureFloatPanel/LiveActivityPanel/useLiveSessionEvents),提交见 v0.20.md v0.20.7 交付记录) | v0.20 系列 | 用户 11 项问题 3;架构见 ADR-031 |
591594

592595
## 优先级定义
593596

0 commit comments

Comments
 (0)