diff --git a/changelog.d/veteran-total-disability-rating.fixed.md b/changelog.d/veteran-total-disability-rating.fixed.md new file mode 100644 index 00000000000..9348c76e2f8 --- /dev/null +++ b/changelog.d/veteran-total-disability-rating.fixed.md @@ -0,0 +1 @@ +Use the VA 100% service-connected rating flag for the Medicaid work requirement veteran exemption, the Kansas disabled veteran exemption, Hawaii LIHEAP points and SNAP's elderly or disabled member, and document both VA rating flags. diff --git a/policyengine_us/parameters/gov/usda/disabled_programs.yaml b/policyengine_us/parameters/gov/usda/disabled_programs.yaml index cb417554b43..b0f156ccc54 100644 --- a/policyengine_us/parameters/gov/usda/disabled_programs.yaml +++ b/policyengine_us/parameters/gov/usda/disabled_programs.yaml @@ -9,6 +9,13 @@ values: - receives_ssi - ssi - social_security_disability + # Clause (6) of the definition covers "a veteran with a service-connected + # or non-service-connected disability rated by the Veteran's + # Administration (VA) as total or paid as total". The first flag covers a + # service-connected rating, temporary or permanent; the second covers a + # permanent and total rating, which a non-service-connected (pension) + # rating requires. + - is_fully_disabled_service_connected_veteran - is_permanently_disabled_veteran - is_surviving_spouse_of_disabled_veteran - is_surviving_child_of_disabled_veteran diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.yaml index 3fa67b1aad2..6ba5269c4a2 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.yaml @@ -412,3 +412,26 @@ medicaid_community_engagement_pass_through_eligible: false output: medicaid_work_requirement_eligible: true + +- name: Case 42, a veteran with a 100% service-connected rating is exempt. + period: 2027 + input: + age: 40 + monthly_hours_worked: 0 + is_veteran: true + is_fully_disabled_service_connected_veteran: true + medicaid_community_engagement_pass_through_eligible: false + output: + medicaid_work_requirement_eligible: true + +- name: Case 43, a veteran with only the tax permanent and total disability flag is not exempt as a veteran. + period: 2027 + input: + age: 40 + monthly_hours_worked: 0 + is_veteran: true + is_permanently_and_totally_disabled: true + is_fully_disabled_service_connected_veteran: false + medicaid_community_engagement_pass_through_eligible: false + output: + medicaid_work_requirement_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/liheap/hi_liheap_points.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/liheap/hi_liheap_points.yaml index 614919e9a1a..0f12c3d4df2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/liheap/hi_liheap_points.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/liheap/hi_liheap_points.yaml @@ -1067,3 +1067,39 @@ county: HONOLULU_COUNTY_HI output: hi_liheap_points: [5, 5, 5, 4] + +- name: Case 17, a 100% service-connected veteran adds the disabled-adult point. + period: 2026 + # Same income as Case 16's person3 (5 points with the disabled point). + input: + people: + person1: + age: 40 + ssi: 0 + employment_income: 12_000 + is_fully_disabled_service_connected_veteran: true + person2: + age: 40 + ssi: 0 + employment_income: 12_000 + is_fully_disabled_service_connected_veteran: false + spm_units: + spm_unit1: + members: [person1] + heating_type: NATURAL_GAS + hi_tanf: 0 + spm_unit2: + members: [person2] + heating_type: NATURAL_GAS + hi_tanf: 0 + households: + household1: + members: [person1] + state_code: HI + county: HONOLULU_COUNTY_HI + household2: + members: [person2] + state_code: HI + county: HONOLULU_COUNTY_HI + output: + hi_liheap_points: [5, 4] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemption_2025.yaml b/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemption_2025.yaml index f662fcff863..9f8c7225cf5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemption_2025.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemption_2025.yaml @@ -7,7 +7,8 @@ input: people: person1: - is_permanently_and_totally_disabled: true + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: true is_veteran: true employment_income: 50_000 tax_units: @@ -28,11 +29,13 @@ input: people: person1: - is_permanently_and_totally_disabled: true + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: true is_veteran: true employment_income: 40_000 person2: - is_permanently_and_totally_disabled: true + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: true is_veteran: true employment_income: 30_000 tax_units: @@ -54,7 +57,8 @@ input: people: person1: - is_permanently_and_totally_disabled: true + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: true is_veteran: true employment_income: 60_000 person2: @@ -81,7 +85,8 @@ input: people: person1: - is_permanently_and_totally_disabled: true + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: true is_veteran: true employment_income: 50_000 tax_units: @@ -102,7 +107,8 @@ input: people: person1: - is_permanently_and_totally_disabled: true + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: true is_veteran: true tax_units: tax_unit: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemptions_eligible_person.yaml.yaml b/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemptions_eligible_person.yaml.yaml index 8077164b043..b7efd2c6b1d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemptions_eligible_person.yaml.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemptions_eligible_person.yaml.yaml @@ -1,8 +1,8 @@ - name: Case 1, the filer is a disabled veteran, get exemptions. period: 2023 input: - is_permanently_and_totally_disabled: true - is_veteran: true + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: true state_code: KS output: ks_disabled_veteran_exemptions_eligible_person: true @@ -33,3 +33,21 @@ state_code: KS output: ks_disabled_veteran_exemptions_eligible_person: false + +- name: Case 5, a 100% service-connected rating that is not permanent gets no exemption. + period: 2025 + input: + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: false + state_code: KS + output: + ks_disabled_veteran_exemptions_eligible_person: false + +- name: Case 6, a permanent and total rating below the 100% service-connected rate gets no exemption. + period: 2025 + input: + is_fully_disabled_service_connected_veteran: false + is_permanently_disabled_veteran: true + state_code: KS + output: + ks_disabled_veteran_exemptions_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/ks_2025_integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/ks_2025_integration.yaml index 487509ee4f7..dba0e96e9ff 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/ks_2025_integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ks/tax/income/ks_2025_integration.yaml @@ -290,8 +290,8 @@ is_tax_unit_head: true age: 50 employment_income: 45_000 - is_permanently_and_totally_disabled: true - is_veteran: true + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: true tax_units: tax_unit: members: [person1] diff --git a/policyengine_us/tests/policy/baseline/gov/usda/is_usda_disabled.yaml b/policyengine_us/tests/policy/baseline/gov/usda/is_usda_disabled.yaml index 1cdab9f8b50..8db7987d2f5 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/is_usda_disabled.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/is_usda_disabled.yaml @@ -67,3 +67,12 @@ social_security_disability: 100 output: is_usda_disabled: true + +- name: Case 9, a veteran with a 100% service-connected rating that is not permanent is USDA disabled. + period: 2026 + input: + age: 40 + is_fully_disabled_service_connected_veteran: true + is_permanently_disabled_veteran: false + output: + is_usda_disabled: true diff --git a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py index 153c5276120..e7e82c6ec44 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py +++ b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py @@ -10,6 +10,8 @@ class medicaid_work_requirement_eligible(Variable): "https://www.congress.gov/bill/119th-congress/house-bill/1/text", "https://www.medicaid.gov/federal-policy-guidance/downloads/cib12082025.pdf", "https://www.law.cornell.edu/uscode/text/42/1382c#a_3", + "https://www.govinfo.gov/content/pkg/PLAW-119publ21/pdf/PLAW-119publ21.pdf#page=242", + "https://www.law.cornell.edu/cfr/text/42/435.554", ) def formula(person, period, parameters): @@ -64,12 +66,10 @@ def formula(person, period, parameters): is_dependent = person("is_tax_unit_dependent", period) is_disabled = person("is_disabled", period) has_disabled = person.tax_unit.any(is_dependent & is_disabled) - # veteran and is_permanently_and_totally_disabled p.694 (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 + # Clause (IV): a veteran with a disability rated as total under 38 + # U.S.C. 1155, which 42 CFR 435.554(c)(4) reads as "a temporary or + # permanent disability ... rated as 100 percent (total)". + eligible_veteran = person("is_fully_disabled_service_connected_veteran", period) # blind or disabled or is_incapable_of_self_care p.694 (V) is_blind = person("is_blind", period) is_incapable_of_self_care = person("is_incapable_of_self_care", period) diff --git a/policyengine_us/variables/gov/states/hi/dhs/liheap/hi_liheap_points.py b/policyengine_us/variables/gov/states/hi/dhs/liheap/hi_liheap_points.py index ccf15e3e147..92f53f6474b 100644 --- a/policyengine_us/variables/gov/states/hi/dhs/liheap/hi_liheap_points.py +++ b/policyengine_us/variables/gov/states/hi/dhs/liheap/hi_liheap_points.py @@ -52,14 +52,16 @@ def formula(spm_unit, period, parameters): age = person("age", period) qualified = person("hi_liheap_qualified_member", period) # The manuals define a disabled individual by receipt of SSI or Social - # Security disability payments. Veterans' 100% ratings, governmental - # disability retirement and railroad disability have no separate input, - # so is_disabled stands in for them. This affects points only. + # Security disability payments, or "VA benefits for a 100% + # service-connected disability". Governmental disability retirement + # and railroad disability have no separate input, so is_disabled + # stands in for them. This affects points only. disabled = ( person("is_disabled", period) | (person("ssi", period, options=[ADD]) > 0) | (add(person, period, ["receives_ssi"]) > 0) | (person("social_security_disability", period) > 0) + | person("is_fully_disabled_service_connected_veteran", period) ) ages = p.payment.points.vulnerability vulnerable = spm_unit.any( diff --git a/policyengine_us/variables/gov/states/il/rta/cta/free_ride/il_cta_military_service_pass_eligible.py b/policyengine_us/variables/gov/states/il/rta/cta/free_ride/il_cta_military_service_pass_eligible.py index 82e6b58a4de..04b9cbcd9c2 100644 --- a/policyengine_us/variables/gov/states/il/rta/cta/free_ride/il_cta_military_service_pass_eligible.py +++ b/policyengine_us/variables/gov/states/il/rta/cta/free_ride/il_cta_military_service_pass_eligible.py @@ -11,6 +11,9 @@ class il_cta_military_service_pass_eligible(Variable): def formula(person, period, parameters): is_in_active_duty = person("military_basic_pay", period) > 0 + # NOTE: The CTA covers a veteran with VA disability compensation "of + # 10% or greater". The model has no input for ratings below 100%, so + # veterans rated 10% to 90% are missed. disabled_veterans = person( "is_fully_disabled_service_connected_veteran", period ) diff --git a/policyengine_us/variables/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemptions_person.py b/policyengine_us/variables/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemptions_person.py index cd536e88133..35845d9aa89 100644 --- a/policyengine_us/variables/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemptions_person.py +++ b/policyengine_us/variables/gov/states/ks/tax/income/exemptions/ks_disabled_veteran_exemptions_person.py @@ -8,13 +8,22 @@ class ks_disabled_veteran_exemptions_eligible_person(Variable): unit = USD definition_period = YEAR reference = ( - "https://law.justia.com/codes/kansas/chapter-79/article-32/section-79-32-121/" + "https://law.justia.com/codes/kansas/chapter-79/article-32/section-79-32-121/", + "https://www.kslegislature.gov/li/b2025_26/statute/079_000_0000_chapter/079_032_0000_article/079_032_0121b_section/079_032_0121b_k/", + "https://www.ksrevenue.gov/pdf/ip23.pdf#page=6", ) defined_for = StateCode.KS def formula(person, period, parameters): p = parameters(period).gov.states.ks.tax.income.exemptions.disabled_veteran - disabled = person("is_permanently_and_totally_disabled", period) - is_veteran = person("is_veteran", period) - - return p.in_effect * disabled * is_veteran + # K.S.A. 79-32,121b(b)(2): a veteran the VA certifies "to be in + # receipt of disability compensation at the 100% rate, if the + # disability is permanent and was sustained through military action + # or accident or resulted from disease contracted while in such + # active service". The VA flags already imply veteran status. The + # honorable-discharge condition has no input. + paid_at_100_percent = person( + "is_fully_disabled_service_connected_veteran", period + ) + permanent = person("is_permanently_disabled_veteran", period) + return p.in_effect & paid_at_100_percent & permanent diff --git a/policyengine_us/variables/gov/states/nc/tax/income/deductions/military_retirement/nc_military_retirement_deduction_eligible.py b/policyengine_us/variables/gov/states/nc/tax/income/deductions/military_retirement/nc_military_retirement_deduction_eligible.py index 14c137c951e..ad29f9191f1 100644 --- a/policyengine_us/variables/gov/states/nc/tax/income/deductions/military_retirement/nc_military_retirement_deduction_eligible.py +++ b/policyengine_us/variables/gov/states/nc/tax/income/deductions/military_retirement/nc_military_retirement_deduction_eligible.py @@ -16,7 +16,10 @@ class nc_military_retirement_deduction_eligible(Variable): def formula(person, period, parameters): p = parameters(period).gov.states.nc.tax.income.deductions.military_retirement # G.S. 105-153.5(b)(5a)a.: a retired member who served the minimum - # years or was medically retired. + # years or was "Medically retired under 10 U.S.C. Chapter 61". + # NOTE: The model has no input for a chapter 61 disability retirement, + # so the VA permanent and total rating stands in. It misses a member on + # the temporary disability retired list (10 U.S.C. 1202). is_medically_retired = person("is_permanently_disabled_veteran", period) served_minimum_years = person("years_in_military", period) >= p.minimum_years # (5a)b.: the Survivor Benefit Plan beneficiary of such a member. diff --git a/policyengine_us/variables/household/demographic/person/is_fully_disabled_service_connected_veteran.py b/policyengine_us/variables/household/demographic/person/is_fully_disabled_service_connected_veteran.py index 8c0b204dc00..fae89b13e08 100644 --- a/policyengine_us/variables/household/demographic/person/is_fully_disabled_service_connected_veteran.py +++ b/policyengine_us/variables/household/demographic/person/is_fully_disabled_service_connected_veteran.py @@ -6,3 +6,13 @@ class is_fully_disabled_service_connected_veteran(Variable): entity = Person label = "Is a fully disabled veteran who became so as a result of an injury during service" definition_period = YEAR + # True when the Department of Veterans Affairs rates or pays a + # service-connected disability at the 100% rate, temporary or permanent, + # including a total rating based on individual unemployability. A + # permanent rating is is_permanently_disabled_veteran. The model has no + # input for ratings below 100%. + reference = ( + "https://www.law.cornell.edu/uscode/text/38/1155", + "https://www.law.cornell.edu/cfr/text/38/3.340", + "https://www.law.cornell.edu/cfr/text/38/4.16", + ) diff --git a/policyengine_us/variables/household/demographic/person/is_permanently_disabled_veteran.py b/policyengine_us/variables/household/demographic/person/is_permanently_disabled_veteran.py index bf6b687dc6d..521e65ab073 100644 --- a/policyengine_us/variables/household/demographic/person/is_permanently_disabled_veteran.py +++ b/policyengine_us/variables/household/demographic/person/is_permanently_disabled_veteran.py @@ -6,3 +6,12 @@ class is_permanently_disabled_veteran(Variable): entity = Person definition_period = YEAR label = "Permanently disabled veteran" + # True when the Department of Veterans Affairs has rated the veteran's + # disability permanent and total, for service-connected compensation or + # for a pension, which requires a permanent and total non-service-connected + # disability (38 U.S.C. 1521(a)). A 100% service-connected rating that is + # not permanent is is_fully_disabled_service_connected_veteran. + reference = ( + "https://www.law.cornell.edu/cfr/text/38/3.340", + "https://www.law.cornell.edu/uscode/text/38/1521", + )