| name | code-review-and-quality |
| description | Five-axis code review before merge, plus responsive-parity and documentation-accuracy gates. Use for quality passes after implementation, before merge, and when asked to review a diff. |
| context | fork |
Code review and quality
Overview
Review every non-trivial change before it lands on the main line. Use five axes: correctness, readability, architecture, security, performance — plus the two repo-specific gates below them, responsive parity and documentation accuracy.
Approval bar: Approve when the change clearly improves or preserves overall code health and matches project conventions. Do not block because you would have written it differently. Do block on real defects, security issues, or violations of agreed patterns.
When to use
- Before merge / when asked to review a change
- After implementation (self-review or cross-review)
- After bugfixes (review fix and regression coverage)
- When evaluating code produced by another agent or author
Review modes
Choose the review mode from the user's request and available context:
| Mode | Use when | Required context |
|---|
| Local review | Reviewing uncommitted local changes | git status, git diff, full changed files, related OpenSpec artifacts if any |
| PR review | Reviewing a GitHub PR number or URL | PR metadata, PR diff, full changed files at PR head, related OpenSpec artifacts |
| Self-review | Finishing an implementation slice | Touched files, completed task, tests run, remaining task status |
| OpenSpec review | Reviewing an OpenSpec-backed change | proposal.md, design.md, tasks.md, changed specs, implementation diff |
| Pipeline review | CI/bot review of a PR diff | Base/head refs, PR diff, full changed files, related OpenSpec artifacts, relevant check output |
For PR review, read full changed files, not only diff hunks. Diffs show what changed; full files show whether the change fits the surrounding design.
Pipeline review mode
Use this mode when the review is executed by CI, a scheduled bot, or any non-interactive automation. Keep the normal five-axis review, but make the result deterministic and machine-readable.
Scope
- Review only the PR/diff scope. Do not fail the pipeline for pre-existing issues unless the PR worsens them or makes them newly reachable.
- Read full changed files and related artifacts for context, but comments/findings must point to changed lines or changed artifacts whenever possible.
- Do not run Nx
build targets from this review pipeline. Treat build as a separate CI concern and only record its status when an existing CI check already provides it.
- Separate review from publishing:
- Review step produces a structured result artifact.
- Comment-publishing step may post inline comments and one top-level summary, but only from the structured result.
Output artifact
Emit a JSON object with this shape:
{
"verdict": "pass | warn | fail",
"summary": "Short human-readable summary.",
"findings": [
{
"severity": "critical | required | warning | nit | optional | fyi",
"category": "correctness | readability | architecture | security | performance | responsive | documentation | openspec | verification",
"file": "path/from/repo/root",
"line": 123,
"side": "RIGHT | LEFT",
"startLine": null,
"startSide": null,
"anchorable": true,
"message": "Review comment body.",
"blocking": true
}
],
"verification": [
{
"command": "npm exec nx test @epam/chat",
"status": "passed | failed | skipped",
"reason": "Only for failed/skipped or notable context."
}
],
"topLevelComment": "Markdown summary suitable for a PR conversation comment."
}
Use verdict: "fail" when any finding is blocking or a required verification command failed. Use verdict: "warn" only for non-blocking risks or skipped verification. Use verdict: "pass" when there are no blocking findings and required verification is green or explicitly covered by trusted CI.
file, line, side, startLine, and startSide are intended to be compatible with GitHub pull request review comments. Use side: "RIGHT" for new/head lines and side: "LEFT" only when the finding must anchor to a removed/base line. Use startLine/startSide only for multi-line comments; otherwise set them to null.
Set anchorable: true only when the finding points to a line present in the PR diff. If the issue is real but cannot be anchored to a changed line, set anchorable: false, keep file/line as best-effort context if known, and include the finding in topLevelComment instead of attempting an inline comment.
Every finding must include a non-empty message containing the full review comment body. Do not put the explanation only in custom fields, summary text, or the top-level comment; pipeline publishers use message for both inline review comments and the sticky summary table.
Pipeline fail rules
Fail the pipeline for:
- Any
critical or required finding.
- Relevant non-build Nx target failure run by this review pipeline, such as test, lint, OpenAPI, or generated-client checks.
- OpenSpec drift: implementation materially diverges from proposal/design/tasks/specs.
- API/OpenAPI/generated-client contract mismatch.
- Hand-authored
libs/* leaking host/external integration details.
- Security, authz, secret exposure, data loss, or broken public contract risks.
npm run validate:docs failure, or a lib's public API changing without its README, when the diff touches libs/*/src/index.ts, any README, or docs/**.
Do not fail the pipeline for nit, optional, or fyi findings. Use warning for non-blocking risk, missing non-critical evidence, or human-follow-up items.
Simplification and extraction findings usually use nit or optional. Use warning only when duplication or missing extraction creates meaningful maintenance risk, repeated bug-prone logic, expensive test setup, or an ownership-boundary concern. Use required only when the structure causes a concrete defect, violates library isolation, or breaks a documented architecture rule.
Comment publishing
If a pipeline job is configured to publish comments:
- Post inline comments only for
critical, required, and high-signal warning findings with anchorable: true.
- Do not post inline comments for
nit by default unless explicitly configured.
- Do not attempt inline comments for findings with
anchorable: false; summarize them in the top-level PR comment.
- Always post one top-level PR conversation comment.
- If everything is good, post a concise positive summary instead of staying silent, for example:
Automated review passed.
- No blocking findings.
- Verification: `npm exec nx affected --target=test --base=origin/development` passed.
- Scope checked: correctness, architecture boundaries, security, performance, responsive parity, documentation accuracy, and OpenSpec alignment.
If there are findings, the top-level comment must summarize the verdict, count blocking/non-blocking findings, and list verification status. Inline comments carry the detailed code-specific feedback.
GitHub publishing step requirements:
- Add the PR head SHA as
commit_id at publish time; do not require the review agent to hardcode it into findings.
- For individual inline comments, use GitHub's pull request review comment API with
path, line, side, optional start_line/start_side, body, and commit_id.
- If the API rejects an inline comment because the line is not in the diff, retry once as a top-level PR comment entry and mark the finding as not anchored in the publishing log.
- For the top-level summary, use a PR conversation comment or a review body, depending on the CI integration.
OpenSpec review gate
If the change is tied to OpenSpec, review the artifacts before judging the code:
- Identify the change from the branch, PR description, user request, or
openspec list --json.
- Read the relevant artifacts under
openspec/changes/<change>/:
proposal.md for problem, scope, non-goals
design.md for architecture and local patterns
tasks.md for promised implementation and verification
- changed specs under
specs/**/spec.md when present
- Check the diff against the artifacts:
- Implementation matches the accepted scope and does not add silent scope creep.
- Completed task checkboxes correspond to real code and tests.
- New requirements discovered during implementation are captured in specs/design/tasks, not only in code.
- Non-goals are still respected.
- If implementation reveals a design/spec gap, request an artifact update before or alongside code changes.
Block merge for OpenSpec-backed work when code behavior materially diverges from the artifacts, when tasks are marked complete without implementation, or when API/user-facing requirements were implemented without updating the relevant spec/design/task.
Five-axis review
1. Correctness
- Matches spec, task, or PR description
- Edge cases: null, empty, boundaries, errors — not only happy path
- Tests exist, assert behavior, and would catch regressions
- Watch for off-by-one, races, inconsistent state
2. Readability and simplicity
- Names are specific; avoid meaningless
data, result, temp
- Control flow is easy to follow; avoid unnecessary cleverness
- Abstractions earn their complexity; prefer duplication over wrong abstraction until patterns repeat
- Flag simplification opportunities: repeated logic, deeply nested code, broad functions, or verbose conditionals that would become clearer as a focused helper, hook, component, utility, or method.
- Recommend extracting reusable utilities, hooks, components, or methods when the same behavior appears in multiple places, when a local helper would clarify a complex block, or when nearby features are likely to reuse the behavior.
- Do not request extraction just because code could be abstracted; require a concrete readability, testability, reuse, or ownership-boundary benefit.
- Comments only where intent is non-obvious; remove dead code and noise
3. Architecture
- Fits existing Nx boundaries (
apps/*, libs/*) and import direction
- Libraries stay host-agnostic: no host-owned integration details inside
libs/*, including hardcoded /api paths, generated clients, server-api imports, app contexts, auth/session/cookie/env access, feature flags, routing/navigation, analytics/telemetry/logging clients, deployment/tenant/provider details, third-party SDK setup, platform bridges, app-specific URL schemes, or app storage keys/schemas
- Exception:
libs/chat-api-client is generated by OpenAPI scripts, so generated endpoint paths, DTOs, runtime transport code, and OpenAPI artifacts are allowed there. Block hand-authored app behavior in that package and direct generated-client usage from other hand-authored libs.
- Host/external integrations are adapted at the app edge and passed into libs through props, callbacks, resolved values, or narrow interfaces
- No unjustified new patterns; justified new ones are called out
- No sneaky circular deps or leaky module APIs
- Reusable helpers live at the right ownership level: app-specific helpers stay in
apps/*, host-agnostic helpers/components may move to libs/*, and shared types stay in libs/chat-shared
- Relative
.ts/.tsx imports and re-exports omit .js, .jsx, .ts, and .tsx; Vite projects use bundler resolution rather than Node ESM source specifiers
- Named finite sets of statuses, modes, variants, or lifecycle states use string enums instead of string-literal unions when exported, reused, or compared
- Duplication: only consolidate when the rule of three (or team norm) says so
4. Security
- User and external input validated at boundaries; treat external data as untrusted
- No secrets in code, logs, or repo; authz where required
- Injection-safe queries and APIs; XSS-aware rendering in UI code
- New dependencies: necessity, maintenance, size, license,
npm audit awareness
5. Performance
- N+1, unbounded loops/fetches, missing pagination on lists
- UI: avoidable re-renders, huge props, sync work on hot paths
- Only flag with measurable or clear scaling reasoning when possible
6. Responsive parity
- UI changes use the project's named breakpoint prefixes (
mobile: / desktop:), not nonexistent small_tablet:/large_tablet:/large_desktop:, Tailwind defaults such as sm:/md:/lg:, or arbitrary min-[…]: queries
- Authoring style is mobile-first — base classes describe the smallest supported viewport, larger bands are added via the named prefixes
- Components that branch in JS use
useBreakpoint / useIsMobile from apps/chat/src/hooks/breakpoint/useBreakpoint.ts, not direct window.innerWidth reads
- Touch targets meet ~44×44 CSS px on mobile; no
:hover-only affordances; no horizontal scroll at 360px
- Verification story names which breakpoints were exercised — "desktop verified only" is a request-changes signal for any user-facing change
- See
.claude/skills/responsive-design/SKILL.md for the full rubric
7. Documentation accuracy
Docs drift silently — no build breaks when a README documents a component that
was renamed two releases ago. Nothing in lint/test/build covers it, so the
review is the only gate.
npm run validate:docs is green. It checks README coverage and H1/package identity, lib package.json metadata (description, license), that every relative markdown link resolves, and that every name a lib README imports from its own package is actually exported. Treat a failure as required.
- A change to a lib's
src/index.ts — added, renamed, or removed export — carries a matching README change in the same diff.
- A renamed prop, a changed prop type, or a newly required prop is reflected in every README example that passes it.
- README code fences name only symbols that exist, with the required props present, the right value types, and imports from the package that actually exports the name (
CatalogEntityType is @epam/ai-dial-chat-shared, not @epam/ai-dial-catalog).
- Prose describes what the code does today, not an intended capability. A claimed feature the component lacks is
required, not a nit — readers act on it.
- Structural additions (lib, app, backend domain, context, route,
ApiEndpoints entry) update docs/architecture.md; new or removed environment variables update apps/chat-api/README.md and .env.template.
- Deleting a doc means fixing every link to it, including the
dial-docs skill index.
- See
.claude/rules/docs.md for the same-change update matrix and the drift classes already found here.
Repo-specific routing
Use the repository skills and rules as the source of truth before applying generic advice:
| Change area | Read / apply |
|---|
| Workspace structure, project ownership | openspec/config.yaml, AGENTS.md, .agents/skills/nx-workspace/SKILL.md |
| Multi-file implementation or refactor | thin vertical slices + per-slice verify (openspec/config.yaml task rules) |
| HTTP API contract or generated client | .agents/skills/api-design/SKILL.md |
apps/chat-api/** | apps/chat-api/AGENTS.md |
libs/* React components | openspec/config.yaml, library isolation rules from AGENTS.md, openspec/lib-styling-guide.md plus exported-symbol JSDoc rules |
| UI kit components | Use the @epam/ai-dial-ui-kit MCP tools before recommending raw HTML primitives |
| Responsive / mobile parity | .claude/skills/responsive-design/SKILL.md |
READMEs, docs/**, lib public API | .claude/rules/docs.md plus npm run validate:docs; use the dial-docs skill to find the authoritative doc |
| CI status or self-healing fixes | .agents/skills/monitor-ci/SKILL.md; do not replace it with ad hoc polling |
Do not import generic standards that conflict with these repo rules. For example, do not require a new REST response envelope, direct frontend REST helpers, raw HTML controls, or a generic project structure when local conventions say otherwise.
Code quality standards
Use these as cross-cutting checks after applying repo-specific rules:
- Prefer clear, specific names over generic
data, result, temp, item when the domain is known.
- Keep control flow shallow with early returns or extracted helpers when nesting hides the main path.
- When new code repeats behavior across files or components, call out whether it should become a reusable utility, hook, component, or method. Keep the suggested location consistent with ownership boundaries.
- When a single function grows to mix several responsibilities, suggest extracting the smallest named helper that makes the main path easier to read and test.
- Avoid functions that mix validation, IO, transformation, and presentation unless the surrounding pattern already does so.
- Avoid magic numbers; name domain thresholds, debounce delays, limits, and TTLs.
- Avoid mutation of shared state. Local mutation is acceptable only when contained, intentional, and clearer or measurably faster.
- Comments should explain why a choice exists, not restate what the code does.
- React components should expose event callback props as
onEvent and name internal handlers handleEvent.
- No
console.log in application code; use the app's logging pattern.
- No TODO/FIXME in merge-ready code unless linked to an accepted follow-up and non-blocking by design.
- Tests should assert observable behavior and meaningful edge/error paths, not implementation details.
Change sizing
| Size (approx.) | Expectation |