Skip to content

Separate the dependent portion of 11 states' personal exemptions#8696

Open
DTrim99 wants to merge 3 commits into
PolicyEngine:mainfrom
DTrim99:separate-state-dependent-exemptions
Open

Separate the dependent portion of 11 states' personal exemptions#8696
DTrim99 wants to merge 3 commits into
PolicyEngine:mainfrom
DTrim99:separate-state-dependent-exemptions

Conversation

@DTrim99

@DTrim99 DTrim99 commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

What this does

Adds Child Poverty Impact Dashboard contrib reforms that separate the dependent portion of each state's per-person personal exemption (or credit) into its own variable + parameters, for 11 states: AR, HI, IN, MD, MI, NE, OH, OK, VT, WI, WV. This mirrors the existing RI/DE/OR/VA reforms and lets the per-dependent amount be adjusted or eliminated independently of the head/spouse exemption (which most of these states bundle together).

Each reform:

  • Defaults to a no-opin_effect=false, and when on, the default amount reproduces current law.
  • Exposes gov.contrib.states.{st}.dependent_exemption.{in_effect, amount, age_limit/*} (AR uses dependent_credit; MD/OH also get a phaseout group).

How each separates

Group States Approach
Bundled per-person exemption → head/spouse + dependent HI, IN, MI, NE, OK, VT, WI, WV Recompute the personal count excluding dependents; add a separate {st}_dependent_exemption. HI preserves its aged add-on; IN leaves the existing per-child additional exemption untouched.
AGI-stepped per-person amount MD, OH Dependent amount defaults to the baseline income-stepped schedule via a negative-amount sentinel (so default = no-op); a non-negative value applies a flat per-dependent amount, plus an optional income phase-out.
Shared credit base AR Redirects the existing person-level dependent slice of the personal credit to a contributed amount (its base is otherwise shared with head/spouse). No age limit — it's summed via adds, which only reflects uniform per-dependent amounts.

Indiana's module directory is the Python keyword in, so it is imported dynamically in reforms.py and uses getattr for parameter access.

Tests

Each state has YAML tests (tests/policy/contrib/states/{st}/) covering: default no-op for a family with children, amount reduction / elimination (amount: 0), childless-filer no-op, and (exemption states) age-limit fallback. All pass. The system smoke-imports cleanly with all 11 registered in create_structural_reforms_from_parameters.

Follow-up

Once released, the dashboard flips these states to amount-editable (separate PR). Companion: #8691 (SC dependent-exemption parameter).

🤖 Generated with Claude Code

DTrim99 and others added 2 commits June 19, 2026 16:09
Adds Child Poverty Impact Dashboard contrib reforms that split the dependent
portion of each state's per-person personal exemption (or credit) into its own
variable + parameters, mirroring the existing RI/DE/OR/VA reforms. Each defaults
to a no-op (in_effect=false; default amount reproduces current law) and lets the
per-dependent amount be adjusted or zeroed independently of the head/spouse
exemption.

States and how they separate:
- Bundled per-person exemption split into head/spouse + dependent: HI (preserves
  the aged add-on), IN (base; the additional per-child exemption is untouched),
  MI, NE, OK, VT, WI, WV.
- AGI-stepped per-person amount (MD, OH): the dependent amount defaults to the
  baseline income-stepped schedule via a negative-amount sentinel, with an
  optional flat override and income phase-out group.
- AR: redirects the existing person-level dependent slice of the personal credit
  to a contributed amount (its base is otherwise shared with head/spouse). No
  age limit, since it is summed via `adds`.

Each reform exposes in_effect + amount (+ age_limit for the exemption states;
+ phaseout for MD/OH). Indiana's module dir is the Python keyword `in`, so it is
imported dynamically in reforms.py and uses getattr for parameter access.

Parameters under gov.contrib.states.{st}.dependent_exemption (AR:
dependent_credit). Registered in reforms.py. Each state has YAML tests covering
the default no-op, amount reduction/elimination, childless-filer no-op, and
age-limit fallback; all pass. System smoke-imports cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…coverage

- Remove accidentally committed SEP_MSG.tmp scratch file from repo root
- HI dependent-exemption reform: use `reference` field instead of `documentation`
- Add MD/OH flat-amount and phaseout test cases (previously untested paths)
- Add joint-filing test cases (MD, OH, MI, AR, HI, IN) covering the
  head/spouse-vs-dependent count split in 2-adult units
- Strengthen MD/OH no-op case documentation

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@DTrim99 DTrim99 requested a review from PavelMakarchuk June 22, 2026 17:07

@PavelMakarchuk PavelMakarchuk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Program Review — Separate the dependent portion of 11 states' personal exemptions

Scope: Child Poverty Impact Dashboard contrib reforms, 11 states (AR, HI, IN, MD, MI, NE, OH, OK, VT, WI, WV) · three separation patterns (bundled split; AGI-stepped sentinel + phaseout; shared credit-base redirect)

A large but disciplined PR. All four review dimensions cleared the implementation: every state defaults to a verified no-op, cross-state isolation holds (no copy-paste/wrong-state references — the main risk in a multi-state PR), variable overrides match their baselines exactly, and all 55 YAML cases pass. Requesting changes to tighten the test suite before merge — the gaps are in what the tests prove, not in the code.

Requested changes

  1. Add an end-to-end tax/net-income assertion (systemic — affects all 11 states). Every test currently asserts the reform's own exemption/credit-total variable (e.g. md_total_personal_exemptions, hi_regular_exemptions, ar_personal_credits) — one level above the per-dependent variable, which does prove the head/spouse split arithmetic. But no test asserts state taxable income, state tax, or net income, so the exemption→tax wiring is unproven end-to-end. AR is most exposed (it asserts only a credit total, never a resulting AR tax/net-income figure). Please add at least one downstream-outcome case — ideally for AR plus one bundled-split state and MD/OH.

  2. Add the joint 2-adult case to NE, OK, VT, WI, WV. These five states have 4 cases and omit the joint two-adult + dependents case that HI/IN/MI/MD/OH/AR include. That case is precisely what catches off-by-one / sign-flip errors in the personal_count = size − dependents + over-age dependents formula — the risk the PR description itself flags. Add a joint 2-adult + 2-dependent case to each, mirroring HI/IN/MI.

Suggestions (non-blocking)

  • Re-run the canceled "Quick Feedback (Selective Tests + Coverage)" job — it was canceled by an infra runner-shutdown, not a real failure (the Full Suite - Contrib (states-shard-*) jobs that run these tests all passed).
  • Several count variables are typed float / unit = USD (should be int/count); unused instant import in ~7 reform files.
  • Most contrib params omit reference — consistent with the merged DE/RI/VA/OR siblings, so optional; a one-line provenance comment on each amount.yaml noting it mirrors the state baseline would make the derivation explicit.
  • Minor consistency: inconsistent state-level __init__.py presence (works via namespace packages); WI/WV test values lack numeric underscores; effective-date style varies (0000-01-01 vs 2025-01-01) for inert defaults.

Validation Summary

Check Result
Regulatory Accuracy ✅ No-op fidelity verified for all 11; bundled-split arithmetic, MD/OH sentinel, and state-specific preservations (HI aged add-on, IN per-child exemption, AR credit base, MI stillborn, OK extras, WV size==0) all correct; isolation confirmed
Reference Quality ✅ All 11 default amounts trace to state baselines; metadata complete & consistent with siblings
Code Patterns ✅ All update_variable overrides match baseline name/entity/period/value_type; non-negative fallback counts; IN dynamic import correct; 5-year gating loop references each state's own parameter — no cross-state leakage
Test Coverage ⚠️ No-op + elimination + special mechanics covered; gaps: no downstream-tax assertion; 5 states lack joint case
CI Status ⚠️ One job canceled by infra (runner shutdown) — not a code failure; contrib state shards passed

Review Severity: REQUEST_CHANGES (approve-leaning — gaps are test-completeness only)

To auto-fix: /fix-pr 8696

🤖 Generated with Claude Code

Resolves PavelMakarchuk review on PR PolicyEngine#8696:
- Add downstream-tax/net-income assertions (AR, MI, MD, OH) so tests
  no longer stop at intermediate exemption/credit variables
- Add married-filing-joint 2-adult cases for NE, OK, VT, WI, WV
- Add age-17 (eligible) / age-18 (excluded) boundary cases for all 10
  age-limit states
- Enrich AR dependent credit reference (AR1000F Line 7A + statute
  subsections); fix WI/WV test literal underscores
- Remove unused `instant` imports (7 reform modules); add ne/wi
  re-export __init__.py; type dependent-count helpers as int (drop USD)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@DTrim99

DTrim99 commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

Fixes Applied (full scope)

Addresses PavelMakarchuk's review. CI: the prior "Full Suite - Rest" failure was a runner cancellation, not a test failure.

Blocking review items

  • Downstream-outcome assertions — tests no longer stop at intermediate exemption/credit variables; added state taxable-income / tax-reducing assertions for AR (ar_non_refundable_credits), MI (mi_taxable_income), MD (md_exemptions), and OH (oh_taxable_income), confirming the dependent-exemption change flows through.
  • Joint 2-adult cases — added married-filing-joint cases for NE, OK, VT, WI, WV (HI/IN/MI/MD/OH/AR already had them), verifying the head/spouse-vs-dependent count split has no off-by-one.

Suggestions

  • Age-limit boundary tests — age-17 (eligible) / age-18 (excluded) cases for all 10 age-limit states.
  • AR reference — added AR1000F instructions (Line 7A, where $29 appears) plus statute subsections, mirroring the AR baseline parameter.
  • WI/WV test literals — added missing numeric underscores.
  • Module cleanups — removed unused instant imports (7 reform modules); added the missing ne/wi re-export __init__.py; typed the dependent-count helper variables as int (dropped the spurious USD unit).

Verification

  • Reform modules + reforms.py import cleanly (py3.11).
  • Local contrib test run for all 11 states was passing (no failures); CI on this PR is the authoritative gate.
  • No duplicate test cases; no parameter/reform-logic changes beyond the cleanups above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants