Appearance
Best Practices
The platform is underpinned by the following non-negotiable design principles that govern every architectural decision.
- Sovereignty — runs entirely in-jurisdiction with no mandatory external data transfer.
- Open standards — Apache Iceberg, Kafka, Trino, Spark, and dbt throughout — avoiding proprietary lock-in.
- Governance first — Atlas wraps every layer; governance is built in, not retrofitted.
- Medallion quality pattern — raw data preserved while consumers always receive certified, validated data.
- Single semantic truth — one definition of every KPI, exposed consistently via the semantic layer.
- Separation of concerns — ingestion, storage, processing, intelligence, and consumption are decoupled; changes do not cascade without governed promotion.
- AI-native — vector stores, feature stores, MLOps, and multi-agent orchestration are first-class citizens.
Golden rules
Every rule here exists because breaking it caused a real incident.
Ingestion
- Decide partitioning before you deploy. Use none or month; never
day()on big backfills. Why: the partition spec is fixed at deploy, and day-partitioned backfills crashed ingestion with out-of-memory errors and created millions of tiny files. - End dates are exclusive, bounds are midnight, and never in the future. Why: whole-day, half-open ranges. Future days get recorded as loaded-but-empty.
- Check "Already loaded" before any historical load. Why: historical loads append without de-duplication, so an overlap doubles rows.
- Backfill one large table at a time. Why: concurrent large backfills competed for memory and produced short or duplicated counts.
- Verify counts after a backfill (monthly counts vs the source, or Reconciliation). Why: a green run means the steps finished, not that the table is complete.
- Don't re-trigger in a panic. Wait for the 5-minute reconciler, and check chunk status first. Why: repeated triggers during a backfill multiply work and confuse state.
- Leave Tuning defaults alone. Output Batch Size 0, Concurrent Tasks 1, Avro logical types on. Why: a batch size of 1 once turned 350K rows into billions.
- Pick a bookmark column that is indexed, never NULL, and updated on change. Why: otherwise updates are missed or every run scans the whole source.
- One destination per pipeline, one pipeline per table. Why: shared ownership caused type drift and write crashes.
- Nothing runs until it's scheduled. Why: the most common "stale data" complaint was simply an unscheduled pipeline.
Transformation
- In the dbt terminal: commit, then push immediately. Why: the terminal workspace resets to the repository copy, and unpushed commits are destroyed.
- Commit
packages.yml,package-lock.ymlanddbt_packages/. Why: air-gapped schedulers can't download packages. - Keep the whole dbt project compiling. Why: scheduling parses every model, so one broken file breaks all jobs.
- Always pass
--targetin the terminal, and keep each model to one engine's dialect. Why: the terminal's default target may differ from the UI's. - De-duplicate and enforce NOT NULL in silver. Why: bronze is raw and nullable by design.
- Re-save a job after changing its models. Why: jobs run their own copy of the project.
Serving & analytics
- Cubes and dashboards read gold, never bronze.
- Pre-join one-to-many relationships in dbt gold. Why: fan-out inflates metrics and blocks materialization.
- Add a Refresh cubes node after gold in the job. Why: warehouse MVs over Iceberg don't notice new data by themselves.
- Use Export CSV for large results, not a bigger Limit. Why: the grid caps at 10k rows, while export is complete and governed.
- Filter on dates, select only needed columns, filter before joining. Why: per-query memory is finite, and Iceberg rewards pruning.
Notebooks
- Aggregate in Spark;
.toPandas()only small results. Why: the kernel has only a few GB. - Experiment in
sandbox_<you>, productionise in dbt + Jobs. Why: notebooks stop after 30 minutes idle and aren't scheduled. - After two failed spawns, stop and report. Why: the hub shuts itself down after five.
Security & access
- Sensitive analysis happens on per-user governed surfaces (Workbench Lakehouse, JDBC, cubes, impersonated BI connections). Why: Voir, the warehouse tab, notebooks and hand-made BI connections use shared identities.
- Scope governance policies narrowly and test with a non-admin user. Why: one catalog-wide rule once hid every schema.
- Update saved passwords in tools right after changing yours. Why: stale retries trigger lockout.
- Don't build on Lakebase (internal Postgres). Why: it holds platform state, and changes there can break pipelines.
