How to read the review Hound posts on a pull request — severity tiers, the categories it covers, what a suggested fix looks like, and the playbook for acting on the verdict.
Hound asks the underlying model to label every finding with one of four real severity tags, parsed from the response in services/review.js. These are the only tiers you'll see in a verdict:
CRITICAL — must block merge. Logic bugs that corrupt data, remote code execution, leaked secrets, auth bypass, or anything that ships broken behavior to real users. Treat as "do not merge until fixed."HIGH — should block merge. Significant correctness issues, unsafe patterns, missing input validation in a public surface, race conditions, or anything that will hurt users in production even if it doesn't fully break them.MEDIUM — will not block merge on its own, but the author should respond. Edge cases that bite under load, error-handling gaps that swallow failures, non-trivial maintainability problems, or noticeable performance issues.LOW — informational. Naming, comment clarity, minor stylistic notes. Do not nitpick (the prompt in review.js explicitly tells the model not to).What Hound has already done about it. Nothing — Hound only posts a comment. It never auto-merges, auto-requests-changes, or otherwise touches PR branch state. You (a human maintainer) decide what to do with the verdict.
Example finding for each tier, lifted from the prompt's brief in services/review.js:
CRITICAL — SQL concatenation with user input on POST /search (db/queries.js:42) — classic injection. Use parameterized queries: db.query('SELECT ... WHERE id = $1', [id]).
HIGH — Token stored in plaintext on User model (db/users.js:19) — replace with bcrypt.hash(token, 12) and store the hash.
MEDIUM — Bulk import swallows DB errors (routes/import.js:88) — log the row id and rethrow; today a single bad row silently drops the whole batch.
LOW — Inconsistent naming on the response helper (lib/respond.js:3) — pick one of {success, ok, status} across the codebase.
Hound doesn't store a findings.category column — categories live only as descriptive labels in the comment. They mirror the focus areas the review prompt in services/review.js asks the model to cover, so what Hound tells you about lines up with what its brief says to look for:
One-line example per category, again shaped like the model's natural output:
Logic — route returns 200 even when no row matched (routes/items.js:54) — should be 404.
Security — /admin accepts the role from the request body (routes/admin.js:12) — derive server-side from the session.
Perf — listUsers does a query inside a for-loop (routes/users.js:30) — collect ids first, then IN(...).
Errors — try/catch around fetch logs and continues (services/sync.js:18) — rethrow or surface to the caller.
Style — three near-identical mapping helpers (lib/map-*.js) — collapse into one with a type arg.
A single finding can hit more than one category (e.g., a missing input check is both security and logic). When that happens Hound names the dominant one — the comment, not a schema, is the source of truth.
What you see in the PR comment is the human-readable review_text — a summary paragraph followed by severity-tagged findings. Each finding has the same four-line shape that the review prompt in services/review.js asks the model for:
HIGH — `db/queries.js:42` — User-controlled `q` is concatenated into the raw SQL.
Strings built by concatenation bypass parameterized queries and let an
attacker end the query and append their own. Any string field that
reaches `db.query` raw is a candidate.
Fix: pass `q` as a parameter and let the driver bind it —
db.query('SELECT id, name FROM users WHERE name ILIKE $1', [`%${q}%`])
Also escape `%` / `_` from the user input if you wire up LIKE wildcards.
Anatomy of each finding:
<SEVERITY> — file:line — one-line summary. The severity tag here is what's parsed into findings[].severity by the regex on services/review.js:60.The full verdict (the prose summary plus every tagged finding) is also stored on the reviews table as review_text (TEXT) and findings (JSONB) — see the API reference for the exact response shape. The PR comment is the rendered form of the same record.
This is the human-side playbook, not a contract. Hound does not auto-merge, auto-request-changes, or auto-comment today — the comment on the PR is its only output. Treat the rules below as guidance for the maintainer reviewing the verdict.
Edge cases:
findings[].severity is the model's call, not policy.← Back to the quickstart · API reference · Setup guide · Troubleshooting