Skip to main content

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:

PrefixAsks about
PGPostgreSQL schemas and migrations
MYMySQL schemas and migrations
GENstatements that are wrong on either engine
SECthe security category, which cuts across every suite and carries its own severity
CAPwhether a migration could be captured and read at all
DEPLOYthe deploy suite: pre-deploy gates, post-deploy verdicts, the debt ledger
LINTthe lint run itself — a suppression that names nothing, a rule that cannot report
DEBTthe debt ledger's own bookkeeping
AUDITthe 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:

#SourceWhere you write it
1configthe sqlens.ignore list
2audit_ignorethe audit suite's own ignore list
3baseline.sqlens-baseline.json
4annotationa #[SqlensIgnore] attribute on a migration class
5destructive_opt_inyour 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.