dsh-archived-chats 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,8 +46,8 @@ dsh plugin --profile web update dsh-archived-chats
46
46
  ```
47
47
 
48
48
  <p align="center">
49
- <a href="assets/screenshots/preview-03.png"><img src="assets/screenshots/preview-03.png" width="49%" alt="Native read-only legacy-data preview with snapshot time and a synthetic stored image"></a>
50
- <a href="assets/screenshots/preview-07.png"><img src="assets/screenshots/preview-07.png" width="49%" alt="Storage and Retention with session directories, protection snapshots, and policy controls"></a>
49
+ <a href="assets/screenshots/preview-03.png"><img src="assets/screenshots/preview-03.png" width="49%" alt="Multi-workspace archive chooser with Select all and explicit confirmation"></a>
50
+ <a href="assets/screenshots/preview-07.png"><img src="assets/screenshots/preview-07.png" width="49%" alt="Confirmation before enabling automatic Recycle Bin cleanup"></a>
51
51
  </p>
52
52
 
53
53
  ## Core capabilities
@@ -57,20 +57,20 @@ dsh plugin --profile web update dsh-archived-chats
57
57
  | **Browse and search** | Workspace-grouped archive browsing, full-text search across messages and tool results, filters, sorting, tags, and notes. |
58
58
  | **Archive a workspace** | From **Settings → Session Archive**, choose a workspace and open one confirmation for every eligible chat in it. Empty new-session windows are excluded; the workspace and its directory stay unchanged. |
59
59
  | **Read-only preview** | Native conversation layout for Markdown, reasoning, tool activity, JSON, code, and available stored images, with responsive turn navigation. |
60
- | **Existing data** | Prior snapshots remain accessible under **Storage & Retention → Legacy data** for read-only preview, recovery as an archived copy, or confirmed deletion. Archiving no longer creates versions. |
60
+ | **Existing data** | Prior snapshots appear directly in the **Recycle Bin** for read-only preview, recovery as a new archived copy, or confirmed permanent deletion. Archiving no longer creates versions. |
61
61
  | **Backup and restore** | JSON + Markdown ZIP export with preview-first, conflict-safe import. Existing session IDs are never overwritten. |
62
62
  | **Recoverable deletion** | Snapshot-protected Recycle Bin with immediate Undo, two-level restore, separately confirmed permanent deletion, and an optional direct permanent-delete action for users who do not need recovery. |
63
- | **Storage and relationships** | Separate storage accounting, preview-first Recycle Bin age policies, and read-only Origins & Branches for forks and subagent trees. |
63
+ | **Storage and relationships** | Separate storage accounting, optional automatic Recycle Bin cleanup, and read-only Origins & Branches for forks and subagent trees. |
64
64
 
65
- The four main views are **Archived**, **Recycle Bin**, **Storage & Retention**, and **Origins & Branches**. Existing snapshots are preserved during upgrades; the separate History tab and archive-time capture have been retired.
65
+ The four main views are **Archived**, **Recycle Bin**, **Storage & Retention**, and **Origins & Branches**. Existing snapshots are preserved during upgrades and folded into the Recycle Bin; the separate History entry and archive-time capture have been retired.
66
66
 
67
67
  ## Safety by design
68
68
 
69
69
  - **Local only:** plugin metadata, recycle records, policies, and validated snapshots stay under `$DSH_HOME/plugin-data/archived-chats/`. Nothing is uploaded or cloud-synced.
70
- - **No silent overwrite:** imports and legacy-data recovery create or select non-conflicting IDs; they never replace an existing session.
70
+ - **No silent overwrite:** imports and legacy-snapshot recovery create or select non-conflicting IDs; they never replace an existing session.
71
71
  - **Deletion stays explicit:** ordinary removal enters the Recycle Bin after snapshot protection. Physical removal is available only through confirmed permanent-purge actions.
72
- - **No automatic cleanup:** retention policies are saved separately from execution. Every cleanup starts with a short-lived preview and explicit selection.
73
- - **Confirmed workspace archive:** the plugin prepares the exact set in the background, then shows one confirmation with the workspace and chat count. Only sessions whose inspected log contains a real `turn/start` are eligible; empty new-session windows and sessions whose content cannot be confirmed are skipped. Its five-minute, single-use credential excludes chats added later; a running chat is skipped, never stopped or moved.
72
+ - **Optional automatic cleanup:** off by default. After confirming a retention period, expired Recycle Bin chats are permanently deleted while DSH runs, with catch-up on startup. Enabling or shortening the period shows affected chats for confirmation; older saved policies stay disabled.
73
+ - **Confirmed workspace archive:** the chooser lists only workspaces with eligible chats and supports single, multiple, or toggleable Select all selection through a bottom-right Confirm button. The plugin prepares each exact set in the background, skips workspaces that became empty, then shows one aggregate confirmation. Only sessions whose inspected log contains a real `turn/start` are eligible; empty new-session windows and sessions whose content cannot be confirmed are skipped. Each workspace keeps its own five-minute, single-use credential, which excludes chats added later; a running chat is skipped, never stopped or moved.
74
74
  - **Backup scope is visible:** ZIP exports preserve complete session JSON and readable Markdown, but do not include attachment bytes or descendant sessions.
75
75
 
76
76
  ## Compatibility
@@ -79,14 +79,14 @@ Features activate from the public capabilities exposed by the DeepSeek Harness H
79
79
 
80
80
  | Host capability | Plugin behavior |
81
81
  | --- | --- |
82
- | Archive and session reads | Browsing, search, preview, legacy-data inventory, storage accounting, and lineage. |
83
- | `settings.section` + public `archiveSession` | The plugin-owned settings page provides the workspace chooser and one-confirmation archive flow without requiring a workspace-menu extension slot. Without archive capability, preparation returns `workspace-archive-unsupported` and makes no change. |
82
+ | Archive and session reads | Browsing, search, preview, legacy-snapshot inventory in the Recycle Bin, storage accounting, and lineage. |
83
+ | `settings.section` + public `archiveSession` | The plugin-owned settings page provides an eligible-only multi-workspace chooser and one aggregate confirmation without requiring a workspace-menu extension slot. Without archive capability, preparation returns `workspace-archive-unsupported` and makes no change. |
84
84
  | Attachment reads | Stored images appear in conversation and snapshot previews; without it, text remains readable. |
85
85
  | Session-scoped log location | Recycle Bin permanent deletion uses the persistence provider's public `locate(meta)` capability. Providers without a session-scoped location remain unsupported; failed operations retain their rows and display the reason. |
86
- | Public session writer | ZIP import, legacy-data recovery, and snapshot fallback when an original is missing all write through the Host's public `create` / `append` / `locate` capability, or a dedicated restore entry point where one exists. |
86
+ | Public session writer | ZIP import, legacy-snapshot recovery, and snapshot fallback when an original is missing all write through the Host's public `create` / `append` / `locate` capability, or a dedicated restore entry point where one exists. |
87
87
  | Missing write capability | The operation returns `restore-unsupported` without writing or overwriting data. |
88
88
 
89
- Back up `$DSH_HOME/plugin-data/archived-chats/` before downgrading to a release that does not display legacy data or understand recycle snapshots.
89
+ Back up `$DSH_HOME/plugin-data/archived-chats/` before downgrading to a release that does not understand the unified Recycle Bin or newer snapshot state.
90
90
 
91
91
  ## Demo preview
92
92
 
@@ -97,19 +97,19 @@ The eight fixed screenshots below come from an isolated Simplified Chinese light
97
97
  <br>
98
98
  <table>
99
99
  <tr>
100
- <td><img src="assets/screenshots/preview-01.png" alt="Session Archive overview with four management views"><br><sub>Archive overview</sub></td>
100
+ <td><img src="assets/screenshots/preview-01.png" alt="Latest Archived view with search, filters, tags, one-line notes, and current actions"><br><sub>Archive overview</sub></td>
101
101
  <td><img src="assets/screenshots/preview-02.png" alt="Full-text search, filters, tags, and readable hit excerpts"><br><sub>Full-text search</sub></td>
102
102
  </tr>
103
103
  <tr>
104
- <td><img src="assets/screenshots/preview-03.png" alt="Native read-only legacy-data preview with a stored image"><br><sub>Read-only preview</sub></td>
105
- <td><img src="assets/screenshots/preview-04.png" alt="Legacy data with recovery and deletion actions"><br><sub>Legacy data</sub></td>
104
+ <td><img src="assets/screenshots/preview-03.png" alt="Eligible-only multi-workspace archive chooser with Select all"><br><sub>Workspace archive chooser</sub></td>
105
+ <td><img src="assets/screenshots/preview-04.png" alt="Native read-only legacy snapshot preview with a stored image"><br><sub>Read-only preview</sub></td>
106
106
  </tr>
107
107
  <tr>
108
- <td><img src="assets/screenshots/preview-05.png" alt="Irreversible confirmation before clearing legacy data"><br><sub>Clear legacy data confirmation</sub></td>
109
- <td><img src="assets/screenshots/preview-06.png" alt="Recycle Bin protection snapshot, restore, and permanent deletion"><br><sub>Recycle Bin</sub></td>
108
+ <td><img src="assets/screenshots/preview-05.png" alt="Unified Recycle Bin with legacy snapshots and row and workspace actions"><br><sub>Unified Recycle Bin</sub></td>
109
+ <td><img src="assets/screenshots/preview-06.png" alt="Irreversible confirmation before emptying every workspace in the Recycle Bin"><br><sub>Empty Recycle Bin confirmation</sub></td>
110
110
  </tr>
111
111
  <tr>
112
- <td><img src="assets/screenshots/preview-07.png" alt="Storage accounting and retention policy controls"><br><sub>Storage and retention</sub></td>
112
+ <td><img src="assets/screenshots/preview-07.png" alt="Storage and Retention confirmation before enabling automatic cleanup"><br><sub>Automatic cleanup confirmation</sub></td>
113
113
  <td><img src="assets/screenshots/preview-08.png" alt="Origins and Branches with forks, subagents, and recycled state"><br><sub>Origins and Branches</sub></td>
114
114
  </tr>
115
115
  </table>
@@ -135,7 +135,7 @@ Session Archive is actively maintained. The latest stable npm release receives f
135
135
  npm test
136
136
  ```
137
137
 
138
- The suite covers Host and browser behavior, export/import, legacy-data recovery, Recycle Bin, retention, search, responsive layout, public types, package contents, and repository hygiene. It uses isolated temporary data and never reads real sessions.
138
+ The suite covers Host and browser behavior, export/import, older-snapshot recovery, Recycle Bin, retention, search, responsive layout, public types, package contents, and repository hygiene. It uses isolated temporary data and never reads real sessions.
139
139
 
140
140
  ## Uninstall
141
141
 
@@ -143,7 +143,7 @@ The suite covers Host and browser behavior, export/import, legacy-data recovery,
143
143
  dsh plugin --profile web remove dsh-archived-chats
144
144
  ```
145
145
 
146
- Uninstalling removes only the plugin package. It does not delete local data under `$DSH_HOME/plugin-data/archived-chats/` or trigger Recycle Bin permanent purge. Retained data includes `metadata.json`, `trash.json`, `retention.json`, the `snapshots/` directory, and any legacy `pending-deletions.json` that has not yet been migrated. A later reinstall can use this data. Before permanently removing the directory, restore and back up anything you need, then delete it manually only after confirming that none of its data is still required.
146
+ Uninstalling removes only the plugin package. It does not delete local data under `$DSH_HOME/plugin-data/archived-chats/` or trigger Recycle Bin permanent purge. Retained data includes `metadata.json`, `trash.json`, `legacy-recycle.json`, `retention.json`, the `snapshots/` directory, and any legacy `pending-deletions.json` that has not yet been migrated. A later reinstall can use this data. Before permanently removing the directory, restore and back up anything you need, then delete it manually only after confirming that none of its data is still required.
147
147
 
148
148
  ## License
149
149
 
package/README.zh-CN.md CHANGED
@@ -45,8 +45,8 @@ dsh plugin --profile web update dsh-archived-chats
45
45
  ```
46
46
 
47
47
  <p align="center">
48
- <a href="assets/screenshots/preview-03.png"><img src="assets/screenshots/preview-03.png" width="49%" alt="带旧版快照时间和合成图片的原生只读预览"></a>
49
- <a href="assets/screenshots/preview-07.png"><img src="assets/screenshots/preview-07.png" width="49%" alt="空间与策略中的会话目录、保护快照和保留策略"></a>
48
+ <a href="assets/screenshots/preview-03.png"><img src="assets/screenshots/preview-03.png" width="49%" alt="支持全选并明确确认的多工作区归档选择器"></a>
49
+ <a href="assets/screenshots/preview-07.png"><img src="assets/screenshots/preview-07.png" width="49%" alt="启用回收站自动清理前的确认"></a>
50
50
  </p>
51
51
 
52
52
  ## 核心能力
@@ -56,20 +56,20 @@ dsh plugin --profile web update dsh-archived-chats
56
56
  | **浏览与搜索** | 按工作区浏览归档聊天,全文搜索消息和工具结果,并支持筛选、排序、标签与备注。 |
57
57
  | **归档整个工作区** | 从 **设置 → 会话档案** 打开工作区选择器,再用一次确认归档其中全部符合条件的聊天;空白的新会话窗口不会计入,工作区及其目录保持不变。 |
58
58
  | **原生只读预览** | 以原生对话布局展示 Markdown、思考过程、工具活动、JSON、代码和可用的已存储图片,并提供响应式轮次导航。 |
59
- | **旧版数据** | 已有快照保留在 **空间与策略 → 旧版数据**,支持只读预览、恢复为归档副本或确认删除;归档不再生成版本。 |
59
+ | **已有快照** | 已有快照直接显示在 **回收站**,支持只读预览、恢复为新的归档副本或确认永久删除;归档不再生成版本。 |
60
60
  | **备份与恢复** | 导出 JSON + Markdown ZIP,并通过预览优先、冲突安全的流程导入;已有会话 ID 永不覆盖。 |
61
61
  | **可恢复删除** | 带保护快照的回收站支持立即撤销、两级恢复,以及单独确认的永久删除。 |
62
- | **空间与关系** | 空间分账、预览优先的回收站保留天数策略,以及用于分叉和子代理树的只读「来源与分支」。 |
62
+ | **空间与关系** | 空间分账、可选的回收站自动清理,以及用于分叉和子代理树的只读「来源与分支」。 |
63
63
 
64
- 四个主视图为 **已归档**、**回收站**、**空间与策略** 和 **来源与分支**。升级会保留已有快照;独立历史版本标签与归档时自动抓取已取消。
64
+ 四个主视图为 **已归档**、**回收站**、**空间与策略** 和 **来源与分支**。升级会保留已有快照并统一放入回收站;独立历史版本入口与归档时自动抓取已取消。
65
65
 
66
66
  ## 安全设计
67
67
 
68
68
  - **数据只在本机:** 插件元数据、回收记录、策略和已验证快照均保存在 `$DSH_HOME/plugin-data/archived-chats/`,不会上传或云同步。
69
- - **不静默覆盖:** 导入和旧版数据恢复只创建或选择无冲突 ID,绝不覆盖已有会话。
69
+ - **不静默覆盖:** 导入和旧快照恢复只创建或选择无冲突 ID,绝不覆盖已有会话。
70
70
  - **删除必须明确:** 普通移除会在快照保护后进入回收站;只有经过确认的永久删除操作才会物理清除。
71
- - **不自动清理:** 保留策略的保存与执行分离,每次清理都从短效预览和明确选择开始。
72
- - **确认工作区归档:** 插件在后台准备精确集合,再显示一次包含工作区与会话数量的确认。只有检查到真实 `turn/start` 的会话才符合条件;空白的新会话窗口及无法确认内容的会话都会跳过。5 分钟有效、只能使用一次的凭据不会纳入之后新建的聊天;运行中的聊天只会跳过,绝不停止或移动。
71
+ - **可选自动清理:** 默认关闭,确认保留期限后,DSH 运行时自动永久删除到期的回收聊天,启动后补清理。开启或缩短期限会先列出受影响聊天供确认;旧版设置不会自动开启。
72
+ - **确认工作区归档:** 选择器只显示有可归档会话的工作区,支持单选、多选和可再次点击取消的“全选”,并统一从右下角“确定”继续。插件在后台分别准备精确集合,跳过准备期间变为空的工作区,再显示一次汇总确认。只有检查到真实 `turn/start` 的会话才符合条件;空白的新会话窗口及无法确认内容的会话都会跳过。每个工作区保留独立的 5 分钟单次凭据,不会纳入之后新建的聊天;运行中的聊天只会跳过,绝不停止或移动。
73
73
  - **备份范围清楚:** ZIP 保留完整会话 JSON 和可读 Markdown,但不包含附件二进制或后代会话。
74
74
 
75
75
  ## 兼容性
@@ -78,14 +78,14 @@ dsh plugin --profile web update dsh-archived-chats
78
78
 
79
79
  | Host 能力 | 插件行为 |
80
80
  | --- | --- |
81
- | 归档与会话读取 | 浏览、搜索、预览、旧版数据清单、空间分账和会话血缘。 |
82
- | `settings.section` + 公开 `archiveSession` | 插件自己的设置页提供工作区选择器和一次确认归档流程,不依赖工作区菜单扩展 slot;缺少归档能力时,准备请求返回 `workspace-archive-unsupported`,且不作任何修改。 |
81
+ | 归档与会话读取 | 浏览、搜索、预览、回收站中的旧快照清单、空间分账和会话血缘。 |
82
+ | `settings.section` + 公开 `archiveSession` | 插件自己的设置页提供仅展示可归档项的多工作区选择器和一次汇总确认,不依赖工作区菜单扩展 slot;缺少归档能力时,准备请求返回 `workspace-archive-unsupported`,且不作任何修改。 |
83
83
  | 附件读取 | 对话和快照预览可显示已存储图片;缺少时文本内容仍可阅读。 |
84
84
  | 会话独立日志位置 | 回收站永久删除使用持久化后端公开的 `locate(meta)` 能力。后端不提供会话独立位置时不支持永久删除;失败的条目保留在列表中并显示具体原因。 |
85
- | 公开会话 writer | ZIP 导入、旧版数据恢复 和原件丢失时的快照回退,都通过 Host 公开的 `create` / `append` / `locate` 能力写入;Host 提供专用恢复入口时优先使用。 |
85
+ | 公开会话 writer | ZIP 导入、旧快照恢复和原件丢失时的快照回退,都通过 Host 公开的 `create` / `append` / `locate` 能力写入;Host 提供专用恢复入口时优先使用。 |
86
86
  | 缺少写入能力 | 操作返回 `restore-unsupported`,不会写入或覆盖数据。 |
87
87
 
88
- 降级到不显示旧版数据或不识别回收快照的版本前,请备份 `$DSH_HOME/plugin-data/archived-chats/`。
88
+ 降级到不识别统一回收站或新版快照状态的版本前,请备份 `$DSH_HOME/plugin-data/archived-chats/`。
89
89
 
90
90
  ## 演示预览
91
91
 
@@ -96,19 +96,19 @@ dsh plugin --profile web update dsh-archived-chats
96
96
  <br>
97
97
  <table>
98
98
  <tr>
99
- <td><img src="assets/screenshots/preview-01.png" alt="会话档案总览和四个管理视图"><br><sub>归档总览</sub></td>
99
+ <td><img src="assets/screenshots/preview-01.png" alt="包含搜索、筛选、标签、单行备注和当前操作的最新版归档页"><br><sub>归档总览</sub></td>
100
100
  <td><img src="assets/screenshots/preview-02.png" alt="全文搜索、筛选、标签与命中摘要"><br><sub>全文搜索</sub></td>
101
101
  </tr>
102
102
  <tr>
103
- <td><img src="assets/screenshots/preview-03.png" alt="带已存储图片的原生只读旧版数据预览"><br><sub>原生只读预览</sub></td>
104
- <td><img src="assets/screenshots/preview-04.png" alt="带恢复和删除操作的旧版数据"><br><sub>旧版数据</sub></td>
103
+ <td><img src="assets/screenshots/preview-03.png" alt="仅展示可归档项并支持全选的多工作区归档选择器"><br><sub>工作区归档选择器</sub></td>
104
+ <td><img src="assets/screenshots/preview-04.png" alt="带已存储图片的旧版快照原生只读预览"><br><sub>原生只读预览</sub></td>
105
105
  </tr>
106
106
  <tr>
107
- <td><img src="assets/screenshots/preview-05.png" alt="清空旧版数据前的不可恢复确认"><br><sub>清空旧版数据确认</sub></td>
108
- <td><img src="assets/screenshots/preview-06.png" alt="保护快照、恢复和永久删除"><br><sub>回收站</sub></td>
107
+ <td><img src="assets/screenshots/preview-05.png" alt="包含旧版快照及单条和工作区操作的统一回收站"><br><sub>统一回收站</sub></td>
108
+ <td><img src="assets/screenshots/preview-06.png" alt="清空所有工作区回收站前的不可恢复确认"><br><sub>清空回收站确认</sub></td>
109
109
  </tr>
110
110
  <tr>
111
- <td><img src="assets/screenshots/preview-07.png" alt="空间分账和保留策略控件"><br><sub>空间与策略</sub></td>
111
+ <td><img src="assets/screenshots/preview-07.png" alt="空间与策略中启用自动清理前的确认"><br><sub>自动清理确认</sub></td>
112
112
  <td><img src="assets/screenshots/preview-08.png" alt="来源与分支中的分叉、子代理和回收状态"><br><sub>来源与分支</sub></td>
113
113
  </tr>
114
114
  </table>
@@ -134,7 +134,7 @@ Session Archive 目前处于积极维护状态。最新 npm 稳定版会接收
134
134
  npm test
135
135
  ```
136
136
 
137
- 测试覆盖 Host 与浏览器行为、导出导入、旧版数据恢复、回收站、保留策略、全文搜索、响应式布局、公开类型、包内容和仓库卫生。测试只使用隔离临时数据,不读取真实会话。
137
+ 测试覆盖 Host 与浏览器行为、导出导入、旧快照恢复、回收站、保留策略、全文搜索、响应式布局、公开类型、包内容和仓库卫生。测试只使用隔离临时数据,不读取真实会话。
138
138
 
139
139
  ## 卸载
140
140
 
@@ -142,7 +142,7 @@ npm test
142
142
  dsh plugin --profile web remove dsh-archived-chats
143
143
  ```
144
144
 
145
- 卸载只移除插件包,不会删除 `$DSH_HOME/plugin-data/archived-chats/` 中的本地数据,也不会触发回收站永久删除。保留的数据包括 `metadata.json`、`trash.json`、`retention.json`、`snapshots/` 目录,以及尚未迁移时可能存在的旧版 `pending-deletions.json`。之后重新安装仍可继续使用这些数据。准备彻底删除该目录前,请先恢复并备份需要的内容;只有确认其中的数据都不再需要时,才手动删除整个目录。
145
+ 卸载只移除插件包,不会删除 `$DSH_HOME/plugin-data/archived-chats/` 中的本地数据,也不会触发回收站永久删除。保留的数据包括 `metadata.json`、`trash.json`、`legacy-recycle.json`、`retention.json`、`snapshots/` 目录,以及尚未迁移时可能存在的旧版 `pending-deletions.json`。之后重新安装仍可继续使用这些数据。准备彻底删除该目录前,请先恢复并备份需要的内容;只有确认其中的数据都不再需要时,才手动删除整个目录。
146
146
 
147
147
  ## 许可证
148
148
 
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -10,7 +10,7 @@ The plugin has a Host service half and a browser client half:
10
10
 
11
11
  - The Host service in lib/index.js runs inside the DSH Web host, reads the workspace registry and session persistence, and exposes local HTTP routes.
12
12
  - The browser client in lib/client.js registers the Session Archive settings.section and renders state and actions.
13
- - Pure domain logic lives in lib/export.js, lib/import.js, lib/restore.js, lib/metadata.js, lib/search.js, lib/stats.js, lib/insights.js, lib/retention.js, lib/retention-service.js, lib/lineage.js, and lib/workspace-bulk-archive.js. lib/persistence-compat.js narrows the current Host's handle-based reads to a private read-only view; lib/history.js owns legacy-data inventory and preview authorization; lib/history-restore.js owns single-use restore-as-copy transactions. lib/trash.js owns the recycle catalog, lib/snapshot.js owns verified snapshots, and lib/recycle.js composes recycle lifecycle operations.
13
+ - Pure domain logic lives in lib/export.js, lib/import.js, lib/restore.js, lib/metadata.js, lib/search.js, lib/stats.js, lib/insights.js, lib/retention.js, lib/retention-service.js, lib/auto-retention.js, lib/lineage.js, and lib/workspace-bulk-archive.js. lib/persistence-compat.js narrows the current Host's handle-based reads to a private read-only view; lib/history.js owns legacy-snapshot inventory and preview authorization; lib/history-restore.js owns single-use restore-as-copy transactions; and lib/legacy-recycle.js projects old snapshots into the unified Recycle Bin and persists migration state. lib/trash.js owns the regular recycle catalog, lib/snapshot.js owns verified snapshots, and lib/recycle.js composes the ordinary recycle lifecycle.
14
14
 
15
15
  The browser never reads session files directly. All reads and writes go through Host routes.
16
16
 
@@ -26,6 +26,7 @@ GET /plugins/dsh-archived-chats/workspace-archive/workspaces
26
26
  POST /plugins/dsh-archived-chats/workspace-archive/preview
27
27
  POST /plugins/dsh-archived-chats/workspace-archive/apply
28
28
  POST /plugins/dsh-archived-chats/retention/policy
29
+ POST /plugins/dsh-archived-chats/retention/policy/preview
29
30
  POST /plugins/dsh-archived-chats/retention/preview
30
31
  POST /plugins/dsh-archived-chats/retention/apply
31
32
  GET /plugins/dsh-archived-chats/lineage
@@ -54,9 +55,9 @@ POST /plugins/dsh-archived-chats/delete
54
55
  POST /plugins/dsh-archived-chats/delete-all
55
56
  ~~~
56
57
 
57
- Every mutating route, plus preview, preview/image, search, history/preview, and history/preview/image, requires the `x-dsh-archived-chats: 1` header. `GET /history` returns only bounded safe inventory. Legacy-data images require both the snapshot identity and the complete projected descriptor to match.
58
+ Every mutating route, plus preview, preview/image, search, history/preview, and history/preview/image, requires the `x-dsh-archived-chats: 1` header. `GET /history` returns only bounded safe inventory. Compatibility snapshot images require both the snapshot identity and the complete projected descriptor to match. History routes remain a migration and read-compatibility layer; the browser no longer exposes a standalone History view.
58
59
 
59
- Workspace archive lists only safe workspace summaries. Preview accepts exactly one workspace ID and creates a five-minute, single-use token/nonce for at most 2,000 ordered eligible IDs. Apply accepts only that token and nonce, never caller-selected IDs. Eligibility requires unarchived membership in the existing workspace, no non-idle Host agent, and an inspected live or persisted event log containing `turn/start`; an empty new-session window is classified as `session-empty`, while an inspection failure is `session-unavailable`, and both fail closed. On Hosts without agent status, a loaded session is conservatively considered live. Candidate inspection is bounded to eight concurrent reads. Each item revalidates membership, archive state, agent status, and conversation content inside the shared lifecycle queue, then invokes the public `workspaceRegistry.archiveSession()` receiver-bound to the registry. New chats after preview are excluded; an item that became live, empty, unavailable, archived, or detached is reported and skipped. Successful archives do not capture snapshots. This feature changes neither workspace membership nor a workspace path or directory, and never moves a chat across workspaces. A Host without public `archiveSession` returns `workspace-archive-unsupported` without mutation.
60
+ Workspace archive lists only safe workspace summaries with at least one eligible chat. The browser may select one or more workspaces, but it still calls Preview separately for each workspace. Preview accepts exactly one workspace ID and creates a five-minute, single-use token/nonce for at most 2,000 ordered eligible IDs. The aggregate confirmation retains only nonempty previews; if every workspace became empty, the refreshed chooser returns without an empty-result confirmation. Apply accepts one workspace token and nonce at a time, never caller-selected IDs; the browser consumes those credentials in selection order and combines their safe results. Eligibility requires unarchived membership in the existing workspace, no non-idle Host agent, and an inspected live or persisted event log containing `turn/start`; an empty new-session window is classified as `session-empty`, while an inspection failure is `session-unavailable`, and both fail closed. On Hosts without agent status, a loaded session is conservatively considered live. Candidate inspection is bounded to eight concurrent reads. Each item revalidates membership, archive state, agent status, and conversation content inside the shared lifecycle queue, then invokes the public `workspaceRegistry.archiveSession()` receiver-bound to the registry. New chats after preview are excluded; an item that became live, empty, unavailable, archived, or detached is reported and skipped. Successful archives do not capture snapshots. This feature changes neither workspace membership nor a workspace path or directory, and never moves a chat across workspaces. A Host without public `archiveSession` returns `workspace-archive-unsupported` without mutation.
60
61
 
61
62
  ## State and local data
62
63
 
@@ -65,15 +66,16 @@ The state route joins archived sessions, workspace, tags, notes, and metadataUpd
65
66
  ~~~text
66
67
  $DSH_HOME/plugin-data/archived-chats/metadata.json
67
68
  $DSH_HOME/plugin-data/archived-chats/trash.json
69
+ $DSH_HOME/plugin-data/archived-chats/legacy-recycle.json
68
70
  $DSH_HOME/plugin-data/archived-chats/retention.json
69
71
  $DSH_HOME/plugin-data/archived-chats/snapshots/
70
72
  ~~~
71
73
 
72
- Metadata and recycle catalogs are versioned. Writes serialize and atomically replace their documents through temporary files. An unreadable or unsupported `trash.json` is preserved byte-for-byte, hides no archived sessions, and disables recycle mutations.
74
+ Metadata, recycle catalogs, and the legacy-snapshot migration catalog are versioned. Writes serialize and atomically replace their documents through temporary files. An unreadable or unsupported `trash.json` is preserved byte-for-byte, hides no archived sessions, and disables recycle mutations. An unreadable `legacy-recycle.json` blocks legacy-snapshot migration operations rather than guessing state.
73
75
 
74
76
  The stats route measures session directories with concurrency four, skips symbolic links, and caches results for 30 seconds. A measurement failure marks only that row unavailable; list and mutation actions continue. Delete invalidates the affected cache row.
75
77
 
76
- Insights joins session measurement with a stream-verified snapshot inventory and counts repeated snapshot attachments only from validated SHA-256 descriptors. The browser keeps totals in summary cards and presents session/snapshot inventories only in bounded searchable dialogs. retention.json retains a compatible version-one schema. Only Recycle Bin age contributes cleanup candidates; legacy snapshot-count, age, and quota fields do not schedule snapshot deletion. Saving never runs cleanup. Preview issues a five-minute single-use token/nonce and apply revalidates inside the lifecycle queue; recycle candidates still delegate to recycle purge. Lineage uses only durable parentSession edges, never rewrites headers, and resolves titles for at most 100 untitled active source nodes already included in the focused tree. Its 5,000-node cap bounds the PROJECTED graph, not the Host's store: `focusIds` narrows the output to archived and recycled chats plus their explaining context, so a store of 100,000 sessions with 25 archived projects 25 nodes. Header fields are coerced per node rather than validated whole-graph — an unanticipated `origin` value, an absent `createdAt`, a changed numeric type each degrade that node to a value the public LineageNode already allows, and only an unusable identity drops a row. A projection that rejected the whole graph for one unrecognized header let a Host-side change disable the panel with no plugin change at all; malformed workspace and recycle entries are skipped for the same reason.
78
+ Insights joins session measurement with a stream-verified snapshot inventory and counts repeated snapshot attachments only from validated SHA-256 descriptors. The browser keeps totals in summary cards and presents session/snapshot inventories only in bounded searchable dialogs. retention.json uses schema version 2 with an explicit recycleAutoDelete flag. Version-one documents remain readable, force that flag to false, and are not silently rewritten. Only Recycle Bin age contributes cleanup candidates; legacy snapshot-count, age, and quota fields do not schedule snapshot deletion. Policy preview issues a five-minute single-use token/nonce for enabling or shortening, bound to the current policy, proposed policy, and expired candidates. Policy save accepts { policy, confirmation: { token, nonce } } and revalidates under the lifecycle lock; the save request does not perform deletion itself. Automatic checks begin after startup recovery and repeat once a minute without overlap. Each candidate delegates to unified recycle purge, revalidating the setting and record inside its lifecycle lock before writing purge-pending intent. Plugin disposal stops new jobs; already-committed permanent deletions are retried. Legacy retention/preview and retention/apply manual APIs remain compatible, but the UI no longer has an extra manual cleanup-preview step. Lineage uses only durable parentSession edges, never rewrites headers, and resolves titles for at most 100 untitled active source nodes already included in the focused tree. Its 5,000-node cap bounds the PROJECTED graph, not the Host's store: `focusIds` narrows the output to archived and recycled chats plus their explaining context, so a store of 100,000 sessions with 25 archived projects 25 nodes. Header fields are coerced per node rather than validated whole-graph — an unanticipated `origin` value, an absent `createdAt`, a changed numeric type each degrade that node to a value the public LineageNode already allows, and only an unusable identity drops a row. A projection that rejected the whole graph for one unrecognized header let a Host-side change disable the panel with no plugin change at all; malformed workspace and recycle entries are skipped for the same reason.
77
79
 
78
80
  ## Preview and full-text search
79
81
 
@@ -83,15 +85,15 @@ The preview/image authorization sequence is fixed: first require POST and `x-dsh
83
85
 
84
86
  Cross-session persistence inspection is limited to four concurrent reads, stops scheduling batches once the hit limit is satisfied, and aborts an older browser request when a newer search starts. A broken session is reported in `skipped` while other hits still succeed. Canonical projection limits each segment to 256 Ki code points, each message to 1 Mi code points and 1,000 segments, and each session to 10,000 projected messages; unknown structured values are bounded by depth, node, and character budgets before stringify. A 30-second TTL, 64-session LRU, and per-session cache cap keep bounded projections resident. Unarchive, delete, and restore invalidate affected cache entries.
85
87
 
86
- ## Legacy-data compatibility and recovery
88
+ ## Legacy-snapshot compatibility and unified recycling
87
89
 
88
- Archiving no longer calls `history/capture`; that compatibility route refuses new History captures. Upgrades preserve existing snapshots. Existing inventory, preview, restore, and delete routes serve **Storage & Retention Legacy data**. Recycle Bin operations still capture protection snapshots required for recovery.
90
+ Archiving no longer calls `history/capture`; that compatibility route refuses new History captures. Upgrades preserve existing snapshots. `legacy-recycle.js` projects snapshots not referenced by regular recycle records as `legacy:<snapshotId>` Recycle Bin items, so the browser displays them in the unified Recycle Bin. Existing History inventory, preview, restore, and delete routes remain for migration and compatible callers. Recycle Bin operations still capture protection snapshots required for recovery.
89
91
 
90
92
  `history.js` groups published snapshots as `archived`, `recycled`, or `history-only`, inspects no more than 5,000 snapshot directories, shares one in-flight request, and caches completed inventory for 30 seconds. Inventory contains only safe title/workspace title, timestamps, sizes, attachment counts, and protection state; degraded entries expose only snapshot ID and a stable code. Paginated preview and image reads revalidate snapshot identity, digests, and complete descriptors without returning paths or raw records.
91
93
 
92
- `history-restore.js` fully validates the snapshot, asks the Host for a new session ID, and issues a five-minute single-use token/nonce. Confirmation consumes the credential before writes and rechecks the manifest, then creates persistence, rewrites session/attachment identities, appends events, restores workspace and metadata, and commits archive registry state last. Failures reverse plugin-controlled steps. The source session and snapshot never change, and the plugin makes no claim that Host-global attachment objects were deleted.
94
+ `history-restore.js` fully validates the snapshot, asks the Host for a new session ID, and issues a five-minute single-use token/nonce. Confirmation consumes the credential before writes and rechecks the manifest, then creates persistence, rewrites session/attachment identities, appends events, restores workspace and metadata, and commits archive registry state last. After commit, unified recycling marks the migration state `restore-complete`, then removes the restored snapshot and migration entry; a cleanup failure retains cleanup state without undoing the successfully created archived copy. Failures before commit reverse plugin-controlled steps. The source session and snapshot do not change before commit, and the plugin makes no claim that Host-global attachment objects were deleted.
93
95
 
94
- Legacy-data item deletion and clear-all both enter the shared lifecycle queue and bypass the ordinary 30-second cache/in-flight list so current snapshot and recycle-protection state is recomputed. Both reject a snapshot a recycle record still names, degraded or not that record is its last claim. Both otherwise accept a degraded snapshot: it can no longer be previewed or restored from, but its bytes are still on disk and no other surface can reclaim them (retention now plans only Recycle Bin purges), so refusing here would leak the store permanently. Deletion physically removes the plugin snapshot and its attachment copies, while the original chat and other versions remain unchanged.
96
+ Legacy-snapshot permanent deletion and Empty Recycle Bin both enter the shared lifecycle queue and bypass the ordinary 30-second cache/in-flight list so current snapshot and regular recycle-protection state is recomputed. A snapshot referenced by a regular recycle record is not also projected as a legacy item. A degraded snapshot cannot be previewed or restored, but it can be permanently deleted through the unified Recycle Bin so its bytes remain reclaimable. Deletion physically removes the plugin snapshot and its attachment copies while leaving the source chat and other snapshots unchanged.
95
97
 
96
98
  ## Export flow
97
99
 
@@ -118,19 +120,19 @@ import/inspect accepts only version-one ZIPs produced by this plugin. The Host s
118
120
  5. restore.js uses a feature-detected adapter to write sessions, metadata, and archive state.
119
121
  6. Any failure rolls back staged data and never overwrites an existing session.
120
122
 
121
- The confirmation token expires quickly, can be used once, and is bounded to eight retained plans and 128 MiB total per process. Confirmation-time conflict revalidation, staging, and commit all run inside the shared lifecycle queue. Import resolves a session writer by capability: a dedicated Host restore entry point when one exists, otherwise the ordinary `create` / `append` / `locate` surface — the same capability legacy-data recovery writes through, so import works wherever that works. The append writer carries its own session-scoped rollback (it confirms the located directory is the session's own before creating anything), so a separate removal capability is required only for a dedicated restore entry point. Archive and metadata write capabilities are still required. The staged id does not exist yet, so a session reader that fails closed on unknown ids is the expected answer to the capability probe and never aborts the restore. Workspace attach is used only with a matching detach, otherwise the item restores ungrouped with a warning. A boundary that throws after changing state is compensated in reverse order; failed compensation is reported explicitly rather than returning false success.
123
+ The confirmation token expires quickly, can be used once, and is bounded to eight retained plans and 128 MiB total per process. Confirmation-time conflict revalidation, staging, and commit all run inside the shared lifecycle queue. Import resolves a session writer by capability: a dedicated Host restore entry point when one exists, otherwise the ordinary `create` / `append` / `locate` surface — the same capability legacy-snapshot recovery writes through, so import works wherever that works. The append writer carries its own session-scoped rollback (it confirms the located directory is the session's own before creating anything), so a separate removal capability is required only for a dedicated restore entry point. Archive and metadata write capabilities are still required. The staged id does not exist yet, so a session reader that fails closed on unknown ids is the expected answer to the capability probe and never aborts the restore. Workspace attach is used only with a matching detach, otherwise the item restores ungrouped with a warning. A boundary that throws after changing state is compensated in reverse order; failed compensation is reported explicitly rather than returning false success.
122
124
 
123
125
  ## Recycle and protection-snapshot lifecycle
124
126
 
125
127
  `trash.json` permits only `trashed`, `purge-pending`, and `degraded`. Legal transitions are `missing -> trashed`, `trashed/degraded -> purge-pending`, and removal of an existing state after a committed transaction. A `purge-pending` record cannot restore.
126
128
 
127
- Protection manifests use `dsh-archived-chats/snapshot` v1 and session payloads use `dsh-archived-chats/snapshot-session` v1. Each recycle record names one active snapshot; retained snapshots from restore/recycle cycles remain available under Legacy data until explicit deletion or permanent purge. Exact limits are 4 MiB manifest, 64 MiB session JSON, 1,000 attachments, 32 MiB each, and 512 MiB total. Restore validation streams attachment digests first and rereads one attachment at a time immediately before Host writes, never retaining all attachment bytes together. Snapshot publication/deletion and state-file renames sync file and parent-directory durability, with a safe fallback on Windows filesystems that do not expose directory fsync. Windows cannot atomically replace a file or remove a directory entry while another handle is open on it — an indexer or antivirus scan is enough — so replaces and recursive removals retry the transient `EPERM` / `EACCES` / `EBUSY` codes there, bounded, and only there: on POSIX the same codes are permanent conditions and retrying would only delay the same failure. Snapshot publication also treats a rename refused onto an existing directory as a conflict after probing the destination, because Windows reports that as `EPERM` rather than `EEXIST`. Path containment is tested with the platform separator and rejects an absolute answer, so a Windows `..\` escape or a different drive letter cannot read as inside the root.
129
+ Protection manifests use `dsh-archived-chats/snapshot` v1 and session payloads use `dsh-archived-chats/snapshot-session` v1. Each regular recycle record names one active snapshot. A valid snapshot left without a regular recycle reference after restore or another recycle cycle automatically appears as a legacy-snapshot item in the unified Recycle Bin until it is restored as a copy or permanently deleted. Exact limits are 4 MiB manifest, 64 MiB session JSON, 1,000 attachments, 32 MiB each, and 512 MiB total. Restore validation streams attachment digests first and rereads one attachment at a time immediately before Host writes, never retaining all attachment bytes together. Snapshot publication/deletion and state-file renames sync file and parent-directory durability, with a safe fallback on Windows filesystems that do not expose directory fsync. Windows cannot atomically replace a file or remove a directory entry while another handle is open on it — an indexer or antivirus scan is enough — so replaces and recursive removals retry the transient `EPERM` / `EACCES` / `EBUSY` codes there, bounded, and only there: on POSIX the same codes are permanent conditions and retrying would only delay the same failure. Snapshot publication also treats a rename refused onto an existing directory as a conflict after probing the destination, because Windows reports that as `EPERM` rather than `EEXIST`. Path containment is tested with the platform separator and rejects an absolute answer, so a Windows `..\` escape or a different drive letter cannot read as inside the root.
128
130
 
129
131
  Move ordering is: validate archive ownership → dispose or park a live session → capture and verify snapshot → recheck ownership → atomically commit `trashed` → invalidate caches. Ordinary move never removes the persistence artifact.
130
132
 
131
133
  Archived sessions also expose an explicit direct permanent-delete action. It uses the same session-scoped physical-delete checks and crash-recovery bracket as Recycle Bin purge, but intentionally skips snapshot creation and recycle storage after a separate irreversible confirmation. Ordinary delete remains recoverable by default.
132
134
 
133
- Restore first rejects an existing-ID conflict. With an intact original it restores archive visibility and removes only the recycle record, without rewriting persistence; the snapshot remains available under Legacy data. With a missing original it completes validation and attachment-identity republishing before writing through public `create` / `append` / `saveImage` capabilities. A failure rolls back the new artifact and retains trash.
135
+ Restore first rejects an existing-ID conflict. With an intact original it restores archive visibility and removes only the regular recycle record without rewriting persistence; the protection snapshot then appears as a legacy-snapshot item in the unified Recycle Bin. With a missing original it completes validation and attachment-identity republishing before writing through public `create` / `append` / `saveImage` capabilities. A failure rolls back the new artifact and retains trash.
134
136
 
135
137
  Permanent purge persists `purge-pending` before physical writes, then removes every snapshot for that source, then the original session, and finally the recycle record. The session delete is deliberately last: a failure before it leaves the original intact and the record completable, rather than a `purge-pending` record whose session is already gone and which can therefore neither restore nor complete. The snapshot sweep attributes each published snapshot by manifest identity so a snapshot that fails validation is still removed when it belongs to this session, and an unrelated unverifiable snapshot is skipped instead of aborting the sweep — corruption elsewhere in the store must never make a purge impossible. The recycle record also names its own snapshot id, covering one damaged past attribution. Workspace, metadata, snapshot, or physical-delete failures retain `purge-pending`; snapshot deletion is rescanned before success can be returned. Physical deletion additionally requires the located artifact to sit in a directory named for the session itself, so a backend layout that shares one parent between sessions can never have that parent removed. Startup recovery retries only `purge-pending`, never plain `trashed`. Legacy `pending-deletions.json` is strict read-only migration input: each still-archived ID becomes recoverable trash and is never boot-deleted merely because of the old marker.
136
138
 
@@ -139,12 +141,13 @@ Permanent purge persists `purge-pending` before physical writes, then removes ev
139
141
  client.js registers an order-30 `settings.section` plus a `shell.overlay`, and uses public Host archive services and design tokens. Workspace archive UI state stays inside the plugin-owned settings section and requires no workspace-action slot or shared client store. The page state includes:
140
142
 
141
143
  - A frame-wide archive success notice in `shell.overlay`: during its effect lifetime the plugin wraps public `workspaces.archiveSession` and reports success only after the original succeeds. View and Undo remain available, with a three-second dismissal. No history capture is requested.
142
- - An **Archive workspace chats** action in **Settings → Session Archive**: it opens a workspace chooser, then prepares the selected workspace and shows one confirmation with the exact eligible count, Archived destination, and only a nonzero live-skip count, with no visible session preview. Full success refreshes consumers and closes; any skipped or failed outcome retains the per-item result until dismissed.
144
+ - An **Archive workspace chats** action in **Settings → Session Archive**: the chooser lists only workspaces with eligible chats and supports single selection, multiple selection, and Select all that toggles off on a second click. The bottom-right Confirm button is the only continuation. The client prepares each selection, drops workspaces that concurrently became empty, and shows one aggregate confirmation with the exact total eligible count, Archived destination, and only a nonzero live-skip count, with no visible session preview. Full success refreshes consumers and closes; any skipped or failed outcome retains the per-item result until dismissed.
143
145
  - Archived sessions and workspace groups.
144
146
  - Search, type/project/tag filters, and sorting.
145
147
  - Tag and note editor.
146
- - Selected-item export, unarchive, and move to Recycle Bin.
147
- - Four tabs: Archived, Recycle Bin, Storage & Retention, and Origins & Branches. Storage exposes Legacy data on demand for prior snapshot preview, recovery as a new archived copy, and confirmed deletion. Restore confirmation focuses Cancel first and never places token/nonce in the render tree. Storage and relationship views retain bounded dialogs and read-only relationship projection.
148
+ - Row actions handle one chat in this order: preview, edit tags and note, permanent delete, and Unarchive; there is no single-chat export. Archive workspace menus provide Export all, Unarchive all, Delete all permanently, and Move all to Recycle Bin in that order. Recycle Bin workspace menus provide Restore all and Delete all permanently. Neither view has multi-select state, row checkboxes, or a batch toolbar.
149
+ - Archived and Recycle Bin title rows provide cross-workspace Delete all and Empty Recycle Bin actions respectively; the latter covers every recycled chat and protection snapshot. Recycle Bin row restore and permanent delete are named, tooltip-backed icon buttons.
150
+ - Four tabs: Archived, Recycle Bin, Storage & Retention, and Origins & Branches. Existing snapshots expose preview, recovery as a new archived copy, and confirmed deletion in the Recycle Bin. Restore confirmation focuses Cancel first and never places token/nonce in the render tree. Storage and relationship views retain bounded dialogs and read-only relationship projection.
148
151
  - Import preview, disabled conflicts, and restore results.
149
152
  - Responsive settings-page markers and sidebar refresh injection.
150
153
 
@@ -159,7 +162,7 @@ The browser never mutates files directly. After an operation, the Host response
159
162
  ## Security and failure policy
160
163
 
161
164
  - All state-changing routes require POST and the guard header.
162
- - Legacy-data responses exclude workspace/snapshot/attachment paths, raw events, notes, and confirmation tokens; logs contain only IDs and stable codes.
165
+ - Compatibility History responses and legacy-snapshot Recycle Bin items exclude workspace/snapshot/attachment paths, raw events, notes, and confirmation tokens; logs contain only IDs and stable codes.
163
166
  - Workspace archive responses expose only safe workspace IDs/titles, eligible counts, session IDs/titles/timestamps in a confirmed preview, and stable per-item outcomes; workspace paths, event bodies, notes, attachment paths, and confirmation credentials stay out of logs and rendered results.
164
167
  - Import limits ZIP size, entries, paths, versions, and JSON structure, rejecting traversal, duplicates, and prototype-pollution keys.
165
168
  - Ordinary delete never invokes physical purge; only a committed recycle record can enter purge.
@@ -173,7 +176,7 @@ The plugin adapts through Host capability detection: archive reads, attachment r
173
176
 
174
177
  Snapshot and ZIP schema v1 cannot preserve `inheritedEventCount`. When a current read handle reports an inherited prefix greater than zero, the adapter returns `session-inspection-unsupported` before reading events and still closes the handle, avoiding a silently flattened branch history. Workspace archive no longer depends on snapshot capture. Recycle protection and ZIP export continue to reject unsupported inherited event data. This UI change does not widen the snapshot or restore protocol.
175
178
 
176
- On Hosts with the compatible legacy writer surface, Import, legacy-data recovery, and snapshot fallback when the original is missing still write through the public `create` / `append` / `locate` capability, or a dedicated restore entry point where the Host offers one; only a Host exposing neither returns `restore-unsupported` without mutation. A capability set that no shipped Host satisfies is not an acceptable guard — it makes the feature permanently dead rather than gracefully degraded. Back up the complete plugin-data directory before downgrading to a release that does not display legacy data or understand recycle snapshots.
179
+ On Hosts with the compatible legacy writer surface, Import, legacy-snapshot recovery, and snapshot fallback when the original is missing still write through the public `create` / `append` / `locate` capability, or a dedicated restore entry point where the Host offers one; only a Host exposing neither returns `restore-unsupported` without mutation. A capability set that no shipped Host satisfies is not an acceptable guard — it makes the feature permanently dead rather than gracefully degraded. Back up the complete plugin-data directory before downgrading to a release that does not understand the unified Recycle Bin or newer snapshot state.
177
180
 
178
181
  Coverage includes:
179
182
 
@@ -184,8 +187,8 @@ Coverage includes:
184
187
  - stats.js symlink handling, caching, and concurrency limits.
185
188
  - search.js message projection, Unicode search, pagination, partial failures, and TTL/LRU caching.
186
189
  - trash.js, snapshot.js, and recycle.js format validation, concurrency, recovery, rollback, crash intent, and legacy migration.
187
- - insights.js, retention.js, retention-service.js, and lineage.js trusted accounting, policy bounds, short-lived authority, revalidation, and bounded graph projection.
188
- - history.js and history-restore.js legacy-data preservation, cache invalidation, snapshot authorization, single-use confirmation, transaction rollback, and source immutability.
190
+ - insights.js, retention.js, retention-service.js, auto-retention.js, and lineage.js trusted accounting, policy bounds, short-lived authority, revalidation, scheduler lifecycle, and bounded graph projection.
191
+ - history.js, history-restore.js, and legacy-recycle.js legacy-snapshot preservation, unified recycle projection, cache invalidation, snapshot authorization, single-use confirmation, transaction rollback, and source immutability.
189
192
  - Host routes and browser settings smoke/responsive behavior.
190
193
 
191
194
  Run: