Skip to content

ADR 017 — Partner-Managed Bronze: Accepting External Snowflake Loading

Status

Accepted

Context

When onboarding Rippit QA evaluation data for Condé Nast (#540), two options were evaluated:

Option 1 — S3 Pipeline (standard xo-foundry pattern) Build an xo-foundry extractor that hits the Rippit API, stages files to S3, and loads into CND_DB.BRONZE via COPY INTO. This is the standard ELT pattern used for Gladly, Sprout, and Google Sheets.

Option 2 — Partner-Managed Bronze (selected) The Rippit team already maintains a native Snowflake integration that loads QA evaluation data directly into MAESTRO_DB.MAESTRO within the XtendOps Snowflake account (FBRITWN-XOS6437). XO-Data accepts this database as an externally-managed Bronze source and references it from dbt Silver models.

The Rippit team manages their own load schedule, warehouse (RIPPIT_LOAD_WH), and role (MAESTRO_ROLE). The data is available for XO-Data to read via cross-database references.

Decision

When a data partner or tool vendor already loads data into a table in the XtendOps Snowflake account, we accept the partner-managed database as the Bronze source rather than building a redundant extraction pipeline.

For Rippit specifically: - MAESTRO_DB.MAESTRO is the Bronze source for CND QA evaluation data - The Rippit team (MAESTRO_USER / MAESTRO_ROLE) owns all loading into this database - XO-Data dbt Silver models reference MAESTRO_DB.MAESTRO as a cross-database source - No xo-foundry extractor, S3 staging, or schemachange migration is needed for the Bronze layer

Partner database connection details (read reference)

Field Value
Account FBRITWN-XOS6437 (XtendOps account — same as XO-Data)
Database MAESTRO_DB
Schema MAESTRO
Warehouse (Rippit-owned) RIPPIT_LOAD_WH
Role (Rippit-owned) MAESTRO_ROLE

XO-Data queries this database using its own read-capable role; no credentials sharing is required.

Consequences

Gets easier: - Zero ingestion infrastructure to build or maintain for this data source - Data is always current — Rippit controls freshness and load cadence - Schema exploration and Silver model development can start immediately against live data

Gets harder / risks to manage: - XO-Data does not own Bronze ingestion — we cannot control load timing, retries, or backfill - Rippit schema changes (column renames, type changes, table drops) can silently break downstream Silver/Gold models; we must monitor for schema drift - No BATCH_ID / LOADED_AT metadata columns are guaranteed — Silver models must adapt to whatever columns Rippit provides - Pipeline observability is split: Rippit owns the load, XO-Data owns the transformation; failure attribution requires coordination

Mitigations: - Add a dbt source freshness check on MAESTRO_DB.MAESTRO tables so Airflow alerts if the Rippit load stops - Document the Rippit schema in the Silver model's schema.yml so column changes surface as dbt compilation errors - Establish a communication channel with the Rippit team for schema change notifications

Options Considered

Option 1 — S3-Based xo-foundry Extractor (not selected)

Pros: XO-Data owns the full pipeline; consistent with all other CND/WBP pipelines; Bronze metadata columns (BATCH_ID, LOADED_AT, RECORD_KEY) guaranteed; easier to debug load failures.

Rejected because: Rippit already has a working Snowflake integration loading live data. Building a parallel S3 pipeline would duplicate the ingestion work, require Rippit API credentials and maintenance, and add latency. The marginal benefit of owning the Bronze layer does not outweigh the cost when the partner database is already in the same Snowflake account.

When to Apply This Pattern

Accept partner-managed Bronze when all three conditions are true:

  1. The data partner already loads into a table in the XtendOps Snowflake account (FBRITWN-XOS6437)
  2. The partner database is readable by XO-Data roles (confirmed access)
  3. The data partner commits to providing advance notice of breaking schema changes

If any condition is not met, fall back to the standard xo-foundry S3 pipeline.


See also: ADR 011 — batch_replace loading | ADR 013 — Bronze all-VARCHAR | Snowflake Object Inventory