Medicare Advantage, Part D, Medicaid

MA Star Ratings — cross-year measure crosswalk

medicare_silver.dim_stars_measure_crosswalk·partial·silver·annual·Medicare Advantage Star Ratings
Rows
N/A
Columns
9
History
2024 (from_rating_year) to 2025 (from_rating_year); maps forward to 2026 (to_rating_year)
Card
yesgrain, traps, filters
Typed tools
0

What it is

  1. 1A CMS Medicare Advantage / Part D Star Ratings measure-ID crosswalk: it maps each quality measure's ID from one rating year to its corresponding ID in the next rating year, flagging whether the ID stayed the same (identity) or was renumbered (renamed).
  2. 2Its purpose is to let an agent join Star Ratings measure-level data across rating years WITHOUT being fooled by CMS's annual measure renumbering (where the same code can be reused for a different measure).

Grain

KeyGrain
from_measure_idfrom_rating_yearsource
  1. 1Logically, one row per (source measure, source rating year) per provenance source — i.e. one mapping of a measure from year N to year N+1, recorded once per CMS source document.
  2. 2The MINIMAL verified unique key is (from_measure_id, from_rating_year, source) = 109 distinct logical rows (equivalently to_measure_id/to_rating_year are derivable, since no measure fans out).
  3. 3IMPORTANT: the physical table holds 53,079 rows, NOT 109 — every logical row is duplicated many times (median 631x for the primary source, 3x for the secondary), an append-without-dedup artifact.
  4. 4There are only 89 distinct (from_measure_id,from_rating_year,to_measure_id,to_rating_year) tuples and 109 distinct full rows.
  5. 5You MUST SELECT DISTINCT (or GROUP BY the key) to recover the true grain; raw COUNT(*) is meaningless.

How to read it

  1. 1To translate a 2025 Part C measure to its 2026 ID before joining year-over-year Star Ratings data: SELECT DISTINCT from_measure_id, to_measure_id, crosswalk_type, notes FROM dim_stars_measure_crosswalk WHERE from_rating_year=2025 AND from_measure_id='C14'.
  2. 2Returns C14 -> C17 (renamed), telling you that RY2025 'Medication Reconciliation Post-Discharge' (C14) is RY2026 C17, so a naive join on code 'C14' across years would silently mismatch.

Traps

  1. 1ROW COUNT IS A LIE: 53,079 physical rows but only 109 distinct logical rows / 89 distinct measure-pair tuples. Every mapping is appended many times (median 631x for source='cms_tech_notes_attachment_j', 3x for source='cms_tech_notes'). ALWAYS SELECT DISTINCT or GROUP BY the grain key — never trust COUNT(*), AVG, or unaggregated joins against this table or you will multiply downstream rows ~600x.
  2. 2is_current IS A DEAD FLAG: it is constant true for all 53,079 rows and performs NO dedup or versioning. Filtering is_current=true removes nothing and does NOT collapse the duplicates. (This is unlike sibling Medicare snapshot dims where is_current actually selects the live version.)
  3. 3TWO PROVENANCE VARIANTS OF THE SAME MAPPING: source has two values ('cms_tech_notes_attachment_j' = primary/authoritative, 'cms_tech_notes' = secondary). The same measure pair often appears under both, which is why distinct full-rows (109) > distinct measure tuples (89). Pick one source (prefer cms_tech_notes_attachment_j) when deduping, or you'll get two rows per mapping.
  4. 4to_rating_year and to_measure_id are NOT independent keys. to_rating_year is ALWAYS from_rating_year+1 (only consecutive-year links: 2024->2025, 2025->2026 — no multi-year hops). to_measure_id is functionally determined by (from_measure_id, from_rating_year) with zero fan-out. So the real key is just the from-side + source.
  5. 5THE WHOLE POINT IS ID REUSE DANGER — read notes. CMS renumbered Part C measures for RY2026 (inserted C13 'Kidney Health Evaluation', bumping downstream codes +3), so the SAME code means DIFFERENT measures across years. notes carries explicit WARNINGs (e.g. 'RY2026 C04 is a DIFFERENT measure', 'RY2026 C13 is a NEW measure, no RY2025 predecessor'). Part D (D01-D12) stayed identity in both transitions; 2024->2025 is 100% identity; only 2025->2026 Part C has renames. Do not assume a code is stable across years just because crosswalk_type isn't checked.

Columns (9)

ColumnTypeMeaning
from_measure_idstringSource Star Ratings measure ID in the EARLIER rating year (string). 42 distinct values across two prefixes: C## = Part C / health-plan measures (e.g. C01 Breast Cancer Screening, C14 Controlling Blood Pressure), D## = Part D / drug-plan measures (D01-D12). Combined with from_rating_year this is the left side of the year-over-year mapping. NO nulls.
from_rating_yearintThe earlier CMS Star Ratings Year (int) of the mapping. Only two values observed: 2024 and 2025. This is the table's primary time column (profiler temporal: earliest 2024, latest 2025).
to_measure_idstringThe same logical measure's ID in the LATER rating year (string), 45 distinct values. For crosswalk_type='identity' it equals from_measure_id; for 'renamed' it is the renumbered ID (e.g. C14->C17, a +3 shift). Functionally determined by (from_measure_id, from_rating_year) — verified zero fan-out (no from-measure maps to >1 to-measure). NO nulls.
to_rating_yearintThe later Star Ratings Year (int). VERIFIED to ALWAYS equal from_rating_year + 1 (53,079/53,079 rows). So the table only links CONSECUTIVE years: 2024->2025 and 2025->2026. Carries no independent information beyond from_rating_year+1.
crosswalk_typestringHow the measure ID changed across the two years. Only TWO values: 'identity' (ID stable, to_measure_id == from_measure_id; 57 distinct logical mappings) and 'renamed' (ID renumbered, to_measure_id != from_measure_id; 52 distinct logical mappings). 2024->2025 is 100% identity; 2025->2026 has the renames (Part C shifted, Part D stayed identity).
confidencestringStated confidence of the mapping. CONSTANT — every row is 'certain'. Carries no discriminating information in the current data (1 distinct value); exists for future lower-confidence/fuzzy mappings.
sourcestringProvenance label citing the CMS document the mapping was read from. TWO values: 'cms_tech_notes_attachment_j' (69 logical mappings — the primary/authoritative set, physically appended ~631x) and 'cms_tech_notes' (25 logical mappings — a secondary near-duplicate variant, appended only ~3x). The 89->109 distinct-row inflation is driven entirely by the same measure pair appearing under BOTH source labels. NO nulls.
notesstringFree-text human description of the measure plus CRITICAL warnings about ID-reuse traps. ALWAYS populated (zero nulls/empties). Contains the renumbering rationale and danger flags, e.g. 'Controlling Blood Pressure. Bumped +3 (C13 newly used for Kidney Health Evaluation).' and 'WARNING: RY2026 C04 is a DIFFERENT measure ... returned from display' and 'WARNING: RY2026 C13 is a NEW measure ... no RY2025 predecessor.' This is the field that prevents naive ID-based joins across years.
is_currentbooleanBoolean snapshot/active flag. CONSTANT true for all 53,079 rows (0 false). It does NOT perform any dedup or versioning here — there is no historical/superseded slice. Filtering on is_current=true is a no-op and does NOT remove the physical row duplication.

Query it

describe_data_source(source_fqn="medicare_silver.dim_stars_measure_crosswalk")     # the card, live
query_substrate(sql="SELECT * FROM medicare_silver.dim_stars_measure_crosswalk WHERE from_measure_id = '<value>' AND from_rating_year = '<value>' AND source = '<value>' LIMIT 100")
ItemValue
Typed tools that read itnone; raw SQL
Identity keyfrom_measure_id
Joinhow_to_join(source_fqn="medicare_silver.dim_stars_measure_crosswalk")
Raw doorAthena (read-only via query_substrate): medicare_silver.dim_stars_measure_crosswalk (filter is_current = true)
NoteGrain-governed; backfilled by product1_stars_crosswalk_backfill_v1; see the crosswalk end-to-end plan.

This page as markdown: /docs-md/data/medicare_silver_dim_stars_measure_crosswalk.md · every page in one file: /llms-full.txt