首页
/ Impeccable doctor 命令实战指南:检测与修复项目工件漂移

Impeccable doctor 命令实战指南:检测与修复项目工件漂移

2026-09-09 20:14:05作者:仰钰奇

Impeccable 是一套让 AI 设计工作流(Agent/harness)更懂设计的技能与引擎,它以 PRODUCT.mdDESIGN.md 及其 .impeccable/design.json 伴生文件、.impeccable/config.json、持久化 surface briefs 和 design hook 等一批"工件"(artifact)作为设计决策的权威来源。本文讲解 impeccable doctor 这一维护型命令:如何在项目工件与已安装的 Impeccable 版本所读取的格式之间检测"漂移"(drift),如何按严重性分级处置,以及 monorepo 场景下的专项检查。读完你将掌握 doctor 的完整操作流程、每个 finding 的语义与修复动作,并理解其背后的源码实现逻辑。

doctor 的职责边界:维护,而非设计

doctor 是维护性命令,不是设计命令。它的职责是:报告并修复本项目的 Impeccable 工件与当前安装版本所读取内容之间的漂移,检查对象包括:

  • PRODUCT.md(产品真相记录)
  • DESIGN.md 及其 .impeccable/design.json 伴生文件(设计系统记录)
  • .impeccable/config.json(项目级配置)
  • 持久化的 surface briefs(.impeccable/surfaces/ 下的简报)
  • design hook(接入各 harness 的自动检测钩子)

运行时不要重新设计任何东西、不要打开报告之外的文件、不要作为副作用执行其他命令。源码 doctor.rs 中的用法说明也印证了这一点:Report drift between this project's Impeccable artifacts and what the installed version reads

三种漂移:先分清楚再动手

"过时(out of date)"名下其实混着三种完全不同的漂移,处理方式各异,必须分开对待:

漂移类型 含义 谁负责 是否本命令职责
工具版本漂移(Tool version) 已安装的 skill 比发布版旧 impeccable context 在启动时以 UPDATE_AVAILABLE 报告,npx impeccable update 修复
Schema 漂移(Schema drift) 工件由旧版 Impeccable 写出:含有无人读取的字段、缺少新版期望的字段、文件位于退役位置 机械性问题,doctor 可修复其中大部分
真值漂移(Truth drift) 代码演进后文档不再描述现实 没有文件对比能裁决;document 拥有 DESIGN.md,init 拥有 PRODUCT.md,doctor 的职责是把具体缺口交给它们,而不是给出模糊怀疑 否(仅移交)

这一分类在实现中同样可见:collect_boot_finding_groupsstaleness.rs)负责 boot 期的机械性工件检查,而 check_design_drift 等深层检查(staleness_deep.rs)只负责给出"值得重读"的信号,不自行改写文档。

第一步:运行检查

在项目根目录(或 skill 安装目录)执行:

"<skill-base-dir>/scripts/impeccable" doctor --json

其中 <skill-base-dir> 是当前 harness 下 Impeccable skill 的安装目录(例如 .claude/skills/impeccable),scripts/impeccable 是平台启动器(launcher)。启动器源码见 skill/scripts/impeccable:它会依次尝试 $IMPECCABLE_BIN、随附平台二进制、~/.impeccable/bin/impeccable、版本固定缓存,最后才回退到 PATH 上的 impeccable,全程不需要 Node。

参数说明

doctor 的完整参数(与 doctor.rs 中的 parse_args 与 usage 文本一致):

参数 作用
--json 以 JSON 形式输出 findings
--fix 只应用 severity 为 auto 的机械迁移
--target <path> 在 monorepo 中选择某个 workspace / 文件 / 路由
--help / -h 输出用法并退出,不运行任何检查(优先级最高)

当用户点名了 monorepo 中的某个 workspace、文件或路由时,必须追加 --target <path>;不追加时报告描述的是仓库根,在 monorepo 中这往往是错误的项目。参数解析要求 --target 必须有值(--target <path>--target=<path> 两种写法都支持,见 target_args.rs),--target 缺值会向 stderr 输出错误并以退出码 1 结束。

输出结构

--json 输出的顶层字段包括:projectRootrepoRootisMonorepoproductPathdesignPathplatformruleRegistryAvailablefindingsworkspaces,以及(仅在使用 --fix 时)fixes。其中:

  • 每个 finding 携带 idartifactpathseveritysummaryfix 六个字段(字段定义见 staleness.rsFinding 结构);
  • monorepo 场景下 workspaces 数组给出每个 app 的 product/design 解析结果(含 productStatus/designStatusplatform,见 staleness_deep.rsWorkspaceRow);
  • ruleRegistryAvailable: false 表示无法加载内置检测器注册表,此时被忽略的规则 id 无法被校验,报告时必须如实说明,而不是暗示清单是干净的。

文本输出则按严重性分组展示(route/mention/auto),格式可参见测试金标准 tests/oracle/golden/doctor-legacy-fix.json:每个 finding 一行 id [path],接着 summary→ fix

findings 数组是理想结果(文本输出为 No drift found. Every artifact matches what this version reads.,见 tests/oracle/golden/doctor-full-text.json),此时用一行说明"无漂移"并停止即可。findings 不是错误,命令不会因它们而失败(run 在正常情况下总是返回 0)。

第二步:按严重性分级行动

severity 字段描述的是"应该发生什么",而不是"问题有多严重":

  • auto(自动迁移):不携带任何决策。直接运行一次 "<skill-base-dir>/scripts/impeccable" doctor --fix 应用这些迁移,然后用一行汇报移动了什么。无需事先征求许可,事后也不必再问
  • mention(值得一说):用户需要知道,但此刻不需要做决定。用一句话陈述每条及其建议的修复。
  • route(需要路由到专门命令):需要一个特定命令来修复。说出命令名及它能消除的缺口,仅当用户在本轮明确要求时才执行——initdocument 是访谈式对话流程,不是可无人值守执行的修复。

三组必须一次性全部报告,不要挑着说。

--fix 实际做什么

--fix 只处理 auto 严重性的项(doctor.rsapply_fixes):

  • design-sidecar-legacy-path:当规范的 .impeccable/design.json 不存在时,把旧位置的侧车文件 rename 过去(输出 Moved <旧路径> to <新路径>.);若规范位置已存在则跳过并注明 already exists; not overwriting
  • legacy-live-state:跳过,提示"确认没有 live 会话运行后手动删除"(避免在会话活动时删除状态);
  • 其他 auto 项若没有实现迁移,则记为 no automatic migration implemented
  • auto 项统一跳过,理由为 needs a decision from the user

此外,--fix 有一个与 findings 无关的独立动作:若 PRODUCT.md 存在、没有 schema 戳、且本轮没有 product-schema-legacy finding,则通过 stampProductSchema 写入 <!-- impeccable:product-schema 1 --> 戳(插入在 H1 之后),输出 Stamped PRODUCT.md as product-schema 1.。这正是 tests/oracle/golden/doctor-fix-stamps-product.json 验证的行为——第一次 --fix 打戳,第二次输出 Applied nothing.。Schema 版本常量定义在 artifact_schema.rsPRODUCT_SCHEMA_VERSION = 1DESIGN_SIDECAR_SCHEMA_VERSION = 2

第三步:弃用字段具有约束力

任何报告了弃用字段的 finding(当前是 ## Register都不是风格建议。从这一刻起,无论该字段持有何值,都必须把它当作不存在来对待,并主动提议删除该章节。

原因很现实:v4 用四种访客模式(Persuade / Operate / Read / Experience,按 surface 选择并持久化在该 surface 的 brief 中)取代了品牌/产品 register 轴,没有任何代码再读取 ## Register。实现上,artifact_schema.rsPRODUCT_DEPRECATED_SECTIONS 记录了该章节及其废弃理由,而 staleness.rscheck_product 会为每个仍存在的废弃章节生成 product-deprecated-register finding(severity 为 mention)。"留着以防万一"恰恰是让退役的轴继续暗中影响当前输出的方式。

第四步:不要在真值漂移上过度断言

design-md-drift 统计的是自 DESIGN.md 上次编辑以来,视觉源目录上的提交数(源码见 staleness_deep.rscheck_design_drift)。视觉源目录固定为 srcapppagescomponentssitestylespublic 七个(VISUAL_SOURCE_DIRS),检查仅在两件事同时成立时触发:项目在 git 仓库内,且自上次编辑 DESIGN.md 的提交 HEAD..last 之间对上述目录的提交数 ≥ 阈值 25(threshold 参数)。提交数不是矛盾证据:要报告这个数字及其衡量对象,如果用户想知道文档是否真的错了,就把 DESIGN.md 与当前 tokens 和 components 逐一对照,基于对照结果回答。绝不要因为数字大就断言 DESIGN.md 过时了

同样的克制适用于 workspace-context-inherited:继承是设计好的行为(一个 workspace 继承仓库根的 PRODUCT.md 是刻意支持的),一条产品记录是否如实描述多个 app,是用户要回答的问题,不是需要修复的缺陷。

Monorepo 专项检查

monorepo 中 doctor 的 workspace 检查由 check_workspacesstaleness_deep.rs)驱动,要点如下:

  • workspace-platform-native-evidence 是最关键的 finding:某个 workspace 携带原生构建文件,却继承了解析为 web 的根记录,那么它整个生命周期都只会得到 web 指导,永远不会加载 ios.mdandroid.md。修复方式是在该 workspace 内写一份子级 PRODUCT.md——因为一条继承记录无法同时承载两个平台。原生证据的识别(staleness.rscheck_native_platform_evidence)检查两类信号:原生构建文件(pubspec.yamlios/Podfileandroid/build.gradleandroid/build.gradle.ktsios/Runner.xcodeproj)以及 package.json 中的原生依赖(react-nativeexpo@react-native/metro-config),并在有原生证据时建议 ## Platform 取值(ios / android / 多平台或混合时 adaptive)。
  • config-project-roots-match-nothing:表示 projectRoots 的每个 glob 都没有命中,仓库根被静默当作活动项目。重命名的 workspace 目录是常见诱因。报告这些模式并询问它们应该指向哪些目录。实现见 check_project_roots:只要存在一个非 ! 开头的正模式且候选数为 0,就触发该 finding。
  • config-invalid-build-pathconfig-build-path-unset 都围绕同一个键:.impeccable/config.json 中的 buildPath(或其 gitignore 的 .impeccable/config.local.json,后者对特定开发者生效)。它只接受 compcode 两个值(BUILD_PATH_VALUES),决定新 surface 是从生成的 comp 构建,还是直接在代码中构建:
    • config-invalid-build-path:值无效,无效值不会回退到另一条路径,而是回退到默认值,因此一个本意是 code 的项目可能一直在走 comp 主导的构建流程——必须报告确切值;
    • config-build-path-unset:仅在项目做过方向性工作(存在 .impeccable/surfaces.impeccable/mocks/decision,见 DIRECTION_WORK_PATHS)却从未记录偏好时触发;并且只有你的工具面存在图像生成能力时才应给出选择提议(comp-first 或 code-first 二选一写入 "buildPath": "comp" / "buildPath": "code",合并保留已有键)。没有图像生成能力就没有可选择的余地,保持沉默。
  • 在提出任何改动前,先用 workspaces 表向用户展示:哪些 app 携带自己的上下文、哪些继承、哪些完全没有(金标准输出见 tests/oracle/golden/doctor-monorepo-text.jsonapps/a product: child design: childapps/b product: inherited design: inherited)。

从源码看 doctor 的检查编排

doctor 的检查顺序固定(与 docs/CLI-CONTRACT.md 记载一致,见 doctor.rscollect):check_productcheck_native_platform_evidence(仅在存在 PRODUCT.md 时)→ check_design_sidecarcheck_design_driftcheck_design_coveragecheck_configcheck_build_path_unsetcheck_detector_ignorescheck_surface_briefscheck_hook_installationcheck_legacy_live_statecheck_project_roots → workspace findings。其中 boot 期基础检查(Tier 1,staleness.rs)与 doctor 专属深层检查(Tier 2,staleness_deep.rs)交错执行,既复用 boot 策略又保持既有顺序。

值得注意的检查细节:

  • 配置键白名单KNOWN_CONFIG_KEYS):hookdetectorupdateCheckstalenessCheckprojectRootsbuildPath$schemaversion。未知顶层键触发 config-unknown-keysdetector 对象的合法键为 ignoreRulesignoreFilesignoreValuesdesignSystemextensions,常见的 ignoreRule(少了 s)永远不会抑制任何东西(config-unknown-detector-keys)。
  • 忽略规则校验check_detector_ignores 会把 ignoreRules 中的 id 与内置注册表(staleness_deep.rsload_known_rule_ids,取自 impeccable_core::registry::ANTIPATTERNS)比对,未命中的触发 detector-ignore-rules-unknownignoreFiles 中不存在的路径触发 detector-ignore-files-missing
  • hook 健康检查check_hook_installation 按 provider 查找清单(claude-code.claude/settings.local.json.claude/settings.jsoncodex/agents.codex/hooks.jsoncursor.cursor/hooks.jsongithub.github/hooks/impeccable.jsongrok.grok/hooks/impeccable.json,见 context_cli.rshook_manifests_for),解析 hook 命令中的脚本路径(hook_markers.rshook_program_token)并检查文件是否存在:缺失则触发 hook-script-missing(hook 空转、UI 编辑一直未被扫描,但项目看起来"已覆盖"),修复方式是 impeccable hooks on 重装;清单已安装而配置设了 hook.enabled: false 则触发 hook-enabled-conflict
  • surface brief 孤儿检测check_surface_briefs 会找出 primary_target 指向已不存在文件、且不是 URL 或 route: 前缀的持久化 brief,触发 surface-brief-orphaned——在该 brief 重定向或删除之前,它仍是已消失文件的"权威"。
  • legacy live 状态.impeccable-live.json.impeccable-live 是退役位置(LEGACY_LIVE_PATHS),当前 live 模式写 .impeccable/live/ 下。旧位置只通过向后兼容回退读取,无 live 会话运行时可安全删除。

选择退出启动时检查

impeccable context 在会话启动时会报告这些 finding 的"廉价子集"(collect_boot_findings,只做 Tier 1 检查,不做需要 git 的深层检查),且按项目每周最多一次节流。节流实现见 staleness_notice.rsRENOTIFY_INTERVAL_MS 为 7 天,filter_fresh_findings 只放行距离上次通知超过 7 天的非 auto finding(auto 总是放行且不打时间戳),缓存默认落在 ~/.impeccable/staleness-check.json(可用 IMPECCABLE_STALENESS_CACHE 覆盖)。

退出方式有两种:

  • .impeccable/config.json 中设置 "stalenessCheck": false(永久关闭);
  • 设置环境变量 IMPECCABLE_NO_STALENESS_CHECK=1(仅本次会话)。

staleness_check_disabled 的判定是:环境变量非空,或任一 root 的 config.json / config.local.jsonstalenessCheck === false(后者优先,后读覆盖先读)。关闭检查不影响 doctor 命令本身——对于只想在主动询问时才看到报告的用户,这就是推荐组合:关闭启动检查,需要时手动运行 doctor

完整实操流程速查

  1. 确定项目根或 monorepo 目标:monorepo 中先 --target <path>
  2. 运行 doctor --json(或文本模式),一次性拿到全部 findings 与 workspaces 表;
  3. 空 findings → 一行汇报"无漂移"并结束;
  4. 有 findings → 按 auto / mention / route 三分组,全部汇报:auto 直接跑 doctor --fixmention 一句一句陈述,route 点名命令与缺口、仅在用户要求时执行;
  5. 任何 ## Register 等弃用字段按"不存在"处理并提议删除;
  6. design-md-drift 等真值漂移只报告数字与含义,不臆断文档错误;
  7. monorepo 中先把 workspaces 表摆给用户看,再谈任何改动。

doctor 的完整命令契约(参数、输入、输出格式、副作用、测试列表)可继续查阅 docs/CLI-CONTRACT.md,其行为由 oracle 金标准测试固化,如 tests/oracle/golden/doctor-legacy-fix.jsontests/oracle/golden/doctor-monorepo-roots-match-nothing.json 等。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
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
docsdocs
暂无描述
Markdown
899
5.83 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
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
525
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