Repository navigation
Derive raw-PUF partnership self-employment earnings with the archived formula - #1209
Merged
Merged
Conversation
The raw-column fallback in puf_support._person_source_values returned E25960 + E26180 for partnership_self_employment_net_earnings: the partnership loss leg plus the S corporation loss leg, the same two columns the function subtracts a few lines above to build partnership_income and s_corp_income. Port the archived processed-PUF derivation instead (policyengine-us-data 42ed5d45, datasets/puf/puf.py lines 723-746): (E30400 + E30500) / 0.9235 - (E00900 + E02100) where E25940 + E25980 - E25920 - E25960 is nonzero, else zero. All eight columns are required, so a raw PUF carrying only some of them derives nothing and the donor build fails closed. The certified default is unaffected: its pinned processed_puf carries partnership_se_income and no raw E-columns, so it takes the alias branch. Spec-engine pins that attest puf_support.py's bytes follow in the next commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
puf_support.py is on _DIRECT_KERNEL_MODULES, so the previous commit's byte change moves the seed-protocol and seed-map digests, the US spec_sha256 and the coverage evidence. Recomputed from the tree: - EXPECTED_HASHES seed_protocol 114217a2... -> e7ed105b... - EXPECTED_HASHES seed_map b4d6ec9c... -> 533ef661... - US spec_sha256 f76f921d... -> fa609914... (pool-tool test, coverage JSON) - docs/evidence/spec-engine/us-f0-coverage.json regenerated with tools/spec_engine_coverage.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ip-se-fallback # Conflicts: # docs/evidence/spec-engine/us-f0-coverage.json # packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py # packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py
Main's #1186 also edited puf_support.py and re-pinned, so the merge took main's pins and this commit recomputes them for the combined bytes: - EXPECTED_HASHES seed_protocol 37da8f68... -> 027e9471... - EXPECTED_HASHES seed_map 7d03cc07... -> 976dc97b... - US spec_sha256 fbf25dba... -> 2bd6fc62... (pool-tool test, coverage JSON) - docs/evidence/spec-engine/us-f0-coverage.json regenerated; tools/spec_engine_coverage.py --check exits 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The golden spec_sha256 in test_spec_engine_loader.py attests the direct kernel modules too (main's #1178 moved it when it edited puf_support.py). 32305247... -> a7e42313..., the value the test observes on this head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ip-se-fallback # Conflicts: # docs/evidence/spec-engine/us-f0-coverage.json # packages/microcosm-build/src/microcosm/build/spec_engine/inventory_coverage.py # packages/microcosm-build/tests/engine_free/shared/test_spec_engine_loader.py # packages/microcosm-build/tests/engine_workflow/us/test_us_multispine_pool_tool.py
test_no_incumbent_data_package_references_in_live_tree forbids the retired data package's name outside its allowlist; cite it as the retired enhanced-CPS repository at 42ed5d45, as the other ports do. Also state that _numeric_array, not the archived fillna(0), turns a nonnumeric value into zero (review round 1, P3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The merge took main's pins; this recomputes them for this PR's puf_support.py bytes on the merged tree: - EXPECTED_HASHES seed_protocol 8d028354... -> 0e4c8a4a... - EXPECTED_HASHES seed_map bdd33986... -> 41a64b88... - US spec_sha256 638cd60e... -> 3080fe93... (pool-tool test, coverage JSON) - minimal-loader golden aadf7c8c... -> 0c0c8eea... - coverage JSON regenerated; spec_engine_coverage.py --check and generate_us_bundle_from_constants.py --check exit 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as ready for review
October 12, 2026 23:19
Contributor
Author
|
Merged at reviewed head Gates at merge time:
|
MaxGhenis
added a commit
that referenced
this pull request
Oct 13, 2026
Keeps #1209's archived Schedule SE derivation for partnership_self_employment_net_earnings beside this branch's line-32 raw derivation, and re-pins the identities the combined puf_support bytes and source manifest move: seed protocol/map, US spec_sha256 98ab131c..., the minimal-loader golden, and the regenerated coverage evidence (tools/spec_engine_coverage.py --check: 42229/42229, 41/41). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
puf_support._person_source_valuesresolves each requested donor output from the PUF arrays. Forpartnership_self_employment_net_earningsits last resort was a raw-column fallback that returnedE25960 + E26180.A few lines above, the same function builds
partnership_income = E25980 - E25960ands_corp_income = E26190 - E26180. SoE25960andE26180are the partnership and S corporation loss legs, and the fallback defined partnership self-employment net earnings as partnership losses plus S corporation losses. That is not the engine's variable (policyengine-us 2.2.1 documents it as "partnership net earnings allocated to self-employment tax and earned-income calculations, generally from Schedule K-1 Box 14"), and it let an S corporation amount into a self-employment column.The fallback arrived in ddb7d81 (#182, 2026-06-26).
Which branch production reaches
Production does not reach the fallback, so this PR changes no production value.
load_puf_tax_unit_donor(us_runtime/puf_donor_io.py, used bytools/build_us_multispine_pool.py) and_puf_tax_unit_donor_from_h5intools/build_us_puf_support_base.py. Both pass every root dataset of one processed PUF H5 topuf_tax_unit_donor_from_arrays.processed_pufsource pinned inus/spec/sources.yaml(sha2567669f5b5…d6df, 316,939,164 bytes).tools/route_a/route_a.shanddocs/us-modal-stage-route-a-base-plan.jsonname the same hash.partnership_se_incomeandpartnership_s_corp_income. It does not havepartnership_self_employment_net_earnings,partnership_incomeors_corp_income.partnership_se_incomealias branch (puf_support.py, the branch just above the raw-column ones). The column is both-signed in that file (6.4% of rows positive, 3.6% negative), which a sum of two loss legs could not be.partnership_se_income; the conclusion is the same.Before this PR, one caller reached
E25960 + E26180: the testtest_puf_tax_unit_donor_derives_partnership_and_s_corp_split_from_raw_fields, which asserted the loss sum.The fix
Port the archived derivation, and fail closed when a raw PUF lacks any input.
The archived pipeline (PolicyEngine/policyengine-us-data at
42ed5d45,datasets/puf/puf.pylines 723-746) computes:It matches
part_sein Yale Budget Lab Tax-Data'ssrc/process_puf.R(lines 279-281 at2f55fa97). The archived pipeline has used this formula for the column since policyengine-us-data#485 (2026-01-26), then under the namepartnership_se_income.I ported it and did not remove the fallback because every other raw-column fallback in the function reproduces the archived derivation of its leaf:
partnership_income,s_corp_income, theE17500medical split,qualified_tuition_expensesand theE02400Social Security carry. This one was the exception.All eight columns are required. With any absent,
_person_source_valuesreturnsNoneandpuf_tax_unit_donor_from_arraysraisesPUF donor cannot derive requested output(s), as it does for any other underivable output. A raw PUF carrying onlyE25960andE26180now raises.The column meanings in the new docstring are the archived pipeline's own comments. I did not check them against the PUF documentation, and the docstring says so.
Invariants
Stated in
test_us_puf_partnership_se_derivation.pyand checked with Hypothesis (200 examples each):(result + E00900 + E02100) × 0.9235 = E30400 + E30500.Two behaviours follow from porting the archive faithfully and are intended:
Example tests cover hand arithmetic for six records, missing values, the source precedence (stored leaf, then
partnership_se_income, then raw columns), the donor-builder seam, and a refusal for each of the eight columns removed in turn.Do the tests catch wrong formulas?
An in-memory mutation check (
mutation_check.py, not committed) swapped the helper for 13 wrong versions and ran every test in the new file against each:E25960 + E26180Every mutant was caught, and the unmutated helper passed all tests.
Pins
puf_support.pyis on_DIRECT_KERNEL_MODULESinspec_engine/seeds.py, so its bytes are attested. Main moved these pins twice while this PR was open, once in #1186, which also edited this module. So the branch merges main taking main's pins, and the last commit recomputes them for this PR's bytes on the merged tree (main at977ac983a):EXPECTED_HASHES["seed_protocol"]8d028354…0e4c8a4a…EXPECTED_HASHES["seed_map"]bdd33986…41a64b88…spec_sha256(engine_workflow/us/test_us_multispine_pool_tool.py, coverage JSON)638cd60e…3080fe93…test_spec_engine_loader.py)aadf7c8c…0c0c8eea…docs/evidence/spec-engine/us-f0-coverage.jsonwas regenerated withtools/spec_engine_coverage.py. Afterwardstools/spec_engine_coverage.py --checkandtools/generate_us_bundle_from_constants.py --checkboth exit 0.Nothing else names the old digests. The module defines no graph kernel class, and no graph parity fixture refers to it. No schema or
source_stages.jsonchanged, so the frozen manifest hash stays put.Tests run locally
On head
7556a00cf, US-engine venv,pytest -n 4: 341 passed, 0 failed. The run covered:test_us_puf_partnership_se_derivation.py(new),test_us_puf_support.py,test_us_qbi_inputs.py,test_us_puf_donor_io.py;test_us_multispine_pool_tool.pyfiles;test_spec_engine_inventory_coverage.py,test_spec_engine_coverage_tool.py,test_spec_engine_loader.py;test_us_plan.py::TestUsSources::test_no_incumbent_data_package_references_in_live_tree.That last guard failed CI on an earlier head because the new docstring named the retired data package. The code now cites it as "the retired enhanced-CPS repository at 42ed5d45", as the other ports do.
ruff checkandruff format --checkon the touched files are clean, andpython3 tools/ci_test_plan.py verifypasses.Review
GPT-6.1 Sol reviewed the PR (Subfleet, review/hard) and returned APPROVE with one P3: the docstring credited the nonnumeric-to-zero coercion to the archive's
fillna(0), but_numeric_arraydoes it. The docstring now says so.The reviewer also confirmed:
A round-2 delta review on head
7556a00cf(GPT-6.1 Sol) returned APPROVE with no findings. It covered the P3 fix, the retired-package wording, the merge with main at977ac983a, and the re-pins. It confirmed:puf_support.pybytes restores main's value for each._preserve_cps_reported_social_securityis byte-identical to main, and this PR's derivation is unchanged since round 1.Both review outputs are kept outside the repository, at
~/reviews/microcosm-raw-puf-partnership-se-2026-10-11/.Notes
EXPECTED_HASHESentries and coverage JSON. Whichever lands second re-pins on the merged tree.🤖 Generated with Claude Code