# MA Star Ratings — contract metadata

`medicare_silver.stars_contracts` · Medicare Advantage, Part D, Medicaid · status live

Contract-level Stars metadata (org type, parent org, marketing name). The join spine from a Star rating to the carrier/parent for sell-side rollups.

**Grain.** One row per Medicare contract per Star Ratings rating year. The MINIMAL verified key is (contract_id, rating_year): 14,138 distinct = 14,138 total rows (COUNT(*)=14138, COUNT(DISTINCT contract_id||rating_year)=14138). The profiler's reported 3-column key (contract_id, contract_name, bronze_publication_id) is a SUPERSET -- contract_name and bronze_publication_id are redundant because bronze_publication_id maps 1:1 to rating_year (20 publications = 20 years) and contract_id is already unique within a year. Spread: 20 annual vintages (RY2007=552 contracts ... RY2026=769); contract_id alone is NOT unique (1,905 distinct across all years; a long-lived contract like H5859 appears in all 20 years).

**How to use it.** Map a CMS contract to its parent payer for a given Star year, or list a carrier's MA/PDP footprint. Example: SELECT rating_year, contract_id, contract_name, marketing_name, org_type, snp_flag FROM medicare_silver.stars_contracts WHERE parent_org LIKE '%Humana%' AND rating_year = 2026 ORDER BY contract_id; -- answers 'which Medicare contracts did Humana operate in the 2026 Star vintage, and which are SNP / what org type'. To attribute scores, join a Star measure/summary table ON (contract_id, rating_year). Always pin rating_year (the grain), never rely on effective_period_end (always NULL)."

**Traps.**
- GRAIN TRAP: contract_id is NOT unique (1,905 distinct across 14,138 rows -- a contract recurs every year it operated; H5859 appears in all 20 years). The real key is (contract_id, rating_year). The profiler's (contract_id, contract_name, bronze_publication_id) is a redundant superset since bronze_publication_id == rating_year 1:1 and contract_name is sometimes NULL.
- NULLS CARRY MEANING (vintage coverage): descriptive columns are NULL not because a contract lacks the attribute but because that year's CMS source file didn't include the column. org_type/marketing_name/parent_org are NULL for RY2007/2008/2011; contract_name NULL for RY2008-2010 & 2012; snp_flag only from RY2013+; disaster_2023_pct only in RY2025-2026; disaster_2024_pct only in RY2026. Don't infer 'unknown contract type' from a NULL in early years.
- is_current is 100% TRUE and cms_vintage_sequence/parse_revision are constant (1 and 0), restatement_of is 100% NULL -- this is a clean single-version-per-year load with NO superseded rows yet. The SCD/restatement machinery (is_current, restatement_of, calculation_epoch '_v1', cms_vintage_sequence) is scaffolding that is inert today; code defensively for when restatements arrive but don't expect dedup to be needed now.
- effective_period_end is 100% NULL -- you CANNOT do as-of/point-in-time filtering with the effective_period_start/end pair. Use rating_year (or effective_period_start, which is a single release date per year) to pick a vintage. Also note RY2024's release date is an outlier (2024-07-02 mid-year vs the usual October-of-prior-year cadence).
- payment_year == rating_year and performance_year == rating_year - 2 in EVERY row -- these are deterministic derivations, not independent facts. asserted_at is the May-2026 backfill load time, NOT data validity; never use it for time-series. This table has NO star score/measure columns -- it is the contract dimension only; join Star measure/summary tables on (contract_id, rating_year) to get the actual ratings.
- parent_org is free-text and not normalized: Anthem appears as both 'Anthem Inc.' and 'Elevance Health, Inc.' across years, 'Molina Healthcare, Inc.,' has a trailing comma, 'CIGNA' is all-caps. Normalize/fuzzy-match before grouping payers. Also 6 empty-string (not NULL) values exist in org_type and snp_flag, confined to RY2013.

| column | type | meaning |
|---|---|---|
| contract_id | string | CMS Medicare contract identifier (the H/S/R/E number). Part of the grain. Prefix encodes contract type: H=MA/MA-PD or cost (12,685 rows, 1,699 distinct), S=standalone PDP (1,042 rows, 149 distinct), R=regional PPO (352 rows, 37 distinct), E=employer/EGWP direct-contract (48 rows, 10 distinct), plus a handful of stray single rows. NOT unique on its own -- unique only within a rating_year. |
| org_type | string | CMS contract organization type. Top values: 'Local CCP' (9,870 -- local coordinated-care MA HMO/PPO, the bulk), 'PDP' (798 standalone Part D), 'Demo' (606), 'Regional CCP' (310), 'PFFS' (236), '1876 Cost' (205), 'National PACE' (134), 'MSA' (47), 'Employer/Union Only Direct Contract PDP' (44), '1833 Cost/HCPP' (25), 'Chronic Care' (8), plus a few more. NULL for some early vintages (2007,2008,2011) where the source file lacked it; 6 EMPTY-STRING rows exist only in RY2013 (parse artifact). |
| contract_name | string | Legal/contract name of the organization (e.g. 'CHA HMO, INC.', 'SUPERIOR HEALTHPLAN, INC.'). Inconsistently populated by vintage: present for RY2007, RY2011, and RY2013+, but NULL for RY2008-2010 and RY2012 (those source files did not carry it). |
| marketing_name | string | Consumer-facing brand name the plan markets under (e.g. 'Humana', 'Wellcare', 'Wellcare By Allwell'). Often differs from contract_name. NULL for RY2007 and RY2008 (not in early source files); populated RY2009+. |
| parent_org | string | Parent organization / ultimate payer the contract rolls up to (e.g. 'UnitedHealth Group, Inc.' 1,326 rows, 'Humana Inc.' 823, 'Centene Corporation' 742, 'Aetna Inc.', 'CVS Health Corporation', 'Anthem Inc.'/'Elevance Health, Inc.', 'CIGNA', 'Kaiser Foundation Health Plan, Inc.'). This is THE column for attributing a contract to a carrier. NULL for RY2007,2008,2011. Note free-text inconsistency: Anthem appears as both 'Anthem Inc.' and 'Elevance Health, Inc.' across years; 'Molina Healthcare, Inc.,' has a trailing comma. |
| snp_flag | string | Whether the contract includes any Special Needs Plan (SNP): 'Yes' (4,492) or 'No' (5,765). Only populated from RY2013 onward (NULL for RY2007-2012); 6 empty-string rows in RY2013. |
| disaster_2023_pct | double | Percent of the contract's enrollment affected by a 2023 FEMA-declared disaster (0-100, used by CMS for the Star Ratings 'extreme and uncontrollable circumstances' adjustment). Range observed 0.0-97.0, mean ~1.16, only 28 distinct values. ONLY populated in the RY2025 and RY2026 vintages (NULL everywhere else) -- a year-specific adjustment column carried in recent data tables. |
| disaster_2024_pct | double | Percent of the contract's enrollment affected by a 2024 FEMA-declared disaster (0-100; CMS disaster adjustment). Range 0.0-100.0, mean ~8.08. ONLY populated in the RY2026 vintage (NULL all other years). |
| sanction_deduction | string |  |
| effective_period_start | date | CMS release/effective date of that year's Star Ratings data-table vintage -- exactly ONE distinct date per rating_year (RY2026=2025-10-10, RY2025=2024-10-11, RY2023=2022-10-06...). This is the table's primary temporal anchor. Note RY2024 is anomalous at 2024-07-02 (mid-year, vs the usual Oct of the prior calendar year). Earliest 2006-11-09 (RY2007), latest 2025-10-10 (RY2026). |
| effective_period_end | date | Intended SCD close date for the vintage, but 100% NULL across all 14,138 rows -- never populated, even for old vintages. Do NOT use it for point-in-time/as-of filtering; treat every row as open-ended and disambiguate by rating_year instead. |
| calculation_epoch | string | Logical vintage label, format 'ry{YYYY}_v1' (e.g. 'ry2026_v1'). Maps 1:1 to rating_year. The '_v1' suffix and the all-v1 reality signal a restatement-versioning scheme that currently has only first versions loaded. |
| restatement_of | string | Provenance pointer to a prior vintage this row restates. Currently 100% NULL (no restatements have been ingested yet) -- lineage scaffolding for future CMS data-table reissues. |
| parse_revision | int | Parser revision number for the row. Constant 0 across all rows (single parser generation in this load). |
| parser_artifact_hash | string | Short hash (e.g. '86dfb448d9b9beb9') identifying the parser code/artifact that produced the row -- provenance for reproducibility. |
| source_url | string | Original CMS download URL the vintage was parsed from -- exactly one distinct URL per rating_year (20 distinct). URL pattern evolved: early years '..._plan_ratings.zip', recent years '...-star-ratings-data-tables.zip' (e.g. RY2026 = https://www.cms.gov/files/zip/2026-star-ratings-data-tables.zip). |
| sha256_content_hash | string | SHA-256 of the source bronze file content -- one value shared by all rows from the same vintage (content-addressed provenance/dedup of the raw download). |
| bronze_publication_id | string | UUID of the bronze ingestion/publication event. Maps 1:1 to rating_year (20 distinct). Looks key-like but is NOT a row key -- it groups ~600-875 rows (all contracts in that vintage). Equivalent to rating_year for partitioning. |
| asserted_at | timestamp | Pipeline ingest/load timestamp (when this row was written to silver), NOT data validity time. All rows loaded in a tight backfill window 2026-05-18 to 2026-05-28 (8 load days). Do not use for temporal analysis -- use effective_period_start / rating_year. |
| rating_year | int | The CMS Star Ratings rating year -- the headline temporal dimension and part of the grain. Ranges 2007-2026 (20 values). This is the year the ratings are PUBLISHED/labeled (e.g. '2026 Star Ratings'), released in autumn of the prior calendar year. |
| performance_year | int | The measurement/performance year the ratings reflect. Deterministically = rating_year - 2 for EVERY row (verified: offset always 2). Reflects CMS's standard ~2-year lag between data collection and rating publication. Derived, not independent. |
| payment_year | int | The year CMS payment/bonus adjustments apply. Deterministically = rating_year for EVERY row (verified equal in 100% of rows). Derived/redundant with rating_year in this table. |
| is_current | boolean | SCD current-version flag. 100% TRUE for all 14,138 rows -- there are NO superseded/historical shadow rows in this table. Filtering on is_current=true is a harmless no-op today; it exists for the restatement model (when restatements arrive, old versions would flip false). |
| cms_vintage_sequence | int | Ordinal of the CMS publication for a given rating_year (1=first/original release, 2=reissue, etc.). Constant 1 across all rows -- only original releases ingested so far; would increment if CMS reissues a year's tables. |
| qbp_payment_year | int |  |

Tools that read it: get_stars_rollup

Query it: `query_substrate` with `SELECT ... FROM medicare_silver.stars_contracts WHERE ... LIMIT 100`; read `describe_data_source("medicare_silver.stars_contracts")` first.
