1 Commits
Author SHA1 Message Date
Claude Opus 5 2bfbd3f159 feat(analytics): sql/009 — execution metadata, metric governance, semantic registry, quarantine, usage ledger
CI (SIAX Cloud) / integration (push) Failing after 38s
CI (SIAX Cloud) / quality (push) Successful in 1m0s
CI (SIAX Cloud) / security (push) Successful in 25s
Security Scan (SIAX Cloud) / security (push) Successful in 28s
CI (SIAX Cloud) / integration (pull_request) Failing after 48s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m16s
CI (SIAX Cloud) / security (pull_request) Successful in 27s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 23s
The migration the previous commits' comments promised. Additive and idempotent
throughout, so the restore drill can replay it onto a live database.

BI-P018 adds principal_id, workload, compiled_query_hash, datasets, metrics,
cache_status and cost_units to the execution record — and deliberately NO
`query_text` column, with a CHECK pinning the hash to 64 hex characters so a
statement smuggled into that field is refused by the database. A test asserts
the absence of `query_text` and `sql` as columns.

BI-P031's DoD gets a Postgres TRIGGER, not just the TypeScript guard: a
certified metric whose meaning_hash changes without a version bump raises. That
is the layer that holds when something writes without going through the
application — a migration script, a psql session, an admin tool. A compiler
opinion does not survive `psql`; a trigger does.

BI-P030 gets a version-history table whose CONTENT is immutable (status and
valid_from may still move) plus a PARTIAL UNIQUE INDEX enforcing at most one
ACTIVE version per model per tenant. Two active versions is a silent
correctness failure in which half the dashboards read a different model, so it
is an index rather than application discipline.

BI-P021's usage ledger is append-only by trigger: update and delete both raise.
BI-P026's freshness table DEFAULTS TO 'UNKNOWN' — a dataset nobody has computed
freshness for must not read as FRESH — and requires a non-empty disclosure,
because a state with no words attached is a state a dashboard renders as a
silent green dot. BI-P025's quarantine record requires a principal and a reason
on release.

A BUG IN THIS MIGRATION, FOUND BY RUNNING IT:

  `SELECT 1 FROM pg_constraint WHERE conname = '...'` is NOT schema-scoped.
  conname is unique per schema, not per database, so on a database that already
  had these tables in `public` every guarded CHECK was silently skipped when
  the file was applied into a second schema. The constraints simply were not
  there, and the tests that should have proven them PASSED — because the
  INSERTs they expected to fail succeeded, and `expect(message).toContain(...)`
  on an undefined message reads as a type error, not as "the constraint is
  missing". Every guard now scopes via `conrelid = '<table>'::regclass`, and
  the fix is proven by applying the file to `public` FIRST and then running the
  suite into a fresh schema: 20/20.

Two flaws in my own test harness, also found by running it:
  * `sql.unsafe("SET search_path ...; SELECT ...")` is a multi-statement simple
    query, and postgres.js returns the LAST statement's result — so a SELECT
    silently returned the connection object and two assertions compared against
    nonsense. search_path is now pinned on the CONNECTION.
  * the fixture INSERT used column names that do not exist in sql/008's dataset
    table, which surfaced as a suite-level failure rather than as 20 skips.

20 tests against a real Postgres 16, gated on ANALYTICS_TEST_DATABASE_URL, and
each of them attempts the write the constraint exists to refuse.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 03:00:56 +02:00