You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .claude/commands/review-pr.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,5 @@
1
1
---
2
-
description: Produce a structured local review report for a CoWservices PR (read-only; user posts comments manually)
2
+
description: Produce a structured local PR review report for cowprotocol/services — synthesizes context, builds a codemap, applies CoW-specific + Rust review skills, and emits severity-ranked findings with actionable questions. Use when the user says "review this PR", "/review-pr 1234", "look at PR #1234", or pastes a cowprotocol/services PR URL. Read-only; the user posts any comments manually.
-**Signal over noise.** Report genuine concerns only. LGTM is a perfectly valid verdict and is the correct one whenever the PR is clean.
15
-
-**Never post to GitHub.** Output is strictly for the user's terminal. No `gh pr review`, no `gh pr comment`, no `gh pr close`. The user decides what to say on GitHub.
14
+
-**CRITICAL: Signal over noise.** Report genuine concerns only. LGTM is a perfectly valid verdict and is the correct one whenever the PR is clean. The goal is not to maximise finding count — the goal is to be worth a senior reviewer's attention.
15
+
-**CRITICAL: Never post to GitHub.** Output is strictly for the user's terminal. No `gh pr review`, no `gh pr comment`, no `gh pr close`. The user decides what to say on GitHub.
16
+
-**CRITICAL: Code is the primary source of truth.**`CLAUDE.md`, existing design docs, and this skill's own sibling docs can go stale. When a finding turns on *"X is called from Y"* or *"this field is read by Z"*, verify by grepping the codebase or using an LSP symbol tool — not by citing a doc. Docs give you higher-level *shape*; code gives you ground truth.
16
17
-**Explain, don't just flag.** Each finding must give the reviewer enough context to understand *and defend* the point — not just forward AI-generated text.
17
18
-**Actionable framing.** Every finding ends with either a concrete `Action:` or a specific `Question:`. Never both.
19
+
-**Token discipline.** Don't read entire files when a grep or a targeted LSP symbol lookup suffices. Build a codemap (see [§3.5](#35-codemap-phase)) *before* reading file bodies. When you do need a file, read hunks adjacent to changed lines rather than the whole thing.
Error behavior is consolidated in [§9. Error Playbook](#9-error-playbook).
30
33
@@ -90,6 +93,61 @@ This list will grow. When adding a new sibling doc (e.g. `solver-engine.md`, `au
90
93
91
94
---
92
95
96
+
## 3.5 Codemap Phase
97
+
98
+
**Purpose:** Before reading file bodies, build a targeted map of the symbols the diff touches, their callers, and their call sites. A codemap turns a 1000-line diff into a ~20-line mental model and preempts the "I read 10 files to find the impact" failure mode. It also catches findings that only become visible at the *shape* level (API ergonomics, unused abstractions, caller-count inconsistencies).
99
+
100
+
### What to map
101
+
102
+
For each non-trivial symbol the diff adds, modifies, or deletes:
103
+
104
+
1.**New public types / traits / functions** — what are their fields / methods / signatures? (`rust-symbol-analyzer` or `get_symbols_overview`.)
105
+
2.**Modified function signatures** — who calls them? (`rust-call-graph`, `find_referencing_symbols`, or `rg '<fn_name>\b' crates/`.) This is how you catch "this signature changed but 4 call sites weren't updated".
106
+
3.**New trait impls** — which types implement the trait? Is the trait used anywhere outside the PR? (`rust-trait-explorer` or `find_referencing_symbols`.)
107
+
4.**Error-type changes** — where do callers match on this error? (`rg '::<ErrorVariant>'` / `find_referencing_symbols`.)
108
+
109
+
### Tools (prefer the cheapest viable option)
110
+
111
+
In order of token cost, ascending:
112
+
113
+
| Tool | When |
114
+
|---|---|
115
+
|`Grep` with `-n` on a symbol name | Fastest. Use when you need caller counts, not structure. Example: `rg 'OrderValidator::new\b' crates/` to verify all call sites were updated. |
116
+
|`mcp__plugin_serena_serena__find_symbol` / `find_referencing_symbols`| Cheap, precise. Use when you need location + kind + signature, not the whole file. |
117
+
|`mcp__plugin_serena_serena__get_symbols_overview` on a single file | Use before reading the file body — gets the symbol table for free. |
118
+
| LSP-backed skills (`rust-call-graph`, `rust-symbol-analyzer`, `rust-trait-explorer`, `rust-code-navigator`) | Richer analysis — full call hierarchies, trait impl trees, type relationships. Use for diffs that touch cross-crate abstractions. |
119
+
| Reading full files with `Read`| Last resort. Only when the diff hunks don't give enough surrounding context and the LSP tools can't pin down what you need. |
120
+
121
+
### What the codemap produces
122
+
123
+
A short block in the report header (shown to the reviewer) that looks like:
This is not filler — it's the raw material §4 (synthesis) and §5 (findings) work from. A finding like *"`Eip1271Simulator` pub fields have no constructor; 16 callers means each future field addition is a source-break"* only becomes findable once the codemap surfaces the caller count.
142
+
143
+
### When to skip the codemap
144
+
145
+
- Trivial PRs (docs-only, single-line version bump, pure test addition) — skip.
146
+
- Pure refactor PRs where the diff has no added public API — skim only.
147
+
- Everything else — do it.
148
+
149
+
---
150
+
93
151
## 4. Context Synthesis
94
152
95
153
Produce a 1-3 paragraph block combining:
@@ -117,13 +175,32 @@ Produce a 1-3 paragraph block combining:
117
175
118
176
## 5. Review and Severity
119
177
120
-
Read the diff. For non-trivial hunks, read the full changed file(s) for surrounding context. Apply, in order:
178
+
With the codemap ([§3.5](#35-codemap-phase)) and context synthesis ([§4](#4-context-synthesis)) in hand, review the diff. For non-trivial hunks, read the full changed file only when the codemap + diff don't answer the question. Apply, in order:
121
179
122
-
1.Generic Rust review from `actionbook/rust-skills`.
123
-
2.CoW services conventions from `CLAUDE.md`.
124
-
3.Conditionally loaded sibling docs from [§3](#3-classification).
180
+
1.CoW services conventions from `CLAUDE.md`.
181
+
2.Sibling docs from [§3](#3-classification) (conditionally loaded).
182
+
3.**Activate installed Rust review skills by diff content (below).**
125
183
4. Soft QM skill (`ra-qm-team`), if in `loaded_context`.
These skills are installed via `actionbook/rust-skills` (hard prereq) and the related ecosystem. They're most effective when *explicitly* activated based on what the diff contains. Before writing findings, scan the diff and invoke any skill whose trigger fires:
|`m04-zero-cost`| Adds new generics, `impl Trait`, `dyn Trait`, trait objects, `Box<dyn ...>`| Validates static-vs-dynamic dispatch choice, unnecessary allocation, trait-object safety, monomorphization cost on a workspace this large. |
194
+
|`m05-type-driven`| Adds newtypes, `PhantomData`, marker traits, builder patterns, type-state | Validates "make invalid states unrepresentable" and whether the type design actually narrows the state space. |
195
+
|`m15-anti-pattern`| Any non-trivial new code | Sanity pass for common Rust anti-patterns. Cheap; run it. |
|`unsafe-checker`| Any `unsafe` block, FFI (`extern`), `transmute`, raw pointers, `MaybeUninit`|**Mandatory** — any finding here defaults to **High**. Soundness issues are never Small. |
198
+
|`rust-trait-explorer`| Adds a new trait or a new impl of an existing trait | Maps the trait's existing impls — catches "you added a default method to a trait with 12 impls, one of them should override it". |
199
+
|`rust-call-graph` / `rust-code-navigator`| Modified function signatures on cross-crate public APIs | Catches missed caller sites, breaking changes, downstream blast radius. |
**Rule of thumb:** If a skill's trigger keywords appear in the diff's **added** lines, activate it. Don't run skills on context lines (unchanged code around the diff) — that wastes tokens on things you're not actually reviewing.
203
+
127
204
### Severity Rubric
128
205
129
206
| Severity | Meaning | Example |
@@ -158,6 +235,8 @@ A senior reviewer catches things that aren't bugs. They shape the code for futur
158
235
159
236
7.**Description-vs-code mismatches.** If the PR body describes `Mutex<HashSet>` and the code has `DashSet`, the description is stale. Flag it — not because it changes the code, but because whoever reads the PR as history will be confused. Small finding, usually.
160
237
238
+
**Related: design spec referenced but not committed.** If the PR body mentions a design spec (e.g. `docs/superpowers/specs/...`) that isn't in the PR's diff, that's a **Small** finding asking the author to commit it — teammates reading the PR six months from now can't see the rationale otherwise.
239
+
161
240
8.**Bundled orthogonal changes.** When a PR contains a change that isn't clearly required by the main feature, ask: does this belong in its own PR? Sometimes the answer is "it's required, here's why" (fine — ask for the reason to be in the commit message or a code comment). Sometimes the answer is "you're right, let me split it" (better git history).
162
241
163
242
9.**Error taxonomies in web3 code.** Blockchain RPC errors have multiple categories: contract reverts, RPC transport failures, provider-side rate-limiting, timeout errors, decoding failures. Each should lead to *different* handling. If new code treats `Err(_)` as a single bucket when the branches should differ (e.g. cache a non-vault verdict on contract revert, but *not* on a network error), this is a correctness issue — Medium or High depending on whether the wrong classification can poison downstream behavior.
When a finding rests on a claim about the codebase, verify the claim by looking at the code — not by trusting a doc, a comment, or this skill's own sibling files.
435
+
436
+
-**Claim:***"`OrderSimulator::encode_order` only reads `OrderData` and `Interactions`."*
437
+
**Wrong:** cite a doc comment.
438
+
**Right:**`rg 'fn encode_order' crates/orderbook/src/` → read the function body → verify.
439
+
440
+
-**Claim:***"All `OrderValidator::new` call sites have been updated."*
441
+
**Wrong:** count the test assertions in the diff.
442
+
**Right:**`rg 'OrderValidator::new\b' crates/` → compare the count to the diff's modified lines.
443
+
444
+
-**Claim:***"This module is only used by X."*
445
+
**Wrong:** trust the module's top-level comment.
446
+
**Right:**`find_referencing_symbols` on the public exports → see actual call graph.
447
+
448
+
Docs age. Comments lie. Grep and LSP don't. When reporting a finding that depends on such a claim, verify *before* you write the finding — not after the author pushes back.
449
+
450
+
---
451
+
344
452
## Maintenance Notes
345
453
346
454
-**When you find yourself adding a project-specific heuristic more than twice**, move it into a sibling context doc under `docs/review-context/` and add a trigger rule to [§3](#3-classification).
0 commit comments