Rules — how an id is built, and how to silence one
Every finding SQLens reports names a rule id, and every id has a page here. This page is about the id itself: what its parts tell you before you open anything, and what to do when a rule is right about the mechanism and wrong about your project.
Reading an id
An id is dot-separated and reads left to right, from who asks to what it found:
PG.L7.INDEX_REDUNDANT
│ │ └─ what it found
│ └──── the level band it belongs to
└─────── the engine, or the suite, that asks
The first part tells you whether the rule can apply to you at all:
| Prefix | Asks about |
|---|---|
PG | PostgreSQL schemas and migrations |
MY | MySQL schemas and migrations |
GEN | statements that are wrong on either engine |
SEC | the security category, which cuts across every suite and carries its own severity |
CAP | whether a migration could be captured and read at all |
DEPLOY | the deploy suite: pre-deploy gates, post-deploy verdicts, the debt ledger |
LINT | the lint run itself — a suppression that names nothing, a rule that cannot report |
DEBT | the debt ledger's own bookkeeping |
AUDIT | the audit run itself, including what the catalog reader could not read |
PG and MY ids carry a level band, L1 through L9. Levels are cumulative: a run at
level 5 evaluates everything from L1 up to L5 and nothing above it. The band is a
statement about how much a project has decided to care, not about how serious the finding is
— severity is a separate axis, and SEC rules carry their own.
A rule that reaches you from an external tool keeps that tool's namespace instead:
SQUAWK.ban-drop-table, PGLS.<rule>. Those ids are the tool's, not this package's, and
they are spelled exactly as the binary prints them.
Three answers, not two
A rule reports pass, fail, or undetermined — a check that could not run, with a
named reason. An undetermined is never quietly folded into a pass, because "we did not look"
and "we looked and it is fine" are different facts about your database. See
Contracts for what each one costs you at the exit code.
Silencing a rule
Five layers can hide a finding, and the first one that covers it wins:
| # | Source | Where you write it |
|---|---|---|
| 1 | config | the sqlens.ignore list |
| 2 | audit_ignore | the audit suite's own ignore list |
| 3 | baseline | .sqlens-baseline.json |
| 4 | annotation | a #[SqlensIgnore] attribute on a migration class |
| 5 | destructive_opt_in | your standing consent to a destructive operation |
⚠️ The baseline is third, not first, and that is the design. A baseline records findings somebody intends to fix, and that number is meant to fall; an ignore list records that a rule never applies here, and that number is meant to stay. If the baseline won a tie, a standing decision would land on a burn-down list it can never leave. The lint page has the full mechanics, including what happens to a baseline entry the order shadows.
Whichever layer you use, a suppressed finding is never silent: it is listed, counted per source, and any entry that matched nothing this run is reported as stale.
Finding the page you want
The pages below are one per id, sorted by prefix and level. A finding in your terminal already carries the link — every reporter prints the documentation URL beside the id, so you rarely need to come here to search.