Skip to content

feat(session): 删除扁平 legacy store,init(appId) 必填 - #1344

Draft
LucasIcarus wants to merge 4 commits into
feat/session-endstate-store-closefrom
feat/session-endstate-drop-flat-store
Draft

feat(session): 删除扁平 legacy store,init(appId) 必填#1344
LucasIcarus wants to merge 4 commits into
feat/session-endstate-store-closefrom
feat/session-endstate-drop-flat-store

Conversation

@LucasIcarus

@LucasIcarus LucasIcarus commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

摘要

  • docs/design/2026-08-12-session-restage-store-first.md §5 A-8:init(appId: string) 必填,删除扁平 sessions.db / sessions.json 的 8 处支持点,以及 host / CLI / whiteboard 上「无 larkAppId 走扁平库」的分支。无 larkAppId 的行直接放弃(读不到、写不了、离线关闭报缺字段),不回落扁平 store。
  • 测试侧约 20 个文件机械补 init(appId),并删掉依赖扁平 store 的用例(含 writeLegacySessions、无 appId 写扁平库、从扁平 sessions.json 按 bot 过滤导入)。一次性导入 / 文件锁 / 中毒恢复仍保留(C-15)。
  • 本 PR 叠在 feat(session): 收口跨进程会话库协议并补齐升级可见性 #1342(A+B)之上,请先合 feat(session): 收口跨进程会话库协议并补齐升级可见性 #1342 再合本 PR。拆出去是为了审查信噪比:A+B 里的协议删除不被约 100+ 处夹具改写淹没。扁平 store 生产零调用,多留一个 PR 不构成半套协议。

影响面

  • 共用路径session-store.ts(路径解析、listStoreRefs / listUnmigratedAppIds / loadAllSessionsSnapshot / readSessionRowFromDisk / runUnownedRowTxn)、session-command-host.tsHostTarget.larkAppId 必填)、cli.tshostTarget / abandonSessionAuthoritatively)、whiteboard-store.ts(无 larkAppId 直接 unresolved)、resolve-session-by-id.ts(不再认空 appId 为 unmigrated)。
  • 跨会话类型:话题 / 群 / adopt / restore / sandbox 只要行上有 larkAppId,行为与 A+B 相同;缺 larkAppId 的行不再有离线关闭特例。
  • 跨平台 / 跨 CLI:只动会话库身份与 host 写入,不改 PTY / 适配器 / 关停协议实现。
  • 验收 grepgrep -rnE "sessionStore\.init\(\s*\)" test | wc -l 在本 PR 为 0(A+B 允许非 0)。

测试

bun run build
# 通过

grep -rnE "sessionStore\.init\(\s*\)" test | wc -l
# 0

bun run test -- test/session-store.test.ts test/session-store-sqlite.test.ts \
  test/session-occupancy.test.ts test/session-delete-cli.test.ts \
  test/whiteboard-unbind-session.test.ts test/fs-policy.test.ts \
  test/mojo-containment.test.ts test/session-turn-queue.test.ts \
  test/resolve-session-by-id.test.ts test/session-store-copy.test.ts \
  test/cli-send-hook-context.test.ts
# Test Files  11 passed (11)
# Tests  372 passed | 2 skipped

bun run test -- test/dashboard-ipc.test.ts test/kill-worker-orphaned-backend.test.ts \
  test/mojo-close-worker-journal.integration.test.ts test/mojo-orphan-cancel-crash.test.ts \
  test/restore-zombie-close.test.ts
# 5 files 全绿(含 dashboard-ipc 334)

switch:here、未重启 live daemon。验证止于 build + 单测。

复核跟进(2026-09-09)

  • 已 rebase 到 feat(session): 收口跨进程会话库协议并补齐升级可见性 #1342 最新 head(a26249ba)。独立复核的处理见评论;修复提交 3a9b155,设计文档同步提交 f9708d7
  • 数字订正:测试侧实际是 35 个文件、99 处无参 init()(含 9 个原本未 init、需要补的文件);设计 §2.2 列的 8 处扁平支持点中 7 处在本 PR,第 8 处(loadFromFrozenJson 的 legacy 分支)已随 feat(session): 收口跨进程会话库协议并补齐升级可见性 #1342 删除。
  • 影响面补充:一次性导入的 readFrozenSnapshotForImport 不再回落扁平 sessions.json,中毒库恢复的快照佐证只认 sessions-<appId>.json(实现未动,两条用例的播种文件名随之调整;该套件本机因 bun 版本钉死全量失败,依赖 CI 验证)。cli.ts 里 cmdResume 等 6 处「行缺 larkAppId」分支在快照无条件补齐 larkAppId 后已不可达,不在本 PR 范围。

@LucasIcarus
LucasIcarus marked this pull request as draft September 9, 2026 05:40
@LucasIcarus
LucasIcarus force-pushed the feat/session-endstate-drop-flat-store branch from 4280ad9 to bc360a6 Compare September 9, 2026 05:54
@LucasIcarus
LucasIcarus force-pushed the feat/session-endstate-store-close branch from 6bf84e2 to a26249b Compare September 9, 2026 12:22
LucasIcarus added a commit that referenced this pull request Sep 9, 2026
- references 补 #1342 / #1344;决策记录与 §5 A-8 的「约 20 个文件」订正为 35 个文件、99 处,并注明导入快照佐证不再回落扁平 JSON 的影响
- §2.2 身份行与 §2.3 第 2 条销账(JSON 那一半随 #1342、扁平 .db 那一半随 #1344);验收 grep 的括号说明与 §6 中已删用例的表述同步
- isolated-bot-deploy.md 的 deny 清单去掉已不存在的 data/sessions.json
@LucasIcarus
LucasIcarus force-pushed the feat/session-endstate-drop-flat-store branch from bc360a6 to f9708d7 Compare September 9, 2026 13:10
@LucasIcarus

Copy link
Copy Markdown
Collaborator Author

独立复核(相对 #1342 head a26249b 的 diff),并已 rebase 到 #1342 最新 head:唯一冲突是 test/group-join-shared-routing.test.ts#1307 新增的返回字段 vs 本 PR 的 init('test-app')),手工合并。

结论:方向与设计 §5 A-8 一致,没有超范围;可合。 生产侧删得干净:跨进程读取面不依赖 currentAppIdabandonSessionAuthoritatively 是纯去缩进重构,listUnmigratedAppIds 已不可能返回空 appId,中毒恢复的佐证逻辑去掉 legacy 分支后仍自洽。

复核里发现并已在 3a9b155 处理的:

  1. getSessionFresh 在未 init 的进程里从「返回 undefined」变成抛错(load() 静默早退、getDbPath() 却抛)。唯一刻意跳过 init 的生产进程是 BOTMUX_WORKFLOW=1 的 worker,沙盒 relay 的 authorizeManagedSend 无 try/catch 调它。改为与 load() 一致返回 undefined;persistRow 的错误信息在未初始化时不再调用 getDbPath。(不能反过来让 workflow worker 也 init:改造前那一次未初始化调用其实会跑完 owner 引导、把扁平 sessions.json 导进一个新建的扁平 .db,正是要删的行为。)
  2. 类型边界没跟着收紧:readSessionRowFromDisk / runUnownedRowTxn / readSessionRowUnowned / applySessionCommandUnownedlarkAppId 仍可选、靠运行时兜底折成 missing,而 HostTarget 已必填。统一收紧为必填、删兜底;缺 larkAppId 的判定只在调用方做,文案统一为 SESSION_ROW_MISSING_APP_ID。对应的 returns missing when the row carries no larkAppId 用例随之删除(契约已由 tsc 保证)。
  3. init('') 拒绝空串;whiteboard 解绑对无 larkAppId 的行前置早退并带 reason。
  4. 注释债:模块头 71-79 仍在描述 feat(session): 收口跨进程会话库协议并补齐升级可见性 #1342 已删的 db-else-json 读路径、loadAllSessionsSnapshot 注释仍写 legacy store / per-bot 赢重复 / 从文件名取 appId、63-65 折行被改坏、fs-policy.ts:888 一处过时注释——全部改掉。
  5. 测试面:恢复被删的「导入源 JSON 损坏时不得留下空壳 .db」断言(改成 per-bot 形态,全仓唯一守这条不变量的用例);新增「磁盘上残留的扁平 sessions.db / sessions.json 被完全忽略:不枚举、不计数、不报 unmigrated」(A-8 最核心的对外语义此前零覆盖);删掉与 :381 完全重复的中毒恢复用例;去掉依赖 readdir 顺序的跨 store 重复 id 断言;session-resume 的 store appId 与行上的 larkAppId 对齐。

复核后不改、留记录的:

  • cli.ts 里 cmdResume 等 6 处「行缺 larkAppId」的用户可见分支在快照无条件补齐 larkAppId 后已不可达,不在 A-8 枚举范围内,留给后续 CLI 清理;scripts/close-sessions.ts 仍按扁平 sessions.json 读,是 2026-03-22 起就失效的先存脚本,另行处理。
  • 中毒恢复的「快照佐证」不再回落扁平 sessions.json,语义比之前收紧(无 per-bot JSON 的 store 缺 WAL 证据与 receipt 时会 fail closed 而非空恢复),与 C-15 的方向一致,已写进设计文档 §5 A-8。
  • 本机 ~/.botmux/data/sessions.json(62K / 7 行,2026-08-09)从「被报成未迁移」变成完全惰性,符合决策。

描述里的数字已订正:实际是 35 个测试文件、99 处无参 init();设计 §2.2 列的 8 处支持点里 7 处在本 PR、第 8 处已随 #1342;PR 首批 11 个文件在当前 HEAD 为 375 passed。

验证(rebase + 修复后):bun run build 通过;PR 涉及的全部测试文件本机跑过——13 个核心文件 469 passed / 2 skipped,dashboard-ipc / restore-zombie-close / kill-worker-orphaned-backend / remote-shutdown-detach 362 passed,其余 20 个 434 passed;session-store-sqlite-poisoned-recovery 17 条因本机 bun 1.4.1 ≠ 钉死的 1.4.2 全部失败(环境性,与本 PR 无关);验收 grep sessionStore.init(\s*) 在 test 下为 0。接下来做本机 dogfooding。

LucasIcarus added a commit that referenced this pull request Sep 9, 2026
- references 补 #1342 / #1344;决策记录与 §5 A-8 的「约 20 个文件」订正为 35 个文件、99 处,并注明导入快照佐证不再回落扁平 JSON 的影响
- §2.2 身份行与 §2.3 第 2 条销账(JSON 那一半随 #1342、扁平 .db 那一半随 #1344);验收 grep 的括号说明与 §6 中已删用例的表述同步
- isolated-bot-deploy.md 的 deny 清单去掉已不存在的 data/sessions.json
@LucasIcarus
LucasIcarus force-pushed the feat/session-endstate-drop-flat-store branch from f9708d7 to 6e24cb1 Compare September 9, 2026 13:19
@LucasIcarus

Copy link
Copy Markdown
Collaborator Author

已再次 rebase 到 #1342 最新 head e161e88(包含「unmigrated 只对仍存在的 bot 判定」那条修复),head 现为 6e24cb1;仅 whiteboard-store.ts 的 import 行冲突,已合并。bun run build 通过,14 个核心测试文件 473 passed / 2 skipped,验收 grep sessionStore.init(\s*) 在 test 下为 0。接下来从本分支做本机 dogfooding,结果另行补充。

@LucasIcarus

Copy link
Copy Markdown
Collaborator Author

本机 dogfooding(bun run switch:here && bun run daemon:restart,6e24cb18,叠在 #1342 e161e88 之上):4 个 daemon + dashboard 全部 online,重启约 40 秒,zmx 后端的 6 个会话全部续上;descriptor 带 sessionStoreProtocol / botmuxVersion,无旧字段;4 个会话库的 occupancy 租约由各自 daemon 持有并续期;botmux list 正常列出 6 个会话,且宿主 shell 下不再出现「会话库尚未迁移」的误报(本机 data/ 下 4 份已移除 bot 的残留 JSON 与扁平 sessions.json 都被忽略,没有创建扁平 sessions.db);重启后由分离脚本经会话内 botmux send 发出的报告正常送达。

@LucasIcarus
LucasIcarus force-pushed the feat/session-endstate-store-close branch from e161e88 to ee25027 Compare September 11, 2026 09:22
LucasIcarus and others added 4 commits September 11, 2026 17:23
扁平 store 早于 v2.16.1、生产零调用;从 A+B 拆出以免约 20 个测试文件的夹具改写淹没协议删除审查。

Co-authored-by: Cursor <cursoragent@cursor.com>
A-8 后写路径必须先 init(appId);CI 里 card-handler / worker-pool / VC 等仍走未初始化的内存夹具,并去掉扁平 store 播种。

Co-authored-by: Cursor <cursoragent@cursor.com>
- getSessionFresh 在未 init 的进程里(BOTMUX_WORKFLOW=1 的 worker)与 load() 一致返回 undefined,不再因 getDbPath 抛错;persistRow 的错误信息在未初始化时不再调用 getDbPath
- init(appId) 拒绝空串
- readSessionRowFromDisk / runUnownedRowTxn / readSessionRowUnowned / applySessionCommandUnowned 的 larkAppId 收紧为必填,删除运行时兜底;缺 larkAppId 的判定只在调用方(cli / whiteboard)做,文案统一为 SESSION_ROW_MISSING_APP_ID
- whiteboard 解绑对无 larkAppId 的行前置早退并带 reason
- 模块头注释与 loadAllSessionsSnapshot 注释改为只认 SQLite、无胜出顺序;fs-policy 一处过时注释
- 测试:恢复「导入源损坏时不留空壳 .db」的断言(per-bot 形态);新增「磁盘上残留的扁平 sessions.db / sessions.json 被完全忽略」;删除与 :381 重复的中毒恢复用例;去掉依赖 readdir 顺序的重复 id 断言;session-resume 的 store appId 与行身份对齐
- references 补 #1342 / #1344;决策记录与 §5 A-8 的「约 20 个文件」订正为 35 个文件、99 处,并注明导入快照佐证不再回落扁平 JSON 的影响
- §2.2 身份行与 §2.3 第 2 条销账(JSON 那一半随 #1342、扁平 .db 那一半随 #1344);验收 grep 的括号说明与 §6 中已删用例的表述同步
- isolated-bot-deploy.md 的 deny 清单去掉已不存在的 data/sessions.json
@LucasIcarus
LucasIcarus force-pushed the feat/session-endstate-drop-flat-store branch from 6e24cb1 to 27f24e5 Compare September 11, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant