首页
/ Impeccable Doctor 实战指南:用 `impeccable doctor` 报告与修复设计产物的漂移

Impeccable Doctor 实战指南:用 `impeccable doctor` 报告与修复设计产物的漂移

2026-09-09 14:12:13作者:薛曦旖Francesca

Impeccable 是让 AI 助手在界面设计上表现更好的设计语言与工具链。在长期迭代的项目中,PRODUCT.mdDESIGN.md 及其 sidecar、.impeccable/config.json、持久化的 surface briefs 与设计检测 hook 等“设计产物”,会与当前安装版本的读取方式逐渐脱节,这种脱节在 Impeccable 中被称为 drift(漂移)impeccable doctor 正是为此而生的维护命令:它一次性扫描这些产物,报告每一项漂移及其修复建议,并自动应用其中机械性的迁移。读完本文,你将掌握 doctor 的完整使用方式——包括三类漂移的区分、--json/--fix/--target 参数的语义、按严重级别(auto/mention/route)处置发现的行动准则,以及 monorepo 场景与启动检查退出的实战配置。

本文以 skill/reference/doctor.md 为骨架,并结合仓库中 impeccable doctor 的 Rust 实现(crates/context/src/doctor.rs)与其底层漂移检查模块(crates/context/src/staleness.rscrates/context/src/staleness_deep.rs)展开。

职责边界:doctor 拥有什么,不拥有什么

先明确一个原则:这是维护工作,不是设计工作doctor 不会重新设计任何界面,不会打开报告中未提及的文件,也不会作为副作用运行任何其他命令。

文档将“过期/过时(out of date)”划分为三种截然不同的漂移,务必区分对待:

  • 工具版本漂移(Tool version):已安装的 skill 比已发布的版本旧。impeccable context 在会话启动时会以 UPDATE_AVAILABLE 指令报告这一点,npx impeccable update 即可修复。这不是 doctor 的职责。从实现看,更新检查由 crates/context/src/context_cli.rscompute_update_directive 完成,它缓存最新版本并生成一段 UPDATE_AVAILABLE 提示;更新会重写当前会话正在读取的 skill 文件,因此文档明确要求:只提示、不在当前轮次执行更新。
  • Schema 漂移(Schema drift):某个产物由旧版 Impeccable 写成:包含没有任何代码读取的字段、缺少现在被期望的字段、文件位于已被废弃的位置。这类漂移是机械性的,doctor 能修复其中的大部分
  • 真相漂移(Truth drift):代码已经前进,而文档不再描述它。没有任何文件比对能解决这个问题——document 拥有 DESIGN.mdinit 拥有 PRODUCT.md,doctor 的职责是把某个具体缺口交给它们,而不是交出一个模糊的怀疑

理解这一分工后,doctor 的命令流程就清晰了。

Step 1:运行一次全面扫描

在会话开始时运行:

{{scripts_path}}/impeccable doctor --json

(在项目环境中即 impeccable doctor --json;Windows 无 sh 的 shell 下使用 impeccable.cmd。)--json 让输出以结构化 JSON 呈现,便于 Agent 解析与后续按严重级别处置。命令行用法与参数解析见 crates/context/src/doctor.rs

Usage: impeccable doctor [--json] [--fix] [--target <path>]

  --json           Emit findings as JSON.
  --fix            Apply the mechanical migrations (severity "auto") only.
  --target <path>  Select a workspace in a monorepo.

--target:在 monorepo 中选择正确的项目

当用户提到的是 monorepo 中的某个 workspace、文件或路由时,应附加 --target <path>。不加时,报告描述的是仓库根目录——在 monorepo 中这常常是错误的项目。参数解析同时支持 --target <path>--target=<path> 两种写法(见 crates/context/src/target_args.rs)。

理解 JSON 输出结构

输出携带:

  • findings:每项包含 idartifactpathseveritysummaryfix。其中 severity 取值为 automentionroute 三者之一(见下文 Step 2)。
  • workspaces(monorepo 下):每个应用的 product 与 design 解析情况,包括 productStatusdesignStatusplatform 等字段,由 crates/context/src/staleness_deep.rscheck_workspaces 生成。
  • ruleRegistryAvailable: false:意味着被忽略的规则 id 无法校验(内置检测器未能解析出规则注册表),应当如实说明,而不是暗示“忽略列表是干净的”。

此外输出还包含 projectRootrepoRootisMonorepoproductPathdesignPathplatform 等元信息(见 crates/context/src/doctor.rs)。

findings 数组就是最好的结果——用一句话说明“未发现漂移,所有产物与当前版本读取一致”然后停止,不要无谓展开。

Step 2:按严重级别行动

severity 字段表达的是“接下来应该发生什么”,而不是“问题有多糟糕”。三层语义各不相同:

严重级别 语义 行动
auto 不携带任何决策,纯机械迁移 运行一次 {{scripts_path}}/impeccable doctor --fix 应用全部,然后用一句话报告移动了什么。不需要事先征求许可,事后也不需要再询问
mention 需要用户知道,但现在不需要做任何决定 用一句话陈述每一项及其给出的修复建议
route 需要某个特定命令 说出命令名及它能弥合的缺口;仅当用户在本轮中明确要求时才运行——initdocument 是对话式流程,不是你能无人值守代跑的修复

三类发现要在同一次通过中全部报告。注意:发现(findings)不是错误,命令不会因为它们而失败——从 crates/context/src/doctor.rs 可以看到,doctor 的进程退出码仅与参数解析是否成功有关。

--fix 的实现(apply_fixes,见 crates/context/src/doctor.rs)会遍历全部 findings,只处理 severity == "auto" 的项,其余记录为“需要用户决策”而跳过。实际实现的自动迁移包括:

  • design-sidecar-legacy-path:把处于旧位置的 DESIGN.json sidecar 移动到规范位置 .impeccable/design.json(目标位置已存在时跳过,不覆盖)。
  • legacy-live-state:旧版 live 状态文件(.impeccable-live.json.impeccable-live)需要等无 live 会话运行时手工删除,--fix 会跳过并给出理由。
  • product schema 盖章:当 PRODUCT.md 存在内容但没有 schema 版本戳、且没有 product-schema-legacy 发现时,自动写入 <!-- impeccable:product-schema 1 --> 戳(版本号来自 crates/context/src/artifact_schema.rsPRODUCT_SCHEMA_VERSION)。

Step 3:弃用字段是强制的,不是风格建议

当某个 finding 报告了弃用字段时,这不是一条风格提示。以 ## Register 为例——它是当前版本明确弃用的节:

  • 从这一刻起,无论该字段持有何值,对之后的一切决策都视为其不存在
  • 主动提议删除该节。

文档给出的理由很尖锐:“‘以防万一’地保留它,就是让一条已退役的轴继续左右当前的输出。”从 crates/context/src/artifact_schema.rs 可以看到,PRODUCT_DEPRECATED_SECTIONS 明确记录:v4 用四种访客模式(Persuade、Operate、Read、Experience)取代了品牌/产品 register 轴,模式按 surface 选择并持久化在对应 brief 中,“没有任何代码再读取 ## Register”。对应检查在 crates/context/src/staleness.rscheck_product 中实现,产出的 finding id 为 product-deprecated-register,严重级别为 mention

Step 4:不要在真相漂移上过度断言

提交数不是矛盾design-md-drift 统计的是“自 DESIGN.md 上次编辑以来,视觉源码目录被提交改动的次数”——从 crates/context/src/staleness_deep.rs 的实现看,它借助 git 完成:先取 DESIGN.md 的最后一次提交哈希,再统计 srcapppagescomponentssitestylespublic 这七个视觉源码目录中自那以来的提交数(VISUAL_SOURCE_DIRS),超过阈值(当前实现中为 25)才报告。它衡量的是“值得重新阅读这份文档”,而不是“文档是错的”。

因此正确的做法是:

  • 报告数字,说明它衡量的是什么;
  • 如果用户想知道文档是否真的错了,DESIGN.md 与当前的 tokens 和组件逐一对照阅读,并据此回答;
  • 永远不要因为数字大就断言 DESIGN.md 已过期。该 finding 的 fix 文案也写明:先读 DESIGN.md 对照当前 tokens 与组件再信任它;若确已漂移,document 会从代码重新生成。

同样的克制适用于 workspace-context-inherited继承是设计好的行为——一个 product 记录是否如实地描述了多个应用,这是要问用户的问题,而不是需要修复的缺陷。

Monorepo 专项注意事项

在 monorepo 中,有几类 finding 需要特别留意:

workspace-platform-native-evidence:最重要的一项

某个 workspace 携带原生构建文件,却继承了解析为 web 的根记录——它会终身得到 web 侧指导,永远加载不到 skill/reference/ios.mdskill/reference/android.md。修复方式是给该 workspace 一份子级 PRODUCT.md,因为一份继承的记录无法同时承载两个平台

实现上(crates/context/src/staleness.rscheck_native_platform_evidence),它会在 pubspec.yaml(Flutter → adaptive)、ios/Podfileandroid/build.gradle(.kts)ios/Runner.xcodeproj 以及 package.json 中的 react-nativeexpo@react-native/metro-config 依赖里寻找原生证据,结合 workspace 的 product_status == "inherited" 给出针对性修复。

config-project-roots-match-nothing:projectRoots 全部落空

每个 projectRoots glob 都没有匹配到任何目录,仓库根目录于是静默地充当了活动项目。重命名 workspace 目录是常见原因。做法:报告这些 pattern,询问它们应当指向哪些目录。

config-invalid-build-pathconfig-build-path-unset:同一个键的两面

两者都涉及 .impeccable/config.json 中的一个键 buildPath(被 gitignore 的 .impeccable/config.local.json 会覆盖它,后者对那个开发者生效)。它取值 compcode,决定新 surface 是从生成的 comp 构建、还是直接在代码中构建。源码中合法值集合为 ["comp", "code"]crates/context/src/staleness.rsBUILD_PATH_VALUES)。

  • 不可读的值不会回退到另一条路径:一个本意是 code 的项目实际上一直在走 comp 主导的构建。报告确切的值。
  • config-build-path-unset 只在满足两个条件时触发:该项目做过方向性(direction)工作——即存在 .impeccable/surfaces.impeccable/mocks/decision 目录——却从未记录偏好;且你的工具面存在图像生成能力时,才属于该 finding 并提供选择。没有图像生成就没有可选的选项,也没有可说的内容。

workspaces 表先展示再动手

在提出任何修改前,先用 workspaces 表向用户展示:哪些应用自带上下文、哪些继承、哪些什么都没有。该表由 check_workspaces 构建(crates/context/src/staleness_deep.rs),包含每个 workspace 的 productStatus(own/inherited/none 之一)、designStatusplatform 等,供用户先看清全局。

退出启动检查:按需报告

impeccable context 会在会话启动时报告这些 finding 的“廉价子集”,每个项目每周最多一次(节流实现见 crates/context/src/staleness_notice.rsRENOTIFY_INTERVAL_MS 为 7 天,状态缓存在 ~/.impeccable/staleness-check.json)。两种方式可以静默它:

{
  "stalenessCheck": false
}

写入 .impeccable/config.json;或为单次会话设置环境变量:

IMPECCABLE_NO_STALENESS_CHECK=1

对应实现是 crates/context/src/staleness_notice.rsstaleness_check_disabled:环境变量优先,其次读取 config.json / config.local.json 中的 stalenessCheck 布尔值。关闭检查后 doctor 命令本身依然完全可用——对于“只在用户主动询问时想要报告”的场景,这正是推荐组合。

顺带一提,.impeccable/config.json 当前版本可识别的顶层键共有 8 个:hookdetectorupdateCheckstalenessCheckprojectRootsbuildPath$schemaversion(见 crates/context/src/staleness.rsKNOWN_CONFIG_KEYS)。detector 对象内可识别的键为 ignoreRulesignoreFilesignoreValuesdesignSystemextensions。出现这些集合之外的键会触发 config-unknown-keys / config-unknown-detector-keysmention 级发现——文档特别提醒:ignoreRule(漏了 s)之于 ignoreRules 是最常见的近拼错误,它从未静默过任何规则

更多值得了解的发现

doctor 的全量检查还覆盖以下场景(供排查时对照 finding id):

  • design-sidecar-schema-outdated / design-sidecar-stale:sidecar 的 schemaVersion 低于当前版本(当前为 2,见 crates/context/src/artifact_schema.rsDESIGN_SIDECAR_SCHEMA_VERSION),或 DESIGN.md 在 sidecar 生成之后被编辑过——修复由 document 负责,它读取现有 DESIGN.md 重新生成 sidecar,无需访谈。
  • design-md-coverageDESIGN.md 缺少 colorstypography(种子文件时)或 components 节,Agent 生成新页面时对这些维度没有规范指导,live 设计面板只能渲染通用近似值。
  • detector-ignore-rules-unknown / detector-ignore-files-missingdetector.ignoreRules 引用了检测器不存在的规则 id(规则被改名/删除,或 id 拼错从未生效过),或 detector.ignoreFiles 指向已不存在的文件路径。
  • hook-script-missing / hook-enabled-conflict:hook 清单安装的脚本路径不存在(hook 成为 no-op,UI 编辑一直未被扫描),或 hook 已安装但 hook.enabled: false 导致“触发后拒绝扫描”。
  • product-schema-legacy / product-schema-outdatedPRODUCT.md 没有 schema 戳且缺少当前记录新增的四个节(PositioningOperating ContextEvidence on HandProduct Principles),或戳版本低于当前值——均由 init 通过访谈弥合,保留已确认的答案,绝不从推断重写文件。
  • surface-brief-orphaned:持久化的 surface brief 指向的主目标文件已不存在——询问是 surface 移动了(重定向 brief)还是被删除了(删除 brief)。

与整体 skill 的关系

skill/SKILL.src.md 的命令路由中,doctor 的触发条件是用户调用它、或询问“什么过期了 / 陈旧了 / 需要刷新”。Setup 输出中的 CONTEXT_STALE 指令是同一份报告的廉价子集,应按其自身指示就地处理,而不是未经请求就运行完整的 doctor。最后一条铁律值得重申:永远不要在设计任务的副作用中修复漂移——除非用户明确要求,CONTEXT_STALE 发现只被报告、不被执行;唯一例外是标记为 auto 的发现,因为下次写入该文件时它本来就会被执行。这正是 skill/reference/doctor.md 所定义的纪律:doctor 是一次显式、可控、职责单一的维护动作。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525