sql-correctness-review — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited sql-correctness-review (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Use when a query might return wrong results — regardless of how fast it runs. Triggers:
Routing: performance/anti-patterns → sql-query-review. Bad data in the table (not the query) → data-quality-audit. The first job here is deciding which of the two it is.
| Input | Why it matters |
|---|---|
| Query text | The suspect |
| Expected output grain | "One row per X" — every check is relative to this |
| Key relationships | Which joins are 1:1 vs 1:N (or what you believe they are) |
| A reconciliation anchor | A number you trust (row count, total from a source system) to diff against |
| Access to run SQL | Evidence queries are the core of this skill |
| # | Class | Symptom | Canonical cause |
|---|---|---|---|
| 1 | Duplicates | Row count too high; metrics inflated | Source table grain misunderstood; missing dedup |
| 2 | Join fanout | Totals inflate after a join | Joining on a partial key (1:N or N:M treated as 1:1) |
| 3 | Wrong join type | Rows silently disappear | INNER where LEFT intended; WHERE on a LEFT join's right table |
| 4 | NULL handling | Rows vanish or comparisons silently fail | NOT IN + NULL; col != 'x' dropping NULLs; NULL join keys |
| 5 | CASE issues | Misclassified or NULL categories | Missing ELSE; overlapping branches; NULL never matching |
select <grain_cols>, count(*) as n
from (<query>)
group by <grain_cols>
having count(*) > 1
order by n desc
limit 20;Zero rows = clean. Any rows = pull one offending key and eyeball the duplicated rows — the differing columns point at the culprit join or missing dedup.
select join_key, count(*) from right_table group by join_key having count(*) > 1 limit 10;Then measure the explosion directly: row count before vs after the join. A join you believed was 1:1 that grows rows is the smoking gun. scripts/logic_checks.sql has templated checks.
where r.col = 'x' silently converts LEFT to INNER. Move the condition into the ON clause or handle NULL explicitly.select count(*) from left_table l left join r on ... where r.key is null; — is that number expected?NOT IN (subquery) where the subquery can yield NULL → returns zero rows. Use NOT EXISTS.where col != 'x' — NULLs are dropped too. Intended? If not: where col != 'x' or col is null.select count(*) from t where join_key is null;count(col) vs count(*) — the former skips NULLs.avg(col) averages only non-null rows. Decide if that's the intended denominator.>= 100 before >= 1000) make later branches dead code.when col = 'x' — handle with an explicit when col is null branch. select <case_expression> as branch, count(*) from t group by 1 order by 2 desc;A NULL branch with rows in it is a missing-ELSE or missing-NULL-branch finding.
# SQL Correctness Review: <query description>
## Expected grain
One row per <grain>. Verified: <yes / NO — see finding 1>
## Findings
### Finding 1 (blocker): orders→items join fans out 3.2×
- **Evidence:** `select order_id, count(*) from order_items group by 1 having count(*) > 1` → 84% of orders have multiple items; query treats join as 1:1
- **Impact:** revenue inflated ~3.2× (matches the "too high" report)
- **Fix:** pre-aggregate items to order grain before joining
### Finding 2 (major): LEFT join silently converted to INNER
- **Evidence:** `where i.status = 'shipped'` filters NULLs from unmatched orders; 12,440 orders dropped
- **Fix:** move predicate to ON clause: `on ... and i.status = 'shipped'`
## Corrected query
\`\`\`sql
-- [fixed SQL]
\`\`\`
## Reconciliation
| Measure | Before | After | Anchor | Gap |
|---|---|---|---|---|
| Row count | 412,032 | 128,760 | 128,760 (orders table) | 0 |
| Revenue | $4.1M | $1.28M | $1.27M (finance) | +0.8% (refund timing) |
## Remaining risks
- <anything not fully resolved>data-quality-audit problem. Don't patch it silently with DISTINCT in the query — flag it.minus both directions), not their logic. The population difference usually names the bug (filters, join type, time window).scripts/logic_checks.sql — templated evidence queries: grain/duplicate check, join fanout audit, LEFT-join loss count, NULL-key share, NOT IN trap detector, CASE branch coverage.sql-query-review — performance and anti-pattern review of the same querydata-quality-audit — when the source table, not the query, is brokenmodular-sql-ctes — restructuring so each CTE has one verifiable grainmetric-definition — when two reports disagree because the metric was never pinned down~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.