Every finding carries a rule id such as BV002, BP006 or SL013. The two letters are the family — which corpus the rule belongs to, where it runs and what it reads. The three digits are stable for the life of the rule; a retired rule leaves a gap and a number is never reused. Separately, every rule is tagged with a two-letter category such as LK or CN that says what goes wrong. Families group rules by mechanism, categories by harm: one category spans several families, and one family covers many categories.
Families — the id prefix
| Prefix | Engine | Corpus | Rules | Reads | Default posture |
|---|---|---|---|---|---|
BV### | Postgres | Core safety | 50 | The parse tree of one migration; refined against the live schema with --db | Blocks CI on critical findings |
BP### | Postgres | Performance | 11 | The parse tree, plus index and table statistics with --db | Advisory notes; never fails CI unless team policy raises it |
BS### | Postgres | Set ordering | 2 | Every file in the migration set, in apply order | Blocks CI; silent on a single file |
BC### | Postgres and any text file | Credentials | 6 | String literals in SQL; with bolvrk secrets, any file | Blocks CI; the value is always masked |
EX### | Postgres | Plan rules | — | EXPLAIN (FORMAT JSON) output from bolvrk explain | Warnings and notes; not part of check |
SL### | SQLite (alpha) | Static corpus | 35 | The SQLite parse tree, behind --engine=sqlite | Local only; no --db or --remote yet |
MY### | MySQL | Static corpus | — | The MySQL parse tree | Planned; not run anywhere yet |
The engine a rule targets follows from the prefix alone: SL is SQLite, MY is MySQL, every other family is Postgres. Reports and the rule reference list families in a fixed order — BV, BP, BS, BC, then SL — and numerically within a family. The free CLI bundles 18 of the 68 Postgres SQL rules; the rest run in the hosted service on Startup and above.
Categories — the two-letter tag
Categories are shared across every engine, so one filter reads the same for a Postgres rule and a SQLite rule. A rule has exactly one. They are the category filter on the rule reference and on the Policy page, and the code chip on every rule row.
| Code | Name | What it covers |
|---|---|---|
LK | Locks & blocking | Statements that queue or block production traffic while they run. |
RW | Table rewrites | Changes that copy or rewrite every row of a table. |
CN | Constraints & keys | Constraints, primary keys, and foreign keys added the slow or unsafe way. |
DS | Destructive changes | Statements that remove data, objects, or enforcement. |
DW | Deploy window | Changes that break code still running the previous release. |
TX | Transactions | Statements that misbehave inside a multi-statement transaction. |
RP | Replication & durability | Replication, WAL, vacuum, and crash-safety settings. |
TY | Type choices | Column types with well-known traps. |
OP | Operational safety | Server-level or batch operations that do not belong in a migration. |
PC | Privileges & credentials | Security posture: privileges, row-level security, secrets in SQL. |
IX | Index hygiene | Indexes that cost writes without paying back in reads. |
QS | Query shape | Index design judged against the migration's own queries. |
TS | Table settings | Per-table storage and planner settings that undo good defaults. |
SO | Set ordering | Promises one migration makes that a later one must keep. |
Roughly: the first ten categories are where the BV, BC and SL rules land, IX, QS and TS belong to the performance corpus, and SO is the set-ordering corpus. That is a tendency, not a rule — BV017 (foreign key without a covering index) is CN.
Reading an id
BV002 — Postgres core safety, rule 2: ADD COLUMN NOT NULL without a default. Category CN. BP006 — Postgres performance, rule 6, category QS: an index judged against the queries in the same migration. SL013 — SQLite, rule 13, category DS: a destructive change, tagged with the same code a Postgres DROP would carry.