Fix Maine PTFC senior benefit base (mis-typed marginal scale) (#8813)#8814
Conversation
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Review: Fix Maine PTFC senior benefit base (mis-typed marginal scale)
Good catch and a correct, minimal fix. Requesting changes mainly to fix a pre-existing uprating bug that lives in the exact metadata block this PR edits — cheap to fix now — plus a wrong reference link and two test additions.
Verified correct (the fix)
- Adding
type: single_amountmakessenior.calc(65)return $4,100 (inclusive threshold), $0 below 65, unchanged at 66+, and $0 pre-2024 — verified empirically againstSingleAmountTaxScale.calc. The bug was isolated to exactly age 65 (the marginal scale returned $0 there, tripping thesenior_benefit_base != 0fallback to the non-senior base). Metadata now matches siblingproperty_tax/cap.yaml; the incorrect pre-fixunit: currency-USDis correctly removed. - Values confirmed against Maine sources: senior base $4,100 (2025 Schedule PTFC/STFC line 8) / $4,000 (2024, §5219-KK(1)(A-1)(4)), non-senior single $2,550, 4% rate, age 65+ (one spouse suffices), effective TY2024+. Regression test (age 65, 2025, $60k, $5k → $1,700 vs pre-fix $150) discriminates the senior path correctly; 9/9 tests pass.
Requested changes
- Fix the senior base's uprating while you're in this block (pre-existing, but in-scope now).
senior.yaml:14-18declares uprating at the bracket level (uprating: gov.irs.upratingwith a siblingrounding:key) instead of the working nested form used insingle.yaml(uprating: {parameter: gov.irs.uprating, rounding: {...}}). Effect: the senior base stays flat at $4,100 for 2026+ instead of inflation-adjusting per 36 M.R.S. §5403, whereassingle.yamlcorrectly steps 2,550 → 2,600 → … It's latent onmain(not a regression) and doesn't affect the explicit 2024/2025 values — but since this PR is already rewritingsenior.yaml's scale metadata, converting the uprating to the working nested form here avoids leaving the senior base understated in later years. - Reference fix: the "2024 Form 1040ME" entry (
senior.yaml) links to23_1040me_sched_pstfc_ff.pdf— the same URL as the 2023 entry. Point it at the actual 2024 form PDF (locate the real filename on maine.gov/revenue; a naive24_…guess 404s). - Tests:
- The age-64 case doesn't isolate the base (its output is driven by the under-65 cap, so it'd pass even if the senior base wrongly applied at 64). Add a discriminating age-64 mirror of the age-65 case (2025, $60k, $5k → $150).
- Add an MFJ / one-spouse-65+ case (e.g. head 60 / spouse 67, 2025) to exercise the
greater_age_head_spouseselection.
Suggestions
- Replace the
senior_benefit_base != 0sentinel inme_property_tax_fairness_credit_base_cap.py:19with an explicit age / in-effect check for clarity (functionally correct today). senior.yamldescription verb "allows for" isn't in the approved verb list (limits/provides/sets/excludes/deducts/uses) — pre-existing.- Add
absolute_error_marginto the older cases (1-4) for consistency with the newer ones.
🤖 Reviewed with Claude Code
…ence, boundary tests - Convert the senior benefit-base bracket uprating to the working nested form so it inflation-adjusts for 2026+ per 36 M.R.S. §5403 (the flat form with a sibling rounding key silently left it flat at $4,100). - Repoint the 2024 Form 1040ME reference from the 2023 PDF to the actual 2024 Schedule PTFC/STFC PDF (verified live; shows $4,000 senior base). - Add a discriminating age-64 test (->$150, senior base does not apply) and an MFJ one-spouse-67 test (->$1,700, senior base selected via greater_age_head_spouse); add absolute_error_margin to the older cases; fix the description verb. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes applied (addressing @PavelMakarchuk's review)Pushed as Requested changes
Suggestions
CI running now. |
…yEngine#8813) benefit_base/senior.yaml lacked metadata.type: single_amount, so its brackets loaded as a MarginalAmountTaxScale whose calc() treats the threshold as exclusive. At the exact age-65 threshold it returned 0 instead of $4,100, so me_property_tax_fairness_credit_base_cap silently fell back to the non-senior single base and under-computed the credit for 65+ filers (tax years 2024+). Add type: single_amount (matching cap.yaml) plus threshold_unit/amount_unit, and add an age-exactly-65 regression test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ence, boundary tests - Convert the senior benefit-base bracket uprating to the working nested form so it inflation-adjusts for 2026+ per 36 M.R.S. §5403 (the flat form with a sibling rounding key silently left it flat at $4,100). - Repoint the 2024 Form 1040ME reference from the 2023 PDF to the actual 2024 Schedule PTFC/STFC PDF (verified live; shows $4,000 senior base). - Add a discriminating age-64 test (->$150, senior base does not apply) and an MFJ one-spouse-67 test (->$1,700, senior base selected via greater_age_head_spouse); add absolute_error_margin to the older cases; fix the description verb. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The previous revision moved the `uprating:` block into the *bracket's* metadata (`brackets[1].metadata.uprating`). The core uprater only reads `uprating` off leaf Parameter nodes (or a scale-level `metadata.uprating` that it propagates to bracket amounts via ParameterScale.propagate_uprating); a block on the bracket node itself is silently ignored. Empirically the senior base stayed flat at $4,100 for 2026+ despite the block, which is the exact freezing bug the review asked to fix. Nest `uprating:` inside the `amount:` leaf's own metadata (using the `values:`/`metadata:` split form the parser requires for a dated leaf). The senior amount now uprates by gov.irs.uprating, floored to $50: 2025 $4,100 -> 2026 $4,150 -> 2027 $4,300, while the age-65 threshold stays fixed (thresholds only uprate under `uprate_thresholds`). Verified end-to-end through the full system, not just a manual uprate call. Add a 2026 regression test (age 66, $60k income, $5k rent -> $1,750) that discriminates a working uprating from a base frozen at $4,100 (which yields $1,700). Rebased onto main (post PolicyEngine#8907/PolicyEngine#8908); the code-health guard tests/code_health/test_uprating_placement.py stays green (this file uses the scale `brackets` structure, not the `values`/`uprating` sibling form the guard flags). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2b424ed to
9e19995
Compare
Rebased onto main + finished the review items (pushed
|
| Year | Senior base (age 65+) |
|---|---|
| 2025 | $4,100 |
| 2026 | $4,150 |
| 2027 | $4,300 |
| 2028 | $4,350 |
The age-65 threshold stays fixed (thresholds only uprate under uprate_thresholds), so only the amount indexes — which matches the intent of keeping it "inside the bracket so only the amount uprates." Added a 2026 regression test (age 66, $60k income, $5k rent → $1,750) that discriminates a working uprating from a base frozen at $4,100 (which would give $1,700).
Status of each requested change
- Senior-base uprating — now genuinely inflation-adjusts for 2026+ (was still frozen after the prior push; see above). ✅
- 2024 reference — repointed to
24_Form%201040ME_Sch%20PTFC_ff.pdf#page=2. Verified live: header reads "2024 Form 1040ME, Schedule PTFC/STFC, page 2", Line 8 says "If line 7 is yes, enter $4,000", non-senior single $2,450, senior cap $2,000 (Line 12), age 65+ one-spouse-suffices (Line 7). ✅ - Tests — age-64 discriminating case (→ $150) and MFJ one-spouse-67 case (→ $1,700) present from the prior push; added the 2026 uprating-regression case (→ $1,750). ✅
Suggestions
absolute_error_marginon cases 1–4 and the description verb ("allows for" → "provides") were handled in the prior push. ✅- Left the
senior_benefit_base != 0sentinel inme_property_tax_fairness_credit_base_cap.pyas-is, per your note that it's functionally correct today.
Tests
- Full ME baseline directory: 550 passed.
property_tax_fairness_credit/directory: 33 passed (base-cap file now 12 cases).test_uprating_placement.py: passed;test_parameter_files.py(6) andtest_system_import.py(5): passed.ruff format --check/ruff check: clean (no.pytouched).
The changelog fragment now notes both the age-65 threshold fix and the 2026+ uprating fix.
CI noteEverything relevant to this change is green — both baseline ME shards ( The one red check, Full Suite - Contrib (states-shard-2), is a pre-existing CI-infra flake unrelated to this PR. It runs contrib state-reform structural YAML tests ( The same shard is currently failing on |
All requested items verified implemented (see the resolution comment on this thread); dismissing so the verified state can merge.
MaxGhenis
left a comment
There was a problem hiding this comment.
Fable review + agent verification: the author's reference and test asks were verified done; the uprating ask needed real work — the bracket-level metadata placement was empirically dead (flat $4,100 through 2028), and the fix nests it in the amount leaf (verified $4,150/2026, $4,300/2027 exact index math) with a re-freeze regression test. 550 ME tests green; guard test green.
Fixes #8813.
Problem
The Maine Property Tax Fairness Credit under-computed the credit for filers whose older of head/spouse is exactly age 65+ (tax years 2024+): the enhanced senior benefit base silently never applied.
Root cause
parameters/.../fairness/property_tax/benefit_base/senior.yamlwas missingmetadata.type: single_amount, so itsbracketsloaded as aMarginalAmountTaxScaleinstead of aSingleAmountTaxScale. The marginal scale treats the bracket threshold as exclusive, sosenior.calc(65)returned0at the exact threshold. The guard inme_property_tax_fairness_credit_base_cap(senior_benefit_base != 0) then fell back to the non-senior single base.(This is why the existing age-66 test passed — above the threshold the marginal scale coincidentally returns the right amount; only age exactly 65 was broken.)
Fix
type: single_amount(plusthreshold_unit: year/amount_unit: currency-USD, matching the siblingcap.yaml) tosenior.yaml.me_property_tax_fairness_credit_base_cap.yaml: 2025 single filer, income $60,000, countable rent property tax $5,000 → base cap $1,700 (senior base $4,100 − 4% × income). Before the fix this returned $150 (fallback to the $2,550 single base).References
🤖 Generated with Claude Code