AWR 的某个行为不符合你的预期。本指南从症状出发给出修复方法:先做健康 检查,然后是数据库问题,最后是被中断的来源文件变更。每一节都给出要运行 的确切命令和输出的读法。日常命令见日常工作流和 CLI 参考。
第一步:运行健康检查
AWR 内置一个名为 Doctor 的诊断命令,分两个级别:
awr --json doctor --database-only
awr --json doctor
--database-only检查 SQLite 数据库本身:完整性、外键、schema 版本、 迁移标识,以及 AWR 持有的 schema 对象。- 完整的
doctor还会检查你选定的来源文件,以及运行时记录与磁盘文件 之间的绑定。
Doctor 以只读方式打开数据库。它不迁移 schema、不重建索引、不应用 待决的变更、不使认领过期,也不删除孤儿文件——因此它总是可以安全运行, 即使在已损坏的项目上。
读懂 Doctor 的发现
Doctor 以明确的发现(findings)报告问题,而不是猜测:
schema_issues——对照内置迁移检查出的缺失或被改动的 AWR 持有的表、 列、索引或触发器。多余的对象可以共存;Doctor 不会修复定义,也不会 打印它们的 SQL。foreign_key_check_error——畸形的引用让 SQLite 连外键检查都无法运行。 看到这个字段意味着数据库不健康,此时报告的零违规表示"我们无法统计", 而不是"一切正常"。- 活跃会话——仅供参考;一条旧记录并不证明进程已死。
- 缺失的依赖、悬空的边、不可用的来源、被中断的保存,以及损坏或未注册的 制品,都会各自作为发现报告。不可读的页或外来的(非 AWR)数据库会产生 明确的错误,而不是误导性的状态。
症状:"AWR 拒绝了我的来源文件"
当 YAML 来源文件有语法错误或字段类型错误时,AWR 以错误码 InvalidInput 失败,并给出结构化的细节:
{
"location": {
"locator": "file:///project/work.yaml",
"pointer": "/work_items/0/title",
"line": 3,
"column": 10
},
"rule": "ledger.string",
"repair": "Use a quoted string or a YAML block scalar (|) for multiline text."
}
读法:pointer 用你来源文件自己的词汇(包括配置的中文字段名)指出 出问题的字段;line 和 column 从 1 开始计数。纯语法错误可能只有 解析器坐标,而某些查找(如 YAML 锚点别名)会保留 pointer 但坐标为 null——这并不会让一个本来合法的文件被拒绝。rule 是未满足的期望的 名称;repair 描述期望的结构。它绝不编辑文件,也不回显被拒绝的值。
一个常见情况:你写了 title: [Draft, Review],YAML 会把它解析成列表, 但该字段要求字符串。如果逗号本来就该是字面的:
title: "Draft, Review"
多行描述请使用 YAML 块标量(|);合法的中文文本和带空格的路径完全 受支持。
症状:"我的改动在查询里看不到"
你编辑了来源文件,但 AWR 仍显示旧事实。运行重建索引:
awr source reindex
然后检查报告的两个部分:操作是否成功以及投影是否完整。扫描成功 的同时投影可能仍不完整,因为扫描只是观测来源,并不导入其中变化了的 事实。同样的报告可以通过 --json 以 JSON 获得,也可经由 MCP 的 awr_source_reindex 获得。要比较输出,请从等价的起始快照开始比较; 重建索引本身会更新来源状态。
如果某个工作项的证据看起来不对,work show(或 MCP 的 awr_work_get) 会在扁平的 evidence 列表之外报告 evidence_groups。每个分组有一个 精确的定位符;同一路径下的来源引用和已验证报告保持相互独立,分组绝不 在记录之间转移验证结论。
症状:"数据库损坏或丢失了"
你的来源文件是项目事实的权威,但 SQLite 数据库(.awr/state.db)还 保存着来源文件不包含的状态:会话、认领、检查点、运行时事件、制品注册 和变更尝试。重建索引能从来源刷新投影,但无法重建那段运行时历史——用 同样的来源初始化一个全新的数据库同样做不到。
正确地备份
要得到可恢复的快照,把以下所有内容放在一起保存,并在收集它们时暂停 项目的写入方(SQLite 的备份 API 能给出一致的数据库映像,但不会快照 周围的文件):
- 用 SQLite 备份 API 或等价工具制作的
.awr/state.db一致性备份—— 在写入方活跃时直接复制文件,可能丢失仍在预写日志(write-ahead log) 中的已提交记录。 - 对应的来源文件、Git 修订版本、
.awr/project.toml、授权根配置,以及 任何显式授权的外部来源。 - 受管理的制品文件、注册过的位于受管理目录之外的本地制品,以及待决 操作所引用的
.awr/mutations恢复日志和快照。
恢复
- 停止项目。
- 在记录的规范根路径上恢复;保留被替换下来的状态,而不是删除它。
- 运行
awr --json doctor --database-only,然后运行完整的awr --json doctor。
恢复可能找回一个制品注册,而其文件仍然缺失——恢复该文件,或让这个 发现保持未解决。awr source reindex 既不是运行时恢复工具,也不是 数据库搬迁工具。
Doctor 可以执行具名修复,但前提是提供当前项目修订版本、选定对象和 理由;修复会保留来源和无关的运行时状态。如果数据库完整性已被破坏, 建议的运行时修复会被禁用——不做自动重建。
症状:"一次变更在写入中途被中断"
AWR 把已批准的提案应用到你的来源文件时带有持久化防护:在记录尝试之前 先保存不可变的变更前/后快照,成功则需要目标来源字节、重建后的投影和 最终的应用事件三者齐备。如果进程在写入中途死亡,该尝试保持打开且可 恢复。
如果你收到 MutationIncomplete 和 write_outcome: pending_recovery, 先检查:
awr --json doctor
awr --json proposal show PROPOSAL_ID
从输出中读取当前的 project_revision,然后恢复该提案:
awr --json proposal recover PROPOSAL_ID \
--actor reviewer \
--reason "Resume the interrupted report review" \
--expected-revision CURRENT_REVISION
恢复做什么,取决于尝试进行到哪一步:
| 中断后的状态 | 恢复的行为 |
|---|---|
| 快照存在,无应用日志 | 来源未变化;可以重新开始一次新的 proposal apply。 |
| 日志存在,来源仍与"变更前"一致 | 重新校验所有权、配置、来源和修订版本,然后安装记录的"变更后"字节。 |
| 来源已与"变更后"一致,投影不完整 | 重建投影,不改写文件。 |
| 投影已提交,最终事件缺失 | 校验投影并提交最终事件——不做第二次文件写入。 |
| 最终事件已提交,响应丢失 | 返回持久回执;重复恢复会以 InvalidTransition 失败,不产生重复事件。 |
| 来源或快照与记录的计划不一致 | 保留来源,报告冲突,不予完成。 |
成功的重试会报告 recovered,指明原始尝试,并把它的 resolved_event_id 绑定到最终事件。
两件不要做的事:
- 不要编辑快照来强行制造结果。 如果当前来源与两个快照都不匹配, 解决来源冲突并准备一个新提案。
- 不要假设重试一定写了文件。
source_write_performed只描述本次 调用——这正是恢复要先重新校验的原因。
并发:AWR 的写入方通过按来源的 OS 锁和事务性的 expected_revision 检查来协调。不同来源独立推进,但中间出现的项目修订版本可能要求一次 显式的恢复重试。外部编辑器不参与该锁;指纹检查会发现它们的改动。
什么时候停下来求助
遇到以下情况时,停下来升级上报,而不是临场发挥:
- Doctor 报告数据库完整性损坏(
foreign_key_check_error、不可读的页) ——运行时修复已禁用,不做自动重建。 - 一次变更恢复报告来源/快照冲突——受支持的路径是新建提案,而不是手改 快照或日志。
- 你的场景涉及机器断电、分布式写入方或其他操作系统——恢复保证只覆盖 本地进程中断;超出这个范围的行为尚未确立。
在求助或提交 issue 之前,趁状态新鲜时把它捕获下来:
awr --json doctor --database-only
awr --json doctor
awr --json proposal show PROPOSAL_ID # if a mutation is involved
保持被替换下来的数据库、.awr/mutations 日志和相关来源文件原封不动 ——它们让报告可被处理,也是修复出错时你的退路。
