Code Review
A disciplined, methodology-driven code review. The goal is not to leave many
comments — it is to find the issues that matter, rank them honestly by impact,
and propose a concrete fix for each. A review that flags one real
SQL-injection beats a review that flags twenty style nits and misses the bug.
This skill is grounded in established practice:
- Correctness first. Reviewers and research (Google, Microsoft, the SmartBear
studies) converge on the same point: the highest-value defects found in review
are logic and correctness defects, not formatting. Read for what the code
does before what it looks like.
- Security via OWASP / CWE. The security pass is structured around the
OWASP Top 10 categories and the corresponding
CWE weakness classes, so findings map to a recognized
taxonomy instead of vibes.
- Performance via Big-O reasoning. Performance findings are justified by
complexity and the cost model (allocations, round-trips, I/O), not by
micro-optimization folklore.
- "Comment on what matters, not nits." In the spirit of Google's engineering
code-review guidelines: distinguish things that must change from preferences,
label preferences as such, and never block a merge on style when a linter or
formatter could settle it.
When to Activate
Activate this skill when the user:
- Shares a diff, patch, or pull request and asks for a review.
- Pastes a file or function and asks "is this correct / safe / any bugs?".
- Asks for a pre-merge check, audit, or second pair of eyes.
- Asks specifically to focus on security, performance, or correctness
of a change (run the relevant pass with extra depth, but still do a quick
sweep of the others).
If the request is "write code" or "explain code," this is not the right skill.
This skill evaluates existing code.
Step 1: Scope & Context
Before reading line by line, establish what you are reviewing. State these back
to the user briefly so assumptions are visible:
- What changed? A diff/PR (review only the changed lines plus their blast
radius) or a whole file (review all of it). For a diff, the surrounding
unchanged code is context, not subject — but flag it if the change makes it
wrong (e.g. a new caller breaks an old invariant).
- Language & framework. Determines the idioms, the footguns, and the
security surface (e.g. Django ORM vs raw SQL, React vs server-rendered HTML).
- Runtime & security surface. Is this server-side, client-side, a CLI, a
library, infra-as-code? Does it touch the network, the filesystem, a database,
user input, authentication, money, or PII? The surface dictates which passes
matter most.
- Tests present? Did the change add or modify tests? Is there existing
coverage for the touched code? "No tests for a behavior change" is itself a
finding.
- Intent. What is the change supposed to do? Review against intent — a
correct implementation of the wrong thing is still a finding.
If critical context is missing (e.g. you cannot tell whether input is trusted),
say so explicitly and review for the worst plausible case.
Step 2: Severity Model
Every finding gets exactly one severity. Be honest — inflating severity trains
people to ignore you; deflating it lets real bugs ship.
| Severity |
Meaning |
Blocks merge? |
| Critical |
Data loss, security vulnerability, crash, or corruption in normal use. |
Yes |
| High |
Wrong behavior / incorrect results for realistic inputs. |
Yes |
| Medium |
Performance or design risk that will bite under load or over time. |
Usually |
| Low |
Maintainability: unclear code, duplication, weak naming, missing docs. |
No |
| Nit |
Pure style / preference a formatter or linter could decide. |
No |
Rules:
- Label nits as
Nit: and never block on them. If a formatter/linter can
fix it, say so in one line and move on. Do not let nits dilute the signal.
- One severity per finding. If something is both a perf and a correctness
problem, file it as the higher one and mention the other dimension.
- Justify Critical/High. State the input or condition that triggers the bad
behavior. "Could be a problem" is not a finding; "with
n=0 this divides by
zero" is.
Step 3: Review Passes in Priority Order
Run the passes in this order. Earlier passes outrank later ones: a
correctness bug is more important than a naming nit on the same line. Each pass
is a checklist of concrete things to look for.
(a) Correctness — does it actually work?
The highest-value pass. Read the changed logic and ask "for which input does
this do the wrong thing?"
- Off-by-one / boundaries: loop bounds, slice indices,
< vs <=,
inclusive/exclusive ranges, empty collections, single-element collections.
- Null / undefined / None: dereferencing a value that can be absent;
Optionals unwrapped without a check; missing map keys; default-vs-missing.
- Error handling: swallowed exceptions; errors logged but not handled;
ignored return/
error values; partial failures that leave inconsistent state;
cleanup that doesn't run on the error path (no finally/defer/with).
- Edge cases: zero, negative, empty string, very large input, Unicode,
duplicate keys, the "happy path only" smell.
- Concurrency / races: shared mutable state without synchronization;
check-then-act (TOCTOU); non-atomic read-modify-write; assuming ordering
between async tasks; deadlock / lock-ordering.
- Async / await: missing
await (fire-and-forget promise); awaiting in a
loop that should be parallel; unhandled promise rejection; mixing callback and
promise styles; async function whose error path is silently dropped.
- Resource leaks: files/sockets/connections/locks opened but not reliably
closed; growing caches/listeners never released; goroutines/threads that never
exit.
- Numeric / floating-point:
== on floats; money in floats instead of
integer minor units / decimal; integer overflow/truncation; rounding direction.
- Time & timezones: naive vs aware datetimes; assuming UTC; DST gaps;
off-by-one on dates; comparing timestamps in different units (s vs ms).
- Logic: inverted conditions, wrong boolean operator, copy-paste of the
wrong variable, fall-through, default branch missing.
(b) Security — can it be abused? (OWASP / CWE)
Tag each finding with the relevant OWASP category and/or CWE id where it applies.
- Injection — SQL, NoSQL, OS command, LDAP, template. String-concatenated
queries or shell commands from user input. (OWASP A03; CWE-89 SQLi, CWE-78
command injection, CWE-94 code injection.)
- Broken access control — missing/incorrect authz checks; IDOR (acting on an
object id without verifying ownership); trusting a client-supplied role/flag.
(OWASP A01; CWE-285, CWE-639.)
- Authentication gaps — missing auth on a sensitive route; weak session
handling; credentials compared non-constant-time. (OWASP A07; CWE-287.)
- Secrets in code — hardcoded API keys, passwords, tokens, private keys;
secrets logged. (CWE-798 hardcoded credentials, CWE-532 secrets in logs.)
- Unsafe deserialization —
pickle/yaml.load/Java native deserialization
of untrusted data; prototype pollution. (OWASP A08; CWE-502.)
- SSRF — fetching a user-controlled URL without allow-listing the host.
(OWASP A10; CWE-918.)
- Path traversal — joining user input into a filesystem path without
normalization/containment. (CWE-22.)
- XSS — rendering untrusted data into HTML without escaping;
innerHTML /
dangerouslySetInnerHTML; unsanitized template output. (OWASP A03; CWE-79.)
- Missing input validation — trusting length/type/range/format of external
input; mass assignment binding unexpected fields. (CWE-20, CWE-915.)
- Insecure crypto / transport — MD5/SHA1 for passwords (use bcrypt/argon2);
ECB mode; static IV; disabled TLS verification; predictable randomness for
tokens. (OWASP A02; CWE-327, CWE-295, CWE-330.)
(c) Performance — will it scale? (Big-O + cost model)
Justify each finding with complexity or a concrete cost (round-trips, bytes,
allocations). Do not micro-optimize cold paths.
- N+1 queries — a query inside a loop over rows; missing eager-load/join.
- Accidental O(n²) — nested loops over the same collection;
in/indexOf on
a list inside a loop (use a set/map); repeated string concatenation in a loop.
- Unnecessary allocations / copies — copying large structures per iteration;
building a full list when a generator/stream suffices; boxing in hot paths.
- Blocking I/O on a hot path — synchronous network/disk in a request handler
or event loop; missing batching; chatty APIs.
- Missing indexes — querying/filtering on an unindexed column at scale.
- Unbounded growth — caches/queues/lists with no eviction or limit; loading
an entire dataset into memory; recursion without depth bound.
(d) API & Design — is it well-shaped?
- Naming — does the name say what it does? Misleading or vague names; verbs
for queries with side effects.
- Cohesion / responsibility — function doing too much; mixed levels of
abstraction; god object.
- Leaky abstractions — internal types/SQL/HTTP details bleeding through a
public interface.
- Backward compatibility — removed/renamed public function, changed
signature, changed default, changed serialization format, narrowed accepted
input. Flag breaking changes explicitly and ask about versioning.
- Error contracts — what does this throw/return on failure? Is it consistent
with siblings? Are errors typed/actionable or stringly-typed?
(e) Tests — is the change covered?
- Coverage for the change — is the new/changed behavior actually exercised?
A behavior change with no test is a finding.
- Edge & negative cases — only the happy path is tested; no test for the
error path, empty input, or the boundary the code handles.
- Flaky patterns — reliance on real time/sleep, network, ordering of maps,
shared global state between tests, randomness without a fixed seed.
- Asserting implementation, not behavior — tests that assert internal calls /
private state and will break on refactor without catching real regressions;
over-mocking that tests the mock.
(f) Maintainability — can the next person change it?
- Dead code — unreachable branches, unused vars/imports/params, commented-out
blocks.
- Duplicated logic — copy-paste that should be extracted; the same constant
redefined.
- Unclear names / magic numbers — unexplained literals; abbreviations;
single-letter names outside tight loops.
- Comment quality — comments that restate the code vs explain why; stale
comments contradicting the code; missing doc on a non-obvious public API.
Step 4: Red-Flags Quick Scan
Before (or alongside) the passes, do a fast scan for instant blockers. Any hit is
Critical until proven safe:
- Hardcoded secret / API key / password / private key.
eval / exec / Function() / system() on anything derived from input.
- SQL/command built by string concatenation or f-string with a variable.
- TLS/cert verification disabled (
verify=False, rejectUnauthorized: false,
InsecureSkipVerify: true).
- Catch-all that swallows errors silently (
except: pass, empty catch {}).
- A committed
.env, credentials file, or key material in the diff.
- Infinite-loop / unbounded-recursion risk (loop with no progress toward exit).
dangerouslySetInnerHTML / innerHTML with non-constant data.
- Disabled auth/permission check, or a
# TODO: add auth on a live route.
Step 5: Output Format
Produce the review in this structure. Be specific, cite the line, propose the
fix, and separate must-fix from nice-to-have.
1. Verdict
One line, one of:
- Approve — no blocking issues; any comments are Low/Nit.
- Approve with comments — safe to merge after addressing minor points; no
Critical/High.
- Request changes — one or more Critical/High findings must be fixed first.
Follow with a one-sentence rationale.
2. Findings table
| ID |
Location |
Severity |
Issue |
| C1 |
path/file.py:42 |
Critical |
SQL injection via f-string query (CWE-89) |
| H1 |
path/file.py:31 |
High |
Endpoint missing ownership check (IDOR) |
| M1 |
path/file.py:55 |
Medium |
N+1 query inside the response loop |
Order by severity (Critical → Nit). Use stable IDs (C1, H1, M2, L1,
N1) so the user can reference them.
3. Per-finding detail
For each finding, in severity order:
[C1] SQL injection — path/file.py:42 — Critical (CWE-89, OWASP A03)
Why it matters: the user_id value comes straight from the request and is
interpolated into the query string, so an attacker can read or drop tables.
Fix: use a parameterized query.
# before
cur.execute(f"SELECT * FROM orders WHERE user_id = {user_id}")
# after
cur.execute("SELECT * FROM orders WHERE user_id = %s", (user_id,))
Every Critical/High must include the triggering condition and a concrete fix
(code where feasible). Mediums should include a fix or clear direction. Lows/Nits
can be one line each.
4. What's good
A short, genuine section acknowledging strengths — solid test coverage, a clean
abstraction, a good edge-case already handled. This is not filler: it calibrates
trust and signals you read the whole change, not just hunted for faults.
Reviewer principles (carry through every review)
- Be specific. Cite
file:line. "Somewhere there's a bug" helps no one.
- Propose the fix. A finding without a suggested direction is half a review.
- Separate must-fix from nice-to-have. The severity model is the contract.
- Don't block on nits. Label them, batch them, move on.
- Review the code, not the author. "This function…", not "you always…".
- Stay within scope. Note adjacent problems briefly, but don't rewrite the
PR; the diff under review is the subject.
1---2name: code-review3description: Rigorous, prioritized code review of a diff, PR, or file — correctness bugs first, then security (OWASP/CWE), performance, API design, tests, and maintainability. Outputs severity-rated findings with specific fixes, not nitpicks. Use to review a pull request, audit a change, or pre-merge check.4---56# Code Review78A disciplined, methodology-driven code review. The goal is **not** to leave many9comments — it is to find the issues that *matter*, rank them honestly by impact,10and propose a concrete fix for each. A review that flags one real11SQL-injection beats a review that flags twenty style nits and misses the bug.1213This skill is grounded in established practice:1415- **Correctness first.** Reviewers and research (Google, Microsoft, the SmartBear16 studies) converge on the same point: the highest-value defects found in review17 are logic and correctness defects, not formatting. Read for what the code18 *does* before what it *looks like*.19- **Security via OWASP / CWE.** The security pass is structured around the20 [OWASP Top 10](https://owasp.org/Top10/) categories and the corresponding21 [CWE](https://cwe.mitre.org/) weakness classes, so findings map to a recognized22 taxonomy instead of vibes.23- **Performance via Big-O reasoning.** Performance findings are justified by24 complexity and the cost model (allocations, round-trips, I/O), not by25 micro-optimization folklore.26- **"Comment on what matters, not nits."** In the spirit of Google's engineering27 code-review guidelines: distinguish things that must change from preferences,28 label preferences as such, and never block a merge on style when a linter or29 formatter could settle it.3031---3233## When to Activate3435Activate this skill when the user:3637- Shares a **diff**, **patch**, or **pull request** and asks for a review.38- Pastes a **file** or **function** and asks "is this correct / safe / any bugs?".39- Asks for a **pre-merge check**, **audit**, or **second pair of eyes**.40- Asks specifically to focus on **security**, **performance**, or **correctness**41 of a change (run the relevant pass with extra depth, but still do a quick42 sweep of the others).4344If the request is "write code" or "explain code," this is not the right skill.45This skill *evaluates existing code*.4647---4849## Step 1: Scope & Context5051Before reading line by line, establish what you are reviewing. State these back52to the user briefly so assumptions are visible:5354- **What changed?** A diff/PR (review only the changed lines plus their blast55 radius) or a whole file (review all of it). For a diff, the surrounding56 unchanged code is context, not subject — but flag it if the change *makes* it57 wrong (e.g. a new caller breaks an old invariant).58- **Language & framework.** Determines the idioms, the footguns, and the59 security surface (e.g. Django ORM vs raw SQL, React vs server-rendered HTML).60- **Runtime & security surface.** Is this server-side, client-side, a CLI, a61 library, infra-as-code? Does it touch the network, the filesystem, a database,62 user input, authentication, money, or PII? The surface dictates which passes63 matter most.64- **Tests present?** Did the change add or modify tests? Is there existing65 coverage for the touched code? "No tests for a behavior change" is itself a66 finding.67- **Intent.** What is the change *supposed* to do? Review against intent — a68 correct implementation of the wrong thing is still a finding.6970If critical context is missing (e.g. you cannot tell whether input is trusted),71say so explicitly and review for the worst plausible case.7273---7475## Step 2: Severity Model7677Every finding gets exactly one severity. Be honest — inflating severity trains78people to ignore you; deflating it lets real bugs ship.7980| Severity | Meaning | Blocks merge? |81|--------------|-------------------------------------------------------------------------|---------------|82| **Critical** | Data loss, security vulnerability, crash, or corruption in normal use. | Yes |83| **High** | Wrong behavior / incorrect results for realistic inputs. | Yes |84| **Medium** | Performance or design risk that will bite under load or over time. | Usually |85| **Low** | Maintainability: unclear code, duplication, weak naming, missing docs. | No |86| **Nit** | Pure style / preference a formatter or linter could decide. | No |8788Rules:8990- **Label nits as `Nit:` and never block on them.** If a formatter/linter can91 fix it, say so in one line and move on. Do not let nits dilute the signal.92- **One severity per finding.** If something is both a perf and a correctness93 problem, file it as the higher one and mention the other dimension.94- **Justify Critical/High.** State the input or condition that triggers the bad95 behavior. "Could be a problem" is not a finding; "with `n=0` this divides by96 zero" is.9798---99100## Step 3: Review Passes in Priority Order101102Run the passes **in this order**. Earlier passes outrank later ones: a103correctness bug is more important than a naming nit on the same line. Each pass104is a checklist of concrete things to look for.105106### (a) Correctness — *does it actually work?*107108The highest-value pass. Read the changed logic and ask "for which input does109this do the wrong thing?"110111- **Off-by-one / boundaries:** loop bounds, slice indices, `<` vs `<=`,112 inclusive/exclusive ranges, empty collections, single-element collections.113- **Null / undefined / None:** dereferencing a value that can be absent;114 Optionals unwrapped without a check; missing map keys; default-vs-missing.115- **Error handling:** swallowed exceptions; errors logged but not handled;116 ignored return/`error` values; partial failures that leave inconsistent state;117 cleanup that doesn't run on the error path (no `finally`/`defer`/`with`).118- **Edge cases:** zero, negative, empty string, very large input, Unicode,119 duplicate keys, the "happy path only" smell.120- **Concurrency / races:** shared mutable state without synchronization;121 check-then-act (TOCTOU); non-atomic read-modify-write; assuming ordering122 between async tasks; deadlock / lock-ordering.123- **Async / await:** missing `await` (fire-and-forget promise); awaiting in a124 loop that should be parallel; unhandled promise rejection; mixing callback and125 promise styles; `async` function whose error path is silently dropped.126- **Resource leaks:** files/sockets/connections/locks opened but not reliably127 closed; growing caches/listeners never released; goroutines/threads that never128 exit.129- **Numeric / floating-point:** `==` on floats; money in floats instead of130 integer minor units / decimal; integer overflow/truncation; rounding direction.131- **Time & timezones:** naive vs aware datetimes; assuming UTC; DST gaps;132 off-by-one on dates; comparing timestamps in different units (s vs ms).133- **Logic:** inverted conditions, wrong boolean operator, copy-paste of the134 wrong variable, fall-through, default branch missing.135136### (b) Security — *can it be abused?* (OWASP / CWE)137138Tag each finding with the relevant OWASP category and/or CWE id where it applies.139140- **Injection** — SQL, NoSQL, OS command, LDAP, template. String-concatenated141 queries or shell commands from user input. *(OWASP A03; CWE-89 SQLi, CWE-78142 command injection, CWE-94 code injection.)*143- **Broken access control** — missing/incorrect authz checks; IDOR (acting on an144 object id without verifying ownership); trusting a client-supplied role/flag.145 *(OWASP A01; CWE-285, CWE-639.)*146- **Authentication gaps** — missing auth on a sensitive route; weak session147 handling; credentials compared non-constant-time. *(OWASP A07; CWE-287.)*148- **Secrets in code** — hardcoded API keys, passwords, tokens, private keys;149 secrets logged. *(CWE-798 hardcoded credentials, CWE-532 secrets in logs.)*150- **Unsafe deserialization** — `pickle`/`yaml.load`/Java native deserialization151 of untrusted data; prototype pollution. *(OWASP A08; CWE-502.)*152- **SSRF** — fetching a user-controlled URL without allow-listing the host.153 *(OWASP A10; CWE-918.)*154- **Path traversal** — joining user input into a filesystem path without155 normalization/containment. *(CWE-22.)*156- **XSS** — rendering untrusted data into HTML without escaping; `innerHTML` /157 `dangerouslySetInnerHTML`; unsanitized template output. *(OWASP A03; CWE-79.)*158- **Missing input validation** — trusting length/type/range/format of external159 input; mass assignment binding unexpected fields. *(CWE-20, CWE-915.)*160- **Insecure crypto / transport** — MD5/SHA1 for passwords (use bcrypt/argon2);161 ECB mode; static IV; disabled TLS verification; predictable randomness for162 tokens. *(OWASP A02; CWE-327, CWE-295, CWE-330.)*163164### (c) Performance — *will it scale?* (Big-O + cost model)165166Justify each finding with complexity or a concrete cost (round-trips, bytes,167allocations). Do not micro-optimize cold paths.168169- **N+1 queries** — a query inside a loop over rows; missing eager-load/join.170- **Accidental O(n²)** — nested loops over the same collection; `in`/`indexOf` on171 a list inside a loop (use a set/map); repeated string concatenation in a loop.172- **Unnecessary allocations / copies** — copying large structures per iteration;173 building a full list when a generator/stream suffices; boxing in hot paths.174- **Blocking I/O on a hot path** — synchronous network/disk in a request handler175 or event loop; missing batching; chatty APIs.176- **Missing indexes** — querying/filtering on an unindexed column at scale.177- **Unbounded growth** — caches/queues/lists with no eviction or limit; loading178 an entire dataset into memory; recursion without depth bound.179180### (d) API & Design — *is it well-shaped?*181182- **Naming** — does the name say what it does? Misleading or vague names; verbs183 for queries with side effects.184- **Cohesion / responsibility** — function doing too much; mixed levels of185 abstraction; god object.186- **Leaky abstractions** — internal types/SQL/HTTP details bleeding through a187 public interface.188- **Backward compatibility** — removed/renamed public function, changed189 signature, changed default, changed serialization format, narrowed accepted190 input. Flag breaking changes explicitly and ask about versioning.191- **Error contracts** — what does this throw/return on failure? Is it consistent192 with siblings? Are errors typed/actionable or stringly-typed?193194### (e) Tests — *is the change covered?*195196- **Coverage for the change** — is the new/changed behavior actually exercised?197 A behavior change with no test is a finding.198- **Edge & negative cases** — only the happy path is tested; no test for the199 error path, empty input, or the boundary the code handles.200- **Flaky patterns** — reliance on real time/sleep, network, ordering of maps,201 shared global state between tests, randomness without a fixed seed.202- **Asserting implementation, not behavior** — tests that assert internal calls /203 private state and will break on refactor without catching real regressions;204 over-mocking that tests the mock.205206### (f) Maintainability — *can the next person change it?*207208- **Dead code** — unreachable branches, unused vars/imports/params, commented-out209 blocks.210- **Duplicated logic** — copy-paste that should be extracted; the same constant211 redefined.212- **Unclear names / magic numbers** — unexplained literals; abbreviations;213 single-letter names outside tight loops.214- **Comment quality** — comments that restate the code vs explain *why*; stale215 comments contradicting the code; missing doc on a non-obvious public API.216217---218219## Step 4: Red-Flags Quick Scan220221Before (or alongside) the passes, do a fast scan for instant blockers. Any hit is222**Critical** until proven safe:223224- Hardcoded secret / API key / password / private key.225- `eval` / `exec` / `Function()` / `system()` on anything derived from input.226- SQL/command built by string concatenation or f-string with a variable.227- TLS/cert verification disabled (`verify=False`, `rejectUnauthorized: false`,228 `InsecureSkipVerify: true`).229- Catch-all that swallows errors silently (`except: pass`, empty `catch {}`).230- A committed `.env`, credentials file, or key material in the diff.231- Infinite-loop / unbounded-recursion risk (loop with no progress toward exit).232- `dangerouslySetInnerHTML` / `innerHTML` with non-constant data.233- Disabled auth/permission check, or a `# TODO: add auth` on a live route.234235---236237## Step 5: Output Format238239Produce the review in this structure. Be specific, cite the line, propose the240fix, and separate must-fix from nice-to-have.241242### 1. Verdict243244One line, one of:245246- **Approve** — no blocking issues; any comments are Low/Nit.247- **Approve with comments** — safe to merge after addressing minor points; no248 Critical/High.249- **Request changes** — one or more Critical/High findings must be fixed first.250251Follow with a one-sentence rationale.252253### 2. Findings table254255| ID | Location | Severity | Issue |256|----|----------|----------|-------|257| C1 | `path/file.py:42` | Critical | SQL injection via f-string query (CWE-89) |258| H1 | `path/file.py:31` | High | Endpoint missing ownership check (IDOR) |259| M1 | `path/file.py:55` | Medium | N+1 query inside the response loop |260261Order by severity (Critical → Nit). Use stable IDs (`C1`, `H1`, `M2`, `L1`,262`N1`) so the user can reference them.263264### 3. Per-finding detail265266For each finding, in severity order:267268> **[C1] SQL injection — `path/file.py:42` — Critical (CWE-89, OWASP A03)**269> **Why it matters:** the `user_id` value comes straight from the request and is270> interpolated into the query string, so an attacker can read or drop tables.271> **Fix:** use a parameterized query.272> ```python273> # before274> cur.execute(f"SELECT * FROM orders WHERE user_id = {user_id}")275> # after276> cur.execute("SELECT * FROM orders WHERE user_id = %s", (user_id,))277> ```278279Every Critical/High **must** include the triggering condition and a concrete fix280(code where feasible). Mediums should include a fix or clear direction. Lows/Nits281can be one line each.282283### 4. What's good284285A short, genuine section acknowledging strengths — solid test coverage, a clean286abstraction, a good edge-case already handled. This is not filler: it calibrates287trust and signals you read the whole change, not just hunted for faults.288289---290291### Reviewer principles (carry through every review)292293- **Be specific.** Cite `file:line`. "Somewhere there's a bug" helps no one.294- **Propose the fix.** A finding without a suggested direction is half a review.295- **Separate must-fix from nice-to-have.** The severity model is the contract.296- **Don't block on nits.** Label them, batch them, move on.297- **Review the code, not the author.** "This function…", not "you always…".298- **Stay within scope.** Note adjacent problems briefly, but don't rewrite the299 PR; the diff under review is the subject.