Skip to content

ADR-0012 — Minimal dbt: a contract and four models, no medallion ceremony

  • Status: proposed (accept in CP13)
  • Date: 2026-07-02
  • Domain: transformation layer · scope discipline

Context

The project's governing rule: an architecture choice is showcased only when a viewer can observe its tradeoff against the rejected alternative. A full bronze/silver/gold medallion build shows no tradeoff — it is backdrop, not exhibit. But two pieces of the transform layer are genuinely load-bearing: the bronze contract (without a shared event shape, the batch-vs-streaming comparison compares apples to oranges) and a dedup/cleaning step (benchmarking engines on dirty, double-observed data would make Comparison 3's numbers meaningless).

Decision

Keep exactly what carries weight:

  • The bronze contract (docs/contracts/media-bronze-contract.md) — non-negotiable.
  • A minimal dbt project, four models (per ADR-0015's dual-source pivot, still within CLAUDE.md M5's 3–4 model bound): one staging model per source — stg_wiki_edits, stg_hn_snapshots (dedup, typing) — feeding two narrow aggregates, no separate fact layer for either (there isn't enough shape between staging and aggregate here to earn one): agg_wiki_edit_rate_hourly (the rolling-window aggregate that is the primary benchmark query — chosen over HN engagement for volume: EventStreams reaches useful scale in days, HN's 15-minute snapshot cadence accumulates far more slowly) and agg_hn_engagement_daily (score/comment-velocity deltas — the mutable-fact narrative example, not the benchmarked table). Schema tests (unique, not_null) on the keys. Run as an ephemeral container (make dbt-run), zero steady-state RAM.

No named gold layer, no exposure docs, no snapshot machinery. dbt is here for two reasons only: it is the honest home for the cleaning logic, and its visible presence is recruiter-legible evidence of standard tooling. Both are served by three models.

Consequences

  • The transform layer costs one task of setup and nothing at runtime.
  • Comparison 3 gets a fair, deduplicated input, and its query lives in version control as a tested model rather than a string in application code.
  • If the project later earns a real gold layer, the structure extends without rework — the restraint is reversible; gold-plating up front would not have been.

Alternatives considered

  • Full medallion + dbt docs/tests suite — rejected: decoration by the project's own rule.
  • Plain SQL in the poller, no dbt — viable and leaner; rejected because the cleaning logic deserves tests and lineage, and the tool's presence is cheap at this scope.