This capability requires Python on Linux or WSL. SQL execution fails closed
on Windows and macOS because its hard worker memory boundary is Linux-specific.
Parsing and row-comparison helpers remain portable.This capability is Python-only. The TypeScript SDK does not invoke Python on
your behalf. Use an SDK build that advertises the
sql command; source code
and an installed package release are separate availability boundaries.Prepare a fictional fixture
Use a dedicated fixture database with fictional or approved de-identified data. Avoid a production database. For example, create a SQLite fixture:sql-cases.jsonl:
id, question, generatedSql, and
referenceSql. orderMatters defaults to false; floatTolerance defaults
to 0.000000001 and must be finite and nonnegative. Unknown fields, duplicate
ids, invalid types, and empty files are refused. The command accepts at most
10,000 cases, a regular case file of at most 32 MiB, ids of at most 256
UTF-8 bytes, JSONL lines of at most 1 MiB, and 100,000 UTF-8 bytes per SQL statement. Inputs are read with
a byte bound before JSON parsing; pipes and device files are refused.
The reader streams LF-delimited lines within the byte limits; blank padding
does not create a list of every line, and Unicode separators inside JSON values
remain part of the value.
sqlite:///fixture.db resolves relative to the working directory. Use
sqlite:////absolute/path/fixture.db for an absolute path. The database must
already exist; the checker never creates it.
Understand comparisons
Column names are ignored. Column count and position must match, including for empty result sets. By default, rows are compared as a multiset: order is ignored, duplicate rows retain their multiplicity,NULL stays NULL, and
strings compare exactly. Finite floats may differ by at most the absolute
floatTolerance; decimals retain exact decimal precision.
Use orderMatters: true only when the reference query orders by a unique key
or otherwise resolves every tie. Ordering on non-unique values alone does not
make the database’s tie order deterministic.
The report contains an outcome for every case:
Execution accuracy is
matches / (case count - reference errors). Reference
errors are invalid evidence, and the gate stays inconclusive even if all other
cases match. Refusal, timeout, row/byte limits and worker resource failures also
keep the gate inconclusive, including when a low accuracy threshold was supplied.
A file with no valid reference cases has unavailable accuracy.
Reports omit SQL, questions, connection strings, database error text, and result
rows by default. --show-diff explicitly includes at most five rows from each
side for mismatches, at most twenty columns per row, with values clipped to
bounded previews. Decimal, date/time, UUID and nested values carry type tags
in the preview. A diff exceeding the worker report budget is omitted and
marked diffTruncated. Across the entire job, the parent caps the serialized
report at 16 MiB and drops additional optional diffs before retaining each
case; diffTruncatedCaseCount records how many previews were dropped. Every
completed case id and outcome stays in the report. If even the base outcomes
cannot fit, the whole job returns WEAK_EVIDENCE with complete: false and no
accuracy, rather than scoring a partial cohort. Those rows
may contain fixture data; review their handling before saving or sharing a
report. The report’s case ids are the ids you supplied.
PostgreSQL fixtures
Install the Python SDK’ssql extra to enable psycopg. Supply a dedicated
fixture role with SELECT access only. The checker refuses superusers, elevated
role attributes, table write grants, and membership in server-file or
server-program roles. Configure the fixture role itself without write grants;
the client check is an additional guard.
statement_timeout bounds each server
statement, and the worker also checks its deadline while fetching/comparing.
Queries run with search_path=pg_catalog; unqualified fixture tables are
validated and rewritten as quoted public tables. Use explicit schema
qualification for other fixture schemas. Only a fixed set of pure built-in
functions is supported, including common aggregates, math/string/date functions
and JSON/array construction. Unknown functions, session-control functions and
custom schema functions are refused. Views, foreign tables, row-level security,
generated columns and custom-typed columns are unsupported because their
definitions can hide function calls. Materialized views contain stored data
and may be read when their types satisfy the same checks.
Execution boundaries
SQLite opens the file with URImode=ro, sets query_only=ON, disables extension
loading, and uses an authorizer that allows SELECT/read operations only. On
Python versions with SQLite connection limits, individual SQLite values are
capped at 1 MB. PostgreSQL uses server-enforced read-only transactions and a
role without write grants. Both additionally parse SQL and refuse multiple
statements, non-SELECT commands, write CTEs, SELECT INTO, locking queries, and
non-allowlisted functions, custom operators/types and file/extension operations.
--timeout-ms accepts 1–300,000; --max-rows accepts 1–100,000. Each query fetches
at most the cap plus one row to detect overflow. Each value has a 1 MiB accounting
budget, and each query has an 8 MiB aggregate result budget. SQLite also enforces
its stricter 1 MB value limit on Python versions with connection limits.
Every case executes in a fresh worker with a hard 512 MiB Linux address-space
limit, a CPU-time ceiling, and disabled core dumps. Python starts in isolated
mode so the bootstrap ignores the working directory
and inherited PYTHONPATH; the verified SDK package root is added only after
hard limits are installed. The parent enforces a
wall-clock deadline of three query timeouts plus ten seconds for worker setup
and returns a resource failure if the worker dies. Only a bounded report
(maximum 128 KiB per case), never raw result sets, crosses the worker pipe.
This protects the CLI process even when a driver buffers a single huge field
before the value budget can be checked.
These are fixture execution
checks, not a general sandbox for hostile database extensions or untrusted
database administrators. The worker limit does not bound the PostgreSQL server
process or server-side extension memory; configure server resource limits and
use a disposable database you control with trusted table definitions. The separate
portable-quality query sandbox continues to refuse raw SQL.
For SDK contributors, the ordinary Python test lane exercises SQLite and the
PostgreSQL transport contract. Real PostgreSQL proofs run in a separate lane
and require a disposable database with role/schema creation permissions:
src/packages/sdk-python after installing the development and
sql extras. The native lane creates a temporary fixture schema and a dedicated
read-only role, removes both afterward, and fails if its database prerequisite
is missing. It checks decimal precision, empty-result columns, server-enforced
read-only behavior, role refusal, timeout, row caps, and SQL refusal.