Skip to content

Chesterton's-fence audit: wire NIPA wages/proprietors, net worth, LIHEAP; fence every exclusion#405

Merged
MaxGhenis merged 1 commit into
mainfrom
target-parity-nipa-wages
Jul 13, 2026
Merged

Chesterton's-fence audit: wire NIPA wages/proprietors, net worth, LIHEAP; fence every exclusion#405
MaxGhenis merged 1 commit into
mainfrom
target-parity-nipa-wages

Conversation

@MaxGhenis

Copy link
Copy Markdown
Contributor

Chesterton's-fence audit of the target-parity contract

Follow-up to #404. Max flagged that macro_control_total was over-broad: us-data deliberately targeted NIPA totals to capture wages that never reach tax returns (filed-return / CPS wages cover ~$4T; NIPA wages are the ~$12.4T economy-wide universe including nonfilers). The rule is absolute: us-data-targeted ⇒ compiled, unless source-absent. A category label is no longer a sufficient reason to drop a target — every reviewed exclusion now carries a fence {origin, purpose, verdict_basis} recovered by git/PR archaeology on the archived policyengine-us-data repo, and the regenerator refuses a fenceless exclusion. Where archaeology is inconclusive, the fence is rebuilt (wired), not removed.

The authoritative us-data target surface is the eCPS loss matrix (utils/loss.py) + db/etl_national_targets.py, read from the GitHub archive.

Wired — reviewed_exclusion → compiled (following us-data's exact concept mapping)

family engine counterpart origin purpose (verbatim)
bea_nipa.total_wages_salaries (red line) employment_income_before_lsr national, $12,387,929,000,000 exact PR #994 "add BEA/NIPA all-population macro targets for wages … nonfiler income"; local fit showed microdata wages $4.06T vs the $12.388T target
bea_nipa.proprietors_income self_employment_income_before_lsr + sstb_… + farm_operations_income + partnership_s_corp_income national PR #994 "Proprietors' income … all persons, including nonfilers"
federal_reserve_z1.households_nonprofits_balance_sheet net_worth national PR #282 no prose rationale in-thread → wire-by-default; linear direct-sum pins the post-reweight wealth aggregate the input-stage SCF imputation does not
hhs_acf_liheap.national_profile indicator sum of spm_unit_energy_subsidy (recipient households) PR #688 "we could not calibrate LIHEAP recipient counts … despite having CPS/SPM baseline LIHEAP receipt" — the SNAP-caseload pattern

bea_nipa.total_wages_salaries joins ssa_supplement.ssi_recipients in the gate's red-line set: silent loss of economy-wide wage targeting is the exact failure this audit exists to catch. Net-worth and proprietors carry a documented period-aging caveat (the feed's cy2023 fact is aged to 2024; a cy2024 fact would replace the estimate).

The classified fence table — us-data targets populace does not compile

family classification origin verdict + basis
bea_nipa.personal_interest_income / personal_dividend_income macro_control_total PR #994 (added) → #1059 (removed) us-data itself declined: "BEA personal interest/dividends include imputed interest, pension-plan dividends, and trust flows, so those macro totals should not directly calibrate tax/CPS interest and dividend variables" (loss.py:67-70). Calibrated from SOI/CBO (compiled).
bea_regional.state_wages_salaries deferred PR #1034 deferred: the feed carries raw place-of-work SAINC4 line-50 wages (DC = $96.8B, far above residence wages); us-data residence-adjusts (line 42 apportioned) + scales to the national total in bea_regional.py, not reproducible from the feed. National wage aggregate is compiled.
cms_nhe.medicaid_title_xix_expenditures non_linear PR #292 architecture-retires: PE-US PR #1138 made medicaid cost a person_weight-dependent SLCSP allocation → not a linear row; populace keeps it calibration_role=validation_only.
irs_soi.traditional_ira_contributions, roth_ira_contributions, form_w2_401k_elective_deferrals, form_w2_designated_roth_401k_contributions input_side PR #496 / #554 → #1125 architecture-retires: us-data #1125 and populace both govern retirement contributions as imputed pre-limit input columns (*_contributions_desired, POST_REFERENCE_ECPS_REQUIRED_INPUTS), with PE-US applying statutory limits — calibrating here would double-govern. The feed carries the amounts, so this is not a source gap.
irs_soi.form_w2_social_security_tips not_modeled PR #220 (fixes #215) deferred: "'No Tax on Tips' requires a clean tip_income field … tipped workers skew lower-income" — but PE-US yields a structural zero for tip_income in the base microdata until the tip source stage is ported; the target is unsatisfiable, not silently dropped.
bls.consumer_expenditure, wic.national_summary, hud.housing_assistance source_absent loss.py BLS_CE_TOTALS / etl WIC / etl_housing_assistance source-absent: no BLS/WIC/HUD fact in the pinned feed.

Every other BEA/KFF/census-projection/SNAP-persons/TANF-caseload/SOI-CD family carries a "not a us-data calibration target" fence — verified absent from loss.py and etl_national_targets.py by archaeology (the only BEA direct-sum targets were wages + proprietors, PR #994; the programs some NIPA series measure are calibrated from SSA/CMS/CBO admin sources, compiled).

Schema + mechanics

  • TargetFence(origin, purpose, verdict_basis) — required on every reviewed exclusion; TargetFamily rejects a fenceless exclusion; the loader parses it and the anti-rot enforces it.
  • The wirings reuse the existing dispatch/materializer machinery: _bea_reference_from_fact (source-specific dispatch, like ssa/census_pep), a DIRECT_LEDGER_TARGETS entry for net worth, an INDICATOR_LEDGER_TARGETS entry for LIHEAP (the snap_households pattern), and CBO-income-source aging roles for the cy2023 NIPA levels.
  • Registry 5,689 → 5,693 specs; manifest 25 → 29 compiled, 55 → 51 reviewed exclusions; deterministic; Ruff clean.

Testing

Wiring tests per family (NIPA wages exact-value + proprietors expression + other-BEA-not-compiled + state-wages-deferred + net-worth + LIHEAP indicator), fence-schema tests (fence required, three-field validation, every shipped exclusion fenced, deferred state-wages fence names PR #1034), the red-line generalization, and the guarded regeneration test proving the committed artifacts reproduce from the pinned feed. Full contract + fiscal-targets + builder suites green.

Please do not merge — conductor reviews. Gates Build M alongside #404.

🤖 Generated with Claude Code

…EAP; fence every exclusion

Applies the rule us-data-targeted => compiled (unless source-absent) to every
target the retired us-data/eCPS pipeline calibrated to, recovered by PR
archaeology on the archived policyengine-us-data repo.

Wired (were reviewed exclusions, now compiled), each following us-data's exact
concept mapping:
- bea_nipa.total_wages_salaries -> employment_income_before_lsr, national
  ($12,387,929,000,000, exact). BEA NIPA all-population wages incl. nonfilers
  (loss.py BEA_NIPA_DIRECT_SUM_TARGETS, PR #994) — the ~$12.4T universe that
  filed-return / CPS wages undercount by two-thirds. Added to the gate red line.
- bea_nipa.proprietors_income -> self_employment_income_before_lsr +
  sstb_self_employment_income_before_lsr + farm_operations_income +
  partnership_s_corp_income, national (PR #994).
- federal_reserve_z1 net worth -> net_worth, national (PR #282; linear direct
  sum pinning the post-reweight wealth aggregate).
- hhs_acf_liheap.national_profile -> indicator sum of spm_unit_energy_subsidy
  (LIHEAP recipient households, PR #688) — the SNAP-caseload pattern.

Fence schema (cannot-rot): every reviewed exclusion now carries a
{origin, purpose, verdict_basis} recovering why the target existed and the
purpose-informed basis for the exclusion; the regenerator refuses a fenceless
exclusion. Bare category labels are no longer sufficient. Verdicts recorded:
- bea interest/dividends: us-data itself declined (PR #994 added -> #1059
  removed): imputed interest/pension-plan dividends/trust flows, not a close
  microdata concept.
- bea_regional state wages: deferred (PR #1034) — the feed's raw place-of-work
  SAINC4 line-50 facts can't reproduce us-data's residence adjustment + national
  scaling; the national wage aggregate is compiled.
- cms_nhe medicaid spending: architecture-retires (PR #292 -> PE-US #1138 made
  cost person_weight-dependent; validation_only).
- retirement contributions: architecture-retires (PR #496/#554 -> #1125:
  governed as imputed input columns, not reweighting targets).
- tip_income: deferred (PR #220) — structural zero until the tip source stage
  is ported.
- the remaining BEA/KFF/census-projection/SNAP-persons/TANF-caseload/SOI-CD
  families carry a "not a us-data target" fence (verified absent from loss.py +
  etl_national_targets.py).

Registry 5,689 -> 5,693 specs; manifest 25 -> 29 compiled, 55 -> 51 reviewed
exclusions. Deterministic, Ruff clean. Wiring tests per family + the fence
schema tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MaxGhenis MaxGhenis merged commit dc70318 into main Jul 13, 2026
4 checks passed
MaxGhenis added a commit that referenced this pull request Jul 14, 2026
…zer guard (#429)

Build M's sparse run stopped at target materialization: the #405 NIPA
and LIHEAP targets carry fact metadata identifying which published
series the registry selected (ledger_filter_bea_nipa.series_code,
ledger_filter_administering_entity, ledger_filter_program). The guard
rightly refuses ledger_filter_* keys it cannot apply, but these are
identity qualifiers applied at registry fact-selection — there is no
household-level series code to filter on — so a reviewed
IDENTITY_LEDGER_FILTER_METADATA_KEYS class now passes them as inert
provenance. Unknown ledger_filter_* keys remain fatal, so a genuine
domain filter can never be silently ignored.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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