← 返回首页

更新后会话恢复之谜

发布时间: 2026-08-05 20:35(北京时间)

摘要: 作者记录了一次因更新导致的会话数据不可见问题及其排查过程:新增数据库列未同步至兼容性探测逻辑,最终由新建会话触发补列而恢复。分析指出缺陷源于硬编码的维护清单遗漏,并将其归因于技术债的必然性。全文逻辑清晰,语气冷静。

标签: 技术分析, 数据库迁移, 会话系统, 兼容性, 代码维护, 反思, 冷静

字数: 786

散步前点了下 Hermes Agent 的更新,回来后发现虽然更新成功但我的历史会话都看不到了。

开一个新会话让查一下日志以及确认下数据库目前的状况。提示词刚发出去的瞬间,历史会话就恢复了。

日志显示:sqlite3.OperationalError: no such column: s.last_read_at
也就是说读会话列表的时候发现 sessions 表缺少了一列。

这个变动是在 ec0c8d9c2 feat(state): sessions carry read/unread state 中引入的,新增一列 last_read_at 是方便界面推导出“未读”状态。这是好事,而且作者也说了”no surface exposes it yet”,所以这应该不涉及 SCHEMA 版本的更新。

但作者可能忽略了 list_sessions_rich() 这个查询本身就会依赖新列。本来查到这应该就差不多了,归因到作者给表加了新列但是忽略了兼容性似乎也没毛病。

但继续往下挖会发现,完整链条是这样的:

  1. SessionDB(read_only=True) 的时候是不会自动补列。
  2. list_sessions_rich() 的时候是只读连接的。
  3. Hermes 有兜底策略,只读连接后会跑一个探测查询,判断是老库的话也会补列。
  4. 但这个“探测查询”是硬编码的,也没有检查到 last_read_at,所以永远“通过”。
  5. 我新建会话的时候是 read_only=False 并触发 _init_schema,补列成功,历史会话瞬间恢复并加载。

*另外,这个“探测清单”本身就是之前挖的坑,里面硬编码的都是以前某次更新需要补的列。但显然这次提交的时候忘记维护这茬了。不过要我说,这个忘记几乎是必然发生的,属于“屎山代码”的诅咒。