diff --git a/changelog.d/round-summed-limits.fixed.md b/changelog.d/round-summed-limits.fixed.md new file mode 100644 index 00000000000..a78a2e3c648 --- /dev/null +++ b/changelog.d/round-summed-limits.fixed.md @@ -0,0 +1 @@ +Round summed resources to whole cents before SSI, SNAP, Medicaid, Medicare Savings Program and state asset tests compare them with their dollar limits, so balances that add to exactly a limit pass or fail as the total does. A child's share of parental resources stays unrounded and is compared exactly. diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medically_needy/is_medically_needy_for_medicaid.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medically_needy/is_medically_needy_for_medicaid.yaml index a3934f084f7..7331422ee87 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medically_needy/is_medically_needy_for_medicaid.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medically_needy/is_medically_needy_for_medicaid.yaml @@ -940,3 +940,219 @@ # 2027 still reads the 195,000 couple limit; 31,000 first applies in 2028. is_in_medicaid_medically_needy_category: [true, true] is_medically_needy_for_medicaid: [true, true] + +# Hawaii's 2,000 individual asset limit: 178.57 + 1,547.79 + 273.64 = +# 2,000.00. The float32 balances add to 2,000.0001 unless rounded to cents. +- name: Three accounts that total exactly the Hawaii limit pass + period: 2026 + input: + is_disabled: true + meets_ssi_disability_criteria: true + is_in_medicaid_medically_needy_category: true + is_adult_for_medicaid: false + is_optional_senior_or_disabled_for_medicaid: false + ssi_countable_income: 0 + bank_account_assets: 178.57 + stock_assets: 1_547.79 + bond_assets: 273.64 + state_code: HI + output: + is_medically_needy_for_medicaid: true + +# 178.57 + 1,547.79 + 273.65 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the Hawaii limit fail + period: 2026 + input: + is_disabled: true + meets_ssi_disability_criteria: true + is_in_medicaid_medically_needy_category: true + is_adult_for_medicaid: false + is_optional_senior_or_disabled_for_medicaid: false + ssi_countable_income: 0 + bank_account_assets: 178.57 + stock_assets: 1_547.79 + bond_assets: 273.65 + state_code: HI + output: + is_medically_needy_for_medicaid: false + + +# A child's resources include the SSI parental share (Cases 5 and 6). The +# first child's own income is too high for SSI, as in Case 5, so they don't +# count in the division but are still deemed the share the three SSI-eligible +# siblings divide (SI 01330.200 B, which sets no rounding rule for a share). +# The parent's 2,100 is 100 over the SSI individual allowance, so the share +# is 100 / 3 = 33.3333. The first child's 1,966.67 in one account plus the +# share is 2,000.0033, over Massachusetts's 2,000 limit. The siblings receive +# SSI, so they qualify through that pathway instead; the parent's 80,000 of +# wages keeps the children out of the MAGI child groups. +- name: Case 37, a fractional parental share counts against a disabled child's asset limit. + period: 2026 + input: + people: + parent: + age: 40 + is_tax_unit_head: true + is_parent: true + employment_income_before_lsr: 80_000 + bank_account_assets: 2_100 + child1: + age: 8 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 21_358 + medicaid_medically_needy_medical_expenses: 16_000 + is_optional_senior_or_disabled_for_medicaid: false + bank_account_assets: 1_966.67 + child2: + age: 10 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 0 + is_optional_senior_or_disabled_for_medicaid: false + child3: + age: 12 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 0 + is_optional_senior_or_disabled_for_medicaid: false + child4: + age: 14 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 0 + is_optional_senior_or_disabled_for_medicaid: false + tax_units: + tax_unit: + members: [parent, child1, child2, child3, child4] + marital_units: + parent_unit: + members: [parent] + child1_unit: + members: [child1] + child2_unit: + members: [child2] + child3_unit: + members: [child3] + child4_unit: + members: [child4] + households: + household: + members: [parent, child1, child2, child3, child4] + state_code: MA + output: + ssi_resources_deemed_from_ineligible_parent: + 2026-01: [0, 33.3333, 33.3333, 33.3333, 33.3333] + is_medically_needy_for_medicaid: [false, false, false, false, false] + +# With four SSI-eligible siblings the parent's 100 of excess divides as 25 +# each. The first child's 178.57 + 1,522.79 + 273.64 = 1,975.00 plus 25 is +# 2,000.00, at the limit, and income 21,358 - 16,000 = 5,358 <= 6,264 as in +# Case 5. That child's float32 balances add to 1,975.0001 unless rounded to +# cents. +- name: Case 38, a disabled child's accounts plus a whole-cent parental share at the asset limit qualify. + period: 2026 + input: + people: + parent: + age: 40 + is_tax_unit_head: true + is_parent: true + employment_income_before_lsr: 80_000 + bank_account_assets: 2_100 + child1: + age: 8 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 21_358 + medicaid_medically_needy_medical_expenses: 16_000 + is_optional_senior_or_disabled_for_medicaid: false + bank_account_assets: 178.57 + stock_assets: 1_522.79 + bond_assets: 273.64 + child2: + age: 10 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 0 + is_optional_senior_or_disabled_for_medicaid: false + child3: + age: 12 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 0 + is_optional_senior_or_disabled_for_medicaid: false + child4: + age: 14 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 0 + is_optional_senior_or_disabled_for_medicaid: false + child5: + age: 16 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 0 + is_optional_senior_or_disabled_for_medicaid: false + tax_units: + tax_unit: + members: [parent, child1, child2, child3, child4, child5] + marital_units: + parent_unit: + members: [parent] + child1_unit: + members: [child1] + child2_unit: + members: [child2] + child3_unit: + members: [child3] + child4_unit: + members: [child4] + child5_unit: + members: [child5] + households: + household: + members: [parent, child1, child2, child3, child4, child5] + state_code: MA + output: + ssi_resources_deemed_from_ineligible_parent: + 2026-01: [0, 25, 25, 25, 25, 25] + is_medically_needy_for_medicaid: [false, true, false, false, false, false] + +# The parent's 2,100.01 is 100.01 over the SSI individual allowance, all +# deemed to the only child, whose own income is too high for SSI. The +# child's 1,899.99 plus 100.01 is exactly 2,000.00, at the limit. +- name: Case 39, a disabled child's whole-cent parental share that reaches the asset limit exactly qualifies. + period: 2026 + input: + people: + parent: + age: 40 + is_tax_unit_head: true + is_parent: true + employment_income_before_lsr: 80_000 + bank_account_assets: 2_100.01 + child1: + age: 8 + is_tax_unit_dependent: true + is_ssi_disabled: true + ssi_countable_income: 21_358 + medicaid_medically_needy_medical_expenses: 16_000 + is_optional_senior_or_disabled_for_medicaid: false + bank_account_assets: 1_899.99 + tax_units: + tax_unit: + members: [parent, child1] + marital_units: + parent_unit: + members: [parent] + child1_unit: + members: [child1] + households: + household: + members: [parent, child1] + state_code: MA + output: + ssi_resources_deemed_from_ineligible_parent: + 2026-01: [0, 100.01] + is_medically_needy_for_medicaid: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicare/savings_programs/eligibility/msp_asset_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicare/savings_programs/eligibility/msp_asset_eligible.yaml index feaba98d662..e932d51a68d 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicare/savings_programs/eligibility/msp_asset_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicare/savings_programs/eligibility/msp_asset_eligible.yaml @@ -437,3 +437,30 @@ # July 2027; resources may not exceed it. msp_asset_eligible: 2027-07: [true, true] + +# 42 U.S.C. 1396d(p)(1)(C): 2,885.40 + 5,798.41 + 976.19 = 9,660.00, at the +# 2025 individual limit. The float32 balances add to 9,660.001 unless rounded. +- name: Three accounts that total exactly the individual limit pass + period: 2025-01 + input: + age: 67 + bank_account_assets: 2_885.40 + stock_assets: 5_798.41 + bond_assets: 976.19 + spm_unit_is_married: false + state_code: TX + output: + msp_asset_eligible: true + +# 2,885.40 + 5,798.41 + 976.20 = 9,660.01, a cent over the limit. +- name: Three accounts a cent over the individual limit fail + period: 2025-01 + input: + age: 67 + bank_account_assets: 2_885.40 + stock_assets: 5_798.41 + bond_assets: 976.20 + spm_unit_is_married: false + state_code: TX + output: + msp_asset_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/tanf/non_cash/meets_tanf_non_cash_asset_test.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/tanf/non_cash/meets_tanf_non_cash_asset_test.yaml index 9a37b0b65a0..fc4e1b64f1a 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/tanf/non_cash/meets_tanf_non_cash_asset_test.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/tanf/non_cash/meets_tanf_non_cash_asset_test.yaml @@ -106,3 +106,26 @@ household_vehicles_value: 18_000 output: meets_tanf_non_cash_asset_test: true + +# Idaho's 5,000 BBCE asset limit: 4,338.99 + 609.03 + 51.98 = 5,000.00. +# The float32 balances add to 5,000.0005 unless rounded to cents. +- name: Three accounts that total exactly the Idaho limit pass + period: 2026 + input: + state_code_str: ID + bank_account_assets: 4_338.99 + stock_assets: 609.03 + bond_assets: 51.98 + output: + meets_tanf_non_cash_asset_test: true + +# 4,338.99 + 609.03 + 51.99 = 5,000.01, a cent over the limit. +- name: Three accounts a cent over the Idaho limit fail + period: 2026 + input: + state_code_str: ID + bank_account_assets: 4_338.99 + stock_assets: 609.03 + bond_assets: 51.99 + output: + meets_tanf_non_cash_asset_test: false diff --git a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_parent.yaml b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_parent.yaml index 7d42e07cc67..515fd731e6b 100644 --- a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_parent.yaml +++ b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_parent.yaml @@ -397,6 +397,346 @@ ssi_resources_deemed_from_ineligible_parent: [0, 500, 0, 500, 0, 500] meets_ssi_resource_test: [false, true, false, true, false, false] +# 20 CFR 416.1202(b)(1), 416.1205: the child's 575.52 + 570.57 + 353.91 = +# 1,500.00 plus parental excess 2,500 - 2,000 = 500 is 2,000.00, at the +# individual limit. The child's float32 balances add to 1,500.0001 unless +# rounded to cents. +- name: Child accounts plus parental excess that total exactly the limit pass + period: 2026-01 + input: + people: + parent: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_head: true + is_parent: true + bank_account_assets: 2_500 + child: + age: 16 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 575.52 + stock_assets: 570.57 + bond_assets: 353.91 + tax_units: + tax_unit: + members: [parent, child] + marital_units: + parent_unit: + members: [parent] + child_unit: + members: [child] + households: + household: + members: [parent, child] + output: + ssi_resources_deemed_from_ineligible_parent: [0, 500] + meets_ssi_resource_test: [false, true] + +# The child's 575.52 + 570.57 + 353.92 = 1,500.01 plus the same 500 is +# 2,000.01, a cent over the individual limit. +- name: Child accounts plus parental excess a cent over the limit fail + period: 2026-01 + input: + people: + parent: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_head: true + is_parent: true + bank_account_assets: 2_500 + child: + age: 16 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 575.52 + stock_assets: 570.57 + bond_assets: 353.92 + tax_units: + tax_unit: + members: [parent, child] + marital_units: + parent_unit: + members: [parent] + child_unit: + members: [child] + households: + household: + members: [parent, child] + output: + ssi_resources_deemed_from_ineligible_parent: [0, 500] + meets_ssi_resource_test: [false, false] + +# POMS SI 01330.200 B: 'equally divide the value of the deemed resources +# among those children'; 20 CFR 416.1202(b)(1) sets no rounding rule for a +# child's share. The parent's 2,100 is 100 over the individual limit, so +# each of three children is deemed 100 / 3 = 33.3333. Each child holds +# 1,966.67 in one account, so the total of 2,000.0033 is over the limit. +- name: A share of parental excess counts to the fraction of a cent + period: 2026-01 + input: + people: + parent: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_head: true + is_parent: true + bank_account_assets: 2_100 + child1: + age: 8 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 1_966.67 + child2: + age: 10 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 1_966.67 + child3: + age: 12 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 1_966.67 + tax_units: + tax_unit: + members: [parent, child1, child2, child3] + marital_units: + parent_unit: + members: [parent] + child1_unit: + members: [child1] + child2_unit: + members: [child2] + child3_unit: + members: [child3] + households: + household: + members: [parent, child1, child2, child3] + output: + ssi_resources_deemed_from_ineligible_parent: [0, 33.3333, 33.3333, 33.3333] + meets_ssi_resource_test: [false, false, false, false] + +# SI 01330.200 B: when a child is ineligible, 'divide the value of the deemed +# resources among the remaining eligible children'. The first child's +# 1,966.67 plus the exact share of 33.3333 is over the limit, so that child +# leaves the division and keeps the share last tested; the other two +# children, who hold nothing, divide the 100 as 50 each. +- name: A child whom an unrounded share takes over the limit leaves the division + period: 2026-01 + input: + people: + parent: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_head: true + is_parent: true + bank_account_assets: 2_100 + child1: + age: 8 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 1_966.67 + child2: + age: 10 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + child3: + age: 12 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1, child2, child3] + marital_units: + parent_unit: + members: [parent] + child1_unit: + members: [child1] + child2_unit: + members: [child2] + child3_unit: + members: [child3] + households: + household: + members: [parent, child1, child2, child3] + output: + ssi_resources_deemed_from_ineligible_parent: [0, 33.3333, 50, 50] + meets_ssi_resource_test: [false, false, true, true] + +# The parent's 2,100 is 100 over the individual limit, which divides among +# four children as 25 each. The first child's 178.57 + 1,522.79 + 273.64 = +# 1,975.00 plus 25 is 2,000.00, at the limit. That child's float32 balances +# add to 1,975.0001 unless rounded to cents. +- name: Child accounts plus a share of parental excess that total exactly the limit pass + period: 2026-01 + input: + people: + parent: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_head: true + is_parent: true + bank_account_assets: 2_100 + child1: + age: 8 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 178.57 + stock_assets: 1_522.79 + bond_assets: 273.64 + child2: + age: 10 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + child3: + age: 12 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + child4: + age: 14 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1, child2, child3, child4] + marital_units: + parent_unit: + members: [parent] + child1_unit: + members: [child1] + child2_unit: + members: [child2] + child3_unit: + members: [child3] + child4_unit: + members: [child4] + households: + household: + members: [parent, child1, child2, child3, child4] + output: + ssi_resources_deemed_from_ineligible_parent: [0, 25, 25, 25, 25] + meets_ssi_resource_test: [false, true, true, true, true] + +# 20 CFR 416.1202(b)(1): the parent's 2,100.01 is 100.01 over the +# individual limit, all deemed to the only child, whose 1,899.99 brings the +# total to exactly 2,000.00. Stored as the nearest float32, the 100.01 share +# would read back as 100.010002 and push that total over the limit. +- name: A whole-cent parental share that brings a child exactly to the limit passes + period: 2026-01 + input: + people: + parent: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_head: true + is_parent: true + bank_account_assets: 2_100.01 + child: + age: 16 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 1_899.99 + tax_units: + tax_unit: + members: [parent, child] + marital_units: + parent_unit: + members: [parent] + child_unit: + members: [child] + households: + household: + members: [parent, child] + output: + ssi_resources_deemed_from_ineligible_parent: [0, 100.01] + meets_ssi_resource_test: [false, true] + +# SI 01330.200 B: the parent's 2,048.30 is 48.30 over the individual limit, +# which divides among three children as 16.10 each. The first child's +# 1,983.90 plus 16.10 is exactly 2,000.00, so all three stay in the division +# and pass. In float64, 2,048.30 - 2,000 gives an excess of 48.30000000000018, +# and 1,983.90 plus a third of it gives 2,000.0000000000002, which would +# remove the first child and raise the others' shares. +- name: A child whom a share reaches exactly to the limit stays in the division + period: 2026-01 + input: + people: + parent: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_head: true + is_parent: true + bank_account_assets: 2_048.30 + child1: + age: 8 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 1_983.90 + child2: + age: 10 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 1_980 + child3: + age: 12 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1, child2, child3] + marital_units: + parent_unit: + members: [parent] + child1_unit: + members: [child1] + child2_unit: + members: [child2] + child3_unit: + members: [child3] + households: + household: + members: [parent, child1, child2, child3] + output: + ssi_resources_deemed_from_ineligible_parent: [0, 16.10, 16.10, 16.10] + meets_ssi_resource_test: [false, true, true, true] + +# 20 CFR 416.1202(b)(1): the child's own 178.57 + 1,547.79 + 273.64 = +# 2,000.00 is at the individual limit, so the child is deemed the parent's +# 100 of excess and fails at 2,100.00. The float32 balances add to +# 2,000.0001 unless rounded to cents, which would leave the child out of the +# deeming and pass them on their own 2,000.00. +- name: A child whose own accounts total exactly the limit is still deemed the parental excess + period: 2026-01 + input: + people: + parent: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_head: true + is_parent: true + bank_account_assets: 2_100 + child: + age: 16 + is_ssi_aged_blind_disabled: true + is_tax_unit_dependent: true + bank_account_assets: 178.57 + stock_assets: 1_547.79 + bond_assets: 273.64 + tax_units: + tax_unit: + members: [parent, child] + marital_units: + parent_unit: + members: [parent] + child_unit: + members: [child] + households: + household: + members: [parent, child] + output: + ssi_resources_deemed_from_ineligible_parent: [0, 100] + meets_ssi_resource_test: [false, false] + # POMS SI 01330.340 White example: parent pool1200 <=couple limit3000; child deemed0. - name: POMS White eligible parent leaves no excess resources to deem period: 2024-01 diff --git a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/resources/meets_ssi_resource_test.yaml b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/resources/meets_ssi_resource_test.yaml index 111d5625edf..99b9b0ac73a 100644 --- a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/resources/meets_ssi_resource_test.yaml +++ b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/resources/meets_ssi_resource_test.yaml @@ -326,3 +326,159 @@ ssi_resources_deemed_from_ineligible_parent: [0, 0, 0, 0, 0, 0, 0, 0, 0] ssi_resources_deemed_from_ineligible_spouse: [3001, 0, 0, 0, 0, 0, 0, 0, 0] meets_ssi_resource_test: [true, true, true, true, true, true, true, true, true] + +# 20 CFR 416.1205: 178.57 + 1,547.79 + 273.64 = 2,000.00, at the individual +# limit. The three float32 balances add to 2,000.0001 unless rounded to cents. +- name: Three accounts that total exactly the individual limit pass + period: 2026-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + bank_account_assets: 178.57 + stock_assets: 1_547.79 + bond_assets: 273.64 + output: + meets_ssi_resource_test: true + +# 178.57 + 1,547.79 + 273.65 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the individual limit fail + period: 2026-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + bank_account_assets: 178.57 + stock_assets: 1_547.79 + bond_assets: 273.65 + output: + meets_ssi_resource_test: false + +# 20 CFR 416.1202(a), 416.1205: the claimant's and the ineligible spouse's +# 575.52 + 570.57 + 353.91 = 1,500.00 each add to 3,000.00, at the couple +# limit. The float32 balances add to 3,000.0002 unless rounded to cents. +- name: Spousal accounts that total exactly the couple limit pass + period: 2026-01 + input: + people: + claimant: + age: 40 + is_ssi_aged_blind_disabled: true + is_tax_unit_head: true + bank_account_assets: 575.52 + stock_assets: 570.57 + bond_assets: 353.91 + spouse: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_spouse: true + bank_account_assets: 575.52 + stock_assets: 570.57 + bond_assets: 353.91 + tax_units: + family: + members: [claimant, spouse] + marital_units: + family_couple_0: + members: [claimant, spouse] + households: + family: + members: [claimant, spouse] + output: + ssi_claim_is_joint: [false, false] + meets_ssi_resource_test: [true, true] + +# The spouse's 575.52 + 570.57 + 353.92 = 1,500.01 makes 3,000.01, a cent +# over the couple limit. The spouse, who isn't aged, blind or disabled, is +# tested alone against the individual limit and passes. +- name: Spousal accounts a cent over the couple limit fail + period: 2026-01 + input: + people: + claimant: + age: 40 + is_ssi_aged_blind_disabled: true + is_tax_unit_head: true + bank_account_assets: 575.52 + stock_assets: 570.57 + bond_assets: 353.91 + spouse: + age: 40 + is_ssi_aged_blind_disabled: false + is_tax_unit_spouse: true + bank_account_assets: 575.52 + stock_assets: 570.57 + bond_assets: 353.92 + tax_units: + family: + members: [claimant, spouse] + marital_units: + family_couple_0: + members: [claimant, spouse] + households: + family: + members: [claimant, spouse] + output: + ssi_claim_is_joint: [false, false] + meets_ssi_resource_test: [false, true] + +# 20 CFR 416.1205: a jointly eligible couple's 1,500.00 in one account and +# 575.52 + 570.57 + 353.91 = 1,500.00 add to 3,000.00, at the couple limit. +# The float32 balances add to 3,000.0001 unless rounded to cents. +- name: Joint claim accounts that total exactly the couple limit pass + period: 2026-01 + input: + people: + claimant: + age: 40 + is_ssi_aged_blind_disabled: true + is_tax_unit_head: true + bank_account_assets: 1_500 + spouse: + age: 40 + is_ssi_aged_blind_disabled: true + is_tax_unit_spouse: true + bank_account_assets: 575.52 + stock_assets: 570.57 + bond_assets: 353.91 + tax_units: + family: + members: [claimant, spouse] + marital_units: + family_couple_0: + members: [claimant, spouse] + households: + family: + members: [claimant, spouse] + output: + ssi_claim_is_joint: [true, true] + meets_ssi_resource_test: [true, true] + +# The spouse's 575.52 + 570.57 + 353.92 = 1,500.01 makes 3,000.01, a cent +# over the couple limit. +- name: Joint claim accounts a cent over the couple limit fail + period: 2026-01 + input: + people: + claimant: + age: 40 + is_ssi_aged_blind_disabled: true + is_tax_unit_head: true + bank_account_assets: 1_500 + spouse: + age: 40 + is_ssi_aged_blind_disabled: true + is_tax_unit_spouse: true + bank_account_assets: 575.52 + stock_assets: 570.57 + bond_assets: 353.92 + tax_units: + family: + members: [claimant, spouse] + marital_units: + family_couple_0: + members: [claimant, spouse] + households: + family: + members: [claimant, spouse] + output: + ssi_claim_is_joint: [true, true] + meets_ssi_resource_test: [false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ak/dpa/atap/ak_atap_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ak/dpa/atap/ak_atap_resources_eligible.yaml index 7c1b7871e76..cdf490fab39 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ak/dpa/atap/ak_atap_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ak/dpa/atap/ak_atap_resources_eligible.yaml @@ -188,3 +188,28 @@ # Elderly, limit is $3,000 # $3,000 = $3,000 = eligible ak_atap_resources_eligible: true + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: AK + output: + ak_atap_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: AK + output: + ak_atap_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/dhs/tea/ar_tea_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/dhs/tea/ar_tea_resources_eligible.yaml index 3ff73c08f4c..35116efc03b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/dhs/tea/ar_tea_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/dhs/tea/ar_tea_resources_eligible.yaml @@ -95,3 +95,28 @@ output: ar_tea_resources_eligible: false # 10,000 > 3,000 -> ineligible + +# 798.28 + 2,187.62 + 14.10 = 3,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 3,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.10 + state_code: AR + output: + ar_tea_resources_eligible: true + +# 798.28 + 2,187.62 + 14.11 = 3,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.11 + state_code: AR + output: + ar_tea_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/az/hhs/tanf/az_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/az/hhs/tanf/az_tanf_resources_eligible.yaml index 253c6e15d87..13ad274e098 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/az/hhs/tanf/az_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/az/hhs/tanf/az_tanf_resources_eligible.yaml @@ -100,3 +100,28 @@ output: # $5,000 > $2,000 limit az_tanf_resources_eligible: false + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: AZ + output: + az_tanf_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: AZ + output: + az_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/capi/eligibility/ca_capi_resource_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/capi/eligibility/ca_capi_resource_eligible.yaml index e21c6962b06..2e7d8d9d241 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/capi/eligibility/ca_capi_resource_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/capi/eligibility/ca_capi_resource_eligible.yaml @@ -33,3 +33,32 @@ state_code: CA output: ca_capi_resource_eligible: false + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: CA + output: + ca_capi_resource_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: CA + output: + ca_capi_resource_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/tanf/cash/eligibility/ca_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/tanf/cash/eligibility/ca_tanf_resources_eligible.yaml index 56a3befc19b..741e139b403 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/tanf/cash/eligibility/ca_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/tanf/cash/eligibility/ca_tanf_resources_eligible.yaml @@ -143,3 +143,28 @@ # Resources: 14,000 + 501 = 14,501 exceeds the lower resource limit # but stays within the higher limit for households with an elderly member ca_tanf_resources_eligible: true + +# 8,441.48 + 8.48 + 3,687.04 = 12,137.00, at the limit. +# The float32 balances add to a fraction of a cent above 12,137 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025 + input: + age: 30 + bank_account_assets: 8_441.48 + stock_assets: 8.48 + bond_assets: 3_687.04 + state_code: CA + output: + ca_tanf_resources_eligible: true + +# 8,441.48 + 8.48 + 3,687.05 = 12,137.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025 + input: + age: 30 + bank_account_assets: 8_441.48 + stock_assets: 8.48 + bond_assets: 3_687.05 + state_code: CA + output: + ca_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/ssa/oap/co_oap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/ssa/oap/co_oap_eligible.yaml index 88b99f6d860..af164364611 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/ssa/oap/co_oap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/ssa/oap/co_oap_eligible.yaml @@ -47,3 +47,32 @@ state_code: CO output: co_oap_eligible: true + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: CO + output: + co_oap_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: CO + output: + co_oap_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ssp/eligibility/ct_ssp_resource_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ssp/eligibility/ct_ssp_resource_eligible.yaml index f1c4a0a51dc..f88d486d645 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ssp/eligibility/ct_ssp_resource_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ssp/eligibility/ct_ssp_resource_eligible.yaml @@ -204,3 +204,32 @@ output: # Married households use the $2,400 couple limit; $2,500 is ineligible. ct_ssp_resource_eligible: [false, false] + +# 1,079.68 + 511.39 + 8.93 = 1,600.00, at the limit. +# The float32 balances add to a fraction of a cent above 1,600 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_079.68 + stock_assets: 511.39 + bond_assets: 8.93 + state_code: CT + output: + ct_ssp_resource_eligible: true + +# 1,079.68 + 511.39 + 8.94 = 1,600.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_079.68 + stock_assets: 511.39 + bond_assets: 8.94 + state_code: CT + output: + ct_ssp_resource_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/tfa/eligibility/ct_tfa_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/tfa/eligibility/ct_tfa_resources_eligible.yaml index 9fbf36fe64d..65e8bf5fdc3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/tfa/eligibility/ct_tfa_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/tfa/eligibility/ct_tfa_resources_eligible.yaml @@ -123,3 +123,28 @@ output: # $5,000 > $3,000 old limit, ineligible before 10/1/2023 ct_tfa_resources_eligible: false + +# 4,489.49 + 1,282.41 + 228.10 = 6,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 6,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 4_489.49 + stock_assets: 1_282.41 + bond_assets: 228.10 + state_code: CT + output: + ct_tfa_resources_eligible: true + +# 4,489.49 + 1,282.41 + 228.11 = 6,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 4_489.49 + stock_assets: 1_282.41 + bond_assets: 228.11 + state_code: CT + output: + ct_tfa_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/dc/dhs/tanf/eligibility/dc_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/dc/dhs/tanf/eligibility/dc_tanf_resources_eligible.yaml index f316a3c6abd..004e26a22b4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/dc/dhs/tanf/eligibility/dc_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/dc/dhs/tanf/eligibility/dc_tanf_resources_eligible.yaml @@ -35,3 +35,28 @@ bank_account_assets: 2_001 output: dc_tanf_resources_eligible: false + +# 798.28 + 2,187.62 + 14.10 = 3,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 3,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.10 + state_code: DC + output: + dc_tanf_resources_eligible: true + +# 798.28 + 2,187.62 + 14.11 = 3,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.11 + state_code: DC + output: + dc_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/de/dhss/tanf/eligibility/de_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/de/dhss/tanf/eligibility/de_tanf_resources_eligible.yaml index 42366652f8c..8a0d4c517f6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/de/dhss/tanf/eligibility/de_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/de/dhss/tanf/eligibility/de_tanf_resources_eligible.yaml @@ -72,3 +72,28 @@ output: # $10,001 > $10,000 limit → ineligible de_tanf_resources_eligible: false + +# 8,688.73 + 9.74 + 1,301.53 = 10,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 10,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.53 + state_code: DE + output: + de_tanf_resources_eligible: true + +# 8,688.73 + 9.74 + 1,301.54 = 10,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.54 + state_code: DE + output: + de_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/fl/dcf/tanf/fl_tca_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/fl/dcf/tanf/fl_tca_resources_eligible.yaml index f8b813e1729..b281102d1c2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/fl/dcf/tanf/fl_tca_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/fl/dcf/tanf/fl_tca_resources_eligible.yaml @@ -69,3 +69,28 @@ state_code: FL output: fl_tca_resources_eligible: false + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: FL + output: + fl_tca_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: FL + output: + fl_tca_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/dfcs/tanf/eligibility/ga_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/dfcs/tanf/eligibility/ga_tanf_resources_eligible.yaml index 21f0ca1b77e..da1ffd0b19d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/dfcs/tanf/eligibility/ga_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/dfcs/tanf/eligibility/ga_tanf_resources_eligible.yaml @@ -29,3 +29,28 @@ spm_unit_cash_assets: 999 output: ga_tanf_resources_eligible: true + +# 650.46 + 299.64 + 49.90 = 1,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 1,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.90 + state_code: GA + output: + ga_tanf_resources_eligible: true + +# 650.46 + 299.64 + 49.91 = 1,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.91 + state_code: GA + output: + ga_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/dhs/fip/ia_fip_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/dhs/fip/ia_fip_resources_eligible.yaml index 5aab0ffe678..3e665e4b9cf 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/dhs/fip/ia_fip_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/dhs/fip/ia_fip_resources_eligible.yaml @@ -97,3 +97,28 @@ output: # At limit should be eligible (<=) ia_fip_resources_eligible: true + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: IA + output: + ia_fip_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: IA + output: + ia_fip_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml new file mode 100644 index 00000000000..3c5c7e5b0b7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml @@ -0,0 +1,96 @@ +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: IA + output: + ia_ssa_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: IA + output: + ia_ssa_eligible: false + +# ia_ssa_resources_deemed_from_parents divides the parental excess among the +# children as SSI does, and a certified share can be entered instead. A share +# of 33.3333 (100 divided among three children) plus the child's 1,966.67 in +# one account is 2,000.0033, over the limit: the share isn't rounded to +# cents, as SSI sets no rounding rule for it (SI 01330.200 B). +- name: A fractional share of parental excess counts against the resource limit + period: 2026-01 + input: + people: + parent: + age: 40 + child: + age: 10 + bank_account_assets: 1_966.67 + ia_ssa_resources_deemed_from_parents: 33.3333 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: true + meets_ssi_disability_criteria: true + marital_units: + parent_unit: + members: [parent] + child_unit: + members: [child] + tax_units: + family: + members: [parent, child] + households: + home: + members: [parent, child] + state_code: IA + output: + ia_ssa_eligible: [false, false] + +# A share of 25 (100 divided among four children) plus the child's 178.57 + +# 1,522.79 + 273.64 = 1,975.00 is 2,000.00, at the limit. The child's float32 +# balances add to 1,975.0001 unless rounded to cents. +- name: Three accounts plus a whole-cent share of parental excess at the limit pass + period: 2026-01 + input: + people: + parent: + age: 40 + child: + age: 10 + bank_account_assets: 178.57 + stock_assets: 1_522.79 + bond_assets: 273.64 + ia_ssa_resources_deemed_from_parents: 25 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: true + meets_ssi_disability_criteria: true + marital_units: + parent_unit: + members: [parent] + child_unit: + members: [child] + tax_units: + family: + members: [parent, child] + households: + home: + members: [parent, child] + state_code: IA + output: + ia_ssa_eligible: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml index a4329d445fe..f998bf24a8e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml @@ -422,3 +422,303 @@ ia_ssa_resources_deemed_from_parents: [0, 200] ia_ssa_eligible: [false, true] ia_ssa: [0, 400] + +# The parent's 1,805.81 + 244.12 + 50.07 = 2,100.00 is 100 over the one-parent +# allowance; the float32 balances add to 2,100.0002 unless rounded to cents. +# The child's 1,900 plus 100 is exactly the 2,000 limit. +- name: Case 8, a parent's three accounts at the allowance plus 100 deem exactly 100. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + bank_account_assets: + 2026: 1_805.81 + stock_assets: + 2026: 244.12 + bond_assets: + 2026: 50.07 + person2: + age: + 2026: 10 + person_id: + 2026: 2 + parent_1_id: + 2026: 1 + bank_account_assets: + 2026: 1_900 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + marital_units: + person1_unit: + members: [person1] + person2_unit: + members: [person2] + families: + family: + members: [person1, person2] + tax_units: + family: + members: [person1, person2] + spm_units: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: + 2026: IA + output: + ia_ssa_resources_deemed_from_parents: [0, 100] + ia_ssa_eligible: [false, true] + +# The parent's 2,100.01 is 100.01 over the allowance, all deemed to the only +# child, whose 1,899.99 brings the total to exactly 2,000.00. Stored as the +# nearest float32, the share would read back as 100.010002. +- name: Case 9, a whole-cent share that brings a child exactly to the limit leaves them eligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + bank_account_assets: + 2026: 2_100.01 + person2: + age: + 2026: 10 + person_id: + 2026: 2 + parent_1_id: + 2026: 1 + bank_account_assets: + 2026: 1_899.99 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + marital_units: + person1_unit: + members: [person1] + person2_unit: + members: [person2] + families: + family: + members: [person1, person2] + tax_units: + family: + members: [person1, person2] + spm_units: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: + 2026: IA + output: + ia_ssa_resources_deemed_from_parents: [0, 100.01] + ia_ssa_eligible: [false, true] + +# The parent's 100 of excess divides among four children as 25 each. The +# first child's 178.57 + 1,522.79 + 273.64 = 1,975.00 plus 25 is 2,000.00, at +# the limit; the float32 balances add to 1,975.0001 unless rounded to cents, +# which would leave the child out and deem every child 33.33. +- name: Case 10, a child whose three accounts and share total exactly the limit stays in the division. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + bank_account_assets: + 2026: 2_100 + person2: + age: + 2026: 8 + person_id: + 2026: 2 + parent_1_id: + 2026: 1 + bank_account_assets: + 2026: 178.57 + stock_assets: + 2026: 1_522.79 + bond_assets: + 2026: 273.64 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + person3: + age: + 2026: 10 + person_id: + 2026: 3 + parent_1_id: + 2026: 1 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + person4: + age: + 2026: 12 + person_id: + 2026: 4 + parent_1_id: + 2026: 1 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + person5: + age: + 2026: 14 + person_id: + 2026: 5 + parent_1_id: + 2026: 1 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + marital_units: + person1_unit: + members: [person1] + person2_unit: + members: [person2] + person3_unit: + members: [person3] + person4_unit: + members: [person4] + person5_unit: + members: [person5] + families: + family: + members: [person1, person2, person3, person4, person5] + tax_units: + family: + members: [person1, person2, person3, person4, person5] + spm_units: + unit: + members: [person1, person2, person3, person4, person5] + households: + home: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: IA + output: + ia_ssa_resources_deemed_from_parents: [0, 25, 25, 25, 25] + ia_ssa_eligible: [false, true, true, true, true] + +# The parent's 48.30 of excess divides among three children as 16.10 each. +# The first child's 1,983.90 plus 16.10 is exactly 2,000.00. In float64, +# 2,048.30 - 2,000 gives an excess of 48.30000000000018, and 1,983.90 plus a +# third of it gives 2,000.0000000000002, which would leave the first child +# out of the division. +- name: Case 11, a child whom a share reaches exactly to the limit stays in the division. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + bank_account_assets: + 2026: 2_048.30 + person2: + age: + 2026: 8 + person_id: + 2026: 2 + parent_1_id: + 2026: 1 + bank_account_assets: + 2026: 1_983.90 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + person3: + age: + 2026: 10 + person_id: + 2026: 3 + parent_1_id: + 2026: 1 + bank_account_assets: + 2026: 1_980 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + person4: + age: + 2026: 12 + person_id: + 2026: 4 + parent_1_id: + 2026: 1 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + marital_units: + person1_unit: + members: [person1] + person2_unit: + members: [person2] + person3_unit: + members: [person3] + person4_unit: + members: [person4] + families: + family: + members: [person1, person2, person3, person4] + tax_units: + family: + members: [person1, person2, person3, person4] + spm_units: + unit: + members: [person1, person2, person3, person4] + households: + home: + members: [person1, person2, person3, person4] + state_code: + 2026: IA + output: + ia_ssa_resources_deemed_from_parents: [0, 16.10, 16.10, 16.10] + ia_ssa_eligible: [false, true, true, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/id/tafi/id_tafi_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/id/tafi/id_tafi_resources_eligible.yaml index 451c82e2971..7bdf37bdcaa 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/id/tafi/id_tafi_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/id/tafi/id_tafi_resources_eligible.yaml @@ -101,3 +101,28 @@ output: id_tafi_resources_eligible: false # $100,000 > $5,000 -> ineligible + +# 4,211.74 + 769.20 + 19.06 = 5,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 5,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 4_211.74 + stock_assets: 769.20 + bond_assets: 19.06 + state_code: ID + output: + id_tafi_resources_eligible: true + +# 4,211.74 + 769.20 + 19.07 = 5,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 4_211.74 + stock_assets: 769.20 + bond_assets: 19.07 + state_code: ID + output: + id_tafi_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/il/dhs/aabd/asset/il_aabd_asset_value_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/il/dhs/aabd/asset/il_aabd_asset_value_eligible.yaml index e3f21170387..3a60f1a78e6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/il/dhs/aabd/asset/il_aabd_asset_value_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/il/dhs/aabd/asset/il_aabd_asset_value_eligible.yaml @@ -33,3 +33,32 @@ state_code: IL output: il_aabd_asset_value_eligible: true + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: IL + output: + il_aabd_asset_value_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: IL + output: + il_aabd_asset_value_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/tanf/resources/in_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/tanf/resources/in_tanf_resources_eligible.yaml index 0e5da21a6d4..3f2a4f46298 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/tanf/resources/in_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/tanf/resources/in_tanf_resources_eligible.yaml @@ -58,3 +58,28 @@ output: in_tanf_resources_eligible: true # 0 <= 1_000 = true + +# 650.46 + 299.64 + 49.90 = 1,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 1,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.90 + state_code: IN + output: + in_tanf_resources_eligible: true + +# 650.46 + 299.64 + 49.91 = 1,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.91 + state_code: IN + output: + in_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ks/dcf/tanf/ks_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ks/dcf/tanf/ks_tanf_resources_eligible.yaml index 6c8dd12e410..3952e174c96 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ks/dcf/tanf/ks_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ks/dcf/tanf/ks_tanf_resources_eligible.yaml @@ -40,3 +40,28 @@ spm_unit_cash_assets: 10_000 output: ks_tanf_resources_eligible: false + +# 798.28 + 2,187.62 + 14.10 = 3,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 3,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.10 + state_code: KS + output: + ks_tanf_resources_eligible: true + +# 798.28 + 2,187.62 + 14.11 = 3,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.11 + state_code: KS + output: + ks_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ky/dcbs/ktap/ky_ktap_resource_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ky/dcbs/ktap/ky_ktap_resource_eligible.yaml index fd1658a596d..c0e3229af88 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ky/dcbs/ktap/ky_ktap_resource_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ky/dcbs/ktap/ky_ktap_resource_eligible.yaml @@ -102,3 +102,28 @@ output: # Not in Kentucky ky_ktap_resource_eligible: false + +# 8,688.73 + 9.74 + 1,301.53 = 10,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 10,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.53 + state_code: KY + output: + ky_ktap_resource_eligible: true + +# 8,688.73 + 9.74 + 1,301.54 = 10,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.54 + state_code: KY + output: + ky_ktap_resource_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_eligible.yaml index e139b19db84..827caa644a9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_eligible.yaml @@ -386,3 +386,45 @@ state_code: MD output: md_paa_eligible: true + +# PAA Manual §500's $2,000 limit: 178.57 + 1,547.79 + 273.64 = 2,000.00, at +# the limit. The three float32 balances add to 2,000.0001 unless rounded to +# cents. +- name: Case 19, three accounts that total exactly the resource limit are eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_disabled: true + ssi: 800 + bank_account_assets: 178.57 + stock_assets: 1_547.79 + bond_assets: 273.64 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: true + +# 178.57 + 1,547.79 + 273.65 = 2,000.01, a cent over the limit. +- name: Case 20, three accounts a cent over the resource limit are ineligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_disabled: true + ssi: 800 + bank_account_assets: 178.57 + stock_assets: 1_547.79 + bond_assets: 273.65 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/tanf/me_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/tanf/me_tanf_resources_eligible.yaml index 3024313a3a5..3574d25a15a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/tanf/me_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/tanf/me_tanf_resources_eligible.yaml @@ -27,3 +27,28 @@ spm_unit_cash_assets: 0 output: me_tanf_resources_eligible: true + +# 8,688.73 + 9.74 + 1,301.53 = 10,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 10,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.53 + state_code: ME + output: + me_tanf_resources_eligible: true + +# 8,688.73 + 9.74 + 1,301.54 = 10,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.54 + state_code: ME + output: + me_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/eligibility/mi_fip_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/eligibility/mi_fip_resources_eligible.yaml index 9c15f884ddd..500406f49c5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/eligibility/mi_fip_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mi/mdhhs/fip/eligibility/mi_fip_resources_eligible.yaml @@ -45,3 +45,28 @@ spm_unit_cash_assets: 10_000 output: mi_fip_resources_eligible: 0 + +# 8,612.82 + 6,310.95 + 76.23 = 15,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 15,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_612.82 + stock_assets: 6_310.95 + bond_assets: 76.23 + state_code: MI + output: + mi_fip_resources_eligible: true + +# 8,612.82 + 6,310.95 + 76.24 = 15,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_612.82 + stock_assets: 6_310.95 + bond_assets: 76.24 + state_code: MI + output: + mi_fip_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dcyf/mfip/mn_mfip_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dcyf/mfip/mn_mfip_resources_eligible.yaml index 10a5e6fc792..301006eec8e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mn/dcyf/mfip/mn_mfip_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dcyf/mfip/mn_mfip_resources_eligible.yaml @@ -82,3 +82,28 @@ # Limit: $10,000 # Eligible: 10,001 <= 10,000 = false mn_mfip_resources_eligible: false + +# 8,688.73 + 9.74 + 1,301.53 = 10,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 10,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.53 + state_code: MN + output: + mn_mfip_resources_eligible: true + +# 8,688.73 + 9.74 + 1,301.54 = 10,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.54 + state_code: MN + output: + mn_mfip_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.yaml index e51576f874a..ddc7e1bec8c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.yaml @@ -332,3 +332,32 @@ state_code: MN output: mn_msa_resource_eligible: true + +# 8,688.73 + 9.74 + 1,301.53 = 10,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 10,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.53 + state_code: MN + output: + mn_msa_resource_eligible: true + +# 8,688.73 + 9.74 + 1,301.54 = 10,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.54 + state_code: MN + output: + mn_msa_resource_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_resources_eligible.yaml index 6abfee83c58..50616a884c9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_resources_eligible.yaml @@ -21,3 +21,28 @@ spm_unit_cash_assets: 1_001 output: mo_tanf_resources_eligible: false + +# 650.46 + 299.64 + 49.90 = 1,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 1,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.90 + state_code: MO + output: + mo_tanf_resources_eligible: true + +# 650.46 + 299.64 + 49.91 = 1,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.91 + state_code: MO + output: + mo_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ms/dhs/tanf/ms_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ms/dhs/tanf/ms_tanf_resources_eligible.yaml index f6c851d2cae..33e366dd5bb 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ms/dhs/tanf/ms_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ms/dhs/tanf/ms_tanf_resources_eligible.yaml @@ -64,3 +64,28 @@ output: # Not in MS, returns false (defined_for = MS) ms_tanf_resources_eligible: false + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: MS + output: + ms_tanf_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: MS + output: + ms_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ms/dom/hmw/eligibility/ms_hmw_resource_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ms/dom/hmw/eligibility/ms_hmw_resource_eligible.yaml index 6bcc9a817e5..d1d0a3b36f5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ms/dom/hmw/eligibility/ms_hmw_resource_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ms/dom/hmw/eligibility/ms_hmw_resource_eligible.yaml @@ -109,3 +109,32 @@ members: [person2] output: ms_hmw_resource_eligible: [true, true] + +# 1,843.69 + 2,145.15 + 11.16 = 4,000.00, which the limit excludes. +# The float32 balances add to a fraction of a cent below 4,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit fail + period: 2025 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_843.69 + stock_assets: 2_145.15 + bond_assets: 11.16 + state_code: MS + output: + ms_hmw_resource_eligible: false + +# 1,843.69 + 2,145.15 + 11.15 = 3,999.99, a cent under the limit. +- name: Three accounts a cent under the resource limit pass + period: 2025 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 1_843.69 + stock_assets: 2_145.15 + bond_assets: 11.15 + state_code: MS + output: + ms_hmw_resource_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/dhs/tanf/eligibility/mt_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/dhs/tanf/eligibility/mt_tanf_resources_eligible.yaml index f883908a09f..8413dc1b1c0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/dhs/tanf/eligibility/mt_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/dhs/tanf/eligibility/mt_tanf_resources_eligible.yaml @@ -21,3 +21,28 @@ bank_account_assets: 0 output: mt_tanf_resources_eligible: true + +# 798.28 + 2,187.62 + 14.10 = 3,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 3,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.10 + state_code: MT + output: + mt_tanf_resources_eligible: true + +# 798.28 + 2,187.62 + 14.11 = 3,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.11 + state_code: MT + output: + mt_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nd/dhs/tanf/nd_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nd/dhs/tanf/nd_tanf_resources_eligible.yaml index 08bf4c5395d..8ed8999c375 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nd/dhs/tanf/nd_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nd/dhs/tanf/nd_tanf_resources_eligible.yaml @@ -237,3 +237,28 @@ # Limit: $6,000 + $25 * (10-2) = $6,000 + $200 = $6,200 # $6,200 <= $6,200 = true nd_tanf_resources_eligible: true + +# 798.28 + 2,187.62 + 14.10 = 3,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 3,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.10 + state_code: ND + output: + nd_tanf_resources_eligible: true + +# 798.28 + 2,187.62 + 14.11 = 3,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 798.28 + stock_assets: 2_187.62 + bond_assets: 14.11 + state_code: ND + output: + nd_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ne/dhhs/adc/ne_adc_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ne/dhhs/adc/ne_adc_resources_eligible.yaml index 596d450fe45..28a326e8432 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ne/dhhs/adc/ne_adc_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ne/dhhs/adc/ne_adc_resources_eligible.yaml @@ -84,3 +84,28 @@ spm_unit_size: 2 ne_adc_resources_eligible: false # Resources ($6,001) > Limit ($6,000) -> false + +# 2,286.12 + 404.84 + 1,309.04 = 4,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 4,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025 + input: + age: 30 + bank_account_assets: 2_286.12 + stock_assets: 404.84 + bond_assets: 1_309.04 + state_code: NE + output: + ne_adc_resources_eligible: true + +# 2,286.12 + 404.84 + 1,309.05 = 4,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025 + input: + age: 30 + bank_account_assets: 2_286.12 + stock_assets: 404.84 + bond_assets: 1_309.05 + state_code: NE + output: + ne_adc_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/fanf/nh_fanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/fanf/nh_fanf_resources_eligible.yaml index a64ded75848..8b2eb46310e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/fanf/nh_fanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/fanf/nh_fanf_resources_eligible.yaml @@ -118,3 +118,28 @@ output: # $1,999 < $2,000 limit = eligible nh_fanf_resources_eligible: true + +# 719.22 + 208.18 + 72.60 = 1,000.00, which the limit excludes. +# The float32 balances add to a fraction of a cent below 1,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit fail + period: 2025 + input: + age: 30 + bank_account_assets: 719.22 + stock_assets: 208.18 + bond_assets: 72.60 + state_code: NH + output: + nh_fanf_resources_eligible: false + +# 719.22 + 208.18 + 72.59 = 999.99, a cent under the limit. +- name: Three accounts a cent under the resource limit pass + period: 2025 + input: + age: 30 + bank_account_assets: 719.22 + stock_assets: 208.18 + bond_assets: 72.59 + state_code: NH + output: + nh_fanf_resources_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ssp/nh_ssp_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ssp/nh_ssp_eligible.yaml new file mode 100644 index 00000000000..894d144a8c8 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ssp/nh_ssp_eligible.yaml @@ -0,0 +1,28 @@ +# 285.92 + 1,181.93 + 32.15 = 1,500.00, at the limit. +# The float32 balances add to a fraction of a cent above 1,500 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 285.92 + stock_assets: 1_181.93 + bond_assets: 32.15 + state_code: NH + output: + nh_ssp_eligible: true + +# 285.92 + 1,181.93 + 32.16 = 1,500.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_disabled: true + bank_account_assets: 285.92 + stock_assets: 1_181.93 + bond_assets: 32.16 + state_code: NH + output: + nh_ssp_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/njdhs/wfnj/nj_wfnj_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/njdhs/wfnj/nj_wfnj_resources_eligible.yaml index 6fc296c5bdf..992dcf63659 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/njdhs/wfnj/nj_wfnj_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/njdhs/wfnj/nj_wfnj_resources_eligible.yaml @@ -21,3 +21,28 @@ spm_unit_cash_assets: 0 output: nj_wfnj_resources_eligible: true + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: NJ + output: + nj_wfnj_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: NJ + output: + nj_wfnj_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/hca/nm_works/eligibility/nm_works_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/hca/nm_works/eligibility/nm_works_resources_eligible.yaml index 13fb0f6fbcd..fcee32c4d3b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/hca/nm_works/eligibility/nm_works_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/hca/nm_works/eligibility/nm_works_resources_eligible.yaml @@ -36,3 +36,28 @@ # Liquid resources alone can fail the NM Works test even before adding any # future modeled non-liquid countable resources. nm_works_resources_eligible: false + +# 285.92 + 1,181.93 + 32.15 = 1,500.00, at the limit. +# The float32 balances add to a fraction of a cent above 1,500 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 285.92 + stock_assets: 1_181.93 + bond_assets: 32.15 + state_code: NM + output: + nm_works_resources_eligible: true + +# 285.92 + 1,181.93 + 32.16 = 1,500.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 285.92 + stock_assets: 1_181.93 + bond_assets: 32.16 + state_code: NM + output: + nm_works_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/tanf/eligibility/nv_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/tanf/eligibility/nv_tanf_resources_eligible.yaml index 9f571c0547d..a8b4ad3b553 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/tanf/eligibility/nv_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/tanf/eligibility/nv_tanf_resources_eligible.yaml @@ -24,3 +24,28 @@ spm_unit_cash_assets: 10_001 output: nv_tanf_resources_eligible: false + +# 8,688.73 + 9.74 + 1,301.53 = 10,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 10,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.53 + state_code: NV + output: + nv_tanf_resources_eligible: true + +# 8,688.73 + 9.74 + 1,301.54 = 10,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.54 + state_code: NV + output: + nv_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/tanf/ny_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/tanf/ny_tanf_resources_eligible.yaml index 5fdaef1d68a..19757c115f5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/tanf/ny_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/tanf/ny_tanf_resources_eligible.yaml @@ -171,3 +171,28 @@ # Pre-reform: disability did NOT qualify for higher limit # Uses $2,000 limit, $2,500 > $2,000 → ineligible ny_tanf_resources_eligible: false + +# 2,105.87 + 384.60 + 9.53 = 2,500.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,500 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 2_105.87 + stock_assets: 384.60 + bond_assets: 9.53 + state_code: NY + output: + ny_tanf_resources_eligible: true + +# 2,105.87 + 384.60 + 9.54 = 2,500.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 2_105.87 + stock_assets: 384.60 + bond_assets: 9.54 + state_code: NY + output: + ny_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_resources_eligible.yaml index 38583a1f602..cac5d84846c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_resources_eligible.yaml @@ -77,3 +77,28 @@ state_code: OK output: ok_tanf_resources_eligible: true + +# 650.46 + 299.64 + 49.90 = 1,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 1,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.90 + state_code: OK + output: + ok_tanf_resources_eligible: true + +# 650.46 + 299.64 + 49.91 = 1,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.91 + state_code: OK + output: + ok_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/odhs/tanf/or_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/odhs/tanf/or_tanf_resources_eligible.yaml index 1186d1002bf..98ca066c457 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/or/odhs/tanf/or_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/or/odhs/tanf/or_tanf_resources_eligible.yaml @@ -35,3 +35,28 @@ spm_unit_cash_assets: 10_001 output: or_tanf_resources_eligible: false + +# 8,688.73 + 9.74 + 1,301.53 = 10,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 10,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.53 + state_code: OR + output: + or_tanf_resources_eligible: true + +# 8,688.73 + 9.74 + 1,301.54 = 10,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 8_688.73 + stock_assets: 9.74 + bond_assets: 1_301.54 + state_code: OR + output: + or_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/pa/dhs/tanf/eligibility/pa_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/pa/dhs/tanf/eligibility/pa_tanf_resources_eligible.yaml index a959a2e9858..db07aa1209f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/pa/dhs/tanf/eligibility/pa_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/pa/dhs/tanf/eligibility/pa_tanf_resources_eligible.yaml @@ -45,3 +45,28 @@ state_code: PA output: pa_tanf_resources_eligible: false + +# 650.46 + 299.64 + 49.90 = 1,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 1,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.90 + state_code: PA + output: + pa_tanf_resources_eligible: true + +# 650.46 + 299.64 + 49.91 = 1,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.91 + state_code: PA + output: + pa_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/works/ri_works_resource_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/works/ri_works_resource_eligible.yaml index 6c572074ff6..ba661907dce 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/works/ri_works_resource_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/works/ri_works_resource_eligible.yaml @@ -64,3 +64,28 @@ # Limit: $5,000 # $4,999 <= $5,000 = true ri_works_resource_eligible: true + +# 4,211.74 + 769.20 + 19.06 = 5,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 5,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 4_211.74 + stock_assets: 769.20 + bond_assets: 19.06 + state_code: RI + output: + ri_works_resource_eligible: true + +# 4,211.74 + 769.20 + 19.07 = 5,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 4_211.74 + stock_assets: 769.20 + bond_assets: 19.07 + state_code: RI + output: + ri_works_resource_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_resources_eligible.yaml index ef036df8b90..09d3821e098 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_resources_eligible.yaml @@ -34,3 +34,28 @@ output: sc_tanf_resources_eligible: true # 0 <= 2,500 -> eligible + +# 2,105.87 + 384.60 + 9.53 = 2,500.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,500 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 2_105.87 + stock_assets: 384.60 + bond_assets: 9.53 + state_code: SC + output: + sc_tanf_resources_eligible: true + +# 2,105.87 + 384.60 + 9.54 = 2,500.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 2_105.87 + stock_assets: 384.60 + bond_assets: 9.54 + state_code: SC + output: + sc_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/sd/dss/tanf/eligibility/sd_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/sd/dss/tanf/eligibility/sd_tanf_resources_eligible.yaml index e26e7dedeb8..dfdcecd592d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/sd/dss/tanf/eligibility/sd_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/sd/dss/tanf/eligibility/sd_tanf_resources_eligible.yaml @@ -102,3 +102,28 @@ # Limit: $2,000 # Eligible: $1,999 <= $2,000 = true sd_tanf_resources_eligible: true + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: SD + output: + sd_tanf_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: SD + output: + sd_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/tn/dhs/ff/eligibility/tn_ff_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/tn/dhs/ff/eligibility/tn_ff_resources_eligible.yaml index a8bd6fe0df9..77d310f3adc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/tn/dhs/ff/eligibility/tn_ff_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/tn/dhs/ff/eligibility/tn_ff_resources_eligible.yaml @@ -114,3 +114,28 @@ output: # Countable: $3,000 liquid assets + ($6,600 - $4,600 vehicle exclusion) = $5,000 tn_ff_resources_eligible: false + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: TN + output: + tn_ff_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: TN + output: + tn_ff_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/tx/tanf/eligibility/tx_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/tx/tanf/eligibility/tx_tanf_resources_eligible.yaml index c3a2135753c..8b11f01a5f2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/tx/tanf/eligibility/tx_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/tx/tanf/eligibility/tx_tanf_resources_eligible.yaml @@ -42,3 +42,28 @@ output: tx_tanf_resources_eligible: true # Resources (0) <= limit (1,000) → Pass + +# 650.46 + 299.64 + 49.90 = 1,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 1,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.90 + state_code: TX + output: + tx_tanf_resources_eligible: true + +# 650.46 + 299.64 + 49.91 = 1,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 650.46 + stock_assets: 299.64 + bond_assets: 49.91 + state_code: TX + output: + tx_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/fep/eligibility/ut_fep_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/fep/eligibility/ut_fep_resources_eligible.yaml index f8905ef04be..746a2074200 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/fep/eligibility/ut_fep_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/fep/eligibility/ut_fep_resources_eligible.yaml @@ -45,3 +45,28 @@ output: # Resources = 5,000 > 2,000 - ineligible ut_fep_resources_eligible: false + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: UT + output: + ut_fep_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: UT + output: + ut_fep_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/dars/ag/va_ag_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/dars/ag/va_ag_eligible.yaml new file mode 100644 index 00000000000..fb98c10be34 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/va/dars/ag/va_ag_eligible.yaml @@ -0,0 +1,35 @@ +# An applicant who doesn't receive SSI is tested against the SSI resource +# limits. 178.57 + 1,547.79 + 273.64 = 2,000.00, at the $2,000 individual +# limit. The three float32 balances add to 2,000.0001 unless rounded to cents. +- name: Three accounts that total exactly the individual resource limit are eligible + period: 2026-01 + input: + state_code: VA + age: 70 + is_disabled: true + is_ssi_aged_blind_disabled: true + va_ag_certified: true + ssi: 0 + social_security: 30_000 + bank_account_assets: 178.57 + stock_assets: 1_547.79 + bond_assets: 273.64 + output: + va_ag_eligible: true + +# 178.57 + 1,547.79 + 273.65 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the individual resource limit are ineligible + period: 2026-01 + input: + state_code: VA + age: 70 + is_disabled: true + is_ssi_aged_blind_disabled: true + va_ag_certified: true + ssi: 0 + social_security: 30_000 + bank_account_assets: 178.57 + stock_assets: 1_547.79 + bond_assets: 273.65 + output: + va_ag_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/vt/dcf/reach_up/vt_reach_up_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/vt/dcf/reach_up/vt_reach_up_resources_eligible.yaml index 1072da1660a..3e503e86178 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/vt/dcf/reach_up/vt_reach_up_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/vt/dcf/reach_up/vt_reach_up_resources_eligible.yaml @@ -73,3 +73,28 @@ output: # Assets: $9,001 > $9,000 limit vt_reach_up_resources_eligible: false + +# 617.28 + 8,353.98 + 28.74 = 9,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 9,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 617.28 + stock_assets: 8_353.98 + bond_assets: 28.74 + state_code: VT + output: + vt_reach_up_resources_eligible: true + +# 617.28 + 8,353.98 + 28.75 = 9,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 617.28 + stock_assets: 8_353.98 + bond_assets: 28.75 + state_code: VT + output: + vt_reach_up_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/wa/dshs/tanf/wa_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wa/dshs/tanf/wa_tanf_resources_eligible.yaml index ee925dfa47f..c14319af143 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wa/dshs/tanf/wa_tanf_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wa/dshs/tanf/wa_tanf_resources_eligible.yaml @@ -50,3 +50,28 @@ bank_account_assets: 1_001 output: wa_tanf_resources_eligible: false + +# 8,978.98 + 2,564.81 + 456.21 = 12,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 12,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025 + input: + age: 30 + bank_account_assets: 8_978.98 + stock_assets: 2_564.81 + bond_assets: 456.21 + state_code: WA + output: + wa_tanf_resources_eligible: true + +# 8,978.98 + 2,564.81 + 456.22 = 12,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025 + input: + age: 30 + bank_account_assets: 8_978.98 + stock_assets: 2_564.81 + bond_assets: 456.22 + state_code: WA + output: + wa_tanf_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/dcf/works/wi_works_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/dcf/works/wi_works_resources_eligible.yaml index 62907a62354..ee465405121 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/dcf/works/wi_works_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/dcf/works/wi_works_resources_eligible.yaml @@ -36,3 +36,28 @@ state_code: CA output: wi_works_resources_eligible: false + +# 2,105.87 + 384.60 + 9.53 = 2,500.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,500 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025 + input: + age: 30 + bank_account_assets: 2_105.87 + stock_assets: 384.60 + bond_assets: 9.53 + state_code: WI + output: + wi_works_resources_eligible: true + +# 2,105.87 + 384.60 + 9.54 = 2,500.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025 + input: + age: 30 + bank_account_assets: 2_105.87 + stock_assets: 384.60 + bond_assets: 9.54 + state_code: WI + output: + wi_works_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/works/wv_works_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/works/wv_works_resources_eligible.yaml index 64cb29352e1..16e4e33fab5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/works/wv_works_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/works/wv_works_resources_eligible.yaml @@ -50,3 +50,28 @@ spm_unit_cash_assets: 10_000 output: wv_works_resources_eligible: false + +# 1,157.81 + 285.17 + 557.02 = 2,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 2,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.02 + state_code: WV + output: + wv_works_resources_eligible: true + +# 1,157.81 + 285.17 + 557.03 = 2,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 1_157.81 + stock_assets: 285.17 + bond_assets: 557.03 + state_code: WV + output: + wv_works_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/wy/dfs/power/wy_power_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wy/dfs/power/wy_power_resources_eligible.yaml index e1aeccfbe8d..0f12cd002d9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wy/dfs/power/wy_power_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wy/dfs/power/wy_power_resources_eligible.yaml @@ -34,3 +34,28 @@ spm_unit_cash_assets: 5_001 output: wy_power_resources_eligible: false + +# 4,211.74 + 769.20 + 19.06 = 5,000.00, at the limit. +# The float32 balances add to a fraction of a cent above 5,000 unless rounded to cents. +- name: Three accounts that total exactly the resource limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 4_211.74 + stock_assets: 769.20 + bond_assets: 19.06 + state_code: WY + output: + wy_power_resources_eligible: true + +# 4,211.74 + 769.20 + 19.07 = 5,000.01, a cent over the limit. +- name: Three accounts a cent over the resource limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 4_211.74 + stock_assets: 769.20 + bond_assets: 19.07 + state_code: WY + output: + wy_power_resources_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_asset_test.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_asset_test.yaml index 58a3ceb5d15..2367a19f859 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_asset_test.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_asset_test.yaml @@ -78,3 +78,26 @@ # $4,000 is between the $3,000 standard and $4,500 elderly/disabled # limits, and the eligible elderly member confers the higher limit. meets_snap_asset_test: true + +# 7 U.S.C. 2014(g)(1): 2,607.87 + 29.87 + 362.26 = 3,000.00, at the FY2025 +# standard limit. The float32 balances add to 3,000.0002 unless rounded. +- name: Three accounts that total exactly the standard limit pass + period: 2025-01 + input: + age: 30 + bank_account_assets: 2_607.87 + stock_assets: 29.87 + bond_assets: 362.26 + output: + meets_snap_asset_test: true + +# 2,607.87 + 29.87 + 362.27 = 3,000.01, a cent over the limit. +- name: Three accounts a cent over the standard limit fail + period: 2025-01 + input: + age: 30 + bank_account_assets: 2_607.87 + stock_assets: 29.87 + bond_assets: 362.27 + output: + meets_snap_asset_test: false diff --git a/policyengine_us/tests/unit/test_round_to_cents_properties.py b/policyengine_us/tests/unit/test_round_to_cents_properties.py new file mode 100644 index 00000000000..8dfc05b2b56 --- /dev/null +++ b/policyengine_us/tests/unit/test_round_to_cents_properties.py @@ -0,0 +1,51 @@ +"""Hypothesis check that splitting a total into cents doesn't change a limit test. + +Account balances are stored as float32, so three balances that add to a limit +in cents can sum a fraction of a cent above or below it. Asset tests round the +sum to cents before comparing it with the limit (``round_to_cents``). + +The property checks the helper alone, without a model, on both ways the model +sums inputs: float32 addition within one entity, and a float64 sum cast back +to float32 when person inputs are added up to a group entity. The YAML cases +at each fixed limit check the model. Hypothesis is a dev extra, so this module +skips without it. +""" + +import numpy as np +import pytest + +from policyengine_us.tools.general import round_to_cents + +hypothesis = pytest.importorskip("hypothesis") +st = pytest.importorskip("hypothesis.strategies") + +# Three float32 parts and two float32 additions each err by at most half a +# unit in the last place of the total. Below 2**15 dollars a half unit is at +# most 2**-10, so the sum stays within 5 / 2**10 < 0.005 of the total. +MAX_CENTS = 2**15 * 100 - 1 + + +@st.composite +def cent_split(draw, total_cents): + """Three whole-cent parts that add to total_cents.""" + cuts = sorted(draw(st.integers(0, total_cents)) for _ in range(2)) + return (cuts[0], cuts[1] - cuts[0], total_cents - cuts[1]) + + +@st.composite +def total_and_split(draw): + total = draw(st.integers(0, MAX_CENTS)) + return total, draw(cent_split(total)) + + +@hypothesis.settings(max_examples=2_000, deadline=None) +@hypothesis.given(total_and_split()) +def test_rounded_sum_of_float32_parts_is_the_total(case): + total, parts = case + values = [np.float32(part / 100) for part in parts] + # Float32 addition, as a formula adding one entity's own inputs. + float32_sum = values[0] + values[1] + values[2] + # A float64 sum stored as float32, as an aggregate to a group entity. + float64_sum = np.float32(sum(float(value) for value in values)) + for amount in (float32_sum, float64_sum): + assert round_to_cents(amount) == total / 100 diff --git a/policyengine_us/tools/general.py b/policyengine_us/tools/general.py index 7afc7860fd7..90d9ad38984 100644 --- a/policyengine_us/tools/general.py +++ b/policyengine_us/tools/general.py @@ -14,6 +14,55 @@ USD = "currency-USD" +def round_to_cents(amount): + """Round a dollar amount to whole cents, as a float64 array. + + Inputs are stored as float32, which holds most cent amounts only + approximately. A sum of several of them can land a fraction of a cent + above or below the whole-cent total they represent: three balances + entered as 178.57, 1,547.79 and 273.64 add to 2,000.0001 in float32. + Rounding the sum before an exact-limit comparison compares the total the + inputs represent, so a split of a total among accounts or people passes + or fails the limit as the total does. + """ + return np.round(np.asarray(amount, dtype=np.float64), 2) + + +def meets_limit_with_share(own, excess, divisor, limit): + """Whether own + excess / divisor <= limit, computed exactly. + + own, excess and limit are whole-cent amounts (round summed balances + first); the share excess / divisor need not be. Float64 arithmetic can + put a total at the limit a hair above it (2,048.30 - 2,000 gives an + excess of 48.30000000000018, and 1,983.90 plus a third of it gives + 2,000.0000000000002), so compare whole cents instead: + divisor x own + excess <= divisor x limit. + """ + own_cents = np.rint(np.asarray(own, dtype=np.float64) * 100).astype(np.int64) + excess_cents = np.rint(np.asarray(excess, dtype=np.float64) * 100).astype(np.int64) + limit_cents = np.rint(np.asarray(limit, dtype=np.float64) * 100).astype(np.int64) + divisor = np.asarray(divisor).astype(np.int64) + return excess_cents <= divisor * (limit_cents - own_cents) + + +def float32_at_most(amount): + """The largest float32 at or below each amount. + + Float variables are stored as float32, and the nearest float32 can lie + above the amount: a share of 100.01 is stored as 100.010002, so own + resources of 1,899.99 plus that share exceed a 2,000 limit that the + exact total meets. Storing the float32 at or below the amount never + fails a total that meets the limit. A total over a whole-cent limit + exceeds it by at least a cent divided by the share's divisor, which is + more than float32's step for any share below 2**11 dollars and divisor + below 80, so there the comparison stays exact both ways. + """ + amount = np.asarray(amount, dtype=np.float64) + nearest = amount.astype(np.float32) + below = np.nextafter(nearest, np.float32(-np.inf)) + return np.where(nearest.astype(np.float64) > amount, below, nearest) + + def has_input_for_period(simulation, variable, period): """Whether the visible array for this exact period was set as an input. diff --git a/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py b/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py index b4745bda5ad..c09be4d4c19 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py +++ b/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py @@ -19,7 +19,7 @@ def formula(person, period, parameters): # the individual or the married couple, not the tax filing unit. personal_assets = person("ssi_countable_resources", period) # $ # Inputs are stored as float32, so compare whole cents with the limit. - assets = np.round(person.marital_unit.sum(personal_assets), 2) + assets = round_to_cents(person.marital_unit.sum(personal_assets)) is_couple = person.marital_unit.nb_persons() == 2 state = person.household("state_code_str", period) diff --git a/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medically_needy/is_medically_needy_for_medicaid.py b/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medically_needy/is_medically_needy_for_medicaid.py index 633c16213f9..ea217c5be14 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medically_needy/is_medically_needy_for_medicaid.py +++ b/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medically_needy/is_medically_needy_for_medicaid.py @@ -33,7 +33,8 @@ def formula(person, period, parameters): # includes their deemed income. SSI's allocation gates apply: a child # whose own resources exceed the SSI individual limit, or who fails # SSI's immigration test, is deemed nothing. - personal_assets = person("ssi_countable_resources", period) + person( + personal_assets = person("ssi_countable_resources", period) + deemed_assets = person( "ssi_resources_deemed_from_ineligible_parent", period.first_month ) # SSI financial responsibility rules (42 CFR 435.602): the unit is @@ -57,7 +58,11 @@ def formula(person, period, parameters): income = marital_unit.sum( personal_income - medical_expenses - parental_expense_share ) - assets = marital_unit.sum(personal_assets) + # Balances are float32 inputs, so round their sum to cents. The SSI + # parental share is an equal division with no rounding rule (SI + # 01330.200 B, 416.1202(b)(1)), so it is added unrounded. + own_assets = round_to_cents(marital_unit.sum(personal_assets)) + assets = own_assets + marital_unit.sum(deemed_assets) ma = parameters(period).gov.hhs.medicaid mn = ma.eligibility.categories.medically_needy is_joint = marital_unit.nb_persons() == 2 diff --git a/policyengine_us/variables/gov/hhs/medicare/savings_programs/eligibility/msp_asset_eligible.py b/policyengine_us/variables/gov/hhs/medicare/savings_programs/eligibility/msp_asset_eligible.py index 98455cb905b..c0fa8859dd2 100644 --- a/policyengine_us/variables/gov/hhs/medicare/savings_programs/eligibility/msp_asset_eligible.py +++ b/policyengine_us/variables/gov/hhs/medicare/savings_programs/eligibility/msp_asset_eligible.py @@ -24,10 +24,13 @@ def formula(person, period, parameters): # If asset test doesn't apply, everyone is asset-eligible personal_resources = person("ssi_countable_resources", period.this_year) married = person.spm_unit("spm_unit_is_married", period.this_year) - countable_resources = where( - married, - person.marital_unit.sum(personal_resources), - personal_resources, + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents( + where( + married, + person.marital_unit.sum(personal_resources), + personal_resources, + ) ) # States may set a higher limit than the federal one, never a lower one. state_limit = p.asset.state_limit diff --git a/policyengine_us/variables/gov/hhs/tanf/non_cash/meets_tanf_non_cash_asset_test.py b/policyengine_us/variables/gov/hhs/tanf/non_cash/meets_tanf_non_cash_asset_test.py index 7cfb1a7e15c..bd326fec4e4 100644 --- a/policyengine_us/variables/gov/hhs/tanf/non_cash/meets_tanf_non_cash_asset_test.py +++ b/policyengine_us/variables/gov/hhs/tanf/non_cash/meets_tanf_non_cash_asset_test.py @@ -24,6 +24,7 @@ def formula(spm_unit, period, parameters): 0, ) tx_vehicle_value = max_(vehicle_value - vehicle_exemption, 0) - assets = assets + where(state == "TX", tx_vehicle_value, 0) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(assets + where(state == "TX", tx_vehicle_value, 0)) asset_limit = limits.asset_limit[state] return assets <= asset_limit diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_parent.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_parent.py index 2c0a1f658dd..c146f90f560 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_parent.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_parent.py @@ -120,11 +120,15 @@ def formula(person, period, parameters): # 'only to the extent that those resources exceed the resource limits # described in § 416.1205': use the reformable individual/couple limits. allowance = where(parent_count > 1, p.couple, p.individual) - excess = max_(0, parental_resources - allowance) + # Balances are float32 inputs. Each deemor's are added together, then + # the deemors' totals, so the sum can land a fraction of a cent off + # the total it represents: round it to cents before the limit comes off. + excess = max_(0, round_to_cents(parental_resources) - allowance) # Do not discard ABD parents. SI 01330.310 B-C says zero if parent(s) # meets resource eligibility, usual deeming if not. The Ryder example # (.340) has an ABD mother failing the couple limit: 3100-3000=100. - own_resources = person("ssi_countable_resources", period) + # The child's own float32 balances are added together: round to cents. + own_resources = round_to_cents(person("ssi_countable_resources", period)) active = person("is_ssi_resource_deeming_child", period) & ( own_resources <= p.individual ) @@ -148,10 +152,22 @@ def formula(person, period, parameters): pool_count = int(np.max(pool, initial=-1)) + 1 for _ in range(rounds): count = np.bincount(pool[active & income_eligible], minlength=pool_count) - share = excess / max_(1, count[pool]) + divisor = max_(1, count[pool]) + # The share is a division, not a sum of balances, so it stays + # exact: SI 01330.200 B says to 'equally divide the value of the + # deemed resources among those children', and 416.1202(b)(1) sets + # no rule for rounding a child's share. Own resources and the + # excess are whole cents, so test own + share in whole cents. + # https://secure.ssa.gov/poms.nsf/lnx/0501330200 + # https://www.law.cornell.edu/cfr/text/20/416.1202 + share = excess / divisor deemed = where(active, share, deemed) - remaining = active & (own_resources + share <= p.individual) + remaining = active & meets_limit_with_share( + own_resources, excess, divisor, p.individual + ) if np.array_equal(active, remaining): break active = remaining - return deemed + # Stored as float32, a share must not round up: own resources plus + # the share read back would then exceed a limit the exact total meets. + return float32_at_most(deemed) diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/resources/meets_ssi_resource_test.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/resources/meets_ssi_resource_test.py index 8a593952788..e206d99cd66 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/resources/meets_ssi_resource_test.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/resources/meets_ssi_resource_test.py @@ -17,18 +17,17 @@ def formula(person, period, parameters): joint_claim = person("ssi_claim_is_joint", period) personal_resources = person("ssi_countable_resources", period) spousal_deeming = person("is_ssi_spousal_resource_deeming_applies", period) - deemed_resources = add( - person, - period, - [ - "ssi_resources_deemed_from_ineligible_spouse", - "ssi_resources_deemed_from_ineligible_parent", - ], - ) + spouse_resources = person("ssi_resources_deemed_from_ineligible_spouse", period) + parent_resources = person("ssi_resources_deemed_from_ineligible_parent", period) + # Balances are float32 inputs, so a sum of them can land a fraction of + # a cent off the total it represents. Round each such sum to cents: a + # couple's balances, or a person's own plus a spouse's. The parental + # share is an equal division with no rounding rule (SI 01330.200 B, + # 416.1202(b)(1)), so it is added unrounded. countable_resources = where( joint_claim, - person.marital_unit.sum(personal_resources), - personal_resources + deemed_resources, + round_to_cents(person.marital_unit.sum(personal_resources)), + round_to_cents(personal_resources + spouse_resources) + parent_resources, ) # 416.1205(a): an individual living with an ineligible spouse counts # 'including the resources of the spouse' against the spouse limit. diff --git a/policyengine_us/variables/gov/states/ak/dpa/atap/eligibility/ak_atap_resources_eligible.py b/policyengine_us/variables/gov/states/ak/dpa/atap/eligibility/ak_atap_resources_eligible.py index 34b4fd788d9..b352a28ccb2 100644 --- a/policyengine_us/variables/gov/states/ak/dpa/atap/eligibility/ak_atap_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ak/dpa/atap/eligibility/ak_atap_resources_eligible.py @@ -14,7 +14,8 @@ class ak_atap_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ak.dpa.atap.resource_limit - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) # Higher limit if household has elderly member (age 60+) person = spm_unit.members diff --git a/policyengine_us/variables/gov/states/ar/dhs/tea/eligibility/ar_tea_resources_eligible.py b/policyengine_us/variables/gov/states/ar/dhs/tea/eligibility/ar_tea_resources_eligible.py index a9dd2f42819..3d6ecda781d 100644 --- a/policyengine_us/variables/gov/states/ar/dhs/tea/eligibility/ar_tea_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ar/dhs/tea/eligibility/ar_tea_resources_eligible.py @@ -15,5 +15,6 @@ def formula(spm_unit, period, parameters): # Per 208.00.13 Ark. Code R. Section 001, Section 3.4 p = parameters(period).gov.states.ar.dhs.tea.resources # Use federal asset calculation for SPM unit - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.limit diff --git a/policyengine_us/variables/gov/states/az/hhs/tanf/eligibility/az_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/az/hhs/tanf/eligibility/az_tanf_resources_eligible.py index 4cdea6416b5..d7b36d6b804 100644 --- a/policyengine_us/variables/gov/states/az/hhs/tanf/eligibility/az_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/az/hhs/tanf/eligibility/az_tanf_resources_eligible.py @@ -13,5 +13,6 @@ class az_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.az.hhs.tanf.resources - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.limit diff --git a/policyengine_us/variables/gov/states/ca/cdss/capi/eligibility/ca_capi_resource_eligible.py b/policyengine_us/variables/gov/states/ca/cdss/capi/eligibility/ca_capi_resource_eligible.py index 89ba309b6b7..af80f3980bc 100644 --- a/policyengine_us/variables/gov/states/ca/cdss/capi/eligibility/ca_capi_resource_eligible.py +++ b/policyengine_us/variables/gov/states/ca/cdss/capi/eligibility/ca_capi_resource_eligible.py @@ -10,7 +10,8 @@ class ca_capi_resource_eligible(Variable): reference = "https://www.cdss.ca.gov/Portals/9/CAPI/CAPI_Regulations-Accessible.pdf" def formula(spm_unit, period, parameters): - resources = spm_unit("ca_capi_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("ca_capi_resources", period)) p = parameters(period).gov.states.ca.cdss.capi.resources married = spm_unit("spm_unit_is_married", period) resource_limit = where(married, p.limit.couple, p.limit.single) diff --git a/policyengine_us/variables/gov/states/ca/cdss/tanf/cash/eligibility/ca_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/ca/cdss/tanf/cash/eligibility/ca_tanf_resources_eligible.py index 3d48ac8ead1..346d9c99fed 100644 --- a/policyengine_us/variables/gov/states/ca/cdss/tanf/cash/eligibility/ca_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ca/cdss/tanf/cash/eligibility/ca_tanf_resources_eligible.py @@ -10,6 +10,7 @@ class ca_tanf_resources_eligible(Variable): reference = "https://my.dpss.lacounty.gov/public/en/home/epolicy/program/calworks/property/property.html" def formula(spm_unit, period, parameters): - resources = spm_unit("ca_tanf_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("ca_tanf_resources", period)) limit = spm_unit("ca_tanf_resources_limit", period) return resources <= limit diff --git a/policyengine_us/variables/gov/states/co/ssa/oap/co_oap_eligible.py b/policyengine_us/variables/gov/states/co/ssa/oap/co_oap_eligible.py index 5d9e562ce4c..9eb4dbcb247 100644 --- a/policyengine_us/variables/gov/states/co/ssa/oap/co_oap_eligible.py +++ b/policyengine_us/variables/gov/states/co/ssa/oap/co_oap_eligible.py @@ -9,7 +9,8 @@ class co_oap_eligible(Variable): defined_for = StateCode.CO def formula(person, period, parameters): - assets = person("ssi_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(person("ssi_countable_resources", period)) joint_claim = person("ssi_claim_is_joint", period) p = parameters(period).gov.states.co.ssa.oap asset_limit = where(joint_claim, p.resources.couple, p.resources.single) diff --git a/policyengine_us/variables/gov/states/ct/dss/ssp/eligibility/ct_ssp_resource_eligible.py b/policyengine_us/variables/gov/states/ct/dss/ssp/eligibility/ct_ssp_resource_eligible.py index f4e5cf330f0..97ad8dfea5b 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ssp/eligibility/ct_ssp_resource_eligible.py +++ b/policyengine_us/variables/gov/states/ct/dss/ssp/eligibility/ct_ssp_resource_eligible.py @@ -35,4 +35,5 @@ def formula(person, period, parameters): p.asset_limit.couple, p.asset_limit.individual, ) - return resources <= limit + # Inputs are stored as float32, so compare whole cents with the limit. + return round_to_cents(resources) <= limit diff --git a/policyengine_us/variables/gov/states/ct/dss/tfa/eligibility/ct_tfa_resources_eligible.py b/policyengine_us/variables/gov/states/ct/dss/tfa/eligibility/ct_tfa_resources_eligible.py index 5b6de4508de..379336c8115 100644 --- a/policyengine_us/variables/gov/states/ct/dss/tfa/eligibility/ct_tfa_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ct/dss/tfa/eligibility/ct_tfa_resources_eligible.py @@ -13,5 +13,6 @@ class ct_tfa_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ct.dss.tfa.resource - assets = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return assets <= p.limit diff --git a/policyengine_us/variables/gov/states/dc/dhs/tanf/eligibility/dc_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/dc/dhs/tanf/eligibility/dc_tanf_resources_eligible.py index d69a7d04eaf..37b07a2aa2c 100644 --- a/policyengine_us/variables/gov/states/dc/dhs/tanf/eligibility/dc_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/dc/dhs/tanf/eligibility/dc_tanf_resources_eligible.py @@ -24,5 +24,8 @@ def formula(spm_unit, period, parameters): p.higher.amount, p.lower.amount, ) - countable_resources = spm_unit("dc_tanf_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents( + spm_unit("dc_tanf_countable_resources", period) + ) return countable_resources <= resource_limit diff --git a/policyengine_us/variables/gov/states/de/dhss/tanf/eligibility/de_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/de/dhss/tanf/eligibility/de_tanf_resources_eligible.py index 97c1189e3b9..692ba24d48a 100644 --- a/policyengine_us/variables/gov/states/de/dhss/tanf/eligibility/de_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/de/dhss/tanf/eligibility/de_tanf_resources_eligible.py @@ -12,6 +12,7 @@ class de_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): # Per DSSM 4002: Resource limit is $10,000 p = parameters(period).gov.states.de.dhss.tanf - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.resource_limit diff --git a/policyengine_us/variables/gov/states/fl/dcf/tanf/eligibility/fl_tca_resources_eligible.py b/policyengine_us/variables/gov/states/fl/dcf/tanf/eligibility/fl_tca_resources_eligible.py index 1be15ff8877..58cbc2d93e7 100644 --- a/policyengine_us/variables/gov/states/fl/dcf/tanf/eligibility/fl_tca_resources_eligible.py +++ b/policyengine_us/variables/gov/states/fl/dcf/tanf/eligibility/fl_tca_resources_eligible.py @@ -15,5 +15,6 @@ class fl_tca_resources_eligible(Variable): def formula(spm_unit, period, parameters): # Per Florida DCF: Countable assets must be <= $2,000 p = parameters(period).gov.states.fl.dcf.tanf.resources - assets = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return assets <= p.asset_limit diff --git a/policyengine_us/variables/gov/states/ga/dfcs/tanf/eligibility/ga_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/ga/dfcs/tanf/eligibility/ga_tanf_resources_eligible.py index a15e7b7049c..5d7e01e7b23 100644 --- a/policyengine_us/variables/gov/states/ga/dfcs/tanf/eligibility/ga_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ga/dfcs/tanf/eligibility/ga_tanf_resources_eligible.py @@ -18,5 +18,6 @@ def formula(spm_unit, period, parameters): # In a more complete implementation, this would account for # excluded resources (primary residence, household goods, etc.) # and vehicle value limits - cash_assets = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + cash_assets = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return cash_assets <= p.limit diff --git a/policyengine_us/variables/gov/states/ia/dhs/fip/eligibility/ia_fip_resources_eligible.py b/policyengine_us/variables/gov/states/ia/dhs/fip/eligibility/ia_fip_resources_eligible.py index 5db0c542a5b..fb075e93bb7 100644 --- a/policyengine_us/variables/gov/states/ia/dhs/fip/eligibility/ia_fip_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ia/dhs/fip/eligibility/ia_fip_resources_eligible.py @@ -19,5 +19,6 @@ def formula(spm_unit, period, parameters): p.recipient_limit, p.applicant_limit, ) - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= limit diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py index 9bdb207b59b..56bdd0255ee 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py @@ -43,7 +43,13 @@ def formula(person, period, parameters): community | person("ia_ssa_rcf_couple_budget", period) ) resource = where(couple, person.marital_unit.sum(resource), resource) - resource = resource + person("ia_ssa_resources_deemed_from_parents", period) + # Balances are float32 inputs, so round their sum to cents. The + # parental share divides the excess as SSI does, and SSI sets no rule + # for rounding a share (SI 01330.200 B, 416.1202(b)(1)), so it is + # added unrounded. + resource = round_to_cents(resource) + person( + "ia_ssa_resources_deemed_from_parents", period + ) # 6-B Resources prints "$2,000 for an individual" and "$3,000 for a # married couple living together" under 20 CFR 416.1202; these equal # the SSI limits of 20 CFR 416.1205, so the federal parameters are used diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py index 7ffa7cf73c7..312f25dec08 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py @@ -53,21 +53,28 @@ def formula(person, period, parameters): person, period, resources ) allowance = where(parent_count > 1, limit.couple, limit.individual) - excess = max_(parental_resources - allowance, 0) + # Balances are float32 inputs, so round the deemors' total and the + # child's own balances to cents, as SSI's deeming does. The share + # stays exact, so own + share is tested in whole cents. + excess = max_(round_to_cents(parental_resources) - allowance, 0) child = person("is_ssi_resource_deeming_child", period) ihhrc = person("ia_ssa_nonfinancial_eligible", period) & ( person("ia_ssa_ihhrc_amount", period) > 0 ) - own = person("ssi_countable_resources", period.this_year) + own = round_to_cents(person("ssi_countable_resources", period.this_year)) eligible = child & (receives_ssi | ihhrc) & (own <= limit.individual) pool_count = int(np.max(pool, initial=-1)) + 1 share = excess # Each round removes at least one child or leaves the result stable. for _ in range(int(np.max(person.household.nb_persons(), initial=0)) + 1): count = np.bincount(pool[eligible], minlength=pool_count) - share = excess / max_(count[pool], 1) - remaining = eligible & (own + share <= limit.individual) + divisor = max_(count[pool], 1) + share = excess / divisor + remaining = eligible & meets_limit_with_share( + own, excess, divisor, limit.individual + ) if np.array_equal(remaining, eligible): break eligible = remaining - return child * share + # Stored as float32, a share must not round up past the exact total. + return float32_at_most(child * share) diff --git a/policyengine_us/variables/gov/states/id/tafi/eligibility/id_tafi_resources_eligible.py b/policyengine_us/variables/gov/states/id/tafi/eligibility/id_tafi_resources_eligible.py index f348121d4c0..41902b707e1 100644 --- a/policyengine_us/variables/gov/states/id/tafi/eligibility/id_tafi_resources_eligible.py +++ b/policyengine_us/variables/gov/states/id/tafi/eligibility/id_tafi_resources_eligible.py @@ -12,5 +12,6 @@ class id_tafi_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.id.tafi.resources # Per IDAPA 16.03.08.200: Resources must not exceed $5,000 - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.limit diff --git a/policyengine_us/variables/gov/states/il/dhs/aabd/asset/il_aabd_asset_value_eligible.py b/policyengine_us/variables/gov/states/il/dhs/aabd/asset/il_aabd_asset_value_eligible.py index 70eeaf73810..2912c634701 100644 --- a/policyengine_us/variables/gov/states/il/dhs/aabd/asset/il_aabd_asset_value_eligible.py +++ b/policyengine_us/variables/gov/states/il/dhs/aabd/asset/il_aabd_asset_value_eligible.py @@ -16,7 +16,8 @@ class il_aabd_asset_value_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.il.dhs.aabd.asset.disregard size = spm_unit("spm_unit_size", period) - countable_asset = spm_unit("il_aabd_countable_assets", period) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_asset = round_to_cents(spm_unit("il_aabd_countable_assets", period)) capped_size = min_(size, 2) reduced_unit_size = max_(size - 2, 0) p1 = p.base[capped_size] diff --git a/policyengine_us/variables/gov/states/in/fssa/tanf/eligibility/in_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/in/fssa/tanf/eligibility/in_tanf_resources_eligible.py index bf033a68739..621ec6ead8e 100644 --- a/policyengine_us/variables/gov/states/in/fssa/tanf/eligibility/in_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/in/fssa/tanf/eligibility/in_tanf_resources_eligible.py @@ -14,7 +14,8 @@ class in_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].fssa.tanf.resources.limit - countable = spm_unit("in_tanf_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + countable = round_to_cents(spm_unit("in_tanf_countable_resources", period)) is_enrolled = spm_unit("is_tanf_enrolled", period) limit = where( diff --git a/policyengine_us/variables/gov/states/ks/dcf/tanf/eligibility/ks_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/ks/dcf/tanf/eligibility/ks_tanf_resources_eligible.py index 8fcc8858c32..87b2e17eaf5 100644 --- a/policyengine_us/variables/gov/states/ks/dcf/tanf/eligibility/ks_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ks/dcf/tanf/eligibility/ks_tanf_resources_eligible.py @@ -15,5 +15,6 @@ class ks_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): # Per KEESM 5110: Resource limit is $3,000 p = parameters(period).gov.states.ks.dcf.tanf.resource_limit - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.amount diff --git a/policyengine_us/variables/gov/states/ky/dcbs/ktap/eligibility/ky_ktap_resource_eligible.py b/policyengine_us/variables/gov/states/ky/dcbs/ktap/eligibility/ky_ktap_resource_eligible.py index e73597c2678..6dc029862af 100644 --- a/policyengine_us/variables/gov/states/ky/dcbs/ktap/eligibility/ky_ktap_resource_eligible.py +++ b/policyengine_us/variables/gov/states/ky/dcbs/ktap/eligibility/ky_ktap_resource_eligible.py @@ -11,5 +11,6 @@ class ky_ktap_resource_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ky.dcbs.ktap.eligibility - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.resource_limit diff --git a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_eligible.py b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_eligible.py index 5d71e550170..2559d8f9f62 100644 --- a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_eligible.py +++ b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_eligible.py @@ -61,7 +61,10 @@ def formula(person, period, parameters): ssi_resource_limit = parameters( period ).gov.ssa.ssi.eligibility.resources.limit.individual - ssi_resources = person("ssi_countable_resources", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + ssi_resources = round_to_cents( + person("ssi_countable_resources", period.this_year) + ) resource_eligible = ssi_resources <= ssi_resource_limit living_arrangement = person("md_paa_living_arrangement", period) in_facility = living_arrangement != living_arrangement.possible_values.NONE diff --git a/policyengine_us/variables/gov/states/me/dhhs/tanf/eligibility/me_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/me/dhhs/tanf/eligibility/me_tanf_resources_eligible.py index 64f0dd1b647..651e4499b58 100644 --- a/policyengine_us/variables/gov/states/me/dhhs/tanf/eligibility/me_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/me/dhhs/tanf/eligibility/me_tanf_resources_eligible.py @@ -17,5 +17,8 @@ def formula(spm_unit, period, parameters): # Resource limit is $10,000 per family # One vehicle per licensed driver is exempt p = parameters(period).gov.states.me.dhhs.tanf - countable_resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents( + spm_unit("spm_unit_cash_assets", period.this_year) + ) return countable_resources <= p.resource_limit diff --git a/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_resources_eligible.py b/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_resources_eligible.py index f779f24d077..622cc1efd5a 100644 --- a/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_resources_eligible.py +++ b/policyengine_us/variables/gov/states/mi/mdhhs/fip/eligibility/mi_fip_resources_eligible.py @@ -17,6 +17,7 @@ def formula(spm_unit, period, parameters): # Count liquid financial assets explicitly. BEM 400 excludes several # non-liquid resources that are not yet modeled separately here. - assets = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return assets <= p.resources.limit diff --git a/policyengine_us/variables/gov/states/mn/dcyf/mfip/eligibility/mn_mfip_resources_eligible.py b/policyengine_us/variables/gov/states/mn/dcyf/mfip/eligibility/mn_mfip_resources_eligible.py index df1826a132e..b23c3a1da1a 100644 --- a/policyengine_us/variables/gov/states/mn/dcyf/mfip/eligibility/mn_mfip_resources_eligible.py +++ b/policyengine_us/variables/gov/states/mn/dcyf/mfip/eligibility/mn_mfip_resources_eligible.py @@ -13,5 +13,6 @@ def formula(spm_unit, period, parameters): # Per MN Stat. 256P.02, Subd. 2: # Assets must not exceed $10,000. p = parameters(period).gov.states.mn.dcyf.mfip.resources - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.limit diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.py b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.py index dcbab010738..98379d99009 100644 --- a/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.py +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.py @@ -25,5 +25,6 @@ def formula(person, period, parameters): p = parameters(period).gov.states.mn.dhs.msa.eligibility receives_ssi = (person("ssi", period) > 0) | person("receives_ssi", period) countable_resources = person("ssi_countable_resources", period.this_year) - unit_resources = person.marital_unit.sum(countable_resources) + # Inputs are stored as float32, so compare whole cents with the limit. + unit_resources = round_to_cents(person.marital_unit.sum(countable_resources)) return receives_ssi | (unit_resources <= p.asset_limit.non_ssi_track) diff --git a/policyengine_us/variables/gov/states/mo/dss/tanf/eligibility/mo_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/mo/dss/tanf/eligibility/mo_tanf_resources_eligible.py index 29a469b49b0..9c0cee65722 100644 --- a/policyengine_us/variables/gov/states/mo/dss/tanf/eligibility/mo_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/mo/dss/tanf/eligibility/mo_tanf_resources_eligible.py @@ -20,5 +20,6 @@ def formula(spm_unit, period, parameters): # pact"); IEP participation is not observable, so the $1,000 limit # applies to all units. p = parameters(period).gov.states.mo.dss.tanf.resource_limit - resources = spm_unit("mo_tanf_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("mo_tanf_countable_resources", period)) return resources <= p.amount diff --git a/policyengine_us/variables/gov/states/ms/dhs/tanf/eligibility/ms_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/ms/dhs/tanf/eligibility/ms_tanf_resources_eligible.py index 337e0289112..d469c4e8bbb 100644 --- a/policyengine_us/variables/gov/states/ms/dhs/tanf/eligibility/ms_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ms/dhs/tanf/eligibility/ms_tanf_resources_eligible.py @@ -15,5 +15,8 @@ class ms_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ms.dhs.tanf.resources - household_assets = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + household_assets = round_to_cents( + spm_unit("spm_unit_cash_assets", period.this_year) + ) return household_assets <= p.limit diff --git a/policyengine_us/variables/gov/states/ms/dom/hmw/eligibility/ms_hmw_resource_eligible.py b/policyengine_us/variables/gov/states/ms/dom/hmw/eligibility/ms_hmw_resource_eligible.py index 8cf9b04ed93..edb83ae7be6 100644 --- a/policyengine_us/variables/gov/states/ms/dom/hmw/eligibility/ms_hmw_resource_eligible.py +++ b/policyengine_us/variables/gov/states/ms/dom/hmw/eligibility/ms_hmw_resource_eligible.py @@ -23,4 +23,5 @@ def formula(person, period, parameters): personal_resources, ) p = parameters(period).gov.states.ms.dom.hmw.resources.limit - return resources < where(couple, p.couple, p.individual) + # Inputs are stored as float32, so compare whole cents with the limit. + return round_to_cents(resources) < where(couple, p.couple, p.individual) diff --git a/policyengine_us/variables/gov/states/mt/dhs/tanf/eligibility/mt_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/mt/dhs/tanf/eligibility/mt_tanf_resources_eligible.py index d05fd7d9d16..cb4dcd924f6 100644 --- a/policyengine_us/variables/gov/states/mt/dhs/tanf/eligibility/mt_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/mt/dhs/tanf/eligibility/mt_tanf_resources_eligible.py @@ -11,5 +11,8 @@ class mt_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.mt.dhs.tanf.resource_limit - countable_resources = spm_unit("mt_tanf_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents( + spm_unit("mt_tanf_countable_resources", period) + ) return countable_resources <= p.amount diff --git a/policyengine_us/variables/gov/states/nd/dhs/tanf/eligibility/nd_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/nd/dhs/tanf/eligibility/nd_tanf_resources_eligible.py index cba07aa9691..d8630342090 100644 --- a/policyengine_us/variables/gov/states/nd/dhs/tanf/eligibility/nd_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/nd/dhs/tanf/eligibility/nd_tanf_resources_eligible.py @@ -11,7 +11,8 @@ class nd_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nd.dhs.tanf.resources.limit - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) unit_size = spm_unit("spm_unit_size", period.this_year) capped_size = min_(unit_size, 2) base_limit = p.base[capped_size] diff --git a/policyengine_us/variables/gov/states/ne/dhhs/adc/eligibility/ne_adc_resources_eligible.py b/policyengine_us/variables/gov/states/ne/dhhs/adc/eligibility/ne_adc_resources_eligible.py index d2a5813e246..e57f9d19eca 100644 --- a/policyengine_us/variables/gov/states/ne/dhhs/adc/eligibility/ne_adc_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ne/dhhs/adc/eligibility/ne_adc_resources_eligible.py @@ -15,7 +15,8 @@ class ne_adc_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ne.dhhs.adc # Count explicitly modeled liquid financial assets. - countable_resources = spm_unit("spm_unit_cash_assets", period) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents(spm_unit("spm_unit_cash_assets", period)) size = spm_unit("spm_unit_size", period) # Resource limits: $4,000 for 1 person, $6,000 for 2+ persons limit = p.resources.limit.calc(size) diff --git a/policyengine_us/variables/gov/states/nh/dhhs/fanf/eligibility/nh_fanf_resources_eligible.py b/policyengine_us/variables/gov/states/nh/dhhs/fanf/eligibility/nh_fanf_resources_eligible.py index 4494d90ee00..b586b9bacea 100644 --- a/policyengine_us/variables/gov/states/nh/dhhs/fanf/eligibility/nh_fanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/nh/dhhs/fanf/eligibility/nh_fanf_resources_eligible.py @@ -19,7 +19,8 @@ def formula(spm_unit, period, parameters): # NOTE: One vehicle per adult is excluded regardless of value. # Resource limits differ for applicants ($1,000) vs recipients ($5,000 as of 07/01/22) p = parameters(period).gov.states.nh.dhhs.fanf.resources - resources = spm_unit("spm_unit_cash_assets", period) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period)) # He-W 656.06(a)(1) also treats an applicant who received FANF in any # one of the previous 6 months as a recipient. The inputs have no # 6-month look-back, so current enrollment stands in for it. diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ssp/nh_ssp_eligible.py b/policyengine_us/variables/gov/states/nh/dhhs/ssp/nh_ssp_eligible.py index 4ba8532fe3f..b931c4de3d6 100644 --- a/policyengine_us/variables/gov/states/nh/dhhs/ssp/nh_ssp_eligible.py +++ b/policyengine_us/variables/gov/states/nh/dhhs/ssp/nh_ssp_eligible.py @@ -42,6 +42,8 @@ def formula(person, period, parameters): resources = resources + essential * max_( essential_resources, spouse_value(essential_resources, spouse) ) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(resources) # He-W 616.02(a): qualified aliens under 8 USC 1641(b) are eligible once # the waiting period since entry has elapsed, which also covers entry # before August 22, 1996. AAM 305.11 exempts the listed statuses, as diff --git a/policyengine_us/variables/gov/states/nj/njdhs/wfnj/eligibility/nj_wfnj_resources_eligible.py b/policyengine_us/variables/gov/states/nj/njdhs/wfnj/eligibility/nj_wfnj_resources_eligible.py index 52729d916fb..0933ef6c5f7 100644 --- a/policyengine_us/variables/gov/states/nj/njdhs/wfnj/eligibility/nj_wfnj_resources_eligible.py +++ b/policyengine_us/variables/gov/states/nj/njdhs/wfnj/eligibility/nj_wfnj_resources_eligible.py @@ -11,5 +11,6 @@ class nj_wfnj_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nj.njdhs.wfnj.resources - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.limit diff --git a/policyengine_us/variables/gov/states/nm/hca/nm_works/eligibility/nm_works_resources_eligible.py b/policyengine_us/variables/gov/states/nm/hca/nm_works/eligibility/nm_works_resources_eligible.py index ea5843c25d3..e41f1d96fad 100644 --- a/policyengine_us/variables/gov/states/nm/hca/nm_works/eligibility/nm_works_resources_eligible.py +++ b/policyengine_us/variables/gov/states/nm/hca/nm_works/eligibility/nm_works_resources_eligible.py @@ -11,7 +11,10 @@ class nm_works_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nm.hca.nm_works.resources.limit - liquid_resources = spm_unit("nm_works_countable_liquid_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + liquid_resources = round_to_cents( + spm_unit("nm_works_countable_liquid_resources", period) + ) non_liquid_resources = spm_unit( "nm_works_countable_non_liquid_resources", period ) diff --git a/policyengine_us/variables/gov/states/nv/dwss/tanf/eligibility/nv_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/nv/dwss/tanf/eligibility/nv_tanf_resources_eligible.py index aa7c78bfff2..6c6f08ff330 100644 --- a/policyengine_us/variables/gov/states/nv/dwss/tanf/eligibility/nv_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/nv/dwss/tanf/eligibility/nv_tanf_resources_eligible.py @@ -14,5 +14,6 @@ def formula(spm_unit, period, parameters): # Nevada excludes the home and up to two vehicles, so use liquid # financial assets explicitly until those vehicle exclusions are # modeled separately. - assets = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return assets <= p.amount diff --git a/policyengine_us/variables/gov/states/ny/otda/tanf/eligibility/ny_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/ny/otda/tanf/eligibility/ny_tanf_resources_eligible.py index 8a5ee8a8fd0..56c2e4af153 100644 --- a/policyengine_us/variables/gov/states/ny/otda/tanf/eligibility/ny_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ny/otda/tanf/eligibility/ny_tanf_resources_eligible.py @@ -34,5 +34,6 @@ def formula(spm_unit, period, parameters): p.resource_limit.higher.amount, p.resource_limit.lower.amount, ) - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= resource_limit diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_resources_eligible.py index 5b29e7bdfb2..0952aef98e3 100644 --- a/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_resources_eligible.py @@ -14,5 +14,6 @@ class ok_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ok.dhs.tanf.resources # Per OAC 340:10-3-5: Maximum countable reserve is $1,000 - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.limit diff --git a/policyengine_us/variables/gov/states/or/odhs/tanf/eligibility/or_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/or/odhs/tanf/eligibility/or_tanf_resources_eligible.py index 58f51d3a206..be74e18548a 100644 --- a/policyengine_us/variables/gov/states/or/odhs/tanf/eligibility/or_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/or/odhs/tanf/eligibility/or_tanf_resources_eligible.py @@ -15,5 +15,8 @@ class or_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states["or"].odhs.tanf.resources.limit # Count explicitly modeled liquid financial assets. - countable_resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents( + spm_unit("spm_unit_cash_assets", period.this_year) + ) return countable_resources <= p.amount diff --git a/policyengine_us/variables/gov/states/pa/dhs/tanf/eligibility/pa_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/pa/dhs/tanf/eligibility/pa_tanf_resources_eligible.py index fb86153e9de..bda666ab06f 100644 --- a/policyengine_us/variables/gov/states/pa/dhs/tanf/eligibility/pa_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/pa/dhs/tanf/eligibility/pa_tanf_resources_eligible.py @@ -12,6 +12,9 @@ class pa_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.pa.dhs.tanf - household_assets = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + household_assets = round_to_cents( + spm_unit("spm_unit_cash_assets", period.this_year) + ) return household_assets <= p.resource_limit diff --git a/policyengine_us/variables/gov/states/ri/dhs/works/eligibility/ri_works_resource_eligible.py b/policyengine_us/variables/gov/states/ri/dhs/works/eligibility/ri_works_resource_eligible.py index 94ed47b2733..bb5033b466b 100644 --- a/policyengine_us/variables/gov/states/ri/dhs/works/eligibility/ri_works_resource_eligible.py +++ b/policyengine_us/variables/gov/states/ri/dhs/works/eligibility/ri_works_resource_eligible.py @@ -14,5 +14,6 @@ class ri_works_resource_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ri.dhs.works - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.resource_limit diff --git a/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_resources_eligible.py index 1e6c3f92bac..83f72782efc 100644 --- a/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_resources_eligible.py @@ -11,5 +11,6 @@ class sc_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.sc.tanf.resources - assets = spm_unit("sc_tanf_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(spm_unit("sc_tanf_countable_resources", period)) return assets <= p.limit diff --git a/policyengine_us/variables/gov/states/sd/dss/tanf/eligibility/sd_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/sd/dss/tanf/eligibility/sd_tanf_resources_eligible.py index 4aa8067f568..2a0feb13035 100644 --- a/policyengine_us/variables/gov/states/sd/dss/tanf/eligibility/sd_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/sd/dss/tanf/eligibility/sd_tanf_resources_eligible.py @@ -11,5 +11,6 @@ class sd_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.sd.dss.tanf.resources - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.limit diff --git a/policyengine_us/variables/gov/states/tn/dhs/ff/eligibility/tn_ff_resources_eligible.py b/policyengine_us/variables/gov/states/tn/dhs/ff/eligibility/tn_ff_resources_eligible.py index 023b4003ece..aba97c3046c 100644 --- a/policyengine_us/variables/gov/states/tn/dhs/ff/eligibility/tn_ff_resources_eligible.py +++ b/policyengine_us/variables/gov/states/tn/dhs/ff/eligibility/tn_ff_resources_eligible.py @@ -10,6 +10,9 @@ class tn_ff_resources_eligible(Variable): defined_for = StateCode.TN def formula(spm_unit, period, parameters): - countable_resources = spm_unit("tn_ff_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents( + spm_unit("tn_ff_countable_resources", period) + ) p = parameters(period).gov.states.tn.dhs.ff.resources return countable_resources <= p.limit diff --git a/policyengine_us/variables/gov/states/tx/tanf/eligibility/tx_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/tx/tanf/eligibility/tx_tanf_resources_eligible.py index 65248230bf3..e438cc96097 100644 --- a/policyengine_us/variables/gov/states/tx/tanf/eligibility/tx_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/tx/tanf/eligibility/tx_tanf_resources_eligible.py @@ -13,7 +13,10 @@ class tx_tanf_resources_eligible(Variable): defined_for = StateCode.TX def formula(spm_unit, period, parameters): - countable_resources = spm_unit("tx_tanf_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents( + spm_unit("tx_tanf_countable_resources", period) + ) p = parameters(period).gov.states.tx.tanf.resources return countable_resources <= p.resource_limit diff --git a/policyengine_us/variables/gov/states/ut/dwf/fep/eligibility/ut_fep_resources_eligible.py b/policyengine_us/variables/gov/states/ut/dwf/fep/eligibility/ut_fep_resources_eligible.py index d4404c00f8e..d08d1e7a029 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/fep/eligibility/ut_fep_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ut/dwf/fep/eligibility/ut_fep_resources_eligible.py @@ -15,5 +15,6 @@ def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ut.dwf.fep.resources.limit # Count liquid financial assets explicitly; other excluded resources # are not yet modeled separately here. - assets = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return assets <= p.amount diff --git a/policyengine_us/variables/gov/states/va/dars/ag/va_ag_eligible.py b/policyengine_us/variables/gov/states/va/dars/ag/va_ag_eligible.py index acc268b6f8e..7a1f7ed8d4d 100644 --- a/policyengine_us/variables/gov/states/va/dars/ag/va_ag_eligible.py +++ b/policyengine_us/variables/gov/states/va/dars/ag/va_ag_eligible.py @@ -18,7 +18,10 @@ def formula(person, period, parameters): person.marital_unit.sum(person("va_ag_is_joint_initial_month", period)) == 2 ) resources = person("ssi_countable_resources", period.this_year) - resources = where(joint, person.marital_unit.sum(resources), resources) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents( + where(joint, person.marital_unit.sum(resources), resources) + ) limits = parameters(period).gov.ssa.ssi.eligibility.resources.limit receives_ssi = (person("ssi", period) > 0) | person("receives_ssi", period) resource_eligible = receives_ssi | ( diff --git a/policyengine_us/variables/gov/states/vt/dcf/reach_up/eligibility/vt_reach_up_resources_eligible.py b/policyengine_us/variables/gov/states/vt/dcf/reach_up/eligibility/vt_reach_up_resources_eligible.py index b0f625dc3f8..5dacf52526e 100644 --- a/policyengine_us/variables/gov/states/vt/dcf/reach_up/eligibility/vt_reach_up_resources_eligible.py +++ b/policyengine_us/variables/gov/states/vt/dcf/reach_up/eligibility/vt_reach_up_resources_eligible.py @@ -14,5 +14,6 @@ def formula(spm_unit, period, parameters): p = parameters(period).gov.states.vt.dcf.reach_up.resources # NOTE: Many exclusions exist (vehicles, retirement accounts, etc.) # that are not separately tracked in PolicyEngine - assets = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return assets <= p.limit diff --git a/policyengine_us/variables/gov/states/wa/dshs/tanf/wa_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/wa/dshs/tanf/wa_tanf_resources_eligible.py index 984fd596db5..ab86366a75e 100644 --- a/policyengine_us/variables/gov/states/wa/dshs/tanf/wa_tanf_resources_eligible.py +++ b/policyengine_us/variables/gov/states/wa/dshs/tanf/wa_tanf_resources_eligible.py @@ -11,5 +11,8 @@ class wa_tanf_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.wa.dshs.tanf - countable_resources = spm_unit("wa_tanf_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents( + spm_unit("wa_tanf_countable_resources", period) + ) return countable_resources <= p.resource_limit diff --git a/policyengine_us/variables/gov/states/wi/dcf/works/eligibility/wi_works_resources_eligible.py b/policyengine_us/variables/gov/states/wi/dcf/works/eligibility/wi_works_resources_eligible.py index 7871b8455c5..14c8e8ce701 100644 --- a/policyengine_us/variables/gov/states/wi/dcf/works/eligibility/wi_works_resources_eligible.py +++ b/policyengine_us/variables/gov/states/wi/dcf/works/eligibility/wi_works_resources_eligible.py @@ -13,6 +13,7 @@ class wi_works_resources_eligible(Variable): defined_for = StateCode.WI def formula(spm_unit, period, parameters): - countable = spm_unit("wi_works_countable_resources", period) + # Inputs are stored as float32, so compare whole cents with the limit. + countable = round_to_cents(spm_unit("wi_works_countable_resources", period)) p = parameters(period).gov.states.wi.dcf.works.asset return countable <= p.limit diff --git a/policyengine_us/variables/gov/states/wv/dhhr/works/eligibility/wv_works_resources_eligible.py b/policyengine_us/variables/gov/states/wv/dhhr/works/eligibility/wv_works_resources_eligible.py index d22bd9bdfa5..8ffbd787b1f 100644 --- a/policyengine_us/variables/gov/states/wv/dhhr/works/eligibility/wv_works_resources_eligible.py +++ b/policyengine_us/variables/gov/states/wv/dhhr/works/eligibility/wv_works_resources_eligible.py @@ -12,5 +12,8 @@ class wv_works_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.wv.dhhr.works.resources # Count explicitly modeled liquid financial assets. - countable_resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + countable_resources = round_to_cents( + spm_unit("spm_unit_cash_assets", period.this_year) + ) return countable_resources <= p.limit diff --git a/policyengine_us/variables/gov/states/wy/dfs/power/eligibility/wy_power_resources_eligible.py b/policyengine_us/variables/gov/states/wy/dfs/power/eligibility/wy_power_resources_eligible.py index 792b0606f84..6e5c7c395a2 100644 --- a/policyengine_us/variables/gov/states/wy/dfs/power/eligibility/wy_power_resources_eligible.py +++ b/policyengine_us/variables/gov/states/wy/dfs/power/eligibility/wy_power_resources_eligible.py @@ -14,5 +14,6 @@ class wy_power_resources_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.wy.dfs.power.resources - resources = spm_unit("spm_unit_cash_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + resources = round_to_cents(spm_unit("spm_unit_cash_assets", period.this_year)) return resources <= p.limit diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/meets_snap_asset_test.py b/policyengine_us/variables/gov/usda/snap/eligibility/meets_snap_asset_test.py index a7b89c647c5..3c03accc5a0 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/meets_snap_asset_test.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/meets_snap_asset_test.py @@ -26,7 +26,8 @@ def formula(spm_unit, period, parameters): # their share at the moment. has_elderly_or_disabled = spm_unit("has_snap_elderly_disabled_member", period) asset_test = parameters(period).gov.usda.snap.asset_test - assets = spm_unit("snap_assets", period.this_year) + # Inputs are stored as float32, so compare whole cents with the limit. + assets = round_to_cents(spm_unit("snap_assets", period.this_year)) asset_limit = where( has_elderly_or_disabled, asset_test.limit.elderly_disabled,