Skip to content

[finding] ttl.onlyWhen's {$null: true} is pinned COMPILE-ONLY on pg/mysql while a live-cell testkit exists — measured live by hand, holds on both #10836

Description

@os-elon

Filed unassigned by the dev on #7826 (draft PR #10633) as an out-of-scope observation. Nothing is broken — the live measurement below passes on both servers. This records a coverage shape, with the numbers, so the measurement is not lost.

What is pinned today

packages/drivers/driver-sql/src/sql-driver-ttl-onlywhen-null-dialects.test.ts (landed by #10344 for #10165) measures the Reaper-shaped where
{ expires_at: { $lt: cutoff }, revoked_at: { $null: true } } across three dialects, but not at the same depth:

dialectwhat the suite proves
sqlite (better-sqlite3)live: find + count really return ['expired'], tombstone excluded, unfiltered counter-face returns both
pgcompile-onlynew SqlDriver({ client: 'pg', connection: {} }), .toSQL(), string assertions. "Connection is never opened."
mysql2compile-only, same shape

Compile-only proves the SQL text. It cannot prove the server returns those rows, and it never exercises the ttl cutoff against the column type the dialect actually creates — which is where the two dialects differ from sqlite: sqlite stores expires_at as TEXT, while the same declaration creates timestamp with time zone on pg and datetime on MariaDB/MySQL (measured below via columnInfo()). An ISO-8601 …Z comparand against a real temporal column under STRICT_TRANS_TABLES is exactly the class of thing a text assertion cannot see.

The repo already has the mechanism this file does not use

packages/drivers/driver-sql/src/live-dialect-matrix.testkit.ts exports PG_CELL / MYSQL_CELL (OS_TEST_POSTGRES_URL / OS_TEST_MYSQL_URL, per-file schema derivation, declareUnprovisionedCell for announcing an un-run cell). Sibling suites use it — sql-driver-datetime-postgres-timezone.test.ts, sql-driver-datetime-mysql-storage.test.ts, sql-driver-time-live-dialects.test.ts. The $null suite is the only dialect suite in that directory that hand-rolls connection: {} instead. It is also the only $null dialect suite in the package (grep -l '$null' over *live*.ts / *dialect*.ts returns exactly it).

Measured by hand on #7826, on live servers, and it holds

Both servers were provisioned in the dev container (/usr/lib/postgresql/16/bin + apt-get install mariadb-server) and driven through the realSysSession declaration → real LifecycleService → real SqlDriver, i.e. the shape packages/plugins/plugin-auth/src/sys-session-ttl-sweep.test.ts runs on sqlite:

PostgreSQL 16.13
expires_at = {"type":"timestamp with time zone",...} revoked_at = {"type":"timestamp with time zone",...}
SPARING : survivors after sweep: ["sess_live","sess_tombstone"]
POSITIVE : report: [{"object":"sys_session","policy":"ttl","cutoff":"2026-08-02T00:00:00.000Z","deleted":1}]
UNFILTERED (onlyWhen dropped): survivors: ["sess_live"] ← tombstone reaped, so the filter is what spares it
MariaDB 10.11.14 (sql_mode=STRICT_TRANS_TABLES,...)
expires_at = {"type":"datetime",...} revoked_at = {"type":"datetime",...}
SPARING : survivors after sweep: ["sess_live","sess_tombstone"]
POSITIVE : report: [{"object":"sys_session","policy":"ttl","cutoff":"2026-08-02T00:00:00.000Z","deleted":1}]
UNFILTERED (onlyWhen dropped): survivors: ["sess_live"]

⚠️ MariaDB is a MySQL-protocol stand-in, not MySQL 8.0 — good for predicate compilation and row selection, not for asserting MySQL error wording.

Suggested shape, if anyone picks this up

Give the existing suite live legs through PG_CELL / MYSQL_CELL rather than adding a file — the compile-only assertions stay (they run with no server), and the live legs skipIf themselves off when the env vars are absent. Extending the existing file also avoids a second engine-double-contract pin.

⛔ Deliberately not done inside #10633: that card is a rescue completing missing evidence, and CI provisions no live servers, so a committed live test adds no CI protection today. Duplicate scan: one semantic search over open+closed issues (a second scan was cut short by a GitHub API rate limit), no match.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions