diff --git a/changelog.d/eitc-age-ceiling-completed-years.fixed.md b/changelog.d/eitc-age-ceiling-completed-years.fixed.md new file mode 100644 index 00000000000..03b09444c03 --- /dev/null +++ b/changelog.d/eitc-age-ceiling-completed-years.fixed.md @@ -0,0 +1 @@ +Compare completed years in the childless EITC age ceiling, so a filer aged 64.5, who has not attained 65, meets IRC 32(c)(1)(A)(ii)(II). diff --git a/policyengine_us/parameters/gov/irs/credits/eitc/eligibility/age/max.yaml b/policyengine_us/parameters/gov/irs/credits/eitc/eligibility/age/max.yaml index 1a26635ef5e..236d40c8685 100644 --- a/policyengine_us/parameters/gov/irs/credits/eitc/eligibility/age/max.yaml +++ b/policyengine_us/parameters/gov/irs/credits/eitc/eligibility/age/max.yaml @@ -1,4 +1,4 @@ -description: The US limits EITC eligibility for filers without children to those below this age. +description: The US limits EITC eligibility for filers without children to those whose completed age is at most this value. metadata: unit: year label: EITC maximum childless age diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_demographic_eligible_fractional_age.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_demographic_eligible_fractional_age.yaml new file mode 100644 index 00000000000..9780664fe36 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_demographic_eligible_fractional_age.yaml @@ -0,0 +1,219 @@ +# IRC 32(c)(1)(A)(ii)(II): a filer without a qualifying child must have +# "attained age 25 but not attained age 65 before the close of the taxable +# year". gov.irs.credits.eitc.eligibility.age.max is the highest completed age +# that qualifies (64; no limit in 2021 under ARPA's 32(n)(2)), so the test +# compares completed years. + +- name: Childless filer aged 64.0 meets the age test, 2024 + period: 2024 + input: + people: + filer: + age: 64.0 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + tax_units: + unit: + members: [filer] + filing_status: SINGLE + would_file_taxes_voluntarily: true + takes_up_eitc: true + output: + # Completed age 64 <= 64. + eitc_demographic_eligible: true + # 7.65% x $8,000 = $612, under the $632 maximum and the $10,330 phase-out start. + eitc: 612 + +- name: Childless filer aged 64.5 has not attained 65 and meets the age test, 2024 + period: 2024 + input: + people: + filer: + age: 64.5 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + tax_units: + unit: + members: [filer] + filing_status: SINGLE + would_file_taxes_voluntarily: true + takes_up_eitc: true + output: + # Completed age 64 <= 64; main tested 64.5 <= 64 and failed. + eitc_demographic_eligible: true + # 7.65% x $8,000 = $612, under the $632 maximum and the $10,330 phase-out start. + eitc: 612 + +- name: Childless filer aged 65.0 has attained 65 and fails the age test, 2024 + period: 2024 + input: + people: + filer: + age: 65.0 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + tax_units: + unit: + members: [filer] + filing_status: SINGLE + would_file_taxes_voluntarily: true + takes_up_eitc: true + output: + # Completed age 65 > 64. + eitc_demographic_eligible: false + eitc: 0 + +- name: Childless filer aged 64.5 meets the age test, 2026 + period: 2026 + input: + people: + filer: + age: 64.5 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + tax_units: + unit: + members: [filer] + filing_status: SINGLE + would_file_taxes_voluntarily: true + takes_up_eitc: true + output: + # Completed age 64 <= 64. + eitc_demographic_eligible: true + +- name: Childless filer aged 64.5 meets the age test in 2021, with no upper limit + period: 2021 + input: + people: + filer: + age: 64.5 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + tax_units: + unit: + members: [filer] + filing_status: SINGLE + would_file_taxes_voluntarily: true + takes_up_eitc: true + output: + # ARPA 32(n)(2) removed the upper limit for 2021. + eitc_demographic_eligible: true + +- name: Childless filer aged 80.5 meets the age test in 2021, with no upper limit + period: 2021 + input: + people: + filer: + age: 80.5 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + tax_units: + unit: + members: [filer] + filing_status: SINGLE + would_file_taxes_voluntarily: true + takes_up_eitc: true + output: + # ARPA 32(n)(2) removed the upper limit for 2021. + eitc_demographic_eligible: true + +- name: Childless filer aged 24.5 has not attained 25 and fails the age test, 2024 + period: 2024 + input: + people: + filer: + age: 24.5 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + tax_units: + unit: + members: [filer] + filing_status: SINGLE + would_file_taxes_voluntarily: true + takes_up_eitc: true + output: + # The minimum is unchanged: 24.5 < 25. + eitc_demographic_eligible: false + +- name: Childless filer aged 64.99 has not attained 65 and meets the age test, 2024 + period: 2024 + input: + people: + filer: + age: 64.99 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + tax_units: + unit: + members: [filer] + filing_status: SINGLE + would_file_taxes_voluntarily: true + takes_up_eitc: true + output: + # Completed age 64 <= 64; rounding 64.99 to 65 would fail it. + eitc_demographic_eligible: true + # 7.65% x $8,000 = $612, under the $632 maximum and the $10,330 phase-out start. + eitc: 612 + +- name: Joint filers aged 70 and 64.5 meet the age test through the spouse, 2024 + period: 2024 + input: + people: + head: + age: 70 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + spouse: + age: 64.5 + is_tax_unit_spouse: true + ssn_card_type: CITIZEN + tax_units: + unit: + members: [head, spouse] + filing_status: JOINT + would_file_taxes_voluntarily: true + takes_up_eitc: true + marital_units: + mu: + members: [head, spouse] + output: + # Either spouse may meet 32(c)(1)(A)(ii)(II); the spouse's completed age is 64. + eitc_demographic_eligible: true + # 7.65% x $8,000 = $612, under the $632 maximum and the joint phase-out start. + eitc: 612 + +- name: Joint filers aged 70 and 65 don't meet the age test, 2024 + period: 2024 + input: + people: + head: + age: 70 + is_tax_unit_head: true + ssn_card_type: CITIZEN + employment_income: 8_000 + spouse: + age: 65.0 + is_tax_unit_spouse: true + ssn_card_type: CITIZEN + tax_units: + unit: + members: [head, spouse] + filing_status: JOINT + would_file_taxes_voluntarily: true + takes_up_eitc: true + marital_units: + mu: + members: [head, spouse] + output: + # Neither spouse's completed age (70, 65) is at most 64. + eitc_demographic_eligible: false + eitc: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/tax/income/credits/me_eitc.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/tax/income/credits/me_eitc.yaml index 244cf86f664..140d6af1e00 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/me/tax/income/credits/me_eitc.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/me/tax/income/credits/me_eitc.yaml @@ -606,3 +606,31 @@ eitc: 0 me_pro_forma_childless_eitc: 765 me_eitc: 153 + +- name: 2024 federally eligible couple aged 23 and 64.5 that does not take up the federal EITC gets no Maine credit + # The 64.5-year-old has not attained 65, so the couple fails the Maine cohort + # and takes the federal path. If the federal test goes back to the exact age, + # the cohort flag and the pro forma credit return, and me_eitc pays 306. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + head: + age: 64.5 + spouse: + age: 23 + employment_income: 8_000 + tax_units: + tax_unit: + members: [head, spouse] + filing_status: JOINT + takes_up_eitc: false + households: + household: + members: [head, spouse] + state_code: ME + output: + me_childless_eitc_age_eligible: false + eitc: 0 + me_pro_forma_childless_eitc: 0 + me_eitc: 0 diff --git a/policyengine_us/tests/test_me_childless_eitc_age_gate.py b/policyengine_us/tests/test_me_childless_eitc_age_gate.py index 0697b02c1f2..ba3a7cf3143 100644 --- a/policyengine_us/tests/test_me_childless_eitc_age_gate.py +++ b/policyengine_us/tests/test_me_childless_eitc_age_gate.py @@ -125,7 +125,7 @@ def filers(h): def meets_federal_age(h, year): minimum, student_minimum, maximum = federal_age_limits(year) return any( - (student_minimum if student else minimum) <= age <= maximum + (student_minimum if student else minimum) <= age < maximum + 1 for age, student in filers(h) ) diff --git a/policyengine_us/tests/test_me_childless_eitc_age_gate_property.py b/policyengine_us/tests/test_me_childless_eitc_age_gate_property.py index 167b27c8ab3..b679dc0c5cf 100644 --- a/policyengine_us/tests/test_me_childless_eitc_age_gate_property.py +++ b/policyengine_us/tests/test_me_childless_eitc_age_gate_property.py @@ -13,10 +13,8 @@ # Filers are 18 or older: the model makes a married 17-year-old a dependent, # not a spouse. The YAML cases and the under-18 witness cover age 17. The -# fractional ages test "has not attained 25". None falls between 64 and 65: -# the federal test (eitc_demographic_eligible, unchanged here) compares the -# exact age with 64, and the oracle copies it. -fractional_ages = st.sampled_from([18.5, 23.5, 24.5, 24.99]) +# fractional ages test "has not attained 25" and "not attained age 65". +fractional_ages = st.sampled_from([18.5, 23.5, 24.5, 24.99, 64.5, 64.99]) spouse_strategy = st.fixed_dictionaries( { "age": st.one_of(st.integers(18, 80), fractional_ages), diff --git a/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_demographic_eligible.py b/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_demographic_eligible.py index 9cb742b764f..311e62c1bf7 100644 --- a/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_demographic_eligible.py +++ b/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_demographic_eligible.py @@ -26,7 +26,13 @@ def formula(tax_unit, period, parameters): student = person("is_full_time_student", period) min_age = where(student, min_age_student, min_age_non_student) max_age = parameters.gov.irs.credits.eitc.eligibility.age.max(period) - meets_age_requirements = (age >= min_age) & (age <= max_age) + # IRC 32(c)(1)(A)(ii)(II): "attained age 25 but not attained age 65 + # before the close of the taxable year". The parameter is the highest + # completed age that qualifies, so compare completed years: a filer + # aged 64.5 has not attained 65. The minimum already works for + # fractional ages. This reads `age` as the age at the close of the + # taxable year. + meets_age_requirements = (age >= min_age) & (np.floor(age) <= max_age) # IRC § 32(c)(1)(A)(ii)(II) applies the age test to the filer or, # on a joint return, either spouse — never to dependents. is_filer_or_spouse = ~person("is_tax_unit_dependent", period) diff --git a/policyengine_us/variables/gov/states/me/tax/income/credits/eitc/me_childless_eitc_age_eligible.py b/policyengine_us/variables/gov/states/me/tax/income/credits/eitc/me_childless_eitc_age_eligible.py index 07a398bb53f..4458a540ad8 100644 --- a/policyengine_us/variables/gov/states/me/tax/income/credits/eitc/me_childless_eitc_age_eligible.py +++ b/policyengine_us/variables/gov/states/me/tax/income/credits/eitc/me_childless_eitc_age_eligible.py @@ -52,7 +52,7 @@ def formula(tax_unit, period, parameters): ) meets_federal_age = ( (age >= federal_min_age) - & (age <= federal_age.max(period)) + & (np.floor(age) <= federal_age.max(period)) & is_head_or_spouse )