docs(backup): clarify manifest and step-0 version gate readability

- split manifest fields into definition + version-field role table
- explain release migration regen rationale for backupFormatVersion bump
- restructure §9 step 0 with nested list (format check / schema compare
  three states / failure handling / cross-branch)
- add user-facing error for migrate-forward failure, matching other
  gate-failure branches

Signed-off-by: George·Dong <GeorgeDong32@qq.com>
This commit is contained in:
George·Dong
2026-06-19 17:07:14 +08:00
parent d24ae5adaf
commit ef1ae2cbca

View File

@@ -81,7 +81,22 @@ flowchart LR
B --> C1
```
**manifest**(备份与恢复唯一交接物的元数据,归档内与 `backup.sqlite`/`files`/`knowledge` 同级)`backupFormatVersion`归档格式版本v2 起 = 1major bump = 不兼容;**release 前重生成单条 clean initial migration 时须 major bump**,使旧格式备份被拒而非走 migrate-forward`schemaMigrationId`producer 已应用的最末 migration 的 `when`(folderMillis)drizzle migrate 按 folderMillis 决定增量、**非** tag 词典序,故版本比对以 folderMillis 为权威tag 如 `0005_lyrical_galactus` 仅诊断)、`producerAppVersion`producer app 版本,源自 `package.json`,仅诊断/错误提示)、`domains`(域范围:完整/精简)、`resources`(文件/知识库资源清单)。`backupFormatVersion` + `schemaMigrationId` 供恢复第一步兼容门禁§9 step 0
**manifest**(备份与恢复唯一交接物的元数据,归档内与 `backup.sqlite`/`files`/`knowledge` 同级)。五字段分两类:
- **内容范围**`domains`(域:完整/精简)、`resources`(文件/知识库清单)
- **版本兼容**`backupFormatVersion``schemaMigrationId``producerAppVersion`
三个版本字段角色不同仅前两个进兼容门禁§9 step 0
| 字段 | 管什么 | 进门禁 |
|---|---|---|
| `backupFormatVersion` | 归档**格式**v2 起 = 1major bump = 不兼容 → 拒) | ✅ |
| `schemaMigrationId` | DB **schema** 版本指纹 | ✅ |
| `producerAppVersion` | **app** 版本(`package.json` | ❌ 仅诊断/错误提示 |
- `schemaMigrationId` 取 producer 最末 migration 的 `when`(folderMillis)——drizzle migrate 按 folderMillis 决定增量、**非** tag 词典序,故比对以 folderMillis 为权威tag`0005_lyrical_galactus`)仅诊断。
- **release 转换点须 `backupFormatVersion` major bump**CLAUDE.md 规定 release 前 `migrations/sqlite-drizzle/` 会清空并重生成成一条全新 clean initial migration开发期 migration 是 throwaway。此举换掉整条 chain、打断 migrate-forward 依赖的连续性——旧备份的 `schemaMigrationId` 指向已被替换的旧 chainmigrate-forward 会拿新 clean initial 的 `CREATE TABLE` 去撞 backup.sqlite 里已建好的表(`table already exists`)。故在该 release 版本点 major bump formatVersion让旧格式备份在门禁直接被拒而非走到必失败的 migrate-forward。
- `producerAppVersion` 不进门禁:`schemaMigrationId` 偏序已蕴含 app 版本偏序,它仅用于用户可见的错误提示。
每个域由一个 `BackupContributor` 表示:
@@ -334,7 +349,15 @@ flowchart TB
当前文件级回滚只覆盖 FILE_STORAGE 覆盖写入,不覆盖 DB 行导入中途失败,也不覆盖 API key / 偏好 / provider / assistant / agent / 聊天记录等 SQLite 数据。补恢复编排层 RestoreRecoveryPoint整库 DB pre-snapshot + restore journal + 受影响文件快照(同 restoreId。**执行分层严格分离**(符合 V2 withWriteTx「fn 内仅 DB ops、不做文件 IO」约束
0. **manifest 版本门禁**(恢复第一步,先于 RESTORE BARRIER只读/操作备份文件、不碰 live DB读 manifest先校验 `backupFormatVersion`major bump = 不兼容 → 拒绝 + 明确错误);再比对 producer/consumer 的 migration chain 位置——以 `schemaMigrationId``when`(folderMillis) 为权威序(**非 tag 词典序**drizzle migrate 按 folderMillis 决定增量):**consumer chain 前缀包含 producer 末端(老备份)→ migrate-forward**,对 `backup.sqlite` 在**独立 libsql client**(非 live `DbService.client`,避免污染 live 连接)跑 drizzle `migrate` 到 consumer 末条——因 VACUUM INTO 连带复制了 producer 的 `__drizzle_migrations`migrator 自动只应用 producer 之后的增量;**producer 末端不在 consumer chain 上(新备份 / 跨分支分叉)→ 拒绝**并提示升级 app等同 → 直接导入。migrate-forward 失败 = 门禁失败:中止恢复、保留 live DB 原状(未触碰)、删临时 `backup.sqlite`**不触发 step 4 整库回滚**。migrate-forward 跑 release migration chain`migrations/sqlite-drizzle` 正式产物),不碰开发期 drift跨分支表集差异`agent_task` vs `painting`/`agent_workspace`,§四)由 chain 位置识别并经 migrate-forward 消解。
0. **manifest 版本门禁**(恢复第一步,先于 RESTORE BARRIER只读/操作备份文件、**不碰 live DB**
- **格式校验**`backupFormatVersion` major bump = 不兼容 → 拒绝 + 明确错误
- **schema 比对**(以 `schemaMigrationId``when`(folderMillis) 为权威序,**非 tag 词典序**——drizzle migrate 按 folderMillis 决定增量),三种状态:
- **老备份**consumer chain 前缀含 producer 末端)→ **migrate-forward**:对 `backup.sqlite` 在**独立 libsql client**(非 live `DbService.client`,避免污染 live 连接)跑 drizzle `migrate` 到 consumer 末条——因 VACUUM INTO 连带复制了 producer 的 `__drizzle_migrations`migrator 自动只应用 producer 之后的增量
- **新备份 / 跨分支分叉**producer 末端不在 consumer chain 上)→ **拒绝**,提示升级 app
- **等同** → 直接导入
- **失败善后**migrate-forward 失败(备份损坏 / migration SQL 执行失败)= 门禁失败,中止恢复、保留 live DB 原状(未触碰)、删临时 `backup.sqlite`**不触发 step 4 整库回滚**(因 live DB 未变),并向用户报错「备份无法恢复:文件损坏或版本不受支持」
- migrate-forward 跑 release migration chain`migrations/sqlite-drizzle` 正式产物),不碰开发期 drift跨分支表集差异`agent_task` vs `painting`/`agent_workspace`,§四)由 chain 位置识别并经 migrate-forward 消解
1. **RESTORE BARRIER** acquire静默 WhenReady DB writers + 阻塞 renderer mutation全程后用 VACUUM INTO 建快照(须事务外,持 withExclusiveAccess 写锁)
2. contributor restoreResources 文件 IO 在 withWriteTx 之外、之前
3. 仅 DB 行导入在 withWriteTx 内