首页
/ impeccable doctor:AI 设计工件漂移的检测、分级与修复完全指南

impeccable doctor:AI 设计工件漂移的检测、分级与修复完全指南

2026-09-07 10:48:50作者:虞亚竹Luna

导读: impeccable doctor 是 impeccable 设计技能包中专门负责"体检"维护性命令。它扫描项目里 PRODUCT.md、DESIGN.md 及其 design.json 旁车文件、.impeccable/config.json、持久化的 surface briefs 与 design hook,对照"当前安装版本实际读取的内容"报告并修复两者之间的漂移(drift)。读完本文,你将掌握 doctor 的三种漂移分类、JSON 报告结构、按 severity 分级处置的纪律,以及 Monorepo 下最关键的配置型 finding 的判定与修复方法。

doctor 是什么:职责边界与三种"过期"

官方文档对 doctor 的定位非常克制——Report and repair drift between this project's Impeccable artifacts and what the installed version reads。它只做维护,不做设计:

  • 不重新设计任何东西;
  • 不打开报告之外的文件;
  • 不把任何其他命令作为副作用去执行。

它检查的工件清单是固定的:PRODUCT.mdDESIGN.md 及其 .impeccable/design.json 旁车文件、.impeccable/config.json、持久化的 surface briefs、以及 design hook。

三类漂移要分开处理

"过期(out of date)"在 impeccable 中被拆成三种语义完全不同的漂移,doctor 明确把它们区分开:

漂移类型 含义 谁来负责
Tool version(工具版本) 已安装的 skill 比已发布的旧 impeccable context 在启动时上报为 UPDATE_AVAILABLEnpx impeccable update 修复
Schema drift(模式漂移) 工件由旧版 impeccable 写出:存在无人读取的字段、缺失新版本期望的字段、文件位于废弃位置 doctor 大部分可机械修复
Truth drift(真相漂移) 代码演进后文档不再如实描述它 没有文件比对能裁决;document 拥有 DESIGN.md、init 拥有 PRODUCT.md,doctor 的职责是把"一个具体缺口"递给它们,而不是给一句模糊的怀疑

从技能包路由层看,这一职责划分也被刻意设计成边界。skill/SKILL.src.md 中写明:doctor 在用户调用 impeccable doctor、或询问"什么过期了/陈旧了/需要刷新"时加载 reference/doctor.md;并且明确了一条纪律——绝不在设计任务中作为副作用顺手修复漂移CONTEXT_STALE 这类 finding 只上报不处置,唯一的例外是标记为 auto 的 finding(下次写该文件时本来就会被应用)。

运行一次检测:命令形态与 JSON 输出

基础命令与定位目标

.agent/skills/impeccable/scripts/impeccable doctor --json

当用户点名了某个 workspace、文件或 Monorepo 中的路由时,加 --target <path>

.agent/skills/impeccable/scripts/impeccable doctor --json --target packages/website

不传 --target 时,报告描述的是仓库根目录——在 Monorepo 中这常常指向错误的项目,因此对 Monorepo 场景,明确目标是第一优先。

实现层面的调用入口:在仓库源码形态中该命令对应 skill/scripts/doctor.mjs(skill 发行版内以 node {{scripts_path}}/doctor.mjs --json 形式书写);根文档中的 .agent/skills/impeccable/scripts/impeccable doctor 是已安装 skill 的封装形态。

输出结构:findings 是可消费的数据

--json 输出携带 findings,其中每一条 finding 都包含五个固定字段(见 CLAUDE.md 对数据模型的描述):

{ "id": "finding-名", "artifact": "受影响的工件", "path": "文件路径",
  "severity": "auto | mention | route", "summary": "摘要", "fix": "给出的修复" }
  • 在 Monorepo 中,输出还包含 workspaces 表,列出每个 app 的 product / design 解析结果(自己带上下文、继承、还是什么都没有);
  • ruleRegistryAvailable: false 表示被忽略的规则 id 无法通过规则注册表校验——此时要如实说明"该列表未被验证为干净",而不是暗示它已经干净;
  • findings 为空数组是最好结果:一行说清即可,然后停手,不要画蛇添足。

doctor 从架构上就不是"找错报警器"。findings 不是错误,命令不会因为存在 finding 而失败;severity 表达的是"接下来该发生什么",而不是"问题有多严重"。

源码纵深:两个检测层

结合 CLAUDE.md 可以看清 doctor 在工程中的层级定位:

  • Tier 1context 启动时输出的是整套发现的廉价子集(CONTEXT_STALE 指令);
  • Tier 2lib/staleness-deep.mjs,由 skill/scripts/doctor.mjs 按需调用——做 git log、逐 workspace 扫描、用实时 ANTIPATTERNS 规则注册表做忽略列表校验、以及 hook 脚本解析。

也就是说 doctor 是"深检",context 启动检查是"浅检";二者共享同一套 findings 数据结构,让启动指令、文本报告与 --json 渲染的是同一份数据。

按 severity 分级处置:严重度决定动作,而非好坏

doctor 命令约定三种严重度,处置纪律如下:

severity 语义 处置动作
auto 不携带任何决策 直接运行一次 impeccable doctor --fix 应用这些修复,然后用一行汇报"移动/修改了什么"。不需要先征得许可,事后也不需要再追问
mention 需要让用户知道,但此刻无需用户做决定 用一句话陈述每条,附上它给出的修复建议
route 需要某个具体命令来收口 说出命令名以及它能弥合的缺口;只有用户在本轮明确要求时才运行。initdocument 是"对话",不是可以无人值守替你完成的修复

三组 finding 要在一趟中全部报告完毕。注意 auto 修复只对 --fix 生效,且只应用"不涉及判断"的那部分——见 CLAUDE.md 的说明:doctor --fix applies only auto, and only where no judgment is involved。

已弃用字段是绑定的,不是风格建议

某个 finding 如果报告了一个已弃用字段(当前以 ## Register 为实例),那不是一条风格建议。处置规则是:从这一刻起,把该字段当作不存在——无论它现在的值是什么,所有后续决策都不得再参考它;并向用户提议删除整个小节。

保留它的理由即使只是"万一以后还用得上",也是错误的:一个退役的轴,正是靠这种方式继续影响当前输出(steering current output)。这与工件模式注册表的设计一脉相承——CLAUDE.md 要求每当退休 PRODUCT.md 的一个字段时,把它加入 lib/artifact-schema.mjsPRODUCT_DEPRECATED_SECTIONS 并写明原因;原因是装饰性文案之外的关键信息:仅被告知"字段已弃用"的模型会出于保险心态保留它。

不要对真相漂移过度断言

两条 finding 尤其考验克制:

  • design-md-drift 统计的是"DESIGN.md 最后一次编辑之后,视觉源码目录上的提交次数"。提交次数不等于文档矛盾。正确做法是:报告这个数字、说明它衡量的是什么;只有当用户想确认文档是否真的错了时,才去把 DESIGN.md 对着当前 tokens 与组件逐条阅读,然后基于阅读作答。永远不要因为数字大就断言 DESIGN.md 已陈旧。
  • workspace-context-inherited 同理。继承是被设计出来的行为;一份 product 记录是否如实地描述了多个 app,这是留给用户判断的问题,不是需要你修复的缺陷。

Monorepo 专项 finding 速查

doctor 在 Monorepo 下有几条高价值 finding,文档逐一给出了判定与修复方向:

workspace-platform-native-evidence:最值得注意的一条

一个 workspace 携带了原生构建文件,却在继承一条解析结果为 web 的根级记录——它的整个生命周期都会收到 web 侧的指导,永远不加载 ios.mdandroid.md。修复方式是在该 workspace 写一份子级 PRODUCT.md:一份被继承的记录无法同时承载两个平台

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

每条 projectRoots glob 都没命中,仓库根目录于是静默充当了活动项目。最常见原因是 workspace 目录被重命名。处置:把实际的 patterns 报告出来,问用户这些 glob 应该指向哪些目录。

config-invalid-build-path / config-build-path-unset:都围绕同一个键

两条 finding 都围绕 .impeccable/config.json 中的 buildPath 一个键:

取值 含义
comp 新 surface 从生成的 comp 开始构建
code 直接在代码中构建

注意优先级细节:被 gitignore 的 .impeccable/config.local.json 对该开发者而言优先于 config.json。同时"读取不到值"不会回退到相反路径——所以一个本意是 code 的项目可能在持续走 comp-led 构建;config-invalid-build-path 时要报告精确值。config-build-path-unset 只在"项目已做过方向性工作却从未记录偏好"时触发;并且只有当你所在工具面存在图像生成能力时,其修复提议才成立——没有图像生成就没有可选择的选项,也就无可说。

改动前先展示 workspaces 表

在提出任何改动之前,用 workspaces 表向用户展示:哪些 app 携带自己的上下文、哪些继承、哪些什么都没有。

退出启动检查:报告只在你索要时出现

impeccable context(源码形态即 context.mjs)会在会话启动时报告这些 finding 的廉价子集,每个项目每周最多节流一次。退出方式有两种:

  • .impeccable/config.json 中设 "stalenessCheck": false,彻底静默;
  • 或者设环境变量 IMPECCABLE_NO_STALENESS_CHECK=1,只对本会话生效。

禁用启动检查不影响 doctor 本身仍然可用。对"只想在自己要求时才看到报告"的用户,这正是建议的组合:关闭 context 的自动浅检,保留按需触发的深检。

节流与发射纪律的源码佐证

CLAUDE.md 给出了工程细节:启动输出已经很重,因此 Tier 1 对整个发现集合只发射一条 CONTEXT_STALE 指令;lib/staleness-notice.mjsmentionroute finding 节流到每项目每周一次,缓存落在 ~/.impeccable/staleness-check.json(与更新缓存同处,不需要 gitignore 条目)。而 auto finding 永不节流、也从不展示给用户——它本来就是静默自愈的。这正是测试里那些断言"其他启动指令"的用例需要设置该环境变量的原因,也是 doctor 与 context 之间"报告仅当被询问"这一契约的实现基础。

事实溯源:工件版本如何被识别

doctor 所以能把"模式漂移"和"真相漂移"分开,靠的是**来源戳(provenance stamp)**机制。PRODUCT.md 携带 <!-- impeccable:product-schema N --> 注释(常量定义在 lib/artifact-schema.mjs)。两个关键约束(见 CLAUDE.md):

  • 戳是模式版本而非发行版本——由 v4.0.0 写出的 PRODUCT.md 在 v4.0.1 下并不算陈旧;只有文件形状(shape)变化时模式版本才递增;
  • DESIGN.md 刻意不带戳,因为它遵循 Stitch 的 linter 校验的外部 design.md 规范,且 DESIGN.md 的所有信号(旁车 schemaVersion、旁车 mtime、章节覆盖率、git 漂移)没有戳也能测量。

没有戳时,所有检查都退化为对"文件来自哪个年代"的启发式重建——这正是把 Register 这类弃用字段当作绑定约束、把 auto 静默应用约束在同一数据模型里的根本原因。

结论与最小操作清单

对使用者而言,doctor 的完整流程可以浓缩为四步:--json 跑一趟 → 空结果则一行收尾 → 非空则按 auto(直接 --fix)/ mention(一句话陈述)/ route(点名命令、获准才跑)分级处置 → 对弃用字段与 Monorepo 配置型 finding 单独核实。它始终遵守同一条原则:这是维护,不是设计;报告缺口,不替 initdocument 做设计决定。

相关仓库文件(可继续深入阅读):

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

项目优选

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