From b23b5c7515386b4be4c03e8c6d1e9f8ef20ab488 Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Wed, 1 Jul 2026 14:21:01 -0400 Subject: [PATCH 1/3] Add dependent-exemption/credit age-gate contributed reforms for 13 states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds gov.contrib.states.{st}.dependent_exemption / dependent_credit contributed reforms so a state's per-dependent exemption or credit can be adjusted, eliminated, or age-limited (restricted to dependents under a chosen age). This lets tools model eliminating the exemption/credit only for young children and swapping it for a child allowance. Each contrib has an in_effect flag, an amount (default reproduces the baseline, so activating at default is a no-op — a negative sentinel means "use the baseline schedule" for the stepped states), and an age_limit (in_effect + threshold). New contribs: - Separate-variable states: NY, IL, MS, NJ, SC - Bundled personal+dependent carve-out: GA, KS, MN (MN's AGI phase-out preserved) - Exemption-credit states: CA, IA (per-dependent portion separated) - Income/age-stepped: AL (AGI-stepped, reads the baseline schedule), AZ (age-based schedule) Also adds an age_limit sub-tree to the existing AR dependent_credit contrib and age-gates its person-level per-dependent amount. Each state has a YAML test: default reproduces baseline; amount 0 eliminates the dependent portion only; the age limit restricts to under-threshold dependents. All pass against the current engine. Also fixes CLAUDE.md to note the default branch is `main`, not `master`. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 8 +- .../al-dependent-exemption-age-gate.added.md | 1 + .../ar-dependent-credit-age-limit.added.md | 1 + .../az-dependent-credit-age-gate.added.md | 1 + .../ca-dependent-credit-age-gate.added.md | 1 + .../ga-dependent-exemption-age-gate.added.md | 1 + .../ia-dependent-credit-age-gate.added.md | 1 + .../il-dependent-exemption-age-gate.added.md | 1 + .../ks-dependent-exemption-age-gate.added.md | 1 + .../mn-dependent-exemption-age-gate.added.md | 1 + .../ms-dependent-exemption-age-gate.added.md | 1 + .../nj-dependent-exemption-age-gate.added.md | 1 + .../ny-dependent-exemption-age-gate.added.md | 1 + .../sc-dependent-exemption-age-gate.added.md | 1 + .../age_limit/in_effect.yaml | 7 + .../age_limit/threshold.yaml | 7 + .../states/al/dependent_exemption/amount.yaml | 7 + .../al/dependent_exemption/in_effect.yaml | 7 + .../dependent_credit/age_limit/in_effect.yaml | 7 + .../dependent_credit/age_limit/threshold.yaml | 7 + .../dependent_credit/age_limit/in_effect.yaml | 7 + .../dependent_credit/age_limit/threshold.yaml | 7 + .../states/az/dependent_credit/amount.yaml | 7 + .../states/az/dependent_credit/in_effect.yaml | 7 + .../dependent_credit/age_limit/in_effect.yaml | 9 ++ .../dependent_credit/age_limit/threshold.yaml | 9 ++ .../states/ca/dependent_credit/amount.yaml | 9 ++ .../states/ca/dependent_credit/in_effect.yaml | 9 ++ .../age_limit/in_effect.yaml | 9 ++ .../age_limit/threshold.yaml | 9 ++ .../states/ga/dependent_exemption/amount.yaml | 15 ++ .../ga/dependent_exemption/in_effect.yaml | 9 ++ .../dependent_credit/age_limit/in_effect.yaml | 9 ++ .../dependent_credit/age_limit/threshold.yaml | 9 ++ .../states/ia/dependent_credit/amount.yaml | 9 ++ .../states/ia/dependent_credit/in_effect.yaml | 9 ++ .../age_limit/in_effect.yaml | 7 + .../age_limit/threshold.yaml | 7 + .../states/il/dependent_exemption/amount.yaml | 10 ++ .../il/dependent_exemption/in_effect.yaml | 7 + .../age_limit/in_effect.yaml | 9 ++ .../age_limit/threshold.yaml | 9 ++ .../states/ks/dependent_exemption/amount.yaml | 14 ++ .../ks/dependent_exemption/in_effect.yaml | 9 ++ .../age_limit/in_effect.yaml | 7 + .../age_limit/threshold.yaml | 7 + .../states/mn/dependent_exemption/amount.yaml | 19 +++ .../mn/dependent_exemption/in_effect.yaml | 7 + .../age_limit/in_effect.yaml | 7 + .../age_limit/threshold.yaml | 7 + .../states/ms/dependent_exemption/amount.yaml | 10 ++ .../ms/dependent_exemption/in_effect.yaml | 7 + .../age_limit/in_effect.yaml | 7 + .../age_limit/threshold.yaml | 7 + .../states/nj/dependent_exemption/amount.yaml | 10 ++ .../nj/dependent_exemption/in_effect.yaml | 7 + .../age_limit/in_effect.yaml | 7 + .../age_limit/threshold.yaml | 7 + .../states/ny/dependent_exemption/amount.yaml | 10 ++ .../ny/dependent_exemption/in_effect.yaml | 7 + .../age_limit/in_effect.yaml | 7 + .../age_limit/threshold.yaml | 7 + .../states/sc/dependent_exemption/amount.yaml | 19 +++ .../sc/dependent_exemption/in_effect.yaml | 7 + policyengine_us/reforms/reforms.py | 60 +++++++ .../states/al/dependent_exemption/__init__.py | 5 + .../al_dependent_exemption_reform.py | 59 +++++++ .../ar_dependent_credit_reform.py | 18 ++- .../states/az/dependent_credit/__init__.py | 5 + .../az_dependent_credit_reform.py | 66 ++++++++ .../states/ca/dependent_credit/__init__.py | 5 + .../ca_dependent_credit_reform.py | 97 ++++++++++++ .../states/ga/dependent_exemption/__init__.py | 5 + .../ga_dependent_exemption_reform.py | 100 ++++++++++++ .../states/ia/dependent_credit/__init__.py | 5 + .../ia_dependent_credit_reform.py | 87 ++++++++++ .../states/il/dependent_exemption/__init__.py | 5 + .../il_dependent_exemption_reform.py | 59 +++++++ .../states/ks/dependent_exemption/__init__.py | 5 + .../ks_dependent_exemption_reform.py | 149 ++++++++++++++++++ .../states/mn/dependent_exemption/__init__.py | 5 + .../mn_dependent_exemption_reform.py | 84 ++++++++++ .../states/ms/dependent_exemption/__init__.py | 5 + .../ms_dependent_exemption_reform.py | 59 +++++++ .../states/nj/dependent_exemption/__init__.py | 5 + .../nj_dependent_exemption_reform.py | 66 ++++++++ .../states/ny/dependent_exemption/__init__.py | 5 + .../ny_dependent_exemption_reform.py | 60 +++++++ .../states/sc/dependent_exemption/__init__.py | 5 + .../sc_dependent_exemption_reform.py | 69 ++++++++ .../al/dependent_exemption_reform_test.yaml | 41 +++++ .../ar/dependent_credit_reform_test.yaml | 15 ++ .../az/dependent_credit_reform_test.yaml | 41 +++++ .../ca/dependent_credit_reform_test.yaml | 54 +++++++ .../ga/dependent_exemption_reform_test.yaml | 55 +++++++ .../ia/dependent_credit_reform_test.yaml | 54 +++++++ .../il/dependent_exemption_reform_test.yaml | 41 +++++ .../ks/dependent_exemption_reform_test.yaml | 73 +++++++++ .../mn/dependent_exemption_reform_test.yaml | 97 ++++++++++++ .../ms/dependent_exemption_reform_test.yaml | 41 +++++ .../nj/dependent_exemption_reform_test.yaml | 60 +++++++ .../ny/dependent_exemption_reform_test.yaml | 41 +++++ .../sc/dependent_exemption_reform_test.yaml | 57 +++++++ 103 files changed, 2205 insertions(+), 8 deletions(-) create mode 100644 changelog.d/al-dependent-exemption-age-gate.added.md create mode 100644 changelog.d/ar-dependent-credit-age-limit.added.md create mode 100644 changelog.d/az-dependent-credit-age-gate.added.md create mode 100644 changelog.d/ca-dependent-credit-age-gate.added.md create mode 100644 changelog.d/ga-dependent-exemption-age-gate.added.md create mode 100644 changelog.d/ia-dependent-credit-age-gate.added.md create mode 100644 changelog.d/il-dependent-exemption-age-gate.added.md create mode 100644 changelog.d/ks-dependent-exemption-age-gate.added.md create mode 100644 changelog.d/mn-dependent-exemption-age-gate.added.md create mode 100644 changelog.d/ms-dependent-exemption-age-gate.added.md create mode 100644 changelog.d/nj-dependent-exemption-age-gate.added.md create mode 100644 changelog.d/ny-dependent-exemption-age-gate.added.md create mode 100644 changelog.d/sc-dependent-exemption-age-gate.added.md create mode 100644 policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ar/dependent_credit/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ar/dependent_credit/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/az/dependent_credit/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/az/dependent_credit/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/az/dependent_credit/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/az/dependent_credit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/age_limit/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/age_limit/threshold.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/in_effect.yaml create mode 100644 policyengine_us/reforms/states/al/dependent_exemption/__init__.py create mode 100644 policyengine_us/reforms/states/al/dependent_exemption/al_dependent_exemption_reform.py create mode 100644 policyengine_us/reforms/states/az/dependent_credit/__init__.py create mode 100644 policyengine_us/reforms/states/az/dependent_credit/az_dependent_credit_reform.py create mode 100644 policyengine_us/reforms/states/ca/dependent_credit/__init__.py create mode 100644 policyengine_us/reforms/states/ca/dependent_credit/ca_dependent_credit_reform.py create mode 100644 policyengine_us/reforms/states/ga/dependent_exemption/__init__.py create mode 100644 policyengine_us/reforms/states/ga/dependent_exemption/ga_dependent_exemption_reform.py create mode 100644 policyengine_us/reforms/states/ia/dependent_credit/__init__.py create mode 100644 policyengine_us/reforms/states/ia/dependent_credit/ia_dependent_credit_reform.py create mode 100644 policyengine_us/reforms/states/il/dependent_exemption/__init__.py create mode 100644 policyengine_us/reforms/states/il/dependent_exemption/il_dependent_exemption_reform.py create mode 100644 policyengine_us/reforms/states/ks/dependent_exemption/__init__.py create mode 100644 policyengine_us/reforms/states/ks/dependent_exemption/ks_dependent_exemption_reform.py create mode 100644 policyengine_us/reforms/states/mn/dependent_exemption/__init__.py create mode 100644 policyengine_us/reforms/states/mn/dependent_exemption/mn_dependent_exemption_reform.py create mode 100644 policyengine_us/reforms/states/ms/dependent_exemption/__init__.py create mode 100644 policyengine_us/reforms/states/ms/dependent_exemption/ms_dependent_exemption_reform.py create mode 100644 policyengine_us/reforms/states/nj/dependent_exemption/__init__.py create mode 100644 policyengine_us/reforms/states/nj/dependent_exemption/nj_dependent_exemption_reform.py create mode 100644 policyengine_us/reforms/states/ny/dependent_exemption/__init__.py create mode 100644 policyengine_us/reforms/states/ny/dependent_exemption/ny_dependent_exemption_reform.py create mode 100644 policyengine_us/reforms/states/sc/dependent_exemption/__init__.py create mode 100644 policyengine_us/reforms/states/sc/dependent_exemption/sc_dependent_exemption_reform.py create mode 100644 policyengine_us/tests/policy/contrib/states/al/dependent_exemption_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/az/dependent_credit_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/ca/dependent_credit_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/ga/dependent_exemption_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/ia/dependent_credit_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/il/dependent_exemption_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/ks/dependent_exemption_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/mn/dependent_exemption_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/ms/dependent_exemption_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/nj/dependent_exemption_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/ny/dependent_exemption_reform_test.yaml create mode 100644 policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml diff --git a/CLAUDE.md b/CLAUDE.md index 114c80793b4..311d083f90f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -53,6 +53,12 @@ make documentation ``` ## GitHub Workflow +- **Default branch is `main`, NOT `master`.** Base new work on `main`: + `git fetch upstream main && git checkout -b upstream/main`. A personal + fork's `origin/master` is often stale or absent — `git checkout master` can + silently land you on an ancient commit (e.g. a 1.44.x-era tree missing recent + contribs), so always branch from `upstream/main` (or `origin/main` when the fork + is current). Note the upstream remote uses `main` and has no `master` ref. - Checkout a PR: `gh pr checkout [PR-NUMBER]` - View PR list: `gh pr list` - View PR details: `gh pr view [PR-NUMBER]` @@ -84,7 +90,7 @@ changelog.d/medicaid-ce-exclusions.md ## Project Requirements - Python >= 3.11, < 3.15 -- Follow GitHub Flow with PRs targeting master branch +- Follow GitHub Flow with PRs targeting the `main` branch (the default branch is `main`, **not** `master`) - Every PR needs a changelog fragment in `changelog.d/` - **ALWAYS run `make format` before every commit** - this is mandatory diff --git a/changelog.d/al-dependent-exemption-age-gate.added.md b/changelog.d/al-dependent-exemption-age-gate.added.md new file mode 100644 index 00000000000..cfff0fdfbca --- /dev/null +++ b/changelog.d/al-dependent-exemption-age-gate.added.md @@ -0,0 +1 @@ +Added an Alabama dependent exemption contributed reform with an adjustable per-dependent amount and optional age limit. diff --git a/changelog.d/ar-dependent-credit-age-limit.added.md b/changelog.d/ar-dependent-credit-age-limit.added.md new file mode 100644 index 00000000000..a07160e1a08 --- /dev/null +++ b/changelog.d/ar-dependent-credit-age-limit.added.md @@ -0,0 +1 @@ +Added an optional age limit to the Arkansas dependent tax credit contributed reform. diff --git a/changelog.d/az-dependent-credit-age-gate.added.md b/changelog.d/az-dependent-credit-age-gate.added.md new file mode 100644 index 00000000000..a5a45a7d9fd --- /dev/null +++ b/changelog.d/az-dependent-credit-age-gate.added.md @@ -0,0 +1 @@ +Added an Arizona dependent tax credit contributed reform with an adjustable per-dependent amount and optional age limit. diff --git a/changelog.d/ca-dependent-credit-age-gate.added.md b/changelog.d/ca-dependent-credit-age-gate.added.md new file mode 100644 index 00000000000..7341c698d0a --- /dev/null +++ b/changelog.d/ca-dependent-credit-age-gate.added.md @@ -0,0 +1 @@ +Add California dependent credit age-gate contributed reform. diff --git a/changelog.d/ga-dependent-exemption-age-gate.added.md b/changelog.d/ga-dependent-exemption-age-gate.added.md new file mode 100644 index 00000000000..09817f801d5 --- /dev/null +++ b/changelog.d/ga-dependent-exemption-age-gate.added.md @@ -0,0 +1 @@ +Added Georgia dependent exemption age-gate contributed reform. diff --git a/changelog.d/ia-dependent-credit-age-gate.added.md b/changelog.d/ia-dependent-credit-age-gate.added.md new file mode 100644 index 00000000000..59eab2e021e --- /dev/null +++ b/changelog.d/ia-dependent-credit-age-gate.added.md @@ -0,0 +1 @@ +Add Iowa dependent credit age-gate contributed reform. diff --git a/changelog.d/il-dependent-exemption-age-gate.added.md b/changelog.d/il-dependent-exemption-age-gate.added.md new file mode 100644 index 00000000000..5f833a7f7e1 --- /dev/null +++ b/changelog.d/il-dependent-exemption-age-gate.added.md @@ -0,0 +1 @@ +Added Illinois dependent exemption age-gate contributed reform. diff --git a/changelog.d/ks-dependent-exemption-age-gate.added.md b/changelog.d/ks-dependent-exemption-age-gate.added.md new file mode 100644 index 00000000000..504d671d964 --- /dev/null +++ b/changelog.d/ks-dependent-exemption-age-gate.added.md @@ -0,0 +1 @@ +Added Kansas dependent exemption age-gate contributed reform. diff --git a/changelog.d/mn-dependent-exemption-age-gate.added.md b/changelog.d/mn-dependent-exemption-age-gate.added.md new file mode 100644 index 00000000000..0116e9532af --- /dev/null +++ b/changelog.d/mn-dependent-exemption-age-gate.added.md @@ -0,0 +1 @@ +Add Minnesota dependent exemption age-gate contributed reform. diff --git a/changelog.d/ms-dependent-exemption-age-gate.added.md b/changelog.d/ms-dependent-exemption-age-gate.added.md new file mode 100644 index 00000000000..8ad909405ec --- /dev/null +++ b/changelog.d/ms-dependent-exemption-age-gate.added.md @@ -0,0 +1 @@ +Added Mississippi dependent exemption age-gate contributed reform. diff --git a/changelog.d/nj-dependent-exemption-age-gate.added.md b/changelog.d/nj-dependent-exemption-age-gate.added.md new file mode 100644 index 00000000000..13dab473711 --- /dev/null +++ b/changelog.d/nj-dependent-exemption-age-gate.added.md @@ -0,0 +1 @@ +Add New Jersey dependent exemption age-gate contributed reform. diff --git a/changelog.d/ny-dependent-exemption-age-gate.added.md b/changelog.d/ny-dependent-exemption-age-gate.added.md new file mode 100644 index 00000000000..3bca2e49082 --- /dev/null +++ b/changelog.d/ny-dependent-exemption-age-gate.added.md @@ -0,0 +1 @@ +Added a New York dependent exemption contributed reform with an adjustable per-dependent amount and an optional age limit. diff --git a/changelog.d/sc-dependent-exemption-age-gate.added.md b/changelog.d/sc-dependent-exemption-age-gate.added.md new file mode 100644 index 00000000000..1a10e4cb11d --- /dev/null +++ b/changelog.d/sc-dependent-exemption-age-gate.added.md @@ -0,0 +1 @@ +Add South Carolina dependent exemption age-gate contributed reform. diff --git a/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/age_limit/in_effect.yaml new file mode 100644 index 00000000000..11d85bb9e8c --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/age_limit/in_effect.yaml @@ -0,0 +1,7 @@ +description: Alabama limits the dependent exemption to dependents under a given age when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Alabama dependent exemption age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/age_limit/threshold.yaml new file mode 100644 index 00000000000..7979839859a --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/age_limit/threshold.yaml @@ -0,0 +1,7 @@ +description: Alabama limits the dependent exemption to dependents under this age when the age limit is in effect. +values: + 2021-01-01: 18 +metadata: + unit: year + period: year + label: Alabama dependent exemption age threshold diff --git a/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/amount.yaml new file mode 100644 index 00000000000..4b4be5cb230 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/amount.yaml @@ -0,0 +1,7 @@ +description: Alabama provides this dependent exemption amount per eligible dependent under the contributed reform. A negative sentinel uses the baseline AGI-stepped amount (a no-op at default); a non-negative value applies a flat per-dependent amount. +values: + 0000-01-01: -1 +metadata: + unit: currency-USD + period: year + label: Alabama dependent exemption reform amount diff --git a/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/in_effect.yaml new file mode 100644 index 00000000000..1fe840f041a --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/al/dependent_exemption/in_effect.yaml @@ -0,0 +1,7 @@ +description: Alabama applies an adjustable dependent exemption reform when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Alabama dependent exemption reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ar/dependent_credit/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ar/dependent_credit/age_limit/in_effect.yaml new file mode 100644 index 00000000000..ec16e5804be --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ar/dependent_credit/age_limit/in_effect.yaml @@ -0,0 +1,7 @@ +description: Arkansas limits the dependent tax credit to dependents under a given age when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Arkansas dependent credit age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ar/dependent_credit/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/ar/dependent_credit/age_limit/threshold.yaml new file mode 100644 index 00000000000..76a37e97ea3 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ar/dependent_credit/age_limit/threshold.yaml @@ -0,0 +1,7 @@ +description: Arkansas limits the dependent tax credit to dependents under this age when the age limit is in effect. +values: + 2021-01-01: 18 +metadata: + unit: year + period: year + label: Arkansas dependent credit age threshold diff --git a/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/age_limit/in_effect.yaml new file mode 100644 index 00000000000..4d74a9df97d --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/age_limit/in_effect.yaml @@ -0,0 +1,7 @@ +description: Arizona limits the dependent tax credit to dependents under a given age when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Arizona dependent credit age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/age_limit/threshold.yaml new file mode 100644 index 00000000000..810266542c7 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/age_limit/threshold.yaml @@ -0,0 +1,7 @@ +description: Arizona limits the dependent tax credit to dependents under this age when the age limit is in effect. +values: + 2021-01-01: 18 +metadata: + unit: year + period: year + label: Arizona dependent credit age threshold diff --git a/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/amount.yaml b/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/amount.yaml new file mode 100644 index 00000000000..11c6795dd75 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/amount.yaml @@ -0,0 +1,7 @@ +description: Arizona provides this dependent tax credit amount per eligible dependent under the contributed reform. A negative sentinel uses the baseline age-based amount (a no-op at default); a non-negative value applies a flat per-dependent amount. +values: + 0000-01-01: -1 +metadata: + unit: currency-USD + period: year + label: Arizona dependent credit reform amount diff --git a/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/in_effect.yaml new file mode 100644 index 00000000000..01a3bd859ce --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/az/dependent_credit/in_effect.yaml @@ -0,0 +1,7 @@ +description: Arizona applies an adjustable dependent tax credit reform when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Arizona dependent credit reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/age_limit/in_effect.yaml new file mode 100644 index 00000000000..0821488b4d5 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/age_limit/in_effect.yaml @@ -0,0 +1,9 @@ +description: California limits the dependent exemption credit to dependents under a certain age, if this is true. + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: California dependent credit age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/age_limit/threshold.yaml new file mode 100644 index 00000000000..4ce5ad06ce0 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/age_limit/threshold.yaml @@ -0,0 +1,9 @@ +description: California limits the dependent exemption credit to dependents under this age. + +values: + 2025-01-01: 18 + +metadata: + label: California dependent credit age threshold + period: year + unit: year diff --git a/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/amount.yaml b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/amount.yaml new file mode 100644 index 00000000000..c7b4c4f1c4c --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/amount.yaml @@ -0,0 +1,9 @@ +description: California provides this dependent exemption credit amount per eligible dependent under the reform. + +values: + 2025-01-01: 475 + +metadata: + label: California dependent credit amount + period: year + unit: currency-USD diff --git a/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/in_effect.yaml new file mode 100644 index 00000000000..4792b3201cd --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/in_effect.yaml @@ -0,0 +1,9 @@ +description: California applies the dependent exemption credit reform, if this is true (separates the per-dependent exemption credit from the personal exemption credits so it can be re-priced and age-gated). + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: California dependent credit reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/age_limit/in_effect.yaml new file mode 100644 index 00000000000..af6eebadbd2 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/age_limit/in_effect.yaml @@ -0,0 +1,9 @@ +description: Georgia limits the dependent exemption to dependents under a certain age, if this is true. + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: Georgia dependent exemption age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/age_limit/threshold.yaml new file mode 100644 index 00000000000..3b85d128b41 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/age_limit/threshold.yaml @@ -0,0 +1,9 @@ +description: Georgia limits the dependent exemption to dependents under this age. + +values: + 2025-01-01: 18 + +metadata: + label: Georgia dependent exemption age threshold + period: year + unit: year diff --git a/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/amount.yaml new file mode 100644 index 00000000000..334d112b182 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/amount.yaml @@ -0,0 +1,15 @@ +description: Georgia provides this per-dependent exemption amount under the reform. + +values: + 2024-01-01: 4_000 + 2026-01-01: 5_000 + +metadata: + label: Georgia dependent exemption amount + period: year + unit: currency-USD + reference: + - title: 2025 IT-511 Individual Income Tax Booklet - page 17 - FORM 500, LINE 14 + href: https://dor.georgia.gov/document/document/2025-it-511-individual-income-tax-booklet/download#page=17 + - title: Georgia HB463 (2025-2026), Section 2-2 amending O.C.G.A. § 48-7-26(b) + href: https://www.legis.ga.gov/api/legislation/document/20252026/249080#page=3 diff --git a/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/in_effect.yaml new file mode 100644 index 00000000000..d3eb8c5130d --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ga/dependent_exemption/in_effect.yaml @@ -0,0 +1,9 @@ +description: Georgia applies the dependent exemption reform, if this is true (modifies only the per-dependent exemption, not the personal exemption). + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: Georgia dependent exemption reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/age_limit/in_effect.yaml new file mode 100644 index 00000000000..6a27ae23c98 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/age_limit/in_effect.yaml @@ -0,0 +1,9 @@ +description: Iowa limits the dependent exemption credit to dependents under a certain age, if this is true. + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: Iowa dependent credit age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/age_limit/threshold.yaml new file mode 100644 index 00000000000..c06eb88e06e --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/age_limit/threshold.yaml @@ -0,0 +1,9 @@ +description: Iowa limits the dependent exemption credit to dependents under this age. + +values: + 2021-01-01: 18 + +metadata: + label: Iowa dependent credit age threshold + period: year + unit: year diff --git a/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/amount.yaml b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/amount.yaml new file mode 100644 index 00000000000..b85297353dc --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/amount.yaml @@ -0,0 +1,9 @@ +description: Iowa provides this dependent exemption credit amount per eligible dependent under the reform. + +values: + 2021-01-01: 40 + +metadata: + label: Iowa dependent credit amount + period: year + unit: currency-USD diff --git a/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/in_effect.yaml new file mode 100644 index 00000000000..7ab03872a5c --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/in_effect.yaml @@ -0,0 +1,9 @@ +description: Iowa applies the dependent exemption credit reform, if this is true (separates the per-dependent exemption credit from the personal exemption credit so it can be re-priced and age-gated). + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: Iowa dependent credit reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/age_limit/in_effect.yaml new file mode 100644 index 00000000000..4924d8f6af7 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/age_limit/in_effect.yaml @@ -0,0 +1,7 @@ +description: Illinois limits the dependent exemption to dependents under a given age when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Illinois dependent exemption age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/age_limit/threshold.yaml new file mode 100644 index 00000000000..d02b4b56e4a --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/age_limit/threshold.yaml @@ -0,0 +1,7 @@ +description: Illinois limits the dependent exemption to dependents under this age when the age limit is in effect. +values: + 2021-01-01: 18 +metadata: + unit: year + period: year + label: Illinois dependent exemption age threshold diff --git a/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/amount.yaml new file mode 100644 index 00000000000..c3c1e2b9a02 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/amount.yaml @@ -0,0 +1,10 @@ +description: Illinois provides this dependent exemption amount per eligible dependent under the contributed reform. Defaults to the baseline amount, so activating the reform at the default is a no-op. +values: + 2021-01-01: 2_850 +metadata: + unit: currency-USD + period: year + label: Illinois dependent exemption reform amount + reference: + - title: 2025 Schedule IL-E/EIC - Illinois Exemption and Earned Income Credit + href: https://tax.illinois.gov/content/dam/soi/en/web/tax/forms/incometax/documents/currentyear/individual/il-1040-schedule-il-e-eic.pdf#page=1 diff --git a/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/in_effect.yaml new file mode 100644 index 00000000000..1dcf329592c --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/in_effect.yaml @@ -0,0 +1,7 @@ +description: Illinois applies a separate, adjustable dependent exemption reform when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Illinois dependent exemption reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/age_limit/in_effect.yaml new file mode 100644 index 00000000000..7f5d17337c7 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/age_limit/in_effect.yaml @@ -0,0 +1,9 @@ +description: Kansas limits the dependent exemption to dependents under a certain age, if this is true. + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: Kansas dependent exemption age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/age_limit/threshold.yaml new file mode 100644 index 00000000000..a2a1445954b --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/age_limit/threshold.yaml @@ -0,0 +1,9 @@ +description: Kansas limits the dependent exemption to dependents under this age. + +values: + 2025-01-01: 18 + +metadata: + label: Kansas dependent exemption age threshold + period: year + unit: year diff --git a/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/amount.yaml new file mode 100644 index 00000000000..b7bb1add123 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/amount.yaml @@ -0,0 +1,14 @@ +description: Kansas provides this per-dependent exemption amount under the reform. + +values: + 2021-01-01: 2_320 + +metadata: + label: Kansas dependent exemption amount + period: year + unit: currency-USD + reference: + - title: 2025 Form K-40 instructions + href: https://www.ksrevenue.gov/pdf/ip25.pdf#page=2 + - title: Kan. Stat. 79-32,121 (a) + href: https://casetext.com/statute/kansas-statutes/chapter-79-taxation/article-32-income-tax/section-79-32121-kansas-exemption-for-an-individual diff --git a/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/in_effect.yaml new file mode 100644 index 00000000000..f9c9258ad3e --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/in_effect.yaml @@ -0,0 +1,9 @@ +description: Kansas applies the dependent exemption reform, if this is true (modifies only the per-dependent exemption, not the personal exemption). + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: Kansas dependent exemption reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/age_limit/in_effect.yaml new file mode 100644 index 00000000000..1cc83aef3d3 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/age_limit/in_effect.yaml @@ -0,0 +1,7 @@ +description: Minnesota limits the dependent exemption to dependents under a given age when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Minnesota dependent exemption age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/age_limit/threshold.yaml new file mode 100644 index 00000000000..8ae576d66ab --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/age_limit/threshold.yaml @@ -0,0 +1,7 @@ +description: Minnesota limits the dependent exemption to dependents under this age when the age limit is in effect. +values: + 2021-01-01: 18 +metadata: + unit: year + period: year + label: Minnesota dependent exemption age threshold diff --git a/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/amount.yaml new file mode 100644 index 00000000000..94f413dea71 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/amount.yaml @@ -0,0 +1,19 @@ +description: Minnesota provides this dependent exemption amount per eligible dependent under the contributed reform. Defaults to the baseline current-law amount, so activating the reform at the default is a no-op. +values: + 2021-01-01: 4_350 + 2022-01-01: 4_450 + 2023-01-01: 4_800 + 2024-01-01: 5_050 + 2025-01-01: 5_200 +metadata: + period: year + unit: currency-USD + label: Minnesota dependent exemption reform amount per dependent + uprating: + parameter: gov.irs.uprating + rounding: + type: downwards + interval: 50 + reference: + - title: Minnesota Statutes 290.0121 DEPENDENT EXEMPTION. Subd. 1. Exemption amount. + href: https://www.revisor.mn.gov/statutes/cite/290.0121#stat.290.0121.1 diff --git a/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/in_effect.yaml new file mode 100644 index 00000000000..10fe8fc9fa2 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/mn/dependent_exemption/in_effect.yaml @@ -0,0 +1,7 @@ +description: Minnesota applies a separate, adjustable dependent exemption reform when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Minnesota dependent exemption reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/age_limit/in_effect.yaml new file mode 100644 index 00000000000..a90ecf6b9cc --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/age_limit/in_effect.yaml @@ -0,0 +1,7 @@ +description: Mississippi limits the dependent exemption to dependents under a given age when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Mississippi dependent exemption age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/age_limit/threshold.yaml new file mode 100644 index 00000000000..dd7c56f4fe8 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/age_limit/threshold.yaml @@ -0,0 +1,7 @@ +description: Mississippi limits the dependent exemption to dependents under this age when the age limit is in effect. +values: + 2021-01-01: 18 +metadata: + unit: year + period: year + label: Mississippi dependent exemption age threshold diff --git a/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/amount.yaml new file mode 100644 index 00000000000..c08a85a8590 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/amount.yaml @@ -0,0 +1,10 @@ +description: Mississippi provides this dependent exemption amount per eligible dependent under the contributed reform. Defaults to the baseline amount, so activating the reform at the default is a no-op. +values: + 2021-01-01: 1_500 +metadata: + unit: currency-USD + period: year + label: Mississippi dependent exemption reform amount + reference: + - title: Mississippi Income Tax Instructions 2025 + href: https://www.dor.ms.gov/sites/default/files/tax-forms/individual/80100251%202.pdf#page=6 diff --git a/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/in_effect.yaml new file mode 100644 index 00000000000..b75b5d940d2 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ms/dependent_exemption/in_effect.yaml @@ -0,0 +1,7 @@ +description: Mississippi applies a separate, adjustable dependent exemption reform when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: Mississippi dependent exemption reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/age_limit/in_effect.yaml new file mode 100644 index 00000000000..433fe2166e7 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/age_limit/in_effect.yaml @@ -0,0 +1,7 @@ +description: New Jersey re-prices the dependent exemption only for dependents under a given age when this is true; older dependents keep the baseline exemption. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: New Jersey dependent exemption age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/age_limit/threshold.yaml new file mode 100644 index 00000000000..12803ce458b --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/age_limit/threshold.yaml @@ -0,0 +1,7 @@ +description: New Jersey re-prices the dependent exemption only for dependents under this age when the age limit is in effect. +values: + 2021-01-01: 18 +metadata: + unit: year + period: year + label: New Jersey dependent exemption age threshold diff --git a/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/amount.yaml new file mode 100644 index 00000000000..e07a8d8fa62 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/amount.yaml @@ -0,0 +1,10 @@ +description: New Jersey provides this dependent exemption amount per eligible dependent under the contributed reform. Defaults to the baseline amount, so activating the reform at the default is a no-op. +values: + 2021-01-01: 1_500 +metadata: + unit: currency-USD + period: year + label: New Jersey dependent exemption reform amount + reference: + - title: 2025 NJ-1040 Instructions (Lines 10-11) + href: https://www.nj.gov/treasury/taxation/pdf/current/1040i.pdf#page=8 diff --git a/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/in_effect.yaml new file mode 100644 index 00000000000..5743b81d122 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/nj/dependent_exemption/in_effect.yaml @@ -0,0 +1,7 @@ +description: New Jersey applies a separate, adjustable dependent exemption reform when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: New Jersey dependent exemption reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/age_limit/in_effect.yaml new file mode 100644 index 00000000000..67ca3b1e012 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/age_limit/in_effect.yaml @@ -0,0 +1,7 @@ +description: New York limits the dependent exemption to dependents under a given age when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: New York dependent exemption age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/age_limit/threshold.yaml new file mode 100644 index 00000000000..6e47be39cd8 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/age_limit/threshold.yaml @@ -0,0 +1,7 @@ +description: New York limits the dependent exemption to dependents under this age when the age limit is in effect. +values: + 2021-01-01: 18 +metadata: + unit: year + period: year + label: New York dependent exemption age threshold diff --git a/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/amount.yaml new file mode 100644 index 00000000000..e2b31d3929b --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/amount.yaml @@ -0,0 +1,10 @@ +description: New York provides this dependent exemption amount per eligible dependent under the contributed reform. Defaults to the baseline amount, so activating the reform at the default is a no-op. +values: + 2021-01-01: 1_000 +metadata: + unit: currency-USD + period: year + label: New York dependent exemption reform amount + reference: + - title: 2025 Form IT-201-I Instructions Line 36 + href: https://www.tax.ny.gov/pdf/current_forms/it/it201i.pdf#page=11 diff --git a/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/in_effect.yaml new file mode 100644 index 00000000000..00886da7c12 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/ny/dependent_exemption/in_effect.yaml @@ -0,0 +1,7 @@ +description: New York applies a separate, adjustable dependent exemption reform when this is true. +values: + 2021-01-01: false +metadata: + unit: bool + period: year + label: New York dependent exemption reform in effect diff --git a/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/age_limit/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/age_limit/in_effect.yaml new file mode 100644 index 00000000000..9bf6bae77ed --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/age_limit/in_effect.yaml @@ -0,0 +1,7 @@ +description: South Carolina re-prices the dependent exemption only for dependents under a given age when this is true; older dependents keep the baseline exemption. +values: + 2019-01-01: false +metadata: + unit: bool + period: year + label: South Carolina dependent exemption age limit in effect diff --git a/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/age_limit/threshold.yaml b/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/age_limit/threshold.yaml new file mode 100644 index 00000000000..df4409b49fa --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/age_limit/threshold.yaml @@ -0,0 +1,7 @@ +description: South Carolina re-prices the dependent exemption only for dependents under this age when the age limit is in effect. +values: + 2019-01-01: 18 +metadata: + unit: year + period: year + label: South Carolina dependent exemption age threshold diff --git a/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/amount.yaml new file mode 100644 index 00000000000..68964e368e0 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/amount.yaml @@ -0,0 +1,19 @@ +description: South Carolina provides this dependent exemption amount per eligible dependent under the contributed reform. Defaults to the baseline amount, so activating the reform at the default is a no-op. +values: + 2019-01-01: 4_100 + 2021-01-01: 4_300 + 2022-01-01: 4_430 + 2023-01-01: 4_610 + 2024-01-01: 4_790 + 2025-01-01: 4_930 +metadata: + unit: currency-USD + period: year + uprating: gov.irs.uprating + rounding: + type: downwards + interval: 10 + label: South Carolina dependent exemption reform amount + reference: + - title: SC 1040 tax form instructions (2025) + href: https://dor.sc.gov/sites/dor/files/forms/SC1040Instr_2025.pdf#page=16 diff --git a/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/in_effect.yaml new file mode 100644 index 00000000000..e73366c8b7b --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/sc/dependent_exemption/in_effect.yaml @@ -0,0 +1,7 @@ +description: South Carolina applies a separate, adjustable dependent exemption reform when this is true. +values: + 2019-01-01: false +metadata: + unit: bool + period: year + label: South Carolina dependent exemption reform in effect diff --git a/policyengine_us/reforms/reforms.py b/policyengine_us/reforms/reforms.py index 4849fb9168b..67d5c0a5f62 100644 --- a/policyengine_us/reforms/reforms.py +++ b/policyengine_us/reforms/reforms.py @@ -162,6 +162,42 @@ from .states.hi.dependent_exemption.hi_dependent_exemption_reform import ( create_hi_dependent_exemption_reform_fn, ) +from .states.ny.dependent_exemption.ny_dependent_exemption_reform import ( + create_ny_dependent_exemption_reform_fn, +) +from .states.il.dependent_exemption.il_dependent_exemption_reform import ( + create_il_dependent_exemption_reform_fn, +) +from .states.ms.dependent_exemption.ms_dependent_exemption_reform import ( + create_ms_dependent_exemption_reform_fn, +) +from .states.nj.dependent_exemption.nj_dependent_exemption_reform import ( + create_nj_dependent_exemption_reform_fn, +) +from .states.sc.dependent_exemption.sc_dependent_exemption_reform import ( + create_sc_dependent_exemption_reform_fn, +) +from .states.ks.dependent_exemption.ks_dependent_exemption_reform import ( + create_ks_dependent_exemption_reform_fn, +) +from .states.ga.dependent_exemption.ga_dependent_exemption_reform import ( + create_ga_dependent_exemption_reform_fn, +) +from .states.mn.dependent_exemption.mn_dependent_exemption_reform import ( + create_mn_dependent_exemption_reform_fn, +) +from .states.al.dependent_exemption.al_dependent_exemption_reform import ( + create_al_dependent_exemption_reform_fn, +) +from .states.ca.dependent_credit.ca_dependent_credit_reform import ( + create_ca_dependent_credit_reform_fn, +) +from .states.ia.dependent_credit.ia_dependent_credit_reform import ( + create_ia_dependent_credit_reform_fn, +) +from .states.az.dependent_credit.az_dependent_credit_reform import ( + create_az_dependent_credit_reform_fn, +) from .states.md.dependent_exemption.md_dependent_exemption_reform import ( create_md_dependent_exemption_reform_fn, ) @@ -451,6 +487,18 @@ def create_structural_reforms_from_parameters(parameters, period): wv_dependent_exemption = create_wv_dependent_exemption_reform_fn(parameters, period) wi_dependent_exemption = create_wi_dependent_exemption_reform_fn(parameters, period) hi_dependent_exemption = create_hi_dependent_exemption_reform_fn(parameters, period) + ny_dependent_exemption = create_ny_dependent_exemption_reform_fn(parameters, period) + il_dependent_exemption = create_il_dependent_exemption_reform_fn(parameters, period) + ms_dependent_exemption = create_ms_dependent_exemption_reform_fn(parameters, period) + nj_dependent_exemption = create_nj_dependent_exemption_reform_fn(parameters, period) + sc_dependent_exemption = create_sc_dependent_exemption_reform_fn(parameters, period) + ks_dependent_exemption = create_ks_dependent_exemption_reform_fn(parameters, period) + ga_dependent_exemption = create_ga_dependent_exemption_reform_fn(parameters, period) + mn_dependent_exemption = create_mn_dependent_exemption_reform_fn(parameters, period) + al_dependent_exemption = create_al_dependent_exemption_reform_fn(parameters, period) + ca_dependent_credit = create_ca_dependent_credit_reform_fn(parameters, period) + ia_dependent_credit = create_ia_dependent_credit_reform_fn(parameters, period) + az_dependent_credit = create_az_dependent_credit_reform_fn(parameters, period) md_dependent_exemption = create_md_dependent_exemption_reform_fn(parameters, period) oh_dependent_exemption = create_oh_dependent_exemption_reform_fn(parameters, period) ar_dependent_credit = create_ar_dependent_credit_reform_fn(parameters, period) @@ -592,6 +640,18 @@ def create_structural_reforms_from_parameters(parameters, period): wv_dependent_exemption, wi_dependent_exemption, hi_dependent_exemption, + ny_dependent_exemption, + il_dependent_exemption, + ms_dependent_exemption, + nj_dependent_exemption, + sc_dependent_exemption, + ks_dependent_exemption, + ga_dependent_exemption, + mn_dependent_exemption, + al_dependent_exemption, + ca_dependent_credit, + ia_dependent_credit, + az_dependent_credit, md_dependent_exemption, oh_dependent_exemption, ar_dependent_credit, diff --git a/policyengine_us/reforms/states/al/dependent_exemption/__init__.py b/policyengine_us/reforms/states/al/dependent_exemption/__init__.py new file mode 100644 index 00000000000..aa8fbc03d8f --- /dev/null +++ b/policyengine_us/reforms/states/al/dependent_exemption/__init__.py @@ -0,0 +1,5 @@ +from .al_dependent_exemption_reform import ( + create_al_dependent_exemption, + create_al_dependent_exemption_reform_fn, + al_dependent_exemption_reform, +) diff --git a/policyengine_us/reforms/states/al/dependent_exemption/al_dependent_exemption_reform.py b/policyengine_us/reforms/states/al/dependent_exemption/al_dependent_exemption_reform.py new file mode 100644 index 00000000000..7891f445fca --- /dev/null +++ b/policyengine_us/reforms/states/al/dependent_exemption/al_dependent_exemption_reform.py @@ -0,0 +1,59 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_al_dependent_exemption() -> Reform: + class al_dependent_exemption(Variable): + value_type = float + entity = TaxUnit + label = "Alabama dependent exemption" + unit = USD + definition_period = YEAR + defined_for = StateCode.AL + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.al.dependent_exemption + p_base = parameters(period).gov.states.al.tax.income.exemptions + al_agi = tax_unit("al_agi", period) + person = tax_unit.members + is_dependent = person("is_tax_unit_dependent", period) + if p.age_limit.in_effect: + age = person("age", period) + eligible = is_dependent & (age < p.age_limit.threshold) + else: + eligible = is_dependent + count = tax_unit.sum(eligible) + per_dependent = where(p.amount < 0, p_base.dependent.calc(al_agi), p.amount) + return count * per_dependent + + class reform(Reform): + def apply(self): + self.update_variable(al_dependent_exemption) + + return reform + + +def create_al_dependent_exemption_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_al_dependent_exemption() + + p = parameters.gov.contrib.states.al.dependent_exemption + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_al_dependent_exemption() + else: + return None + + +al_dependent_exemption_reform = create_al_dependent_exemption_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/ar/dependent_credit/ar_dependent_credit_reform.py b/policyengine_us/reforms/states/ar/dependent_credit/ar_dependent_credit_reform.py index e09314a848a..2e12a55fa4c 100644 --- a/policyengine_us/reforms/states/ar/dependent_credit/ar_dependent_credit_reform.py +++ b/policyengine_us/reforms/states/ar/dependent_credit/ar_dependent_credit_reform.py @@ -12,15 +12,19 @@ class ar_personal_credit_dependent(Variable): defined_for = StateCode.AR def formula(person, period, parameters): - # Separate the dependent portion of Arkansas's personal tax credit - # so its per-dependent amount can be set independently of the - # head/spouse credit (which keeps reading personal.amount.base). - # No age limit: this person-level credit is consumed via ``adds`` - # in ar_personal_credits_potential, which only reflects uniform - # per-dependent amounts, so a per-dependent age gate is not exposed. + # Separate the dependent portion of the personal tax credit so its + # per-dependent amount can be set independently. An optional age + # limit zeroes the credit for dependents at or over the threshold + # age; this person-level amount is summed via adds in + # ar_personal_credits_potential, so the age gate composes. p = parameters(period).gov.contrib.states.ar.dependent_credit is_dependent = person("is_tax_unit_dependent", period) - return is_dependent * p.amount + if p.age_limit.in_effect: + age = person("age", period) + eligible = is_dependent & (age < p.age_limit.threshold) + else: + eligible = is_dependent + return eligible * p.amount class reform(Reform): def apply(self): diff --git a/policyengine_us/reforms/states/az/dependent_credit/__init__.py b/policyengine_us/reforms/states/az/dependent_credit/__init__.py new file mode 100644 index 00000000000..a4e9c65fc25 --- /dev/null +++ b/policyengine_us/reforms/states/az/dependent_credit/__init__.py @@ -0,0 +1,5 @@ +from .az_dependent_credit_reform import ( + create_az_dependent_credit, + create_az_dependent_credit_reform_fn, + az_dependent_credit_reform, +) diff --git a/policyengine_us/reforms/states/az/dependent_credit/az_dependent_credit_reform.py b/policyengine_us/reforms/states/az/dependent_credit/az_dependent_credit_reform.py new file mode 100644 index 00000000000..badd857571e --- /dev/null +++ b/policyengine_us/reforms/states/az/dependent_credit/az_dependent_credit_reform.py @@ -0,0 +1,66 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_az_dependent_credit() -> Reform: + class az_dependent_tax_credit_potential(Variable): + value_type = float + entity = TaxUnit + label = "Arizona dependent tax credit" + unit = USD + definition_period = YEAR + defined_for = StateCode.AZ + + def formula(tax_unit, period, parameters): + person = tax_unit.members + p_base = parameters( + period + ).gov.states.az.tax.income.credits.dependent_credit + p = parameters(period).gov.contrib.states.az.dependent_credit + dependent = person("is_tax_unit_dependent", period) + age = person("age", period) + if p.age_limit.in_effect: + eligible = dependent & (age < p.age_limit.threshold) + else: + eligible = dependent + per_dependent = where(p.amount < 0, p_base.amount.calc(age), p.amount) + amount = tax_unit.sum(per_dependent * eligible) + income = tax_unit("adjusted_gross_income", period) + filing_status = tax_unit("filing_status", period) + reduction_start = p_base.reduction.start[filing_status] + excess = max_(income - reduction_start, 0) + increments = np.ceil(excess / p_base.reduction.increment) + reduction_percentage = min_(increments * p_base.reduction.percentage, 1) + return amount * (1 - reduction_percentage) + + class reform(Reform): + def apply(self): + self.update_variable(az_dependent_tax_credit_potential) + + return reform + + +def create_az_dependent_credit_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_az_dependent_credit() + + p = parameters.gov.contrib.states.az.dependent_credit + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_az_dependent_credit() + else: + return None + + +az_dependent_credit_reform = create_az_dependent_credit_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/ca/dependent_credit/__init__.py b/policyengine_us/reforms/states/ca/dependent_credit/__init__.py new file mode 100644 index 00000000000..a8d15f313f4 --- /dev/null +++ b/policyengine_us/reforms/states/ca/dependent_credit/__init__.py @@ -0,0 +1,5 @@ +from .ca_dependent_credit_reform import ( + create_ca_dependent_credit_reform, + create_ca_dependent_credit_reform_fn, + ca_dependent_credit_reform, +) diff --git a/policyengine_us/reforms/states/ca/dependent_credit/ca_dependent_credit_reform.py b/policyengine_us/reforms/states/ca/dependent_credit/ca_dependent_credit_reform.py new file mode 100644 index 00000000000..d190f71b159 --- /dev/null +++ b/policyengine_us/reforms/states/ca/dependent_credit/ca_dependent_credit_reform.py @@ -0,0 +1,97 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_ca_dependent_credit_reform() -> Reform: + class ca_exemptions(Variable): + value_type = float + entity = TaxUnit + label = "CA Exemptions" + defined_for = StateCode.CA + unit = USD + definition_period = YEAR + reference = "https://www.ftb.ca.gov/forms/2021/2021-540.pdf" + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.ca.tax.income.exemptions + c = parameters(period).gov.contrib.states.ca.dependent_credit + agi = tax_unit("adjusted_gross_income", period) + filing_status = tax_unit("filing_status", period) + + # Calculating phase out amount per credit + over_agi_threshold = max_(0, agi - p.phase_out.start[filing_status]) + increments = np.ceil( + over_agi_threshold / p.phase_out.increment[filing_status] + ) + exemption_reduction = increments * p.phase_out.amount + + # Personal exemptions (unchanged) + personal_exemption_count = p.personal_scale[filing_status] + personal_aged_blind_exemption_count = personal_exemption_count + tax_unit( + "aged_blind_count", period + ) + personal_aged_blind_exemption = max_( + 0, + personal_aged_blind_exemption_count * (p.amount - exemption_reduction), + ) + + # Split dependents into age-eligible (re-priced) and over-age + # (baseline) groups. When the age limit is not in effect every + # dependent is age-eligible, matching the baseline count. + person = tax_unit.members + age = person("age", period) + is_dependent = person("is_tax_unit_dependent", period) + if c.age_limit.in_effect: + eligible = is_dependent & (age < c.age_limit.threshold) + else: + eligible = is_dependent + eligible_count = tax_unit.sum(eligible) + total_dependents = tax_unit.sum(is_dependent) + older_count = max_(0, total_dependents - eligible_count) + + # Re-priced dependent credit for age-eligible dependents. + eligible_dependent_exemption = max_( + 0, eligible_count * (c.amount - exemption_reduction) + ) + # Over-age dependents keep the baseline dependent exemption amount. + older_dependent_exemption = max_( + 0, older_count * (p.dependent_amount - exemption_reduction) + ) + + return ( + personal_aged_blind_exemption + + eligible_dependent_exemption + + older_dependent_exemption + ) + + class reform(Reform): + def apply(self): + self.update_variable(ca_exemptions) + + return reform + + +def create_ca_dependent_credit_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_ca_dependent_credit_reform() + + p = parameters.gov.contrib.states.ca.dependent_credit + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_ca_dependent_credit_reform() + else: + return None + + +ca_dependent_credit_reform = create_ca_dependent_credit_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/ga/dependent_exemption/__init__.py b/policyengine_us/reforms/states/ga/dependent_exemption/__init__.py new file mode 100644 index 00000000000..343daea5071 --- /dev/null +++ b/policyengine_us/reforms/states/ga/dependent_exemption/__init__.py @@ -0,0 +1,5 @@ +from .ga_dependent_exemption_reform import ( + create_ga_dependent_exemption, + create_ga_dependent_exemption_reform_fn, + ga_dependent_exemption_reform, +) diff --git a/policyengine_us/reforms/states/ga/dependent_exemption/ga_dependent_exemption_reform.py b/policyengine_us/reforms/states/ga/dependent_exemption/ga_dependent_exemption_reform.py new file mode 100644 index 00000000000..a481f29abd6 --- /dev/null +++ b/policyengine_us/reforms/states/ga/dependent_exemption/ga_dependent_exemption_reform.py @@ -0,0 +1,100 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_ga_dependent_exemption() -> Reform: + class ga_eligible_dependents_count(Variable): + value_type = int + entity = TaxUnit + label = "Georgia eligible dependents count" + definition_period = YEAR + defined_for = StateCode.GA + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.ga.dependent_exemption + + person = tax_unit.members + age = person("age", period) + is_dependent = person("is_tax_unit_dependent", period) + + # Apply age limit if in effect. + if p.age_limit.in_effect: + age_threshold = p.age_limit.threshold + eligible_dependents = is_dependent & (age < age_threshold) + else: + eligible_dependents = is_dependent + + return tax_unit.sum(eligible_dependents) + + class ga_dependent_exemption(Variable): + value_type = float + entity = TaxUnit + label = "Georgia dependent exemption" + unit = USD + definition_period = YEAR + defined_for = StateCode.GA + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.ga.dependent_exemption + + dependents_count = tax_unit("ga_eligible_dependents_count", period) + return dependents_count * p.amount + + class ga_exemptions(Variable): + value_type = float + entity = TaxUnit + label = "Georgia Exemptions" + defined_for = StateCode.GA + unit = USD + definition_period = YEAR + reference = ( + "https://apps.dor.ga.gov/FillableForms/PDFViewer/Index?form=2022GA500", + ) + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.ga.tax.income.exemptions + + # Separated, age-gated and re-priced dependent exemption. Georgia + # provides no per-dependent personal exemption, so over-age dependents + # fall back to the personal treatment, which is nothing. + dependent_exemptions = tax_unit("ga_dependent_exemption", period) + + if p.personal.availability: + filing_status = tax_unit("filing_status", period) + personal_exemptions = p.personal.amount[filing_status] + return personal_exemptions + dependent_exemptions + return dependent_exemptions + + class reform(Reform): + def apply(self): + self.update_variable(ga_eligible_dependents_count) + self.update_variable(ga_dependent_exemption) + self.update_variable(ga_exemptions) + + return reform + + +def create_ga_dependent_exemption_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_ga_dependent_exemption() + + p = parameters.gov.contrib.states.ga.dependent_exemption + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_ga_dependent_exemption() + else: + return None + + +ga_dependent_exemption_reform = create_ga_dependent_exemption_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/ia/dependent_credit/__init__.py b/policyengine_us/reforms/states/ia/dependent_credit/__init__.py new file mode 100644 index 00000000000..86935d90bb9 --- /dev/null +++ b/policyengine_us/reforms/states/ia/dependent_credit/__init__.py @@ -0,0 +1,5 @@ +from .ia_dependent_credit_reform import ( + create_ia_dependent_credit_reform, + create_ia_dependent_credit_reform_fn, + ia_dependent_credit_reform, +) diff --git a/policyengine_us/reforms/states/ia/dependent_credit/ia_dependent_credit_reform.py b/policyengine_us/reforms/states/ia/dependent_credit/ia_dependent_credit_reform.py new file mode 100644 index 00000000000..446ae2e4c34 --- /dev/null +++ b/policyengine_us/reforms/states/ia/dependent_credit/ia_dependent_credit_reform.py @@ -0,0 +1,87 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_ia_dependent_credit_reform() -> Reform: + class ia_exemption_credit(Variable): + value_type = float + entity = TaxUnit + label = "Iowa exemption credit" + unit = USD + definition_period = YEAR + reference = ( + "https://revenue.iowa.gov/sites/default/files/2021-12/IA6251%2841131%29.pdf", + "https://revenue.iowa.gov/sites/default/files/2023-01/IA6251%2841131%29.pdf", + ) + defined_for = StateCode.IA + + def formula(tax_unit, period, parameters): + # Count adult and dependent exemptions + adult_count = tax_unit("head_spouse_count", period) + filing_status = tax_unit("filing_status", period) + hoh_status = filing_status.possible_values.HEAD_OF_HOUSEHOLD + hoh_bonus = filing_status == hoh_status + # Count extra adult exemptions based on being elderly and/or blind + p = parameters(period).gov.states.ia.tax.income + exemption = p.credits.exemption + c = parameters(period).gov.contrib.states.ia.dependent_credit + elder_head = tax_unit("age_head", period) >= exemption.elderly_age + elder_spouse = tax_unit("age_spouse", period) >= exemption.elderly_age + elder_count = elder_head.astype(int) + elder_spouse.astype(int) + blind_head = tax_unit("blind_head", period) + blind_spouse = tax_unit("blind_spouse", period) + blind_count = blind_head.astype(int) + blind_spouse.astype(int) + additional_count = elder_count + blind_count + + # Split dependents into age-eligible (re-priced) and over-age + # (baseline) groups. When the age limit is not in effect every + # dependent is age-eligible, matching the baseline count. + person = tax_unit.members + age = person("age", period) + is_dependent = person("is_tax_unit_dependent", period) + if c.age_limit.in_effect: + eligible = is_dependent & (age < c.age_limit.threshold) + else: + eligible = is_dependent + eligible_count = tax_unit.sum(eligible) + total_dependents = tax_unit.sum(is_dependent) + older_count = max_(0, total_dependents - eligible_count) + + return ( + (adult_count + hoh_bonus) * exemption.personal + + additional_count * exemption.additional + + eligible_count * c.amount + + older_count * exemption.dependent + ) + + class reform(Reform): + def apply(self): + self.update_variable(ia_exemption_credit) + + return reform + + +def create_ia_dependent_credit_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_ia_dependent_credit_reform() + + p = parameters.gov.contrib.states.ia.dependent_credit + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_ia_dependent_credit_reform() + else: + return None + + +ia_dependent_credit_reform = create_ia_dependent_credit_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/il/dependent_exemption/__init__.py b/policyengine_us/reforms/states/il/dependent_exemption/__init__.py new file mode 100644 index 00000000000..2112991ccf6 --- /dev/null +++ b/policyengine_us/reforms/states/il/dependent_exemption/__init__.py @@ -0,0 +1,5 @@ +from .il_dependent_exemption_reform import ( + create_il_dependent_exemption, + create_il_dependent_exemption_reform_fn, + il_dependent_exemption_reform, +) diff --git a/policyengine_us/reforms/states/il/dependent_exemption/il_dependent_exemption_reform.py b/policyengine_us/reforms/states/il/dependent_exemption/il_dependent_exemption_reform.py new file mode 100644 index 00000000000..9b2ee01bfe6 --- /dev/null +++ b/policyengine_us/reforms/states/il/dependent_exemption/il_dependent_exemption_reform.py @@ -0,0 +1,59 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_il_dependent_exemption() -> Reform: + class il_dependent_exemption(Variable): + value_type = float + entity = TaxUnit + label = "Illinois dependent exemption" + unit = USD + definition_period = YEAR + defined_for = StateCode.IL + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.il.dependent_exemption + person = tax_unit.members + is_dependent = person("is_tax_unit_dependent", period) + # Age gate: when in effect, restrict the exemption to dependents + # under the chosen age; otherwise every dependent qualifies, + # matching the baseline tax_unit_dependents count. + if p.age_limit.in_effect: + age = person("age", period) + eligible = is_dependent & (age < p.age_limit.threshold) + else: + eligible = is_dependent + count = tax_unit.sum(eligible) + return count * p.amount + + class reform(Reform): + def apply(self): + self.update_variable(il_dependent_exemption) + + return reform + + +def create_il_dependent_exemption_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_il_dependent_exemption() + + p = parameters.gov.contrib.states.il.dependent_exemption + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_il_dependent_exemption() + else: + return None + + +il_dependent_exemption_reform = create_il_dependent_exemption_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/ks/dependent_exemption/__init__.py b/policyengine_us/reforms/states/ks/dependent_exemption/__init__.py new file mode 100644 index 00000000000..0662e11d0be --- /dev/null +++ b/policyengine_us/reforms/states/ks/dependent_exemption/__init__.py @@ -0,0 +1,5 @@ +from .ks_dependent_exemption_reform import ( + create_ks_dependent_exemption, + create_ks_dependent_exemption_reform_fn, + ks_dependent_exemption_reform, +) diff --git a/policyengine_us/reforms/states/ks/dependent_exemption/ks_dependent_exemption_reform.py b/policyengine_us/reforms/states/ks/dependent_exemption/ks_dependent_exemption_reform.py new file mode 100644 index 00000000000..f7bb85ea843 --- /dev/null +++ b/policyengine_us/reforms/states/ks/dependent_exemption/ks_dependent_exemption_reform.py @@ -0,0 +1,149 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_ks_dependent_exemption() -> Reform: + class ks_eligible_dependents_count(Variable): + value_type = int + entity = TaxUnit + label = "Kansas eligible dependents count" + definition_period = YEAR + defined_for = StateCode.KS + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.ks.dependent_exemption + + person = tax_unit.members + age = person("age", period) + is_dependent = person("is_tax_unit_dependent", period) + + # Apply age limit if in effect. + if p.age_limit.in_effect: + age_threshold = p.age_limit.threshold + eligible_dependents = is_dependent & (age < age_threshold) + else: + eligible_dependents = is_dependent + + return tax_unit.sum(eligible_dependents) + + class ks_dependent_exemption(Variable): + value_type = float + entity = TaxUnit + label = "Kansas dependent exemption" + unit = USD + definition_period = YEAR + defined_for = StateCode.KS + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.ks.dependent_exemption + + dependents_count = tax_unit("ks_eligible_dependents_count", period) + return dependents_count * p.amount + + class ks_older_dependents_count(Variable): + value_type = int + entity = TaxUnit + label = "Kansas older dependents count" + definition_period = YEAR + defined_for = StateCode.KS + + def formula(tax_unit, period, parameters): + person = tax_unit.members + is_dependent = person("is_tax_unit_dependent", period) + total_dependents = tax_unit.sum(is_dependent) + eligible_dependent_exemptions = tax_unit( + "ks_eligible_dependents_count", period + ) + return max_(0, total_dependents - eligible_dependent_exemptions) + + class ks_exemptions(Variable): + value_type = float + entity = TaxUnit + label = "Kansas exemptions amount" + unit = USD + definition_period = YEAR + reference = "https://law.justia.com/codes/kansas/chapter-79/article-32/section-79-32-121/" + defined_for = StateCode.KS + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.ks.tax.income.exemptions + + veteran_exemptions_count = add( + tax_unit, + period, + ["ks_disabled_veteran_exemptions_eligible_person"], + ) + veterans_exemption_amount = ( + veteran_exemptions_count * p.disabled_veteran.base + ) + + # Separated, age-gated and re-priced dependent exemption. + dependent_exemption_amount = tax_unit("ks_dependent_exemption", period) + + if p.by_filing_status.in_effect: + filing_status = tax_unit("filing_status", period) + base_amount = p.by_filing_status.amount[filing_status] + head_of_household = ( + filing_status == filing_status.possible_values.HEAD_OF_HOUSEHOLD + ) + head_of_household_additional_amount = ( + head_of_household * p.by_filing_status.hoh_additional_amount + ) + # Personal portion excludes the per-dependent exemption. In this + # regime Kansas provides no per-dependent personal exemption, so + # over-age dependents fall back to the personal treatment, which + # is nothing. + personal_amount = ( + base_amount + + veterans_exemption_amount + + head_of_household_additional_amount + ) + return personal_amount + dependent_exemption_amount + + # Consolidated regime: each person, including dependents, receives the + # consolidated per-person exemption. Remove eligible dependents from the + # personal count (their exemption is re-priced separately); over-age + # dependents remain in the personal count and fall back to the base + # per-person amount. + exemptions_count = tax_unit("ks_count_exemptions", period) + eligible_dependents = tax_unit("ks_eligible_dependents_count", period) + personal_count = exemptions_count - eligible_dependents + personal_amount = ( + personal_count * p.consolidated.amount + veterans_exemption_amount + ) + return personal_amount + dependent_exemption_amount + + class reform(Reform): + def apply(self): + self.update_variable(ks_eligible_dependents_count) + self.update_variable(ks_dependent_exemption) + self.update_variable(ks_older_dependents_count) + self.update_variable(ks_exemptions) + + return reform + + +def create_ks_dependent_exemption_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_ks_dependent_exemption() + + p = parameters.gov.contrib.states.ks.dependent_exemption + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_ks_dependent_exemption() + else: + return None + + +ks_dependent_exemption_reform = create_ks_dependent_exemption_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/mn/dependent_exemption/__init__.py b/policyengine_us/reforms/states/mn/dependent_exemption/__init__.py new file mode 100644 index 00000000000..79f1cd0f7e2 --- /dev/null +++ b/policyengine_us/reforms/states/mn/dependent_exemption/__init__.py @@ -0,0 +1,5 @@ +from .mn_dependent_exemption_reform import ( + create_mn_dependent_exemption, + create_mn_dependent_exemption_reform_fn, + mn_dependent_exemption_reform, +) diff --git a/policyengine_us/reforms/states/mn/dependent_exemption/mn_dependent_exemption_reform.py b/policyengine_us/reforms/states/mn/dependent_exemption/mn_dependent_exemption_reform.py new file mode 100644 index 00000000000..6ef99a8ea57 --- /dev/null +++ b/policyengine_us/reforms/states/mn/dependent_exemption/mn_dependent_exemption_reform.py @@ -0,0 +1,84 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ +from numpy import ceil + + +def create_mn_dependent_exemption() -> Reform: + class mn_exemptions(Variable): + value_type = float + entity = TaxUnit + label = "Minnesota exemptions amount" + unit = USD + definition_period = YEAR + reference = ( + "https://www.revisor.mn.gov/statutes/cite/290.0121" + "https://www.revenue.state.mn.us/sites/default/files/2025-11/m1-inst-25_0.pdf#page=14" + ) + defined_for = StateCode.MN + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.mn.dependent_exemption + p_baseline = parameters(period).gov.states.mn.tax.income.exemptions + + person = tax_unit.members + is_dependent = person("is_tax_unit_dependent", period) + + # Age gate: when in effect, only dependents under the chosen age + # receive the re-priced exemption; over-age dependents fall back to + # the baseline per-dependent amount. Without the age limit, every + # dependent receives the re-priced amount. + if p.age_limit.in_effect: + age = person("age", period) + eligible = is_dependent & (age < p.age_limit.threshold) + else: + eligible = is_dependent + older = is_dependent & ~eligible + + eligible_count = tax_unit.sum(eligible) + older_count = tax_unit.sum(older) + + # Pre-phase-out exemption base: young (or all) dependents priced at + # the reform amount, over-age dependents kept at the baseline amount. + exemptions = eligible_count * p.amount + older_count * p_baseline.amount + + # Preserve the baseline AGI phase-out exactly: scale the total by the + # same stepped fraction above the filing-status AGI threshold. + agi = tax_unit("adjusted_gross_income", period) + filing_status = tax_unit("filing_status", period) + excess_agi = max_(0, agi - p_baseline.agi_threshold[filing_status]) + steps = ceil(excess_agi / p_baseline.agi_step_size[filing_status]) + offset_fraction = p_baseline.agi_step_fraction * steps + offset = offset_fraction * exemptions + return max_(0, exemptions - offset) + + class reform(Reform): + def apply(self): + self.update_variable(mn_exemptions) + + return reform + + +def create_mn_dependent_exemption_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_mn_dependent_exemption() + + p = parameters.gov.contrib.states.mn.dependent_exemption + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_mn_dependent_exemption() + else: + return None + + +mn_dependent_exemption_reform = create_mn_dependent_exemption_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/ms/dependent_exemption/__init__.py b/policyengine_us/reforms/states/ms/dependent_exemption/__init__.py new file mode 100644 index 00000000000..b684ca9bbff --- /dev/null +++ b/policyengine_us/reforms/states/ms/dependent_exemption/__init__.py @@ -0,0 +1,5 @@ +from .ms_dependent_exemption_reform import ( + create_ms_dependent_exemption, + create_ms_dependent_exemption_reform_fn, + ms_dependent_exemption_reform, +) diff --git a/policyengine_us/reforms/states/ms/dependent_exemption/ms_dependent_exemption_reform.py b/policyengine_us/reforms/states/ms/dependent_exemption/ms_dependent_exemption_reform.py new file mode 100644 index 00000000000..f52206e39af --- /dev/null +++ b/policyengine_us/reforms/states/ms/dependent_exemption/ms_dependent_exemption_reform.py @@ -0,0 +1,59 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_ms_dependent_exemption() -> Reform: + class ms_dependents_exemption(Variable): + value_type = float + entity = TaxUnit + label = "Mississippi qualified and other dependent children exemption" + reference = "https://www.dor.ms.gov/sites/default/files/Forms/Individual/80100221.pdf#page=5" + definition_period = YEAR + defined_for = StateCode.MS + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.ms.dependent_exemption + person = tax_unit.members + is_dependent = person("is_tax_unit_dependent", period) + # Age gate: when in effect, restrict the exemption to dependents + # under the chosen age; otherwise every dependent qualifies, + # matching the baseline tax_unit_dependents count. + if p.age_limit.in_effect: + age = person("age", period) + eligible = is_dependent & (age < p.age_limit.threshold) + else: + eligible = is_dependent + count = tax_unit.sum(eligible) + return count * p.amount + + class reform(Reform): + def apply(self): + self.update_variable(ms_dependents_exemption) + + return reform + + +def create_ms_dependent_exemption_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_ms_dependent_exemption() + + p = parameters.gov.contrib.states.ms.dependent_exemption + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_ms_dependent_exemption() + else: + return None + + +ms_dependent_exemption_reform = create_ms_dependent_exemption_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/nj/dependent_exemption/__init__.py b/policyengine_us/reforms/states/nj/dependent_exemption/__init__.py new file mode 100644 index 00000000000..6ee02bc3e9c --- /dev/null +++ b/policyengine_us/reforms/states/nj/dependent_exemption/__init__.py @@ -0,0 +1,5 @@ +from .nj_dependent_exemption_reform import ( + create_nj_dependent_exemption, + create_nj_dependent_exemption_reform_fn, + nj_dependent_exemption_reform, +) diff --git a/policyengine_us/reforms/states/nj/dependent_exemption/nj_dependent_exemption_reform.py b/policyengine_us/reforms/states/nj/dependent_exemption/nj_dependent_exemption_reform.py new file mode 100644 index 00000000000..fdc62ae76bb --- /dev/null +++ b/policyengine_us/reforms/states/nj/dependent_exemption/nj_dependent_exemption_reform.py @@ -0,0 +1,66 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_nj_dependent_exemption() -> Reform: + class nj_dependents_exemption(Variable): + value_type = float + entity = TaxUnit + label = "New Jersey qualified and other dependent children exemption" + reference = "https://casetext.com/statute/new-jersey-statutes/title-54a-new-jersey-gross-income-tax-act/chapter-54a3-personal-exemptions-and-deductions/section-54a3-1-personal-exemptions-and-deductions" + unit = USD + definition_period = YEAR + defined_for = StateCode.NJ + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.nj.dependent_exemption + baseline = parameters( + period + ).gov.states.nj.tax.income.exemptions.dependents.amount + person = tax_unit.members + is_dependent = person("is_tax_unit_dependent", period) + # Age gate: when in effect, only dependents under the chosen age + # are re-priced to the reform amount; older dependents keep the + # baseline exemption. Otherwise every dependent is re-priced, + # matching the baseline tax_unit_dependents count at the default. + if p.age_limit.in_effect: + age = person("age", period) + young = is_dependent & (age < p.age_limit.threshold) + older = is_dependent & (age >= p.age_limit.threshold) + young_count = tax_unit.sum(young) + older_count = tax_unit.sum(older) + return young_count * p.amount + older_count * baseline + count = tax_unit.sum(is_dependent) + return count * p.amount + + class reform(Reform): + def apply(self): + self.update_variable(nj_dependents_exemption) + + return reform + + +def create_nj_dependent_exemption_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_nj_dependent_exemption() + + p = parameters.gov.contrib.states.nj.dependent_exemption + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_nj_dependent_exemption() + else: + return None + + +nj_dependent_exemption_reform = create_nj_dependent_exemption_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/ny/dependent_exemption/__init__.py b/policyengine_us/reforms/states/ny/dependent_exemption/__init__.py new file mode 100644 index 00000000000..4b7d2d71bd3 --- /dev/null +++ b/policyengine_us/reforms/states/ny/dependent_exemption/__init__.py @@ -0,0 +1,5 @@ +from .ny_dependent_exemption_reform import ( + create_ny_dependent_exemption, + create_ny_dependent_exemption_reform_fn, + ny_dependent_exemption_reform, +) diff --git a/policyengine_us/reforms/states/ny/dependent_exemption/ny_dependent_exemption_reform.py b/policyengine_us/reforms/states/ny/dependent_exemption/ny_dependent_exemption_reform.py new file mode 100644 index 00000000000..3b3b26af188 --- /dev/null +++ b/policyengine_us/reforms/states/ny/dependent_exemption/ny_dependent_exemption_reform.py @@ -0,0 +1,60 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_ny_dependent_exemption() -> Reform: + class ny_exemptions(Variable): + value_type = float + entity = TaxUnit + label = "NY exemptions" + unit = USD + definition_period = YEAR + reference = "https://www.nysenate.gov/legislation/laws/TAX/616" + defined_for = StateCode.NY + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.ny.dependent_exemption + person = tax_unit.members + is_child_dependent = person("is_child_dependent", period) + # Age gate: when in effect, restrict the exemption to child + # dependents under the chosen age; otherwise every child dependent + # qualifies, matching the baseline tax_unit_child_dependents count. + if p.age_limit.in_effect: + age = person("age", period) + eligible = is_child_dependent & (age < p.age_limit.threshold) + else: + eligible = is_child_dependent + count = tax_unit.sum(eligible) + return count * p.amount + + class reform(Reform): + def apply(self): + self.update_variable(ny_exemptions) + + return reform + + +def create_ny_dependent_exemption_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_ny_dependent_exemption() + + p = parameters.gov.contrib.states.ny.dependent_exemption + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_ny_dependent_exemption() + else: + return None + + +ny_dependent_exemption_reform = create_ny_dependent_exemption_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/reforms/states/sc/dependent_exemption/__init__.py b/policyengine_us/reforms/states/sc/dependent_exemption/__init__.py new file mode 100644 index 00000000000..f8d99edabf1 --- /dev/null +++ b/policyengine_us/reforms/states/sc/dependent_exemption/__init__.py @@ -0,0 +1,5 @@ +from .sc_dependent_exemption_reform import ( + create_sc_dependent_exemption, + create_sc_dependent_exemption_reform_fn, + sc_dependent_exemption_reform, +) diff --git a/policyengine_us/reforms/states/sc/dependent_exemption/sc_dependent_exemption_reform.py b/policyengine_us/reforms/states/sc/dependent_exemption/sc_dependent_exemption_reform.py new file mode 100644 index 00000000000..ccb3db4039e --- /dev/null +++ b/policyengine_us/reforms/states/sc/dependent_exemption/sc_dependent_exemption_reform.py @@ -0,0 +1,69 @@ +from policyengine_us.model_api import * +from policyengine_core.periods import period as period_ + + +def create_sc_dependent_exemption() -> Reform: + class sc_dependent_exemption(Variable): + value_type = float + entity = TaxUnit + label = "South Carolina dependent exemption" + unit = USD + definition_period = YEAR + reference = ( + "https://dor.sc.gov/forms-site/Forms/SC1040_2022.pdf#page=2", + "https://www.scstatehouse.gov/code/t12c006.php", + ) + defined_for = StateCode.SC + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.states.sc.dependent_exemption + baseline = parameters( + period + ).gov.states.sc.tax.income.deductions.dependent_exemption.amount + person = tax_unit.members + is_dependent = person("is_tax_unit_dependent", period) + # Age gate: when in effect, only dependents under the chosen age + # are re-priced to the reform amount; older dependents keep the + # baseline exemption. Otherwise every dependent is re-priced, + # matching the baseline tax_unit_dependents count at the default. + if p.age_limit.in_effect: + age = person("age", period) + young = is_dependent & (age < p.age_limit.threshold) + older = is_dependent & (age >= p.age_limit.threshold) + young_count = tax_unit.sum(young) + older_count = tax_unit.sum(older) + return young_count * p.amount + older_count * baseline + count = tax_unit.sum(is_dependent) + return count * p.amount + + class reform(Reform): + def apply(self): + self.update_variable(sc_dependent_exemption) + + return reform + + +def create_sc_dependent_exemption_reform_fn(parameters, period, bypass: bool = False): + if bypass: + return create_sc_dependent_exemption() + + p = parameters.gov.contrib.states.sc.dependent_exemption + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_sc_dependent_exemption() + else: + return None + + +sc_dependent_exemption_reform = create_sc_dependent_exemption_reform_fn( + None, None, bypass=True +) diff --git a/policyengine_us/tests/policy/contrib/states/al/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/al/dependent_exemption_reform_test.yaml new file mode 100644 index 00000000000..e7894da550d --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/al/dependent_exemption_reform_test.yaml @@ -0,0 +1,41 @@ +- name: AL dependent exemption reform - default reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.al.dependent_exemption.al_dependent_exemption_reform.al_dependent_exemption_reform + input: + gov.contrib.states.al.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: AL}} + output: {al_dependent_exemption: 2_000} + +- name: AL dependent exemption reform - amount zero eliminates the exemption + period: 2025 + reforms: policyengine_us.reforms.states.al.dependent_exemption.al_dependent_exemption_reform.al_dependent_exemption_reform + input: + gov.contrib.states.al.dependent_exemption.in_effect: true + gov.contrib.states.al.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: AL}} + output: {al_dependent_exemption: 0} + +- name: AL dependent exemption reform - age limit excludes dependents at or over the age + period: 2025 + reforms: policyengine_us.reforms.states.al.dependent_exemption.al_dependent_exemption_reform.al_dependent_exemption_reform + input: + gov.contrib.states.al.dependent_exemption.in_effect: true + gov.contrib.states.al.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.al.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: AL}} + output: {al_dependent_exemption: 1_000} diff --git a/policyengine_us/tests/policy/contrib/states/ar/dependent_credit_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ar/dependent_credit_reform_test.yaml index 22cb7167244..20f09163f7a 100644 --- a/policyengine_us/tests/policy/contrib/states/ar/dependent_credit_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/ar/dependent_credit_reform_test.yaml @@ -136,3 +136,18 @@ # credit from 87 to 29, raising AR income tax by exactly 58 (1346.67 -> 1404.67). # Confirms the dependent-credit -> tax wiring under the shared-base-redirect pattern. output: {ar_income_tax: 1404.67} + +- name: AR dependent credit reform - age limit excludes dependents at or over the age + period: 2025 + reforms: policyengine_us.reforms.states.ar.dependent_credit.ar_dependent_credit_reform.ar_dependent_credit_reform + input: + gov.contrib.states.ar.dependent_credit.in_effect: true + gov.contrib.states.ar.dependent_credit.age_limit.in_effect: true + gov.contrib.states.ar.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 50_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: AR}} + output: {ar_personal_credits: 58} diff --git a/policyengine_us/tests/policy/contrib/states/az/dependent_credit_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/az/dependent_credit_reform_test.yaml new file mode 100644 index 00000000000..322a79998c6 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/az/dependent_credit_reform_test.yaml @@ -0,0 +1,41 @@ +- name: AZ dependent credit reform - default reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.az.dependent_credit.az_dependent_credit_reform.az_dependent_credit_reform + input: + gov.contrib.states.az.dependent_credit.in_effect: true + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: AZ}} + output: {az_dependent_tax_credit_potential: 200} + +- name: AZ dependent credit reform - amount zero eliminates the credit + period: 2025 + reforms: policyengine_us.reforms.states.az.dependent_credit.az_dependent_credit_reform.az_dependent_credit_reform + input: + gov.contrib.states.az.dependent_credit.in_effect: true + gov.contrib.states.az.dependent_credit.amount: 0 + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: AZ}} + output: {az_dependent_tax_credit_potential: 0} + +- name: AZ dependent credit reform - age limit excludes dependents at or over the age + period: 2025 + reforms: policyengine_us.reforms.states.az.dependent_credit.az_dependent_credit_reform.az_dependent_credit_reform + input: + gov.contrib.states.az.dependent_credit.in_effect: true + gov.contrib.states.az.dependent_credit.age_limit.in_effect: true + gov.contrib.states.az.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: AZ}} + output: {az_dependent_tax_credit_potential: 100} diff --git a/policyengine_us/tests/policy/contrib/states/ca/dependent_credit_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ca/dependent_credit_reform_test.yaml new file mode 100644 index 00000000000..f96f3533100 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/ca/dependent_credit_reform_test.yaml @@ -0,0 +1,54 @@ +- name: CA dependent credit reform - default amount reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.ca.dependent_credit.ca_dependent_credit_reform.ca_dependent_credit_reform + input: + gov.contrib.states.ca.dependent_credit.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: CA}} + output: {ca_exemptions: 1_103} # 153 personal + 2 * 475 dependent + +- name: CA dependent credit reform - amount zero removes only the dependent portion + period: 2025 + reforms: policyengine_us.reforms.states.ca.dependent_credit.ca_dependent_credit_reform.ca_dependent_credit_reform + input: + gov.contrib.states.ca.dependent_credit.in_effect: true + gov.contrib.states.ca.dependent_credit.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: CA}} + output: {ca_exemptions: 153} # 153 personal, dependent portion eliminated + +- name: CA dependent credit reform - age limit re-prices young and keeps baseline for older + period: 2025 + reforms: policyengine_us.reforms.states.ca.dependent_credit.ca_dependent_credit_reform.ca_dependent_credit_reform + input: + gov.contrib.states.ca.dependent_credit.in_effect: true + gov.contrib.states.ca.dependent_credit.amount: 1_000 + gov.contrib.states.ca.dependent_credit.age_limit.in_effect: true + gov.contrib.states.ca.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: CA}} + output: {ca_exemptions: 1_628} # 153 personal + 1,000 young + 475 baseline older + +- name: CA dependent credit reform - childless filer unaffected + period: 2025 + reforms: policyengine_us.reforms.states.ca.dependent_credit.ca_dependent_credit_reform.ca_dependent_credit_reform + input: + gov.contrib.states.ca.dependent_credit.in_effect: true + gov.contrib.states.ca.dependent_credit.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + tax_units: {tax_unit: {members: [parent], filing_status: SINGLE}} + households: {household: {members: [parent], state_name: CA}} + output: {ca_exemptions: 153} # personal only, no dependents diff --git a/policyengine_us/tests/policy/contrib/states/ga/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ga/dependent_exemption_reform_test.yaml new file mode 100644 index 00000000000..cf48a4d7b62 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/ga/dependent_exemption_reform_test.yaml @@ -0,0 +1,55 @@ +- name: GA dependent exemption reform - default amount reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.ga.dependent_exemption.ga_dependent_exemption_reform.ga_dependent_exemption_reform + input: + gov.contrib.states.ga.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: GA}} + # 2 dependents * 4,000 = 8,000 (matches baseline; GA has no personal exemption in 2025). + output: {ga_exemptions: 8_000} + +- name: GA dependent exemption reform - amount zero removes dependent portion only + period: 2025 + reforms: policyengine_us.reforms.states.ga.dependent_exemption.ga_dependent_exemption_reform.ga_dependent_exemption_reform + input: + gov.contrib.states.ga.dependent_exemption.in_effect: true + gov.contrib.states.ga.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: GA}} + # Dependent portion removed; personal portion preserved (0 in 2025, GA has no personal exemption). + output: {ga_exemptions: 0} + +- name: GA dependent exemption reform - childless single unaffected + period: 2025 + reforms: policyengine_us.reforms.states.ga.dependent_exemption.ga_dependent_exemption_reform.ga_dependent_exemption_reform + input: + gov.contrib.states.ga.dependent_exemption.in_effect: true + people: {parent: {age: 40, employment_income: 60_000}} + tax_units: {tax_unit: {members: [parent], filing_status: SINGLE}} + households: {household: {members: [parent], state_name: GA}} + output: {ga_exemptions: 0} + +- name: GA dependent exemption reform - age limit excludes over-age dependent + period: 2025 + reforms: policyengine_us.reforms.states.ga.dependent_exemption.ga_dependent_exemption_reform.ga_dependent_exemption_reform + input: + gov.contrib.states.ga.dependent_exemption.in_effect: true + gov.contrib.states.ga.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ga.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: GA}} + # Only the under-18 dependent gets the exemption (1 * 4,000). The over-age + # dependent falls back to the personal treatment, which is nothing in GA. + output: {ga_exemptions: 4_000} diff --git a/policyengine_us/tests/policy/contrib/states/ia/dependent_credit_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ia/dependent_credit_reform_test.yaml new file mode 100644 index 00000000000..f671257834f --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/ia/dependent_credit_reform_test.yaml @@ -0,0 +1,54 @@ +- name: IA dependent credit reform - default amount reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.ia.dependent_credit.ia_dependent_credit_reform.ia_dependent_credit_reform + input: + gov.contrib.states.ia.dependent_credit.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: IA}} + output: {ia_exemption_credit: 120} # 40 personal + 2 * 40 dependent + +- name: IA dependent credit reform - amount zero removes only the dependent portion + period: 2025 + reforms: policyengine_us.reforms.states.ia.dependent_credit.ia_dependent_credit_reform.ia_dependent_credit_reform + input: + gov.contrib.states.ia.dependent_credit.in_effect: true + gov.contrib.states.ia.dependent_credit.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: IA}} + output: {ia_exemption_credit: 40} # 40 personal, dependent portion eliminated + +- name: IA dependent credit reform - age limit re-prices young and keeps baseline for older + period: 2025 + reforms: policyengine_us.reforms.states.ia.dependent_credit.ia_dependent_credit_reform.ia_dependent_credit_reform + input: + gov.contrib.states.ia.dependent_credit.in_effect: true + gov.contrib.states.ia.dependent_credit.amount: 100 + gov.contrib.states.ia.dependent_credit.age_limit.in_effect: true + gov.contrib.states.ia.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: IA}} + output: {ia_exemption_credit: 180} # 40 personal + 100 young + 40 baseline older + +- name: IA dependent credit reform - childless filer unaffected + period: 2025 + reforms: policyengine_us.reforms.states.ia.dependent_credit.ia_dependent_credit_reform.ia_dependent_credit_reform + input: + gov.contrib.states.ia.dependent_credit.in_effect: true + gov.contrib.states.ia.dependent_credit.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + tax_units: {tax_unit: {members: [parent], filing_status: SINGLE}} + households: {household: {members: [parent], state_name: IA}} + output: {ia_exemption_credit: 40} # personal only, no dependents diff --git a/policyengine_us/tests/policy/contrib/states/il/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/il/dependent_exemption_reform_test.yaml new file mode 100644 index 00000000000..456b3e54bc6 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/il/dependent_exemption_reform_test.yaml @@ -0,0 +1,41 @@ +- name: IL dependent exemption reform - default amount reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.il.dependent_exemption.il_dependent_exemption_reform.il_dependent_exemption_reform + input: + gov.contrib.states.il.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: IL}} + output: {il_dependent_exemption: 5_700} # 2 * 2,850 + +- name: IL dependent exemption reform - amount zero eliminates the exemption + period: 2025 + reforms: policyengine_us.reforms.states.il.dependent_exemption.il_dependent_exemption_reform.il_dependent_exemption_reform + input: + gov.contrib.states.il.dependent_exemption.in_effect: true + gov.contrib.states.il.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: IL}} + output: {il_dependent_exemption: 0} + +- name: IL dependent exemption reform - age limit excludes dependents at or over the age + period: 2025 + reforms: policyengine_us.reforms.states.il.dependent_exemption.il_dependent_exemption_reform.il_dependent_exemption_reform + input: + gov.contrib.states.il.dependent_exemption.in_effect: true + gov.contrib.states.il.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.il.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: IL}} + output: {il_dependent_exemption: 2_850} # only the under-13 child counts diff --git a/policyengine_us/tests/policy/contrib/states/ks/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ks/dependent_exemption_reform_test.yaml new file mode 100644 index 00000000000..b1f21ce0786 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/ks/dependent_exemption_reform_test.yaml @@ -0,0 +1,73 @@ +- name: KS dependent exemption reform - default amount reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.ks.dependent_exemption.ks_dependent_exemption_reform.ks_dependent_exemption_reform + input: + gov.contrib.states.ks.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: KS}} + # Personal (SINGLE base) 9,160 + 2 dependents * 2,320 = 13,800 (matches baseline). + output: {ks_exemptions: 13_800} + +- name: KS dependent exemption reform - amount zero removes dependent portion only + period: 2025 + reforms: policyengine_us.reforms.states.ks.dependent_exemption.ks_dependent_exemption_reform.ks_dependent_exemption_reform + input: + gov.contrib.states.ks.dependent_exemption.in_effect: true + gov.contrib.states.ks.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: KS}} + # Dependent portion removed; personal (SINGLE base) 9,160 preserved. + output: {ks_exemptions: 9_160} + +- name: KS dependent exemption reform - childless single unaffected + period: 2025 + reforms: policyengine_us.reforms.states.ks.dependent_exemption.ks_dependent_exemption_reform.ks_dependent_exemption_reform + input: + gov.contrib.states.ks.dependent_exemption.in_effect: true + gov.contrib.states.ks.dependent_exemption.amount: 0 + people: {parent: {age: 40, employment_income: 60_000}} + tax_units: {tax_unit: {members: [parent], filing_status: SINGLE}} + households: {household: {members: [parent], state_name: KS}} + output: {ks_exemptions: 9_160} + +- name: KS dependent exemption reform - age limit excludes over-age dependent + period: 2025 + reforms: policyengine_us.reforms.states.ks.dependent_exemption.ks_dependent_exemption_reform.ks_dependent_exemption_reform + input: + gov.contrib.states.ks.dependent_exemption.in_effect: true + gov.contrib.states.ks.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ks.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: KS}} + # Only the under-18 dependent gets the exemption. The over-age dependent falls + # back to the personal treatment, which is nothing in this KS regime. + # 9,160 personal + 1 eligible dependent * 2,320 = 11,480. + output: {ks_exemptions: 11_480} + +- name: KS dependent exemption reform - joint two-adult unit splits head/spouse from dependents + period: 2025 + reforms: policyengine_us.reforms.states.ks.dependent_exemption.ks_dependent_exemption_reform.ks_dependent_exemption_reform + input: + gov.contrib.states.ks.dependent_exemption.in_effect: true + gov.contrib.states.ks.dependent_exemption.amount: 0 + people: + parent1: {age: 40, employment_income: 60_000} + parent2: {age: 38} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent1, parent2, child1, child2], filing_status: JOINT}} + households: {household: {members: [parent1, parent2, child1, child2], state_name: KS}} + # JOINT base 18,320 personal preserved; dependent portion removed (amount 0). + output: {ks_exemptions: 18_320} diff --git a/policyengine_us/tests/policy/contrib/states/mn/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/mn/dependent_exemption_reform_test.yaml new file mode 100644 index 00000000000..115b7018df8 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/mn/dependent_exemption_reform_test.yaml @@ -0,0 +1,97 @@ +- name: MN dependent exemption reform - default amount reproduces baseline below phase-out (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.mn.dependent_exemption.mn_dependent_exemption_reform.mn_dependent_exemption_reform + input: + gov.contrib.states.mn.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: MN}} + # AGI (~63k) is below the SINGLE phase-out threshold (239,050), so the full + # per-dependent exemption applies: 2 * 5,200 = 10,400, matching baseline. + output: {mn_exemptions: 10_400} + +- name: MN dependent exemption reform - default amount reproduces baseline within phase-out (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.mn.dependent_exemption.mn_dependent_exemption_reform.mn_dependent_exemption_reform + input: + gov.contrib.states.mn.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 300_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: MN}} + # AGI is above the SINGLE threshold; the stepped AGI phase-out reduces the + # 10,400 base by exactly 50% to 5,200, matching the unreformed baseline. + output: {mn_exemptions: 5_200} + +- name: MN dependent exemption reform - amount zero removes the dependent portion + period: 2025 + reforms: policyengine_us.reforms.states.mn.dependent_exemption.mn_dependent_exemption_reform.mn_dependent_exemption_reform + input: + gov.contrib.states.mn.dependent_exemption.in_effect: true + gov.contrib.states.mn.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: MN}} + # Re-pricing the per-dependent amount to 0 eliminates the entire exemption. + output: {mn_exemptions: 0} + +- name: MN dependent exemption reform - age limit excludes over-age dependent who keeps baseline + period: 2025 + reforms: policyengine_us.reforms.states.mn.dependent_exemption.mn_dependent_exemption_reform.mn_dependent_exemption_reform + input: + gov.contrib.states.mn.dependent_exemption.in_effect: true + gov.contrib.states.mn.dependent_exemption.amount: 0 + gov.contrib.states.mn.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.mn.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: MN}} + # Young dependent (age 10 < 18) gets the re-priced amount (0); the over-age + # dependent (age 20) keeps the baseline 5,200. Below phase-out: 0 + 5,200. + output: {mn_exemptions: 5_200} + +- name: MN dependent exemption reform - age limit at default amount reproduces baseline + period: 2025 + reforms: policyengine_us.reforms.states.mn.dependent_exemption.mn_dependent_exemption_reform.mn_dependent_exemption_reform + input: + gov.contrib.states.mn.dependent_exemption.in_effect: true + gov.contrib.states.mn.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.mn.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: MN}} + # Young dependent priced at default 5,200 and over-age dependent kept at + # baseline 5,200 both equal the current-law amount: 2 * 5,200 = 10,400. + output: {mn_exemptions: 10_400} + +- name: MN dependent exemption reform - over-age fallback still subject to phase-out + period: 2025 + reforms: policyengine_us.reforms.states.mn.dependent_exemption.mn_dependent_exemption_reform.mn_dependent_exemption_reform + input: + gov.contrib.states.mn.dependent_exemption.in_effect: true + gov.contrib.states.mn.dependent_exemption.amount: 0 + gov.contrib.states.mn.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.mn.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 300_000} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: MN}} + # Base = 0 (young) + 5,200 (over-age fallback) = 5,200; the same 50% AGI + # phase-out that halves the baseline also halves the fallback: 5,200 -> 2,600. + output: {mn_exemptions: 2_600} diff --git a/policyengine_us/tests/policy/contrib/states/ms/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ms/dependent_exemption_reform_test.yaml new file mode 100644 index 00000000000..18ce5d448da --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/ms/dependent_exemption_reform_test.yaml @@ -0,0 +1,41 @@ +- name: MS dependent exemption reform - default amount reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.ms.dependent_exemption.ms_dependent_exemption_reform.ms_dependent_exemption_reform + input: + gov.contrib.states.ms.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: MS}} + output: {ms_dependents_exemption: 3_000} # 2 * 1,500 + +- name: MS dependent exemption reform - amount zero eliminates the exemption + period: 2025 + reforms: policyengine_us.reforms.states.ms.dependent_exemption.ms_dependent_exemption_reform.ms_dependent_exemption_reform + input: + gov.contrib.states.ms.dependent_exemption.in_effect: true + gov.contrib.states.ms.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: MS}} + output: {ms_dependents_exemption: 0} + +- name: MS dependent exemption reform - age limit excludes dependents at or over the age + period: 2025 + reforms: policyengine_us.reforms.states.ms.dependent_exemption.ms_dependent_exemption_reform.ms_dependent_exemption_reform + input: + gov.contrib.states.ms.dependent_exemption.in_effect: true + gov.contrib.states.ms.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ms.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: MS}} + output: {ms_dependents_exemption: 1_500} # only the under-13 child counts diff --git a/policyengine_us/tests/policy/contrib/states/nj/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/nj/dependent_exemption_reform_test.yaml new file mode 100644 index 00000000000..5df8bae505e --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/nj/dependent_exemption_reform_test.yaml @@ -0,0 +1,60 @@ +- name: NJ dependent exemption reform - default amount reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.nj.dependent_exemption.nj_dependent_exemption_reform.nj_dependent_exemption_reform + input: + gov.contrib.states.nj.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: NJ}} + output: {nj_dependents_exemption: 3_000} # 2 * 1,500 + +- name: NJ dependent exemption reform - amount zero eliminates the exemption + period: 2025 + reforms: policyengine_us.reforms.states.nj.dependent_exemption.nj_dependent_exemption_reform.nj_dependent_exemption_reform + input: + gov.contrib.states.nj.dependent_exemption.in_effect: true + gov.contrib.states.nj.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: NJ}} + output: {nj_dependents_exemption: 0} + +- name: NJ dependent exemption reform - age limit re-prices only young dependents; older keep baseline + period: 2025 + reforms: policyengine_us.reforms.states.nj.dependent_exemption.nj_dependent_exemption_reform.nj_dependent_exemption_reform + input: + gov.contrib.states.nj.dependent_exemption.in_effect: true + gov.contrib.states.nj.dependent_exemption.amount: 0 + gov.contrib.states.nj.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.nj.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: NJ}} + output: {nj_dependents_exemption: 1_500} # under-13 child eliminated; age-15 child keeps baseline 1,500 + +- name: NJ dependent exemption reform - college-dependent exemption is unchanged + period: 2025 + reforms: policyengine_us.reforms.states.nj.dependent_exemption.nj_dependent_exemption_reform.nj_dependent_exemption_reform + input: + gov.contrib.states.nj.dependent_exemption.in_effect: true + gov.contrib.states.nj.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + college_kid: + age: 20 + is_tax_unit_dependent: true + is_full_time_college_student: true + tax_units: {tax_unit: {members: [parent, college_kid], filing_status: SINGLE}} + households: {household: {members: [parent, college_kid], state_name: NJ}} + output: + nj_dependents_exemption: 0 # main exemption eliminated + nj_dependents_attending_college_exemption: 1_000 # college exemption untouched diff --git a/policyengine_us/tests/policy/contrib/states/ny/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ny/dependent_exemption_reform_test.yaml new file mode 100644 index 00000000000..285c075b535 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/ny/dependent_exemption_reform_test.yaml @@ -0,0 +1,41 @@ +- name: NY dependent exemption reform - default amount reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.ny.dependent_exemption.ny_dependent_exemption_reform.ny_dependent_exemption_reform + input: + gov.contrib.states.ny.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: NY}} + output: {ny_exemptions: 2_000} # 2 * 1,000 + +- name: NY dependent exemption reform - amount zero eliminates the exemption + period: 2025 + reforms: policyengine_us.reforms.states.ny.dependent_exemption.ny_dependent_exemption_reform.ny_dependent_exemption_reform + input: + gov.contrib.states.ny.dependent_exemption.in_effect: true + gov.contrib.states.ny.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: NY}} + output: {ny_exemptions: 0} + +- name: NY dependent exemption reform - age limit excludes dependents at or over the age + period: 2025 + reforms: policyengine_us.reforms.states.ny.dependent_exemption.ny_dependent_exemption_reform.ny_dependent_exemption_reform + input: + gov.contrib.states.ny.dependent_exemption.in_effect: true + gov.contrib.states.ny.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ny.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: NY}} + output: {ny_exemptions: 1_000} # only the under-13 child counts diff --git a/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml new file mode 100644 index 00000000000..b315ddccb72 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml @@ -0,0 +1,57 @@ +- name: SC dependent exemption reform - default amount reproduces baseline (no-op) + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: SC}} + output: {sc_dependent_exemption: 9_860} # 2 * 4,930 + +- name: SC dependent exemption reform - amount zero eliminates the exemption + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + gov.contrib.states.sc.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: SC}} + output: {sc_dependent_exemption: 0} + +- name: SC dependent exemption reform - age limit re-prices only young dependents; older keep baseline + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + gov.contrib.states.sc.dependent_exemption.amount: 0 + gov.contrib.states.sc.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.sc.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + child2: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: SC}} + output: {sc_dependent_exemption: 4_930} # under-13 child eliminated; age-15 child keeps baseline 4,930 + +- name: SC dependent exemption reform - young child deduction is unchanged + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + gov.contrib.states.sc.dependent_exemption.amount: 0 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: SC}} + output: + sc_dependent_exemption: 0 # dependent exemption eliminated + sc_young_child_deduction: 4_930 # stacked young-child deduction untouched From 5e1c8b4441b8234dc0a0ee07d5ea7fb4b8832d2a Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Wed, 1 Jul 2026 16:32:52 -0400 Subject: [PATCH 2/3] Cap Quick Feedback's direct-file fallback; defer broad PRs to the full suites Quick Feedback runs every selected YAML suite inside one coverage-instrumented process; each contrib suite loads the full tax-benefit system, so a broad PR (13 direct test files here) accumulates memory until the GitHub runner dies (the job failed at ~56 min with no step conclusion and no uploaded logs). limit_test_paths already had two tiers (defer slow directories; reduce broad scopes to directly changed tests) but returned the direct-file fallback unbounded. Add the missing third tier: beyond SELECTIVE_TEST_MAX_DIRECT_FILES (default 8) direct files, defer entirely to the sharded full-suite jobs, which run all of them anyway. Co-Authored-By: Claude Opus 4.8 (1M context) --- policyengine_us/tests/run_selective_tests.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/policyengine_us/tests/run_selective_tests.py b/policyengine_us/tests/run_selective_tests.py index a39760d894d..1e9c4799359 100644 --- a/policyengine_us/tests/run_selective_tests.py +++ b/policyengine_us/tests/run_selective_tests.py @@ -39,6 +39,14 @@ def __init__(self, base_branch: str = "master"): self.base_branch = base_branch self.max_test_targets = int(os.environ.get("SELECTIVE_TEST_MAX_TARGETS", "25")) self.max_test_files = int(os.environ.get("SELECTIVE_TEST_MAX_FILES", "250")) + # Cap on the direct-file fallback: each YAML test file loads the full + # tax-benefit system inside ONE coverage-instrumented process, so a + # broad PR (e.g. 13 contrib suites) accumulates memory until the + # GitHub runner dies. Beyond this many direct files, defer to the + # sharded full-suite jobs instead. + self.max_direct_test_files = int( + os.environ.get("SELECTIVE_TEST_MAX_DIRECT_FILES", "8") + ) # Define regex patterns for matching files to tests # Paths that contain only aggregation lists and should not @@ -376,6 +384,14 @@ def limit_test_paths( "\nSelective test scope is too broad for quick feedback " f"({len(test_paths)} targets / ~{total_test_files} test files)." ) + if len(bounded_test_paths) > self.max_direct_test_files: + print( + f"Even the directly changed tests are too many for one " + f"quick-feedback process ({len(bounded_test_paths)} files > " + f"{self.max_direct_test_files}); deferring to the sharded " + "full suite jobs, which run them all." + ) + return set() if bounded_test_paths: print( "Running only directly changed tests and explicit file targets; " From afbc862d24c7f350f88ec512f385a6c1bdcd18af Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Wed, 1 Jul 2026 16:49:10 -0400 Subject: [PATCH 3/3] Address review of #8816: reference hygiene, no-op robustness, dead var, boundary tests - CA/IA dependent_credit amount.yaml: add missing references (values unchanged). - MN reform: fix reference tuple missing a comma (was one concatenated URL). - No-op robustness: IL/CA/KS contrib amount defaults now replicate the baseline schedule + uprating so activating at default reproduces baseline for all years (previously a static snapshot that drifted outside the snapshot year). MS/NJ/NY/IA baselines are flat constants, already correct. - Remove dead KS variable ks_older_dependents_count (defined but never read). - Tests: append age-limit boundary cases (age==threshold excluded, threshold-1 included) to all 13 states; strengthen GA to pin ga_dependent_exemption directly. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../states/ca/dependent_credit/amount.yaml | 23 ++++++++-- .../states/ia/dependent_credit/amount.yaml | 15 ++++++- .../states/il/dependent_exemption/amount.yaml | 18 +++++++- .../states/ks/dependent_exemption/amount.yaml | 11 ++++- .../ks_dependent_exemption_reform.py | 17 ------- .../mn_dependent_exemption_reform.py | 4 +- .../al/dependent_exemption_reform_test.yaml | 33 ++++++++++++++ .../ar/dependent_credit_reform_test.yaml | 34 ++++++++++++++ .../az/dependent_credit_reform_test.yaml | 32 +++++++++++++ .../ca/dependent_credit_reform_test.yaml | 34 ++++++++++++++ .../ga/dependent_exemption_reform_test.yaml | 45 ++++++++++++++++++- .../ia/dependent_credit_reform_test.yaml | 34 ++++++++++++++ .../il/dependent_exemption_reform_test.yaml | 32 +++++++++++++ .../ks/dependent_exemption_reform_test.yaml | 34 ++++++++++++++ .../mn/dependent_exemption_reform_test.yaml | 35 +++++++++++++++ .../ms/dependent_exemption_reform_test.yaml | 32 +++++++++++++ .../nj/dependent_exemption_reform_test.yaml | 34 ++++++++++++++ .../ny/dependent_exemption_reform_test.yaml | 32 +++++++++++++ .../sc/dependent_exemption_reform_test.yaml | 34 ++++++++++++++ 19 files changed, 505 insertions(+), 28 deletions(-) diff --git a/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/amount.yaml b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/amount.yaml index c7b4c4f1c4c..10a59fe129f 100644 --- a/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/amount.yaml +++ b/policyengine_us/parameters/gov/contrib/states/ca/dependent_credit/amount.yaml @@ -1,9 +1,26 @@ -description: California provides this dependent exemption credit amount per eligible dependent under the reform. - +description: California provides this dependent exemption credit amount per eligible dependent under the contributed reform. Defaults to the baseline amount, so activating the reform at the default is a no-op. values: + 1999-01-01: 227 + 2021-01-01: 400 + 2022-01-01: 433 + 2023-01-01: 446 + 2024-01-01: 461 2025-01-01: 475 - metadata: label: California dependent credit amount period: year unit: currency-USD + uprating: gov.states.ca.cpi + reference: + - title: 2021 Form 540 California Resident Income Tax Return + href: https://www.ftb.ca.gov/forms/2021/2021-540.pdf#page=2 + - title: 2022 Form 540 California Resident Income Tax Return + href: https://www.ftb.ca.gov/forms/2022/2022-540.pdf#page=2 + - title: 2023 Form 540 California Resident Income Tax Return + href: https://www.ftb.ca.gov/forms/2023/2023-540.pdf#page=2 + - title: 2024 Form 540 California Resident Income Tax Return + href: https://www.ftb.ca.gov/forms/2024/2024-540.pdf#page=2 + - title: 2025 Form 540 California Resident Income Tax Return + href: https://www.ftb.ca.gov/forms/2025/2025-540.pdf#page=2 + - title: Cal. Rev. & Tax. Code § 17054 + href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=17054.&nodeTreePath=3.20.2&lawCode=RTC diff --git a/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/amount.yaml b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/amount.yaml index b85297353dc..0efdec601fe 100644 --- a/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/amount.yaml +++ b/policyengine_us/parameters/gov/contrib/states/ia/dependent_credit/amount.yaml @@ -1,4 +1,4 @@ -description: Iowa provides this dependent exemption credit amount per eligible dependent under the reform. +description: Iowa provides this dependent exemption credit amount per eligible dependent under the contributed reform. Defaults to the baseline amount, so activating the reform at the default is a no-op. values: 2021-01-01: 40 @@ -7,3 +7,16 @@ metadata: label: Iowa dependent credit amount period: year unit: currency-USD + reference: + - title: 2021 IA1040 Iowa Income Tax Return, Step 3 + href: https://revenue.iowa.gov/sites/default/files/2022-01/IA1040%2841-001%29.pdf#page=1 + - title: 2021 IA1040 Income Tax Return instructions + href: https://revenue.iowa.gov/sites/default/files/2023-01/2021%20Expanded%20Instructions_010323.pdf#page=9 + - title: 2022 IA1040 Iowa Income Tax Return, Step 3 + href: https://revenue.iowa.gov/sites/default/files/2023-01/2022IA1040%2841001%29.pdf#page=1 + - title: 2022 IA1040 Income Tax Return instructions + href: https://revenue.iowa.gov/sites/default/files/2023-03/2022%20Expanded%20Instructions_022023.pdf#page=8 + - title: 2024 IA1040 Iowa Income Tax Return Instruction, Step 3 + href: https://revenue.iowa.gov/media/4152/download?inline#page=8 + - title: 2025 IA 1040 Expanded Instructions, Exemption Credits + href: https://revenue.iowa.gov/taxes/tax-guidance/individual-income-tax/1040-expanded-instructions/exemption-credits diff --git a/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/amount.yaml index c3c1e2b9a02..f2ccdf30e7c 100644 --- a/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/amount.yaml +++ b/policyengine_us/parameters/gov/contrib/states/il/dependent_exemption/amount.yaml @@ -1,10 +1,26 @@ description: Illinois provides this dependent exemption amount per eligible dependent under the contributed reform. Defaults to the baseline amount, so activating the reform at the default is a no-op. values: - 2021-01-01: 2_850 + 2021-01-01: 2_375 + 2022-01-01: 2_425 + 2024-01-01: 2_775 + 2025-01-01: 2_850 metadata: unit: currency-USD + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 25 period: year label: Illinois dependent exemption reform amount reference: + - title: 2021 Schedule IL-E/EIC - Illinois Exemption and Earned Income Credit + href: https://tax.illinois.gov/content/dam/soi/en/web/tax/forms/incometax/documents/2021/individual/il-1040-schedule-il-e-eic.pdf#page=1 + - title: 2022 Schedule IL-E/EIC - Illinois Exemption and Earned Income Credit + href: https://tax.illinois.gov/content/dam/soi/en/web/tax/forms/incometax/documents/2022/individual/il-1040-schedule-il-e-eic.pdf#page=1 + - title: 2023 Schedule IL-E/EIC - Illinois Exemption and Earned Income Credit + href: https://tax.illinois.gov/content/dam/soi/en/web/tax/forms/incometax/documents/2023/individual/il-1040-schedule-il-e-eic.pdf#page=1 + - title: 2024 Schedule IL-E/EIC - Illinois Exemption and Earned Income Credit + href: https://tax.illinois.gov/content/dam/soi/en/web/tax/forms/incometax/documents/2024/individual/il-1040-schedule-il-e-eic.pdf#page=1 - title: 2025 Schedule IL-E/EIC - Illinois Exemption and Earned Income Credit href: https://tax.illinois.gov/content/dam/soi/en/web/tax/forms/incometax/documents/currentyear/individual/il-1040-schedule-il-e-eic.pdf#page=1 diff --git a/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/amount.yaml index b7bb1add123..19d64bbe653 100644 --- a/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/amount.yaml +++ b/policyengine_us/parameters/gov/contrib/states/ks/dependent_exemption/amount.yaml @@ -1,14 +1,21 @@ -description: Kansas provides this per-dependent exemption amount under the reform. +description: Kansas provides this per-dependent exemption amount under the contributed reform. Defaults to the baseline amount, so activating the reform at the default is a no-op. values: - 2021-01-01: 2_320 + 2021-01-01: 2_250 + 2024-01-01: 2_320 metadata: label: Kansas dependent exemption amount period: year unit: currency-USD reference: + - title: 2023 Form K-40 instructions + href: https://www.ksrevenue.gov/pdf/ip23.pdf#page=2 + - title: 2024 Form K-40 instructions + href: https://www.ksrevenue.gov/pdf/ip24.pdf#page=2 - title: 2025 Form K-40 instructions href: https://www.ksrevenue.gov/pdf/ip25.pdf#page=2 + - title: Kansas Notice 24-08 Changes to individual income tax + href: https://www.ksrevenue.gov/taxnotices/notice24-08.pdf#page=2 - title: Kan. Stat. 79-32,121 (a) href: https://casetext.com/statute/kansas-statutes/chapter-79-taxation/article-32-income-tax/section-79-32121-kansas-exemption-for-an-individual diff --git a/policyengine_us/reforms/states/ks/dependent_exemption/ks_dependent_exemption_reform.py b/policyengine_us/reforms/states/ks/dependent_exemption/ks_dependent_exemption_reform.py index f7bb85ea843..d3c89f7c568 100644 --- a/policyengine_us/reforms/states/ks/dependent_exemption/ks_dependent_exemption_reform.py +++ b/policyengine_us/reforms/states/ks/dependent_exemption/ks_dependent_exemption_reform.py @@ -40,22 +40,6 @@ def formula(tax_unit, period, parameters): dependents_count = tax_unit("ks_eligible_dependents_count", period) return dependents_count * p.amount - class ks_older_dependents_count(Variable): - value_type = int - entity = TaxUnit - label = "Kansas older dependents count" - definition_period = YEAR - defined_for = StateCode.KS - - def formula(tax_unit, period, parameters): - person = tax_unit.members - is_dependent = person("is_tax_unit_dependent", period) - total_dependents = tax_unit.sum(is_dependent) - eligible_dependent_exemptions = tax_unit( - "ks_eligible_dependents_count", period - ) - return max_(0, total_dependents - eligible_dependent_exemptions) - class ks_exemptions(Variable): value_type = float entity = TaxUnit @@ -117,7 +101,6 @@ class reform(Reform): def apply(self): self.update_variable(ks_eligible_dependents_count) self.update_variable(ks_dependent_exemption) - self.update_variable(ks_older_dependents_count) self.update_variable(ks_exemptions) return reform diff --git a/policyengine_us/reforms/states/mn/dependent_exemption/mn_dependent_exemption_reform.py b/policyengine_us/reforms/states/mn/dependent_exemption/mn_dependent_exemption_reform.py index 6ef99a8ea57..d66489b164b 100644 --- a/policyengine_us/reforms/states/mn/dependent_exemption/mn_dependent_exemption_reform.py +++ b/policyengine_us/reforms/states/mn/dependent_exemption/mn_dependent_exemption_reform.py @@ -11,8 +11,8 @@ class mn_exemptions(Variable): unit = USD definition_period = YEAR reference = ( - "https://www.revisor.mn.gov/statutes/cite/290.0121" - "https://www.revenue.state.mn.us/sites/default/files/2025-11/m1-inst-25_0.pdf#page=14" + "https://www.revisor.mn.gov/statutes/cite/290.0121", + "https://www.revenue.state.mn.us/sites/default/files/2025-11/m1-inst-25_0.pdf#page=14", ) defined_for = StateCode.MN diff --git a/policyengine_us/tests/policy/contrib/states/al/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/al/dependent_exemption_reform_test.yaml index e7894da550d..c8c9d90e259 100644 --- a/policyengine_us/tests/policy/contrib/states/al/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/al/dependent_exemption_reform_test.yaml @@ -39,3 +39,36 @@ tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} households: {household: {members: [parent, child1, child2], state_name: AL}} output: {al_dependent_exemption: 1_000} + +- name: AL dependent exemption reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.al.dependent_exemption.al_dependent_exemption_reform.al_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.al.dependent_exemption.in_effect: true + gov.contrib.states.al.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.al.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: AL}} + # Dependent at the age limit (13 == threshold) is excluded; AL has no personal + # dependent fallback, so the exemption is nothing. + output: {al_dependent_exemption: 0} + +- name: AL dependent exemption reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.al.dependent_exemption.al_dependent_exemption_reform.al_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.al.dependent_exemption.in_effect: true + gov.contrib.states.al.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.al.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: AL}} + # Dependent one year under the limit (12 < 13) receives the re-priced exemption. + output: {al_dependent_exemption: 1_000} diff --git a/policyengine_us/tests/policy/contrib/states/ar/dependent_credit_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ar/dependent_credit_reform_test.yaml index 20f09163f7a..5f2473f69f6 100644 --- a/policyengine_us/tests/policy/contrib/states/ar/dependent_credit_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/ar/dependent_credit_reform_test.yaml @@ -151,3 +151,37 @@ tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} households: {household: {members: [parent, child1, child2], state_name: AR}} output: {ar_personal_credits: 58} + +- name: AR dependent credit reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.ar.dependent_credit.ar_dependent_credit_reform.ar_dependent_credit_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ar.dependent_credit.in_effect: true + gov.contrib.states.ar.dependent_credit.age_limit.in_effect: true + gov.contrib.states.ar.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 50_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: AR}} + # Dependent at the age limit (13 == threshold) is excluded; only the head + # personal credit of 29 remains. + output: {ar_personal_credits: 29} + +- name: AR dependent credit reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.ar.dependent_credit.ar_dependent_credit_reform.ar_dependent_credit_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ar.dependent_credit.in_effect: true + gov.contrib.states.ar.dependent_credit.age_limit.in_effect: true + gov.contrib.states.ar.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 50_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: AR}} + # Dependent one year under the limit (12 < 13) receives the credit. + # Head personal credit 29 + 1 dependent * 29 = 58. + output: {ar_personal_credits: 58} diff --git a/policyengine_us/tests/policy/contrib/states/az/dependent_credit_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/az/dependent_credit_reform_test.yaml index 322a79998c6..b2c60223698 100644 --- a/policyengine_us/tests/policy/contrib/states/az/dependent_credit_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/az/dependent_credit_reform_test.yaml @@ -39,3 +39,35 @@ tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} households: {household: {members: [parent, child1, child2], state_name: AZ}} output: {az_dependent_tax_credit_potential: 100} + +- name: AZ dependent credit reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.az.dependent_credit.az_dependent_credit_reform.az_dependent_credit_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.az.dependent_credit.in_effect: true + gov.contrib.states.az.dependent_credit.age_limit.in_effect: true + gov.contrib.states.az.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: AZ}} + # Dependent at the age limit (13 == threshold) is excluded; over-age fallback is nothing. + output: {az_dependent_tax_credit_potential: 0} + +- name: AZ dependent credit reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.az.dependent_credit.az_dependent_credit_reform.az_dependent_credit_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.az.dependent_credit.in_effect: true + gov.contrib.states.az.dependent_credit.age_limit.in_effect: true + gov.contrib.states.az.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 30_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: AZ}} + # Dependent one year under the limit (12 < 13) receives the credit. + output: {az_dependent_tax_credit_potential: 100} diff --git a/policyengine_us/tests/policy/contrib/states/ca/dependent_credit_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ca/dependent_credit_reform_test.yaml index f96f3533100..26038834ab8 100644 --- a/policyengine_us/tests/policy/contrib/states/ca/dependent_credit_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/ca/dependent_credit_reform_test.yaml @@ -52,3 +52,37 @@ tax_units: {tax_unit: {members: [parent], filing_status: SINGLE}} households: {household: {members: [parent], state_name: CA}} output: {ca_exemptions: 153} # personal only, no dependents + +- name: CA dependent credit reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.ca.dependent_credit.ca_dependent_credit_reform.ca_dependent_credit_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ca.dependent_credit.in_effect: true + gov.contrib.states.ca.dependent_credit.amount: 1_000 + gov.contrib.states.ca.dependent_credit.age_limit.in_effect: true + gov.contrib.states.ca.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: CA}} + # Dependent at the age limit (13 == threshold) keeps the baseline older amount. + output: {ca_exemptions: 628} # 153 personal + 475 baseline older + +- name: CA dependent credit reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.ca.dependent_credit.ca_dependent_credit_reform.ca_dependent_credit_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ca.dependent_credit.in_effect: true + gov.contrib.states.ca.dependent_credit.amount: 1_000 + gov.contrib.states.ca.dependent_credit.age_limit.in_effect: true + gov.contrib.states.ca.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: CA}} + # Dependent one year under the limit (12 < 13) is re-priced to the reform amount. + output: {ca_exemptions: 1_153} # 153 personal + 1,000 young diff --git a/policyengine_us/tests/policy/contrib/states/ga/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ga/dependent_exemption_reform_test.yaml index cf48a4d7b62..fd067172dc2 100644 --- a/policyengine_us/tests/policy/contrib/states/ga/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/ga/dependent_exemption_reform_test.yaml @@ -10,7 +10,9 @@ tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} households: {household: {members: [parent, child1, child2], state_name: GA}} # 2 dependents * 4,000 = 8,000 (matches baseline; GA has no personal exemption in 2025). - output: {ga_exemptions: 8_000} + output: + ga_exemptions: 8_000 + ga_dependent_exemption: 8_000 # dedicated dependent variable pins the dependent-vs-personal split - name: GA dependent exemption reform - amount zero removes dependent portion only period: 2025 @@ -25,7 +27,9 @@ tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} households: {household: {members: [parent, child1, child2], state_name: GA}} # Dependent portion removed; personal portion preserved (0 in 2025, GA has no personal exemption). - output: {ga_exemptions: 0} + output: + ga_exemptions: 0 + ga_dependent_exemption: 0 # dependent variable is what amount:0 zeroes, isolated from personal - name: GA dependent exemption reform - childless single unaffected period: 2025 @@ -53,3 +57,40 @@ # Only the under-18 dependent gets the exemption (1 * 4,000). The over-age # dependent falls back to the personal treatment, which is nothing in GA. output: {ga_exemptions: 4_000} + +- name: GA dependent exemption reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.ga.dependent_exemption.ga_dependent_exemption_reform.ga_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ga.dependent_exemption.in_effect: true + gov.contrib.states.ga.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ga.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 18, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: GA}} + # Dependent at the age limit (18 == threshold) is excluded; GA has no personal + # dependent fallback, so both the dependent variable and total exemptions are 0. + output: + ga_exemptions: 0 + ga_dependent_exemption: 0 + +- name: GA dependent exemption reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.ga.dependent_exemption.ga_dependent_exemption_reform.ga_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ga.dependent_exemption.in_effect: true + gov.contrib.states.ga.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ga.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 17, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: GA}} + # Dependent one year under the limit (17 < 18) receives the exemption (1 * 4,000). + output: + ga_exemptions: 4_000 + ga_dependent_exemption: 4_000 diff --git a/policyengine_us/tests/policy/contrib/states/ia/dependent_credit_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ia/dependent_credit_reform_test.yaml index f671257834f..11d65c9d7af 100644 --- a/policyengine_us/tests/policy/contrib/states/ia/dependent_credit_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/ia/dependent_credit_reform_test.yaml @@ -52,3 +52,37 @@ tax_units: {tax_unit: {members: [parent], filing_status: SINGLE}} households: {household: {members: [parent], state_name: IA}} output: {ia_exemption_credit: 40} # personal only, no dependents + +- name: IA dependent credit reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.ia.dependent_credit.ia_dependent_credit_reform.ia_dependent_credit_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ia.dependent_credit.in_effect: true + gov.contrib.states.ia.dependent_credit.amount: 100 + gov.contrib.states.ia.dependent_credit.age_limit.in_effect: true + gov.contrib.states.ia.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: IA}} + # Dependent at the age limit (13 == threshold) keeps the baseline older amount. + output: {ia_exemption_credit: 80} # 40 personal + 40 baseline older + +- name: IA dependent credit reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.ia.dependent_credit.ia_dependent_credit_reform.ia_dependent_credit_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ia.dependent_credit.in_effect: true + gov.contrib.states.ia.dependent_credit.amount: 100 + gov.contrib.states.ia.dependent_credit.age_limit.in_effect: true + gov.contrib.states.ia.dependent_credit.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: IA}} + # Dependent one year under the limit (12 < 13) is re-priced to the reform amount. + output: {ia_exemption_credit: 140} # 40 personal + 100 young diff --git a/policyengine_us/tests/policy/contrib/states/il/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/il/dependent_exemption_reform_test.yaml index 456b3e54bc6..b10de6f49ee 100644 --- a/policyengine_us/tests/policy/contrib/states/il/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/il/dependent_exemption_reform_test.yaml @@ -39,3 +39,35 @@ tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} households: {household: {members: [parent, child1, child2], state_name: IL}} output: {il_dependent_exemption: 2_850} # only the under-13 child counts + +- name: IL dependent exemption reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.il.dependent_exemption.il_dependent_exemption_reform.il_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.il.dependent_exemption.in_effect: true + gov.contrib.states.il.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.il.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: IL}} + # Dependent at the age limit (13 == threshold) is excluded; over-age fallback is nothing. + output: {il_dependent_exemption: 0} + +- name: IL dependent exemption reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.il.dependent_exemption.il_dependent_exemption_reform.il_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.il.dependent_exemption.in_effect: true + gov.contrib.states.il.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.il.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: IL}} + # Dependent one year under the limit (12 < 13) receives the exemption. + output: {il_dependent_exemption: 2_850} diff --git a/policyengine_us/tests/policy/contrib/states/ks/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ks/dependent_exemption_reform_test.yaml index b1f21ce0786..b4c9df30af0 100644 --- a/policyengine_us/tests/policy/contrib/states/ks/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/ks/dependent_exemption_reform_test.yaml @@ -71,3 +71,37 @@ households: {household: {members: [parent1, parent2, child1, child2], state_name: KS}} # JOINT base 18,320 personal preserved; dependent portion removed (amount 0). output: {ks_exemptions: 18_320} + +- name: KS dependent exemption reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.ks.dependent_exemption.ks_dependent_exemption_reform.ks_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ks.dependent_exemption.in_effect: true + gov.contrib.states.ks.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ks.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 18, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: KS}} + # Dependent at the age limit (18 == threshold) is excluded; only the personal + # (SINGLE base) 9,160 remains. + output: {ks_exemptions: 9_160} + +- name: KS dependent exemption reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.ks.dependent_exemption.ks_dependent_exemption_reform.ks_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ks.dependent_exemption.in_effect: true + gov.contrib.states.ks.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ks.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 17, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: KS}} + # Dependent one year under the limit (17 < 18) gets the exemption. + # 9,160 personal + 1 eligible dependent * 2,320 = 11,480. + output: {ks_exemptions: 11_480} diff --git a/policyengine_us/tests/policy/contrib/states/mn/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/mn/dependent_exemption_reform_test.yaml index 115b7018df8..792ebbcaf71 100644 --- a/policyengine_us/tests/policy/contrib/states/mn/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/mn/dependent_exemption_reform_test.yaml @@ -95,3 +95,38 @@ # Base = 0 (young) + 5,200 (over-age fallback) = 5,200; the same 50% AGI # phase-out that halves the baseline also halves the fallback: 5,200 -> 2,600. output: {mn_exemptions: 2_600} + +- name: MN dependent exemption reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.mn.dependent_exemption.mn_dependent_exemption_reform.mn_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.mn.dependent_exemption.in_effect: true + gov.contrib.states.mn.dependent_exemption.amount: 0 + gov.contrib.states.mn.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.mn.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 18, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: MN}} + # Dependent at the age limit (18 == threshold) keeps the baseline 5,200 + # (below phase-out at this AGI). + output: {mn_exemptions: 5_200} + +- name: MN dependent exemption reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.mn.dependent_exemption.mn_dependent_exemption_reform.mn_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.mn.dependent_exemption.in_effect: true + gov.contrib.states.mn.dependent_exemption.amount: 0 + gov.contrib.states.mn.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.mn.dependent_exemption.age_limit.threshold: 18 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 17, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: MN}} + # Dependent one year under the limit (17 < 18) is re-priced to the reform amount (0). + output: {mn_exemptions: 0} diff --git a/policyengine_us/tests/policy/contrib/states/ms/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ms/dependent_exemption_reform_test.yaml index 18ce5d448da..e59194e6d97 100644 --- a/policyengine_us/tests/policy/contrib/states/ms/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/ms/dependent_exemption_reform_test.yaml @@ -39,3 +39,35 @@ tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} households: {household: {members: [parent, child1, child2], state_name: MS}} output: {ms_dependents_exemption: 1_500} # only the under-13 child counts + +- name: MS dependent exemption reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.ms.dependent_exemption.ms_dependent_exemption_reform.ms_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ms.dependent_exemption.in_effect: true + gov.contrib.states.ms.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ms.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: MS}} + # Dependent at the age limit (13 == threshold) is excluded; over-age fallback is nothing. + output: {ms_dependents_exemption: 0} + +- name: MS dependent exemption reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.ms.dependent_exemption.ms_dependent_exemption_reform.ms_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ms.dependent_exemption.in_effect: true + gov.contrib.states.ms.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ms.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: MS}} + # Dependent one year under the limit (12 < 13) receives the exemption. + output: {ms_dependents_exemption: 1_500} diff --git a/policyengine_us/tests/policy/contrib/states/nj/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/nj/dependent_exemption_reform_test.yaml index 5df8bae505e..fc009406f12 100644 --- a/policyengine_us/tests/policy/contrib/states/nj/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/nj/dependent_exemption_reform_test.yaml @@ -58,3 +58,37 @@ output: nj_dependents_exemption: 0 # main exemption eliminated nj_dependents_attending_college_exemption: 1_000 # college exemption untouched + +- name: NJ dependent exemption reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.nj.dependent_exemption.nj_dependent_exemption_reform.nj_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.nj.dependent_exemption.in_effect: true + gov.contrib.states.nj.dependent_exemption.amount: 0 + gov.contrib.states.nj.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.nj.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: NJ}} + # Dependent at the age limit (13 == threshold) keeps the baseline 1,500. + output: {nj_dependents_exemption: 1_500} + +- name: NJ dependent exemption reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.nj.dependent_exemption.nj_dependent_exemption_reform.nj_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.nj.dependent_exemption.in_effect: true + gov.contrib.states.nj.dependent_exemption.amount: 0 + gov.contrib.states.nj.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.nj.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: NJ}} + # Dependent one year under the limit (12 < 13) is re-priced to the reform amount (0). + output: {nj_dependents_exemption: 0} diff --git a/policyengine_us/tests/policy/contrib/states/ny/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ny/dependent_exemption_reform_test.yaml index 285c075b535..65344a7d085 100644 --- a/policyengine_us/tests/policy/contrib/states/ny/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/ny/dependent_exemption_reform_test.yaml @@ -39,3 +39,35 @@ tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} households: {household: {members: [parent, child1, child2], state_name: NY}} output: {ny_exemptions: 1_000} # only the under-13 child counts + +- name: NY dependent exemption reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.ny.dependent_exemption.ny_dependent_exemption_reform.ny_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ny.dependent_exemption.in_effect: true + gov.contrib.states.ny.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ny.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: NY}} + # Dependent at the age limit (13 == threshold) is excluded; over-age fallback is nothing. + output: {ny_exemptions: 0} + +- name: NY dependent exemption reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.ny.dependent_exemption.ny_dependent_exemption_reform.ny_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.ny.dependent_exemption.in_effect: true + gov.contrib.states.ny.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ny.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: NY}} + # Dependent one year under the limit (12 < 13) receives the exemption. + output: {ny_exemptions: 1_000} diff --git a/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml index b315ddccb72..b9dd61a79e2 100644 --- a/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml @@ -55,3 +55,37 @@ output: sc_dependent_exemption: 0 # dependent exemption eliminated sc_young_child_deduction: 4_930 # stacked young-child deduction untouched + +- name: SC dependent exemption reform - age at limit threshold is excluded + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + gov.contrib.states.sc.dependent_exemption.amount: 0 + gov.contrib.states.sc.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.sc.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 13, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: SC}} + # Dependent at the age limit (13 == threshold) keeps the baseline 4,930. + output: {sc_dependent_exemption: 4_930} + +- name: SC dependent exemption reform - age one below threshold is included + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + absolute_error_margin: 0.01 + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + gov.contrib.states.sc.dependent_exemption.amount: 0 + gov.contrib.states.sc.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.sc.dependent_exemption.age_limit.threshold: 13 + people: + parent: {age: 40, employment_income: 60_000} + child1: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1], filing_status: SINGLE}} + households: {household: {members: [parent, child1], state_name: SC}} + # Dependent one year under the limit (12 < 13) is re-priced to the reform amount (0). + output: {sc_dependent_exemption: 0}