# MA pbp section c pos

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

Section C POS: Point-of-service cost-share detail. Coverage: All years (plans with POS only).

**Grain.** One row per MA plan benefit-group per quarterly CMS PBP snapshot: contract_id x plan_id x segment_id x pbp_c_pos_outpt_group_num_id x report_year x quarter. Verified: SELECT DISTINCT on exactly those 6 columns = 70,349 = the full row_count. A "group" is a cost-share tier the plan defines for its POS outpatient benefit (Group 1, Group 2, ...); most plans have 1-2 groups, some up to 20+. NOTE: this is the physical/storage grain — analytically each plan-group is republished IDENTICALLY across the quarters of a year (e.g. 2023 Q1=Q2=Q3=Q4, values unchanged), so the true annual benefit grain is contract_id x plan_id x segment_id x group_num_id x report_year (3,089 distinct plan-groups in 2023 vs 12,353 raw rows).

**How to use it.** Get the member cost-share for a specific MA plan's POS outpatient benefit for a given year, deduped to one snapshot. Example: SELECT pbp_c_pos_outpt_group_num_id, pbp_c_pos_group_lbl, pbp_c_pos_outpt_coins_yn, pbp_c_pos_outpt_coins_min_pct, pbp_c_pos_outpt_copay_yn, pbp_c_pos_outpt_copay_min_amt, pbp_c_pos_outpt_mc_bencats FROM medicare_silver.pbp_section_c_pos WHERE contract_id='H0174' AND plan_id='005' AND segment_id='0' AND report_year=2019 AND quarter=4 ORDER BY pbp_c_pos_outpt_group_num_id; -- returns each cost-share group's coinsurance %/copay $ and the benefit-category codes it applies to, for that plan-year (filter quarter to avoid the 4x quarterly-republication duplication).

**Traps.**
- QUARTER IS A DUPLICATION AXIS, NOT NEW DATA. For 2018+ the same plan-group is republished IDENTICALLY across Q1-Q4 (2023: 12,353 raw rows = 4 x 3,089 distinct plan-groups; benefit values do NOT differ across quarters). Any benefit analysis MUST collapse to one quarter per year (or group by report_year only) or you will 2-4x overcount plans. There is NO is_current column to do this for you.
- PROFILER GRAIN IS A BLOATED SUPERSET. The profiler's 14-column 'verified unique' key wrongly includes VALUE columns (pbp_c_pos_outpt_maxplan_amt/_cov/_per/_per_d/_yn) and the redundant bid_id/plan_type. The true MINIMAL grain is just contract_id x plan_id x segment_id x pbp_c_pos_outpt_group_num_id x report_year x quarter (6 cols = 70,349). pbp_c_pos_outpt_maxplan_per_d is in that profiler key yet is 100% NULL.
- NULL VALUE COLUMNS ARE MEANINGFUL = 'cost-share type does not apply'. coins_min/max_pct is NULL exactly when coins_yn<>'1'; copay_*_amt NULL when copay_yn<>'1'; deduct_amt NULL when deduct_yn<>'1'; maxplan_amt NULL when maxplan_yn<>'1' (all verified, 0 violations). Always gate on the matching _yn='1' flag (1=Yes, 2=No) before reading a dollar/percent value; do not treat NULL as $0.
- coins_*_pct are PERCENTAGES (0-100), copay_*_amt / deduct_amt / maxplan_amt are DOLLARS. maxplan_amt is a PLAN-PAID benefit LIMIT (what the plan covers up to), not a member out-of-pocket cost. A single group can carry BOTH a copay and a coinsurance simultaneously (2,247 rows), so member cost is not one-or-the-other.
- asserted_at / parse_revision / parser_artifact_hash are VLADA ETL metadata (only 2 ingest dates: 2026-05-16 & 2026-05-20), NOT CMS dates. cms_vintage_sequence tracks CMS quarterly re-releases (1-4), also not an is_current flag. For real CMS provenance use source_url + sha256_content_hash (34 distinct, one per snapshot). bid_id is just contract_id_plan_id_segment_id (redundant). pbp_c_pos_group_lbl is free-text and ~50% NULL — never key/join on it.
- This is the POS (Point-of-Service) slice only — one of many PBP Section C benefit tables (sibling pbp_section_c_* tables cover other outpatient/inpatient/professional benefit categories). bencat_bens / mc_bencats / nmc_bencats are CMS PBP benefit-category codes (semicolon-delimited code lists like '7b;8a1;14e1'), not service descriptions; the empty-string bencat_bens is a pre-2013 vintage gap, not a real category.

| column | type | meaning |
|---|---|---|
| contract_id | string | CMS Medicare Advantage contract ID (e.g. H0174). 404 distinct. First component of the plan identity; an org's MA contract. |
| plan_id | string | Plan number within the contract (e.g. '005', zero-padded 3-char string). 288 distinct. contract_id+plan_id+segment_id = the unique benefit package. |
| segment_id | string | Plan segment / service-area sub-division ('0' for the base plan, '1'..'10' for segmented plans). 11 distinct; '0' covers 51,600 of 70,349 rows. Part of the plan key. |
| pbp_c_pos_outpt_group_num_id | string | Cost-share GROUP number the plan defines for its POS outpatient benefit ('1','2','3',...). THE row-level discriminator that makes each plan multi-row. Values 1-20+. Each group bundles a set of service benefit-categories that share one cost-share design. |
| pbp_c_pos_oupt_bencat_bens | string | Benefit-category-set code for the group: '01' (37,623 rows), '10' (16,289), '11' (8,691), or '' empty. Empty string is concentrated in early vintages 2007-2012 (column not populated then) — empty = 'not coded in that vintage', not a real category. Functionally dependent on group_num_id (adding it to the key does not change the grain). |
| version | double | CMS PBP bid version number (double, 1.0-12.0+) — the plan's bid-submission revision; higher = later refile. Descriptive, NOT part of the grain (only the latest captured version per quarter is present). |
| report_year | double | CMS PBP benefit/contract year (double, 2007-2026, 20 distinct). The primary time dimension; equals the calendar year the benefit design is in effect. |
| quarter | double | CMS quarterly release within the report_year (1-4). PART OF THE PHYSICAL GRAIN but a duplication axis: 2007-2017 have only Q1; 2018+ have multiple quarters whose benefit values are IDENTICAL. Some years skip quarters (2020 has no Q3, 2024 no Q2, 2025/2026 only Q1). |
| bid_id | string | Convenience concatenation contract_id + '_' + plan_id + '_' + segment_id (e.g. 'H0174_005_0'). 100% derivable (0 mismatches) — redundant, do not treat as independent key. |
| orgtype | string | CMS organization-type code: '01' (Local CCP, 69,926 rows) dominant, '05' (408), '11' (15). Identifies the MA org structure. |
| pbp_a_ben_cov | string | Section-A flag for whether the plan provides this (Part-A-style) benefit coverage: '1'=Yes (70,219), '2'=No (130). Plan-level attribute repeated on every group row. |
| pbp_a_plan_type | string | CMS plan-type code: '02' dominant (69,783, the HMO-POS/local plan type for this POS table), plus '37','05','04','06','39','31','01','49','10'. Plan-level attribute. |
| pbp_c_pos_group_lbl | string | Free-text label for the group ('Group 1', 'Group 2', or descriptive like '50% coinsurance','20% coinsurance'). OFTEN NULL (~half the rows) and non-standard — display-only, NOT a reliable key or join field. |
| pbp_c_pos_outpt_bendesc_cats | string | Free-text/coded benefit-description categories for the group. Sparse: 7,656 non-null, 966 distinct. Descriptive enrichment of which services the group covers. |
| pbp_c_pos_outpt_coins_cov | string | Coinsurance coverage-scope code. Very sparse: 1,341 non-null, 4 distinct values. Qualifies what the coinsurance applies to. |
| pbp_c_pos_outpt_coins_max_pct | double | Maximum coinsurance PERCENT (0-100, avg 27.8%). Same population rule as min. min=max when the group has a single flat coinsurance rate. |
| pbp_c_pos_outpt_coins_min_pct | double | Minimum coinsurance PERCENT the member pays (0-100, avg 21.4%). Populated iff coins_yn='1' (exactly 31,013 non-null). A COST field. NULL = no coinsurance applies. |
| pbp_c_pos_outpt_coins_yn | string | Does this group charge COINSURANCE? '1'=Yes (31,013), '2'=No (39,312), null (24). When '1', coins_min/max_pct are populated; when '2', they are NULL. |
| pbp_c_pos_outpt_copay_max_amt | double | Maximum copay DOLLARS (0-9999.99, avg $79). Same population rule. A group can have BOTH a copay and a coinsurance (2,247 rows have both yn='1'); 8,667 rows have neither (full coverage / $0 / 'see other'). |
| pbp_c_pos_outpt_copay_min_amt | double | Minimum copay DOLLARS the member pays (0-699, avg $62). Populated iff copay_yn='1' (32,892 non-null). A COST field. NULL = no copay. |
| pbp_c_pos_outpt_copay_yn | string | Does this group charge a COPAY? '1'=Yes (32,892), '2'=No (37,433), null (24). When '1', copay_min/max_amt populated; when '2' they are NULL (verified 0 violations). |
| pbp_c_pos_outpt_cost_share | string | Cost-share-structure enum: '1'/'2'/'3' (3 distinct), only 2,195 non-null. Encodes the cost-share arrangement type for the group; sparse, mostly NULL. |
| pbp_c_pos_outpt_cs_coins_max | double | Combined-cost-share coinsurance max PERCENT (20-50). Only 93 non-null. |
| pbp_c_pos_outpt_cs_coins_min | double | Combined-cost-share coinsurance min PERCENT (0-50). Only 93 non-null. Edge-case cost field. |
| pbp_c_pos_outpt_cs_coins_yn | string | Secondary/combined-cost-share coinsurance flag. VERY sparse: null on 70,083 of 70,349 rows; '2'=173, '1'=93. Used only for rare combined copay+coinsurance designs. |
| pbp_c_pos_outpt_cs_copay_max | double | Combined-cost-share copay max DOLLARS (20-70). Only 176 non-null. |
| pbp_c_pos_outpt_cs_copay_min | double | Combined-cost-share copay min DOLLARS (0-45). Only 176 non-null. Edge-case cost field. |
| pbp_c_pos_outpt_cs_copay_yn | string | Secondary/combined-cost-share copay flag. VERY sparse: null on 70,083 rows; '1'=176, '2'=90. |
| pbp_c_pos_outpt_deduct_amt | double | Deductible DOLLARS (0-5000, avg $1,080). Populated iff deduct_yn='1' (216 non-null). A COST field; NULL = no deductible. |
| pbp_c_pos_outpt_deduct_yn | string | Does this group have a DEDUCTIBLE? '2'=No (69,443), '1'=Yes (216), null (690). Deductibles are rare for POS outpatient. |
| pbp_c_pos_outpt_maxplan_amt | double | Plan-coverage-maximum DOLLAR amount the PLAN will pay (15-500,000, avg $2,109). Populated iff maxplan_yn='1' (5,863 non-null). A benefit-LIMIT field (not a member cost). NULL = no plan max. NOTE: profiler wrongly included this in the grain key — it is a VALUE, not a key. |
| pbp_c_pos_outpt_maxplan_cov | string | Plan-maximum coverage-scope code ('1','2','6'). EXTREMELY sparse: only 69 non-null. Profiler listed it in the key but it is near-empty. |
| pbp_c_pos_outpt_maxplan_per | string | Period the plan-maximum applies over (code: '3' dominant=4,982, plus '1','2','4','5','6','7'). Populated with maxplan_yn='1'. '3' is the most common period basis (per-year/annual). |
| pbp_c_pos_outpt_maxplan_per_d | string | Plan-maximum period detail. 100% NULL (0 non-null across all 70,349 rows) — a completely empty column. TRAP: profiler listed it as a grain key though it carries no data. |
| pbp_c_pos_outpt_maxplan_yn | string | Does the plan cap its own coverage (a plan-coverage maximum / benefit limit) for this group? '2'=No (63,796), '1'=Yes (5,863), null (690). |
| pbp_c_pos_outpt_mc_bencats | string | Semicolon-delimited list of CMS Medicare-Covered benefit-category codes this group's cost-share applies to (e.g. '7b;7d;7f;8a1;...'). 46,314 non-null. These codes (3-1, 7a, 8a1, 14e1...) map to specific outpatient service types in the CMS PBP benefit taxonomy. |
| pbp_c_pos_outpt_nmc_bencats | string | Semicolon-delimited list of Non-Medicare-Covered (supplemental) benefit-category codes for the group. 24,980 non-null, 444 distinct lists. Same delimited code-list format as mc_bencats. |
| observed_period | date | Vlada normalized observation period = Jan 1 of report_year (date). Equivalent to report_year; derived, redundant with effective_period_start. |
| asserted_at | date | Vlada INGEST/parse date (date), only 2 values: 2026-05-16 (33,681 rows, parse_revision 1) and 2026-05-20 (36,668 rows, parse_revision 2). This is WHEN Vlada parsed the file, NOT a CMS provenance date — do not use as a benefit-effective date. |
| effective_period_start | date | Benefit effective start = Jan 1 of report_year (date, 2007-01-01..2026-01-01). The primary temporal anchor; 20 distinct annual values. |
| effective_period_end | date | Benefit effective end = Dec 31 of report_year (date). Together with start, bounds the plan year. |
| cms_vintage_sequence | int | Sequence number (int 1-4) of the CMS re-release within a report_year, tracking quarterly republications. NOT an is_current flag — there is no is_current column on this table. |
| parse_revision | int | Vlada parser revision (int): 1 (33,681 rows, parsed 2026-05-16) or 2 (36,668 rows, parsed 2026-05-20). Load-tracking metadata. |
| parser_artifact_hash | string | SHA-256 of the parser code artifact that produced the row (provenance/reproducibility of the ETL, not of the source data). |
| source_url | string | CMS source URL for the PBP zip the row came from (e.g. .../pbp-benefits-2019-q4.zip). Exactly 34 distinct = one per (report_year,quarter) snapshot. Lets you trace any value to the official CMS file. |
| sha256_content_hash | string | SHA-256 of the source file content. Exactly 34 distinct (1:1 with source_url and with the 34 snapshots) — content-integrity / dedup key for the underlying CMS download. |

Tools that read it: get_pbp_benefit

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