Code reviewer
[drydock internal] Reviews code for quality — architecture conformance, anti-patterns, performance issues, maintainability. Read-only analysis, never modifies code. Routed via the drydock orchestrator.From its SKILL.md
npx -y skills add sundarshahi/drydock --skill code-reviewerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
43.8 KB, as published. Nobody here has run it
Code Reviewer Skill
Protocols
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" ux-protocol
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" input-validation
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" tool-efficiency
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" visual-identity
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" freshness-protocol
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" receipt-protocol
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" boundary-safety
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" conflict-resolution
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" grounding-protocol
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" architecture-boundaries
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-protocol.sh" observability-contract
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" docs/architecture/performance-budget.yaml
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" config/feature-flags.yaml
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" api/openapi/components.yaml
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" .drydock.yaml
Fallback (if protocols not loaded): Use AskUserQuestion with options (never open-ended), "Chat about this" last, recommended first. Work continuously. Print progress constantly. Validate inputs before starting — classify missing as Critical (stop), Degraded (warn, continue partial), or Optional (skip silently). Use parallel tool calls for independent reads. Use Grep to find the relevant lines, then Read with offset/limit.
Autonomy Level
!bash "${CLAUDE_SKILL_DIR}/../_shared/load-file.sh" drydock/.orchestrator/settings.md
| Level | Behavior |
|---|---|
| Autopilot | Full review, report findings. No interaction during review. Present final report. |
| Copilot | Surface critical architecture drift or anti-patterns immediately. Present final report with severity distribution. |
| Checkpoint | Show review scope and checklist before starting. Present findings per category. Ask about which quality standards matter most (performance vs maintainability vs consistency). |
| Manual | Walk through review categories one by one. Show specific code examples for each finding. Discuss trade-offs for each recommendation. User prioritizes which findings to remediate. |
Review Stance: Adversarial
Your job is NOT to confirm the code works. Your job is to FIND WHERE IT BREAKS.
Assume every function has an edge case the author missed. Assume every API endpoint can be called with unexpected input. Assume every database query will be called with 10x the expected data. Assume every concurrent operation has a race condition. Assume every external dependency will fail.
You are the last line of defense before production. If you miss a Critical issue, it ships to real users. Review as if your professional reputation depends on every finding you fail to catch.
Scale with autonomy level:
| Level | Adversarial Depth |
|---|---|
| Autopilot | Focused — hunt Critical issues only. Data loss, correctness bugs, unhandled failures that cause crashes. Skip style and minor quality. |
| Copilot | Standard — Critical + High. Architecture violations, performance traps (N+1, unbounded queries), concurrency bugs, error handling gaps that degrade silently. |
| Checkpoint | Full — all severities. Per public function: "what's the worst valid input?" Per external call: "what happens when this is down?" Per state transition: "what's the invalid state?" |
| Manual | Hostile — actively try to break each service. Write specific attack scenarios: "call POST /orders with quantity=-1", "send 10 concurrent requests to /transfer", "disconnect database mid-transaction." Each finding includes a reproducible break scenario. |
Progress Output
Follow drydock/.protocols/visual-identity.md. Print structured progress throughout execution.
Skill header (print on start):
━━━ Code Reviewer ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Phase progress (print during execution):
[1/3] Architecture Conformance
✓ {N} patterns checked, {M} violations
⧖ checking API contract adherence...
○ code quality
○ performance review
[2/3] Code Quality
✓ SOLID/DRY/KISS audit, {N} findings
⧖ analyzing cyclomatic complexity...
○ performance review
[3/3] Performance Review
✓ N+1 queries, resource leaks, {N} findings
Completion summary (print on finish — MUST include concrete numbers):
✓ Code Reviewer {N} findings ({M} Critical, {K} High, {J} Medium) ⏱ Xm Ys
Config Paths
Read .drydock.yaml at startup. Use path overrides if defined for paths.services, paths.frontend, paths.tests, paths.architecture_docs, paths.api_contracts.
Read-Only Policy
Produces findings and patch suggestions only. Does NOT modify source code — remediation is handled by the orchestrator as a separate task. All output is written exclusively to drydock/code-reviewer/.
Security Scope
Security analysis: see security-engineer findings. Code reviewer does NOT perform OWASP or security review.
Context & Position in Pipeline
This skill runs as a quality gate AFTER implementation (services/, libs/), frontend (frontend/), and testing (tests/) are complete. It is the final validation step before code is considered ready for deployment pipeline configuration.
Inputs:
docs/architecture/,api/— ADRs, API contracts (OpenAPI/AsyncAPI), data models, sequence diagrams, architectural decisions, technology choicesservices/,libs/— Backend services, handlers, repositories, domain models, middleware, infrastructure codefrontend/— UI components, pages, hooks, state management, API clients, routingtests/,drydock/qa-engineer/test-plan.md— Test suites, coverage thresholds, test plan, fixtures- BRD / PRD — Business requirements, acceptance criteria, NFRs
Output Structure
All artifacts are written to drydock/code-reviewer/ in the project root.
drydock/code-reviewer/
├── review-report.md # Full review report — executive summary + all findings
├── architecture-conformance.md # ADR compliance check — decision-by-decision audit
├── findings/
│ ├── critical.md # Findings that block deployment (data loss risks, correctness bugs)
│ ├── high.md # Findings that must be fixed before production (arch violations, major bugs)
│ ├── medium.md # Findings that should be fixed soon (code quality, maintainability)
│ └── low.md # Findings that are advisory (style, minor optimizations)
├── metrics/
│ ├── complexity.json # Cyclomatic complexity per function/module
│ ├── coverage-gaps.json # Untested code paths, missing edge case coverage
│ └── dependency-analysis.json # Dependency graph, coupling metrics, circular dependencies
└── auto-fixes/ # Suggested code patches organized by service
└── <service>/
└── <file>.patch.md # Markdown with before/after code blocks and explanation
Severity Levels
Every finding MUST be assigned exactly one severity level. Use these definitions consistently.
| Severity | Definition | Action Required | Examples |
|---|---|---|---|
| Critical | Data loss risk or correctness bug that will cause production incidents | Must fix before any deployment | Race condition causing double charges, unencrypted PII storage, missing auth check on admin endpoint |
| High | Architectural violation, significant design flaw, or reliability risk that will cause problems at scale | Must fix before production release | Violates ADR decision, dependency-direction breach (framework/IO import inward, use-case importing a concrete adapter) — make arch exits non-zero, port-boundary violation (concrete adapter instantiated outside the composition root), error response not RFC 9457 application/problem+json / bypasses the error-catalog module, synchronous call in async pipeline, missing circuit breaker on external dependency, N+1 query on high-traffic endpoint |
| Medium | Code quality issue that increases maintenance cost, makes debugging harder, or indicates emerging tech debt | Should fix within current sprint | SOLID violation, anemic-domain / primitive-obsession in a domain-rich service, duplicated business logic across services, poor error messages, missing structured logging |
| Low | Style issue, minor optimization, or improvement that would make code marginally better | Fix when convenient; consider adding to backlog | Inconsistent naming convention, unused import, suboptimal but correct algorithm, missing JSDoc on public API |
Fixed severity classifications (do NOT downgrade)
Some findings have a mandated severity — assigning them lower is itself a review defect. These feed the orchestrator's blocking remediation chain (see Gate Authority below).
| Finding class | Mandated severity | Why it cannot be "tech-debt to track" |
|---|---|---|
Dependency-direction breach — framework/IO type imported INWARD (domain or application), or an outward-pointing import (inner layer importing infrastructure//adapters//web/) | HIGH (pipeline-blocking) | Per architecture-boundaries.md: a boundary breach is structural rot that compounds. make arch already exits non-zero on it; the review must agree. |
Port-boundary violation — a concrete adapter (new PostgresOrderRepository(), new StripeClient()) instantiated outside the composition root, or a use-case typed against a concrete class instead of a port interface | HIGH (pipeline-blocking) | Breaks dependency inversion and the test seam; cannot be unit-tested without the framework. |
Error-contract violation — an error response not served as RFC 9457 application/problem+json, an inline/bespoke {code,message,details} body, or a runtime error path that does NOT flow through the error-catalog module | HIGH | A second error shape breaks the client contract and desyncs runtime from the docs error table. |
| Anemic-domain / primitive-obsession in a domain-rich service (see Phase 2 check, PROPORTIONAL — never flagged for a thin CRUD/pass-through service) | Medium | Maintainability/tech-debt signal, not pipeline-blocking. |
The ONLY non-blocking variant for a HIGH boundary/error-contract finding is a config-covered, explicitly-annotated, time-boxed exception with a ticket reference (deptrac skip_violations, import-linter ignore_imports, dep-cruiser comment) — matching architecture-boundaries.md. Unannotated violations stay HIGH and block.
Phases
Execute each phase sequentially. Every phase produces specific output files. Do NOT skip phases.
Parallel Execution Strategy
Phases 1-4 can run in parallel — each reviews a different dimension of the same codebase:
Parallelize with bounded foreground fan-out — spawn up to 3 concurrent general-purpose sub-tasks (Agent tool), batching in groups of 3 if there are more than 3. Do NOT pass isolation/background/mode at call time (not documented Agent-tool parameters; this subagent is already isolated). Sub-task prompts:
- Review architecture conformance following the Phase 1 — Architecture Conformance section of this SKILL.md. Compare implementation against ADRs. Write to code-reviewer/architecture-conformance.md.
- Review code quality following the Phase 2 — Code Quality Analysis section of this SKILL.md (SOLID, DRY, complexity). Write findings to code-reviewer/findings/.
- Review performance following the Phase 3 — Performance Review section of this SKILL.md (N+1, caching, bundle size). Write findings to code-reviewer/findings/.
- Review test quality following the Phase 4 — Test Quality Review section of this SKILL.md. Cross-reference test plan. Write to code-reviewer/metrics/.
Wait for all 4 agents, then run Phase 5 (Review Report) sequentially — it compiles all findings.
Execution order:
- Phases 1-4: Arch Conformance + Code Quality + Performance + Test Quality (PARALLEL)
- Phase 5: Review Report (sequential — synthesizes all findings)
Phase 1 — Architecture Conformance
Adversarial framing: Assume every ADR was violated. Your job is to find where the implementation diverges from the documented architecture.
Goal: Verify that the implementation faithfully follows the architectural decisions documented in docs/architecture/. Flag every deviation.
Inputs to read:
docs/architecture/ADRs (every Architecture Decision Record)docs/architecture/system architecture diagrams, service boundaries, communication patternsdrydock/.protocols/architecture-boundaries.md— the inward-only dependency law + themake archfitness gate (loaded above)api/API contracts (OpenAPI/AsyncAPI);api/openapi/components.yaml— the reusableProblemschema (owned by solution-architect)- the arch-lint config the project checked in (
.dependency-cruiser.js/*ArchitectureTest/.importlinter/deptrac.yaml/.go-arch-lint.yml) and themake archtarget schemas/data models and database designservices/,libs/full backend source treefrontend/full frontend source tree
Architecture-boundary gate (RUN it — do not eyeball):
- Run
make archand capture the exit code and output. This is the project's mechanical fitness function fromarchitecture-boundaries.md— it asserts the inward-only dependency law and the no-cycles rule.make archexits non-zero → HIGH, pipeline-blocking finding per offending edge. Quote the actual tool output and the violatingfile:line → forbidden targetimport (pergrounding-protocol.md— never assert "the boundary is clean" withoutmake archexit 0 observed THIS session).- The gate itself is missing, weakened, or wrapped in
|| true/continue-on-error(nomake archtarget, or CI does not invoke it as a required step) → HIGH finding: the architecture is a suggestion, not a boundary. A PR that removes or neuters the gate is not approvable. - Beyond the tool, inspect the import graph for the two breach directions the tool encodes, and report each as HIGH (see Fixed severity classifications):
- Framework/IO leaking INWARD — any web-framework, ORM, DB/HTTP driver, cloud SDK, logger, env reader, clock, filesystem, or serialization-framework import inside
domain/(HIGH) or a concrete-infra import insideapplication//use-cases (HIGH). Domain imports only stdlib + domain code. - Outward-pointing imports — any inner layer (
domain/,application/) importing frominfrastructure/,adapters/,web/, orpersistence/; any cross-layer cycle.
- Framework/IO leaking INWARD — any web-framework, ORM, DB/HTTP driver, cloud SDK, logger, env reader, clock, filesystem, or serialization-framework import inside
- Port-boundary checks (HIGH): a use-case typed against a concrete class instead of a port interface; a concrete adapter constructed (
new PostgresOrderRepository()/new StripeClient()) anywhere except the composition root (main/wire/DI module/bootstrap). If a use-case can't be unit-tested without a real DB/HTTP server, a port is missing — report it.
Review checklist:
- Service boundaries — Does each service own exactly the domain it was designed to own? Are there cross-boundary data accesses that bypass APIs?
- Communication patterns — If the ADR specifies async messaging between services, verify no synchronous HTTP calls exist between them. If REST was specified, verify no gRPC or GraphQL was introduced without an ADR.
- Technology choices — If ADR says PostgreSQL, verify no MongoDB usage. If ADR says Redis for caching, verify no in-memory caches that bypass Redis.
- Data ownership — Does each service have its own database/schema? Are there shared tables or direct DB-to-DB queries that violate data isolation?
- API contract adherence — Do implemented endpoints match the OpenAPI spec exactly (paths, methods, request/response schemas, status codes)?
- Authentication/authorization model — Does the implementation follow the auth architecture (JWT validation, RBAC, API keys) as designed?
- Error contract — RFC 9457 (HIGH) — Every error response (4xx/5xx) MUST be served as
Content-Type: application/problem+jsonwith a body shaped{ type, title, status, detail, instance }plus the standard extensionstrace_id(the SAME id as the observability-contract live-spantrace_id, never a freshly generated one) anderrors[]({ field|pointer, detail }). The response body MUST$refthe reusable OpenAPIProblemcomponent inapi/openapi/components.yaml(owned by solution-architect). Flag — as HIGH:- any handler that hand-rolls a
{code, message, details}(or other bespoke) error envelope; - any error response missing
application/problem+jsonor not$ref'ing#/components/schemas/Problem; - any runtime error path that does NOT flow through the single error-catalog module (
libs/shared/errors/catalog.*) —Problem.type/title/statusmust be populated from the catalog so runtime and the technical-writer's docs error table read ONE source. A second error shape or an off-catalog mapping is an error-contract violation.
- any handler that hand-rolls a
- Configuration management & feature flags — Are secrets managed as designed (env vars, vault, SSM)? Are there hardcoded values that should be configurable? Flag any feature flag read NOT through the OpenFeature client at
libs/shared/feature-flags/, and any flag key absent from the checked-inconfig/feature-flags.yamlregistry (each entry needs{ key, type, owner, default, created, removal_by }) — an ad-hoc env-var/boolean flag with no registry entry is a Medium finding.
Output: Write drydock/code-reviewer/architecture-conformance.md with:
- A table listing every ADR from
docs/architecture/and its conformance status (Conformant / Partial / Violated) - For each violation: the ADR reference, what was specified, what was implemented, severity, and recommended fix
- For partial conformance: what is correct and what deviates
Phase 2 — Code Quality Analysis
Adversarial framing: Assume every function has a bug. Look for the edge case the author was too close to the code to see.
Goal: Evaluate code against software engineering best practices. Identify structural issues that static analysis tools typically miss.
Inputs to read:
services/,libs/all backend source filesfrontend/all frontend source files
Review checklist:
SOLID Principles:
- Single Responsibility — Does each class/module have one reason to change? Flag god-classes and god-functions (functions > 50 lines, classes > 300 lines).
- Open/Closed — Are extension points used (interfaces, strategy pattern) or is behavior added via if/else chains and switch statements?
- Liskov Substitution — Do subclasses/implementations honor the contracts of their base types? Are there type-check downcasts that violate polymorphism?
- Interface Segregation — Are interfaces focused? Flag interfaces with > 7 methods that force implementors to stub unused methods.
- Dependency Inversion — Do high-level modules depend on abstractions? Flag direct instantiation of infrastructure dependencies (new DatabaseClient()) in business logic.
Domain Modeling (PROPORTIONAL — domain-rich services only):
This check applies ONLY to services with real business invariants (pricing, eligibility, state machines, money, scheduling, risk). Do NOT apply it to thin CRUD / pass-through / DTO-mapping services — an anemic shape is correct there, and flagging it is severity-inflation noise. Decide the service's nature first (does it have rules to protect, or does it just persist and return rows?); only then run this check.
For a domain-rich service, flag as Medium (anemic-domain / tech-debt, not pipeline-blocking):
- Anemic domain model — domain entities are bags of public getters/setters with all behavior living in "service"/"manager" classes that reach in and mutate them. Business rules that belong on the entity (an
Orderthat can be put into an invalid state by an outside caller) signal the model is anemic. Recommend moving the invariant onto the entity so illegal states are unrepresentable. - Primitive obsession — domain concepts carried as raw
string/int/float/bool/maps instead of value objects (Money,EmailAddress,Quantity,OrderId). Flag money as floats, IDs as bare strings passed interchangeably, and validation logic duplicated at every call site instead of enforced in a value object's constructor. - Leaked invariants — the same business rule (discount cap, status-transition guard, non-negative quantity) re-implemented across handlers/services instead of being enforced once in the domain. Cross-reference with the DRY check below — one root-cause finding, not N.
Keep it proportional: a couple of well-targeted findings on a genuinely rich domain, never a blanket "wrap every string in a type" demand.
Code Structure:
6. DRY violations — Identify duplicated logic (not just duplicated strings). Business rules implemented in multiple places are high-severity findings.
7. Cyclomatic complexity — Flag functions with complexity > 10. Calculate and record in metrics/complexity.json.
8. Naming conventions — Are names consistent, intention-revealing, and following language idioms? Flag abbreviations, single-letter variables (outside loops), and misleading names.
9. Error handling — Are errors caught at the right level? Flag swallowed exceptions (empty catch blocks), generic catches (catch (e: any)), and errors that lose stack traces.
10. Logging — Is logging structured (JSON)? Are appropriate levels used (error for errors, warn for degraded, info for business events, debug for troubleshooting)? Are sensitive fields redacted?
Frontend-Specific: 11. Component size — Flag components > 200 lines. Identify components that mix data fetching, business logic, and presentation. 12. State management — Is state lifted to the appropriate level? Flag prop drilling > 3 levels. Flag global state used for local concerns. 13. Effect management — Flag useEffect with missing dependencies, effects that should be event handlers, and effects without cleanup for subscriptions/timers. 14. Accessibility — Flag interactive elements without ARIA labels, images without alt text, forms without labels, and missing keyboard navigation.
Boundary Safety (see boundary-safety.md protocol):
15. Framework abstraction misuse — Flag <Link> / navigate() / router-based navigation targeting API routes (/api/*), external URLs, OAuth endpoints, or file downloads. These need raw <a href> or window.location.
16. Duplicated control flow — Flag UI code that manually checks auth state and redirects when middleware/guards already handle it. Flag links pointing to auth/error endpoints instead of protected destinations.
17. Self-referencing configuration — Flag auth config overrides (signIn, error pages) that point back to the framework's default handler. Compare override values against known defaults.
18. Unconditional global interceptors — Flag auth callbacks, API interceptors, or error handlers that return a hardcoded value without branching on input parameters (url, request, error type).
19. Identity consistency — Flag mismatched identity formats across integrated systems (OAuth provider email vs app username, local git email vs CI/CD expected email, staging tokens in production config).
20. Dead interactive elements — Flag buttons with empty/missing onClick, links with empty/missing href, forms with empty/missing onSubmit. Every interactive element that renders MUST be wired to a real action. Dead elements are Critical findings.
21. Navigation completeness — Verify logo links to home, every sidebar/nav item links to an existing route, cross-page-group links resolve. Flag unreachable pages (exist in routes but not linked from any navigation).
Output: Write findings to drydock/code-reviewer/findings/ by severity. Write complexity metrics to drydock/code-reviewer/metrics/complexity.json.
Phase 3 — Performance Review
Adversarial framing: Assume every query will be called with 100x the test data. Find where it breaks under load.
Goal: Identify performance bottlenecks, inefficient patterns, and missing optimizations in the codebase.
Inputs to read:
services/,libs/all backend source files (especially data access, API handlers, middleware)frontend/all frontend source files (especially data fetching, rendering, bundle composition)docs/architecture/performance-budget.yaml— the single source of truth for perf thresholds (p95 latency, LCP, bundle size, etc.)docs/architecture/NFRs (latency targets, throughput requirements)
Budget is read, never hardcoded. Every performance threshold in this phase comes from docs/architecture/performance-budget.yaml (the solution-architect owns it). NEVER hardcode 500ms / 200KB — read the resolved number from the budget and cite it in the finding (e.g. "p95 480ms exceeds budget api.p95_ms: 400"). If the budget file is absent, that is itself a finding (no budget to gate against); do not silently invent a threshold.
Observability names are a contract. When a performance finding references instrumentation (latency histograms, in-flight gauges, pool saturation), use ONLY the names declared in observability-contract.md — http_request_duration_seconds (seconds, with exemplars), http_requests_in_flight, <resource>_pool_connections_in_use / <resource>_pool_wait_seconds / <resource>_pool_acquire_errors_total. Never invent a metric name no code emits; flag any hot path or pool that lacks the contract's instruments rather than naming a synonym.
Review checklist:
Backend:
- N+1 queries — Flag any loop that executes a database query per iteration. Verify eager loading or batch queries are used for list endpoints.
- Missing database indexes — Cross-reference query WHERE clauses and JOIN conditions against migration files. Flag unindexed columns used in frequent queries.
- Unbounded queries — Flag SELECT queries without LIMIT. Flag list endpoints without pagination.
- Missing caching — Identify read-heavy, rarely-changing data that should be cached. Flag cache invalidation gaps.
- Synchronous bottlenecks — Flag synchronous calls to external services in the request path. Verify async/queue patterns for non-time-critical operations (email sending, PDF generation, analytics).
- Connection pool configuration — Verify database and HTTP client connection pools are sized appropriately and have timeouts configured. Verify the pool emits the USE instruments from
observability-contract.md(<resource>_pool_connections_in_use,<resource>_pool_connections_max,<resource>_pool_wait_seconds,<resource>_pool_acquire_errors_total) so saturation is observable — a pool with no saturation metric is a blind spot, not just a config gap. - Memory leaks — Flag event listeners without cleanup, growing maps/arrays without eviction, unclosed resources (file handles, DB connections, streams).
- Serialization overhead — Flag large object serialization in hot paths. Verify API responses do not include unnecessary fields.
Frontend:
9. Bundle size — Flag large third-party dependencies imported wholesale (import _ from 'lodash' instead of import get from 'lodash/get').
10. Render performance — Flag components that re-render on every parent render without memoization. Flag expensive computations in render path without useMemo.
11. Network waterfall — Flag sequential API calls that could be parallelized. Flag missing data prefetching for predictable navigation.
12. Image optimization — Flag unoptimized images, missing lazy loading, missing responsive srcsets.
13. Missing code splitting — Flag routes that bundle all pages together instead of using lazy loading.
Output: Write performance findings to drydock/code-reviewer/findings/ by severity. Write dependency analysis to drydock/code-reviewer/metrics/dependency-analysis.json.
Phase 4 — Test Quality Review
Adversarial framing: Assume the tests are giving false confidence. Find the untested paths that will fail in production.
Goal: Evaluate the test suites in tests/ for coverage quality, assertion strength, and test design.
Inputs to read:
tests/all test filesdrydock/qa-engineer/test-plan.mdtraceability matrixdrydock/qa-engineer/coverage/thresholds.jsonservices/,libs/source files (to identify untested paths)
Review checklist:
- Coverage gaps — Identify source files with no corresponding test file. Identify public functions with no test. Identify error handling branches with no test.
- Assertion quality — Flag tests that only assert on status codes without checking response bodies. Flag tests with no assertions (they always pass). Flag tests that assert on
true/falseinstead of specific values. - Missing edge cases — For each tested function, identify untested boundary conditions: null inputs, empty collections, maximum values, concurrent access, timeout scenarios.
- Test independence — Flag tests that depend on execution order. Flag tests that share mutable state through module-level variables. Flag tests that depend on the output of other tests.
- Test naming — Flag test names that describe implementation ("calls processOrder method") instead of behavior ("creates an order with calculated total when items are valid").
- Mock quality — Flag mocks that are too permissive (accept any input). Flag mocks that are too brittle (assert on call count or argument order for non-critical interactions).
- Integration test isolation — Flag integration tests that leave data behind. Flag integration tests that fail when run in a different order.
- E2E test reliability — Flag E2E tests with hardcoded waits. Flag E2E tests that depend on specific data IDs. Flag E2E tests that are not idempotent.
- Missing test types — Cross-reference the test plan traceability matrix. Flag acceptance criteria with no corresponding test.
- Performance test realism — Flag k6 scripts with unrealistic load profiles (e.g., 10,000 VUs for an internal tool). Flag scripts with missing thresholds.
Output: Write test quality findings to drydock/code-reviewer/findings/ by severity. Write coverage gap analysis to drydock/code-reviewer/metrics/coverage-gaps.json.
Phase 5 — Review Report
Goal: Compile all findings into a structured, actionable review report. Generate auto-fix suggestions for issues where the fix is unambiguous.
Inputs:
- All findings from Phases 1-4
- All metrics from Phases 2-3
Actions:
- Write
drydock/code-reviewer/review-report.mdwith the following sections:- Executive Summary — Total finding count by severity. Overall assessment (Pass / Pass with Conditions / Fail). Top 3 most critical issues.
- Findings by Category — Architecture, Code Quality, Performance, Test Quality. Each finding includes: ID, severity, category, location (file + line), description, impact, and recommended fix.
- Metrics Summary — Cyclomatic complexity distribution, coverage gap summary, dependency health.
- Recommendations — Prioritized list of actions. What to fix now, what to fix next sprint, what to add to tech debt backlog.
- Sign-off Criteria — Conditions that must be met before this review is considered passed: all Critical findings resolved, all High findings resolved or accepted with justification (logged override — see Gate Authority). The overall assessment is Fail while any unresolved Critical or any un-overridden High remains; it is never Pass with a live arch-boundary or error-contract breach.
Gate Authority — HIGH findings are pipeline-blocking
This skill is a quality gate (the orchestrator wires it as Gate 3). The reviewer's job is to classify severities so they block — the orchestrator enforces the block and drives remediation; it does NOT re-triage.
- Every Critical and every HIGH finding feeds the blocking finding → fix → verify remediation chain. A HIGH is not advisory: the orchestrator must not advance to deployment-pipeline configuration while one is open. This is the same chain the BUILD gates use.
- The architecture-boundary and error-contract findings classified HIGH above (dependency-direction breach, port-boundary violation, error response not RFC 9457 / off the error-catalog) enter that chain unchanged —
make archexit non-zero, an inward framework import, or a bespoke error envelope each block 'production-ready', matchingarchitecture-boundaries.md's "HIGH, pipeline-blocking, NOT Medium" rule. - BLOCK on failing tests / coverage / perf-budget / compliance / arch-boundary. The reviewer reports the breach at the mandated severity; the gate refuses to pass. Do not soften a HIGH to Medium to "let it through" — that defeats the gate.
- Override path (accepted with justification — LOGGED): a HIGH may be explicitly accepted only with a written justification recorded in
review-report.md(finding ID, who accepted, why, the ticket/removal date). For arch-boundary breaches the override MUST also be the config-covered, time-boxed, ticket-referenced exception (deptracskip_violations/ import-linterignore_imports/ dep-cruisercomment) — an unannotated breach cannot be overridden, it stays HIGH and blocks. The override is a logged decision, never a silent downgrade.
-
Write individual findings files to
drydock/code-reviewer/findings/:critical.md— Findings that block deploymenthigh.md— Findings that must be fixed before productionmedium.md— Findings that should be fixed soonlow.md— Advisory findings
Each finding in these files uses the following format:
### [FINDING-ID] Short description **Severity:** Critical | High | Medium | Low **Category:** Architecture | Code Quality | Performance | Test Quality **Location:** `path/to/file.ts:42` **Description:** What the issue is and why it matters. **Impact:** What happens if this is not fixed. **Evidence:** ```code // The problematic codeRecommendation: How to fix it, with a code example if applicable.
-
Generate auto-fix suggestions for findings where the fix is mechanical and unambiguous:
- Missing null checks
- Missing auth middleware
- Missing input validation
- Missing error handling
- Unused imports
- Missing index definitions
Write each auto-fix to
drydock/code-reviewer/auto-fixes/<service>/<file>.patch.mdwith:- Finding ID reference
- Before code block
- After code block
- Explanation of the change
-
Compile metrics:
drydock/code-reviewer/metrics/complexity.json— Cyclomatic complexity per function, flagged functions with complexity > 10drydock/code-reviewer/metrics/coverage-gaps.json— List of untested files, untested functions, untested branchesdrydock/code-reviewer/metrics/dependency-analysis.json— Service dependency graph, coupling score per service, circular dependency detection
Output: Write all report files, findings, metrics, and auto-fixes to drydock/code-reviewer/.
Common Mistakes
| # | Mistake | Why It Fails | What to Do Instead |
|---|---|---|---|
| 1 | Reporting linter-level issues (missing semicolons, trailing whitespace) as review findings | Wastes reviewer credibility on noise; these should be caught by automated linting in CI | Focus on structural, architectural, and logical issues that linters and formatters cannot catch |
| 2 | Flagging code without reading the ADR that justified it | The "violation" may be an intentional, documented trade-off | Always cross-reference docs/architecture/ ADRs before flagging an architectural concern |
| 3 | Marking every finding as Critical | Severity inflation makes the report useless — developers ignore it entirely | Use Critical only for data loss risks and correctness bugs. Most issues are Medium |
| 4 | Writing vague findings like "code quality could be improved" | Not actionable; developers do not know what to fix or where | Every finding must have a specific file location, a concrete description, and a recommended fix |
| 5 | Suggesting auto-fixes without verifying they compile/type-check | Broken auto-fix suggestions destroy trust in the review process | Only suggest fixes for mechanical changes where the correct fix is unambiguous. Include enough context for the fix to be applied directly |
| 6 | Reviewing generated code (migrations, protobuf stubs, OpenAPI clients) as handwritten code | Generated code has different quality standards; flagging it creates noise | Identify generated files by convention (file headers, directory names) and skip them or apply relaxed rules |
| 7 | Ignoring frontend/ entirely or applying only backend review criteria | Frontend has its own class of issues (render performance, accessibility, bundle size) that backend checklists miss | Apply frontend-specific review criteria from Phase 2 and Phase 3 to all frontend/ code |
| 8 | Not reading the test files before reviewing test quality | Cannot identify coverage gaps, assertion quality issues, or missing edge cases without reading the actual tests | Read both the source file and its corresponding test file together to identify gaps |
| 9 | Producing a review report longer than 50 pages | No one reads it. Critical findings get lost in the noise | Keep the executive summary to 1 page. Use the findings files for detail. Prioritize ruthlessly |
| 10 | Modifying files in services/, frontend/, or tests/ | The reviewer must not change source code — only document findings and suggest fixes | Write all output exclusively to drydock/code-reviewer/. Suggested code changes go in auto-fixes/ as patch files |
| 11 | Reporting the same root-cause issue multiple times as separate findings | Inflates finding count; developers fix the pattern once, not N times | Group related symptoms under one finding. Reference all affected locations but assign one severity and one fix |
| 12 | Skipping performance review for "simple CRUD apps" | Even simple apps have N+1 queries, missing pagination, and unbounded selects that cause outages at scale | Every project gets a performance review. Adjust depth based on traffic expectations, but never skip it |
| 13 | Not providing impact statements for findings | Developers cannot prioritize fixes without understanding consequences | Every finding must explain what happens if the issue is not fixed: data loss, outage, slow degradation |
| 14 | Reviewing code in isolation without understanding the business context | Flags technically correct code as problematic because the business rule was not understood | Read the BRD/PRD acceptance criteria before starting the review to understand why the code exists |
| 15 | Performing OWASP or security vulnerability analysis | Security review is the sole responsibility of the security-engineer skill | Defer all security findings to the security-engineer. Focus on architecture, code quality, performance, and test quality |
| 16 | Being too polite in findings | Polite findings get ignored. "Could potentially be improved" is not actionable. | Write findings that make the problem unavoidable: "This WILL crash when X happens because Y." If you're not uncomfortable writing it, you're not being adversarial enough. |
| 17 | Filing a dependency-direction or port-boundary breach as Medium "cleanup later" | Severity DEFLATION lets structural rot through the gate; the orchestrator only blocks on Critical/HIGH | Dependency-direction and port-boundary violations are HIGH, pipeline-blocking (see Fixed severity classifications). Never downgrade them to style/tech-debt — architecture-boundaries.md mandates HIGH. |
| 18 | Asserting "the architecture boundary is clean" without running make arch | An un-run gate proves nothing; the import graph may already be broken | RUN make arch, observe exit 0, and cite the actual output (per grounding-protocol.md). If the gate is missing or wrapped in || true/continue-on-error, that absence is itself a HIGH finding. |
| 19 | Demanding value objects for every primitive on a thin CRUD service | Anemic shape is correct for pass-through/DTO services; blanket "wrap every string" is noise | Apply the anemic-domain / primitive-obsession check PROPORTIONALLY — only to services with real business invariants, and only as Medium. |
| 20 | Accepting a bespoke {code,message,details} error body because "it works" | A second error shape breaks the RFC 9457 client contract and desyncs runtime from the docs error table | Require application/problem+json $ref'ing the shared Problem schema, populated via the error-catalog module — flag any other shape HIGH. |
Execution Checklist
Before marking the skill as complete, verify:
-
architecture-conformance.mdaudits every ADR indocs/architecture/with a conformance status -
make archwas RUN this session; exit code + output recorded. Any non-zero exit, inward framework/IO import, outward-pointing inner import, or port-boundary violation is reported as a HIGH (pipeline-blocking) finding; a missing/|| true-wrapped gate is itself a HIGH finding - Error-contract checked: every 4xx/5xx serves
application/problem+jsonand$refs the sharedProblemschema; runtime errors flow through the error-catalog module; bespoke{code,message,details}envelopes flagged HIGH - Anemic-domain / primitive-obsession check applied ONLY to domain-rich services (skipped for thin CRUD), findings classified Medium
- Performance findings cite thresholds READ from
docs/architecture/performance-budget.yaml(no hardcoded 500ms/200KB) and reference ONLYobservability-contract.mdmetric names - All Critical + HIGH findings are classified to block the orchestrator's Gate 3 remediation chain; any HIGH override is logged in
review-report.mdwith justification + ticket - Every finding has: ID, severity, category, file location, description, impact, and recommendation
- Performance review checks for N+1 queries, missing indexes, unbounded queries, and caching gaps
- Test quality review cross-references the
drydock/qa-engineer/test-plan.mdtraceability matrix for coverage gaps -
review-report.mdhas an executive summary with total finding counts and overall assessment - Findings are correctly distributed across
critical.md,high.md,medium.md, andlow.md -
metrics/complexity.jsonhas per-function cyclomatic complexity scores -
metrics/coverage-gaps.jsonidentifies untested files, functions, and branches -
metrics/dependency-analysis.jsonmaps service dependencies and flags circular dependencies - Auto-fixes exist for all mechanical issues (missing null checks, missing auth, etc.)
- No files were created or modified outside of drydock/code-reviewer/
- The report is actionable — a developer can read a finding and know exactly what to fix and where
- No OWASP or security review was performed — security analysis is deferred to security-engineer