A check snapshot compares named columns with the previous observed version. Use it when the source update clock doesn't reliably identify the business change you need to track.
A plan history might compare only plan. A subscription-state history might also compare status and monthly_amount. The column list gives the history its meaning.
NULL needs no invented replacement: a tracked value changing from unknown to known is a change. Technical fields need a different decision. If updated_at advances during every reload, including it in check_cols creates versions even when the business state stays the same.
Fields outside the comparison are stored when a version is created; they don't refresh in place after unrelated updates. These fixtures provide updated_at separately as a deterministic validity clock, while check_cols decides whether a new version belongs in the history.
{% snapshot subscription_history %}
{{ config(unique_key='subscription_id', strategy='check', updated_at='updated_at', check_cols=['plan', 'status', 'monthly_amount']) }}
select subscription_id, user_id, lower(trim(plan)) as plan,
lower(trim(status)) as status, monthly_amount, updated_at
from {{ source('pulse', 'subscriptions') }}
where subscription_id is not null and updated_at is not null
qualify row_number() over (partition by subscription_id order by updated_at desc, monthly_amount desc nulls last) = 1
{% endsnapshot %}
The check strategy compares three business fields while updated_at supplies the interval timestamp.