Cell Boot 韧性
wesgine Cell Boot 的降级启动与数据恢复机制。
核心不变量
INV-RESIL-01:Boot 永远成功
无论何种数据损坏,Boot 都返回 nil error。
降级是合法状态——唯一的 boot 失败是 ErrCellLocked(进程竞争,非数据问题)。
INV-RESIL-02:Run 永远可用
Runtime().Run() 永远可用。降级只影响历史数据访问,不影响新请求处理。
三层数据库
Cell 使用三层 SQLite 数据库,单层损坏不扩散(INV-RESIL-03):
| 层 | 文件 | 存储内容 | 损坏影响 |
|---|---|---|---|
| Meta | meta.db | Cell 元数据 | 元信息丢失 |
| State | state.db | 运行时状态、Traces | 历史追踪丢失 |
| Sessions | sessions.db | 会话与记忆 | 对话历史丢失 |
sessions.db 损坏不影响 memory/observe;state.db 损坏不影响 sessions。
进程排他锁
INV-RESIL-04:同一 Cell 同一时刻只有一个写入者。
- 使用
flock(.cell.lock)文件锁 - 保证单进程独占 Cell 目录
- 进程内互斥量足够(INV-QUOTA-05)
快照验证
INV-RESIL-05:每次快照后立即 PRAGMA quick_check。
- 损坏快照直接丢弃
- 使用
resilience.SQLiteBackup()(VACUUM INTO 原子快照)
Journal 安全
INV-RESIL-06:Journal 只追加。
- Journal 文件没有 seek/truncate
- 只有
O_APPEND写入
损坏文件保留
INV-RESIL-07:损坏 DB 归档到 corrupt/ 目录供诊断,不直接删除。
mmap 禁用
INV-RESIL-08:PRAGMA mmap_size=0。
消除整类 SQLITE_IOERR_MMAP 故障。
VACUUM 禁止自动
INV-RESIL-09:VACUUM 中断 = 全损。
- 只在
SQLiteBackup(VACUUM INTO)中使用 - 必须先
TriggerSnapshot再 VACUUM
迁移全幂等
INV-RESIL-10:任何迁移重跑 N 次结果一致。
- 含多语句
ADD COLUMN trySkipMultiAddColumn独立处理
Boot 流程
Cell.Start(ctx)
→ 检查 .cell.lock(flock)
→ 打开三层 SQLite(降级模式)
→ 运行 DDL 迁移(幂等)
→ MarkInterruptedSessions()(INV-CKPT-04)
→ ListOrphanedRuns() → MarkRunTerminated()
→ 启动 Supervisor + Inbox + EventBus
→ 播种种子声明(INV-SEED-01)
→ 注册适配器
→ 加载技能
→ Cell 就绪
崩溃恢复
Cell boot 自动执行(INV-CKPT-04):
MarkInterruptedSessions():标记未正常关闭的会话ListOrphanedRuns()→MarkRunTerminated():终结孤儿 Run
消费方(wesclaw/wescode/wescraft/teleclaw)不必在 PostBoot 调用 MarkInterrupted。