Skip to content

Latest commit

 

History

History
92 lines (67 loc) · 4.11 KB

File metadata and controls

92 lines (67 loc) · 4.11 KB

ADR-020: 会话类型字段(图文会话)

状态

已接受

日期

2026-08-22

背景

v0.11.7(图文会话)新增第三采集动线:用户连续框选截屏组成 kind=photo 图文会话(无音频、无转写段)。会话列表徽标(「📷 图文」)、详情页空态 (无讲述内容提示)、崩溃残留清扫(photo recording 超时 → failed)都依赖 「会话属于哪种类型」这一领域语义——类型不是派生可稳定得到的,需要显式建模。

约束:旧库零回归——现有视频类会话(实时捕获/视频导入)不受影响;迁移必须 幂等(ensure_column 先例)。

决策

  1. sessions 表新增 kind TEXT 列:NULL = 视频类会话(实时/导入,默认值, 零回归);'photo' = 图文截屏会话。取值 kebab-case 小写,与 profile 列先例一致。
  2. 迁移走既有 ensure_column 幂等路径(ALTER TABLE sessions ADD COLUMN kind TEXT),建表语句同步包含该列。
  3. 类型穿透:Rust Session/NewSession 结构体新增 kind: Option<String>; 前端 Session 类型同步;新建会话默认 None(视频类)。
  4. 清扫规则:kind='photo' AND status='recording' AND started_at 超 24h → failed,列表加载时执行;清扫失败不阻断列表(防御:列表永远可用)。
  5. 不设 CHECK 约束枚举值(YAGNI):当前仅 photo 一个取值,NULL/photo 二元 语义由代码保证;未来新类型扩展时再评估。

备选方案

方案 A:派生判断(无 segments / 无音频即图文)——未采用

  • 优点:零 schema 变更。
  • 缺点:脆弱且不可靠——播客类档案会话也可能无画面、静音导入也可能无音频, 派生信号与「用户采集意图」不严格对应;清扫/徽标/空态全部依赖隐式推断, 一处失效处处失真。
  • 适用场景:无持久化需求的临时判别。

方案 B:独立新表(session_kinds 字典 / 会话类型关联表)——未采用

  • 优点:可承载多属性类型元数据。
  • 缺点:过度设计——当前只有一个取值、一个标志位,新表引入 JOIN 成本与 迁移复杂度,收益为零。

方案 C:sessions.kind 可空列(采用)

  • 优点:单列幂等迁移(先例 profile 同款)、NULL 默认值天然零回归、 列表/详情/清扫查询零 JOIN 直读。
  • 缺点:取值自由文本(无 CHECK),依赖代码纪律——以单一常量 (photo)写入,测试锁定。

选择理由

会话类型是领域语义而非派生信号:用户显式选择了「图文采集」动线,这个意图 必须持久化。kind 列方案与既有 profile 列迁移模式完全同构(成本最低的 惯用路径),NULL 语义保证旧库、旧代码零回归;备选 A 的派生判断在「播客类 档案无画面」场景下会误判,无法支撑清扫等安全相关逻辑。

影响

正面影响

  • 列表徽标/详情空态/残留清扫获得稳定数据源,语义显式、可测试。
  • 迁移幂等,旧库升级零回归;新建会话默认 NULL 无需改调用方。

负面影响 / 代价

  • Session/NewSession 结构体新增字段,所有构造点需穿透(Rust 编译器 强制列出遗漏构造点)。
  • 前端类型同步(Session.kind)。

风险

  • 取值自由文本可能写错(如大小写/连字符不一致)——以常量 + 测试锁定, 与 profile 列同纪律。

合规性验证

  • cargo test:kind 往返测试(create_session 写入 → 列表读出); ensure_column 幂等测试(旧库迁移零回归,重复执行无副作用)。
  • 清扫测试:photo+recording+超时 → failed;未超时/非 photo 不误伤。
  • 前端 Vitest:kind === "photo" 徽标渲染。

相关决策

  • ADR-004: 会话管理数据模型方案(sessions 表基座)
  • ADR-014: 会话↔笔记关联与批量转化(会话类型影响列表标记)

参考