From b6192c7951fa0a5b5412d1a8d03563e2880cdeeb Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Fri, 16 Oct 2026 16:31:25 -0400 Subject: [PATCH 1/2] Apply the $10 minimum payment in MI FIP, VA TANF, SC TANF and MD TCA Michigan: financial need requires an issuance deficit of at least $10 (BEM 518), for applicants as well as recipients. Virginia: the payment is the budgetary deficiency rounded down to whole dollars, and none is made under $10 (TANF Manual 502.1 A). South Carolina: no payment under $10 (S.C. Code Regs. 114-1140(A)(5)). Maryland: a benefit is issued only when it is at least $10 (COMAR 07.03.03.13 E(2)). Co-Authored-By: Claude Opus 5.5 --- .../fix-9985-tanf-10-dollar-minimum.fixed.md | 1 + .../gov/states/md/tca/minimum_payment.yaml | 13 +++ .../states/mi/mdhhs/fip/minimum_payment.yaml | 15 ++++ .../gov/states/sc/tanf/minimum_payment.yaml | 15 ++++ .../states/va/dss/tanf/minimum_payment.yaml | 13 +++ .../baseline/gov/states/md/tca/md_tca.yaml | 38 +++++++++ .../eligibility/mi_fip_income_eligible.yaml | 51 ++++++++++++ .../gov/states/mi/mdhhs/fip/integration.yaml | 32 ++++++++ .../baseline/gov/states/sc/tanf/sc_tanf.yaml | 47 +++++++++++ .../gov/states/va/dss/tanf/integration.yaml | 20 ++--- .../gov/states/va/dss/tanf/va_tanf.yaml | 81 ++++++++++++++++--- .../variables/gov/states/md/tca/md_tca.py | 6 +- .../fip/eligibility/mi_fip_income_eligible.py | 17 ++-- .../gov/states/mi/mdhhs/fip/mi_fip.py | 3 +- .../variables/gov/states/sc/tanf/sc_tanf.py | 5 +- .../gov/states/va/dss/tanf/va_tanf.py | 6 +- 16 files changed, 331 insertions(+), 32 deletions(-) create mode 100644 changelog.d/fix-9985-tanf-10-dollar-minimum.fixed.md create mode 100644 policyengine_us/parameters/gov/states/md/tca/minimum_payment.yaml create mode 100644 policyengine_us/parameters/gov/states/mi/mdhhs/fip/minimum_payment.yaml create mode 100644 policyengine_us/parameters/gov/states/sc/tanf/minimum_payment.yaml create mode 100644 policyengine_us/parameters/gov/states/va/dss/tanf/minimum_payment.yaml diff --git a/changelog.d/fix-9985-tanf-10-dollar-minimum.fixed.md b/changelog.d/fix-9985-tanf-10-dollar-minimum.fixed.md new file mode 100644 index 00000000000..b6ad835cd61 --- /dev/null +++ b/changelog.d/fix-9985-tanf-10-dollar-minimum.fixed.md @@ -0,0 +1 @@ +Apply the $10 minimum payment in Michigan FIP (BEM 518 issuance deficit test), Virginia TANF (TANF Manual 502.1 A, with the payment rounded down to whole dollars), South Carolina TANF (S.C. Code Regs. 114-1140(A)(5)) and Maryland TCA (COMAR 07.03.03.13 E(2)). diff --git a/policyengine_us/parameters/gov/states/md/tca/minimum_payment.yaml b/policyengine_us/parameters/gov/states/md/tca/minimum_payment.yaml new file mode 100644 index 00000000000..82681b90e0a --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/tca/minimum_payment.yaml @@ -0,0 +1,13 @@ +description: Maryland issues a Temporary Cash Assistance benefit only when the assistance unit is eligible for at least this amount. + +values: + # Dated to the start of the other COMAR 07.03.03.13 E parameters. + 2016-01-01: 10 + +metadata: + unit: currency-USD + period: month + label: Maryland TCA minimum payment + reference: + - title: COMAR 07.03.03.13.E(2) - Benefit Amount + href: https://dsd.maryland.gov/regulations/Pages/07.03.03.13.aspx diff --git a/policyengine_us/parameters/gov/states/mi/mdhhs/fip/minimum_payment.yaml b/policyengine_us/parameters/gov/states/mi/mdhhs/fip/minimum_payment.yaml new file mode 100644 index 00000000000..b4403a25b8c --- /dev/null +++ b/policyengine_us/parameters/gov/states/mi/mdhhs/fip/minimum_payment.yaml @@ -0,0 +1,15 @@ +description: Michigan requires the Family Independence Program payment standard to exceed budgetable income by at least this amount in the issuance deficit test for financial need to exist. + +values: + # Dated to the start of the other BEM 518 income budgeting parameters. + 2008-10-01: 10 + +metadata: + unit: currency-USD + period: month + label: Michigan FIP minimum issuance deficit + reference: + - title: Michigan DHHS BEM 518 - FIP/RCA/SDA Income Budgeting, Financial Need and Issuance Deficit Test + href: https://mdhhs-pres-prod.michigan.gov/olmweb/ex/BP/Public/BEM/518.pdf#page=2 + - title: Michigan DHHS BEM 518 - FIP/RCA/SDA Income Budgeting, Benefit Amount + href: https://mdhhs-pres-prod.michigan.gov/olmweb/ex/BP/Public/BEM/518.pdf#page=4 diff --git a/policyengine_us/parameters/gov/states/sc/tanf/minimum_payment.yaml b/policyengine_us/parameters/gov/states/sc/tanf/minimum_payment.yaml new file mode 100644 index 00000000000..c78b87bad99 --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/minimum_payment.yaml @@ -0,0 +1,15 @@ +description: South Carolina makes no Temporary Assistance for Needy Families payment in a month when the benefit is less than this amount. + +values: + # Dated to the start of the other South Carolina TANF parameters. + 1996-07-01: 10 + +metadata: + unit: currency-USD + period: month + label: South Carolina TANF minimum payment + reference: + - title: S.C. Code Regs. 114-1140(A)(5) - Financial Criteria + href: https://www.scstatehouse.gov/coderegs/Chapter%20114.pdf#page=210 + - title: South Carolina TANF Policy Manual Volume 65, Section 8.16 I - Manual Benefit Calculation + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=133 diff --git a/policyengine_us/parameters/gov/states/va/dss/tanf/minimum_payment.yaml b/policyengine_us/parameters/gov/states/va/dss/tanf/minimum_payment.yaml new file mode 100644 index 00000000000..83ef9e3ece1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/va/dss/tanf/minimum_payment.yaml @@ -0,0 +1,13 @@ +description: Virginia makes no Temporary Assistance for Needy Families payment when the budgetary deficiency is less than this amount. + +values: + # Section 502.1 page dated 7/20 (TANF Transmittal 68). + 2020-07-01: 10 + +metadata: + unit: currency-USD + period: month + label: Virginia TANF minimum payment + reference: + - title: Virginia TANF Manual, Section 502.1 A.2 - Minimum Payment + href: https://www.dss.virginia.gov/media/vdss/benefit-programs/documents/tanfview/tanf/Chapter-500---Authorization-and-Payment.pdf#page=3 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/tca/md_tca.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/tca/md_tca.yaml index adc9a1960ff..23e88dc5f1e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/md/tca/md_tca.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/md/tca/md_tca.yaml @@ -72,3 +72,41 @@ state_code: MD output: md_tca: 0 + +- name: Case 5, a benefit under $10 is not issued. + period: 2025-01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + md_tca_eligible: true + md_tca_maximum_benefit: 448 + md_tca_countable_income: 443.2 + households: + household: + state_code: MD + output: + # Benefit = $448 - $443.20 = $4.80, under $10 (COMAR 07.03.03.13 E(2)) + md_tca: 0 + +- name: Case 6, a benefit of exactly $10 is issued. + period: 2025-01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + md_tca_eligible: true + md_tca_maximum_benefit: 448 + md_tca_countable_income: 438 + households: + household: + state_code: MD + output: + # Benefit = $448 - $438 = $10 + md_tca: 10 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.yaml index 7bd0a3ef29d..53112c3f33f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.yaml @@ -102,3 +102,54 @@ state_code: CA output: mi_fip_income_eligible: false + +- name: Enrolled recipient with an issuance deficit under $10 is not eligible + period: 2025-01 + input: + is_tanf_enrolled: true + state_code: MI + mi_fip_payment_standard: 583 + mi_fip_countable_income_for_benefit: 575 + mi_fip_countable_income_for_eligibility: 575 + output: + # Issuance deficit = $583 - $575 = $8, under $10 (BEM 518) + mi_fip_income_eligible: false + +- name: Enrolled recipient with an issuance deficit of exactly $10 is eligible + period: 2025-01 + input: + is_tanf_enrolled: true + state_code: MI + mi_fip_payment_standard: 583 + mi_fip_countable_income_for_benefit: 573 + mi_fip_countable_income_for_eligibility: 600 + output: + # Issuance deficit = $583 - $573 = $10 + # (the Qualifying Deficit Test does not apply to enrolled recipients) + mi_fip_income_eligible: true + +- name: Applicant passing the qualifying test with an issuance deficit under $10 is not eligible + period: 2025-01 + input: + is_tanf_enrolled: false + state_code: MI + mi_fip_payment_standard: 583 + mi_fip_countable_income_for_benefit: 575 + mi_fip_countable_income_for_eligibility: 580 + output: + # Qualifying deficit = $583 - $580 = $3 (passes) + # Issuance deficit = $583 - $575 = $8, under $10 (fails) + mi_fip_income_eligible: false + +- name: Applicant passing both deficit tests is eligible + period: 2025-01 + input: + is_tanf_enrolled: false + state_code: MI + mi_fip_payment_standard: 583 + mi_fip_countable_income_for_benefit: 500 + mi_fip_countable_income_for_eligibility: 580 + output: + # Qualifying deficit = $583 - $580 = $3 (passes) + # Issuance deficit = $583 - $500 = $83 (passes) + mi_fip_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/integration.yaml index f761ab43123..2c8183e4213 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/integration.yaml @@ -524,3 +524,35 @@ # Not in Michigan - not eligible for MI TANF mi_fip_eligible: false mi_fip: 0 + +- name: Case 16, enrolled family with an issuance deficit under $10. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income_before_lsr: 16_272 # $1,356/month + person2: + age: 8 + person3: + age: 5 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + is_tanf_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: MI + output: + # Family of 3: Payment standard = $583 + # Disregard = $200 + (50% × $1,156) = $778 + # Countable income = $1,356 - $778 = $578 + # Issuance deficit = $583 - $578 = $5, under $10 (BEM 518) + mi_fip_countable_income_for_benefit: 578 + mi_fip_income_eligible: false + mi_fip_eligible: false + mi_fip: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml index 01f7c7cfc9a..24218469053 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml @@ -36,3 +36,50 @@ # need_standard = 1703.33 * 0.5 = 851.67 # excess = 851.67 - 500 = 351.67 # benefit = 351.67 * 0.4046 = 142.31 + +- name: Case 4, a benefit under $10 is not paid. + absolute_error_margin: 0.01 + period: 2025-01 + input: + people: + parent: + age: 30 + child: + age: 5 + spm_units: + spm_unit: + members: [parent, child] + sc_tanf_countable_income: 840 + sc_tanf_eligible: true + households: + household: + members: [parent, child] + state_code: SC + output: + # Need standard for 2 (2025-01) = $1,703.33 * 0.5 = $851.67 + # Benefit = ($851.67 - $840) * 0.4046 = $4.72, under $10 + # (S.C. Code Regs. 114-1140(A)(5)) + sc_tanf: 0 + +- name: Case 5, a benefit of $10 or more is paid. + absolute_error_margin: 0.01 + period: 2025-01 + input: + people: + parent: + age: 30 + child: + age: 5 + spm_units: + spm_unit: + members: [parent, child] + sc_tanf_countable_income: 820 + sc_tanf_eligible: true + households: + household: + members: [parent, child] + state_code: SC + output: + # Need standard for 2 (2025-01) = $851.67 + # Benefit = ($851.67 - $820) * 0.4046 = $12.81 + sc_tanf: 12.81 diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/integration.yaml index fb12851ef99..1d16e0b4589 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/integration.yaml @@ -53,8 +53,8 @@ # Income eligibility: $316.40 <= $1,017? YES (and gross $1,000 <= $1,017) va_tanf_income_eligibility: true # - # Benefit: $508 - $316.40 = $191.60 - va_tanf: 191.6 + # Benefit: $508 - $316.40 = $191.60, rounded down to $191 + va_tanf: 191 - name: Group II locality - Single parent family period: 2021-01 @@ -104,8 +104,8 @@ # Income eligibility: $91.40 <= $663? YES va_tanf_income_eligibility: true # - # Benefit: $332 - $91.40 = $240.60 - va_tanf: 240.6 + # Benefit: $332 - $91.40 = $240.60, rounded down to $240 + va_tanf: 240 - name: TANF-UP scenario - Two able-bodied adults in Group III locality period: 2021-01 @@ -268,8 +268,8 @@ # Step 2: countable $133.07 <= grant $332? YES va_tanf_income_eligibility: true # - # Benefit: $332 - $133.07 = $198.93 - va_tanf: 198.93 + # Benefit: $332 - $133.07 = $198.93, rounded down to $198 + va_tanf: 198 - name: Family with earned and unearned income (child support) period: 2021-01 @@ -470,8 +470,8 @@ # Income eligibility: $116.40 <= $836? YES va_tanf_income_eligibility: true # - # Benefit: $417 - $116.40 = $300.60 - va_tanf: 300.6 + # Benefit: $417 - $116.40 = $300.60, rounded down to $300 + va_tanf: 300 - name: Family with only unearned income (child support) period: 2021-01 @@ -670,8 +670,8 @@ # Step 2: countable $106.40 <= grant $316? YES va_tanf_income_eligibility: true # - # Benefit: $316 - $106.40 = $209.60 - va_tanf: 209.6 + # Benefit: $316 - $106.40 = $209.60, rounded down to $209 + va_tanf: 209 - name: Step 1 passes but Step 2 fails (high unearned income) period: 2021-01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/va_tanf.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/va_tanf.yaml index 21d4de90b7d..86e481883c2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/va_tanf.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/va_tanf.yaml @@ -10,7 +10,7 @@ output: va_tanf: 0 -- name: If tanf eligible, small payment is still paid. +- name: If tanf eligible, a payment under $10 a month is not made. period: 2023 input: va_tanf_eligibility: true @@ -20,32 +20,35 @@ va_tanf_countable_income: 2_000 county_str: ARLINGTON_COUNTY_VA output: - # Grant standard $2,100 - countable income $2,000 = $100 payment - va_tanf: 100 + # Grant standard $2,100 - countable income $2,000 = $100 a year, + # or $8.33 a month, under the $10 minimum (TANF Manual 502.1 A.2) + va_tanf: 0 -- name: If up tanf eligible, small payment is still paid. - period: 2023 +- name: If up tanf eligible before July 2022, the UP grant standard applies. + period: 2021 input: va_tanf_eligibility: true va_up_tanf_eligibility: true va_tanf_grant_standard: 0 - va_tanf_up_grant_standard: 2_100 - va_tanf_countable_income: 2_000 + va_tanf_up_grant_standard: 2_400 + va_tanf_countable_income: 1_200 county_str: ARLINGTON_COUNTY_VA output: - # UP grant standard $2,100 - countable income $2,000 = $100 payment - va_tanf: 100 + # UP grant standard $2,400 - countable income $1,200 = $1,200 payment + # ($200 - $100 = $100 a month, below the monthly maximum) + va_tanf: 1_200 - name: If tanf eligible, payment less than maximum payment, they get the difference. period: 2023 input: va_tanf_eligibility: true va_up_tanf_eligibility: false - va_tanf_grant_standard: 10_000 + va_tanf_grant_standard: 12_000 va_tanf_up_grant_standard: 0 - va_tanf_countable_income: 4_000 + va_tanf_countable_income: 6_000 county_str: ARLINGTON_COUNTY_VA output: + # $1,000 - $500 = $500 a month va_tanf: 6_000 - name: Grant equals countable income. @@ -72,6 +75,62 @@ output: va_tanf: 6_000 +# Payment rounding and minimum (TANF Manual 502.1 A): the budgetary +# deficiency is adjusted to the next lower dollar, and no payment is made +# when it is under $10. + +- name: A deficiency under $10 is not paid. + period: 2025-01 + input: + va_tanf_eligibility: true + va_up_tanf_eligibility: false + va_tanf_grant_standard: 481.635 + va_tanf_up_grant_standard: 0 + va_tanf_countable_income: 479.2 + county_str: PITTSYLVANIA_COUNTY_VA + output: + # $481.635 - $479.20 = $2.435, under $10 + va_tanf: 0 + +- name: A deficiency of $9.99 is not paid. + period: 2025-01 + input: + va_tanf_eligibility: true + va_up_tanf_eligibility: false + va_tanf_grant_standard: 500 + va_tanf_up_grant_standard: 0 + va_tanf_countable_income: 490.01 + county_str: PITTSYLVANIA_COUNTY_VA + output: + # $500 - $490.01 = $9.99, under $10 + va_tanf: 0 + +- name: A deficiency of exactly $10 is paid. + period: 2025-01 + input: + va_tanf_eligibility: true + va_up_tanf_eligibility: false + va_tanf_grant_standard: 500 + va_tanf_up_grant_standard: 0 + va_tanf_countable_income: 490 + county_str: PITTSYLVANIA_COUNTY_VA + output: + # $500 - $490 = $10 + va_tanf: 10 + +- name: The payment is rounded down to the next lower dollar. + period: 2025-01 + input: + va_tanf_eligibility: true + va_up_tanf_eligibility: false + va_tanf_grant_standard: 481.635 + va_tanf_up_grant_standard: 0 + va_tanf_countable_income: 100 + county_str: PITTSYLVANIA_COUNTY_VA + output: + # $481.635 - $100 = $381.635, rounded down to $381 + va_tanf: 381 + # Max payment cap tests -- max payment = ceil(base_max * standard_multiplier) # For 2023: multiplier is 1.155 for all 12 months # Group III TANF: ceil(745*1.155)=861 diff --git a/policyengine_us/variables/gov/states/md/tca/md_tca.py b/policyengine_us/variables/gov/states/md/tca/md_tca.py index 2977afc6451..30a8a600fda 100644 --- a/policyengine_us/variables/gov/states/md/tca/md_tca.py +++ b/policyengine_us/variables/gov/states/md/tca/md_tca.py @@ -14,4 +14,8 @@ def formula(spm_unit, period, parameters): grant_standard = spm_unit("md_tca_maximum_benefit", period) countable_income = spm_unit("md_tca_countable_income", period) benefit = max_(grant_standard - countable_income, 0) - return min_(benefit, grant_standard) + capped_benefit = min_(benefit, grant_standard) + # A benefit is issued only when the unit is eligible for at least + # the minimum (COMAR 07.03.03.13 E(2)). + p = parameters(period).gov.states.md.tca + return where(capped_benefit >= p.minimum_payment, capped_benefit, 0) diff --git a/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.py b/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.py index 37b5286e6a9..39fc8231828 100644 --- a/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.py +++ b/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.py @@ -13,9 +13,9 @@ class mi_fip_income_eligible(Variable): defined_for = StateCode.MI def formula(spm_unit, period, parameters): - # BEM 518 Page 3: Financial need exists when the group passes - # the Qualifying Deficit Test (initial) or Issuance Deficit Test (ongoing) - + # BEM 518: Financial need exists when the group passes the Issuance + # Deficit Test and, at application, the Qualifying Deficit Test. + p = parameters(period).gov.states.mi.mdhhs.fip enrolled = spm_unit("is_tanf_enrolled", period) payment_standard = spm_unit("mi_fip_payment_standard", period) @@ -26,12 +26,15 @@ def formula(spm_unit, period, parameters): ) passes_qualifying_test = countable_income_for_eligibility < payment_standard - # Enrolled recipients: Use Issuance Deficit Test (BEM 520 Section D) + # All groups: Issuance Deficit Test (BEM 520 Section D) # - Uses 50% deduction rate (more generous) + # - BEM 518: the deficit must be at least $10 countable_income_for_benefit = spm_unit( "mi_fip_countable_income_for_benefit", period ) - passes_issuance_test = countable_income_for_benefit < payment_standard + issuance_deficit = payment_standard - countable_income_for_benefit + passes_issuance_test = issuance_deficit >= p.minimum_payment - # Return appropriate test based on enrollment status - return where(enrolled, passes_issuance_test, passes_qualifying_test) + # Applicants must pass both tests; enrolled recipients only the + # Issuance Deficit Test. + return passes_issuance_test & (enrolled | passes_qualifying_test) diff --git a/policyengine_us/variables/gov/states/mi/mdhhs/fip/mi_fip.py b/policyengine_us/variables/gov/states/mi/mdhhs/fip/mi_fip.py index ee0f03186f5..bc24c71240f 100644 --- a/policyengine_us/variables/gov/states/mi/mdhhs/fip/mi_fip.py +++ b/policyengine_us/variables/gov/states/mi/mdhhs/fip/mi_fip.py @@ -23,7 +23,8 @@ def formula(spm_unit, period, parameters): payment_standard = spm_unit("mi_fip_payment_standard", period) countable_income = spm_unit("mi_fip_countable_income_for_benefit", period) - # BEM 518: Minimum benefit requirement is $10 deficit + # BEM 518: a deficit under $10 fails the Issuance Deficit Test, + # so such groups are not eligible (mi_fip_income_eligible). # Negative benefits are set to 0 benefit = max_(payment_standard - countable_income, 0) return min_(benefit, payment_standard) diff --git a/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py b/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py index 061c427ad58..fe92a598b39 100644 --- a/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py +++ b/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py @@ -22,4 +22,7 @@ def formula(spm_unit, period, parameters): benefit = excess_income * p.payment.rate # Cap benefit at need standard to prevent negative income # from inflating benefits above the maximum. - return min_(benefit, need_standard * p.payment.rate) + capped_benefit = min_(benefit, need_standard * p.payment.rate) + # No payment is made in a month when the benefit is under the + # minimum (S.C. Code Regs. 114-1140(A)(5); TANF Policy Manual 8.16 I). + return where(capped_benefit >= p.minimum_payment, capped_benefit, 0) diff --git a/policyengine_us/variables/gov/states/va/dss/tanf/va_tanf.py b/policyengine_us/variables/gov/states/va/dss/tanf/va_tanf.py index dd1c87411a4..d79cd7c29ed 100644 --- a/policyengine_us/variables/gov/states/va/dss/tanf/va_tanf.py +++ b/policyengine_us/variables/gov/states/va/dss/tanf/va_tanf.py @@ -42,4 +42,8 @@ def formula(spm_unit, period, parameters): ) maximum = np.ceil(base_max * p.standard_multiplier) - return min_(payment, maximum) + # The payment is the budgetary deficiency adjusted to the next lower + # dollar; no payment is made when it is under the minimum, but the + # unit stays eligible (TANF Manual 502.1 A). + capped_payment = np.floor(min_(payment, maximum)) + return where(capped_payment >= p.minimum_payment, capped_payment, 0) From d54735d200fb2dbb1685d1eac5656ee36c662c17 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 27 Oct 2026 11:07:38 -0400 Subject: [PATCH 2/2] Address review: neutral VA TANF-UP case, whole-dollar VA tests, MD income rounding - va_tanf.yaml: the edited TANF-UP case no longer asserts which standard a TANF-UP unit gets (both standards are $2,400), so it holds with and without #10253. The 2025 rounding tests use the printed 7/22 Appendix 2 standard ($482); the $381 case floors $381.60 on income cents. - va_tanf: round the capped payment to cents before the floor, so float error does not drop a dollar. The $10,000 / $4,000 case is restored. - md_tca: round net countable income down to the dollar before it is deducted (COMAR 07.03.03.13 E(1)); new cases at $438.50 and $200.75. - sc_tanf.yaml: a $9.99 / $10.30 pair at the minimum, and comments on the unmodeled 114-1140(A)(4) rounding. - References: one BEM 518 entry (#page 2-4); cite Chapter 500, Chapter 114 and COMAR .13 in the variable references. Co-Authored-By: Claude Opus 5.5 --- .../fix-9985-tanf-10-dollar-minimum.fixed.md | 2 +- .../states/mi/mdhhs/fip/minimum_payment.yaml | 4 +- .../baseline/gov/states/md/tca/md_tca.yaml | 46 ++++++++++++++++- .../baseline/gov/states/sc/tanf/sc_tanf.yaml | 51 +++++++++++++++++++ .../gov/states/va/dss/tanf/va_tanf.yaml | 29 ++++++----- .../variables/gov/states/md/tca/md_tca.py | 12 ++++- .../fip/eligibility/mi_fip_income_eligible.py | 3 +- .../variables/gov/states/sc/tanf/sc_tanf.py | 4 +- .../gov/states/va/dss/tanf/va_tanf.py | 10 ++-- 9 files changed, 137 insertions(+), 24 deletions(-) diff --git a/changelog.d/fix-9985-tanf-10-dollar-minimum.fixed.md b/changelog.d/fix-9985-tanf-10-dollar-minimum.fixed.md index b6ad835cd61..e1894e18bed 100644 --- a/changelog.d/fix-9985-tanf-10-dollar-minimum.fixed.md +++ b/changelog.d/fix-9985-tanf-10-dollar-minimum.fixed.md @@ -1 +1 @@ -Apply the $10 minimum payment in Michigan FIP (BEM 518 issuance deficit test), Virginia TANF (TANF Manual 502.1 A, with the payment rounded down to whole dollars), South Carolina TANF (S.C. Code Regs. 114-1140(A)(5)) and Maryland TCA (COMAR 07.03.03.13 E(2)). +Apply the $10 minimum payment in Michigan FIP (BEM 518 issuance deficit test), Virginia TANF (TANF Manual 502.1 A, with the payment rounded down to whole dollars), South Carolina TANF (S.C. Code Regs. 114-1140(A)(5)) and Maryland TCA (COMAR 07.03.03.13 E(2), with net countable income rounded down to whole dollars under E(1)). diff --git a/policyengine_us/parameters/gov/states/mi/mdhhs/fip/minimum_payment.yaml b/policyengine_us/parameters/gov/states/mi/mdhhs/fip/minimum_payment.yaml index b4403a25b8c..647e7e2eb51 100644 --- a/policyengine_us/parameters/gov/states/mi/mdhhs/fip/minimum_payment.yaml +++ b/policyengine_us/parameters/gov/states/mi/mdhhs/fip/minimum_payment.yaml @@ -9,7 +9,5 @@ metadata: period: month label: Michigan FIP minimum issuance deficit reference: - - title: Michigan DHHS BEM 518 - FIP/RCA/SDA Income Budgeting, Financial Need and Issuance Deficit Test + - title: "Michigan DHHS BEM 518 - FIP/RCA/SDA Income Budgeting, Financial Need #page 2-4" href: https://mdhhs-pres-prod.michigan.gov/olmweb/ex/BP/Public/BEM/518.pdf#page=2 - - title: Michigan DHHS BEM 518 - FIP/RCA/SDA Income Budgeting, Benefit Amount - href: https://mdhhs-pres-prod.michigan.gov/olmweb/ex/BP/Public/BEM/518.pdf#page=4 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/tca/md_tca.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/tca/md_tca.yaml index 23e88dc5f1e..03db1d9171c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/md/tca/md_tca.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/md/tca/md_tca.yaml @@ -89,7 +89,9 @@ household: state_code: MD output: - # Benefit = $448 - $443.20 = $4.80, under $10 (COMAR 07.03.03.13 E(2)) + # Net countable income $443.20 is rounded down to $443 + # (COMAR 07.03.03.13 E(1)). + # Benefit = $448 - $443 = $5, under $10 (COMAR 07.03.03.13 E(2)) md_tca: 0 - name: Case 6, a benefit of exactly $10 is issued. @@ -110,3 +112,45 @@ output: # Benefit = $448 - $438 = $10 md_tca: 10 + +- name: Case 7, net countable income is rounded down before it is deducted. + period: 2025-01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + md_tca_eligible: true + md_tca_maximum_benefit: 448 + md_tca_countable_income: 438.5 + households: + household: + state_code: MD + output: + # Net countable income $438.50 is rounded down to $438 + # (COMAR 07.03.03.13 E(1)). + # Benefit = $448 - $438 = $10, which is issued (E(2)). Without the + # rounding, $448 - $438.50 = $9.50 would not be issued. + md_tca: 10 + +- name: Case 8, a benefit above the minimum uses the rounded-down income. + period: 2024-01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + md_tca_eligible: true + md_tca_maximum_benefit: 727 + md_tca_countable_income: 200.75 + households: + household: + state_code: MD + output: + # Net countable income $200.75 is rounded down to $200. + # Benefit = $727 - $200 = $527 + md_tca: 527 diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml index 24218469053..0a8b53f3c1d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml @@ -82,4 +82,55 @@ output: # Need standard for 2 (2025-01) = $851.67 # Benefit = ($851.67 - $820) * 0.4046 = $12.81 + # The rule rounds the need standard and benefit down + # (114-1140(A)(4)), which is not modeled: + # (851 - 820) * 0.4046 = 12.54, so $12. sc_tanf: 12.81 + +- name: Case 6, a benefit of $9.99 is not paid. + absolute_error_margin: 0.01 + period: 2025-01 + input: + people: + parent: + age: 30 + child: + age: 5 + spm_units: + spm_unit: + members: [parent, child] + sc_tanf_countable_income: 826.98 + sc_tanf_eligible: true + households: + household: + members: [parent, child] + state_code: SC + output: + # Need standard for 2 (2025-01) = $851.67 + # Benefit = ($851.67 - $826.98) * 0.4046 = $9.99, under $10 + sc_tanf: 0 + +- name: Case 7, a benefit just over $10 is paid. + absolute_error_margin: 0.01 + period: 2025-01 + input: + people: + parent: + age: 30 + child: + age: 5 + spm_units: + spm_unit: + members: [parent, child] + sc_tanf_countable_income: 826.2 + sc_tanf_eligible: true + households: + household: + members: [parent, child] + state_code: SC + output: + # Need standard for 2 (2025-01) = $851.67 + # Benefit = ($851.67 - $826.20) * 0.4046 = $10.30, at least $10 + # With the 114-1140(A)(4) rounding, which is not modeled: + # (851 - 826.20) * 0.4046 = 10.03, so $10, which is also paid. + sc_tanf: 10.30 diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/va_tanf.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/va_tanf.yaml index 86e481883c2..483162c2dfd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/va_tanf.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/va/dss/tanf/va_tanf.yaml @@ -24,17 +24,19 @@ # or $8.33 a month, under the $10 minimum (TANF Manual 502.1 A.2) va_tanf: 0 -- name: If up tanf eligible before July 2022, the UP grant standard applies. +- name: If up tanf eligible, the payment is the grant standard less countable income. period: 2021 input: va_tanf_eligibility: true va_up_tanf_eligibility: true - va_tanf_grant_standard: 0 + va_tanf_grant_standard: 2_400 va_tanf_up_grant_standard: 2_400 va_tanf_countable_income: 1_200 county_str: ARLINGTON_COUNTY_VA output: - # UP grant standard $2,400 - countable income $1,200 = $1,200 payment + # The TANF and UP grant standards are equal, so the result does not + # depend on which standard a TANF-UP unit gets. + # Grant standard $2,400 - countable income $1,200 = $1,200 payment # ($200 - $100 = $100 a month, below the monthly maximum) va_tanf: 1_200 @@ -43,12 +45,14 @@ input: va_tanf_eligibility: true va_up_tanf_eligibility: false - va_tanf_grant_standard: 12_000 + va_tanf_grant_standard: 10_000 va_tanf_up_grant_standard: 0 - va_tanf_countable_income: 6_000 + va_tanf_countable_income: 4_000 county_str: ARLINGTON_COUNTY_VA output: - # $1,000 - $500 = $500 a month + # $833.33 - $333.33 = $500 a month. The payment is rounded to cents + # before it is adjusted to the lower dollar, so float error in the + # monthly amounts does not drop it to $499. va_tanf: 6_000 - name: Grant equals countable income. @@ -77,19 +81,20 @@ # Payment rounding and minimum (TANF Manual 502.1 A): the budgetary # deficiency is adjusted to the next lower dollar, and no payment is made -# when it is under $10. +# when it is under $10. The $482 grant standard is the 7/22 Section 304, +# Appendix 2 standard for a Group II unit of three. - name: A deficiency under $10 is not paid. period: 2025-01 input: va_tanf_eligibility: true va_up_tanf_eligibility: false - va_tanf_grant_standard: 481.635 + va_tanf_grant_standard: 482 va_tanf_up_grant_standard: 0 va_tanf_countable_income: 479.2 county_str: PITTSYLVANIA_COUNTY_VA output: - # $481.635 - $479.20 = $2.435, under $10 + # $482 - $479.20 = $2.80, under $10 va_tanf: 0 - name: A deficiency of $9.99 is not paid. @@ -123,12 +128,12 @@ input: va_tanf_eligibility: true va_up_tanf_eligibility: false - va_tanf_grant_standard: 481.635 + va_tanf_grant_standard: 482 va_tanf_up_grant_standard: 0 - va_tanf_countable_income: 100 + va_tanf_countable_income: 100.4 county_str: PITTSYLVANIA_COUNTY_VA output: - # $481.635 - $100 = $381.635, rounded down to $381 + # $482 - $100.40 = $381.60, rounded down to $381 va_tanf: 381 # Max payment cap tests -- max payment = ceil(base_max * standard_multiplier) diff --git a/policyengine_us/variables/gov/states/md/tca/md_tca.py b/policyengine_us/variables/gov/states/md/tca/md_tca.py index 30a8a600fda..63f204c8afd 100644 --- a/policyengine_us/variables/gov/states/md/tca/md_tca.py +++ b/policyengine_us/variables/gov/states/md/tca/md_tca.py @@ -8,11 +8,19 @@ class md_tca(Variable): unit = USD definition_period = MONTH defined_for = "md_tca_eligible" - reference = "https://dsd.maryland.gov/regulations/Pages/07.03.03.17.aspx" + reference = ( + "https://dsd.maryland.gov/regulations/Pages/07.03.03.13.aspx", + "https://dsd.maryland.gov/regulations/Pages/07.03.03.17.aspx", + ) def formula(spm_unit, period, parameters): grant_standard = spm_unit("md_tca_maximum_benefit", period) - countable_income = spm_unit("md_tca_countable_income", period) + # Net countable income is rounded down to the nearest dollar before + # it is deducted (COMAR 07.03.03.13 E(1)). Rounding to cents first + # keeps float error from moving the income to the dollar below. + countable_income = np.floor( + np.round(spm_unit("md_tca_countable_income", period), 2) + ) benefit = max_(grant_standard - countable_income, 0) capped_benefit = min_(benefit, grant_standard) # A benefit is issued only when the unit is eligible for at least diff --git a/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.py b/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.py index 39fc8231828..8b45695252d 100644 --- a/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.py +++ b/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_income_eligible.py @@ -7,7 +7,8 @@ class mi_fip_income_eligible(Variable): label = "Eligible for Michigan FIP based on income" definition_period = MONTH reference = ( - "https://mdhhs-pres-prod.michigan.gov/olmweb/ex/BP/Public/BEM/518.pdf#page=5", + # PDF pages 2-5 + "https://mdhhs-pres-prod.michigan.gov/olmweb/ex/BP/Public/BEM/518.pdf#page=2", "https://mdhhs-pres-prod.michigan.gov/olmweb/EX/BP/Public/BEM/520.pdf#page=3", ) defined_for = StateCode.MI diff --git a/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py b/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py index fe92a598b39..c400fe1f4f3 100644 --- a/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py +++ b/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py @@ -9,7 +9,9 @@ class sc_tanf(Variable): definition_period = MONTH defined_for = "sc_tanf_eligible" reference = ( - "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131" + # PDF pages 131, 133 + "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131", + "https://www.scstatehouse.gov/coderegs/Chapter%20114.pdf#page=210", ) def formula(spm_unit, period, parameters): diff --git a/policyengine_us/variables/gov/states/va/dss/tanf/va_tanf.py b/policyengine_us/variables/gov/states/va/dss/tanf/va_tanf.py index d79cd7c29ed..ab1f4ca9e2a 100644 --- a/policyengine_us/variables/gov/states/va/dss/tanf/va_tanf.py +++ b/policyengine_us/variables/gov/states/va/dss/tanf/va_tanf.py @@ -8,7 +8,10 @@ class va_tanf(Variable): unit = USD definition_period = MONTH defined_for = "va_tanf_eligibility" - reference = "https://www.dss.virginia.gov/media/vdss/benefit-programs/documents/tanfx2fview/tanf/Chapter-300---Need-and-Amount-of-Assistance.pdf#page=51" + reference = ( + "https://www.dss.virginia.gov/media/vdss/benefit-programs/documents/tanfx2fview/tanf/Chapter-300---Need-and-Amount-of-Assistance.pdf#page=51", + "https://www.dss.virginia.gov/media/vdss/benefit-programs/documents/tanfview/tanf/Chapter-500---Authorization-and-Payment.pdf#page=3", + ) def formula(spm_unit, period, parameters): # the calculated payment @@ -44,6 +47,7 @@ def formula(spm_unit, period, parameters): # The payment is the budgetary deficiency adjusted to the next lower # dollar; no payment is made when it is under the minimum, but the - # unit stays eligible (TANF Manual 502.1 A). - capped_payment = np.floor(min_(payment, maximum)) + # unit stays eligible (TANF Manual 502.1 A). Rounding to cents first + # keeps float error from dropping a whole dollar. + capped_payment = np.floor(np.round(min_(payment, maximum), 2)) return where(capped_payment >= p.minimum_payment, capped_payment, 0)