Skip to content

Two-signal FLSA overtime incidence: usual-hours leg joins the reference-week snapshot (#451 item 4 residual) - #526

Merged
MaxGhenis merged 4 commits into
mainfrom
overtime-incidence-451
Jul 24, 2026
Merged

Two-signal FLSA overtime incidence: usual-hours leg joins the reference-week snapshot (#451 item 4 residual)#526
MaxGhenis merged 4 commits into
mainfrom
overtime-incidence-451

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Two-signal FLSA overtime incidence: usual-hours leg joins the reference-week snapshot (#451 item 4 residual)

The diagnosis (measured, certified N c3e378a-20260722T010408Z)

The overtime surface was measured-known-short: 19.86M weighted fsla_overtime_premium persons vs Treasury's published ">29 million" TY2025 NTOO claimant units; the OBBBA overtime probe at −$16.86B = 51% of JCX-35-25's FY2026 −$32.806B. Decomposed per the #496 forensics pattern (target-frame checkpoint pairing for pre-solve design weights; direct measurement on the published store):

(c) Concept — small, and it makes the gap worse, not better. The 19.86M carrier persons collapse to 19.03M carrier tax units (only 0.82M weighted units hold 2+ carriers), so in Treasury's own unit space the gap is 29/19.03 ≈ 1.52×. Universe edges (all measured or sourced): TY2024 frame vs TY2025 claims; claims may include non-FLSA-required overtime under the TY2025 transition-relief reporting (over-inclusive edge on the Treasury side); caps/phaseout shrink deductions, not claimant counts. Per-unit mean $6,032 vs Treasury's ">$3,100" average deduction — the tips signature (fewer carriers, ~2× richer) on the overtime surface.

(b) Selection — exonerated on both margins. The stage runs release-side at build_us_fiscal_refresh_release.py:8141, after the frozen rmloss100 selection (~:7033), so selection could not drop carriers that did not exist yet (the tips forensics result generalizes). In weight space the solve up-weighted carriers: design 18.15M → final 19.86M (+9.4%), design mass $110.98B → final $114.79B. Composition: the frame's usual-hours>40 share among earners (18.3% final / similar design) matches the national CPS ORG 2024 donor (17.0% weighted) — the 57,240 frame is not starving high-hours workers. Zero overtime targets in the certified diagnostics (untargeted receipt, re-confirmed from the same diagnostics the #496 tool consumes; running the tool with --target overtime refuses with "No household-entity target matches").

(a) Incidence — the dominant leg, and it is structural. The retired construction gates on hours_worked_last_week > 40: the ASEC reference week (A_HRS1), a single point-in-time draw that is not even inside the retrospective income year the premium is attributed to. Its own archived docstring states the design: "constructs the premium share implied by the reported/reference week, then applies that share to annual employment income" — a mass proxy that collapses incidence to one week's draw. Measured on the certified frame (final weights):

  • Only 31.8M weighted earners have reference-week hours >40 at all; exemption screens cut that to 19.86M. The construction cannot reach 29M no matter how the solve weights it.
  • A 65.5M-person weighted heap sits at exactly 40 hours (39.4% of all earners; usual-hours heap 86.7M) — the gate lives on the knife-edge of CPS hours heaping.
  • 11.5M weighted earners (7.12M after exemption/weeks screens) have usual weekly hours >40 but a reference week ≤40 — regular overtimers whose March week happened to be light, absent, or off. The snapshot lottery drops them entirely while annualizing the hot weeks of 9.2M usual-≤40 workers it did catch.

The fix (deliberate deviation from the exact retired port — adjudication)

derive_flsa_overtime_premium becomes a two-signal estimator over columns already on the frame:

  • Persistent leg (new): usual weekly hours worked last year (weekly_hours_worked_before_lsr ← ASEC HRSWK) above the threshold makes the worker a carrier, with the usual-hours share as the annualizer. A single hot reference week no longer overrides a measured above-threshold usual schedule (measured −$1.4B on the 10.65M double-positive carriers), and a light reference week no longer erases a regular overtime schedule. Year-consistency is channel-scoped: on ASEC-channel rows HRSWK shares the retrospective year with employment_income/weeks_worked (the reference week does not); on PUF-support rows both hours signals are donor-ASEC schedule proxies attached to PUF income — the support design's property, inherited equally by the retired reference-week leg on those same rows. Channel split of the recovered carriers: 3.08M ASEC / 4.04M PUF-support.
  • Snapshot leg (retired convention retained verbatim): usual ≤ threshold keeps the reference-week arithmetic unchanged. It is representative for steady schedules and can under- or over-recover an occasional overtimer's annual premium depending on the sampled week — not an unbiased mass estimator — but it is the only measured signal for that population, and replacing it would require modeled participation rather than measured hours (out of scope by the no-invented-values principle).
  • Populated surfaces converge: the stage's idempotency skip still avoids the semantically unchanged QRF/union/occupation refit, but the premium is now recomputed from the present columns on every entry and refreshed when the stored values came from an earlier construction (a stored NaN always takes the recomputed clean value) — a populated frame can never silently pin the retired semantics. Malformed non-finite inputs read as absent instead of overflowing to silent zeros, at the estimator and the gate alike.
  • Exemption screens, weeks gate, income cap: unchanged. The signal gate's positive_without_overtime invariant now requires both measured signals ≤ threshold, read through the estimator's non-finite-as-absent transform. Stage lineage (source_stages.json) documents which operations remain the exact 9a823603 port (donor build, QRF, union assignment, occupation carries — all of them) and why the premium gate deviates. Known inherited edge documented: both hours measures count all jobs while FLSA §7 applies per employer.

Measured on the certified N frame (final weights):

shipped two-signal
carrier rows 8,748 12,208
weighted persons 19.86M 26.98M
weighted tax units 19.03M 25.73M
premium mass $114.79B $149.53B
mean premium/unit $6,032 $5,812
OBBBA probe (2026 law, same engine) −$16.96B −$22.29B (68% of JCX FY2026)

Every shipped carrier is preserved (the shipped set is a strict subset). Probe measured with the certified-N recipe (store copy + column recompute + the real us_reform_coverage_smoke_gate at 2026 law; shipped store re-scored in the same engine as the control — certified evidence records −$16.86B, the small drift is engine-version, which the same-engine pair isolates away). Build O in-flight cross-check (22bd902 sparse): same 8,748-row shipped surface, −$16.89B probe — the undercount rides into O unchanged; this fix lands at the next release build. Carrier units reach 88.7% of the >29M floor; the named residual is (i) the occasional-overtime universe the one-week snapshot structurally under-counts (unfixable without a week-level donor — SIPP monthly hours is the candidate if it is ever needed), (ii) the claims-side over-inclusion edge, (iii) TY2024-vs-TY2025 growth.

Treasury count-anchor mintability (adjudicated NOT mintable — re-verified, sharper reason)

The prior lane's finding ("floors are not mintable as point facts") re-verified against the schema itself: consumer_fact.v1 has assertion ∈ {observation, source_projection} and a scalar value — no bound semantics. The sharper reason: Treasury never published a point value. sb0517 (June 2026) and the first-year-results release sb0553 both publish only rounded inequalities ("over 29 million filers … average deduction of over $3,100", 75% under $100k). Minting value = 29,000,000 would assert publisher precision the publisher never stated. No IRS SOI TY2025 line item exists yet (filing-season weeklies are volume-only; 26inweek*.xlsx still 404 per #499). The mintable object arrives when SOI publishes the TY2025 qualified-overtime deduction line (exact returns + amount) — an observation at tax_year 2025, aging per the #474 wages-chain path already documented in #499. Until then the floors remain reason-level citations in the coverage manifest (shipped by #499, byte-untouched here).

Not done here (by design)

Named consumer

The OBBBA paper (PolicyEngine/obbba-paper, registered against populace#506 with tracking issue obbba-paper#1) currently computes the FLSA premium by hand from stored hours/wages because no lineage ever shipped it. This stage's stored, Treasury-floor-validated fsla_overtime_premium column — in dense as well as sparse releases — retires that workaround once an evidence-tier dense artifact publishes (#506); the paper's tip-exemption sibling rides #505.

Verification

  • TDD (16 tests in the stage file, all enforced by base CI — the integration tests pin _flsa_policy instead of skipping without the us extra): two-signal arithmetic (recovered carrier, persistent-priority, absent-reference-week, occasional-leg-retained, exemptions, hourly-above-HCE), non-finite-as-absent hardening at both the estimator and the gate, gate accepts usual-leg carriers / rejects both-signals-≤40 and fabricated premiums riding on infinite hours, stage end-to-end through with_us_org_wages_inputs with signal-conflict rows that fail under swapped wiring in either the fresh or the refresh branch, and the stale-populated-surface refresh (QRF poisoned to prove the skip, stale zeros and NaN premiums converge, consistent surfaces pass through unchanged).
  • Full packages/populace-build suite green in this worktree at the pre-rebase base, and green on the rebased head except the test_release_target_parity.py::TestRegeneration class, which fails identically on detached clean origin/main in this venv while main CI is green at the same sha (e56b8ad) — the known local-venv-drift class, arriving with Add JCT tax-expenditure target references: ALD components + CDCC (supersedes #514) #519's new references; this PR's CI is the authoritative run for it.
  • uv run ruff check + ruff format --check clean on the diff.
  • Cross-family sol review (gpt-5.6-sol via delegate, read-only, committed-diff scope): round 1 NOT-MERGE-SAFE (2 blocking + 1 major + 2 minor + 1 nit): populated surfaces silently pinning the retired premium, the overbroad year-consistency claim, the false "mass-preserving in expectation" claim, the hot-week overview sentence, wiring-swap test blindness, non-finite overflow — all addressed in commit 2. Delta round NOT-MERGE-SAFE (3 major + 2 minor): the residual mass claim in the function docstring, NaN-coerced refresh comparison, gate/estimator non-finite mismatch, importorskip leaving the integration tests out of base CI, refresh-branch swap blindness — all addressed in commit 3. Delta-2: all five fixes RESOLVED, no new functional defect; two audit items — the branch had fallen 8 commits behind origin/main (now rebased onto e56b8ad, content unchanged) and the NaN test did not truly pin the fillna regression (a third pass now uses an otherwise-consistent surface with a NaN on a recomputed-zero row, mutation-verified: reintroducing the coercion fails it) — closed in commit 4. Delta-3 final confirmation: MERGE-SAFE — both items RESOLVED (range-diff = on all three replayed commits, byte-identical blobs; the NaN guard verified to fail if the coercion is reintroduced), zero new findings, zero calibration machinery on the exact origin/main..HEAD diff.

Part of populace#451 (item 4 overtime-incidence lane; claim + receipts on the thread).

🤖 Generated with Claude Code

…ce-week snapshot

The retired ORG/FLSA port derived fsla_overtime_premium from the ASEC
reference week alone (A_HRS1 > 40), annualizing one survey week's premium
share over the retrospective income year. Measured on certified Build N,
that construction collapses incidence to a single week's draw: 19.9M
weighted carrier persons (19.0M tax units) against Treasury's published
">29 million" TY2025 No-Tax-on-Overtime claimant floor, with a 65M-person
weighted heap sitting exactly at 40 hours, and the reference week not even
inside the income year the premium is attributed to.

The estimator now adds the income-year-consistent persistent signal: when
usual weekly hours worked last year (HRSWK) exceed the threshold, the
worker carries and the usual-hours share is the annualizer; usual hours at
or below the threshold retain the retired reference-week snapshot leg
unchanged. Exemption screens are untouched, the signal gate's
positive_without_overtime invariant now requires both measured signals at
or below the threshold, and the stage lineage documents the deliberate
deviation from the exact retired port with its adjudication.

Measured on the certified Build N frame: 12,208 carrier rows / 26.98M
weighted persons / 25.73M weighted tax units / $149.5B premium mass
(from 8,748 / 19.86M / 19.03M / $114.8B), with every shipped carrier
preserved.

Part of the populace#451 item 4 overtime-incidence lane.
…ed claims, hardening

Blocking 1: a frame whose ORG surface is already populated skipped the whole
stage, so a stale premium from the retired construction could silently
survive re-entry; the idempotency skip now covers only the semantically
unchanged QRF/union/occupation family while the premium is recomputed from
the present columns and refreshed on disagreement (poisoned-QRF test proves
the skip, consistent surfaces pass through unchanged).

Blocking 2 / major 3 / minor 4: the income-year-consistency claim is now
channel-scoped (ASEC rows exact; PUF-support rows carry donor-ASEC hours
schedules onto PUF income — the support design's property, shared by the
retired reference-week leg; recovered carriers split 3.08M ASEC / 4.04M
PUF-support on certified N), the false "mass-preserving in expectation"
statement is replaced with the honest bias statement for the snapshot leg,
and the module overview no longer claims hot reference weeks stopped
annualizing for usual-sub-threshold workers (that retained leg is stated as
such).

Minor 5: the end-to-end test adds a signal-conflict row (usual 45, reference
60) that fails under swapped caller wiring. Nit 6: non-finite hours/income/
weeks inputs read as absent instead of overflowing the straight-time
denominator into silent zeros.
…ent, CI-runnable integration tests

The function docstring's residual "preserves aggregate mass in expectation"
claim about the retired construction is corrected to the honest mass-proxy
statement. The populated-surface refresh no longer coerces a stored NaN to
zero before comparison, so a NaN-carrying premium column always takes the
recomputed clean values instead of surviving as a nonfinite gate failure.
The signal gate's structural checks now read the four input signals through
the same non-finite-as-absent transform as the estimator (_finite_nonnegative
hoisted to module level), so a fabricated premium riding on an infinite
hours signal trips positive_without_overtime instead of slipping past it;
the premium column itself stays raw so nonfinite outputs remain counted.
Both stage integration tests monkeypatch _flsa_policy instead of skipping
when policyengine-us is absent, so the always-run base CI enforces them, and
the refresh test adds conflicting-signal rows (usual 45 / reference 60) that
would surface a refresh-branch hours swap, plus a NaN-premium row proving
convergence.
…refresh regression guard

The branch is rebased onto origin/main e56b8ad (three commits replayed
cleanly; the audited three-file diff content is unchanged) so the combined
post-main state is what CI and the suite certify. The populated-surface
refresh test gains a third pass on an otherwise-consistent surface whose
only difference is a stored NaN on a recomputed-zero row — the exact
scenario a fillna(0) comparison would silently preserve. Mutation-verified:
reintroducing the coercion fails the test, the shipped code passes it.
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

CI green on the exact head (test + wheels, 3.13/3.14) and mergeable: MERGEABLE — including the TestRegeneration class that fails locally post-#519 (main CI green at e56b8ad; adjudicated as local-env drift in the PR body, now confirmed by this branch's CI). Sol cross-family trail closed at delta-3 MERGE-SAFE. Ready for owner-session merge per the lane contract (#451 receipts comment has the full decomposition). — overtime-incidence lane

@MaxGhenis
MaxGhenis merged commit 0970a59 into main Jul 24, 2026
4 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Owner gate: my review + sol cross-family confirm — items 1–5 pass (statute-faithful two-signal incidence with the port-deviation adjudication note, measured before/after receipts, base-stage-only scope, cache pin fail-closed, coherent tests); sol's single REQUEST CHANGES was the effect-timing wording, corrected in the body (base-stage change ⇒ lands at Build P's base rebuild, not on base-O releases). Merged.

MaxGhenis added a commit that referenced this pull request Jul 25, 2026
…rt-year workers (#539)

* Concept-align the ORG QRF income feature: full-year equivalent for part-year workers

The donor's employment_income is the annualized reference week (pternwa x
52) while recipients fed actual annual income, so part-year workers matched
low-wage full-year donors: 61.5% of weeks<50 earners landed below $16.80/hr
with band p10 $2.13 and 32% of band mass below the federal minimum on
certified N, against 19.4% below the line in the donor itself. Recipients
now feed income x 52/weeks (untouched when weeks are zero or missing), the
premium derivation keeps actual annual income, and the stage lineage
documents the deliberate deviation. Fixes #529.

* Address sol round-1 findings on the stacked diff: full re-imputation on populated surfaces, masked divide, lineage disclosure

HIGH: the populated-surface skip could pin stale QRF outputs now that the
income feature's semantics changed — the stage re-imputes the whole family
on every entry and passes an identical surface through unchanged (seeded
QRF + deterministic lottery + pure derives make same-code re-entry
byte-stable), superseding the premium-only refresh design from the #526
base; regression test proves stale sub-minimum wages and inverted hourly
status converge, and the idempotent pass now also pins the hash-lottery
union column. MEDIUM: the full-year-equivalent factor uses a masked divide
so zero/missing weeks never touch the division (strict-errstate pinned in
the feature test). LOW x2: the structured QRF operation declares the
weeks_worked dependency, and the lineage notes disclose both the
within-quota union reshuffle under the scaled hash and the re-imputation
entry semantics.

* Address sol delta findings: strict-boolean convergence guard, composition-binding tests, fast-path identity

MEDIUM: a boolean output carrying np.nan cast to a truthy True inside
_outputs_match (and nullable pd.NA raised), so a damaged column could
survive the pass-through or crash it — booleans now compare through strict
0/1 numerics where NaN, pd.NA, and non-canonical values all take the
rebuild path; regression test covers both damage classes and pins the
healed dtype. LOW: the populated-surface tests now bind the #529 scaling
composition (a feature-sensitive fake QRF emits $12.50/hr for the part-year
probe if the full-year-equivalent scaling is reverted), assert the planted
all-True union column is re-imposed to quotas and a poisoned occupation
carry re-derives from POCCU2, and the idempotent pass asserts the SAME
frame object returns (the fast path itself, not merely equal values).

* Address sol delta-2 findings: dtype-gated convergence guard, full-surface convergence test

MEDIUM: coercible numeric strings ("0"/"1") passed the strict 0/1 membership
and could identity-match while preserving a damaged str dtype on the fast
path — _outputs_match now rejects object and string dtypes outright for
every output before any coercion (regression: an int-then-str
is_paid_hourly column rebuilds and heals to bool). Partial finding: the
weak not-all-True union assertion is replaced by full-surface convergence —
the poisoned populated frame must reproduce a from-scratch clean build
column-for-column across all twelve outputs, which binds the recomputed
union mask exactly, alongside the retained part-year composition pin.

* Address sol delta-3 findings: dtype-family allowlist, nonconstant union plant

MEDIUM: HDF-storable temporal dtypes (datetime64 at 0/1 ns) coerced through
the numeric comparison and could identity-match while preserving the
damaged dtype — the guard now allows only the boolean/integer/float dtype
families (the only representations the cached Build N/O stores carry) and
rebuilds everything else; datetime regression added. MEDIUM: the planted
all-True union column was constant, so _surface_has_signal bypassed the
populated-surface comparison the convergence test exists to bind — the
plant is now a wrong-but-nonconstant pattern, keeping the full
twelve-column comparison on the populated path where a dropped union
comparison would fail.

* Close sol delta-4 LOW: bind the union comparison specifically

Tests-only. A union-only damaged surface (inverted, nonconstant, every
other column already matching) must converge back — dropping the union
column from the convergence guard would identity-pass it unchanged, which
the full-surface test could not catch because it exits on earlier poisoned
columns.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant