You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Scoping: State Paid Family & Medical Leave in PolicyEngine-US
Status: Draft for internal review (local). Not yet posted. Scope: Government-run (social-insurance / state-fund) PFL, PFML, TDI/SDI, and
family-leave-insurance programs. Excludes purely private/employer plans. Reference for program facts: Bipartisan Policy Center, "State Paid Family
Leave Laws Across the U.S." (plus each state's statute, already cited in the
existing variable reference fields).
1. TL;DR
PolicyEngine-US models the premium/contribution side of these programs well
(13 of 15 jurisdictions), and it flows correctly into household_net_income. It
models the benefit side almost not at all: only Washington has benefit
variables, and even those are orphaned (computed by no other variable, never
added to income) and driven by manual inputs — a what-if calculator, not a
simulated benefit.
Two structural facts shape everything below:
Small-business carve-outs are coded but dormant. The employer-size logic
exists for 6 states, but it keys off employer_headcount, which defaults to 100 and has no microdata source — so in any population run the carve-out
never fires.
Benefits cannot appear in microsimulation without new data. Benefit
receipt depends on who took leave, of what type, for how many weeks — none
of which is in the CPS. Comparable benefits (e.g. unemployment_compensation) enter as data-populated input variables;
there is no analogous paid_family_leave input, and the CPS ASEC does not
separately identify PFL income.
2. Background: a PFL program has two halves
Half
What it is
Who it affects
PolicyEngine mechanism
Premium / contribution
Payroll deduction (employee and/or employer) that funds the program
Employer contributions are aggregated in employer_total_additional_state_payroll_tax (CA, CO, DC, DE, MA, ME, OR, RI,
VT, WA) — tracked but, correctly, not deducted from household net income.
Wage bases are modeled with reasonable fidelity: most cap at the Social Security
wage base (gov.irs.payroll.social_security.cap); NY and DC are uncapped; MN
rounds to the nearest $1,000; NY/DBL apply annual max-contribution caps. All
bases derive from W-2 employment income — see §6 on self-employment.
5. Gap register
G1 — Benefits are essentially unmodeled (severity: high)
Only WA has benefit variables (wa_pfml_eligible, wa_pfml_weekly_benefit_amount, wa_pfml_max_leave_weeks, wa_pfml). The other
12 active programs have no weekly-benefit, wage-replacement, duration, or
eligibility logic. A user asking "what PFL benefit would this household get in
NJ/NY/CA/…?" gets nothing.
G2 — Even WA's benefit is orphaned (severity: high)
wa_pfml is referenced by no other variable (verified by grep). It never
enters household_net_income, MAGI, or any downstream program. It is a
standalone calculator activated only by manual inputs
(wa_pfml_leave_type default NONE, wa_pfml_average_weekly_wage_override
default -1, wa_pfml_qualifying_period_hours_worked default -1). With
defaults, it returns 0.
G3 — Small-business carve-outs are coded but dormant (severity: medium)
Employer-size logic exists for CO, DE, MA, ME, OR, WA via employer_headcount >= employer_headcount_threshold (DE additionally graduates
small → parental-only → full coverage). But employer_headcount is an input
with default_value = 100 and no microdata source, so:
In microsimulation the carve-out never triggers — every worker is treated
as employed by a large firm.
It only works in single-household what-if calls where the user sets headcount.
Correctness note: where modeled, the carve-out reduces only the employer
share (employees at small firms still pay) — which matches statute. DE correctly
zeroes both sides below its small-employer threshold (whole program off).
G4 — Specific carve-outs not modeled at all (severity: medium)
DC "<5 employees exempt": dc_employer_paid_leave_tax has no headcount
check.
MN "<30 employees → reduced 0.66% premium": model has a single flat employee_rate, no size tier — and no MN employer contribution at all.
MD: entire program (0.90% split, <15-employee employer exemption) absent.
G5 — Self-employed opt-in not modeled (severity: low–medium)
All bases are W-2 wages (employment_income / taxable_earnings_for_social_security); self_employment_income is excluded, so
the self-employed contribute $0 by default — which matches the statutory
default (self-employed are excluded unless they elect in). But the opt-in
election (self-employed choosing coverage → pays premium → gains benefit
eligibility) is modeled nowhere (no *_elect/opt_in variable exists). Moot
today because benefits aren't modeled, but needed for a complete benefit build.
Disability halves that co-fund these programs are partially in
(NY DBL ✅, NJ TDI ✅, RI TDI ✅, CA SDI ✅) but their benefit sides are all
absent, same as PFL.
G7 — Data cannot support benefit microsimulation (severity: high, cross-repo)
unemployment_compensation is a formula-less input populated from CPS and
uprated. There is no paid_family_leave input variable, and the CPS ASEC
does not break PFL benefits out of wages/other income. Therefore benefits are
structurally 0 in any population run. Closing this is a policyengine-us-data
task (impute leave-taking + benefit receipt), not just model code.
PFL/family-leave benefits are generally federally taxable (often 1099-G),
while TDI/medical portions vary by state. Any benefit build must decide whether *_pfml adds to AGI / affects other means-tested programs. WA's orphan sidesteps
this entirely.
6. Do we need new variables? Yes — here's the shape
WA reinvented person-level inputs with a wa_ prefix. A benefit build for 12+
states should instead share generic person-level input variables so a
household describes leave once:
took_paid_family_leave (bool) or weeks_on_paid_family_leave (float)
paid_family_leave_type (Enum: family / medical / …) — generalize WAPFMLLeaveType
6b. Per-state benefit variables (WA is the template)
For each active state, mirroring wa/pfml/:
{st}_pfml_eligible (hours/earnings/tenure test)
{st}_pfml_average_weekly_wage
{st}_pfml_weekly_benefit_amount (state replacement formula + min/max)
{st}_pfml_max_leave_weeks (by leave type)
{st}_pfml (annual benefit)
All the replacement-rate math (e.g. CA's HQE tiers, NJ 85% AWW, NY 67% AWW, DC
90%/50% split, CT 95%/60% split) is in the reference table and each statute —
these become parameters, no hard-coding.
6c. Aggregation + income wiring (fixes G2)
paid_family_leave_income (person) that sums the per-state benefits.
Add it to the appropriate income aggregate(s), gated by the tax-treatment
decision (G8).
6d. Carve-out data (fixes G3)
Give employer_headcount a data source / imputation in policyengine-us-data, or at minimum document that the carve-out is
calculator-only today.
6e. Self-employed opt-in (fixes G5)
{st}_pfml_self_employed_elected (input) that switches on the SE wage base and
benefit eligibility.
7. Recommended phased scope
Phase 0 — cheap correctness fixes (model-only, no data):
Wire wa_pfml into paid_family_leave_income and decide its tax treatment
(G2, G8) — makes the one existing benefit actually do something.
Add MN employer side; add DC <5 and MN <30 carve-outs (G4).
Document the employer_headcount default-100 limitation (G3).
Phase 1 — benefit calculators for the big states (model-only, what-if):
Generic leave inputs (§6a) + per-state benefit variables for CA, NJ, NY, MA,
CT, OR, CO (§6b), wired via paid_family_leave_income (§6c). This gives a
working household calculator for ~90% of covered workers without touching data.
Phase 2 — fill remaining programs: DE, ME, RI (TCI), WA parity, then MD/VA
as they take effect.
Phase 3 — microsimulation (requires policyengine-us-data): impute
leave-taking + benefit receipt and an employer_headcount proxy (G7, G3) so
premiums-vs-benefits and reform analysis work at population scale.
8. Open questions for the team
Priority: calculator vs microsim? Phase 1 (household what-if) is fast and
model-only; Phase 3 (population) needs data-repo work. Which matters more
near-term?
Tax treatment of benefits (G8) — adopt "family-leave taxable, medical/TDI
per-state" or a simpler uniform rule to start?
Generic vs per-state leave inputs — OK to introduce shared paid_family_leave_* inputs and refactor WA onto them, or keep per-state?
Scope of the disability halves (SDI/TDI/DBL benefits) — in or out of this
effort?
employer_headcount imputation — is there an appetite for an employer-size
proxy in policyengine-us-data, or do we accept carve-outs as
calculator-only?
Appendix A — key files
Income wiring: variables/gov/states/tax/payroll/employee_state_payroll_tax.py, variables/gov/irs/tax/payroll/employee_payroll_tax.py
WA benefit template: variables/gov/states/wa/pfml/*,
params parameters/gov/states/wa/pfml/*
Example contribution + carve-out: variables/gov/states/de/tax/payroll/paid_leave/de_paid_leave_contribution_rate.py
Data-input pattern to emulate for benefits: variables/gov/states/unemployment_compensation.py (formula-less, CPS-populated)
cc @MaxGhenis@PavelMakarchuk — would value your steer on the phasing and the open questions (esp. calculator-vs-microsim priority and benefit tax treatment).
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Scoping: State Paid Family & Medical Leave in PolicyEngine-US
Status: Draft for internal review (local). Not yet posted.
Scope: Government-run (social-insurance / state-fund) PFL, PFML, TDI/SDI, and
family-leave-insurance programs. Excludes purely private/employer plans.
Reference for program facts: Bipartisan Policy Center, "State Paid Family
Leave Laws Across the U.S." (plus each state's statute, already cited in the
existing variable
referencefields).1. TL;DR
PolicyEngine-US models the premium/contribution side of these programs well
(13 of 15 jurisdictions), and it flows correctly into
household_net_income. Itmodels the benefit side almost not at all: only Washington has benefit
variables, and even those are orphaned (computed by no other variable, never
added to income) and driven by manual inputs — a what-if calculator, not a
simulated benefit.
Two structural facts shape everything below:
exists for 6 states, but it keys off
employer_headcount, which defaults to100 and has no microdata source — so in any population run the carve-out
never fires.
receipt depends on who took leave, of what type, for how many weeks — none
of which is in the CPS. Comparable benefits (e.g.
unemployment_compensation) enter as data-populated input variables;there is no analogous
paid_family_leaveinput, and the CPS ASEC does notseparately identify PFL income.
2. Background: a PFL program has two halves
*_employee_state_payroll_tax→employee_state_payroll_tax→employee_payroll_tax→ reduceshousehold_net_income. Employer side →employer_total_additional_state_payroll_tax.wa_pfmlexists, and it adds to nothing.The premium is an annual, near-universal cost; the benefit is an occasional,
targeted transfer. They require completely different modeling and data.
3. Program universe (15 jurisdictions)
So: contribution side ≈ complete (13/15; MD and VA absent, MN half). Benefit
side ≈ absent (1/15, and non-functional).
4. Current architecture (what works)
Employee contributions are correctly wired into net income:
Employer contributions are aggregated in
employer_total_additional_state_payroll_tax(CA, CO, DC, DE, MA, ME, OR, RI,VT, WA) — tracked but, correctly, not deducted from household net income.
Wage bases are modeled with reasonable fidelity: most cap at the Social Security
wage base (
gov.irs.payroll.social_security.cap); NY and DC are uncapped; MNrounds to the nearest $1,000; NY/DBL apply annual max-contribution caps. All
bases derive from W-2 employment income — see §6 on self-employment.
5. Gap register
G1 — Benefits are essentially unmodeled (severity: high)
Only WA has benefit variables (
wa_pfml_eligible,wa_pfml_weekly_benefit_amount,wa_pfml_max_leave_weeks,wa_pfml). The other12 active programs have no weekly-benefit, wage-replacement, duration, or
eligibility logic. A user asking "what PFL benefit would this household get in
NJ/NY/CA/…?" gets nothing.
G2 — Even WA's benefit is orphaned (severity: high)
wa_pfmlis referenced by no other variable (verified by grep). It neverenters
household_net_income, MAGI, or any downstream program. It is astandalone calculator activated only by manual inputs
(
wa_pfml_leave_typedefaultNONE,wa_pfml_average_weekly_wage_overridedefault
-1,wa_pfml_qualifying_period_hours_workeddefault-1). Withdefaults, it returns 0.
G3 — Small-business carve-outs are coded but dormant (severity: medium)
Employer-size logic exists for CO, DE, MA, ME, OR, WA via
employer_headcount >= employer_headcount_threshold(DE additionally graduatessmall → parental-only → full coverage). But
employer_headcountis an inputwith
default_value = 100and no microdata source, so:as employed by a large firm.
Correctness note: where modeled, the carve-out reduces only the employer
share (employees at small firms still pay) — which matches statute. DE correctly
zeroes both sides below its small-employer threshold (whole program off).
G4 — Specific carve-outs not modeled at all (severity: medium)
dc_employer_paid_leave_taxhas no headcountcheck.
employee_rate, no size tier — and no MN employer contribution at all.G5 — Self-employed opt-in not modeled (severity: low–medium)
All bases are W-2 wages (
employment_income/taxable_earnings_for_social_security);self_employment_incomeis excluded, sothe self-employed contribute $0 by default — which matches the statutory
default (self-employed are excluded unless they elect in). But the opt-in
election (self-employed choosing coverage → pays premium → gains benefit
eligibility) is modeled nowhere (no
*_elect/opt_invariable exists). Moottoday because benefits aren't modeled, but needed for a complete benefit build.
G6 — Missing programs/sub-programs (severity: medium)
(NY DBL ✅, NJ TDI ✅, RI TDI ✅, CA SDI ✅) but their benefit sides are all
absent, same as PFL.
G7 — Data cannot support benefit microsimulation (severity: high, cross-repo)
unemployment_compensationis a formula-less input populated from CPS anduprated. There is no
paid_family_leaveinput variable, and the CPS ASECdoes not break PFL benefits out of wages/other income. Therefore benefits are
structurally 0 in any population run. Closing this is a
policyengine-us-datatask (impute leave-taking + benefit receipt), not just model code.
G8 — Benefit tax treatment undecided (severity: medium, blocks G1)
PFL/family-leave benefits are generally federally taxable (often 1099-G),
while TDI/medical portions vary by state. Any benefit build must decide whether
*_pfmladds to AGI / affects other means-tested programs. WA's orphan sidestepsthis entirely.
6. Do we need new variables? Yes — here's the shape
6a. Shared, generic leave inputs (replace WA's bespoke overrides)
WA reinvented person-level inputs with a
wa_prefix. A benefit build for 12+states should instead share generic person-level input variables so a
household describes leave once:
took_paid_family_leave(bool) orweeks_on_paid_family_leave(float)paid_family_leave_type(Enum: family / medical / …) — generalizeWAPFMLLeaveTypeaverage_weekly_wage_override,qualifying_hours_override6b. Per-state benefit variables (WA is the template)
For each active state, mirroring
wa/pfml/:{st}_pfml_eligible(hours/earnings/tenure test){st}_pfml_average_weekly_wage{st}_pfml_weekly_benefit_amount(state replacement formula + min/max){st}_pfml_max_leave_weeks(by leave type){st}_pfml(annual benefit)All the replacement-rate math (e.g. CA's HQE tiers, NJ 85% AWW, NY 67% AWW, DC
90%/50% split, CT 95%/60% split) is in the reference table and each statute —
these become parameters, no hard-coding.
6c. Aggregation + income wiring (fixes G2)
paid_family_leave_income(person) that sums the per-state benefits.decision (G8).
6d. Carve-out data (fixes G3)
employer_headcounta data source / imputation inpolicyengine-us-data, or at minimum document that the carve-out iscalculator-only today.
6e. Self-employed opt-in (fixes G5)
{st}_pfml_self_employed_elected(input) that switches on the SE wage base andbenefit eligibility.
7. Recommended phased scope
Phase 0 — cheap correctness fixes (model-only, no data):
wa_pfmlintopaid_family_leave_incomeand decide its tax treatment(G2, G8) — makes the one existing benefit actually do something.
employer_headcountdefault-100 limitation (G3).Phase 1 — benefit calculators for the big states (model-only, what-if):
CT, OR, CO (§6b), wired via
paid_family_leave_income(§6c). This gives aworking household calculator for ~90% of covered workers without touching data.
Phase 2 — fill remaining programs: DE, ME, RI (TCI), WA parity, then MD/VA
as they take effect.
Phase 3 — microsimulation (requires
policyengine-us-data): imputeleave-taking + benefit receipt and an
employer_headcountproxy (G7, G3) sopremiums-vs-benefits and reform analysis work at population scale.
8. Open questions for the team
model-only; Phase 3 (population) needs data-repo work. Which matters more
near-term?
per-state" or a simpler uniform rule to start?
paid_family_leave_*inputs and refactor WA onto them, or keep per-state?effort?
employer_headcountimputation — is there an appetite for an employer-sizeproxy in
policyengine-us-data, or do we accept carve-outs ascalculator-only?
Appendix A — key files
variables/gov/states/tax/payroll/employee_state_payroll_tax.py,variables/gov/irs/tax/payroll/employee_payroll_tax.pyvariables/gov/states/tax/payroll/employer_total_additional_state_payroll_tax.pyvariables/input/employer_payroll.pyvariables/gov/states/wa/pfml/*,params
parameters/gov/states/wa/pfml/*variables/gov/states/de/tax/payroll/paid_leave/de_paid_leave_contribution_rate.pyvariables/gov/states/unemployment_compensation.py(formula-less, CPS-populated)cc @MaxGhenis @PavelMakarchuk — would value your steer on the phasing and the open questions (esp. calculator-vs-microsim priority and benefit tax treatment).
Beta Was this translation helpful? Give feedback.
All reactions