PolicyEngine / PolicyEngine/microcosm

Carry CPS employer fields and add a jobs imputation stage for employer-side payroll taxes

Open
#942 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
0
Forks
4
Avg merge
1d 3h
Merged PRs (30d)
94

Description

Finding

The dashboard analysis for FUTA (futa-wage-base-dashboard#4) joined raw CPS ASEC employer fields onto the certified national file by PERIDNUM and source_year (100% of 166,321 persons match, ASEC 2023 to 2025). Two things the file lacks for employer-side payroll taxes:

  1. Employer count. FUTA applies its wage base per employer per employee. The person table has no employers-last-year field, so any per-employer cap is applied once per worker. The raw ASEC has PHMEMPRS (1, 2, 3 or more; simultaneous jobs count as one) and the longest-job vs other-employer wage split (ERN_VAL with ERN_SRCE = 1, WS_VAL). Definitions: Census 2024 ASEC public-use data dictionary.
  2. Longest-job class of worker. PEIO1COW (March reference-week job) is carried; LJCW (class of worker on the longest job last year, with the federal/state/local split) is not. FUTA exemption follows the employer of record for the year's wages.

Measured on the certified file with the joined fields: exempt employers (government plus private nonprofit) hold 21.7% of wages under the $7,000 base and 22.7% under $43,000; per-employer capping as the CPS reports employers raises revenue at the $7,000 base by 7% (Census weights) to 12% (model weights).

Two data-quality observations from the same join

  • Multi-employer workers are over-represented after selection and calibration. 14.8% of wage earners report two or more employers at model weights, 13.1% among the selected rows at Census weights, 10.9% in the full ASEC. Employer count is not a target, so the sparse selection and reweighting drift on it. For ratios like this the raw ASEC at Census weights is currently the better source.
  • The CPS itself undercounts employer-employee pairs. 1.13 employers per wage earner in the ASEC (3 or more counted as 3) against 275.0 million Forms W-2 filed in calendar 2024 (IRS Publication 6961, Table 2) for about 167 million earners, roughly 1.65 per earner. With the exempt and per-employer adjustments applied, the FUTA model sits 17% below IRS collections; this gap is the likely reason.

Proposal

  1. Carry PHMEMPRS, LJCW, ERN_VAL, ERN_SRCE, WS_VAL through the carried-column stage (us_runtime/cps_carried.py, source_stages.json) as person inputs. Small change; unblocks a per-employer FUTA rule in the engine.
  2. Add a jobs imputation stage: give each worker an employer count and wage split seeded from those fields, fitted so the implied distribution of jobs by wage band matches IRS SOI Form W-2 tabulations. Once jobs exist as a structure, W-2 counts by band become ordinary sum targets with broad support (every worker carries jobs), and FUTA collections become a held-out check. Reweighting alone cannot fix the count: hitting 275 million pairs by upweighting the 11% of multi-employer respondents is the thin-support concentration docs/us-fact-to-target.md already rules out.

Related: the wage-band target proposal in the companion issue. Downstream rule change: policyengine-us issue on FUTA exempt employers and per-employer caps (linked from the Slack thread).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with us_runtime/cps_carried.py, source_stages.json, and docs/us-fact-to-target.md; trace how carried person inputs and calibration targets are represented. Carry the named CPS fields and add a jobs-imputation stage whose implied job distribution matches IRS SOI Form W-2 wage-band tabulations, with FUTA collections as a held-out check.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data-engineering
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.