CI's integration job failed, and it failed CORRECTLY. That job provides a live OpenSearch and a live ClickHouse and then asserts that nothing in tests/integration/ skipped, on the stated principle that "a skipped suite must never masquerade as a green integration gate". The DuckDB suite needs a Python interpreter that job does not provide, so it skipped, and the guard fired — the first suite in that directory ever to skip there. Moving the file to tests/duckdb/ respects the guard rather than weakening it. Loosening it to tolerate skips would have traded a real gate for one green job, which is the trade this estate keeps regretting. The suite still runs, still fails rather than skipping when DUCKDB_PYTHON is set and DuckDB is broken, and is still pinned by the committed evidence. Also fixed: "does NOT ship the Iceberg table" asserted against the FILESYSTEM when the claim is about what is COMMITTED. The live suite rebuilds that table locally, so the assertion failed whenever both suites ran in one pass — it was testing the wrong thing rather than catching a real problem. It now asserts against `git ls-files`, and also asserts the parquet/csv fixtures ARE tracked, so a version that stopped shipping any fixture would fail too. docs/analytics/BI_QUERY_METRIC_QUALITY.md is organised around what is PROVEN and what is NOT, because the second list is the one that gets dropped. It records the five findings and the six open items, including that BI-P029's MetricFlow was never executed and that BI-P021's budget is a bound rather than a hard cap (measured 130x overshoot at a 100ms poll). It also reports, without changing it, a latent flaw in .gitea/workflows/ci.yml (a protected file this branch does not touch): the integration guard's second pattern `Tests [0-9]+ passed` never matches, because vitest writes that summary with ANSI colour codes between the words. The guard is therefore STRICTER than it reads — "any skip fails" rather than "skipped and nothing passed" — so nothing is currently unguarded, but the escape hatch does not work and someone will eventually be puzzled by it. 957 tests pass with ClickHouse, Postgres and DuckDB all live. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tests/fixtures/duckdb/ — BI-P014
sales.parquet and customers.csv are committed: small, binary-stable, and
portable across checkouts.
The Iceberg fixture is deliberately NOT committed. pyiceberg writes
ABSOLUTE paths into its metadata and Avro manifests, so a committed table only
resolves on the machine that built it — a fixture that silently fails
everywhere else is worse than no fixture. The recorded result of a real
iceberg_scan run is kept in evidence/bi-p014/duckdb-sandbox.json instead,
and tests/analytics/duckdb-provider.test.ts pins it.
To rebuild the Iceberg fixture locally:
python -m venv .venv && .venv/bin/pip install duckdb pyarrow 'pyiceberg[sql-sqlite]'
DUCKDB_PYTHON=.venv/bin/python pnpm vitest run tests/duckdb/duckdb-provider.live.test.ts
iceberg_scan is pointed at an EXACT metadata JSON file rather than a table
directory. That is not a workaround: DuckDB refuses to glob for the latest
version by default because globbing can read uncommitted data, and an exact
metadata file is precisely what "Iceberg snapshot" means in BI-P014.