Repository navigation
Conversation
The #982 income-rank predictor sends the top-ranked survey tax units, each standing for several hundred units, onto the PUF's top-ranked returns, which stand for one return or less (the synthetic Forbes-tail records weigh about 0.13). One draw put $141B of line-32 mass on a weight-644 unit in the #1251 rebuild. Weight-aware leaf draws (#481) cannot fix this: the slice such a donor belongs to is smaller than one recipient. QRF finalization now caps each raw amount draw at the positive mass per unit of slice weight of the donor's top slice of the recipient's own weight share, and floors losses from the bottom slice, on every amount output. The rule is bound into the primary PUF execution config (schema 6), and each bounded output writes a tail-bound diagnostics record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Snapped (sparse) outputs are bounded on their snap-grid donor values. A slice inside one grid value now caps at that value exactly; computing on unrounded values clipped every draw at an aged statutory maximum to the grid value below (1,163 qualified-tuition rows per seed in the sweep). - Every test that finalizes amount outputs passes a tail-bound diagnostics sink, now required because the recipient-share bound is always active. - Regenerated imputation.yaml (primary execution config schema 6), field usage counts and claim digest, inventory digests (seed protocol and map, producer registry, resource semantics, full checkpoint identity), the pointer inventory digest, coverage evidence, the pool-tool spec sha and the loader golden vector. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ests - Stacked publication and the pool loader required execution-config schema 5 while the builder wrote 6, so no current stacked pool could publish or load. All four sites now read PRIMARY_PUF_EXECUTION_CONFIG_SCHEMA_VERSION. - The comment and docstrings now call the bound an interim censor that limits a record to its slice (not a fix for concentration the slice has), name the root fixes (#958/#964, #481), and record the loosened links across columns, the rung dependence and the Social Security re-split. - Slices use positive-weight donors only; non-finite bounded draws are refused before any write; quantile records carry a rule discriminator. - Tests: zero weights on both sides; an LP optimality check replaces the tautological mass test; production-geometry differential test; tax-unit outputs, Social Security total, and per-leg calibration factors through finalization; the identity is pinned to a literal. - Re-pinned the seed protocol and map, coverage evidence, pool-tool spec sha and loader golden. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- test_us_spec_bundle asserted execution-config schema 5; it now reads the shared constant. The operator-ordering doc and a pass-through fixture said 5 too. - Share-bound diagnostics records carry the recipient and donor weight totals, so rungs can be compared. - Tests: the non-finite check is shown to stop before the quantile cap's write; the LP oracle is scaled to a unit objective so solver tolerance cannot flake; a restated assertion is removed; the base-builder fake record carries the rule field. - Changelog: interim label; schema-5 stacked pools are no longer loadable. - Re-pinned the seed protocol and map, coverage evidence, pool-tool spec sha and loader golden. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub's runner queue for the repository was stalled, so the engine-free and engine-us suites were run on Modal against this branch. They found: - For a snapped output the cap was lowered to the largest grid value within it, which could be zero: a carrier whose slice mass sits below the smallest positive donor value was erased. The cap is now lowered onto the positive grid only, so the bound moves no draw to zero; how many records carry a sparse output stays the donor-rate sparsification's job. - Two tests pinned the old field counts as literals. - Non-production stacked passes that ask for no diagnostics now hand finalization a discarded sink; production still requires one. - Four tests that isolate another mechanism on two- to twenty-unit frames (snapping control column, educator sparsification, farm signed-mass calibration, Social Security preservation) narrow the bound explicitly, through a new test-only passthrough on impute_us_puf_tax_detail_support. - Share-bound diagnostics records carry the recipient count, which is what differs between sample rungs. - Re-pinned the regenerated bundle and every digest derived from it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ew r4) A snapped output is bounded by the larger of its slice cap and its smallest positive donor value, so the bound never erases a carrier. The module comment promised the slice-mass bound without that exception. Comment only; re-pinned the seed protocol and map, coverage evidence, pool-tool spec sha and loader golden, which attest puf_support.py's bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Follow-up to #1239 / #1251. One PUF-channel QRF draw can carry a large share of an amount column: in the #1251 rebuild a single $218.9M line-32 draw on a weight-644.7 tax unit put $141B into the frame. This PR bounds every raw amount draw by the mass of the population slice its recipient stands for.
It is an interim censor at the finalize seam, like the existing
non_sch_d_capital_gainsquantile cap. It limits each record to its slice; it does not remove concentration the slice itself has. The root fix is a tail stratum that carries PUF donors at their own weights (#958, #964); weight-aware draws (#481) complement it.Not for merge by the author. It changes what the next US build carries, so the merge is queued for Max as d1504 (see "Decision").
Why one draw can dominate
Read in code at
ed199a624, and reproduced bit for bit on Modal (below).puf_predictor_income_rank_share(US PUF imputation predicts each income item from the recipient's own survey value, so the PUF clone half reproduces ASEC income #982), each unit's weighted mid-rank within its own population. A top-ranked ASEC tax unit (initial weight about 600 of 89.8M PUF-arm units) lands among the PUF's top ~1,000 returns.Weight-aware leaf draws (#481) do not fix this. They make a donor's draw probability track its weight, which fixes the inclusion lottery but not the granularity: the slice such a donor belongs to is smaller than one recipient, so whichever donor is drawn, one record carries it. DESIGN.md already states the rule this breaks: "tail support below pool resolution is the pool's job (strata), never the fit's." The proper home for that mass is a tail stratum carrying PUF donors at their own weights (#958 increment 2, draft #964).
Nor does the release's tail gate catch it. It tests the top 100 records' share (≤ 0.75); #1251's line 32 passes at 0.399.
How often, and how much (Modal seed sweep)
The primary chain was rerun in full for seeds 0–11 on main (
ed199a624) and on #1251 (45a5b9891), on the Route A base inputs. Seed 0 reproduces both production bases exactly: line-32 net $306.8912B (certified control) and $455.3234B (#1251 treatment), with the same weight-644.7 unit drawing $218.9M from a synthetic donor of weight 0.13. Figures are raw tax-unit draws at initial weights, before finalization's other steps.partnership_income, mainThe arrow is this PR's bound applied to the same draws. Across all ~50 columns it moves about 22 to 23 tax-unit cells per seed (22.7 on main, 22.2 on #1251, of ~11M), at most 3 in any one column. Column means move by the mass the clipped draws carried, for example line 32 on #1251 from $427.6B to $417.2B on average (donor-implied $376.8B), and qualified dividends from $220.8B to $205.9B (donor-implied $165.5B). Every column is in
out/aggregate_main.mdandout/aggregate_l32.mdin the evidence folder.What it does not fix.
The bound
At the existing tail-bound seam in
finalize_us_puf_tax_detail_predictions, after thenon_sch_d_capital_gainsq0.999 cap, every amount output's raw tax-unit draw is clipped to[floor_r, cap_r]. For a recipient whose household design weight is the shares_rof all PUF recipients, take the donor slice holding the same share of donor weight at each end of the column (fractional at the edge):cap_ris the top slice's positive mass per unit of slice weight. Within the positive donors this is the slice's weighted mean, and it falls as the share grows.floor_ris the same for losses, from the bottom slice.So
w_r × value ≤ (W_r / W_d) × positive mass of the top s_r slice: no record carries more mass than the most extreme slice of the population it could stand for. The rule has no tuning constant. Snapped outputs have one exception, described below: their bound ismax(cap_r, the smallest positive donor value).Alternatives, evaluated on the same draws (all columns; main;
out/rule_comparison.md):Choosing slice mass over the boundary is a methodology call and is part of the decision queued for Max.
Invariants
Property tests use Hypothesis (300 examples for the helper, 60 through finalization) in
tests/engine_free/us/test_us_puf_recipient_share_bound.py.floor_r ≤ v'_r ≤ cap_rfor every bounded output and recipient. For a snapped output the upper bound ismax(cap_r, the smallest positive grid value), so a carrier is never erased.sign(v') = sign(v)and|v'| ≤ |v|.capis non-increasing andfloornon-decreasing in the share. Each side applies to every recipient or to none.cap≤ the donor maximum, exactly. A slice made only of tied donors caps at their value exactly.cap × slice weightequals the most positive mass any fractional donor subpopulation of that weight can hold. This is checked against a linear program (scipy.optimize.linprog), independently of the slice construction, and the same for the floor.rulefield.Three documented exceptions. These later steps move bounded values without adding mass:
The first two lift every kept value of the column or leg by one common factor; the third keeps each unit's total. All three are tested.
Known limits.
Binding and pins
imputation.schema.jsonall change.tail_bound_diagnostics=[]arguments).recipient_share_bound_outputsand say why: the quantile-map control, the snapping test's passthrough control column, educator sparsification, the farm signed-mass calibration, and Social Security preservation.impute_us_puf_tax_detail_supportgains that test-only passthrough.imputation.yamlis regenerated (generate_us_bundle_from_constants.py); the USspec_sha256is nowfb7990d6….puf_support.py), producer registry, late resource semantics, full checkpoint identity.tools/spec_engine_coverage.py --checkreports 42,194/42,194 fields and 41/41 checks.Interaction with #1251
The passive leaf is an amount output, so it is bounded automatically once #1251 lands; nothing names it. In the #1251 sweep its largest single draw falls from 16.0% to 7.9% of the column. The same holds for
s_corp_incomeonce the entity split (#1261, stacked on #1251) gives it values. All three PRs move the spec and inventory pins; whichever merges later re-derives them.Frame and engine results
PolicyEngine-US 2.2.1 ran on three bases on Modal, loaded the way microcosm's reform validation loads a release. These are fixed-weight comparisons; no release was re-calibrated.
line32-1239-base-d02fb2bca843).puf_support.pychange. It is on evidence branchus-puf-tail-draw-route-a-evidence(98c832946, not for merge), runtail-bound-base-98c832946(8,420 s). The branch predates this PR's later edits (positive-weight donors only, the finite check, and the never-zero rule for snapped outputs). None of them changes values on these inputs: every donor and recipient weight is positive (donors ≥ 0.12, recipients 19 to 2,313), and the four snapped-output cells the build moved all stayed positive.The three bases share every tax-unit and household id, so the certified Route A final weights apply to all three. The harness reproduces #1251's published deltas exactly.
In the build, the bound moved 26 tax-unit cells in 13 columns (
out/evidence_base_tail_bounds.json). The line-32 draw fell from $141.1B to $33.3B, as the sweep predicted for seed 0, and the unit that drew $218.9M now carries $51.6M. The others include W-2 wages from qualified businesses ($48.0B → $20.1B), estate income ($16.7B → $7.1B) and the passive leaf ($10.5B → $7.4B).At Route A final weights ($B; deltas in $B):
Tests
GitHub's runners for this repository were stalled for about four hours on 2026-10-13 (every run queued from 13:22Z). The workflow's suites were therefore also run on Modal against the pushed branch (
scripts/modal_ci.pyin the evidence folder), with the same commands on 16 CPUs.0260d6404: 17,029 passed, 157 skipped, 3 xfailed, 4 failed.origin/main(74f5e6123), same container: 16,990 passed, 157 skipped, 3 xfailed, and the same 4 failed. All four are environment-bound: one needs an unreadable directory (the container runs as root), one needs Python ≥ 3.14.7 (the image has 3.14.2), one needsps, and one needs the telemetry emitter. The 39 extra passes are this PR's new tests.ci_test_plan.py verify, the graph burndown check,ruff check .): clean.0260d6404. On the previous head its scenario shard passed (14 of 14) and its two contract shards passed 65 of 66 with 2 skipped; the one failure was a literal field count, fixed in0260d6404.683b64428differs from0260d6404by one comment and the pins it moves. Locally,tools/spec_engine_coverage.py --checkreports 42,194/42,194 fields and 41/41 checks,generate_us_bundle_from_constants.py --checkis clean, and the loader golden test and the bound tests pass. A Modal pass and GitHub's own run on this head are in progress.What the Modal run caught that a local run of the new tests had not:
Review
Four rounds of independent review. Rounds 1 to 3 ran on Opus lanes while the Codex lanes were closed; round 4 ran on GPT-6.1 Sol.
d9f180852).8e54ef72b).test_us_spec_bundle.py.635ae0a11). The blocker was resolved and every figure matched the evidence files. The nits were one leftover sentence, the rung-comparison claim (now backed byrecipient_count) and LP conditioning.0260d6404, GPT-6.1 Sol), with no code finding.683b64428); "NII and NIIT are unchanged" overstated +$2.5B and +$0.03B; a stale spec hash.Reports are
review-r{1,2,3,4}-out.mdin the evidence folder.Decision
Queued for Max as d1504. It changes what the next US build carries and retires schema-5 stacked pools, and the choice of the slice-mass rule over a fixed quantile or the slice boundary is a methodology call. It is best merged before or with #1251.
Follow-ups
Evidence (outside the repository):
~/PolicyEngine/_reviews/puf-tail-draw-dominance/, which holdsdesign.md, the sweep scripts,out/aggregate_*.mdandout/*.json. The PUF microdata stayed on Modal.axiom: n/a: microdata imputation bound; no policy rule changes.
🤖 Generated with Claude Code