返回 DeepSeek-Reasonix
new-session-removal-validation.md
根目录 / docs / new-session-removal-validation.md
1 # 新建会话删除与草稿生命周期:实施与验证
2
3 ## English overview
4
5 This change gives each removable new conversation an explicit action based on
6 its persisted identity. Empty drafts are discarded immediately; drafts with
7 content require confirmation; drafts with an unresolved first submission remain
8 protected. Formal sessions, including zero-message sessions, use the existing
9 archive and restore path. A legacy metadata-only topic is discarded when it has
10 no user organization, or archived with recoverable metadata when it has a
11 manual title, pin, group, or unknown title origin.
12
13 `InspectTopicRemoval` returns a disposition and state token. `RemoveTopic`
14 rechecks identity and token under the storage locks and records an idempotent
15 operation before changing indexes or metadata. A separate optional
16 `topicRemovals` collection preserves compatibility with older workspace-state
17 readers. Interrupted operations replay only while their identity and state
18 still match; restore preserves the original topic ID and rejects an occupied ID.
19
20 Post-implementation review found and fixed four further defects: supported v1
21 organization files were rejected; cross-workspace topic ID reuse could damage
22 another workspace on retry or restore; a formal session could be renamed after
23 confirmation but before archive publication; and an unrelated edit could block
24 an interrupted restore indefinitely. Deterministic regression tests cover the
25 failure orderings and startup replay.
26
27 Focused Desktop Go and storage tests passed under `-race`. Frontend tests,
28 typecheck, production build, generated-contract checks, Electron shell build,
29 lint, and an isolated macOS native UI smoke passed. The native smoke covered
30 draft actions, project navigation, legacy placeholder removal, sidebar archive,
31 restart, restore, and a delayed duplicate request. These results do not prove
32 the root cause in the reporter's original 1.38.11 installation, nor validate
33 Windows or Linux packages or a real provider's first submission. This work is
34 source, integration, and macOS development-shell evidence.
35
36 基线:实施前同步 `main-v2`,由分析基线 `c84b4389bf14` 前进至 `ec0df71ec129`。
37 PR 集成时继续同步至 `ea64efc8e`,重新生成 Desktop 契约和命令 inventory。
38 交付包括代码、生成契约、测试及本记录;合并与发布状态以 GitHub 实时记录为准。
39
40 ## 行为
41
42 | 对象 | 操作及结果 |
43 | --- | --- |
44 | 无内容草稿 | 直接丢弃,不进回收站 |
45 | 含文字、附件、引用、调用内容或粘贴块的草稿 | 确认不可恢复后丢弃;取消保留内容 |
46 | 提交中、结果未知、取消尚未完成 | 保留提交所有权,阻止丢弃并解释原因 |
47 | 正式会话,含零消息会话 | 使用原正式归档与恢复流程 |
48 | 自动默认标题、未置顶、未分组的旧空主题 | 移除占位,不进回收站 |
49 | 已命名、置顶、分组或标题来源不明的旧空主题 | 元数据进入回收站,可恢复、彻底删除,无聊天预览 |
50 | 状态改变、归属不唯一或数据无法可靠读取 | 拒绝移除;显示错误并刷新实际状态 |
51
52 关闭界面、切换工作区和会话保持草稿的保存/隐藏语义。草稿继续使用
53 `DiscardSessionDraft(draftID, revision)`,不接入正式会话归档。
54 不新增正式空会话,不删除用户原始附件,不改变草稿保存期限或聊天正文格式。
55
56 ## 实现边界
57
58 - `useSessionDraftSurface` 继续作为草稿 owner。补齐重复点击保护、丢弃中的
59 状态投影和错误展示;保留 revision、编辑版本、提交所有权及导航意图校验。
60 - `InspectTopicRemoval` 返回处理方式、可操作性、阻止原因及状态 token;
61 `RemoveTopic` 接收操作 ID 与原 token,只有明确提交后前端才安装防回跳标记。
62 有部分写入时保留原请求身份,重试不重新猜测删除方式。
63 - 旧 `TrashTopic` 保留运行时快照、租约及正式归档兼容处理;元数据分支共享
64 新分类与事务实现。无索引但有历史文件的对象仍归档,跨工作区歧义被拒绝。
65 - `topicRemovals` 是工作区状态的可选独立集合,不修改旧 PendingOperations
66 的严格类型枚举。保存 prepared 意图和完整主题元数据后才移除索引/元数据;
67 完成记录写失败不得返回成功。
68 - 重启只恢复既有操作,复核身份、版本、会话关联和运行状态。
69 恢复使用原 ID,恢复排序、置顶、标题来源及仍存在的分组;缺失工作区报错,
70 同 ID 新数据冲突不覆盖。清除恢复记录不会再次删除活动主题。
71 - 已完成的默认占位移除保留幂等收据;可恢复记录使用
72 `topic-removal:<operationId>`,移除/恢复/清除推进 generation。
73 - 完整聊天文件索引不包含无文件主题。普通列表现在补入经归属和数据源检查的
74 空占位,避免恢复接口成功但恢复对象在侧栏不可见;不复活已归档正式会话
75 或被目录隐藏的历史恢复副本。
76 - RPC 类型、bridge、mock、英文/简体/繁体文案同步更新。mock 生命周期
77 按需加载,保持既有首屏资源预算。
78
79 ## 本地验证
80
81 全部持久化及原生桌面验证使用隔离数据目录;不操作个人会话。
82
83 | 验证层 | 结果与范围 |
84 | --- | --- |
85 | Desktop Go 回归及 race | TopicRemoval、TrashTopic、空正式会话、旧空主题、完整目录列表、历史恢复链、生成契约检查通过;相关组使用 `-race` |
86 | 草稿与工作区存储 | `go test -race ./internal/draftstate ./internal/workspacestate` 通过 |
87 | 明确故障次序 | 用 checkpoint 中断索引/元数据/最终收据各阶段,并用真实写失败验证不得成功;恢复中断、冲突、重复请求、工作区离线、分组消失有回归 |
88 | 跨进程 | 独立进程重命名后旧 token 被拒绝;存储层已有跨进程 writer/worker 锁测试保持通过 |
89 | 草稿所有权 | 固定丢弃与提交事务先后,验证提交结果未知和取消请求未完成仍阻止丢弃;迟到保存与旧界面响应、确认期间编辑、重复点击、失败保留内容有回归 |
90 | 前端 | 草稿呈现/所有权/导航、主题删除 controller、mock、归档竞态、回收站确认及重试通过;远程项目树 28 项通过 |
91 | 类型及构建 | 前端 typecheck、test:typecheck、完整生产构建及资源预算通过;Electron shell 构建通过 |
92 | macOS 原生开发版 | 全局快捷新建、项目新建按钮键盘激活、切换返回保留草稿、取消/确认丢弃、侧栏右键归档、关闭重启后恢复、迟到重复删除均通过;无 renderer 错误 |
93 | 规范及契约 | repolint、golangci-lint、生成契约一致性、`git diff --check` 通过 |
94 | 降级写入 | 使用基线的真实 v3 workspacestate 源码,读取含 topicRemovals 的状态并执行 RenameWorkspace,确认未知集合及嵌套字段仍完整;新版未知字段往返及深拷贝有单元测试 |
95
96 主要可复现命令:
97
98 ```sh
99 # 仓库根目录
100 go run ./tools/repolint
101
102 # desktop Go 模块
103 go test -race ./internal/draftstate ./internal/workspacestate
104 go test -race . -run 'Test(TopicRemoval|NamedEmptyTopic|EmptyTopicArchive|NewBlank|TrashTopic|HostContractGeneratedFilesAreCurrent|ListProjectTopics|UpgradeLegacyRecoveryChain)' -count=1
105 golangci-lint run --timeout=3m --new-from-rev=HEAD .
106
107 # desktop/frontend
108 pnpm test:typecheck
109 pnpm build
110 pnpm exec tsx src/__tests__/topic-removal-controller.test.tsx
111 pnpm exec tsx src/__tests__/topic-removal-mock.test.ts
112 pnpm exec tsx src/__tests__/session-draft-ownership.test.tsx
113
114 # 先构建 frontend/dist、desktop/build/bin/reasonix-desktop-service 和 Electron shell
115 # desktop/electron
116 node scripts/topic-removal-smoke.mjs
117 ```
118
119 原生冒烟脚本使用真实 Electron renderer、IPC 和 Go 服务。确认对话框的
120 接受/取消由测试控制;持久化 RPC 条件在 Node 侧逐次 await,不使用
121 `waitForFunction(async ...)` 作为持久化完成证据。脚本输出独立目录中的
122 `results.json`、截图和 shell 日志,包括关闭重启后的状态断言。
123
124 ## 实施后缺陷复查
125
126 以下四类问题均先以回归测试复现失败,再修复并通过相同测试:
127
128 | 问题 | 影响与修复 |
129 | --- | --- |
130 | 旧分组文件版本兼容遗漏 | 原读取器支持 v1,但删除检查只接受 v2,导致旧数据无法操作;现沿用受支持的版本范围 |
131 | 中断重试及恢复遗漏其他工作区归属 | 相同主题 ID 被其他工作区占用后,重试可能移除新索引,恢复可能制造重复归属;现持有跨进程索引写锁检查所有工作区的列表、置顶和分组引用,冲突时保留新数据 |
132 | 正式归档提交缺少确认状态校验 | 用户确认后发生重命名,归档仍可能提交,启动重放也可能绕过检查;现持久化正式会话状态 token,在工作区状态事务提交点重新验证,启动重放执行同一校验 |
133 | 恢复中断被无关编辑永久阻塞 | 恢复尚未写入目标元数据时,其他主题编辑会使预留 revision 失效;现仅在目标行及原索引均不存在时重新持久化预留 revision,已有同 ID 数据仍严格校验 |
134
135 回归文件为 `desktop/topic_removal_review_test.go`。并发窗口使用明确 checkpoint
136 固定顺序,覆盖确认后与正式归档提交前两处重命名,以及持久化操作重放;
137 不以 race 检查代替生命周期断言。
138
139 复查后 Desktop 相关回归及 `-race`、workspacestate/draftstate 的 `-race`、
140 golangci-lint、repolint 和生成契约一致性检查通过。此次复查未改变前端代码,
141 前端类型、构建及资源预算结果沿用前述验证。
142 重新构建 Go 服务后,macOS 原生冒烟的七项断言全部通过,renderer 错误列表为空;
143 覆盖草稿取消/丢弃、项目切换、侧栏归档、关闭重启恢复和迟到重复请求。
144
145 ## 证据边界
146
147 PR preflight now covers both generated RPC contracts and the root Desktop
148 inventory. Production payload validation uses the Electron shell and a full
149 40-character `REASONIX_COMMIT`, matching CI rather than the local short-SHA
150 default. Topic-removal mock commands share the lazy lifecycle module, keeping
151 their implementation off the startup path without changing the budget.
152
153 PR 预检同时覆盖 RPC 契约和根模块 Desktop inventory。生产资源验证使用
154 Electron shell 和完整 40 位 `REASONIX_COMMIT`,与 CI 输入一致。
155 主题移除 mock 接口复用按需加载的生命周期模块,未提高本 PR 的资源预算。
156
157 - 已确认源码/集成层旧空主题删除问题,并完成 macOS 开发版原生 UI 回归。
158 - 未取得反馈用户的 1.38.11 原始环境、日志或同安装包复现,不能认定
159 `no sessions to archive` 就是原反馈的唯一根因。
160 - 原生冒烟不调用真实模型服务;首条提交争用、未知结果和取消语义由
161 生命周期/存储测试覆盖,不宣称完成真实提供商首发端到端验证。
162 - Windows、Linux 原生安装包、签名/发布、远程服务协议升级均不属于本次
163 已验证证据。远程协议未调整,只做了前端防误路由回归。
164 - 本次复盘沿用既有“真实 RPC 完成判据”和“恢复后验证列表投影”的规则,
165 未添加重复的技能条目。
166
166 lines MARKDOWN