# D8 可靠性与恢复 PRD > 产品:Feishu Codex Console > 状态:`beta.4` 闭环已完成 > 优先级:P0 > 目标版本:`1.0.0-beta.4` > 依赖:D2 设备状态、D4 任务状态机、D7 安全治理 ## 1. 用户问题 桥接服务运行在用户自己的电脑上,天然会遇到睡眠、断网、网络切换、飞书限流、进程退出、系统更新和版本升级。用户真正担心的不是一次报错,而是异常后出现以下不确定性: - 同一个任务是否会被重复执行。 - 完成结果是否因为卡片更新失败而丢失。 - 任务、卡片和 Codex thread 显示的状态是否一致。 - 升级失败是否损坏原有会话和队列。 - 出问题时是否只能把含有隐私的完整日志发给维护者。 可靠性设计必须优先保证“不重复产生副作用”,其次才是自动继续。 ## 2. 已确认边界 ### 本地优先 - 本版本不提供云端离线队列,也不开放本机公网入口。 - 设备离线时,桥接器无法承诺接收或处理飞书消息;恢复通知会提示用户检查并重新发送未确认的任务。 - 如果飞书在重连后重新投递事件,事件 ID 去重保证同一事件最多消费一次。 - 加密离线中继属于未来可选架构,不进入 `beta.4`。 ### 恢复优先级 1. 不重复执行已经启动的任务或外部动作。 2. 保留可审阅的工作区修改和 Codex thread 标识。 3. 恢复从未开始的可靠队列。 4. 修复卡片显示和本地状态的不一致。 5. 自动化无法证明安全时,停止并要求用户确认。 ## 3. 连接与重试 ### 事件长连接 - 消息和卡片事件消费者分别记录 `ready`、最近就绪、最近退出和重启次数。 - 消费者退出后从 1 秒开始指数退避,最长 30 秒。 - 两个消费者未同时就绪时,设备状态为连接中或降级,不展示虚假的完整操作能力。 ### 飞书 API 请求 - 单次请求默认 20 秒超时。 - `429`、`5xx`、网络重置、暂时不可达和超时最多尝试 3 次。 - 优先遵守 `Retry-After`;否则使用带抖动的指数退避,最长 30 秒。 - 非临时错误立即失败,不重复提交。 - API 连续失败会写入健康快照,事件长连接正常时设备显示“出站 API 降级”。 ### 回复可靠性 - 所有普通回复使用统一 Card 2.0 产品外壳,按信息、成功、提醒和失败展示。 - 卡片创建或回复失败时,自动降级到 SQLite 文本 outbox。 - 终态任务卡更新失败时,即使关闭主动完成通知,也会额外发送终态回复;文本 outbox 负责后续重放。 - 所有卡片和文本在离开本机前使用同一套凭据脱敏规则。 ## 4. 任务恢复与状态对账 ### 自动恢复矩阵 | 启动时证据 | 处理 | 原因 | |---|---|---| | 任务记录和卡片都为 `queued`,没有启动时间/thread | 重新鉴权后恢复队列 | 可以证明从未开始 | | 任一状态为 `running`,或存在启动时间/thread | 标记 `interrupted`,不自动重放 | 可能已经修改文件或执行命令 | | 任一状态已经终止 | 保持终态,不进入队列 | 防止完成任务重复执行 | | 成员、项目 ACL、仓库策略或权限上限变化 | 阻止恢复并标记失败 | 旧授权不能跨重启延续 | ### 权威状态 - SQLite 是恢复来源,但任务记录 `status` 和任务卡 `progress.phase` 会独立对账。 - 显式终态优先于运行/排队;任何启动证据优先于排队。 - 对账结果写回 SQLite、刷新仍可更新的任务卡,并写入审计。 - 已启动任务保留 thread ID、Git 基线和已发现变更,用户审阅后才能手动重试。 - 排队任务在真正执行前再次检查成员角色、项目 ACL、仓库策略和 sandbox 上限。 ## 5. 数据备份、迁移与回滚 ### 自动迁移保护 - SQLite 使用显式 `PRAGMA user_version` 管理数据库结构版本。 - 检测到旧结构后,迁移前使用 SQLite 在线备份 API 生成一致性快照。 - 备份和迁移后都执行 `PRAGMA quick_check`。 - DDL 在事务中完成;结构或状态转换任一步失败,关闭数据库后自动恢复迁移前快照。 - 遇到比当前程序更新的数据库结构时拒绝启动,不做降级猜测。 ### 备份格式 - 默认目录:`/backups//`。 - 包含一致性 `state.sqlite` 和 `manifest.json`。 - 清单记录创建时间、原因、文件大小、SQLite/状态版本和 SHA-256。 - 目录权限为 `0700`,文件权限为 `0600`。 - 默认保留最近 10 份;正在恢复和回滚前的安全备份不会在当前操作中被清理。 ### 运维命令 ```bash feishu-codex-bridge backup --config /path/to/instance.env feishu-codex-bridge backups --config /path/to/instance.env feishu-codex-bridge stop --config /path/to/instance.env feishu-codex-bridge rollback --backup --yes --config /path/to/instance.env feishu-codex-bridge install --config /path/to/instance.env ``` - 在线备份允许服务运行。 - 回滚要求服务已停止,并在替换当前数据库前再创建一份 `before-rollback` 安全备份。 - 恢复前校验清单、SHA-256 和 SQLite 完整性。 - 回滚不自动恢复配置文件;安装器的配置备份使用独立 `.bak.`。 ## 6. 自检、自修复与支持包 ```bash feishu-codex-bridge doctor --fix --config /path/to/instance.env feishu-codex-bridge doctor --diagnostics /private/path/diagnostic.json --config /path/to/instance.env ``` `doctor --fix` 只执行低风险、可重复的本地修复: - 把数据和日志目录权限修复为 `0700`。 - 把 SQLite、健康文件和日志权限修复为 `0600`。 - 移除已经死亡且过期的健康标记。 - 轮转超过配置上限的日志。 诊断包包含: - Node/系统版本和匿名化本机信息。 - 配置能力摘要和成员数量,不包含凭据值。 - 健康快照、SQLite 完整性与任务状态计数。 - 有界的近期日志尾部。 - 全局凭据脱敏和用户主目录折叠。 诊断包不会覆盖已有文件,创建后权限固定为 `0600`。用户分享前仍应人工检查。 ## 7. 保留策略 | 数据 | 默认策略 | |---|---| | 任务 | 最多 100 条,优先保留运行和排队任务 | | 审计 | 最近 5,000 条 | | 事件去重 | 最近 2,000 个事件,可配置 | | 附件 | 72 小时,可配置;活动任务附件受保护 | | 日志 | 单文件 10 MiB,可配置 | | 自动/手动数据库备份 | 最近 10 份 | | 确认卡 | 默认 10 分钟后失效 | 保留策略按数量或容量限制,不上传遥测,也不保存额外的提示词副本。 ## 8. 验收标准 - 杀死桥接进程后,已启动任务变为中断且不会自动重放。 - 从未启动的排队任务只在重新鉴权通过后恢复。 - 任务记录与卡片状态冲突时,保守对账并留下审计证据。 - 飞书 `429`、`5xx`、超时和暂时网络错误按策略重试,非临时错误不重试。 - 终态卡片更新失败时,用户仍能收到产品化回复或可靠文本。 - 数据库结构升级前有一致性备份;模拟迁移失败后原数据库字节语义可读且结构版本不前进。 - `doctor --fix` 不修改身份、项目 ACL、权限模式或用户代码。 - 诊断包不包含测试凭据,且文件权限为 `0600`。 - 回滚在服务运行时拒绝,在服务停止后先做安全备份再替换。 ## 9. 开发任务 - [x] D8-T01:飞书 API 临时错误识别、超时、Retry-After 和指数退避。 - [x] D8-T02:事件消费者/API 健康状态进入设备可用性模型。 - [x] D8-T03:统一产品回复卡与可靠文本降级。 - [x] D8-T04:终态任务卡失败时强制发送结果兜底。 - [x] D8-T05:任务记录、卡片 phase 和 Codex 启动证据保守对账。 - [x] D8-T06:SQLite 显式结构版本、迁移前快照和失败自动回滚。 - [x] D8-T07:手动备份、列表、停止服务和回滚 CLI。 - [x] D8-T08:`doctor --fix` 与脱敏诊断包。 - [x] D8-T09:权限、完整性、回滚、重试和 CardKit 契约测试。 - [x] D8-T10:安装、排错、架构、安全和发布文档同步。 ## 10. 非目标 - 在设备断电、关机或完全离线时继续运行本地 Codex。 - 保证飞书平台在本机离线期间持久保存并重新投递所有消息。 - 自动重放已经启动的任务。 - 自动把配置、代码、附件或日志上传到云端。 - `beta.4` 提供加密离线中继或多设备中心控制面。