diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb2d..510b169f218 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: minor + changes: + added: + - Reconciled Medicaid work requirement reform. diff --git a/policyengine_us/parameters/gov/contrib/reconciliation/medicaid_work_requirement/age_range.yaml b/policyengine_us/parameters/gov/contrib/reconciliation/medicaid_work_requirement/age_range.yaml new file mode 100644 index 00000000000..8fc3edfa0b7 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/reconciliation/medicaid_work_requirement/age_range.yaml @@ -0,0 +1,24 @@ +description: The Committee on Ways and Means proposed to require individuals within these age brackets to meet Medicaid work requirements. +metadata: + threshold_unit: year + amount_unit: bool + period: year + type: single_amount + label: Reconciliation Medicaid work requirements age threshold + reference: + - title: COMMITTEE ON WAYS AND MEANS, THE ONE, BIG, BEAUTIFUL BILL + href: https://budget.house.gov/imo/media/doc/one_big_beautiful_bill_act_-_full_bill_text.pdf#page=376 + +brackets: + - threshold: + 2029-01-01: 0 + amount: + 2029-01-01: false + - threshold: + 2029-01-01: 19 + amount: + 2029-01-01: true + - threshold: + 2029-01-01: 65 + amount: + 2029-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/reconciliation/medicaid_work_requirement/in_effect.yaml b/policyengine_us/parameters/gov/contrib/reconciliation/medicaid_work_requirement/in_effect.yaml new file mode 100644 index 00000000000..2752ca6bf1d --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/reconciliation/medicaid_work_requirement/in_effect.yaml @@ -0,0 +1,12 @@ +description: The Committee on Ways and Means proposed to limit Medicaid to filers who meet work requirements, which comes in effect if this is true. + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: Reconciliation Medicaid with work requirement in effect + reference: + - title: COMMITTEE ON WAYS AND MEANS, THE ONE, BIG, BEAUTIFUL BILL + href: https://budget.house.gov/imo/media/doc/one_big_beautiful_bill_act_-_full_bill_text.pdf#page=364 diff --git a/policyengine_us/parameters/gov/contrib/reconciliation/medicaid_work_requirement/monthly_hours_threshold.yaml b/policyengine_us/parameters/gov/contrib/reconciliation/medicaid_work_requirement/monthly_hours_threshold.yaml new file mode 100644 index 00000000000..6642e328d7b --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/reconciliation/medicaid_work_requirement/monthly_hours_threshold.yaml @@ -0,0 +1,12 @@ +description: The Committee on Ways and Means proposed to limit Medicaid to individuals working more than this number of monthly hours. + +values: + 2029-01-01: 80 + +metadata: + unit: hours + label: Reconciliation Medicaid work requirement monthly hours threshold + period: month + reference: + - title: COMMITTEE ON WAYS AND MEANS, THE ONE, BIG, BEAUTIFUL BILL + href: https://budget.house.gov/imo/media/doc/one_big_beautiful_bill_act_-_full_bill_text.pdf#page=364 diff --git a/policyengine_us/reforms/reconciliation/__init__.py b/policyengine_us/reforms/reconciliation/__init__.py index 8b7c33a2958..c62cb2e8329 100644 --- a/policyengine_us/reforms/reconciliation/__init__.py +++ b/policyengine_us/reforms/reconciliation/__init__.py @@ -28,3 +28,6 @@ from .reconciliation_cdcc import ( create_reconciliation_cdcc_reform, ) +from .reconciled_medicaid_work_requirement import ( + create_reconciled_medicaid_work_requirement_reform, +) diff --git a/policyengine_us/reforms/reconciliation/reconciled_medicaid_work_requirement.py b/policyengine_us/reforms/reconciliation/reconciled_medicaid_work_requirement.py new file mode 100644 index 00000000000..12b9982a536 --- /dev/null +++ b/policyengine_us/reforms/reconciliation/reconciled_medicaid_work_requirement.py @@ -0,0 +1,131 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ +from policyengine_core.periods import instant +import numpy as np + + +def create_reconciled_medicaid_work_requirement() -> Reform: + class medicaid_work_requirement_eligible(Variable): + value_type = bool + entity = Person + label = "Eligible person for Medicaid via work requirement" + definition_period = YEAR + reference = "https://budget.house.gov/imo/media/doc/one_big_beautiful_bill_act_-_full_bill_text.pdf#page=364" + + def formula(person, period, parameters): + p = parameters( + period + ).gov.contrib.reconciliation.medicaid_work_requirement + # Works no less than 80 hours p.364 (2)(A) + monthly_hours_worked = person("monthly_hours_worked", period) + meets_monthly_work_hours = ( + monthly_hours_worked >= p.monthly_hours_threshold + ) + # The individual is enrolled in an educational program at least half-time. p.364 (2)(D) + is_full_time_student = person("is_full_time_student", period) + # pregnant or postpartum medical assistance p.365 (3)(A)(i)(II)(bb) + is_pregnant = person("is_pregnant", period) + # Has attained age of 19 and is under 65 is require to work p.376 (bb) + age = person("age", period) + work_required_age = p.age_range.calc(age) + # parent of a disabled person p.377 (III) + is_parent = person("is_parent", period) + is_disabled = person("is_disabled", period) + is_dependent = person("is_tax_unit_dependent", period) + eligible_parent = is_parent & person.tax_unit.any( + is_dependent & is_disabled + ) + # veteran and is_permanently_and_totally_disabled p.377 (IV) + is_veteran = person("is_veteran", period) + is_permanently_and_totally_disabled = person( + "is_permanently_and_totally_disabled", period + ) + eligible_veteran = is_veteran & is_permanently_and_totally_disabled + # blind or disabled or is_incapable_of_self_care p.377 (V) + is_blind = person("is_blind", period) + is_incapable_of_self_care = person( + "is_incapable_of_self_care", period + ) + eligible_disabled = ( + is_blind | is_disabled | is_incapable_of_self_care + ) + exempted_from_work = ( + is_full_time_student + | is_pregnant + | eligible_parent + | eligible_veteran + | eligible_disabled + ) + return where( + work_required_age, + meets_monthly_work_hours | exempted_from_work, + True, + ) + + class is_medicaid_eligible(Variable): + value_type = bool + entity = Person + label = "Eligible for Medicaid" + definition_period = YEAR + reference = ( + "https://www.law.cornell.edu/uscode/text/42/1396a#a_10" + "https://www.kff.org/racial-equity-and-health-policy/fact-sheet/key-facts-on-health-coverage-of-immigrants" + ) + + def formula(person, period, parameters): + category = person("medicaid_category", period) + categorically_eligible = category != category.possible_values.NONE + istatus = person("immigration_status", period) + undocumented = istatus == istatus.possible_values.UNDOCUMENTED + state = person.household("state_code_str", period) + p = parameters(period).gov.hhs.medicaid.eligibility + state_covers_undocumented = p.undocumented_immigrant[state].astype( + bool + ) + immigration_status_eligible = ( + ~undocumented | undocumented & state_covers_undocumented + ) + work_requirement_eligible = person( + "medicaid_work_requirement_eligible", period + ) + ca_ffyp_eligible = person("ca_ffyp_eligible", period) + return ( + categorically_eligible + & immigration_status_eligible + & work_requirement_eligible + ) | ca_ffyp_eligible + + class reform(Reform): + def apply(self): + self.update_variable(medicaid_work_requirement_eligible) + self.update_variable(is_medicaid_eligible) + + return reform + + +def create_reconciled_medicaid_work_requirement_reform( + parameters, period, bypass: bool = False +): + if bypass: + return create_reconciled_medicaid_work_requirement() + + p = parameters.gov.contrib.reconciliation.medicaid_work_requirement + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_reconciled_medicaid_work_requirement() + else: + return None + + +reconciled_medicaid_work_requirement = ( + create_reconciled_medicaid_work_requirement_reform(None, None, bypass=True) +) diff --git a/policyengine_us/reforms/reforms.py b/policyengine_us/reforms/reforms.py index 977bd2f2106..b038fa02999 100644 --- a/policyengine_us/reforms/reforms.py +++ b/policyengine_us/reforms/reforms.py @@ -106,6 +106,7 @@ create_aca_ptc_immigration_status_reform, create_reconciliation_qbid_with_floor_reform, create_reconciliation_cdcc_reform, + create_reconciled_medicaid_work_requirement_reform, ) from .additional_tax_bracket import ( create_additional_tax_bracket_reform, @@ -257,6 +258,9 @@ def create_structural_reforms_from_parameters(parameters, period): additional_tax_bracket = create_additional_tax_bracket_reform( parameters, period ) + reconciled_medicaid_work_requirement = ( + create_reconciled_medicaid_work_requirement_reform(parameters, period) + ) reforms = [ afa_reform, @@ -311,6 +315,7 @@ def create_structural_reforms_from_parameters(parameters, period): ctc_additional_bracket, reconciliation_cdcc, additional_tax_bracket, + reconciled_medicaid_work_requirement, ] reforms = tuple(filter(lambda x: x is not None, reforms)) diff --git a/policyengine_us/tests/policy/contrib/reconciliation/reconciled_medicaid_work_requirement.yaml b/policyengine_us/tests/policy/contrib/reconciliation/reconciled_medicaid_work_requirement.yaml new file mode 100644 index 00000000000..17dbd56a22b --- /dev/null +++ b/policyengine_us/tests/policy/contrib/reconciliation/reconciled_medicaid_work_requirement.yaml @@ -0,0 +1,74 @@ +- name: Case 1, age 18, work exempted age. + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_medicaid_work_requirement.reconciled_medicaid_work_requirement + input: + gov.contrib.reconciliation.medicaid_work_requirement.in_effect: true + age: 18 + output: + medicaid_work_requirement_eligible: true + +- name: Case 2, age 65, work exempted age. + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_medicaid_work_requirement.reconciled_medicaid_work_requirement + input: + gov.contrib.reconciliation.medicaid_work_requirement.in_effect: true + age: 65 + output: + medicaid_work_requirement_eligible: true + +- name: Case 3, age 19, need working. + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_medicaid_work_requirement.reconciled_medicaid_work_requirement + input: + gov.contrib.reconciliation.medicaid_work_requirement.in_effect: true + age: 19 + output: + medicaid_work_requirement_eligible: false + +- name: Case 4, age 30, working 79 hours per month. + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_medicaid_work_requirement.reconciled_medicaid_work_requirement + input: + gov.contrib.reconciliation.medicaid_work_requirement.in_effect: true + age: 30 + monthly_hours_worked: 79 + output: + medicaid_work_requirement_eligible: false + +- name: Case 5, age 30, working 80 hours per month. + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_medicaid_work_requirement.reconciled_medicaid_work_requirement + input: + gov.contrib.reconciliation.medicaid_work_requirement.in_effect: true + age: 30 + monthly_hours_worked: 80 + output: + medicaid_work_requirement_eligible: true + +- name: Case 6, age 30, is disabled. + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_medicaid_work_requirement.reconciled_medicaid_work_requirement + input: + gov.contrib.reconciliation.medicaid_work_requirement.in_effect: true + age: 19 + monthly_hours_worked: 5 + is_disabled: true + output: + medicaid_work_requirement_eligible: true + +- name: Case 7, integration. + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_medicaid_work_requirement.reconciled_medicaid_work_requirement + input: + gov.contrib.reconciliation.medicaid_work_requirement.in_effect: true + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + monthly_hours_worked: 80 + person2: + age: 30 + is_tax_unit_head_or_spouse: true + monthly_hours_worked: 79 + output: + medicaid_work_requirement_eligible: [true, false]