关于 adversarial-rust
adversarial-rust 用于从架构层面审查并重构沿用其他编程范式的现有 Rust 代码。其规则和示例基于 codex-rs 工作区,涵盖所有权、类型、错误处理、迭代和并发。
主要功能
- 01Rust 架构级审查
- 02所有权与类型重构指导
- 03基于 Result 和 Option 的错误流程
- 04迭代与动态分发指导
- 05异步并发审查规则
- 06基于 codex-rs 的示例
适用场景
- 01重构 Rust 中类似 Java 的模式
- 02理清大量 clone 的所有权设计
- 03替换哨兵值和 unwrap 错误处理
- 04审查异步代码中的阻塞与锁
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ pproenca/ dot-skills --skill adversarial-rust安装后在 Claude Code 中输入/adversarial-rust确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
AGENTS.mdmetadata.jsonassets/templates/_template.mdreferences/_sections.mdarch-default-literal-over-builder.mdarch-drop-di-trait-single-impl.mdarch-free-functions-over-manager-struct.mdarch-no-deref-inheritance.mdarch-public-fields-over-getter-ceremony.mdconc-blocking-pool-over-async-cpu-fanout.mdconc-narrow-locks-before-await.mdconc-own-spawned-task-handles.mdconc-spawn-blocking-over-blocking-async.mddyn-enum-over-box-dyn-closed-set.mddyn-generics-over-boxed-callbacks.mdflow-no-catch-unwind-try-catch.mdflow-option-over-sentinel-values.mdflow-result-over-unwrap-expected.mdflow-thiserror-library-anyhow-application.mditer-combinator-over-index-loop.mditer-stay-lazy-single-collect.mdown-id-map-over-self-referential.mdown-no-rc-refcell-object-graph.mdown-restructure-over-clone.mdtype-enum-over-bool-string-state.mdtype-newtype-parse-dont-validate.mdtype-result-over-parallel-options.mdtype-split-option-god-struct.md详细介绍
对抗式 Rust
针对 Rust 开展对抗式、架构层面的审查与重构。如果说面向新项目的惯用法技能回答的是“现在该用哪个工具?”,那么这项技能针对的是已有代码中引入了错误心智模型的部分——来自 Java/C# 的对象和接口、来自垃圾回收语言的共享一切对象图、异常、C 风格循环和哨兵值、脱离管理的 Promise 并发——指出它违背了哪种范式,并给出重构方案,使其回归惯用的 Rust。
每条规则都基于同一个生产代码库:codex-rs 工作区(github.com/openai/codex,提交 f1affbac5e 中的 codex-rs/,约 125 个 crate / 2,500 个 Rust 文件)。每条规则中“正确”的做法,就是该代码库的实际做法;执行依据是其工作区 lint 配置(禁用 unwrap_used、redundant_clone、needless_collect、await_holding_lock 等约 30 项);而例外则是它实际保留的例外——因此,“何时不适用”绝非假设。对于能力足够的模型已经能正确处理的内容,这里不会设规则。
适用场景
- 从架构而非单纯风格的角度审查或重构现有 Rust——“让它真正符合惯用法”“为什么这段 Rust 有股 Java 味”
- 精简移植过来的繁琐仪式——只有一种实现的依赖注入 trait、用
Deref模拟继承、无状态的*Manager/*Service结构体、getter/setter 样板代码、每个结构体都配一个 builder - 理顺被迫应付的所有权——到处撒
.clone()才能编译、Rc<RefCell<T>>对象图、自引用结构体尝试 - 修复贫血数据——布尔值/字符串状态机、并列的
Option字段、承载领域含义的原始类型、逃出 serde 边界的Option巨型结构体 - 移除异常式流程控制——对预期失败调用
unwrap、哨兵返回值、用catch_unwind模拟 try/catch、在库 API 表面使用anyhow - 精简习惯性间接层——对封闭集合使用
Box<dyn Trait>、装箱的回调参数、索引循环和逐步collect()链 - 修正照搬来的并发习惯——在
async fn中执行阻塞调用、跨.await持有锁守卫、为 CPU 密集型工作扇出异步任务、即发即弃的tokio::spawn
对于编写新 Rust 时的“选哪种模式、哪个 crate、哪种实践”等新项目决策——异步取消、错误枚举设计、沙箱、测试架构——请改用 openai-codex-rust-patterns;这项技能是基于同一代码库、用于诊断和精简分层的配套技能。
规则类别
| # | 类别 | 前缀 | 要剔除的外来模型 |
|---|---|---|---|
| 1 | 企业式繁文缛节与伪面向对象 | arch- | DI trait、Deref 继承、Manager 结构体、getter 繁文缛节、反射式 builder → 具体类型、委托、模块函数、公开字段、结构体字面量 |
| 2 | 与所有权对抗,而非善用所有权 | own- | 为编译而 clone、Rc 对象图、自引用结构体 → 有设计依据的克隆、以 ID 为键的自有映射、单一所有者 |
| 3 | 贫血且依赖字符串的数据 | type- | bool/String 状态、并列的 Option、原始类型、逃出的巨型结构体 → 携带数据的枚举、新类型、一次线上的数据到领域数据转换 |
| 4 | 异常式流程控制 | flow- | 用 unwrap 处理错误、哨兵值、catch_unwind、不透明的库错误 → Result + ?、Option、thiserror 枚举、在边界处使用 anyhow |
| 5 | 习惯性动态分发 | dyn- | 对封闭集合使用 Box、装箱的回调参数 → 带标签的枚举、API 中的泛型 Fn、用通道替代监听器 |
| 6 | 命令式迭代 | iter- | 索引循环、可变累加器、逐步 collect → 命名组合器、单条惰性链、collect 到 Result |
| 7 | 源自其他运行时的并发模式 | conc- | async 中的阻塞调用、跨 await 持有锁、异步 CPU 任务扇出、无主的 spawn → spawn_blocking、缩小锁的持有范围、有界线程池、由调用方持有的句柄 |
快速参考
1. 企业级仪式与虚假的面向对象
arch-drop-di-trait-single-impl— 删除只有一个实现的 DI trait;codex-rs 提供具体的ModelClient和Sessionarch-no-deref-inheritance— codex-rs 的 18 个Deref实现全都是 newtype 或智能指针;没有一个用于模拟继承层次arch-free-functions-over-manager-struct— 无状态能力使用模块函数(git-utils、apply-patch);*Manager只有在拥有状态时才名副其实arch-public-fields-over-getter-ceremony—Config和所有协议类型的字段都为pub;只有存在不变量时才提供访问器arch-default-literal-over-builder— 有 1,787 处结构体字面量使用..Default::default(),而 builder 只有 16 个;只有分阶段构造确有必要时,builder 才有存在的价值
2. 与所有权对抗,而非善用所有权
own-restructure-over-clone— 保留下来的克隆都是经过设计的(Copy ID、增加 Arc 引用计数、锁内快照);为通过编译而添加的克隆会复制数据own-no-rc-refcell-object-graph— 约 2,500 个文件中没有Rc<RefCell>;改用范围明确的 Mutex 字段、通道或 ID 映射own-id-map-over-self-referential— 图存储在HashMap<ThreadId, Arc<CodexThread>>中;交叉引用使用 ID,绝不使用引用
3. 贫血数据与字符串类型泛滥
type-enum-over-bool-string-state— 变体拥有各自的字段(SandboxPolicy);其外部沙箱变体甚至用NetworkAccess表示是或否,而非booltype-result-over-parallel-options— 每种形态各用一个Option,CodexAuth就是反例;表示存在、缺失或失败时,应使用Result<Option<T>, E>type-newtype-parse-dont-validate— 一次解析为ThreadId/AgentPath;模型名称仍使用String,因为不存在不变量type-split-option-god-struct—ConfigToml(97 个字段中有 91 个是 Options)作为传输格式没有问题;将其解析一次,转换为丰富的Config
4. 异常风格的控制流
flow-result-over-unwrap-expected— 工作区范围内禁止使用unwrap_used/expect_used;例外必须附带#[expect]和书面不变量flow-option-over-sentinel-values— 查询返回Option;-1只存在于操作系统退出码边界flow-no-catch-unwind-try-catch— codex-rs 的每处生产环境用法都用于监控外部故障域;没有一处用于捕获预期失败flow-thiserror-library-anyhow-application— 各层分别使用CodexErr/ApiError/TransportError;anyhow用于main()
5. 习惯性使用动态分发
dyn-enum-over-box-dyn-closed-set—Op/EventMsg/TurnItem都是枚举;dyn用于可在运行时扩展的工具注册表dyn-generics-over-boxed-callbacks— API 使用泛型F: Fn,仅在存储时装箱;使用通道而非监听器注册
6. 命令式迭代
iter-combinator-over-index-loop— 禁用 13 条manual_*lint;仅在涉及 await、副作用、将索引作为数据或 FFI 时保留foriter-stay-lazy-single-collect— 使用一条惰性链;collect::<Result<Vec<_>, _>>()是可失败流水线的惯用写法(生产代码中使用 49 次)
7. 来自另一运行时的并发
conc-spawn-blocking-over-blocking-async— 约 50 处spawn_blocking调用:git、文件锁、zstd、OAuth 服务conc-narrow-locks-before-await— 即使是 tokio 守卫也可能无法跨越.await;将快照移出,或使用带原子性原因的#[expect]conc-blocking-pool-over-async-cpu-fanout— 不使用 rayon;在一个spawn_blocking后,通过有界 OS 线程进行 CPU 扇出conc-own-spawned-task-handles—AbortOnDropHandle+ 子CancellationToken;中断流程为取消 → 宽限期 → 中止
使用方法
在审查的代码中遇到相应的异味时,阅读对应的参考文件。每条规则都会指出陌生模式,解释 Rust 为何会拒绝它,并展示重构方式,其中使用真实的 codex-rs 名称,并附上指向固定提交代码库的永久链接。尽可能选择改动预算允许的最彻底重构——重新设计所有权优于到处添加 clone;删除 DI trait 优于通过它进行模拟。每个示例都能在 Rust 1.86(2021 edition)上编译。
相关技能
openai-codex-rust-patterns— 从同一 codex-rs 工作区提炼而来的绿地开发配套指南:编写生产级 Rust 时该采用哪些模式(异步取消、错误枚举设计、沙箱化、测试、工作区布局)。编写代码时用于决策;对抗式审查和简化流程的重构则使用本技能。完成简化后,本指南中的若干规则会将后续内容交由它处理(flow-thiserror-library-anyhow-application→ 其errors-规则,flow-result-over-unwrap-expected→defensive-deny-unwrap-workspace-wide,arch-drop-di-trait-single-impl→ 其测试接缝)。
参考文件
| 文件 | 描述 |
|---|---|
| references/_sections.md | 类别定义和顺序 |
| assets/templates/_template.md | 新规则模板 |
| metadata.json | 版本和来源引用 |