怎样理解“要检查”
- 自动检查:脚本能判定,例如未声明依赖、类型错误、快照差异。
- 人工评审:需要读代码判断,例如卸载是否等待后台任务结束。
- 专项验证:仅在相关改动或工作流中执行,例如真实 API、Windows 打包、发布安装。
提交 hook 和推送 hook 只运行有限检查。本地根据改动范围补齐验证,CI 执行各工作流规定的检查。下面的执行条件区分这些责任。
代码与类型质量
代码能否被正确调用?后来的人能否安全修改它?
1.1 类型:把能提前发现的错误留在运行之前
1.01改了接口,所有调用方必须一起改
- 具体要求
- TypeScript 严格检查无错误;公共 API 变化后,仓库内每个消费者都按新接口调用。
- 为什么这样定
- 编译器能找出遗漏的调用方。只修函数本身,其他包可能仍在使用旧参数或旧返回值。
对照例子:返回值从 string 改成 { text: string },调用方应读取 result.text,不能继续调用 result.trim()。
适用条件:TypeScript 或接口发生变化;pre-push hook 自动执行 typecheck。
检查方式:自动:typecheck。
1.02包能编译,还要检查测试和脚本能否编译
- 具体要求
- 最新 build:artifacts 之后执行 build:check,或执行完整 build;不能只凭包产物生成成功就宣称类型验证完成。
- 为什么这样定
- 测试和仓库脚本会读取生成的声明文件,检查包源码不会自动覆盖所有这些消费者。
对照例子:源码接口已更新,但测试 helper 仍按旧声明构造参数;build:check 应发现这个错误。
适用条件:完成 TypeScript 改动的验证时。
检查方式:自动:build:artifacts → build:check;或 build。
1.03不能用新增 as unknown 掩盖类型不匹配
- 具体要求
- 不增加 as unknown 或 <unknown> 断言;已有基线只能保持或减少。保留的 any 要说明为何无法收窄。
- 为什么这样定
- 先转 unknown 再转目标类型,会跳过编译器对两个类型是否匹配的检查。
对照例子:不要把缺少必填字段的对象双重断言成请求类型;应补齐字段或在真实输入处解析。
适用条件:修改 TypeScript 时;CI 检查断言,评审检查 any 的理由。
检查方式:自动:verify-no-unknown-casts;评审。
1.04新增联合类型分支,处理代码不能漏掉它
- 具体要求
- 闭合判别联合的 switch 用 assertNever 保证穷尽;可通过声明合并扩展的联合使用有说明的默认处理。
- 为什么这样定
- 增加一种状态时,编译错误能指出所有尚未处理它的位置。
对照例子:增加 cancelled 状态后,结果展示必须处理它,不能悄悄当成 succeeded。
适用条件:增加或修改带判别字段的类型及其处理逻辑。
检查方式:类型检查+评审。
1.05不同用途的 ID 不能因为都是字符串就混用
- 具体要求
- 跨边界的 opaque ID 使用 branded type;函数参数保留具体 ID 类型。
- 为什么这样定
- 普通 string 无法区分会话 ID、任务 ID 和用户 ID,传错后通常要到查询时才暴露。
对照例子:getSession 接收 SessionId,不应接受一个类型为 JobId 的变量。
适用条件:增加跨包、服务或持久化接口的 ID 参数时。
检查方式:类型检查+评审。
1.2 代码形式:让静态检查有明确作用
1.06同一份代码遵守同一套 lint 规则
- 具体要求
- 暂存代码和 CI 检查的代码符合仓库 lint 配置;自动修复后确认实际提交内容。
- 为什么这样定
- 统一检查能稳定发现配置所覆盖的错误写法,减少 reviewer 逐行纠正重复问题。
对照例子:pre-commit 自动改了文件,开发者需要确认修改仍然符合原意。
适用条件:pre-commit 检查暂存文件;CI 执行完整 lint。
检查方式:自动:lint、lefthook。
1.07重复实现不能无限复制
- 具体要求
- 跨文件重复代码不超过 jscpd 配置门槛;确属同一逻辑的实现应考虑由一处维护。
- 为什么这样定
- 复制的逻辑会独立演进,修复一个位置时容易遗漏另一份。
对照例子:两个模块复制同一段解析逻辑,之后只在其中一个加了转义处理,就会出现不一致。
适用条件:增加或复制 TypeScript 实现时;CI 执行检查。
检查方式:自动:duplication。
1.08可导入模块不在顶层等待异步操作
- 具体要求
- 包内可导入源码不使用模块级 await;异步工作放入明确调用的函数,并处理失败。已声明的可执行入口有专门排除规则。
- 为什么这样定
- 顶层 await 会使所有导入者等待初始化,并把失败变成模块加载失败;也会影响浏览器 worker 的构建形式。
对照例子:不要 import 一个工具模块就开始等待网络请求;由初始化函数显式执行请求。
适用条件:新增模块或改变初始化方式时。
检查方式:自动:verify-no-top-level-await。
1.09公开函数要写出类型表达不了的使用要求
- 具体要求
- 函数类导出按规则说明参数和返回值,并说明非显然的失败、时序与资源责任;不逐句复述实现。
- 为什么这样定
- 返回一个 handle 的类型,并不能告诉调用者何时关闭、关闭后能否再用。
对照例子:函数创建子进程并返回句柄,文档应交代调用者是否负责终止它。
适用条件:新增或修改模块和公共导出时;doc-sync 检查 JSDoc。
检查方式:自动:verify-export-jsdoc;评审内容准确性。
1.10提交文件不带无意义的格式差异
- 具体要求
- 文件以一个换行结束,暂存 diff 通过空白检查;预期输出文件遵守仓库命名约定。
- 为什么这样定
- 多余空白和不统一命名会干扰 diff,增加查找和审阅成本。
对照例子:只改一行逻辑,却顺带留下尾随空格,应在提交前清掉。
适用条件:提交时检查暂存内容;文件名另有 CI 检查。
检查方式:自动:git diff --cached --check、Expected filenames 工作流。
架构与依赖约束
新功能放在哪里?谁负责配置、资源和清理?
2.1 包与启动:安装后的行为必须和声明一致
2.01用到的包必须由自己的 manifest 声明
- 具体要求
- 包名、目录、workspace 依赖范围符合约定;运行依赖完整声明;跨包导入使用包名。
- 为什么这样定
- monorepo 可能恰好能找到其他包安装的依赖,单独发布安装后却找不到。
对照例子:A 直接导入 B,就不能只靠根目录或另一个包安装了 B。
适用条件:新增包、修改 import、manifest 或依赖时。
检查方式:自动:constraints、verify-package-dependencies、verify-package-paths、verify-runtime-closure。
2.02声明为可选的依赖,缺失时不能拖垮模块加载
- 具体要求
- 发布源码不能静态导入可选依赖的运行时值;仅用类型时使用 import type。真正需要它的能力必须明确处理缺失。
- 为什么这样定
- 静态导入会在模块加载时解析依赖;缺一个可选包就让整个模块无法加载,违背“可选”的承诺。
对照例子:可选图像工具未安装,不应导致与图像无关的文本功能也无法启动。
适用条件:新增 optionalDependencies、可选 peer 或相关导入时。
检查方式:自动:verify-optional-dependency-imports。
2.03正式包要有使用方,实验包不能混进默认产品
- 具体要求
- 非 experimental 包有实际产品用途或明确分类;experimental 包保持在默认安装、运行导入和组合之外,声明的可选 bundle 例外按规则处理。
- 为什么这样定
- 没人使用的正式包仍会产生维护责任;默认启用实验包会把实验状态变成用户隐含依赖。
对照例子:不能为了以后可能用到就加一个正式包,也不能把实验插件直接加进默认 profile。
适用条件:新增包、调整 bundle 或默认 profile 时。
检查方式:自动:verify-product-use、verify-default-product-isolation、verify-official-bundle-catalog。
2.04应用统一从 dsh profile 启动
- 具体要求
- 受支持 Node 应用通过 dsh profiles 启动;不新增绕过它的 package bin、demo 或公共 SDK argv 入口。
- 为什么这样定
- profile 决定运行组合。多个独立启动入口容易加载不同插件、配置和初始化流程。
对照例子:演示某个能力时使用相应 profile,而不是另写一个绕过应用启动流程的脚本。
适用条件:新增启动方式、示例或可执行入口时。
检查方式:自动:verify-application-entrypoints;评审。
2.05配置写出的插件必须能被解析,参数必须由明确位置负责
- 具体要求
- Cordis 裸插件声明在相应 resolver manifest 的 dependencies 中;部署可调参数是经验证的 Config 字段;不能在 shipped 配置中随意内联凭据或 endpoint 环境读取。
- 为什么这样定
- 配置里写了一个名字不等于运行时能加载它;多处读取凭据和默认值会产生不一致行为。
对照例子:把重试次数写成模块常量,用户就无法按部署调整;应由所属插件配置解析。
适用条件:修改 cordis.yml、overlay、插件配置或 resolver manifest 时。
检查方式:自动:verify-cordis-config、verify-config-source-ownership;评审 Config 设计。
2.2 插件生命周期:功能要能装上,也要能卸下
2.06新行为通过扩展点接入
- 具体要求
- 新增能力通过已有的 Service Definition、Provider 和 Consumer 配合完成;修改 agent-loop 必须同步架构文档。
- 为什么这样定
- 把所有新行为塞进循环分支,会使可选功能无法独立组合、测试和卸载。
对照例子:新增一种工具执行方式,应提供对应实现并注册,而不是在核心循环里按工具名加特判。
适用条件:设计新能力或修改 agent-loop 的 PR。
检查方式:评审:architecture 与 defensive patterns。
2.07注册监听器时同时确定注销方式
- 具体要求
- 贡献通过 ctx.effect() / ctx.on() 管理;register 返回 disposer 或文档规定的清理句柄。
- 为什么这样定
- 插件会被卸载或重载。只注册不注销会让旧逻辑继续响应事件。
对照例子:重载三次后,一次点击不能触发三次处理;卸载时应移除之前的注册。
适用条件:新增事件监听、注册表贡献或其他持久副作用时。
检查方式:评审+对应卸载、重载测试。
2.08先结束使用者,再释放它依赖的资源
- 具体要求
- 后台任务、子进程和共享状态有明确所有者;清理要等待消费者结束,再关闭其使用的服务。
- 为什么这样定
- 仅调用 close 不代表异步任务已停止;任务可能继续访问已经关闭的数据库或管道。
对照例子:会话退出时,写入任务尚未结束就关闭数据库,会在 teardown 阶段随机失败。
适用条件:修改并发任务、共享资源、退出或 teardown 逻辑时。
检查方式:评审+生命周期测试。
2.09waterfall 中想继续处理,就必须调用 next()
- 具体要求
- listener 通过 next() 委派;直接返回意味着短路,只有确实想结束处理时才这样做。
- 为什么这样定
- 与普通广播事件不同,waterfall 的后续监听器不会自动执行。
对照例子:一个只想记录日志的 listener 忘了 next(),可能意外阻止真正的处理器运行。
适用条件:增加或修改 waterfall listener 时。
检查方式:评审+链式处理测试。
2.10错误配置和失败不能静默消失
- 具体要求
- 配置问题在加载期或最早可解析时失败;运行失败有处理者和用户可见报告;空 catch 说明忽略原因。
- 为什么这样定
- 继续执行会把最初的错误变成更晚、更难定位的错误,还可能使用不可信结果。
对照例子:配置引用不存在的 provider,应报告该引用,而不是跳过后让请求一直没有结果。
适用条件:修改配置解析、错误处理、重试或后台任务时。
检查方式:评审+失败路径测试。
2.3 客户端和网络:不要绕过已有运行条件
2.11浏览器代码不能无意间依赖 Host 实现
- 具体要求
- Host 与 Client 编译面和依赖关系保持明确;客户端包与领域依赖图通过检查。
- 为什么这样定
- 浏览器没有 Node 文件系统等能力;不恰当的跨层导入还会把整块服务端代码带入 bundle。
对照例子:客户端只需要共享类型,不应因此导入会启动子进程的 Host 模块。
适用条件:修改客户端包、共享导出或编译配置时。
检查方式:自动:verify-client-packages、verify-client-domain-graph;评审编译面。
2.12浏览器应用请求相对于当前文档解析
- 具体要求
- 浏览器访问应用自己的资源使用 document-relative 路径;内部路由注册键可以保留绝对 pathname。
- 为什么这样定
- 网站可能部署在 /workspace/ 等子目录;写死 /api 会请求域名根目录,跳出应用挂载位置。
对照例子:应用位于 /workspace/ 时,fetch("api/x") 与 fetch("/api/x") 不是同一个地址。
适用条件:修改浏览器请求、资源 URL、动态导入或相关 HTML 引用时。
检查方式:自动:verify-client-route-resolution。
2.13网络调用不能悄悄绕过用户代理
- 具体要求
- 普通调用不自行构造 undici Agent 或覆盖 fetch dispatcher;确需独立传输的地方按规则声明理由并使用代理感知机制。
- 为什么这样定
- 显式 dispatcher 会覆盖全局代理。用户已配置代理,某个功能仍可能直接联网。
对照例子:抓取网页的代码不能为了自己的连接设置而忽略应用的代理配置。
适用条件:修改 HTTP 传输或 fetch 配置时。
检查方式:自动:verify-no-bare-dispatcher。
2.14Vendor 更新保留可追踪的上游版本与本地修改
- 具体要求
- 按 vendor 同步流程更新固定版本,重新应用或明确移除记录中的本地修改,并运行规定测试与构建。
- 为什么这样定
- 直接改 vendored 源码但不记录,下一次同步可能覆盖修复,也难以判断与上游差在哪里。
对照例子:同步 Cordis 后检查本地补丁是否仍需保留,而不是只替换目录。
适用条件:修改 vendor 源码或更新上游版本时。
检查方式:自动:vendor manifest guard、rescope-vendor:check;专项:test 与 build。
行为正确性与回归
改动后的结果对不对?同样的检查下次还可信吗?
3.1 测试和快照:用结果说明行为
3.01行为变化要有能发现该错误的测试
- 具体要求
- 相关测试检查正常、错误和边界结果;不通过降低门槛或接受零测试来制造成功。
- 为什么这样定
- 测试只是执行了一遍代码,并不能证明结果正确。错误实现必须让断言失败。
对照例子:修复“取消后仍继续执行”,就检查取消后不再产生后续行为,而不是只检查函数没有抛错。
适用条件:普通推送前运行受影响测试;修改行为时同步调整过时测试。
检查方式:自动:所属 Vitest 测试;评审测试覆盖的行为。
3.02覆盖率按文件达标,不能用全仓平均值掩盖空白
- 具体要求
- 纳入覆盖率范围的包源码执行逐文件 100% 门槛;规定的重型豁免测试仍独立运行。
- 为什么这样定
- 一个大型文件被充分执行,不能抵消另一个新文件完全没被测试。覆盖率也不能代替有效断言。
对照例子:新文件的错误分支没有运行到,即使全仓总覆盖率很高也不能据此通过。
适用条件:CI coverage lane 执行;本地需要覆盖证据时同时指定测试与受影响源码范围。
检查方式:自动:test:coverage、coverage partitions;普通 test 不等价。
3.03模型或用户看到的非平凡变化,要有回放证据
- 具体要求
- 更新相应 recorded-session snapshot;通过正式 dsh profile 回放,并审阅预期输出差异。
- 为什么这样定
- 多个函数各自正常,不代表最终消息内容、顺序和持久化输出没有变化。
对照例子:工具返回值未变,但进入模型请求的消息漏了一段,应由完整会话回放暴露。
适用条件:修改非平凡的模型或产品用户可见行为时。
检查方式:自动:test:snapshot;评审快照 diff。
3.04普通预期输出和 Session 快照分开存放
- 具体要求
- 顶层 snapshots 保存 Session 输入与持久化输出往返案例;ARIA、布局、CLI、生成器等非 Session 预期存于所属测试旁。
- 为什么这样定
- 两类预期有不同的执行方式和维护者,混放会让人误以为它们验证了完整会话。
对照例子:CLI --help 的文本比较属于其测试目录,不应仅因它也是快照就放进 Session corpus。
适用条件:增加或移动 expected 文件时。
检查方式:评审目录归属;test:expected、test:web 或所属单元测试。
3.05循环和事件变化同时验证 TypeScript 与 Python SDK
- 具体要求
- agent-loop、session lifecycle、SessionEventMap 变化,同一 PR 更新两个 SDK 的预期输出并执行对应检查。
- 为什么这样定
- 两套 SDK 都投影同一套事件;只改 TypeScript 会使 Python 消费者收到不同或无法理解的结果。
对照例子:新增终止事件时,Python 的事件读取和预期也必须同步处理。
适用条件:修改上述循环、生命周期或事件定义时。
检查方式:专项:SDK expected outputs;Python keyless CI。
3.2 集成和可靠性:不只在 mock 中成立
3.06Provider 和系统能力使用真实执行路径验证
- 具体要求
- 运行受影响的真实 API、浏览器、子进程或内核隔离测试;缺少凭据时如实说明未执行。
- 为什么这样定
- mock 一般不会复现实际鉴权、内核权限、网络协议或进程启动失败。
对照例子:沙箱配置看起来正确,仍需在实际受限进程中验证禁止的操作确实失败。
适用条件:修改对应 provider、浏览器、subprocess 或 sandbox 能力时;按工作流与凭据条件执行。
检查方式:专项:test:e2e、provider 工作流、sandbox e2e。
3.07测试不能依赖其他测试留下的端口、状态或时序
- 具体要求
- 资源被可靠释放,全局状态恢复;并发、时钟和子进程风险按测试可靠性规范验证。
- 为什么这样定
- 同一测试单独通过、在 CI 并行时失败,常见原因是争用固定端口或清理未结束。
对照例子:关闭服务器后等待其真正退出,再允许后续测试使用相关资源。
适用条件:新增或修改持有资源、全局状态、异步 teardown 的测试与 fixture 时。
检查方式:评审;按风险补充恢复、负对照、静止状态或并发进程证据。
3.08跨平台差异先修 fixture,不靠宽泛归一化抹掉
- 具体要求
- 录制回放 fixture 满足目标平台约定;normalizer 不能无差别删除有意义的差异。
- 为什么这样定
- 过宽的替换可能让真实回归与正常平台差异一起消失。
对照例子:不能为了消除一个路径差异,把输出中所有路径都删掉,导致错误路径也被接受。
适用条件:快照在 macOS/Linux 等环境不一致时。
检查方式:评审 fixture 与 normalizer;对应平台回放。
3.09GUI 改动提供可操作的证据
- 具体要求
- 产品可见 GUI PR 附真实服务器和模型流程录制的 GIF;浏览器测试验证受影响交互。
- 为什么这样定
- 静态截图看不出菜单能否关闭、操作后是否有反馈、键盘焦点是否丢失。
对照例子:修改弹窗后,演示打开、操作与关闭的完整过程。
适用条件:PR 修改产品用户可见 GUI 行为时。
检查方式:专项:真实浏览器流程、GIF;评审 UI 与响应式规范。
3.10界面在窄屏、键盘和失败状态下仍可使用
- 具体要求
- 复用既有组件与视觉 token;检查溢出、触摸、icon-only 控件、tooltip、焦点、loading 和错误反馈位置。
- 为什么这样定
- 正常宽屏截图容易遗漏被截断的按钮、无键盘入口的菜单以及无反馈的失败操作。
对照例子:窗口变窄后不能只剩一个没有可访问名称、又无法触发 tooltip 的图标。
适用条件:修改客户端布局、菜单、overlay、控件或反馈流程时。
检查方式:评审+相关交互测试。
持久化与兼容性
用户升级代码后,磁盘上的旧数据会怎样?
4.1 持久化格式:变化需要明确记录
4.01持久化类型变化不能只改 TypeScript 文件
- 具体要求
- 声明的持久化类型变化有 acknowledgement;目录、类型历史和已发布记录检查通过。
- 为什么这样定
- 类型改变不会转换磁盘上已有的数据;记录变化后,reviewer 才能明确审查读取与迁移。
对照例子:把必填字段改名时,必须处理旧记录仍使用旧字段名的情况。
适用条件:修改声明的持久化类型时,同步处理变更记录。
检查方式:自动:verify-persistence-catalog、verify-persistence-changes、verify-persistence-releases。
4.02已经提交的数据代际保留原样
- 具体要求
- 可以新增版本命名的后继 generation,不移动、覆盖或删除已提交 generation;保留旧代际不等于承诺降级支持。
- 为什么这样定
- 用新数据覆盖旧数据,会失去验证升级能否处理旧格式的依据。
对照例子:迁移 fixture 时新增 successor,而不是把旧 fixture 内容直接改成新格式。
适用条件:迁移已发布 Session 数据或对应 fixture 时。
检查方式:评审+历史与格式检查。
4.03格式变化必须保证旧记录不会被当成另一种含义
- 具体要求
- 现有 discriminator 足以安全区分时可同版本演进;不足时升级 Session 格式。SQLite SCHEMA_VERSION 单调递增。
- 为什么这样定
- 最危险的情况不是读失败,而是读成功却解释错。
对照例子:字段仍是 number,但单位从秒变成毫秒,必须明确区分和处理旧数据。
适用条件:修改字段含义、事件解释、数据库 schema 或读取逻辑时。
检查方式:评审读取兼容性+迁移测试;verify-persistence-formats、verify-session-format-catalog。
4.04正式功能不能把重要记录写成可忽略的实验记录
- 具体要求
- 正式包声明自己的 Session 事件;appendPluginRecord 的生产调用限制在 experimental 包及规定的 owner 范围内。
- 为什么这样定
- 实验 plugin 记录在迁移中只有尽力保留的保证,不能承载正式功能必须保留的状态。
对照例子:正式工具的关键恢复状态不能只写成可能被忽略的 plugin: 记录。
适用条件:新增持久化事件或插件记录写入时。
检查方式:自动:verify-plugin-record-callers;评审事件定义。
4.2 可重建状态与外部用法
4.05发给模型的信息必须能从 Session log 重建
- 具体要求
- 新增模型可见输入对应 Session event;恢复或回放不依赖未记录的内存状态。
- 为什么这样定
- 如果日志里没有这些信息,回放无法复现模型当时看到了什么,也无法解释后续行为。
对照例子:运行时临时拼入一段隐藏上下文,却没有写入事件,会让保存的 Session 缺少关键输入。
适用条件:增加模型上下文或请求内容时。
检查方式:评审+Session 回放。
4.06Session 派生状态有统一的投影与恢复方式
- 具体要求
- 新建或扩展 projection 时按规范处理事件、状态所有权与恢复;不能在多个地方维护互相冲突的派生状态。
- 为什么这样定
- 实时运行和重启后恢复若使用不同规则,同一 Session 就会呈现不同状态。
对照例子:任务完成标志应能从相同事件恢复,而不是只存在某个 UI store 中。
适用条件:增加 Session projection 或把恢复状态迁入 projection 时。
检查方式:评审 session-projection 规范+对应测试。
4.07破坏旧用法时,升级指南写清用户要改什么
- 具体要求
- 外部可感知破坏性变化写入对应版本 upgrade guide;已有未发布指南覆盖的内容继续更新。
- 为什么这样定
- 仓库内调用方可以一起修改,用户保存的配置和脚本不会自动更新。
对照例子:配置键改名时,说明旧键、新键及迁移操作,不能只写“优化配置”。
适用条件:改变 CLI、profile、配置键、SDK/wire API、持久化数据或发布入口的兼容行为时。
检查方式:自动:verify-upgrade-guides;评审说明是否可操作。
文档与产品表达
读者照着说明做,能不能得到描述的结果?
5.1 说明与生成内容:防止事实漂移
5.01代码改了用法,README 和示例同时改
- 具体要求
- 受影响 README、JSDoc、CLI help 与当前行为一致;受检查的文档代码示例能编译。
- 为什么这样定
- 错误示例会把读者直接带到错误路径,即使实现完全正确也无法顺利使用。
对照例子:API 参数已改名,文档不能继续展示旧参数。
适用条件:功能或接口改变用法时;文档及相关注释变化在推送前执行 doc-sync。
检查方式:自动:doc-typecheck、verify-cli-help、README 相关检查;评审行为事实。
5.02生成清单必须对应当前源码,不手工维护另一份事实
- 具体要求
- 工具、配置、客户端、Cordis、依赖、插件、持久化、模块和文档图谱等生成内容与来源一致。
- 为什么这样定
- 手写清单会漏掉新增能力,或继续列出已经删除的能力。
对照例子:删除一个工具后,工具目录中不能还出现它的参数说明。
适用条件:更改生成内容的来源或生成器时,重新生成并检查。
检查方式:自动:各 verify-*-catalog、verify-doc-graphs、verify-module-graph、verify-tsconfig-paths;workflow guest 和 type-equiv 检查。
5.03链接、锚点、图表和网站要能实际使用
- 具体要求
- 受检查的本地链接、公开仓库引用和站点片段有效;Mermaid 与文档站构建通过,站点交互测试通过。
- 为什么这样定
- Markdown 在编辑器中看起来正常,不代表发布后的路径、图表和目录可用。
对照例子:移动章节后,旧锚点仍被引用就会让导航失效。
适用条件:增删移动文档、修改图表或网站投影时。
检查方式:自动:链接/引用/片段检查、verify-mermaid、docs:build 与网站测试。
5.04文档写使用事实,不保留设计讨论过程
- 具体要求
- 内容符合所属文档职责和篇幅预算;注释描述行为、失败与责任,避免过时评审引用、重复代码和含糊术语。
- 为什么这样定
- 读者需要知道现在怎么用,不能被已放弃方案和过去的讨论引导到错误结论。
对照例子:“因为上次 review 建议,所以这里……”应替换为当前成立的具体使用条件。
适用条件:编写 README、注释、说明或 Agent Notes 时。
检查方式:自动:verify-doc-budgets、verify-concrete-terms、verify-md-wrap、doc standard;评审语义。
5.2 语言、记录和图形资源
5.05产品文案从本地化字典取得
- 具体要求
- 用户可见文本使用 typed dictionary、t 或本地化 primitive props;locale keys、插件语言元数据和安装器 locales 满足检查。
- 为什么这样定
- 硬编码一段英文会让其他语言界面出现混杂,也无法由翻译维护者统一更新。
对照例子:新增按钮不能直接写死英文文本,而应增加字典项并通过本地化接口引用。
适用条件:新增或修改客户端产品文案和语言资源时。
检查方式:自动:verify-client-ui-i18n、locale 字典及 metadata、installer locale 检查。
5.06成对文档和翻译记录同步更新
- 具体要求
- 双语文档按配对规则更新对应内容并记录;翻译 prompt 和 skill 调用元数据满足规则。
- 为什么这样定
- 只改一种语言会让两组读者拿到不同的操作方法,配对记录用于识别是否同步。
对照例子:英文删除了一个配置项,中文不能继续推荐它。
适用条件:修改已有双语内容或相关翻译元数据时。
检查方式:自动:verify-translation-pairing、verify-translation-prompt、verify-skill-invocation-metadata;评审译文。
5.07Agent Notes 只保留有后续决策价值的理由
- 具体要求
- 新记录有正确分类和格式;小型机械性变化不记成长久决策;被取代的 active 记录需处理,冻结归档不再编辑。
- 为什么这样定
- 大量流水账会让真正的重要约束难以找到,过时 active note 会与新规则冲突。
对照例子:“按钮向左移动 4px”通常无需长期 note;选择某种持久化策略的限制可能需要。
适用条件:新增、修改、归档或清理 Agent Notes 时。
检查方式:自动:分类、格式和归档检查;评审保留价值。
5.08图标元数据正确,新增官方 glyph 经过设计确认
- 具体要求
- 资源能被包 exports 和发布文件选中;官方 artwork 符合规范,新 glyph 在落地前取得 designer approval。
- 为什么这样定
- 源码里能显示图标,不代表安装包带上了它;视觉含义和辨识度也不能只靠文件格式检查。
对照例子:图标文件存在但未被发布配置包含,用户安装后就会缺图。
适用条件:修改包图标、官方插件 artwork 或资源导出时。
检查方式:自动:verify-package-meta;专项设计评审。
构建、交付与运行质量
源码通过检查后,用户拿到的安装包是否真的可用?
6.1 源码与产物分别验证
6.01源码检查不暗中依赖上次构建的文件
- 具体要求
- 静态 gate 和源码测试经 tsconfig paths 解析 src;读取 lib 的检查明确依赖构建完成。
- 为什么这样定
- 工作区残留的旧声明或 bundle 可能让本机通过,而干净 CI 检出后失败。
对照例子:源码测试不能碰巧因为昨天生成的 lib 还在就成功。
适用条件:修改测试、静态 gate、编译面或构建依赖时。
检查方式:评审 source/artifact 分离;相关编译和 gate 测试。
6.02从包消费者角度检查导出和类型
- 具体要求
- 产物通过 publint 与 NodeNext consumer 检查;包 exports、类型声明和文件布局对应实际发布内容。
- 为什么这样定
- 仓库路径映射可能绕过真实 package exports,从源码成功导入不能说明外部消费者也成功。
对照例子:包根导出指向不存在的 .js 文件,源码测试仍可能通过,安装消费者会失败。
适用条件:修改 manifest、导出入口、声明文件或构建配置时。
检查方式:自动:publint、verify-node-next-types、hygiene。
6.03关键进程从构建产物实际启动一次
- 具体要求
- 相关 built smoke 使用 lib 或实际入口启动 CLI、worker、SDK server、子进程等,不仅导入源码。
- 为什么这样定
- 错误文件路径、ESM/CJS 差异和漏打包 worker,通常只在实际启动时出现。
对照例子:worker 文件没有进入 lib,只有启动它才能发现 ENOENT。
适用条件:修改可执行入口、worker、built runtime 或包导出时。
检查方式:自动:built-bin smoke;源码启动另有 source compatibility smokes。
6.04发布前安装真正生成的 tarball
- 具体要求
- release version 校验、pack 和 packed install 验证通过;依赖布局符合 npm 安装政策。
- 为什么这样定
- workspace 能通过软链接找到源码,用户只能拿到压缩包中的文件和声明的依赖。
对照例子:README 引用的配置模板留在源码树却没进 tarball,用户安装后无法使用。
适用条件:对应 release 工作流;本地修改发布布局时做相关验证。
检查方式:专项:release:verify、release:pack、release:verify-packed-install、verify-npm-install-layout。
6.2 平台、性能和发布材料
6.05平台结果区分必需检查和观察性诊断
- 具体要求
- 目标 Node 与操作系统的 required jobs 成功;Windows 部分 observational 检查只报告诊断,不能把其结果等同必需检查。
- 为什么这样定
- 平台差异必须验证,但每项诊断的阻塞政策不同;仅看任务数量或一个绿色 job 会误判。
对照例子:Windows production build 失败与一个 allow-failure 诊断失败,合并影响不同。
适用条件:对应 CI 工作流触发时;本地只运行与改动相关的验证。
检查方式:自动:Node compatibility、Windows、macOS/Linux、native 与 Python runtime lanes。
6.06性能变化用测量判断
- 具体要求
- 基准满足配置门槛;性能优化给出可复算的前后数据;内存、Web 压力等按所改场景选择。
- 为什么这样定
- 功能测试通常只检查结果,不会因为耗时从一秒变成十秒就失败。
对照例子:声称减少长会话内存,需要用同样的长会话负载比较,而不是只看代码少了几行。
适用条件:CI benchmark lane;性能敏感 PR 按影响增加相关测量。
检查方式:自动:check:ci:bench;专项 Web perf、stress、memory;评审测量条件。
6.07打包后的安全和系统能力仍需执行验证
- 具体要求
- 沙箱在真实内核下达到预期隔离;pack → install 后仍能隔离;原生、桌面、SSH helper 等按对应产物流程验证。
- 为什么这样定
- 限制策略或 native 文件可能在打包后丢失,源码环境的安全测试不能替代安装形态测试。
对照例子:打包后 sandbox launcher 缺失,不能仅凭源码测试曾通过就认为分发版本仍受限。
适用条件:修改 sandbox、native、桌面或平台产物路径时;对应专项 workflow。
检查方式:专项:sandbox packed-distribution e2e、native/desktop/helper 工作流。
6.08依赖、许可证、版本和签名材料可重复核对
- 具体要求
- CI frozen-lockfile 安装成功;包许可证与第三方声明准确;发布版本和适用的桌面签名要求通过验证。
- 为什么这样定
- 依赖临时重新解析会改变构建输入;遗漏许可证或签名材料会影响合法分发或系统安装。
对照例子:不能把缺少依赖的 CI 靠自动改 lockfile“修好”;应提交一致的依赖变更。
适用条件:依赖或声明变化时;版本、签名在对应发布流程中检查。
检查方式:自动/专项:frozen install、verify-dsh-package-licenses、third-party notices、release 与平台签名流程。
评审与协作治理
什么证据支持合并?谁确认了变更,失败如何处理?
7.1 PR 信息和审批
7.01PR 描述对应最终改动,验证只写实际做过的
- 具体要求
- 说明问题、行为变化、Issue、实际验证和 AI 使用;处理 review 或改变范围后更新描述。
- 为什么这样定
- reviewer 根据描述判断要看什么。旧描述或夸大的测试声明会把风险藏起来。
对照例子:只运行一个测试文件,就写该文件,不写“全部测试通过”。
适用条件:创建、修改 PR 及处理 review 后。
检查方式:评审:dsh-pr-description 要求,包括 AI 使用披露。
7.02关联真实 Issue,标签说明变更类别与影响范围
- 具体要求
- 适用 PR 至少引用一个本仓库 Issue,恰有一个合法 kind、至少一个 area、最多一个 p0–p3;PR 编号不算 Issue。
- 为什么这样定
- 维护者需要追溯需求和判断谁应评审,不能靠标题猜测背景和影响范围。
对照例子:Refs #123 指向一个 PR 时,不满足真实 Issue 关联要求。
适用条件:Issue policy:非草稿、人工作者且有请求或已提交 review 的 PR;其余按豁免规则处理。
检查方式:自动:Issue policy。
7.03声称解决 Issue 时,优先级不能与解决对象冲突
- 具体要求
- Fixes/Closes 等 resolving 引用按 Project Priority 校验;普通 Refs 只建立上下文,不要求相同的 Project 读取。
- 为什么这样定
- 真正关闭的问题决定这次修复的优先级,普通背景引用不应额外强迫依赖 Project 数据。
对照例子:PR 关闭多个 Issue 时,Priority 要符合其中最高优先级的规则。
适用条件:适用 PR 包含 resolving Issue 引用时。
检查方式:自动:Issue policy;缺少必需 Project 访问时失败,不静默跳过。
7.04审批达到分数,还必须没有阻塞意见
- 具体要求
- weighted approval 至少 2 分;PR 非草稿;没有有写权限 reviewer 的有效 changes requested。作者自己的 review 不计分。
- 为什么这样定
- 足够的认可不应掩盖尚未解决的反对意见;草稿也不代表作者已经准备合并。
对照例子:两分 approval 已满足,但另一位有权限 reviewer 请求修改,策略仍不通过。
适用条件:审批工作流订阅的 PR、review 和相关委派事件后重算。
检查方式:自动:weighted approval。固定权重、代码所有权与作者历史贡献按政策计算,作者分不能单独达标。
7.05委派审批不能凭复制评论或重复计分实现
- 具体要求
- /delegate 校验双方权限、评论作者及编辑者;每人的点数最多贡献一次,撤销和后续 review 按规则重算。
- 为什么这样定
- 审批代表具体人的责任。未经授权的编辑或重复委派不能凭空增加通过分数。
对照例子:他人编辑评论加上 /delegate,不应转走原作者的审批权重。
适用条件:使用 PR 会话评论委派审批时。
检查方式:自动:委派身份、事件和计分检查;approval policy 测试。
7.06写入合并状态的工作流使用可信代码
- 具体要求
- 审批及 Issue 策略从可信默认分支运行;数据读取或计算失败要给出失败/错误状态,不能留下虚假的成功。
- 为什么这样定
- 若 PR 可以修改自己要通过的检查脚本并以高权限运行,就可能自行绕开合并要求。
对照例子:历史读取不完整导致算不出审批分数,应报错,而不是当成已达标。
适用条件:相关策略工作流执行或维护时。
检查方式:自动:workflow 与 policy 测试;branch rules 应要求规定来源的 status。
7.2 推送和合并:证据必须对应当前代码
7.07本地按改动选检查,不假定 hook 已经全测
- 具体要求
- 普通推送前完成受影响行为、文档、快照或产物验证;pre-push 只有 typecheck,不替代这些检查。
- 为什么这样定
- 类型正确不能说明业务行为、旧数据或安装产物正确。每次全跑也会消耗大量无关时间。
对照例子:只改文档应跑相关文档检查;改 worker 路径则还需要 built smoke。
适用条件:普通推送前按 live base 的完整 diff 选择证据;已通过且未失效的检查不因提交再跑一次。
检查方式:流程:dsh-pre-push-checks;自动 hooks 保持窄范围。
7.08失败就修复或报告,未运行不能写成通过
- 具体要求
- 相关失败阻止普通推送;CI pending 如实标注;环境问题提供具体失败证据,不能只说“应该是 CI 的问题”。
- 为什么这样定
- 把失败交给下一位开发者,会让真正的问题越来越难与环境噪声区分。
对照例子:缺少 API key 就说明真实 API 测试未执行,不能把自跳过等同验证成功。
适用条件:本地检查或 CI 未成功时。
检查方式:流程与评审;hook 绕过需明确授权。
7.09重写历史时不能覆盖他人刚推送的提交
- 具体要求
- 记录已观察的远端 OID,用 force-with-lease 保护;远端移动则中止,禁止裸 force。
- 为什么这样定
- rebase 改写提交 ID,直接强推可能把同事的新提交从分支上覆盖掉。
对照例子:你 rebase 时同事又 push 了一次,lease 应使你的旧预期推送失败。
适用条件:发布重写过的分支历史时。
检查方式:流程:精确 lease,或官方 stack 工具的 lease 保护。
7.10依赖 PR 按 stack 管理,sync 后重新验证
- 具体要求
- 同仓库依赖链使用官方 stacked PR;sync 后重新获取各层 head/base,检查受影响变化,验证完成前不合并。
- 为什么这样定
- 同步可能把新基线带进多层分支,之前通过的结果不能自动证明新的组合正确。
对照例子:底层 API 改变后,上层即使自动 rebase 成功,也可能调用错误接口。
适用条件:同步或合并有依赖关系的 PR 时;sync 是先发布再立即验证的专门例外。
检查方式:流程:官方 stack + post-sync validation。
7.11检查系统本身也有测试和执行顺序
- 具体要求
- gate 图依赖有效;读取产物前构建成功;共享产物的写入不与读取冲突;必需 job 汇总检查其成功状态。
- 为什么这样定
- 并行构建覆盖正在读取的声明文件,会制造偶发错误;错误的汇总也可能把漏跑当成功。
对照例子:一个 Web 热更新测试会重写 lib,就不能与仍在读 lib 的检查任意并行。
适用条件:修改 gate runner、CI 工作流、并发度或构建消费者时。
检查方式:自动:run-gates、workflow、approval/Issue policy 回归测试;聚合状态检查。
用一次改动串起来
假设给工具增加一个“超时”参数,可以依次问:
- 参数类型和调用方改齐了吗?——类型检查。
- 超时值由配置解析,还是散落在实现中?——配置归属。
- 超时之后,任务和子进程真的停止了吗?——生命周期测试。
- 用户和模型收到的失败说明正确吗?——交互与快照。
- 如果保存了新字段,旧 Session 怎么读?——持久化兼容。
- 文档和发布产物是否带上了这项能力?——说明与交付。
每条检查都应能回答一个具体问题:如果违反这条规则,什么对象会在什么场景下出错?