Provider Attribution
Methods
Provider attribution assigns each person to the provider who most plausibly manages their primary care. Organizations use attribution for panel management, quality and cost performance measurement, contracting, network optimization, and outreach workflows.
The Tuva Provider Attribution preprocessing module implements a transparent, CMS-style
primary-care attribution that runs using Tuva's standard claims, eligibility, and
provider data assets. The assignment algorithm does not require external payer
or custom assignment values. Enabling it does, however, also enable the
provider_attribution Input Layer contract: the root project must define that
model with the documented columns. Tuva normalizes that input and joins its
payer/custom fields to member months alongside the calculated assignments.
An empty model resolves the dbt dependency but does not satisfy Structural Data
Quality's source-population requirement.
The logic is inspired by CMS attribution used in ACO/REACH contexts but generalized to work across all payers and claim types brought into Tuva. To improve coverage and analytics usability, we add two additional fallback passes (Steps 4–5) that expand the window and relax provider classification requirements only after the earlier CMS-like passes do not yield an assignment.
Specifically, the Core preprocessing module:
- Classifies rendering NPIs as PCP, Specialist, or NPP using NPPES and the Medicare taxonomy crosswalk.
- Identifies primary-care HCPCS services from claims.
- Requires eligibility via member months within the lookback window.
- Applies a five-pass methodology to find the best-fitting provider, adding broader fallback behavior only when needed.
Five-Pass Methodology
For each person, we evaluate providers in ordered passes and select the first pass that yields any qualifying provider(s). Within the chosen pass, providers are ranked by the highest summed allowed amount, then the highest number of visits. A null or zero allowed amount falls back to the paid amount for that claim line.
- 12-month PCP/NPP primary-care HCPCS
- 12-month Specialist primary-care HCPCS (only if Step 1 has no result)
- 24-month PCP/NPP primary-care HCPCS
- 24-month Primary-care HCPCS (any provider classification)
- 24-month Any rendering NPI (fallback when HCPCS-based classification fails)
Windows differ slightly by output:
- Current: The last 12 or 24 calendar months ending on
as_of_date. See Current Output Date Behavior and Configuration for defaults and overrides. - Yearly: Calendar-year windows (Jan..Dec) for the performance year, with expanded windows spanning Jan of Y-1 through Dec of Y (24 months) as a fallback.
The ranking table exposes all qualifying providers and the first pass each qualifies for. The assignment tables choose the top-ranked provider (rank = 1) or emit a labeled fallback when no assignable history exists.
Data-Source-Aware Attribution and Core Tables
Tuva-assigned attribution is calculated separately for each person_id and
data_source. The yearly output has one row per person_id, data_source, and
performance_year. The current output has one row per person_id,
data_source, and as_of_date.
The yearly output is projected onto member-month records. Every row in
core.member_month for the same person_id, data_source, and calendar year
receives the same Tuva-assigned provider and attribution context. The same fields
flow through to core.cost and core.utilization, which lets cost and
utilization reporting use either externally supplied attribution fields or
Tuva-assigned attribution fields.
Tuva attribution does not partition assignments by payer or plan. Existing
externally supplied payer and custom attribution fields from
input_layer.provider_attribution remain separate and unchanged.
When no eligible claims history exists, Tuva keeps the attribution bucket, step,
and lookback context but leaves tuva_attributed_provider null.
Inputs and Dependencies
- Provider attribution:
input_layer.provider_attributionis cast innormalized__provider_attributionwhen provider attribution is enabled - Provider data:
provider_data.provideris used directly by the attribution-specific provider classification step to validate rendering NPIs, keep individual providers, and attach specialty context - Claims: normalized medical claims from claims preprocessing
- Eligibility: normalized eligibility exploded to Claims Preprocessing member months
- Attribution windows: the package-owned
member_month__month_spine, which contains every calendar month from January 1900 through December 2100. The published dailyterminology.calendarasset is not a dependency. - Terminology and value sets:
cms_provider_attribution__primary_care_hcpcs_codescms_provider_attribution__provider_specialty_assignment_codes
The end-to-end flow is Input Layer provider attribution and provider data →
Normalized Attribution → Claims Preprocessing Attribution → core.member_month,
core.cost, and core.utilization.
Current Output Date Behavior and Configuration
The “current” scope uses a data-driven as_of_date to define its rolling
12- and 24-month windows:
- Default: the maximum claim_end_date in the attribution claim set, if it is not null and is not a future date; otherwise the system date at runtime.
- Override: set the dbt var
provider_attribution_as_of_dateto aYYYY-MM-DDvalue to pinas_of_date.
Examples:
Pin to a date:
dbt build --select tag:provider_attribution \
--vars '{"provider_attribution_as_of_date":"2025-10-01", "claims_enabled": true, "provider_attribution_enabled": true}'
Use the default date and enable both required domains:
dbt build --select tag:provider_attribution \
--vars '{"claims_enabled": true, "provider_attribution_enabled": true}'
Notes:
- Models are enabled when both
provider_attribution_enabledandclaims_enabledevaluate true. - The “current” output runs for every person with at least one member month
in the last 12 months ending at
as_of_date. Persons without assignable history receive a labeled fallback row to keep the output grain of the tables at one row for every member with eligibility during the evaluation period.
Example SQL
Count Assigned by Step (Current)
select
assigned_step
, data_source
, count(*) as members
from claims_preprocessing.assigned_beneficiaries_current
group by
assigned_step
, data_source
order by
assigned_step
, data_source;
Provider Panel Size and Context (Current)
select
provider_id
, provider_bucket
, data_source
, count(*) as attributed_members
, sum(visits) as visits
, cast(sum(allowed_amount) as decimal(18,2)) as allowed_amount
from claims_preprocessing.assigned_beneficiaries_current
where provider_bucket <> 'no_eligible_history'
group by
provider_id
, provider_bucket
, data_source
order by
attributed_members desc;
Fallback Rate (Current)
select
data_source
, cast(sum(case when provider_bucket = 'no_eligible_history' then 1 else 0 end) as decimal(18,2))
/ nullif(count(*), 0) as fallback_rate
from claims_preprocessing.assigned_beneficiaries_current
group by
data_source;
Members With No Assignable History (Current)
select
person_id
, data_source
, as_of_date
from claims_preprocessing.assigned_beneficiaries_current
where provider_bucket = 'no_eligible_history';
Comparing Annual Attribution
with a as (
select
person_id
, data_source
, provider_id
from claims_preprocessing.assigned_beneficiaries_yearly
where performance_year = 2023
and provider_bucket <> 'no_eligible_history'
),
b as (
select
person_id
, data_source
, provider_id
from claims_preprocessing.assigned_beneficiaries_yearly
where performance_year = 2024
and provider_bucket <> 'no_eligible_history'
)
select
coalesce(a.data_source, b.data_source) as data_source
, coalesce(a.provider_id, 'none_prior') as prior_provider
, coalesce(b.provider_id, 'none_current') as current_provider
, count(*) as members
from a
full outer join b
on a.person_id = b.person_id
and a.data_source = b.data_source
where coalesce(a.provider_id, 'none') <> coalesce(b.provider_id, 'none')
group by
coalesce(a.data_source, b.data_source)
, coalesce(a.provider_id, 'none_prior')
, coalesce(b.provider_id, 'none_current')
order by
members desc;
Top-3 Ranked Providers Per Person
This surfaces why a specific provider was chosen by comparing step, allowed_amount, and visits across candidates.
with pr as (
select
person_id
, data_source
, scope
, performance_year
, as_of_date
, lookback_start_date
, lookback_end_date
, provider_id
, provider_bucket
, step as earliest_step
, step_description
, allowed_amount
, visits
, ranking
from claims_preprocessing.provider_ranking
where scope in ('current','yearly')
)
select
person_id
, data_source
, scope
, performance_year
, as_of_date
, lookback_start_date
, lookback_end_date
, provider_id
, provider_bucket
, earliest_step
, step_description
, allowed_amount
, visits
, ranking
from pr
where ranking <= 3
order by
person_id
, data_source
, scope
, ranking;
Sample Dashboard
Below is an embedded, interactive sample built from small CSVs bundled with the docs. Select a measurement period to see coverage, step mix, and top providers.