# 群成员变动记录的临时缓存

退群记录使用插件客户端的共享内存缓存，不引入 SWR，不写本地磁盘或后端存储。
缓存按登录环境、账号和群的 opaque source key 隔离；目前事件类型固定为 `left`。

## 请求规则

- 第一次进入群聊：等待快记窗口和群主身份就绪，查询当前时间范围。
- 五分钟内再次进入：复用记录、查询范围、分页游标和空结果。最新窗口复用原截止时间，避免每次以新的当前时间查询。
- 超过五分钟再次进入：先展示已缓存记录，再查询当前窗口。有效期只在进入时判断，没有定时校准、轮询、聚焦刷新或网络恢复刷新。
- 历史滚动：只查询未覆盖的范围；密集事件的下一页仍由真实滚动触发。游标始终携带原查询范围，不拼接到新的时间窗口。
- 加载旧游标不延长首页的有效期。未加载的分页不能被当作完整历史。
- 查询失败保留已有记录，不自动重试；同群两秒失败冷却跨视图切换保留。

## 缓存的首帧恢复

展示缓存与发起查询分别控制。成员列表刷新时，群主身份会暂时变为未知；快记也可能仍在后台加载。
这两种等待只阻止新的事件查询，不隐藏同账号、同群已授权读取的缓存。
Hook 在渲染阶段通过只读 `peek` 同步取得记录，按已恢复的快记窗口过滤，避免先渲染空列表再等待 Effect 插入退群提示。
组件重新挂载、尚无快记窗口时，使用缓存中上次同模式的窗口，不借用其他群或其他模式的窗口。
没有缓存的首次进入仍等待群主身份和快记窗口。明确撤销权限时，首帧就隐藏记录并清理缓存。

## 生命周期和通知

`member-event-cache.ts` 持有每群的 `MemberEventTimeline`，组件只是订阅者。
离开视图停止通知触发的查询和视图更新，已发出的请求可以完成并填充缓存；再次进入复用同一请求与分页状态。

全局 SSE 消费者通过 `member-event-hints.ts` 通知缓存：

- 正在查看的群沿用 300 毫秒合并、两秒最小刷新间隔和串行请求。
- 非当前群只记录变动，不发请求；再次进入查询一次。
- 事件 ID 去重状态保留在缓存中，请求按发起时的通知版本记录结果。请求期间的新通知继续有效。
- 历史定位视图只刷新其历史窗口；这不能把最新窗口误标为已更新。

退出登录或切换账号、环境会销毁缓存并取消请求，迟到结果不能写回。
确认失去群主身份或服务端拒绝访问会清除对应群记录；身份加载中的临时禁用不会清缓存。
名称点击和发起私聊仍沿用原服务端权限校验。

## 容量与展示

保留最近使用的 20 个群。离开视图后的缓存每群最多保留 1,000 条事件和 200 个查询范围；当前正在浏览的列表不因缓存限额截断。
淘汰事件时同步丢弃覆盖这些事件的查询范围，避免出现“记录已淘汰，但被误判为已经加载”的缺口。

快记与成员变动继续按发生时间和稳定 ID 合并。历史定位过滤当前窗口，不混入未来记录；名称高亮和资料卡行为保持原实现。

## 验证

回归测试覆盖切群和重新挂载的首帧、身份及快记加载中的缓存显示、空结果、过期后展示旧数据、失败冷却、跨视图游标、历史范围缺口、容量淘汰、权限撤销、账号隔离、后台群通知及请求期间新通知。
请求入口和共享缓存通过真实 Hook / 控制器运行，接口边界使用可控响应记录实际发起的调用。
