2026-09-24 07:51:03 +08:00
|
|
|
|
# workbuddy.db 损坏 — 诊断结论与修复方案
|
|
|
|
|
|
|
|
|
|
|
|
> 诊断时间:**2026-09-23 18:2x–18:4x** | 诊断人:会话 `IM线-第11棒`(纯只读诊断,⛔ 未改动任何原文件)
|
|
|
|
|
|
> 库路径:`E:\ProgramData\.workbuddy\workbuddy.db`(活动库,由 `CODEBUDDY_CONFIG_DIR=E:\ProgramData\.workbuddy` 确认)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 一、结论(一句话)
|
|
|
|
|
|
|
|
|
|
|
|
**主库数据不可恢复** —— `sqlite_master` 的 schema 根页(page 1)已被清零破坏,且 96.7% 的页是零页。**推荐路径 = 让 app 重建库**(automation 配置会丢,需重建)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 二、实测证据(全部为只读取证)
|
|
|
|
|
|
|
|
|
|
|
|
| # | 判据 | 实测值 | 含义 |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| 1 | 头部 magic(off 0-15) | `0d000000070081070ea30d5908fd0a530639035f00810000` 等乱码 | **非 `SQLite format 3`** |
|
|
|
|
|
|
| 2 | `page_size`(off 16-17) | `0x0639` = 1593 | **非法值**(合法须 2^n,且 ≥512) |
|
|
|
|
|
|
| 3 | 头部 off 24-99 | **全零** | 头部被覆写(前 24B 垃圾 + 后 76B 零) |
|
|
|
|
|
|
| 4 | 🔴 **page 1 的 b-tree 页头(off 100-107)** | **全零** | ⛔ **`sqlite_master` 根页被毁 ⇒ schema 字典丢失** |
|
|
|
|
|
|
| 5 | 全库页健康度(8637 页) | **8355 页(96.7%)首字节 0x00**;仅 282 页(3.3%)是合法 b-tree 页 | 绝大部分页被清零 |
|
|
|
|
|
|
| 6 | WAL 头 | magic `0x377F0682` ✅、`page_size=0x1000`(4096) ✅、完整 1055 帧 | **WAL 本身完好** |
|
|
|
|
|
|
| 7 | WAL 覆盖范围 | 仅 **62 个不同页**(页号 15..8125),最后 commit 声明 DB = **7504 页** | WAL 只含 0.8% 的页 |
|
|
|
|
|
|
| 8 | WAL 是否有 page 1 | ⛔ **无** | 无法从 WAL 还原头部 |
|
|
|
|
|
|
| 9 | 头部重建实测 | 在**副本**上重建 100 字节合法头(page_size=4096 / db_pages=7504 / ver=2-2 / UTF-8)后打开 ⇒ **仍 `database disk image is malformed`** | ⛔ **方案「只重建头部」已证伪**(因判据 4) |
|
|
|
|
|
|
| 10 | 现成备份 | 顶层**仅三件套,无 `.bak`**;`.backup-20260916\` 里只有 `MEMORY.md`(非 db);`automation-backups\` 仅 2 个 **08-30** 的 JSON | ⛔ **无 db 级可用备份** |
|
|
|
|
|
|
| 11 | `sqlite3` CLI | **未安装** | `.recover` 不可直接用 |
|
|
|
|
|
|
| 12 | 独立数据面(不依赖 db) | `sessions\` **314 个 JSON**(至 09-20)|`tasks\` **38 个目录**(至 09-23 06:08) | ✅ 这部分数据在文件里,可保留 |
|
|
|
|
|
|
|
|
|
|
|
|
**损坏形态判读**:`96.7% 零页 + page 1 全零 + 头部前 24B 垃圾` ⇒ 与项目记忆里那条血教训的现场一致 —— **文件被"部分覆写"**(只有一个大部分为空/零的文件替换了它的一部分)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 三、🔴 当前影响(比库本身更要紧)
|
|
|
|
|
|
|
|
|
|
|
|
1. **所有 automation 停摆** —— 建报 `database disk image is malformed`、查报 `file is not a database`。⇒ **各线的自动化接力全部断层**(不止 IM 线)。
|
|
|
|
|
|
2. **IM 线第 11 棒的接续棒无法登记** ⇒ 已改为**手工接力**(入口 §2 已自包含)。
|
|
|
|
|
|
3. `workbuddy.db` 内的会话历史 / 任务记录不可读(但 `sessions\`、`tasks\` 的文件形态部分仍在)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 四、修复方案(三案,各带优缺点)
|
|
|
|
|
|
|
|
|
|
|
|
### 案 A · 让 app 重建库(**推荐**)
|
|
|
|
|
|
|
|
|
|
|
|
**做法**:停 app → 把坏的三件套**改名**(不删)→ 重启 app。app 依据 `.workbuddy-sqlite-migrations\0000_workbuddy_sqlite_baseline.sql` 自动建全新 schema。
|
|
|
|
|
|
建议**先只重启 app 试一次**(不删任何文件)—— 成本最低,若 app 能自愈则无需后续动作。
|
|
|
|
|
|
|
|
|
|
|
|
- **优点**:功能立即恢复(app 有 migrations baseline ⇒ schema 自动重建);坏库改名保留 ⇒ **可回退**;不依赖任何外部工具(本机无 `sqlite3` CLI)。
|
|
|
|
|
|
- **缺点**:**automation 配置全丢,需逐条重建**(各线的接续棒都要重排);db 内的会话/任务记录丢失(`sessions\`、`tasks\` 的文件形态部分可保留)。
|
|
|
|
|
|
|
|
|
|
|
|
### 案 B · 数据挖掘(从 WAL + 282 个完好页里捞)
|
|
|
|
|
|
|
|
|
|
|
|
- **优点**:理论上能救回最近的部分写入(WAL 62 页)。
|
|
|
|
|
|
- **缺点**:🔴 **page 1 已毁 ⇒ 没有 schema,无法知道这些页属于哪张表**;WAL 仅覆盖 62 页(0.8%);需逐页人工分析、成功率低、耗时长。
|
|
|
|
|
|
|
|
|
|
|
|
### 案 C · 找更早的 db 备份
|
|
|
|
|
|
|
|
|
|
|
|
- **优点**:若有,可恢复较完整数据。
|
|
|
|
|
|
- **缺点**:⛔ **实测已排除** —— 顶层无 `.bak`,`.backup-20260916\` 只含 `MEMORY.md`,`automation-backups\` 只有 2 个 08-30 的 JSON;VSS 卷影未查到可用快照。
|
|
|
|
|
|
|
|
|
|
|
|
**⇒ 推荐案 A**(案 C 已实测排除;案 B 性价比过低)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 五、案 A 的执行步骤(⚠️ 必须由用户执行 —— 我会被停掉)
|
|
|
|
|
|
|
|
|
|
|
|
> 🔴 **红线门禁**:以下动作需**停 app**,会中断当前会话及所有在跑的会话 ⇒ 由用户决定时机并执行。
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
|
# 0. 先确认无 WorkBuddy 进程在写(任务管理器,或)
|
|
|
|
|
|
Get-Process WorkBuddy -ErrorAction SilentlyContinue
|
|
|
|
|
|
|
|
|
|
|
|
# 1. 停掉 WorkBuddy(关闭应用)
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 应急副本(已在 2026-09-23 18:36 生成一份,可再确认)
|
2026-09-24 08:25:34 +08:00
|
|
|
|
# E:\ProgramData\AIProject\aliyun-dsh-server\tmp\dbrescue-20260923\
|
2026-09-24 07:51:03 +08:00
|
|
|
|
# (workbuddy.db / -wal / -shm 三件套,35,377,152 + 4,346,632 + 32,768 字节)
|
|
|
|
|
|
|
|
|
|
|
|
# 3. 把坏的三件套改名(⛔ 不删,留回退路)
|
|
|
|
|
|
cd E:\ProgramData\.workbuddy
|
|
|
|
|
|
Rename-Item workbuddy.db workbuddy.db.broken-20260923
|
|
|
|
|
|
Rename-Item workbuddy.db-wal workbuddy.db-wal.broken-20260923
|
|
|
|
|
|
Rename-Item workbuddy.db-shm workbuddy.db-shm.broken-20260923
|
|
|
|
|
|
|
|
|
|
|
|
# 4. 顺手保一份独立数据面(文件形态,防 app 重建时一并重置)
|
2026-09-24 08:25:34 +08:00
|
|
|
|
Copy-Item -Recurse E:\ProgramData\.workbuddy\sessions E:\ProgramData\AIProject\aliyun-dsh-server\tmp\dbrescue-20260923\sessions
|
|
|
|
|
|
Copy-Item -Recurse E:\ProgramData\.workbuddy\tasks E:\ProgramData\AIProject\aliyun-dsh-server\tmp\dbrescue-20260923\tasks
|
2026-09-24 07:51:03 +08:00
|
|
|
|
|
|
|
|
|
|
# 5. 重启 WorkBuddy ⇒ app 依据 .workbuddy-sqlite-migrations 自动建新库
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**成功判据**:app 内 automation 功能恢复(能列出、能新建)⇒ 库已重建成功。
|
|
|
|
|
|
**回退**:把 `*.broken-20260923` 三个文件改回原名即可。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 六、重建后必做
|
|
|
|
|
|
|
|
|
|
|
|
1. **补登各线接续棒** —— automation 配置已丢,`覆盖网络线` / `插件投放与分库线` / `技能重组线` / `IM 线` 等需按各自入口的 §2 重新登记。
|
|
|
|
|
|
2. **IM 线**:第 11 棒(动工连接层 B 案)的完整动工范围在 `接续入口_IM线_20260922.md` **§2「第 11 棒」** 段(自包含),可直接据此重登 automation。
|
|
|
|
|
|
3. 核对 `sessions\` / `tasks\` 文件形态数据是否被 app 重建时重置(若重置 ⇒ 从本次副本回灌)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 七、本次已执行的只读动作(⛔ 未改动任何原文件)
|
|
|
|
|
|
|
|
|
|
|
|
- 诊断脚本:`tmp\db_diag.py`、`tmp\db_deep.py`、`tmp\db_pagescan.py`、`tmp\db_wal.py`、`tmp\db_rescue.py`
|
|
|
|
|
|
- dry-run 修复脚本(只在副本上跑):`tmp\db_repair.py`
|
|
|
|
|
|
- **应急副本**:`tmp\dbrescue-20260923\`(三件套 + `trial\` 试验副本)
|
|
|
|
|
|
- 项目记忆回写:`MEMORY.md` 血教训条已补两条判据(① 判活动库看 `CODEBUDDY_CONFIG_DIR` ② `immutable=1` 读不出 ≠ 仅 WAL 错位)
|