Public snapshot state stays in the store engine's plain-data vocabulary (immer drafts reject Sets without the MapSet plugin, which stays off): manager/service/contract carry readonly SessionId[] in Host order, and the tree derivations build their own transient Set — the expandedProjects pattern. Membership-unchanged installs still keep the array reference for Object.is short-circuits.
4.2 KiB
Agent Note: Session 归档(注册表级全局集合)
状态:implemented
English | 中文
问题
Sidebar workspace 浏览区的 session 行菜单里,「Delete session」一直是纯视觉占位(无 handler)。产品口径定为归档而非删除:session 日志与 workspace 记账都不动,只把该 session 从所有分组视图(workspace 分组、Ungrouped、搜索、平铺列表)里隐藏。归档记录需要一个落点:Ungrouped 的 session 不属于任何 workspace 实体,per-workspace 字段放不下它。
决策
归档集合是 workspace domain 全局单例(workspaceDomainState.archivedSessionIds)上的一个新字段,覆盖在 workspace 记账之上;显示过滤全部收敛在 client 的 tree.ts 派生层;wire 面走全快照姿态。
- 存储:
archivedSessionIds: z.array(sessionId).default([]),domain version 保持 2——纯增量字段,旧介质经 schema default 解析为空集合,无迁移代码。被归档的 session 保留其sessionIds席位(未来取消归档恢复原位置),因此与「一个 session 只被一个 workspace 记账」不变式零纠缠。 - Registry:
ctx.workspace.archiveSession(id)走enqueueOperation与 create/delete 串行;未知 session(实时与持久化都查不到)抛WorkspaceUnknownSessionError;已归档 id 不写盘不发事件。archivedSessionIdsgetter 暴露只读集合。 - RPC:
workspace.archiveSession({sessionId}) → {archivedSessionIds}(应答完整更新后集合);workspace.list响应携带集合作为重连基线;新 host 帧host/archived-sessions-changed在每次持久变更后推完整快照(与host/workspace-changed同姿态,从domain/changed的 global put 分支比对推帧)。未知 session 复用错误码session-not-found。 - client runtime:
WorkspaceListState.archivedSessionIds(按 Host 顺序的readonly SessionId[],成员不变不换引用——公有快照状态保持 store 引擎的纯数据词汇:immer draft 不开 MapSet 插件就不接受 Set;membership 查询在派生函数内自建临时 Set,与 expandedProjects 同款);list 基线、unary 回声、changed 帧三路都整体替换安装。投影层在当前 selection 落入归档集合时统一清空回 New Session 视图(用户拍板:归档当前打开的 session 主视图回 hero)——一条规则同时覆盖本地 unary 回声、其他标签页的 changed 帧、以及重连基线恢复出一个离线期间被归档的 selection;帧/回声落在 in-flightworkspace.list期间时还会屏蔽旧基线对新集合的回滚。 - UI:菜单项
delete(visual-only)改为archive(label「Archive session」,非 danger 样式,无确认对话框——非破坏性操作,误触后果只是列表隐藏);过滤实现为tree.ts的sessionVisible判据加一档,deriveGroups/deriveFlat增加archived集合入参,四个视图(分组循环、stray 兜底、搜索、平铺)同源生效。
已考虑的替代方案
per-workspace archivedSessionIds(最初表述)。 否决:Ungrouped session 无落点;用户改口全局。
SessionSummary 打 archived 标(session.list 层)。 否决:要把 workspace domain 事实 join 进 sessions domain 投影,summary 无增量帧还得另发通知,跨域耦合大于收益。
host 侧在 workspaceView/sessionIds getter 过滤。 否决:归档 ≠ 改记账,投影过滤会把两个概念搅浑;未来恢复入口也需要 client 拿到全量记账。
增量帧(archived/removed 单条)。 否决:集合极小、变更频率低,全快照免去 client 侧合并逻辑与去重状态,与 workspace-changed 现有姿态一致。
后果
归档后 UI 无查看/取消归档入口(本期口径,README Known Limitation 记账);数据与席位完好,后续加恢复面只是 UI + 一个逆向 RPC。workspace.list 响应形状变化是 pre-release 直改(无兼容层)。e2e(workspace-management)钉住了「归档→行消失→reload 后仍隐藏、日志仍在」的全链路;domain 层测试钉住幂等、未知 id 拒绝、跨重启恢复与旧介质默认升级。