OP Stack 删除式评审方法论:如何证明被删除的外部名字与状态写入没有留下残骸
OP Stack 删除式评审方法论如何证明被删除的外部名字与状态写入没有留下残骸【免费下载链接】optimismOptimism is Ethereum, scaled.项目地址: https://gitcode.com/GitHub_Trending/op/optimism本篇基于 OP Stack monorepo 的删除式代码评审规范deletion-reviewer代理定义及其指定的方法文档展开讲解当一次 diff 删除公开符号、wire 字段、指标、配置键或状态写入时如何系统性地证明没有任何引用者被静默降级、也没有任何存留状态失去覆盖。读完本文你能掌握该 monorepo 中删除类 PR 的完整评审流程全树引用清扫、存活写入者触发窗口分析、连带清理清单、依赖工作区级联检查以及评审输出的标准格式。1. 删除式评审解决什么问题删除与新增的失败模式不同。删除一个东西时编译器已经证明了没有任何代码还需要它——一旦编译通过泛型代码评审看看有没有漏改就到此为止了。但删除真正会咬人的是两类编译器永远看不见的问题这正是 docs/ai/deletion-review.md 所定义的两大检查目标代码之外的引用仍然存活公开文档、Grafana 仪表盘、CI 配置、脚本里以字符串形式引用的名字删掉后不会报编译错误只会静默地失效被删除代码曾是某份状态的唯一/部分写入者删掉后其余写入者存在不等于覆盖某些时间窗口内该状态会悄悄变陈旧。2. 何时触发删除式评审根据 docs/ai/deletion-review.md当 diff 删除以下任意一类内容时本评审适用公开符号类型、函数、事件、枚举变体、接口方法、参数wire 名字RPC 方法名、JSON 响应字段、WS 订阅指标名或指标标签值label value——注意不是指标名也常常不是问题单个 label 值如labellocal-safe被删同样会击穿依赖它的查询配置键、CLI flag、环境变量测试或子测试名称。3. deletion-reviewer 代理使命、方法与边界方法由 .claude/agents/deletion-reviewer.md 中定义的deletion-reviewer代理执行。其 frontmatter 声明如下name: deletion-reviewermodel: opus使用最强推理模型执行该评审description评审删除东西的 diff——公开符号、wire/RPC 字段、指标名或 label 值、事件、配置键、CLI flag。抓住泛型评审漏掉的两种失败模式代码之外仍然存活的引用文档、仪表盘、示例、CI 配置以及剩余写入者未必在删除者覆盖的每个窗口内触发的状态写入。用于在提交任何移除外部可观察名字或向存留状态写数据的 PR 之前。该代理文件本身刻意保持精简其核心约定是方法唯一来源是 docs/ai/deletion-review.md——每次先读它并遵循它它是 single source of truth本文件永不覆盖它。在没有该代理支持的 harness 下开发者也可以直接按方法文档手工执行评审。代理在大纲层面执行四个动作建立删除清单代码形式 字符串形式、执行全树引用清扫及其三分类、执行删除写入分析存活者何时触发而不是它们是否存在、应用连带清理与误报陷阱规避。根目录 AGENTS.md 也将其索引为官方评审指南之一说明它是仓库 AI 工程流程的一部分与.claude/agents/下的 go-code-reviewer、rust-code-reviewer、ci-config-reviewer 等语言型评审代理并列。4. 检查一引用清扫必须越过代码边界方法是先把删除物建成删除清单deletion inventory同时记录它的代码形式和字符串形式JSON 键、指标 label 值、方法名、子测试名然后在整棵树上清扫。编译器看不见的引用点按被遗漏的频率从高到低排列公开文档docs/public-docs/字段列表和示例 payload——一个 JSON 示例会在代码围栏里把同一个 wire 字段再嵌入第二次只查字段表会漏掉它Grafana 仪表盘与监控配置**/grafana/**/*.json删除一个指标或 label 值会让某个 panel 永久绘制一条空序列。当仪表盘存在成对副本时必须保持逐字节一致。 仓库中正好有这样的成对副本kona-node 仪表盘 与 kona-node-dev 仪表盘经diff验证两者当前逐字节相同。且该仪表盘的 PromQL 大量依赖 label 值例如kona_node_block_labels{label~local-safe}——如果某天 PR 删除了local-safe这个 label 的写入18 个 panel 里引用它的查询就会静默变成空序列而所有编译与 CI 检查都会保持绿色。这类指标的写入者可在 rust/kona/crates/node/engine/src/metrics/mod.rs 中找到这正是检查二要追踪的对象CI 配置、justfile、workflows测试名、二进制名、包列表——都是被枚举的字符串名字一改就会静默跳过或炸掉README、compose 文件、脚本。每个清扫命中必须精确归类为三者之一must-update必须更新在同一 PR 内修掉deliberate survivor有意存留例如另一个服务仍在填充的共享 Go 类型、为 wire 兼容性保留的枚举值——在 PR 描述中写明理由同名不同概念same-name, different concept名字是被重载的同一个词可能在一个子系统标记链头、在另一个子系统表示逐消息验证阈值。清扫不得越界去动共享名字的存活功能边界微妙时把该边界记录进 PR 描述。5. 检查二删除写入——证明存活者何时触发这是最隐蔽的删除缺陷形态被删代码是某份存留状态状态字段、tracker、指标、head label的多个写入者之一而评审通过观察到其他写入者存在来确认安全。存在不等于覆盖Existence is not coverage。对每一处被删除的写入方法文档要求三步走枚举同一状态的所有存活写入者对每个存活写入者确立其精确的触发条件——触发事件、守卫条件、运行模式证明存活者触发条件的并集覆盖被删写入者覆盖的全部窗口。容易被漏掉的窗口有五类启动/初始化、同步模式EL/snap sync、derivation 尚未运行、forkchoice 更新被门控的阶段、重置resets、reorg需要把值向后移动的写入者、错误/停止路径error/halt paths。一个未被覆盖的窗口意味着恰恰在运维人员或下游服务健康监控、仪表盘盯着该值的时候它悄悄变陈旧。如果旧耦合是偶然形成的应当把新耦合显式化而不是把被删路径恢复回来。方法文档还特别强调测试要求修复的测试必须钉住语义而不仅是快乐路径。如果该写入必须能把值向后移动就要断言这一点——否则日后某次只允许前进的加固会重新引入陈旧性。6. 连带清理清单Consequential cleanups删除之后同一 PR 内应当完成的五类连带清理如今无法产生的代码唯一生产者已被删除的错误变体或分支随生产者一起删掉死参数穿过接口传递、但删除后无人读取的值——同一 PR 内收缩签名孤儿化副本被删代码可能是某个上游类型/辅助函数本地副本存在的唯一理由重新声明的错误类型、拷贝来的 parser。对被删名字做符号 grep 是发现不了这些的要问被删代码证明了什么而不只是它引用了什么空洞测试vacuous tests对已删字段的断言可能变成零值比零值而永远通过。优先把被删概念变成显式错误而不是返回零值。当被删断言被替换时要证明替代者能够失败——临时反转它守护的性质例如给宽松解析契约临时加deny_unknown_fields并看着它变红。一个构造上不可能失败的测试断言类型系统已保证的东西保护不了任何东西。仓库中 rust/kona/crates/protocol/genesis/src/chain/config.rs 就是一个正面示范ChainConfig上带deny_unknown_fields属性并配有专门的测试用例守护该属性断言一个只多一个键的合法配置必须被拒绝wire 兼容性被删的 RPC/JSON 字段在宽松客户端中解析为零值——追踪仓库内每个消费者对该零值的处理并对仓库外读者披露该删除破坏性变更标记 迁移说明。7. 依赖与工作区级联Dependency and workspace fallout删除会以编译器和 clippy 都不会报警的方式波及构建元数据以下四项全部保持全绿孤儿化依赖删除文件或模块可能抽走某个 crate 对某依赖的最后一处使用。要把被删文件 import 过的每一个符号都 grep 一遍——不允许肯定还在用的捷径——然后本地跑未用依赖门禁。该方法文档给出的命令是cargo nightly udeps --release --workspace --all-features --all-targets即 CI 命令与仓库一致rust/justfile 中的check-udepsrecipe 正是cargo {{NIGHTLY}} udeps --release --workspace --all-features --all-targets。这是唯一能抓住这一类问题的检查feature 转发移除被删依赖可能在 crate 的[features]列表里带有转发项dep/feature形式的转发要逐个确认下游消费者自己启用了被转发的 feature——那个静默依赖传递性启用的消费者就是发现项过期的 feature 列表字符串启用代码被删掉的dep/feature条目能逃过符号 grep它引用的是依赖名而非符号且没有任何工具会报警。要显式清扫[features]段落中出现的被删 crate 名与 feature 名独立工作区的 lockfile通过 path-dependency 依赖被改 crate 的工作区例如 SP1 guest programs 工作区是独立解析的。要重新生成其 lockfile——CI 以新鲜度为门禁just lock-sp1-guest/just check-sp1-guest-lock——并且要在该工作区自己的解析下--manifest-path编译受影响的消费者而不是根工作区下一个依赖了已消失的传递性 feature 启用的 crate 只会在独立解析下失败。仓库中这一机制真实存在rust/kona/sp1/programs/Cargo.toml 是一个独立 Cargo 工作区members 为super-range与super-aggregation其注释明确说明该工作区必须保持分离以隔离 SP1 加密补丁rust/justfile 的check-sp1-guest-lock用cargo metadata --manifest-path ... --locked校验 guest 工作区 Cargo.lock 与新依赖同步过期时给出指向just lock-sp1-guest的修复提示lock-sp1-guest recipe。此外仓库中存在大量[package.metadata.cargo-udeps.ignore]条目本身就印证了这类检查的实战价值例如 rust/op-reth/crates/chainspec/Cargo.toml 用注释解释了为何某个 self dev-dependency 需要被 udeps 忽略它激活 feature 而非 import 符号。8. 误报陷阱False-positive traps评审时最容易被误报的三种情形方法文档明确列出共享类型从某个实现输出中删除的字段可能合理地保留在另一个服务仍在填充的共享结构体里。把它也从共享结构体里删掉是另一项范围更宽的变更——不要把存留者标记为漏网残骸重载名字即同名不同概念一次 grep 命中是一个问题不是一个发现重复产物成对的仪表盘、镜像配置必须一起更新只标记其中一个文件的发现是不完整的。9. 评审输出格式与职责边界deletion-reviewer代理的输出被严格规定为四个小节代理文件原文结构Summary一两句话——删了什么、删除是否完整且安全Critical Issues未被覆盖的写入窗口以及会改变行为的 must-update 引用没有就写空——明确说明没有Findings按 High / Medium / Low 排序。每项包含What带file:line、Why它会咬人、How修具体方案Verified clean列出所有扫干净的清扫与写入分析及其证据grep 了什么、追踪了哪些写入者——缺席声明正是这种评审的价值所在所以要展示其依据。职责边界Boundaries三条范围是删除及其爆炸半径不是一般代码质量——那是语言型评审代理go-code-reviewer / rust-code-reviewer的职责不修改任何文件只报告如实报告列出清扫过什么、以及未能检查什么。10. 小结OP Stack monorepo 对删除建立了独立于语言评审的专项方法论用代码形式 字符串形式双清单做全树引用清扫并三分类用触发条件并集而非写入者存在性来验证删除写入的覆盖性再用连带清理、构建元数据级联与误报陷阱三张清单收尾。配合check-udeps、SP1 guest 独立工作区 lockfile 门禁等真实 CI 设施这套流程保证删除类 PR 在合并前就消除了文档残留、仪表盘空序列、陈旧状态与孤儿依赖四类静默回归。【免费下载链接】optimismOptimism is Ethereum, scaled.项目地址: https://gitcode.com/GitHub_Trending/op/optimism创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考