Skip to content

[Desktop/Chat][P2] 草稿清理后不得重新迁移旧版内容 #76

Description

@jiayuqi7813

触发与范围

桌面聊天本地存储同时存在非空 v1 草稿和 v2 时,v2 的最后一份草稿被清掉后,下一次读取会再次从 v1 迁移,恢复已经清掉的旧正文与选择。clearAllComposerDrafts 仅删 v2,也会留下同样的重新迁移来源。单视图即可触发,不依赖多窗口、失败写入或 Provider。

按 P2 跟踪迁移和清理语义。2026-09-30 的原模块 VM fixture 已确认合成旧稿复活,没有读取真实旧 profile、实际认证锁定、发送旧正文或产生用户事故。范围仅为 desktop-owned 草稿恢复与格式迁移;现有共享 Web 文件用于定位,不要求本轮修改 Web 或后端。

原存储证据与保护对照

原 composerDraftStore.ts TypeScript 转译后直接运行,以原测试 override 接入全成功的合成内存 StorageLike,定时器为内存记录;没有真实窗口、localStorage、HTTP、账号或工具。

  • 非空 v1 第一次读取正常迁移到 v2;调用原 clearComposerDraft 清最后一项并 flush,v2 确为 {drafts:{}}。fresh VM 再读取时,原正文从 v1 回来,并重新写入 v2。
  • 同样 v1 条件下调用原 clearAllComposerDrafts,v2 key 消失、v1 保留;fresh read 再恢复旧正文。
  • 一开始已有合法空 v2 与非空 v1,也把旧稿迁移回来,说明判断的是“当前桶是否空”,没有区分“从未迁移”和“清理后的合法空状态”。
  • 没有 v1 的对照:清最后一项并 flush 后,fresh read 正常返回 null,不复活。

完整旧/新格式输入、清理前后快照、存储操作与源码哈希仅存本地 ignored artifact。此证据限定为本存储中的合成内容恢复,不代表实际用户已经重发旧内容。

根因与影响边界

readBucketFromStorage 只要 parse 后无 key 就调用 migrateV1Drafts。后者会保留 v1 供旧 tab 使用,未记录一次性迁移完成;clearComposerDraft 只更新 v2,clearAllComposerDrafts 也仅删除 v2。保留兼容数据有用途,但当前读取路径把已清空误作需要迁移,旧格式成为可重复回退来源。

已有非空 v2 时不会走该分支;全程没有 v1 的正常清理也工作。风险只涉及升级后仍有旧格式内容的 profile。清理后恢复旧正文、模型或权限选择会让用户难以判断哪些本地状态已失效;没有测试后续提交或实际权限效果,不能报告越权、私有数据外发或 P0。

桌面优化与验收

  • 区分尚未迁移、成功迁移和当前合法空状态;迁移完成后不能因空桶重新回退到旧稿。保留旧 tab 兼容时采用明确完成标记/删除语义,而非用内容是否为空判断版本。
  • 对明确清理的范围覆盖旧格式,或保留可核验的清理标记,确保旧兼容副本不能覆盖用户决定。
  • 重跑上述原模块 fixture:首次迁移完整保留正文、引用、附件元数据及选择;清最后一项、清所有和合法空 v2 后 fresh read 仍为空。无 v1 与非空 v2 的对照继续通过。
  • 独立可弃置升级 profile 补实际桌面恢复验收。临时认证失效时应如何保留草稿仍按 #69 处理,本条不要求扩大 401 删除或把自动锁定当成用户清理授权。

去重与源码

跨 realm 整桶竞争是另一主因;本条只用单 realm/fresh read 和旧格式回迁。与 #58 的写盘失败、#61 的迟到发送清理、#69 的认证自动擦除分别去重,关联 Epic #31。

源码导航:composerDraftStore、ConversationShell 清理调用。公开固定提交仅供导航,隔离证据保存当前源码哈希,不宣称发行包或生产 profile 已复现。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions