CI (SIAX Cloud) / security (push) Successful in 49s
Security Scan (SIAX Cloud) / security (push) Successful in 50s
CI (SIAX Cloud) / integration (push) Successful in 55s
CI (SIAX Cloud) / quality (push) Successful in 1m20s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m21s
CI (SIAX Cloud) / security (pull_request) Successful in 42s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 37s
CI (SIAX Cloud) / integration (pull_request) Successful in 1m10s
A slow query is a complaint; a drifted pre-aggregate answers instantly, with
confidence, and is wrong. So the router is fail-closed on eight named reasons,
and the one people leave out — drift_never_verified — is the one that matters
on launch day: a brand-new aggregate is exactly as unproven as a drifted one.
Proved against ClickHouse 26.3.10.60, 2M rows, a real materialized view
(evidence/bi-p105/materialization-drift.json):
after backfill match, 48 buckets, 801 571 002 both sides
GDPR erasure ALTER TABLE ... DELETE on the source. An MV is an INSERT
trigger and never sees a mutation, so the aggregate kept
the deleted revenue: it would have reported 801 571 002
against a true 761 580 554 — 39 990 448 overstated,
5.251%, with NOTHING stale. Staleness at the moment of
the decision: 1 second.
guarded router base_table (state_not_serving)
counterfactual a staleness-only router SERVES it — measured, not assumed
after rebuild match, and routing returns to the materialization
Drift detection treats a MISSING bucket as drift even when every value present
is correct (late-arriving rows are the sneakiest failure), and an empty
comparison as insufficient_data rather than match — the same false green
BI-P025 found in a quality check over an empty table.
The measured speed-up is reported as a distribution, not a figure: p50 3.4x,
but the run-to-run range spans 0.6x-7.5x on one idle host, so quoting "3.4x"
as a property of the system would be misleading (BI-P104 doctrine).
19 unit tests + 4 against live ClickHouse.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
76 lines
2.3 KiB
JSON
76 lines
2.3 KiB
JSON
{
|
|
"clickhouse_version": "26.3.10.60",
|
|
"recorded_at": "2026-09-07T01:55:42.821Z",
|
|
"source_rows": 2000000,
|
|
"after_backfill": {
|
|
"verdict": "match",
|
|
"buckets_compared": 48,
|
|
"revenue_total": {
|
|
"source": 801571002,
|
|
"aggregate": 801571002,
|
|
"delta": 0
|
|
}
|
|
},
|
|
"performance": {
|
|
"note": "ClickHouse caches marks and pages between repetitions, so these are WARM numbers on one host with nothing else running. They describe this shape of query on this data, not a system property.",
|
|
"repetitions": 9,
|
|
"base_table_ms": {
|
|
"n": 9,
|
|
"min": 48.70366200000012,
|
|
"p50": 76.67811500000016,
|
|
"p95": 115.04416399999991,
|
|
"max": 115.04416399999991,
|
|
"spread_ratio": 2.36
|
|
},
|
|
"pre_aggregate_ms": {
|
|
"n": 9,
|
|
"min": 15.281603999999788,
|
|
"p50": 22.727642999999944,
|
|
"p95": 84.41279499999973,
|
|
"max": 84.41279499999973,
|
|
"spread_ratio": 5.52
|
|
},
|
|
"speedup_p50": 3.4,
|
|
"speedup_range_min_max": [0.6, 7.5]
|
|
},
|
|
"gdpr_erasure_drill": {
|
|
"mutation": "ALTER TABLE sales DELETE WHERE tenant_id='t_alpha' AND customer_id < 250",
|
|
"verdict": "drifted",
|
|
"buckets_compared": 48,
|
|
"revenue_true_after_erasure": 761580554,
|
|
"revenue_pre_aggregate_would_report": 801571002,
|
|
"revenue_overstatement": 39990448,
|
|
"revenue_overstatement_pct": 5.251,
|
|
"worst_bucket": {
|
|
"key": "2026-08-28|FI",
|
|
"metric": "revenue",
|
|
"source_value": 15830779,
|
|
"aggregate_value": 16699145,
|
|
"absolute_delta": 868366,
|
|
"relative_delta": 0.05485301765630106
|
|
},
|
|
"guarded_router_decision": {
|
|
"source": "base_table",
|
|
"refusal": "state_not_serving",
|
|
"detail": "materialization state is \"drifted\""
|
|
},
|
|
"staleness_only_router_would_serve": true,
|
|
"staleness_seconds_at_decision": 1,
|
|
"note": "The aggregate was NOT stale by any clock: it had just been refreshed, and every freshness check passed. Only the source comparison caught it. This is why staleness alone is not a correctness guarantee."
|
|
},
|
|
"after_rebuild": {
|
|
"verdict": "match",
|
|
"revenue_total": {
|
|
"source": 761580554,
|
|
"aggregate": 761580554,
|
|
"delta": 0
|
|
},
|
|
"routing": {
|
|
"source": "materialization",
|
|
"materialization_id": "mv_sales_daily",
|
|
"target_ref": "opt_p105_mtql9p2f.sales_daily",
|
|
"staleness_seconds": 0
|
|
}
|
|
}
|
|
}
|