Files

74 lines
6.2 KiB
Markdown

# Review lenses
Use every core lens. Expand only the checks relevant to the changed surfaces.
## Contents
- Correctness and unintended behavior
- Test validity
- Security and defensive coding
- Architecture and maintainability
- Conditional lenses
## Correctness and unintended behavior
- Trace happy, error, empty, null, boundary, retry, cancellation, and partial-failure paths.
- Check state transitions, ordering, idempotency, caching, invalidation, and cleanup.
- Look for off-by-one errors, stale state, wrong defaults, lossy conversions, timezone or locale mistakes, and mismatched units.
- Check async ownership, missing awaits, races, deadlocks, double execution, resource leaks, and work after cancellation.
- Compare types and runtime values across boundaries; do not assume static types validate external data.
- Check compatibility with existing callers, serialized formats, database rows, events, CLI flags, environment variables, and public APIs.
- Follow error values and exceptions. Flag swallowed failures, misleading fallbacks, partial writes, and success reported before durable completion.
- Verify deletions and refactors leave no live caller, stale branch, duplicate path, or behavior split between old and new implementations.
- Distinguish behavior newly broken by the change from a nearby pre-existing issue.
## Test validity
- Identify the behavior each test claims to protect and the production branch that implements it.
- Mentally mutate or remove the production behavior. Determine whether the test fails for the intended reason.
- Detect tautological assertions, assertions derived from the same value under test, snapshots accepted without semantic inspection, and tests with no meaningful assertion.
- Check that the exercised path runs: awaited promises, consumed generators, subscribed streams, flushed transactions, rendered components, and invoked callbacks.
- Treat mocks as contracts. Compare mock methods, data, ordering, errors, and side effects with the real dependency.
- Flag tests that verify implementation details while missing observable outcomes.
- Check false positives from broad exception assertions, loose matchers, unconditional waits, retries that mask failure, or fixtures that bypass the behavior.
- For bug fixes, require a regression test that would fail on the old behavior when practical.
- Seek high-risk gaps: permissions, tenant isolation, malformed input, boundaries, failure recovery, concurrency, migrations, and cross-component integration.
- Do not demand a test for trivial wiring already proven by stronger coverage.
## Security and defensive coding
- Identify trust boundaries and attacker-controlled input before applying a checklist.
- Check authentication, authorization, object ownership, tenant isolation, and confused-deputy paths at the point of action.
- Validate and canonicalize input at boundaries; encode output for its destination context.
- Look for injection into SQL, commands, templates, HTML, URLs, headers, logs, paths, deserializers, and dynamic code.
- Check secrets, credentials, tokens, personal data, and sensitive metadata in source, logs, errors, caches, telemetry, URLs, and client-visible responses.
- Review cryptography, randomness, signature verification, token lifetime, replay resistance, secure comparison, and key handling when touched.
- Check filesystem traversal, unsafe temporary files, archive extraction, symlink behavior, permissions, and cleanup.
- Review SSRF, redirect validation, request smuggling surfaces, unbounded downloads, parser limits, and denial-of-service opportunities for network-facing changes.
- Check dependency provenance, pinned integrity, install or build scripts, dangerous configuration defaults, and privilege expansion.
- Prefer fail-closed behavior where authorization or integrity is uncertain, without turning recoverable availability failures into outages.
- Consider abuse cases and defense in depth; report only issues supported by a realistic capability and impact.
## Architecture and maintainability
- Compare the change with existing architectural boundaries and dependency direction.
- Check separation of orchestration, domain logic, persistence, transport, and presentation.
- Identify feature logic leaking into shared infrastructure or transport details leaking into the domain.
- Look for duplicated sources of truth, parallel implementations, inconsistent policy enforcement, and abstractions that conceal rather than remove complexity.
- Challenge both under-abstraction and premature abstraction. Require a named invariant or repeated variation before adding a general layer.
- Check cohesion, coupling, fan-in/fan-out, circular dependencies, global state, hidden temporal coupling, and unclear resource ownership.
- Prefer explicit invariants, narrow interfaces, meaningful types, and canonical helpers over casts, optional fields, catch-all objects, and silent fallbacks.
- Judge readability through control flow, naming, locality, concept count, and how much unrelated context a maintainer must retain.
- Check whether the design supports likely change without optimizing for hypothetical futures.
- When suggesting restructuring, name the move and why it lowers risk: split responsibility, invert dependency, centralize policy, remove pass-through abstraction, model state explicitly, or reuse a canonical path.
- Avoid requesting large refactors unless the current change creates or materially worsens the problem.
## Conditional lenses
- Performance: complexity, repeated I/O, N+1 access, allocations, hot-path blocking, pagination, cache correctness, and backpressure.
- Data changes: forward/backward compatibility, transactionality, rollbacks, backfills, mixed-version deployment, and irreversible loss.
- Distributed systems: retries, duplicate delivery, ordering, idempotency, clock assumptions, split brain, and partial availability.
- UI and accessibility: loading/error/empty states, keyboard and focus behavior, semantics, contrast, responsive behavior, and hydration.
- Observability: actionable errors, stable structured fields, correlation, sensitive-data hygiene, metrics on failure paths, and diagnosable fallbacks.
- Dependencies and configuration: default changes, environment parity, least privilege, reproducibility, version compatibility, and safe rollout.