main
1
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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>
|