# What the checker finds and promises

Docs for TrueQuery 0.1.6. What the checker looks for, what it promises, and how to run it on its own.

The checker reads your code and looks for SQL that silently returns the wrong answer. It works with no AI involved. Your agent runs it for you, or you can [run it on its own](https://analytically.ai/truequery/docs.md).

## What it finds

```
$ truequery detect samples/bad_orders.sql
samples/bad_orders.sql:7:19 [error] sql/accidental-cross-join — no predicate links o: every row pairs with every row on the other side
    fix: add ON <keys>, or CROSS JOIN if cartesian is intended
samples/bad_orders.sql:13:7 [error] sql/not-in-nullable-subquery — a NULL in the subquery makes NOT IN return zero rows
    fix: rewrite as NOT EXISTS, or add WHERE col IS NOT NULL
samples/bad_orders.sql:17:14 [error] sql/count-star-after-left-join — COUNT(*) over an outer join counts 1 for unmatched rows
    fix: count the nullable-side key instead, e.g. COUNT(o.<key>)
...
5 errors, 2 warnings in 1 file checked offline
```

`truequery review` adds the receipt. Its `Not checked` lines are the
point: they name what this pass could not verify. Here that's the data
itself; a limit such as integer division is listed only when a file
could hit it.

```
TrueQuery receipt
Checked      1 SQL file · contracts for 0 of 3 tables
Found        5 errors · 2 warnings
Not checked  your data: TrueQuery reads files and never connects to your database
No contract  customers, orders, staging_orders
```

## What it promises

- **Offline and deterministic.** No LLM in the check path and no network
  calls. Your code never leaves your machine.
- **Never a false "clean".** A file it couldn't parse, a statement it
  could read only as an opaque command, or a function body in procedural
  code (PL/pgSQL, `BEGIN … END`) is listed as not checked, and the exit
  code says so. The query inside `EXPLAIN`, `PREPARE`, `DECLARE … CURSOR`
  and `CREATE … AS`, and the statements in a SQL function body, are
  checked.
- **Checks the SQL inside Python too.** SQL strings passed to `execute`,
  `read_sql`, `text()`, `.sql()` or `sql=` (including f-strings,
  `.format()`, `%` and a query held in a same-file variable) get the same
  checks as `.sql` files, and findings point at the Python line and column.
  SQL your program builds at run time (in a loop, in another function or
  module) can't be read from the file: it's listed as not checked, never
  as clean.
- **Checks pandas pipelines too.** A Python file that imports pandas gets
  the pandas checks (see "pandas" below), alongside any SQL inside it.
- **Runs as the agent works.** Hooks check each edit to a SQL file (or a
  Python file with SQL inside, or that imports pandas) for bugs that are never intended (`= NULL`,
  an unguarded `DELETE`, a `WHERE` that empties a left join). At the end
  of each turn they run every enabled check over the files touched. New
  findings go back to the agent once, a clean pass is silent, and no edit
  is ever refused.
- **Works anywhere SQL lives.** In a terminal and in CI, for any agent or
  person: text, JSON or SARIF output. Exit codes: 0 means clean; 1 means
  findings at or above `--fail-on` (default `error`); 2 is a usage or config
  error; 3 means some files couldn't be checked (`--allow-unverified` turns
  3 into 0).
