# MA pbp section b8 clin diag ther

`medicare_silver.pbp_section_b8_clin_diag_ther` · Medicare Advantage, Part D, Medicaid · status partial

Section B8: Clinical/diagnostic/therapeutic services cost-share. Coverage: All years.

**Grain.** One row per Medicare Advantage plan benefit package per CMS quarterly PBP release: i.e. one row per contract_id x plan_id x segment_id x report_year x quarter. Verified: COUNT(DISTINCT contract_id|plan_id|segment_id|report_year|quarter) = 201,488 = total row_count. The same plan-year is RE-FILED in multiple quarterly snapshots (Q1-Q4) for 2018+, so a single benefit year can appear in up to 4 rows; pre-2018 years have only one (Q1) snapshot. Collapsing to the latest quarter per plan-year yields 114,175 distinct plan-years.

**How to use it.** Compare what Medicare Advantage enrollees pay out of pocket for outpatient diagnostic and radiology services across plans/insurers/years. Example: to get the current (latest-snapshot) member cost share for advanced diagnostic radiology (MRI/CT) per plan for 2026, take the row with the max quarter per plan-year and read pbp_b8b_copay_amt_drs / pbp_b8b_coins_pct_drs: WITH latest AS (SELECT contract_id,plan_id,segment_id,report_year,MAX(quarter) mq FROM medicare_silver.pbp_section_b8_clin_diag_ther WHERE report_year=2026 GROUP BY 1,2,3,4) SELECT t.contract_id,t.plan_id,t.pbp_b8b_copay_amt_drs,t.pbp_b8b_coins_pct_drs FROM medicare_silver.pbp_section_b8_clin_diag_ther t JOIN latest l ON t.contract_id=l.contract_id AND t.plan_id=l.plan_id AND t.segment_id=l.segment_id AND t.report_year=l.report_year AND t.quarter=l.mq. Answers: how MA diagnostic-imaging cost-sharing is distributed and how it differs by plan/carrier (DRS copay median ~$4, B-8b therapeutic-radiology coinsurance median 20%).

**Traps.**
- NO is_current / latest flag exists. The same plan-year is re-filed across quarterly snapshots, so a naive COUNT(*) or GROUP BY contract/plan/segment/report_year SUMMED over rows double-counts: 75,577 plan-years appear in 1 quarter, 7,353 in 2, 13,775 in 3, and 17,470 in ALL 4 quarters. To get one current row per plan-year, select MAX(quarter) per (contract_id,plan_id,segment_id,report_year) — that collapses 201,488 raw rows to 114,175.
- quarter is part of the real key, not a throwaway. The minimal verified grain is contract_id x plan_id x segment_id x report_year x quarter (= 201,488). The profiler reported a 10-column SUPERSET that also listed bid_id, pbp_a_plan_type, and the two pbp_b8*_maxplan_yesno_pos columns — those are functionally dependent extras, not part of the key. version is likewise NOT part of the key.
- Quarters available per year are irregular and incomplete: 2001-2017 are Q1-only (annual), 2018/2019/2023 have all four, but 2020=Q1/Q2/Q4, 2024=Q1/Q3/Q4, and 2021/2025/2026=Q1-only. Do not assume Q4 is the canonical snapshot — always take MAX(quarter) actually present for that year.
- Many '*_auth', '*_ehc', and '*_cost_share' string columns are PACKED multi-character flag strings (e.g. auth='01000', coins_ehc='110'), where each character position is a separate yes/no flag for a service sub-type. They are NOT scalar values and must be decoded by position against the CMS PBP B-8 data dictionary. The simple '_yn' companions use CMS coding '1'=Yes, '2'=No (NOT 1/0), with NULL meaning not-applicable for that plan-type/year.
- bid_id is NULL for exactly the 8,316 oldest rows (report_year 2001-2006) because that field predates 2007; for 2007+ it is just contract_id||'_'||plan_id||'_'||segment_id, so it is derivable and not an independent identifier. Relatedly, version=0 marks that same pre-2007 vintage.
- Bitemporal columns are lineage, not benefit content, and do not affect the grain: observed_period/effective_period_start just restate Jan 1 of report_year; asserted_at/cms_vintage_sequence/parse_revision/source_url/sha256_content_hash describe Vlada's load (two batches, 2026-05-16 and 2026-05-20) and each plan-year-quarter is asserted exactly once. Duplicate legacy columns also exist (e.g. pbp_b_8a_ded_amt with an extra underscore vs pbp_b8a_ded_amt) and are almost entirely NULL — prefer the itemized dmc/lab/drs/tmc amount and coins_pct fields for real cost-share values.

| column | type | meaning |
|---|---|---|
| contract_id | string | CMS MA contract number (e.g. H0022, H0028). First key component; one insurer/org holds many contracts. Always populated. |
| plan_id | string | Plan number within the contract (e.g. '001','004'), zero-padded 3-char string. Second key component. |
| segment_id | string | Plan segment within the plan (service-area segment), zero-padded ('0','1','2'); 27 distinct values. Third key component — a plan can have multiple priced segments. Defaults to '0' when not segmented. |
| version | double | CMS PBP submission/resubmission version number (0-27, right-skewed; most rows 1-6). Functionally dependent on the grain (adding it does not change the distinct count). version=0 corresponds exactly to the 2001-2006 vintage where it was not populated. NOT a snapshot/current flag. |
| report_year | double | Benefit/contract year the row describes (double, 2001-2026). Fourth key component. Equals the year of effective_period_start/observed_period. |
| quarter | double | CMS release quarter within the report_year (1-4). Fifth and most important key component: it is the SNAPSHOT dimension — the same plan-year is re-filed each quarter, so quarter distinguishes otherwise-identical plan rows. Not all quarters exist every year. |
| bid_id | string | CMS bid identifier; equals contract_id//'_'//plan_id//'_'//segment_id for all 2007+ rows. NULL for the 8,316 oldest rows (2001-2006), which predate this field. Derivable, not an independent key. |
| orgtype | string | CMS organization-type code (string, '01'-'14'). '01' dominates (177,737 rows, Local CCP/HMO); others e.g. '08','04','11','06','05'. Plan-level attribute, constant within a plan-year. |
| pbp_a_ben_cov | string | Part A benefit coverage indicator carried from PBP Section A. '1'=plan provides Part A benefits (196,773), '2'=does not / Part B-only (4,373), NULL (342). Context flag, not B-8 specific. |
| pbp_a_plan_type | string | CMS plan-type code from Section A (string). '01'=HMO dominant (101,510), '04'=Local PPO (55,909), '02', '20'=PDP-like, etc. Describes the plan, not a B-8 benefit. |
| pbp_b8a_auth | string |  |
| pbp_b8a_auth_pos | string |  |
| pbp_b8a_auth_yn | string |  |
| pbp_b8a_coins_cov_cmc | string |  |
| pbp_b8a_coins_cov_dmc | string |  |
| pbp_b8a_coins_cov_lab | string |  |
| pbp_b8a_coins_cov_pos | string |  |
| pbp_b8a_coins_cov_tmc | string |  |
| pbp_b8a_coins_ehc | string |  |
| pbp_b8a_coins_pct_cmc | double |  |
| pbp_b8a_coins_pct_cmc_max | double |  |
| pbp_b8a_coins_pct_dmc | double |  |
| pbp_b8a_coins_pct_dmc_max | double |  |
| pbp_b8a_coins_pct_lab | double |  |
| pbp_b8a_coins_pct_lab_max | double |  |
| pbp_b8a_coins_pct_pos | double |  |
| pbp_b8a_coins_pct_tmc | double |  |
| pbp_b8a_coins_pct_tmc_max | double |  |
| pbp_b8a_coins_pctmax_pos | double |  |
| pbp_b8a_coins_yesno | string |  |
| pbp_b8a_coins_yesno_pos | string |  |
| pbp_b8a_coins_yn | string |  |
| pbp_b8a_copay_amt_pos | double |  |
| pbp_b8a_copay_amtmax_pos | double |  |
| pbp_b8a_copay_ehc | string |  |
| pbp_b8a_copay_max_cmc_amt | double |  |
| pbp_b8a_copay_max_dmc_amt | double |  |
| pbp_b8a_copay_max_tmc_amt | double |  |
| pbp_b8a_copay_max_yn | string |  |
| pbp_b8a_copay_min_cmc_amt | double |  |
| pbp_b8a_copay_min_dmc_amt | double |  |
| pbp_b8a_copay_min_tmc_amt | double |  |
| pbp_b8a_copay_yesno | string |  |
| pbp_b8a_copay_yesno_pos | string |  |
| pbp_b8a_copay_yn | string |  |
| pbp_b8a_cost_share | string |  |
| pbp_b8a_cost_share_coins_max | double |  |
| pbp_b8a_cost_share_coins_min | double |  |
| pbp_b8a_cost_share_coins_yn | string |  |
| pbp_b8a_cost_share_copay_max | double |  |
| pbp_b8a_cost_share_copay_min | double |  |
| pbp_b8a_cost_share_copay_yn | string |  |
| pbp_b8a_cost_share_yesno | string |  |
| pbp_b8a_cost_share_yn | string |  |
| pbp_b8a_ded_amt | double |  |
| pbp_b8a_ded_amt_pos | double |  |
| pbp_b8a_ded_yesno_pos | string |  |
| pbp_b8a_ded_yn | string |  |
| pbp_b8a_lab_copay_amt | double |  |
| pbp_b8a_lab_copay_amt_max | double |  |
| pbp_b8a_maxenr_amt | double |  |
| pbp_b8a_maxenr_amt_pos | double |  |
| pbp_b8a_maxenr_per | string |  |
| pbp_b8a_maxenr_per_d | string |  |
| pbp_b8a_maxenr_yesno | string |  |
| pbp_b8a_maxenr_yn | string |  |
| pbp_b8a_maxenr_yn_pos | string |  |
| pbp_b8a_maxplan_yesno_pos | string |  |
| pbp_b8a_maxpln_amt_pos | double |  |
| pbp_b8a_maxpln_cov_pos | string |  |
| pbp_b8a_maxpln_per_pos | string |  |
| pbp_b8a_refer_yn | string |  |
| pbp_b8a_sep_cost_yn | string |  |
| pbp_b8b_auth | string |  |
| pbp_b8b_auth_pos | string |  |
| pbp_b8b_auth_yn | string |  |
| pbp_b8b_coins_cov_mc | string |  |
| pbp_b8b_coins_cov_pos | string |  |
| pbp_b8b_coins_cov_tmc | string |  |
| pbp_b8b_coins_ehc | string |  |
| pbp_b8b_coins_pct_cmc | double |  |
| pbp_b8b_coins_pct_cmc_max | double |  |
| pbp_b8b_coins_pct_drs | double |  |
| pbp_b8b_coins_pct_drs_cov | string |  |
| pbp_b8b_coins_pct_drs_max | double |  |
| pbp_b8b_coins_pct_pos | double |  |
| pbp_b8b_coins_pct_tmc | double |  |
| pbp_b8b_coins_pct_tmc_max | double |  |
| pbp_b8b_coins_pctmax_pos | double |  |
| pbp_b8b_coins_yesno | string |  |
| pbp_b8b_coins_yesno_pos | string |  |
| pbp_b8b_coins_yn | string |  |
| pbp_b8b_copay_amt_drs | double |  |
| pbp_b8b_copay_amt_drs_max | double |  |
| pbp_b8b_copay_amt_pos | double |  |
| pbp_b8b_copay_amt_tmc | double |  |
| pbp_b8b_copay_amt_tmc_max | double |  |
| pbp_b8b_copay_amtmax_pos | double |  |
| pbp_b8b_copay_ehc | string |  |
| pbp_b8b_copay_max_yn | string |  |
| pbp_b8b_copay_mc_amt | double |  |
| pbp_b8b_copay_mc_amt_max | double |  |
| pbp_b8b_copay_yesno | string |  |
| pbp_b8b_copay_yesno_pos | string |  |
| pbp_b8b_copay_yn | string |  |
| pbp_b8b_cost_share | string |  |
| pbp_b8b_cost_share_coins_max | double |  |
| pbp_b8b_cost_share_coins_min | double |  |
| pbp_b8b_cost_share_coins_yn | string |  |
| pbp_b8b_cost_share_copay_max | double |  |
| pbp_b8b_cost_share_copay_min | double |  |
| pbp_b8b_cost_share_copay_yn | string |  |
| pbp_b8b_ded_amt | double |  |
| pbp_b8b_ded_amt_pos | double |  |
| pbp_b8b_ded_yesno | string |  |
| pbp_b8b_ded_yesno_pos | string |  |
| pbp_b8b_ded_yn | string |  |
| pbp_b8b_maxenr_amt | double |  |
| pbp_b8b_maxenr_amt_pos | double |  |
| pbp_b8b_maxenr_per | string |  |
| pbp_b8b_maxenr_per_d | string |  |
| pbp_b8b_maxenr_yesno | string |  |
| pbp_b8b_maxenr_yn | string |  |
| pbp_b8b_maxenr_yn_pos | string |  |
| pbp_b8b_maxplan_yesno_pos | string |  |
| pbp_b8b_maxpln_amt_pos | double |  |
| pbp_b8b_maxpln_cov_pos | string |  |
| pbp_b8b_maxpln_per_pos | string |  |
| pbp_b8b_refer_yn | string |  |
| pbp_b8b_sep_cost_yn | string |  |
| pbp_b_8a_ded_amt | double |  |
| pbp_b_8a_ded_yesno | string |  |
| observed_period | date | Vlada bitemporal field: the period the data is observed-as-of. Always Jan 1 of report_year (e.g. 2018-01-01). Equals effective_period_start here; redundant with report_year. |
| asserted_at | date | Vlada ingest/assertion date (when this record was loaded into the substrate): two batches observed, 2026-05-16 (100,054 rows) and 2026-05-20 (101,434 rows). Does NOT split the grain — each plan-year-quarter is asserted in exactly one batch. Use it as load lineage, not a benefit attribute. |
| effective_period_start | date |  |
| effective_period_end | date |  |
| cms_vintage_sequence | int | Which CMS source-file vintage the row came from (int 1-4). Provenance/lineage, correlates with asserted_at batch (batch 1 = vintage 1; batch 2 = vintages 2-4). |
| parse_revision | int | Parser version that produced the row (int, observed 1-2). Lineage only — despite matching an 'is_*'/version-like name search it is NOT a current-record flag. |
| parser_artifact_hash | string | SHA-256 of the parser artifact that produced the row. Pure provenance. |
| source_url | string | CMS download URL of the originating PBP PUF zip (e.g. .../pbp-pufs/pbp-benefits-2018-q2.zip). Encodes the year+quarter of the source file; ~24+16 distinct files across the two batches. Provenance. |
| sha256_content_hash | string | SHA-256 of the source file content. Provenance / dedup integrity, constant within a source file. |
| pbp_b8a_auth / pbp_b8a_auth_pos / pbp_b8b_auth / pbp_b8b_auth_pos |  | PACKED prior-authorization flag strings (e.g. '01000','00111') — each character position is a yes/no flag for whether prior auth is required for a specific service sub-type within the section. NOT a single scalar; must be decoded position-by-position against the CMS PBP B-8 layout. '_pos' variants are the point-of-service / OON counterpart. |
| pbp_b8a_auth_yn / pbp_b8b_auth_yn |  | Simple yes/no roll-up: '1'=Yes (auth required for some service), '2'=No, NULL=not asked for that plan-type/year. (b8a_auth_yn: 121,715 Yes / 18,014 No / 61,759 NULL.) |
| pbp_b8a_refer_yn / pbp_b8b_refer_yn |  | Whether a referral is required for the section's services. '1'=Yes, '2'=No (CMS 1/2 coding). |
| pbp_b8a_coins_yn / pbp_b8a_copay_yn / pbp_b8a_ded_yn (and pbp_b8b_* equivalents) |  | Does the plan charge coinsurance / copay / deductible for this section. CMS coding '1'=Yes, '2'=No, NULL=not applicable. coins_yn and copay_yn are near-mirror-images (a plan usually picks copay OR coinsurance). |
| pbp_b8a_*_ehc / pbp_b8b_*_ehc (e.g. pbp_b8a_coins_ehc, pbp_b8b_copay_ehc) |  | PACKED 'enrollee health-care' indicator strings: b8a = 2 chars (e.g. '11','01','10'), b8b = 3 chars (e.g. '111','110','011'). Each position is a 1/0 flag for whether the cost-share applies to a specific service sub-type (lab / diagnostic / radiology component). Decode by position, do not read as a number. |
| pbp_b8a_lab_copay_amt / _max |  | Member copay dollar amount (and its max) for LAB tests under B-8a. Real $: min 0, observed up to tens of dollars. ~96K populated. _max is the upper bound when the plan files a range. |
| pbp_b8a_copay_min_dmc_amt / pbp_b8a_copay_max_dmc_amt |  | Min/max member copay $ for DIAGNOSTIC tests/procedures (dmc) under B-8a. ~99K populated; range $0-$999, median max ~$37. The headline B-8a diagnostic copay. |
| pbp_b8a_copay_min_cmc_amt / _max_cmc_amt, pbp_b8a_copay_min_tmc_amt / _max_tmc_amt |  | Min/max copay $ for clinical (cmc, rare ~1K) and therapeutic-monitoring (tmc, ~7K) sub-services under B-8a. Sparsely populated — most plans don't itemize these. |
| pbp_b8a_coins_pct_dmc / _lab / _cmc / _tmc (and *_max, *_pct_pos) |  | Coinsurance PERCENTAGES the member pays for the dmc/lab/cmc/tmc sub-services under B-8a (double, 0-50, commonly 20). '_pos' = point-of-service/OON percentage. NULL when the plan charges copay instead. |
| pbp_b8b_copay_amt_drs / _drs_max, pbp_b8b_coins_pct_drs / _drs_max |  | Member cost share for DRS = advanced Diagnostic Radiology Services (MRI/CT/PET) under B-8b. copay_amt_drs ~99K populated, $0-$450 (median ~$4 because many plans use coinsurance); coins_pct_drs is the percentage variant. THE advanced-imaging member-cost field. |
| pbp_b8b_copay_mc_amt / _max, pbp_b8b_coins_pct_cmc / _max |  | Cost share for general outpatient diagnostic radiology / medical radiology (mc/cmc) under B-8b. copay_mc_amt is the most-populated B-8b amount (~108K). |
| pbp_b8b_copay_amt_tmc / _max, pbp_b8b_coins_pct_tmc / _max |  | Cost share for THERAPEUTIC radiology (tmc) under B-8b. coins_pct_tmc median 20% (range 0-50%); ~55K rows populated. Therapeutic (treatment) vs diagnostic radiology distinction lives here. |
| pbp_b8a_ded_amt / pbp_b8b_ded_amt / pbp_b_8a_ded_amt (and *_yn, *_yesno, *_pos) |  | Service-specific deductible dollar amount for the section and its yes/no presence flag. Mostly NULL (most plans have no service-specific B-8 deductible). NOTE pbp_b_8a_ded_amt / pbp_b_8a_ded_yesno (extra underscore) are legacy duplicate columns from an older CMS layout — nearly always NULL. |
| pbp_b8a_maxenr_amt / _per / _per_d / _yn (and pbp_b8b_* equivalents) |  | Service-specific MAXIMUM enrollee out-of-pocket: amount, period code (_per), and free-text period DESCRIPTION (_per_d, e.g. 'The maximum enrollee out-of-pocket cost share is per day.' with inconsistent wording across plans), plus yes/no flag. Sparsely populated. |
| pbp_b8a_maxpln_amt_pos / _cov_pos / _per_pos / pbp_b8a_maxplan_yesno_pos (and b8b) |  | Plan-level maximum-cost and coverage for the point-of-service / out-of-network side of the section. The two maxplan_yesno_pos columns appear in the profiler's reported key but are NOT needed for uniqueness — they are functionally dependent attributes, mostly NULL. |
| pbp_b8a_cost_share* / pbp_b8b_cost_share* (cost_share, _coins_min/_max/_yn, _copay_min/_max/_yn, _yesno, _yn) |  | Generic combined cost-share min/max and yes/no fields (a later CMS layout's roll-up of the copay/coins detail). Largely NULL in this table — the itemized dmc/lab/drs/tmc fields above carry the real values. |
| pbp_b8a_sep_cost_yn / pbp_b8b_sep_cost_yn |  | Whether a SEPARATE cost share applies (vs bundled into another benefit). CMS yes/no, mostly NULL. |
| effective_period_start / effective_period_end |  | The benefit year window the row's terms apply to: start = Jan 1 of report_year, end = Dec 31 of report_year. effective_period_start is the table's primary time column (2001-01-01 to 2026-01-01, annual). |

Tools that read it: get_pbp_benefit

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