首页
/ Impeccable Doctor 巡检器:AI 设计技能中 PRODUCT/DESIGN 工件漂移的报告与修复指南

Impeccable Doctor 巡检器:AI 设计技能中 PRODUCT/DESIGN 工件漂移的报告与修复指南

2026-09-08 11:26:09作者:齐冠琰

本篇技术指南面向 Impeccable——一套让 AI 设计工作流更可靠的设计语言与技能体系。doctor 是其中负责“体检”的维护型命令:它报告并修复项目内 Impeccable 工件(PRODUCT.md、DESIGN.md 及其 .impeccable/design.json sidecar、.impeccable/config.json、持久化的 surface brief、设计 hook)与当前安装版本所读取的规范之间的漂移。读完本文,你将掌握如何运行一次完整的 doctor 巡检、按 severity 分级处置每一项 finding、在 monorepo 中定位错误的项目上下文,以及如何关闭开机自检但保留按需巡检。

该命令的完整行为契约定义在 doctor.md(源文件位于 skill/reference/doctor.md,并被镜像到 .qoder.claude.cursor.gemini 等各 Agent 运行时目录,如 plugin/skills/impeccable/reference/doctor.md)。

1. doctor 是什么:一处明确的职责边界

doctor 的使命只有一句话:报告并修复项目工件与安装版本之间的漂移。它针对的工件集合是固定的——PRODUCT.mdDESIGN.md 及其 .impeccable/design.json sidecar、.impeccable/config.json、持久化的 surface brief,以及设计 hook。

与之同等重要的是它不做什么,这是该命令设计的红线:

  • 这是维护,不是设计。任何 redesign 行为都在范围之外。
  • 不打开报告点名的文件以外的任何文件。
  • 不以副作用形式运行任何其他命令。

从命令体系角度看,这一点被刻意固化:CLAUDE.md 明确指出 doctor 是一个 utility command(实用命令),不是 design command。它遵循 hookspin 的模式(在 SKILL.src.md 中加一行路由 + 一份 reference/doctor.md),而不是 Commands 表模式;它刻意不在 IMPECCABLE_SUB_COMMANDScommand-metadata.jsonSKILL_CATEGORIES 之中,也不计入 23 个设计命令的配额——维护工具被有意排除在“设计菜单”之外。

2. “过期”之下其实是三类不同的漂移

文档要求把三种漂移严格分开处理,不能混为一谈:

漂移类型 含义 归属 处理方式
Tool version(工具版本) 已安装的 skill 比已发布版本旧 context.mjs 在启动时以 UPDATE_AVAILABLE 报告,npx impeccable update 修复 不是本命令的职责
Schema drift(模式漂移) 工件由旧版 Impeccable 写出:含有无人读取的字段、缺少当前期待的字段、文件位于已退役位置 机械性、确定性 本命令修复其中大部分
Truth drift(事实漂移) 代码演进后文档不再描述现状 没有任何文件对比能裁定 document 拥有 DESIGN.md、init 拥有 PRODUCT.md,doctor 的职责是递给它们一个具体的缺口,而非模糊的怀疑

第三类的关键在“具体”二字:与其说“文档可能过时了”,不如说“## Register 已被废弃、DESIGN.md 第 40 行仍在引用它”——把可执行的具体缺口交到负责重写的命令手里。这也解释了为什么 initdocument对话(conversations),而不是可以被无人值守执行的修复。

3. Step 1:跑一遍完整巡检

3.1 命令形态

node {{scripts_path}}/doctor.mjs --json

其中 {{scripts_path}} 是技能参考文件中的占位符,由运行时解析为已安装 skill 的脚本基目录;在具体 Agent 目录的镜像版本里会被替换为真实路径,例如:

node .qoder/skills/impeccable/scripts/doctor.mjs --json

需要说明的是,doctor.mjslib/staleness-deep.mjs 等脚本属于发布到用户项目中的 skill 安装包的一部分,scripts/test-suites.mjs 在其技能脚本清单中即包含了 doctor,这印证了它在分发结构中的既定位置。

3.2 --target:monorepo 中的指路牌

node {{scripts_path}}/doctor.mjs --json --target <path>

当用户在 monorepo 中点名了一个 workspace、文件或路由时,必须加 --target <path>。不带该参数时,报告描述的是仓库根目录;而在 monorepo 中,根目录往往不是那个真正被讨论的项目。

3.3 输出的形状:findings 是数据

输出携带 findings,每个 finding 是结构化记录:idartifactpathseveritysummaryfix。在 monorepo 中还会携带 workspaces,列出每个 app 的产品与设计解析结果(自有 / 继承 / 无)。

两个需要如实转述的特殊状态:

  • ruleRegistryAvailable: false:表示被忽略的规则 id 无法被校验——这时要明说列表未经校验,而不是暗示它已通过验证。
  • 空的 findings 数组就是最好的结果:用一句话说明并停止,不要画蛇添足。

从架构上看,这套输出被刻意做成结构化数据:CLAUDE.md 明确“Findings are data”——同一组 finding 数据既渲染为启动指令、也渲染为文本报告、还可输出为 --json,三者同源同构。

4. Step 2:按 severity 行动——severity 说的是“该怎么办”,不是“有多糟”

这是 doctor 最容易被误读的约定。严重程度不度量损坏程度,而规定下一步动作

  • auto:不带任何决策。直接运行一次 node {{scripts_path}}/doctor.mjs --fix 应用它们,然后用一句话报告移动了什么。不需要先征求许可,事后也不需要再问。因为这类修复不涉及判断。CLAUDE.md 的补充约定是:doctor --fix 只应用 auto,且只应用在不涉及任何判断的地方。
  • mention:用户需要知情,但现在不需要决策。用一句话陈述每条 finding 及其给出的修复选项。
  • route:需要一条具体命令。点出该命令以及它将弥合的缺口,并且只有当用户在本轮明确要求时才执行——initdocument 是对话式流程,不是可无人值守的修复。

三条纪律:

  1. 三类 group 在一次巡检中全部报告,不要分批。
  2. Findings 不是错误,命令不会因为它们而失败退出。
  3. auto 类 finding 在启动自检中永不节流、永不展示给用户(见第 7 节)。

5. Step 3:已废弃字段是硬约束

一条报告“已废弃字段”的 finding 不是风格建议。例如当前已废弃的 ## Register 字段——从此刻起,无论它持有任何值,都要把它当作不存在来参与后续每一个决策,并主动提出删除该章节。

文档的告诫非常直白:为了“以防万一”而保留它,正是让一条已退役的轴线继续左右当前输出的方式。schema 漂移的确定性在这里体现:机械地删除旧字段、补齐新字段,正是 doctor 能“修复大部分”的那一类。

6. Step 4:不要在 truth drift 上过度断言

这一节约束的是 agent 的“话术纪律”,两条最具代表性:

  • design-md-drift:该 finding 统计“自 DESIGN.md 上次被编辑以来,视觉源目录中的提交数”。提交数不是矛盾证据。正确的做法是:报告数字、说明它度量的是什么;如果用户想知道文档是否真的错了,就打开 DESIGN.md 对照当前的 tokens 与 components 亲自读一遍再回答。永远不要因为数字很大就断言 DESIGN.md 已过期
  • workspace-context-inherited:继承是被设计出来的行为。一条产品记录是否如实地描述了多个 app,这是该问用户的问题,而不是需要修复的缺陷

7. 启动自检与两层巡检架构:doctor 在其中的位置

要理解 doctor 与日常会话的关系,需要看它背后两级架构(见 CLAUDE.md):

  • Tier 1(启动时的廉价子集)context.mjs 在会话开始时报告这些 finding 的子集,即 SKILL.src.md 中描述的内容——启动输出里的一条 CONTEXT_STALE 指令是同一次报告的廉价子集。注意它是整组共一条指令,而不是逐条刷屏。
  • Tier 2(按需的深度巡检):即本文的主角,由 doctor.mjs 运行——包括 Git 日志、逐 workspace 扫描、针对实时 ANTIPATTERNS 注册表的 ignore 列表校验、hook 脚本解析。

节流策略是:mentionroute 类 finding 借助 lib/staleness-notice.mjs 每个项目每周至多提示一次(缓存在 ~/.impeccable/staleness-check.json,因此无需在项目 gitignore 中额外登记);而 auto finding 从不节流、从不展示。

**Provenance stamps(来源戳)**也直接影响 doctor 的判断逻辑:PRODUCT.md 携带 <!-- impeccable:product-schema N --> 形式的戳(常量定义于 lib/artifact-schema.mjs,模板见 init.md)。戳是 schema 版本号而非发布版本号——v4.0.0 写的 PRODUCT.md 在 v4.0.1 下并不算过期,只有结构形态变化才升级 schema 版本。而 DESIGN.md 刻意不带戳,因为它遵循外部 design.md 规范(由 Stitch 的 linter 校验),DESIGN.md 的每一个信号(sidecar schemaVersion、sidecar 修改时间、章节覆盖、Git 漂移)不靠戳也可度量。

8. Monorepo 专项:四条高价值 finding 的处置

doctor 在 monorepo 场景下最容易出价值也最容易出误判,文档给了四个专项判例:

8.1 workspace-platform-native-evidence:最该重视的一条

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

8.2 config-project-roots-match-nothing

说明 projectRoots 的每一个 glob 都未命中,于是仓库根目录被静默当作活动项目顶了上来。目录改名是最常见原因。处理方式:报告这些模式,并询问它们应该指向哪些目录——不要自行猜测

8.3 config-invalid-build-path / config-build-path-unset:都围绕 buildPath

两条 finding 都指向 .impeccable/config.json 中的同一个键 buildPath(也可能是被 gitignore 的 .impeccable/config.local.json——对单个开发者而言后者胜出)。该键取值 compcode,决定新 surface 是从生成的 comp 构建、还是直接在代码中构建。

三个要点:

  • 不可读的值不会回退到相反路径——一个本意是 code 的项目可能一直在走 comp-led 流程。因此报告时要给出精确值
  • config-build-path-unset 只在一种情况下触发:项目已经做过方向性工作、却从未记录偏好。
  • “提供选项”这一步只在你的工具面存在图像生成能力时才属于该 finding。没有图像生成,就既没有可选的、也没有可说的。其语义背景见 init.md:init 在首次询问时会向用户陈述两种路径的取舍——comp-first(由图像设定方向)与 code-first,并把回答写入 "buildPath": "comp""buildPath": "code",且只写入用户真实做出的选择。

8.4 先展示 workspaces 表,再提任何修改

在提出任何改动之前,用 workspaces 表让用户看清:哪些 app 自带上下文、哪些在继承、哪些什么都没有。展示在提议之前,这是 monorepo 场景下的事实纪律。

9. 退出开机自检:想要“只在被要求时报告”

context.mjs 在会话开始时报告这些 finding 的廉价子集,按每个项目每周一次节流。两种关闭方式:

  • 项目级:在 .impeccable/config.json 中设置 "stalenessCheck": false,例如:
{
  "stalenessCheck": false
}
  • 单会话级:环境变量 IMPECCABLE_NO_STALENESS_CHECK=1

注意:关闭自检后 doctor 命令本身仍然完全可用。这正是给“只想在主动询问时拿到报告”的用户推荐的组合——CLAUDE.md 还提到,测试套件中断言其他启动指令的用例应设置该环境变量,这也是 tests/context.test.mjs 中更新检查套件的做法,避免自检输出干扰断言。

10. 一次完整的处置流:从自检到巡检到重写

把全文串成一张可执行的时间线:

  1. 会话启动,context.mjs 的廉价子集给出 CONTEXT_STALE(若有)——此时按其自身指令就地处理,不要擅自运行 doctor
  2. 用户明确要求体检/报告过期内容时,加载 reference/doctor.md,运行 doctor.mjs --json(monorepo 中加 --target)。
  3. findings 为空:一句话说明健康,停止。
  4. 否则按 severity 一次报告全部三组:auto--fix 静默应用并一句话汇报;mention 逐条一句话陈述加修复选项;route 点名 init / document 等对话式命令及其要弥合的缺口,仅当用户本轮要求才执行。
  5. 对已废弃字段(如 ## Register)一律视为不存在并提议删除;对 design-md-drift 报告数字而非断言过期;在 monorepo 中先给 workspaces 表,再针对 workspace-platform-native-evidence 等判例提议子级 PRODUCT.md。
  6. 需要让用户重新掌控节奏时,建议 "stalenessCheck": false 或单次 IMPECCABLE_NO_STALENESS_CHECK=1,按需巡检的能力不变。

这套流程把“体检查什么、怎么分级、谁有最终处置权、agent 话术的边界”全部标准化,让一次看似主观的“文档过期”判断,变成可复现、可审计、可机械执行的数据驱动巡检。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 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
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 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
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389