Full-refresh models that rebuild months of history on every run are the quiet budget killers of a warehouse. Converting them to incremental is high-value but subtle — uniqueness keys, late-arriving data, and lookback windows are exactly where "almost right" AI code produces silently wrong tables.
This playbook uses an assistant to propose the incremental strategy and generate the code, then proves correctness with a full-refresh-vs-incremental parity check before the old behavior is retired.
Use this when a model's runtime or scanned bytes have grown with table size, but each run only genuinely changes recent partitions. Best applied to fact-style models with a reliable event timestamp or updated-at column.
Triggers:
Gather the evidence the strategy depends on. Before prompting, answer with queries, not intuition: What is the model's grain and unique key? Which column marks recency (event_ts, updated_at)? How late does data arrive?
-- how late do records really arrive?
SELECT CAST(loaded_at AS DATE) - CAST(event_ts AS DATE) AS days_late,
COUNT(*) AS n
FROM stg_events
GROUP BY 1
ORDER BY 1;
The tail of this distribution sets your lookback window. Guessing it is how incremental models silently drop late rows.
Prompt with the evidence, ask for strategy before code.
Convert the dbt model below from full refresh to incremental.
Facts (measured, not assumed):
- Grain: one row per event_id. unique_key candidate: event_id.
- Recency column: event_ts. Late-arrival distribution: 99.7% within
2 days, max observed 6 days.
- Source is append-only except for a rare status backfill (updates).
- Target warehouse: [X]. Current runtime 34 min, scans 1.2 TB.
First: propose the incremental strategy (merge vs delete+insert vs
append), the unique_key, and the lookback window, with reasoning and
the failure mode of each rejected option. Wait for my confirmation
before writing any code.
[paste current model SQL]
Making the assistant argue strategy first surfaces wrong assumptions while they are still cheap.
Review the strategy against your evidence. Updates in the source rule out pure append. A 6-day observed maximum lateness means a 7-day lookback minimum. If the assistant proposes a 3-day window "as is typical," it ignored your data — push back.
Accept the code, then verify parity before trusting it. Build the incremental version alongside a fresh full-refresh build and diff:
SELECT
(SELECT COUNT(*) FROM fct_events_incr) AS incr_rows,
(SELECT COUNT(*) FROM fct_events_full) AS full_rows,
(SELECT COUNT(*) FROM
(SELECT * FROM fct_events_incr
EXCEPT
SELECT * FROM fct_events_full)) AS incr_not_full,
(SELECT COUNT(*) FROM
(SELECT * FROM fct_events_full
EXCEPT
SELECT * FROM fct_events_incr)) AS full_not_incr;
Both EXCEPT counts must be zero after at least three consecutive incremental runs on live data — a single run proves nothing about the merge logic.
Test the late-data path deliberately. Insert a synthetic source row with an event_ts inside the lookback window but a fresh loaded_at, run incrementally, and confirm it lands. Then insert one just outside the window and confirm you understand (and accept) that it does not.
Add the safety rails before merging. A unique test on the key, a scheduled periodic full-refresh (weekly or monthly) as a self-healing backstop, and a comment in the model recording the measured late-arrival basis for the lookback window.
The lookback window is an empirical claim about your data, not a style choice. Re-measure it when upstream loading behavior changes, or late rows will vanish without an error anywhere.
event_ts when arrival is what matters (or vice versa) either misses late rows or rescans everything. The parity check plus the cost check together catch both directions.MAX(event_ts) in UTC compared against local-time source data shifts the window by hours at the boundary. State the timezone in the prompt and check the boundary explicitly.The strategy discussion needs schema shape and measured distributions, not client data. In restricted environments, run steps 1, 4, 5 (all queries) inside the client warehouse, and give the assistant — via client-tenancy Bedrock/Azure OpenAI, or local Ollama if no approved endpoint exists — only the model SQL with identifiers genericized plus the summary statistics (late-arrival percentiles, row counts). Numbers like "99.7% within 2 days" carry no client-identifying information but are exactly what the strategy depends on. Parity evidence stays in the client environment as the audit artifact.