Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog_entry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- bump: minor
changes:
added:
- CDCTC reform that makes families eligible if at least one parent works (instead of requiring both parents to work)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
description: The CDCTC single parent work requirement reform is in effect.
metadata:
unit: bool
period: year
label: CDCTC single parent work requirement reform in effect

values:
0001-01-01: false
3 changes: 3 additions & 0 deletions policyengine_us/reforms/cdcc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from policyengine_us.reforms.cdcc.cdcc_single_parent_work_requirement import (
create_cdcc_single_parent_work_requirement_reform,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from policyengine_us.model_api import *
from policyengine_core.periods import period as period_


def create_cdcc_single_parent_work_requirement() -> Reform:
"""
Reform that changes CDCTC eligibility to require at least one parent to work
instead of both parents.

Current law: For married couples, childcare expenses are capped at the
minimum of the two spouses' earnings, effectively requiring both to work.

This reform: Changes the cap to the maximum of the two spouses' earnings,
allowing families to qualify if at least one parent works.

Note: We override cdcc_relevant_expenses directly (rather than
min_head_spouse_earned) to avoid affecting state programs that also
use min_head_spouse_earned.
"""

class cdcc_relevant_expenses(Variable):
value_type = float
entity = TaxUnit
label = "CDCC-relevant care expenses"
unit = USD
definition_period = YEAR
reference = (
"https://www.law.cornell.edu/uscode/text/26/21#c",
"https://www.law.cornell.edu/uscode/text/26/21#d_1",
)

def formula(tax_unit, period, parameters):
expenses = tax_unit("tax_unit_childcare_expenses", period)
cdcc_limit = tax_unit("cdcc_limit", period)
eligible_capped_expenses = min_(expenses, cdcc_limit)

# Reform: Use max of head/spouse earnings instead of min
# This allows eligibility if at least one parent works
is_joint = tax_unit("tax_unit_is_joint", period)
head_earnings = tax_unit("head_earned", period)
spouse_earnings = tax_unit("spouse_earned", period)
earnings_cap = where(
is_joint, max_(head_earnings, spouse_earnings), head_earnings
)

return min_(eligible_capped_expenses, earnings_cap)

class reform(Reform):
def apply(self):
self.update_variable(cdcc_relevant_expenses)

return reform


def create_cdcc_single_parent_work_requirement_reform(
parameters, period, bypass: bool = False
):
if bypass:
return create_cdcc_single_parent_work_requirement()

p = parameters.gov.contrib.cdcc.single_parent_work_requirement

# Check if reform is active in current period or next 5 years
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_cdcc_single_parent_work_requirement()
else:
return None


cdcc_single_parent_work_requirement = (
create_cdcc_single_parent_work_requirement_reform(None, None, bypass=True)
)
7 changes: 7 additions & 0 deletions policyengine_us/reforms/reforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@
create_aca_ptc_simplified_bracket_reform,
create_aca_ptc_700_fpl_cliff_reform,
)
from .cdcc import (
create_cdcc_single_parent_work_requirement_reform,
)


from policyengine_core.reforms import Reform
Expand Down Expand Up @@ -298,6 +301,9 @@ def create_structural_reforms_from_parameters(parameters, period):
aca_ptc_700_fpl_cliff = create_aca_ptc_700_fpl_cliff_reform(
parameters, period
)
cdcc_single_parent_work_requirement = (
create_cdcc_single_parent_work_requirement_reform(parameters, period)
)

reforms = [
afa_reform,
Expand Down Expand Up @@ -358,6 +364,7 @@ def create_structural_reforms_from_parameters(parameters, period):
aca_ptc_additional_bracket,
aca_ptc_simplified_bracket,
aca_ptc_700_fpl_cliff,
cdcc_single_parent_work_requirement,
]
reforms = tuple(filter(lambda x: x is not None, reforms))

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Tests for CDCTC reform that makes families eligible if at least one parent works
# instead of requiring both parents to work
#
# NOTE: This reform overrides cdcc_relevant_expenses directly (not min_head_spouse_earned)
# to avoid affecting state programs that use min_head_spouse_earned.

- name: One-earner married couple gets CDCC under reform
period: 2024
reforms: policyengine_us.reforms.cdcc.cdcc_single_parent_work_requirement.cdcc_single_parent_work_requirement
input:
people:
adult1:
age: 35
is_tax_unit_head: true
employment_income: 50_000
adult2:
age: 35
is_tax_unit_spouse: true
employment_income: 0
child:
age: 5
is_tax_unit_dependent: true
tax_units:
tax_unit:
members: [adult1, adult2, child]
tax_unit_childcare_expenses: 5_000
households:
household:
members: [adult1, adult2, child]
state_code: CA
output:
# min_head_spouse_earned is NOT modified by this reform (unchanged from baseline)
min_head_spouse_earned: 0
# Reform calculates: min(expenses, cdcc_limit, max(head, spouse))
# = min($5,000, $3,000, max($50,000, $0)) = min($5,000, $3,000, $50,000) = $3,000
cdcc_relevant_expenses: 3_000

- name: One-earner married couple - baseline would give zero
period: 2024
# No reform - baseline behavior
input:
people:
adult1:
age: 35
is_tax_unit_head: true
employment_income: 50_000
adult2:
age: 35
is_tax_unit_spouse: true
employment_income: 0
child:
age: 5
is_tax_unit_dependent: true
tax_units:
tax_unit:
members: [adult1, adult2, child]
tax_unit_childcare_expenses: 5_000
households:
household:
members: [adult1, adult2, child]
state_code: CA
output:
# Baseline uses min(head_earned, spouse_earned) = min($50,000, $0) = $0
min_head_spouse_earned: 0
# No relevant expenses since capped at $0
cdcc_relevant_expenses: 0
cdcc: 0

- name: Two-earner married couple unchanged by reform
period: 2024
reforms: policyengine_us.reforms.cdcc.cdcc_single_parent_work_requirement.cdcc_single_parent_work_requirement
input:
people:
adult1:
age: 35
is_tax_unit_head: true
employment_income: 50_000
adult2:
age: 35
is_tax_unit_spouse: true
employment_income: 30_000
child:
age: 5
is_tax_unit_dependent: true
tax_units:
tax_unit:
members: [adult1, adult2, child]
tax_unit_childcare_expenses: 5_000
households:
household:
members: [adult1, adult2, child]
state_code: CA
output:
# min_head_spouse_earned unchanged: min($50,000, $30,000) = $30,000
min_head_spouse_earned: 30_000
# Reform: min($5,000, $3,000, max($50,000, $30,000)) = min($5,000, $3,000, $50,000) = $3,000
# Same as baseline since both earnings exceed the $3,000 limit
cdcc_relevant_expenses: 3_000

- name: Single parent unaffected by reform
period: 2024
reforms: policyengine_us.reforms.cdcc.cdcc_single_parent_work_requirement.cdcc_single_parent_work_requirement
input:
people:
adult:
age: 35
is_tax_unit_head: true
employment_income: 40_000
child:
age: 5
is_tax_unit_dependent: true
tax_units:
tax_unit:
members: [adult, child]
tax_unit_childcare_expenses: 4_000
households:
household:
members: [adult, child]
state_code: CA
output:
# Single filer - min_head_spouse_earned uses head_earned
min_head_spouse_earned: 40_000
# Reform: min($4,000, $3,000, $40,000) = $3,000 (same as baseline)
cdcc_relevant_expenses: 3_000

- name: Spouse is the only earner - reform enables credit
period: 2024
reforms: policyengine_us.reforms.cdcc.cdcc_single_parent_work_requirement.cdcc_single_parent_work_requirement
input:
people:
adult1:
age: 35
is_tax_unit_head: true
employment_income: 0
adult2:
age: 35
is_tax_unit_spouse: true
employment_income: 60_000
child:
age: 3
is_tax_unit_dependent: true
tax_units:
tax_unit:
members: [adult1, adult2, child]
tax_unit_childcare_expenses: 8_000
households:
household:
members: [adult1, adult2, child]
state_code: CA
output:
# min_head_spouse_earned unchanged: min($0, $60,000) = $0
min_head_spouse_earned: 0
# Reform: min($8,000, $3,000, max($0, $60,000)) = min($8,000, $3,000, $60,000) = $3,000
cdcc_relevant_expenses: 3_000
4 changes: 2 additions & 2 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.