搜索/让AI在大型代码库中先读代码再修改,并只通过评审来发布

让AI在大型代码库中先读代码再修改,并只通过评审来发布

在包含多个包的大型代码库中让AI代理工作时使用。它会在判断修复前先读代码、依赖项和测试,每件事只保留一种做法,绝不在本地运行不可信的代码,并且只通过评审和你的批准来修改共享代码。

要使用这个AI规则
## 先读根级规则,再读所在目录的指南 根文档只保留硬性策略和路由规范;各领域的详细工作流程由对应范围的指南负责。在某个子目录中开展工作前,先阅读该目录所属的指南。 ### 每类规则只有一个归属地 硬性策略、跨领域的边界规定,以及"哪个指南负责哪部分"这类信息都放在根文档中。具体任务的操作流程则放在管辖相应代码的范围指南里。不要把同一套工作流程在两个地方重复描述,否则两份内容会逐渐产生偏差。 ### 按仓库的方式引用代码 引用文件时使用相对于仓库根目录的路径,而不是绝对路径或用户主目录路径,这样每个读者看到的引用都指向同一个含义。 ## 自己动手做之前,先找现成的库或工具 在提出或构建自定义系统、功能、工具、集成或自动化流程之前,先做一次轻量级检查,看看是否已有现成的库、插件或免费平台能够很好地解决这个问题。 ### 优先选择成熟方案 如果现有方案已经够用,就直接使用。只有在现有方案不合适、成本过高、无人维护、不安全、不合规,或用户明确要求自定义构建时,才自行开发。 ### 让检查保持轻量 这只是一道简短的前置检查,不是一项调研任务。除非用户已批准相应支出,否则不要推荐付费服务。 ## 不只看差异,读完调用方、被调用方和测试再评审 修复、问题分诊和代码评审都需要通过阅读来获得高置信度,而不是仅凭可见的改动去猜测。只看差异(diff)的评审是不够的。 ### 下结论前先通读整个相关范围 在判断"好""坏""最佳修复方案"或"证据是否充分"之前,要通读整个被改动的函数或模块,以及它的调用方、被调用方、同类实现、相邻测试、范围内文档,还有它所依赖对象的契约。 ### 构建一份简明的证据图谱 明确列出被改动的范围、它的入口点、所属边界、至少一个调用方和一个被调用方、共享同一不变量的同类范围、现有测试,以及当前已上线的行为。如果其中任何一项缺失,就明确说明这个空缺,而不是直接下结论。 ### 被质疑时先阅读再辩护 当结论受到质疑时,先去查看之前遗漏的部分;在实际查看之前,不要急于为原先的结论辩护。 ## 直接读依赖项的源码,并实际测试外部API 当某个行为依赖于某个库或外部服务时,要对照真实对象进行验证,而不是依赖记忆、封装层、自动生成的schema,或另一个代理的报告。 ### 阅读依赖项自身的源码 对于依赖项支撑的行为,要直接阅读上游的源码、文档或类型定义,并注明你查看了什么。大多数依赖项都是开源的,因此没有理由靠猜测来判断默认值、错误信息或时序问题。 ### 对外部服务进行实测 涉及外部API的工作需要进行实际测试,并附上当下可引用的证据;不要凭记忆对API行为下断言。只要条件允许就要进行实测验证,且在此过程中绝不能打印任何密钥信息。 ## 判断修复是否最佳,而不只是能用 评审结论必须判断这个改动是否是最佳修复方案,而不仅仅是"恰好能用"的方案。在下结论之前,要比较所属边界、调用方、同类实现、测试情况以及当前行为。 ### 片面的修复需要同类范围的佐证 如果一个修复只涉及某一个范围而没有涉及它的同类范围,就需要证明这些同类范围不受影响,或者明确安排后续工作来覆盖它们。 ### 不要把个人偏好当作问题上报 如果改动后的代码遵循了其范围指南,且不存在用户可见、运行时、安全或维护方面的风险,就不要仅仅因为纯粹的仓库风格偏好而提出问题。 ## 配置只保留一种读法,旧键要迁移而不是丢弃 运行时只读取当前权威格式的配置和数据。对于旧的或格式错误的键,不存在静默兼容这回事。 ### 删除旧路径 优先保留一条权威路径并删除旧路径,除非能引用明确的已发布契约或已标记的升级路径。如果一次重构还留下了第二条路径,这次重构很可能是失败的。 ### 要做迁移,绝不静默丢弃 如果某次改动会使现有配置失效,就要在专门的迁移或修复步骤中添加相应的迁移逻辑;绝不能静默丢弃某个键,因为丢弃一个键就意味着一次隐藏的行为变更。 ### 让配置界面保持精简 配置和环境相关的界面有很高的准入门槛。在新增一个选项之前,要先证明现有行为无法解决这个问题,并且优先考虑删除或合并选项。要把已写入文档的配置流程当作对兼容性敏感的内容:优先使用新增式的开关,而不是破坏现有的配置片段。 ## 模块专属的处理放在该模块里,不放进共享代码 共享代码和核心代码应保持通用;特定归属方的行为应放在其所属的模块中。跨越边界时只能通过有文档记录的公开接口,绝不能直接深入到另一个模块的内部实现中。 ### 转移职责,而不是包装职责 默认的修复方式应该是一次干净、有边界的重构:把逻辑迁移给正确的归属方,并删除过时的抽象、重复的策略和无用的分支,而不是打一个尽可能小的补丁。 ### 正确,但不过度设计 对真实输入和状态保持正确性是必须的;为了应对臆想中的输入而增加的额外层级和防护措施是缺陷,而不是严谨。当你为了换取真正的简洁性而放弃某个不太可能出现的边界情况时,要明确指出这个取舍,让它成为一个有意识的决定,而不是疏漏。 ## 运行时状态放在项目指定的存储里,不另存零散文件 把运行时状态保存在项目的权威存储中。不要把本应由该存储管理的状态、缓存、队列、索引或临时数据分散到各处的附属文件里。 ### 旧格式由迁移逻辑负责 遗留的文件存储和已淘汰的数据格式,只应在运行时之前的迁移或修复代码中进行规范化处理;处于稳定状态的运行时绝不应读取回退位置的数据。 ### 绝不擅自单方面升级schema版本 如果某次schema版本变更会导致旧版读取方无法兼容,就必须先与用户明确讨论并取得同意,绝不能自行推进版本升级。而纯粹新增、旧版本构建仍能兼容的改动,则不需要升级版本号。 ## 复用之前查好的信息,不在每次请求时重新查找 热路径应该携带此前已解析好的事实数据向下传递,而不是在每次请求时重新去发现这些信息。 ### 解析一次,反复使用 将标识符、已解析的路径和能力相关的事实数据向下传递,并复用已准备好的对象。不要通过在各处散布缓存来解决请求时的重复发现问题;而应把权威事实数据提前准备好,并删除重复的查找逻辑。 ### 循环中不做新鲜度轮询 安装信息、清单文件、已解析路径等在进程生命周期内保持稳定的元数据,只会在重启或明确的重新加载时发生变化,因此热路径不应通过重新读取或重新计算哈希来检查其新鲜度。只有当进程本地缓存有明确的生命周期归属并且是有边界的时候,才可以使用它。 ## 用严格类型写简短易读的代码 保持严格类型检查处于开启状态,并让代码保持"诚实"。目标是写出精简清晰的代码,而不是追求最小的差异量。 ### 为边界设定类型,让分支保持封闭 避免使用万能的动态类型;优先使用真实类型和范围明确的适配器。用schema来校验外部输入。分支判断应基于可辨识联合类型或封闭的结果代码,而不是自由格式的字符串或哨兵值,并让不可能出现的状态在类型层面上就无法表示。 ### 为可读性而组织结构 优先使用提前返回,而不是层层嵌套的金字塔结构,并把工作拆分为收集、规范化、决策、执行四个阶段。让调用点保持"平淡无奇":复杂的决策发生在上层,因此传入的参数应始终是名称、字面量或简单的读取值。 ### 只为不明显之处写注释 只有在解释不明显的不变量、顺序约束、归属边界或清理耦合关系时,行内注释才有存在的价值:用一到三行说明这个分支为什么存在,以及删除它会导致什么问题。不要做语法层面的复述。 ## 重构让代码变长时,要删减或说明理由 一次重构删除的局部复杂度应该大致等于它新增的复杂度。生产代码行数净增长是一种需要说明理由的异味,而不是理所当然可以接受的默认结果。 ### 收尾前检查改动规模 在完成一次有一定规模的重构之前,要对比改动前后的规模;如果非测试代码增加了,就要精简它,或者明确说明为什么路径变少了、代码行数却反而增多了。 ### 让新增的接口"物有所值" 新增的辅助函数或文件必须能立刻减少调用路径、概念数量或重复逻辑。不要为了一次性的兼容处理、字段改名或臆测中的容错需求而新增它们。保持公开接口的精简,并返回最小可用的数据形态。 ## 测试行为而不是文字,并让每个测试彼此独立 测试的作用是证明行为并防止回归,而不是为了给每一个内部分支打勾。 ### 测试行为,而不是措辞 优先编写行为测试,而不是靠搜索文档字符串或策略字符串来做测试;把给操作者的提醒信息放在文档里,而不是放进测试断言中。在合入之前审查新增的测试,并删除价值低的测试,包括那些针对你刚刚移除的路径所写的测试。 ### 保持测试的独立性和真实性 要清理定时器、环境变量、全局状态、mock对象和临时状态。mock必须导出真实代码所用到的每一个绑定,包括在身份判断中用到的错误类型。未经批准,不要通过修改基线文件或快照文件来让检查静默通过。 ### 在真实状态的副本上进行测试 当真实数据很重要时,要把状态复制到一个临时位置再对副本进行测试;未经明确批准,绝不能直接原地修改线上服务的状态。 ## 不在本地运行不可信的代码,繁重的构建交给远程执行环境 在决定需要证明到什么程度之前,先对来源的可信度进行分类,并根据这个可信度来决定验证在何处进行。 ### 绝不在本地运行不可信代码 对于可信来源,在依赖就绪的情况下,可以在本地运行少量有针对性的测试和成本较低的静态检查。对于不可信来源或外部贡献的代码,无论需要验证的规模多小,都不能在本地运行它自身的脚本、测试、钩子或配置;应改用隔离且不带凭证的执行环境。 ### 把繁重的工作交给远程执行环境 完整的测试套件、构建、类型检查、打包以及跨平台验证都应交给远程执行环境去完成:在第一次执行繁重命令时按需获取,在同一会话中复用,并在交接前释放。如果远程执行环境不可用,可信的工作可以回退到本地执行;不可信的工作则绝不能这样做。 ### 用一次全新的评审来把关合入 在合入之前,要运行一次全新的自动化评审,直到不再有可处理的问题为止;除非改动范围很小,或用户明确选择跳过,否则不要仅凭持续集成显示为绿色就合入代码。如果验证工作受阻,要准确说明缺少了什么、原因是什么。 ## 按项目流程提交issue和拉取请求,发布前先取得批准 修改共享界面是一种"社会性行为":要遵循项目的贡献流程,并为每一个不可逆的步骤取得批准。 ### 遵循评审与合并流程 在提交任何内容之前,先阅读贡献指南、issue和pull request模板,以及代码所有者文件。对于bug、面向用户的功能和架构决策,要先创建一个issue。撰写内容详实的pull request正文,说明问题、影响和证据,并在进行任何变更之前,通过平台自身的工具核实线上的实际状态。 ### 未经请求,不做任何不可逆的操作 未经要求,不要添加标签、修改标题、变基或合入代码。除非用户明确要求发布,否则要先把公开评论以草稿形式展示出来,并且每一条已发布的评论都要附上对应的链接。issue和pull request相关的工作结束时,要给出完整的条目URL。 ### 保持提交和分支的整洁 只提交预期内的文件,并使用简洁、分组清晰的提交信息;在推送之前先基于最新的主线进行变基,并且绝不删除或重命名意料之外的文件。在同一次改动中让文档与行为保持同步,发布日志则留给发布流程去处理。 ### 发布和密钥相关操作需取得批准 发布、版本号升级以及依赖项或锁定文件的变更都需要明确的批准。绝不能提交真实的凭证或线上配置,密钥应保存在指定的存储中。