From eec910d61a7e0afe21995957740e03d64acdffdc Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 09:36:39 -0400 Subject: [PATCH 1/9] EPUF gate, rules first: reader, operator, cells, algebra, floor builder Registers the rules of a proposed gate that scores the gate-1 generator's earnings against SSA's 2006 Earnings Public-Use File, before any real-PSID value in EPUF units exists. The floor artifact and the draft gates.yaml block follow in a later commit, built by the code committed here. - data/epuf.py: byte-pinned EPUF reader (POPULACE_DYNAMICS_EPUF_DIR) that reproduces SSA's published Table A1, Table 4, Charts 3-4 and the research note's Table 8 from the staged bytes. - harness/epuf_operator.py: EPUF's cap and disclosure operator for survey-side and model-side earnings, with per-year constants read off the pinned bytes. - harness/epuf_cells.py: the window cells (r6, zint, d_anyzero, q_atmax, mpers, q_sexratio by sex and cohort band, 1998-2004) and the report-only career cells. - harness/epuf_gate.py: floor replicate, tolerance, acceptance interval, eligibility, ladder and scoring. - scripts/build_epuf_gate_floors.py: the candidate-blind floor builder. - docs/amendments/gate_epuf_registration_proposal.md: the proposal's rules; its results section is filled by the floor build. Co-Authored-By: Claude Opus 5.5 --- .../epuf_2006/disclosure_constants.json | 591 +++++ .../epuf_2006/epuf_dictionary.source.txt | 201 ++ data/external/epuf_2006/provenance.md | 65 + data/external/epuf_2006/published_tables.json | 2364 +++++++++++++++++ data/external/epuf_2006/rsn2012-01.source.txt | 2028 ++++++++++++++ .../epuf_2006/ssb_v71n4p33.source.txt | 1362 ++++++++++ .../gate_epuf_registration_proposal.md | 375 +++ scripts/build_epuf_gate_floors.py | 1042 ++++++++ scripts/extract_epuf_disclosure_constants.py | 123 + scripts/extract_epuf_published_tables.py | 223 ++ src/populace_dynamics/data/epuf.py | 270 ++ src/populace_dynamics/harness/epuf_cells.py | 468 ++++ src/populace_dynamics/harness/epuf_gate.py | 373 +++ .../harness/epuf_operator.py | 136 + src/populace_dynamics/harness/epuf_run.py | 115 + tests/README-tiers.md | 6 +- tests/data/test_epuf.py | 253 ++ tests/harness/test_epuf_cells.py | 342 +++ tests/harness/test_epuf_gate.py | 340 +++ tests/harness/test_epuf_operator.py | 121 + tests/test_epuf_gate_floor_builder.py | 410 +++ tests/tier_counts.json | 4 +- 22 files changed, 11207 insertions(+), 5 deletions(-) create mode 100644 data/external/epuf_2006/disclosure_constants.json create mode 100644 data/external/epuf_2006/epuf_dictionary.source.txt create mode 100644 data/external/epuf_2006/provenance.md create mode 100644 data/external/epuf_2006/published_tables.json create mode 100644 data/external/epuf_2006/rsn2012-01.source.txt create mode 100644 data/external/epuf_2006/ssb_v71n4p33.source.txt create mode 100644 docs/amendments/gate_epuf_registration_proposal.md create mode 100644 scripts/build_epuf_gate_floors.py create mode 100644 scripts/extract_epuf_disclosure_constants.py create mode 100644 scripts/extract_epuf_published_tables.py create mode 100644 src/populace_dynamics/data/epuf.py create mode 100644 src/populace_dynamics/harness/epuf_cells.py create mode 100644 src/populace_dynamics/harness/epuf_gate.py create mode 100644 src/populace_dynamics/harness/epuf_operator.py create mode 100644 src/populace_dynamics/harness/epuf_run.py create mode 100644 tests/data/test_epuf.py create mode 100644 tests/harness/test_epuf_cells.py create mode 100644 tests/harness/test_epuf_gate.py create mode 100644 tests/harness/test_epuf_operator.py create mode 100644 tests/test_epuf_gate_floor_builder.py diff --git a/data/external/epuf_2006/disclosure_constants.json b/data/external/epuf_2006/disclosure_constants.json new file mode 100644 index 00000000..f9b72f43 --- /dev/null +++ b/data/external/epuf_2006/disclosure_constants.json @@ -0,0 +1,591 @@ +{ + "schema_version": "epuf_disclosure_constants.v1", + "generator": "scripts/extract_epuf_disclosure_constants.py", + "source": { + "annual_sha256": "a47315b56214df66fb9f9abcb2caa60779c8b3d091ded199323672c27e3ea105", + "wage_base": "data/external/track_a_statutory_parameters.json wage_base_change_points" + }, + "rule": { + "bottom_code_below": 100, + "rounding_bases": [ + { + "from": 100, + "below": 1000, + "base": 25 + }, + { + "from": 1000, + "below": 50000, + "base": 100 + }, + { + "from": 50000, + "below": null, + "base": 1000 + } + ], + "band": "values strictly between the wage base less one rounding base (the base at the wage base) and the wage base are replaced by band_mean" + }, + "years": { + "1951": { + "wage_base": 3600, + "band_base": 100, + "bottom_code": 46, + "band_mean": 3553, + "n_bottom_coded": 32453, + "n_band_mean": 9190, + "n_at_wage_base": 141173, + "n_positive": 574666 + }, + "1952": { + "wage_base": 3600, + "band_base": 100, + "bottom_code": 45, + "band_mean": 3553, + "n_bottom_coded": 31996, + "n_band_mean": 9516, + "n_at_wage_base": 164031, + "n_positive": 590383 + }, + "1953": { + "wage_base": 3600, + "band_base": 100, + "bottom_code": 45, + "band_mean": 3553, + "n_bottom_coded": 31082, + "n_band_mean": 9414, + "n_at_wage_base": 187633, + "n_positive": 601308 + }, + "1954": { + "wage_base": 3600, + "band_base": 100, + "bottom_code": 45, + "band_mean": 3553, + "n_bottom_coded": 30967, + "n_band_mean": 9032, + "n_at_wage_base": 186693, + "n_positive": 590541 + }, + "1955": { + "wage_base": 4200, + "band_base": 100, + "bottom_code": 46, + "band_mean": 4153, + "n_bottom_coded": 29469, + "n_band_mean": 8478, + "n_at_wage_base": 163539, + "n_positive": 645873 + }, + "1956": { + "wage_base": 4200, + "band_base": 100, + "bottom_code": 46, + "band_mean": 4153, + "n_bottom_coded": 28305, + "n_band_mean": 9009, + "n_at_wage_base": 189596, + "n_positive": 671229 + }, + "1957": { + "wage_base": 4200, + "band_base": 100, + "bottom_code": 47, + "band_mean": 4154, + "n_bottom_coded": 27403, + "n_band_mean": 9268, + "n_at_wage_base": 209167, + "n_positive": 701607 + }, + "1958": { + "wage_base": 4200, + "band_base": 100, + "bottom_code": 46, + "band_mean": 4154, + "n_bottom_coded": 27960, + "n_band_mean": 8915, + "n_at_wage_base": 211497, + "n_positive": 694826 + }, + "1959": { + "wage_base": 4800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 4753, + "n_bottom_coded": 27264, + "n_band_mean": 7854, + "n_at_wage_base": 190029, + "n_positive": 710553 + }, + "1960": { + "wage_base": 4800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 4755, + "n_bottom_coded": 27162, + "n_band_mean": 8091, + "n_at_wage_base": 202581, + "n_positive": 720003 + }, + "1961": { + "wage_base": 4800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 4755, + "n_bottom_coded": 27222, + "n_band_mean": 7812, + "n_at_wage_base": 211163, + "n_positive": 722824 + }, + "1962": { + "wage_base": 4800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 4754, + "n_bottom_coded": 26457, + "n_band_mean": 7455, + "n_at_wage_base": 230181, + "n_positive": 738066 + }, + "1963": { + "wage_base": 4800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 4754, + "n_bottom_coded": 27075, + "n_band_mean": 7594, + "n_at_wage_base": 244426, + "n_positive": 750314 + }, + "1964": { + "wage_base": 4800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 4755, + "n_bottom_coded": 27048, + "n_band_mean": 7532, + "n_at_wage_base": 265592, + "n_positive": 769290 + }, + "1965": { + "wage_base": 4800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 4754, + "n_bottom_coded": 27280, + "n_band_mean": 8078, + "n_at_wage_base": 288855, + "n_positive": 799836 + }, + "1966": { + "wage_base": 6600, + "band_base": 100, + "bottom_code": 47, + "band_mean": 6554, + "n_bottom_coded": 26666, + "n_band_mean": 6285, + "n_at_wage_base": 203974, + "n_positive": 839992 + }, + "1967": { + "wage_base": 6600, + "band_base": 100, + "bottom_code": 47, + "band_mean": 6556, + "n_bottom_coded": 25742, + "n_band_mean": 6688, + "n_at_wage_base": 223042, + "n_positive": 859300 + }, + "1968": { + "wage_base": 7800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 7755, + "n_bottom_coded": 25002, + "n_band_mean": 5736, + "n_at_wage_base": 189405, + "n_positive": 885946 + }, + "1969": { + "wage_base": 7800, + "band_base": 100, + "bottom_code": 48, + "band_mean": 7758, + "n_bottom_coded": 24846, + "n_band_mean": 5908, + "n_at_wage_base": 221424, + "n_positive": 914616 + }, + "1970": { + "wage_base": 7800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 7757, + "n_bottom_coded": 24854, + "n_band_mean": 6135, + "n_at_wage_base": 240436, + "n_positive": 920526 + }, + "1971": { + "wage_base": 7800, + "band_base": 100, + "bottom_code": 47, + "band_mean": 7759, + "n_bottom_coded": 24816, + "n_band_mean": 6537, + "n_at_wage_base": 262035, + "n_positive": 922906 + }, + "1972": { + "wage_base": 9000, + "band_base": 100, + "bottom_code": 47, + "band_mean": 8959, + "n_bottom_coded": 25081, + "n_band_mean": 5555, + "n_at_wage_base": 238717, + "n_positive": 951405 + }, + "1973": { + "wage_base": 10800, + "band_base": 100, + "bottom_code": 48, + "band_mean": 10763, + "n_bottom_coded": 23735, + "n_band_mean": 4912, + "n_at_wage_base": 201180, + "n_positive": 987692 + }, + "1974": { + "wage_base": 13200, + "band_base": 100, + "bottom_code": 48, + "band_mean": 13164, + "n_bottom_coded": 23018, + "n_band_mean": 3972, + "n_at_wage_base": 152324, + "n_positive": 1003244 + }, + "1975": { + "wage_base": 14100, + "band_base": 100, + "bottom_code": 48, + "band_mean": 14063, + "n_bottom_coded": 22557, + "n_band_mean": 3709, + "n_at_wage_base": 149165, + "n_positive": 993889 + }, + "1976": { + "wage_base": 15300, + "band_base": 100, + "bottom_code": 48, + "band_mean": 15266, + "n_bottom_coded": 20581, + "n_band_mean": 3599, + "n_at_wage_base": 152513, + "n_positive": 1018394 + }, + "1977": { + "wage_base": 16500, + "band_base": 100, + "bottom_code": 49, + "band_mean": 16466, + "n_bottom_coded": 19964, + "n_band_mean": 3495, + "n_at_wage_base": 155942, + "n_positive": 1050246 + }, + "1978": { + "wage_base": 17700, + "band_base": 100, + "bottom_code": 49, + "band_mean": 17662, + "n_bottom_coded": 18234, + "n_band_mean": 2913, + "n_at_wage_base": 166561, + "n_positive": 1083967 + }, + "1979": { + "wage_base": 22900, + "band_base": 100, + "bottom_code": 50, + "band_mean": 22867, + "n_bottom_coded": 16948, + "n_band_mean": 2075, + "n_at_wage_base": 109471, + "n_positive": 1110353 + }, + "1980": { + "wage_base": 25900, + "band_base": 100, + "bottom_code": 50, + "band_mean": 25866, + "n_bottom_coded": 16452, + "n_band_mean": 1759, + "n_at_wage_base": 97609, + "n_positive": 1116739 + }, + "1981": { + "wage_base": 29700, + "band_base": 100, + "bottom_code": 50, + "band_mean": 29670, + "n_bottom_coded": 15288, + "n_band_mean": 1389, + "n_at_wage_base": 85259, + "n_positive": 1118021 + }, + "1982": { + "wage_base": 32400, + "band_base": 100, + "bottom_code": 50, + "band_mean": 32371, + "n_bottom_coded": 14989, + "n_band_mean": 1169, + "n_at_wage_base": 78458, + "n_positive": 1104079 + }, + "1983": { + "wage_base": 35700, + "band_base": 100, + "bottom_code": 50, + "band_mean": 35673, + "n_bottom_coded": 14574, + "n_band_mean": 1044, + "n_at_wage_base": 70073, + "n_positive": 1115203 + }, + "1984": { + "wage_base": 37800, + "band_base": 100, + "bottom_code": 50, + "band_mean": 37775, + "n_bottom_coded": 14452, + "n_band_mean": 1120, + "n_at_wage_base": 73909, + "n_positive": 1157926 + }, + "1985": { + "wage_base": 39600, + "band_base": 100, + "bottom_code": 50, + "band_mean": 39576, + "n_bottom_coded": 14896, + "n_band_mean": 1175, + "n_at_wage_base": 77263, + "n_positive": 1192767 + }, + "1986": { + "wage_base": 42000, + "band_base": 100, + "bottom_code": 50, + "band_mean": 41978, + "n_bottom_coded": 14809, + "n_band_mean": 1264, + "n_at_wage_base": 75421, + "n_positive": 1216539 + }, + "1987": { + "wage_base": 43800, + "band_base": 100, + "bottom_code": 51, + "band_mean": 43780, + "n_bottom_coded": 14459, + "n_band_mean": 1261, + "n_at_wage_base": 76753, + "n_positive": 1246860 + }, + "1988": { + "wage_base": 45000, + "band_base": 100, + "bottom_code": 51, + "band_mean": 44982, + "n_bottom_coded": 14345, + "n_band_mean": 1394, + "n_at_wage_base": 83979, + "n_positive": 1285984 + }, + "1989": { + "wage_base": 48000, + "band_base": 100, + "bottom_code": 52, + "band_mean": 47982, + "n_bottom_coded": 13783, + "n_band_mean": 1282, + "n_at_wage_base": 80975, + "n_positive": 1310357 + }, + "1990": { + "wage_base": 51300, + "band_base": 1000, + "bottom_code": 52, + "band_mean": 50819, + "n_bottom_coded": 13407, + "n_band_mean": 5523, + "n_at_wage_base": 74915, + "n_positive": 1320380 + }, + "1991": { + "wage_base": 53400, + "band_base": 1000, + "bottom_code": 52, + "band_mean": 52975, + "n_bottom_coded": 13346, + "n_band_mean": 4598, + "n_at_wage_base": 73700, + "n_positive": 1315162 + }, + "1992": { + "wage_base": 55500, + "band_base": 1000, + "bottom_code": 52, + "band_mean": 55076, + "n_bottom_coded": 13248, + "n_band_mean": 4499, + "n_at_wage_base": 75601, + "n_positive": 1323691 + }, + "1993": { + "wage_base": 57600, + "band_base": 1000, + "bottom_code": 53, + "band_mean": 57188, + "n_bottom_coded": 13413, + "n_band_mean": 4185, + "n_at_wage_base": 75041, + "n_positive": 1344345 + }, + "1994": { + "wage_base": 60600, + "band_base": 1000, + "bottom_code": 56, + "band_mean": 60191, + "n_bottom_coded": 15999, + "n_band_mean": 4041, + "n_at_wage_base": 74331, + "n_positive": 1372474 + }, + "1995": { + "wage_base": 61200, + "band_base": 1000, + "bottom_code": 56, + "band_mean": 60777, + "n_bottom_coded": 15086, + "n_band_mean": 4157, + "n_at_wage_base": 81094, + "n_positive": 1394997 + }, + "1996": { + "wage_base": 62700, + "band_base": 1000, + "bottom_code": 56, + "band_mean": 62290, + "n_bottom_coded": 15004, + "n_band_mean": 4288, + "n_at_wage_base": 85970, + "n_positive": 1417938 + }, + "1997": { + "wage_base": 65400, + "band_base": 1000, + "bottom_code": 56, + "band_mean": 64992, + "n_bottom_coded": 14089, + "n_band_mean": 4288, + "n_at_wage_base": 89375, + "n_positive": 1444475 + }, + "1998": { + "wage_base": 68400, + "band_base": 1000, + "bottom_code": 57, + "band_mean": 68001, + "n_bottom_coded": 13367, + "n_band_mean": 3953, + "n_at_wage_base": 92907, + "n_positive": 1472473 + }, + "1999": { + "wage_base": 72600, + "band_base": 1000, + "bottom_code": 58, + "band_mean": 72204, + "n_bottom_coded": 13091, + "n_band_mean": 3790, + "n_at_wage_base": 91429, + "n_positive": 1496574 + }, + "2000": { + "wage_base": 76200, + "band_base": 1000, + "bottom_code": 56, + "band_mean": 75820, + "n_bottom_coded": 13280, + "n_band_mean": 3696, + "n_at_wage_base": 94444, + "n_positive": 1521937 + }, + "2001": { + "wage_base": 80400, + "band_base": 1000, + "bottom_code": 58, + "band_mean": 80011, + "n_bottom_coded": 13484, + "n_band_mean": 3525, + "n_at_wage_base": 90952, + "n_positive": 1524651 + }, + "2002": { + "wage_base": 84900, + "band_base": 1000, + "bottom_code": 55, + "band_mean": 84510, + "n_bottom_coded": 13748, + "n_band_mean": 3134, + "n_at_wage_base": 83213, + "n_positive": 1519561 + }, + "2003": { + "wage_base": 87000, + "band_base": 1000, + "bottom_code": 55, + "band_mean": 86635, + "n_bottom_coded": 13802, + "n_band_mean": 3006, + "n_at_wage_base": 84257, + "n_positive": 1520638 + }, + "2004": { + "wage_base": 87900, + "band_base": 1000, + "bottom_code": 59, + "band_mean": 87505, + "n_bottom_coded": 13547, + "n_band_mean": 3287, + "n_at_wage_base": 91287, + "n_positive": 1535509 + }, + "2005": { + "wage_base": 90000, + "band_base": 1000, + "bottom_code": 59, + "band_mean": 89642, + "n_bottom_coded": 13138, + "n_band_mean": 3369, + "n_at_wage_base": 94873, + "n_positive": 1550602 + }, + "2006": { + "wage_base": 94200, + "band_base": 1000, + "bottom_code": 58, + "band_mean": 93843, + "n_bottom_coded": 12743, + "n_band_mean": 3215, + "n_at_wage_base": 95462, + "n_positive": 1562797 + } + } +} diff --git a/data/external/epuf_2006/epuf_dictionary.source.txt b/data/external/epuf_2006/epuf_dictionary.source.txt new file mode 100644 index 00000000..716ea9db --- /dev/null +++ b/data/external/epuf_2006/epuf_dictionary.source.txt @@ -0,0 +1,201 @@ + The 2006 Earnings Public-Use Microdata File + + Data Dictionary and Field Descriptors + + +Part 1. Introduction + +The 2006 Earnings Public-Use File (EPUF) is a systematic 1 percent random sample of all Social +Security numbers issued prior to January 1, 2007. With a few minor exceptions, all of the values for +the data fields in this file are from the Summary Segment of SSA’s Master Earnings File, the +administrative file used to determine an individual’s eligibility status under the Social Security +program and the amount of benefits paid out. + +The EPUF consists of two separate, linkable sub-files—one with demographic and aggregate earnings +information (demographic sub-file) and one with annual earnings information from 1951 to 2006 +(annual earnings sub-file.) Each record on these sub-files has a unique, randomly assigned identifier +allowing linking across both sub-files. The demographic sub-file contains 4,384,254 records, one for +each individual included in EPUF. The annual earnings sub-file contains 60,326,474 earnings records +with positive earnings values for the 3,131,424 individuals who had positive earnings for at least one +year during 1951 to 2006. Years with zero earnings do not generate a record in the annual earnings +sub-file. + +All of the monetary values in the file have been bottom-coded, top-coded, or random rounded for data +disclosure purposes. The rounding base used in the random rounding process depends on the amount +of earnings.1 The random rounding process provides some uncertainty about the actual values on the +individual’s earnings records and the interval of uncertainty increases as earnings increase.2 All of the +values for annual earnings are top-coded at the taxable maximum in a given year. + +Several steps were taken to ensure that the random rounding process did not alter an individual’s +status in terms of: + + 1. worker (in covered employment) versus non-worker in a given year, + 2. earnings below or at least equal to the taxable maximum in a given year, + 3. whether or not the individual had any earnings in the 1937 to 1950 time period + +All annual earnings values less than $100 are bottom-coded so rounding does not result in $0 earnings. +Bottom coding means all earnings values less than $100 in a given year are replaced with the average +value for all records with earnings less than $100 in that year. We also apply bottom coding to the +aggregate values of Social Security Taxable Earnings from 1937 to 1950 that are less than $100. + +To ensure that earnings below the taxable maximum are not random rounded up to the taxable +maximum, all of the earnings values within the random rounding base ($100 or $1,000 depending on +the year) of the taxable maximum are assigned the average value of all earnings records within that +interval. For example, if the taxable maximum is $96,000 and an individual has earnings of +$95,137.00, we assigned the average value for all earnings between $95,000 and $96,000 to the +individual’s record so it is not random rounded up to $96,000. We apply the same process to all other +earnings records between $95,000 and $96,000 for that year. + + +1 + The dollar amounts for the random rounding base in EPUF are similar to those found in Zayatz, Laura. 2007. “Disclosure Avoidance +Practices and Research at the U.S. Census Bureau: An Update.” Journal of Official Statistics, 23(2), 253-265. The rounding base for +earnings between $1 and $999 in EPUF is higher than the base used in the article. +2 + Random rounding provides uncertainty when the amount of earnings reported to SSA is known. Thus, if someone has the actual +value reported to SSA and traditional rounding is used, he/she will know the rounded value on EPUF. However, when random +rounding is used, there are two possible values, only one of which is used in EPUF. + + 1 + In-depth information about this file is available in: + The 2006 Earnings Public-Use Micro Data File: An Introduction, by Michael Compson + +Part 2. Demographic and Aggregate Earnings Information + + +ID Identification Number + + This is the first field in both sub-files. The ID data field allows data linking across both sub- + files. We randomly assigned the Identification Number to each individual included in EPUF + using a random number generator routine. + + +YOB Year of birth + + YOB: Ranges from 1870 to 2006 + + +SEX Sex of beneficiary + + 1: Male + 2: Female + 3: Unspecified gender code + + +TC3750 Total Credits earned from 1937 to 1950 + + This field indicates the total number of Social Security credits earned by the + individual based on his/her earnings from 1937 to 1950. The Social Security + Administration estimates this field. We use credits and quarters of coverage + interchangeably. + + TC3750: Ranges from 0 to 56 + + +TC5152 Total Credits earned from 1951 to 1952 + + This field indicates the total number of Social Security credits earned by the + individual based on his/her earnings in 1951 and 1952. Annual amounts for the + credits earned for each of these two years are not available in electronic format on + the Master Earnings File. The Social Security Administration derives this field from + administrative data. + + TC5152: Ranges from 0 to 8 + + +AE3750 Aggregate Social Security Taxable Earnings from 1937 through 1950 + + This field is the aggregate amount of Social Security Taxable Earnings from 1937 + through 1950. SSA does not have annual values for taxable earnings during this time + period available in electronic format on the Master Earnings File. + + We made one of three potential adjustments to each value of this data field: + 1. The value of all records whose aggregate taxable earnings from 1937 to + 1950 was greater than $37,000 is top-coded and set equal to $41,500 (the + rounded mean of all values greater than $37,000). Approximately one-half + of 1 percent of all the values for this field is greater than the top-coded + value. + + 2. The value of all records whose aggregate taxable earnings from 1937 to + 1950 was greater than zero and less than $100 is bottom-coded and set equal + to $39 (the rounded mean of all values less than $100). + + 3. The value of all remaining records is random rounded to multiples of $25 or + $100 depending on the amount of taxable earnings. + + a. Aggregate taxable earnings greater than $100 and less than $1,000 + are random rounded to a base of $25, + b. Aggregate taxable earnings greater than $1,000 and less than + $37,000 are random rounded to a base of $100. + + +Part 3. Annual Earnings Information + + +ID Identification Number + + This is the first field in both sub-files. The ID data field allows data linking across both sub- + files. We randomly assigned the Identification Number to each individual included in EPUF + using a random number generator routine. For years in which an individual did not have + earnings, he/she will not appear in the annual earnings sub-file. If an individual did not have + any annual taxable earnings between 1951 and 2006 then his/her ID number is not in the + annual earnings sub-file. There are 60,326,474 earnings records in this sub-file for the + 3,139,001 individuals in the EPUF that have at least one year of annual taxable earnings from + 1951 to 2006. + + +YEAR + + The year when the individual had positive taxable earnings from 1951 to 2006. + + YEAR: Ranges from 1951 to 2006 + + +ANNUAL_QTRS + + The annual number of quarters of coverage or credits earned from 1951 to 2006 + + This field indicates the total number of Social Security credits earned by the individual based + on his/her earnings for a given year. The possible maximum value for any given year is four + credits. + + The annual estimates for the quarters of coverage earned in 1951 or 1952 are not available + electronically on the Master Earnings File. Consequently, SSA estimates the values for the + quarters of coverage earned in 1951 and 1952 and includes them in the demographic sub-file. + In the annual earning sub-file, the annual values for quarters of coverage in 1951 and 1952 + are set to a missing value. + + ANNUAL_QTRS: Ranges from missing value, 0 to 4 + + + +ANNUAL_EARNINGS + + Annual Social Security Taxable Earnings for each year from 1951 through 2006 + + This field contains only the positive values for annual Social Security Taxable Earnings up to + the taxable maximum in a given year from 1951 to 2006. + + ANNUAL_EARNINGS Ranges from $46 to $94,200 + + We made one of four potential adjustments to each value of this data field: + + 1. The value of all records whose annual taxable earnings were greater than the + taxable maximum in a given year is top-coded at the taxable maximum. + + 2. Records with an annual value less than $100 are bottom-coded to the rounded + mean of all values less than $100 for the given year. + + 3. With one exception - see number 4 below - records with annual taxable earnings + greater than $100 and less than the taxable maximum for a given year are + random rounded to multiples of $25, $100, $1,000 depending on the amount of + taxable earnings. + + 4. Records with annual taxable earnings within the random rounding base of the + taxable maximum for the given year are top-coded to the average value of all + earnings records for that year between the taxable maximum and the taxable + maximum minus the rounding base. For example, if the taxable maximum is + $96,000 and an individual has annual taxable earnings equal to $95,250 his or + her earnings would be set equal to the average value of all earnings records + between $95,000 and $96,000 in that year. + \ No newline at end of file diff --git a/data/external/epuf_2006/provenance.md b/data/external/epuf_2006/provenance.md new file mode 100644 index 00000000..91468e6f --- /dev/null +++ b/data/external/epuf_2006/provenance.md @@ -0,0 +1,65 @@ +# SSA 2006 Earnings Public-Use File (EPUF): provenance + +Source for the proposed EPUF covered-earnings gate. Read by +`src/populace_dynamics/data/epuf.py`, which refuses any staged member whose +SHA-256 differs from the pins below. + +## The file + +- Landing page: https://www.ssa.gov/policy/docs/microdata/epuf/index.html, + "Earnings Public-Use File, 2006 (released August 2011)", Federal Data + Catalog identifier US-GOV-SSA-336. +- Data: https://www.ssa.gov/policy/docs/microdata/epuf/epuf2006_csv_files.zip +- Dictionary: https://www.ssa.gov/policy/docs/microdata/epuf/epuf_dictionary.pdf + +| File | Bytes | SHA-256 | +|---|---:|---| +| `epuf2006_csv_files.zip` | 291,602,034 | `0bb97275cc35a1bb42d34d26acbc9df720d4f875854ba1d02c50323d2357003b` | +| member `EPUF2006_DEMOGRAPHIC.csv` | 151,016,999 | `195db459ca7b7c810162cb6e432371e8787eba8331787d2ba1eace1a0da2ccb0` | +| member `EPUF2006_ANNUAL.csv` | 1,751,339,555 | `a47315b56214df66fb9f9abcb2caa60779c8b3d091ded199323672c27e3ea105` | +| member `epuf_dictionary.pdf` (2011) | 155,159 | `9aebb2c4310516dd6b8c9067b2f2d5264529f8162c8822c22982b41d3d18b990` | +| member `READ ME FIRST.doc` | 22,528 | `4b46bc26163b30664d1b535d407821e4a77bb52e287ab8020b566f5910f1e434` | +| `epuf_dictionary.pdf` (web copy, 2014) | 155,241 | `54210e2c9642fc2e3dba54c6c41de8be9055dfec2fe1c8f893775698c9db89ff` | + +## Retrieval + +- www.ssa.gov answers command-line clients with HTTP 403, so curl could not + fetch the file. A Chrome download of the zip from the data URL (referrer: + the landing page) dated 2026-03-18 20:00:07 UTC was on Max's machine. +- On 2026-10-01 at 21:13:53 UTC (server `Date`), the orchestrating Claude Code + session fetched the zip and the dictionary from www.ssa.gov in the desktop + app's built-in browser and hashed the response bytes in the page + (`crypto.subtle.digest`). The server reported `content-length` 291,602,034, + `last-modified` Fri, 07 Sep 2012 19:41:59 GMT and `etag` + "11617e72-4c921cd1a4fc0" for the zip, and both hashes equal the staged + copies above. The staged bytes are therefore what SSA serves today. +- Staging: members extracted to `~/PolicyEngine/epuf-data/csv/` (reader + override `POPULACE_DYNAMICS_EPUF_DIR`). The download record, documentation + text and pre-registration EPUF profile are in Max's evidence folder, + `~/microcosm-launch-evidence/dynasim-parity-20260909/epuf-20261001/`. + +## Documentation committed here + +| File | Source | Retrieved | SHA-256 | +|---|---|---|---| +| `ssb_v71n4p33.source.txt` | Compson (2011), "The 2006 Earnings Public-Use Microdata File: An Introduction", *Social Security Bulletin* 71(4), https://www.ssa.gov/policy/docs/ssb/v71n4/v71n4p33.html | 2026-10-01, built-in browser: article text plus the page's hidden chart tables, each checked against the DOM | `b40a828cc44c57f25d95a05d467f4ff881948f4ee136ccb67bc9aee4264bbe35` | +| `rsn2012-01.source.txt` | Compson (2012), "Comparing Earnings Estimates from the 2006 Earnings Public-Use File and the Annual Statistical Supplement", Research and Statistics Note 2012-01, https://www.ssa.gov/policy/docs/rsnotes/rsn2012-01.html | 2026-10-01, same method | `886366c321d2abcaf600ba6b64b47af600f3e3a6672a66e6a07c26e7c5067bf7` | +| `epuf_dictionary.source.txt` | `pdftotext -layout` of the dictionary (the 2011 and 2014 PDFs give identical text) | 2026-10-01 | `35bd61b0336659d3cd75c0313519d70f8014540e326a16ae2051a26574b1ac97` | +| `published_tables.json` | SSB Table A1, Table 4, Charts 3 and 4; RSN Table 8; extracted by `scripts/extract_epuf_published_tables.py` | 2026-10-01 | see the file's `text_sha256` fields | + +## Facts the reader asserts on the pinned bytes + +- 4,384,254 persons. The "4,348,254" printed in parts of the SSB article and + the research note is a digit transposition; the SSB article's own + subtraction (4,413,024 sampled less 28,770 removed) and the dictionary give + 4,384,254. +- 3,131,424 persons with at least one annual row; 60,326,474 annual rows; a + year with zero earnings has no row. +- Rows exist only at calendar-year ages 15-85. +- Every year's maximum equals that year's contribution and benefit base, and + no value exceeds it. +- SSB Table A1 (records by year and sex), SSB Charts 3 and 4 (persons by + birth year and sex) and the EPUF columns of RSN Table 8 (share of workers + below the maximum) reproduce exactly. SSB Table 4 means and medians + reproduce exactly for all workers, men and women; the sex-unknown group's + rounded mean misses by $1 in 1963 and 1992. diff --git a/data/external/epuf_2006/published_tables.json b/data/external/epuf_2006/published_tables.json new file mode 100644 index 00000000..c809270e --- /dev/null +++ b/data/external/epuf_2006/published_tables.json @@ -0,0 +1,2364 @@ +{ + "schema_version": "epuf_published_tables.v1", + "generator": "scripts/extract_epuf_published_tables.py", + "sources": { + "ssb": { + "citation": "Compson, Michael. 2011. 'The 2006 Earnings Public-Use Microdata File: An Introduction.' Social Security Bulletin 71(4).", + "url": "https://www.ssa.gov/policy/docs/ssb/v71n4/v71n4p33.html", + "text": "data/external/epuf_2006/ssb_v71n4p33.source.txt", + "text_sha256": "b40a828cc44c57f25d95a05d467f4ff881948f4ee136ccb67bc9aee4264bbe35" + }, + "rsn": { + "citation": "Compson, Michael. 2012. 'Comparing Earnings Estimates from the 2006 Earnings Public-Use File and the Annual Statistical Supplement.' Research and Statistics Note No. 2012-01.", + "url": "https://www.ssa.gov/policy/docs/rsnotes/rsn2012-01.html", + "text": "data/external/epuf_2006/rsn2012-01.source.txt", + "text_sha256": "886366c321d2abcaf600ba6b64b47af600f3e3a6672a66e6a07c26e7c5067bf7" + } + }, + "retrieved": "2026-10-01", + "tables": { + "ssb_table_a1_records": { + "source": "ssb", + "caption_line": 564, + "description": "Number of individuals with taxable earnings records in EPUF, by sex, 1951-2006 (persons with an annual row)", + "unit": "persons", + "rows": { + "1951": { + "all": 574666, + "men": 380673, + "women": 193655, + "unknown": 338 + }, + "1952": { + "all": 590383, + "men": 387176, + "women": 202841, + "unknown": 366 + }, + "1953": { + "all": 601308, + "men": 392710, + "women": 208254, + "unknown": 344 + }, + "1954": { + "all": 590541, + "men": 386904, + "women": 203317, + "unknown": 320 + }, + "1955": { + "all": 645873, + "men": 426862, + "women": 218624, + "unknown": 387 + }, + "1956": { + "all": 671229, + "men": 441870, + "women": 228933, + "unknown": 426 + }, + "1957": { + "all": 701607, + "men": 468328, + "women": 232861, + "unknown": 418 + }, + "1958": { + "all": 694826, + "men": 464175, + "women": 230290, + "unknown": 361 + }, + "1959": { + "all": 710553, + "men": 471169, + "women": 239044, + "unknown": 340 + }, + "1960": { + "all": 720003, + "men": 474604, + "women": 245085, + "unknown": 314 + }, + "1961": { + "all": 722824, + "men": 475513, + "women": 247008, + "unknown": 303 + }, + "1962": { + "all": 738066, + "men": 482590, + "women": 255187, + "unknown": 289 + }, + "1963": { + "all": 750314, + "men": 488952, + "women": 261077, + "unknown": 285 + }, + "1964": { + "all": 769290, + "men": 499171, + "women": 269834, + "unknown": 285 + }, + "1965": { + "all": 799836, + "men": 514368, + "women": 285184, + "unknown": 284 + }, + "1966": { + "all": 839992, + "men": 531966, + "women": 307743, + "unknown": 283 + }, + "1967": { + "all": 859300, + "men": 540003, + "women": 319006, + "unknown": 291 + }, + "1968": { + "all": 885946, + "men": 551920, + "women": 333731, + "unknown": 295 + }, + "1969": { + "all": 914616, + "men": 564231, + "women": 350067, + "unknown": 318 + }, + "1970": { + "all": 920526, + "men": 565453, + "women": 354749, + "unknown": 324 + }, + "1971": { + "all": 922906, + "men": 565675, + "women": 356911, + "unknown": 320 + }, + "1972": { + "all": 951405, + "men": 578237, + "women": 372840, + "unknown": 328 + }, + "1973": { + "all": 987692, + "men": 593494, + "women": 393844, + "unknown": 354 + }, + "1974": { + "all": 1003244, + "men": 597517, + "women": 405375, + "unknown": 352 + }, + "1975": { + "all": 993889, + "men": 589138, + "women": 404403, + "unknown": 348 + }, + "1976": { + "all": 1018394, + "men": 598171, + "women": 419885, + "unknown": 338 + }, + "1977": { + "all": 1050246, + "men": 611288, + "women": 438619, + "unknown": 339 + }, + "1978": { + "all": 1083967, + "men": 625380, + "women": 458246, + "unknown": 341 + }, + "1979": { + "all": 1110353, + "men": 635128, + "women": 474898, + "unknown": 327 + }, + "1980": { + "all": 1116739, + "men": 634313, + "women": 482099, + "unknown": 327 + }, + "1981": { + "all": 1118021, + "men": 632816, + "women": 484894, + "unknown": 311 + }, + "1982": { + "all": 1104079, + "men": 622799, + "women": 480974, + "unknown": 306 + }, + "1983": { + "all": 1115203, + "men": 625683, + "women": 489213, + "unknown": 307 + }, + "1984": { + "all": 1157926, + "men": 644631, + "women": 512978, + "unknown": 317 + }, + "1985": { + "all": 1192767, + "men": 659120, + "women": 533338, + "unknown": 309 + }, + "1986": { + "all": 1216539, + "men": 668310, + "women": 547925, + "unknown": 304 + }, + "1987": { + "all": 1246860, + "men": 681710, + "women": 564843, + "unknown": 307 + }, + "1988": { + "all": 1285984, + "men": 700961, + "women": 584711, + "unknown": 312 + }, + "1989": { + "all": 1310357, + "men": 711727, + "women": 598334, + "unknown": 296 + }, + "1990": { + "all": 1320380, + "men": 714671, + "women": 605422, + "unknown": 287 + }, + "1991": { + "all": 1315162, + "men": 709678, + "women": 605204, + "unknown": 280 + }, + "1992": { + "all": 1323691, + "men": 711615, + "women": 611804, + "unknown": 272 + }, + "1993": { + "all": 1344345, + "men": 722012, + "women": 622065, + "unknown": 268 + }, + "1994": { + "all": 1372474, + "men": 734324, + "women": 637884, + "unknown": 266 + }, + "1995": { + "all": 1394997, + "men": 745091, + "women": 649650, + "unknown": 256 + }, + "1996": { + "all": 1417938, + "men": 755129, + "women": 662564, + "unknown": 245 + }, + "1997": { + "all": 1444475, + "men": 766814, + "women": 677412, + "unknown": 249 + }, + "1998": { + "all": 1472473, + "men": 779589, + "women": 692640, + "unknown": 244 + }, + "1999": { + "all": 1496574, + "men": 791384, + "women": 704947, + "unknown": 243 + }, + "2000": { + "all": 1521937, + "men": 802776, + "women": 718923, + "unknown": 238 + }, + "2001": { + "all": 1524651, + "men": 803891, + "women": 720525, + "unknown": 235 + }, + "2002": { + "all": 1519561, + "men": 799527, + "women": 719799, + "unknown": 235 + }, + "2003": { + "all": 1520638, + "men": 798428, + "women": 721985, + "unknown": 225 + }, + "2004": { + "all": 1535509, + "men": 805264, + "women": 730008, + "unknown": 237 + }, + "2005": { + "all": 1550602, + "men": 812364, + "women": 738007, + "unknown": 231 + }, + "2006": { + "all": 1562797, + "men": 815763, + "women": 746806, + "unknown": 228 + } + } + }, + "ssb_table_4_mean_median": { + "source": "ssb", + "caption_line": 498, + "description": "Average and median taxable earnings in EPUF, by sex, 1951-2006 (dollars; means rounded to the dollar)", + "unit": "dollars", + "rows": { + "1951": { + "mean_all": 2047.0, + "median_all": 2100.0, + "mean_men": 2404.0, + "median_men": 2900.0, + "mean_women": 1344.0, + "median_women": 1200.0, + "mean_unknown": 1978.0, + "median_unknown": 1950.0 + }, + "1952": { + "mean_all": 2118.0, + "median_all": 2300.0, + "mean_men": 2482.0, + "median_men": 3100.0, + "mean_women": 1423.0, + "median_women": 1300.0, + "mean_unknown": 1904.0, + "median_unknown": 1950.0 + }, + "1953": { + "mean_all": 2187.0, + "median_all": 2400.0, + "mean_men": 2553.0, + "median_men": 3300.0, + "mean_women": 1499.0, + "median_women": 1300.0, + "mean_unknown": 2043.0, + "median_unknown": 2000.0 + }, + "1954": { + "mean_all": 2194.0, + "median_all": 2400.0, + "mean_men": 2544.0, + "median_men": 3300.0, + "mean_women": 1527.0, + "median_women": 1400.0, + "mean_unknown": 1886.0, + "median_unknown": 1700.0 + }, + "1955": { + "mean_all": 2374.0, + "median_all": 2400.0, + "mean_men": 2779.0, + "median_men": 3300.0, + "mean_women": 1583.0, + "median_women": 1300.0, + "mean_unknown": 1932.0, + "median_unknown": 1600.0 + }, + "1956": { + "mean_all": 2472.0, + "median_all": 2600.0, + "mean_men": 2884.0, + "median_men": 3500.0, + "mean_women": 1678.0, + "median_women": 1500.0, + "mean_unknown": 1897.0, + "median_unknown": 1400.0 + }, + "1957": { + "mean_all": 2518.0, + "median_all": 2700.0, + "mean_men": 2900.0, + "median_men": 3600.0, + "mean_women": 1752.0, + "median_women": 1500.0, + "mean_unknown": 1874.0, + "median_unknown": 1450.0 + }, + "1958": { + "mean_all": 2523.0, + "median_all": 2700.0, + "mean_men": 2881.0, + "median_men": 3500.0, + "mean_women": 1801.0, + "median_women": 1600.0, + "mean_unknown": 1914.0, + "median_unknown": 1500.0 + }, + "1959": { + "mean_all": 2766.0, + "median_all": 2800.0, + "mean_men": 3204.0, + "median_men": 3800.0, + "mean_women": 1903.0, + "median_women": 1600.0, + "mean_unknown": 2040.0, + "median_unknown": 1600.0 + }, + "1960": { + "mean_all": 2798.0, + "median_all": 2900.0, + "mean_men": 3239.0, + "median_men": 3900.0, + "mean_women": 1945.0, + "median_women": 1700.0, + "mean_unknown": 2161.0, + "median_unknown": 1800.0 + }, + "1961": { + "mean_all": 2819.0, + "median_all": 2900.0, + "mean_men": 3248.0, + "median_men": 3900.0, + "mean_women": 1994.0, + "median_women": 1700.0, + "mean_unknown": 2190.0, + "median_unknown": 1800.0 + }, + "1962": { + "mean_all": 2879.0, + "median_all": 3100.0, + "mean_men": 3313.0, + "median_men": 4100.0, + "mean_women": 2059.0, + "median_women": 1800.0, + "mean_unknown": 2439.0, + "median_unknown": 2100.0 + }, + "1963": { + "mean_all": 2913.0, + "median_all": 3100.0, + "mean_men": 3345.0, + "median_men": 4300.0, + "mean_women": 2104.0, + "median_women": 1800.0, + "mean_unknown": 2534.0, + "median_unknown": 2200.0 + }, + "1964": { + "mean_all": 2968.0, + "median_all": 3300.0, + "mean_men": 3402.0, + "median_men": 4500.0, + "mean_women": 2166.0, + "median_women": 1900.0, + "mean_unknown": 2717.0, + "median_unknown": 2700.0 + }, + "1965": { + "mean_all": 3012.0, + "median_all": 3400.0, + "mean_men": 3459.0, + "median_men": 4754.0, + "mean_women": 2206.0, + "median_women": 2000.0, + "mean_unknown": 2871.0, + "median_unknown": 2900.0 + }, + "1966": { + "mean_all": 3620.0, + "median_all": 3600.0, + "mean_men": 4312.0, + "median_men": 5000.0, + "mean_women": 2424.0, + "median_women": 2000.0, + "mean_unknown": 3548.0, + "median_unknown": 3300.0 + }, + "1967": { + "mean_all": 3710.0, + "median_all": 3700.0, + "mean_men": 4380.0, + "median_men": 5200.0, + "mean_women": 2576.0, + "median_women": 2200.0, + "mean_unknown": 3580.0, + "median_unknown": 3500.0 + }, + "1968": { + "mean_all": 4134.0, + "median_all": 4000.0, + "mean_men": 4944.0, + "median_men": 5600.0, + "mean_women": 2796.0, + "median_women": 2400.0, + "mean_unknown": 4099.0, + "median_unknown": 3800.0 + }, + "1969": { + "mean_all": 4275.0, + "median_all": 4200.0, + "mean_men": 5093.0, + "median_men": 6000.0, + "mean_women": 2956.0, + "median_women": 2600.0, + "mean_unknown": 4090.0, + "median_unknown": 3900.0 + }, + "1970": { + "mean_all": 4380.0, + "median_all": 4400.0, + "mean_men": 5175.0, + "median_men": 6200.0, + "mean_women": 3113.0, + "median_women": 2700.0, + "mean_unknown": 4214.0, + "median_unknown": 4200.0 + }, + "1971": { + "mean_all": 4485.0, + "median_all": 4600.0, + "mean_men": 5259.0, + "median_men": 6500.0, + "mean_women": 3257.0, + "median_women": 2900.0, + "mean_unknown": 4409.0, + "median_unknown": 4650.0 + }, + "1972": { + "mean_all": 4948.0, + "median_all": 4900.0, + "mean_men": 5893.0, + "median_men": 7000.0, + "mean_women": 3482.0, + "median_women": 3000.0, + "mean_unknown": 5067.0, + "median_unknown": 5100.0 + }, + "1973": { + "mean_all": 5548.0, + "median_all": 5200.0, + "mean_men": 6744.0, + "median_men": 7500.0, + "mean_women": 3745.0, + "median_women": 3100.0, + "mean_unknown": 5776.0, + "median_unknown": 5450.0 + }, + "1974": { + "mean_all": 6223.0, + "median_all": 5500.0, + "mean_men": 7653.0, + "median_men": 8000.0, + "mean_women": 4115.0, + "median_women": 3400.0, + "mean_unknown": 6572.0, + "median_unknown": 5950.0 + }, + "1975": { + "mean_all": 6578.0, + "median_all": 5800.0, + "mean_men": 8023.0, + "median_men": 8300.0, + "mean_women": 4473.0, + "median_women": 3700.0, + "mean_unknown": 6854.0, + "median_unknown": 6400.0 + }, + "1976": { + "mean_all": 7117.0, + "median_all": 6300.0, + "mean_men": 8693.0, + "median_men": 8900.0, + "mean_women": 4870.0, + "median_women": 4100.0, + "mean_unknown": 7806.0, + "median_unknown": 6950.0 + }, + "1977": { + "mean_all": 7625.0, + "median_all": 6700.0, + "mean_men": 9343.0, + "median_men": 9600.0, + "mean_women": 5229.0, + "median_women": 4300.0, + "mean_unknown": 8384.0, + "median_unknown": 7500.0 + }, + "1978": { + "mean_all": 8279.0, + "median_all": 7300.0, + "mean_men": 10132.0, + "median_men": 10400.0, + "mean_women": 5750.0, + "median_women": 4900.0, + "mean_unknown": 8816.0, + "median_unknown": 8200.0 + }, + "1979": { + "mean_all": 9488.0, + "median_all": 7900.0, + "mean_men": 11790.0, + "median_men": 11300.0, + "mean_women": 6410.0, + "median_women": 5400.0, + "mean_unknown": 10383.0, + "median_unknown": 9400.0 + }, + "1980": { + "mean_all": 10346.0, + "median_all": 8600.0, + "mean_men": 12804.0, + "median_men": 12000.0, + "mean_women": 7112.0, + "median_women": 6000.0, + "mean_unknown": 11052.0, + "median_unknown": 9600.0 + }, + "1981": { + "mean_all": 11426.0, + "median_all": 9400.0, + "mean_men": 14106.0, + "median_men": 13000.0, + "mean_women": 7927.0, + "median_women": 6700.0, + "mean_unknown": 12280.0, + "median_unknown": 10300.0 + }, + "1982": { + "mean_all": 12149.0, + "median_all": 9900.0, + "mean_men": 14844.0, + "median_men": 13300.0, + "mean_women": 8659.0, + "median_women": 7200.0, + "mean_unknown": 13362.0, + "median_unknown": 10950.0 + }, + "1983": { + "mean_all": 12810.0, + "median_all": 10300.0, + "mean_men": 15613.0, + "median_men": 13700.0, + "mean_women": 9224.0, + "median_women": 7600.0, + "mean_unknown": 13917.0, + "median_unknown": 11400.0 + }, + "1984": { + "mean_all": 13556.0, + "median_all": 10900.0, + "mean_men": 16572.0, + "median_men": 14500.0, + "mean_women": 9766.0, + "median_women": 7900.0, + "mean_unknown": 14365.0, + "median_unknown": 11300.0 + }, + "1985": { + "mean_all": 14183.0, + "median_all": 11400.0, + "mean_men": 17303.0, + "median_men": 15100.0, + "mean_women": 10325.0, + "median_women": 8300.0, + "mean_unknown": 15037.0, + "median_unknown": 12000.0 + }, + "1986": { + "mean_all": 14824.0, + "median_all": 11900.0, + "mean_men": 18002.0, + "median_men": 15600.0, + "mean_women": 10948.0, + "median_women": 8800.0, + "mean_unknown": 16204.0, + "median_unknown": 12950.0 + }, + "1987": { + "mean_all": 15430.0, + "median_all": 12300.0, + "mean_men": 18636.0, + "median_men": 16100.0, + "mean_women": 11560.0, + "median_women": 9300.0, + "mean_unknown": 16257.0, + "median_unknown": 12700.0 + }, + "1988": { + "mean_all": 16067.0, + "median_all": 12900.0, + "mean_men": 19304.0, + "median_men": 16600.0, + "mean_women": 12186.0, + "median_women": 9800.0, + "mean_unknown": 16943.0, + "median_unknown": 13250.0 + }, + "1989": { + "mean_all": 16847.0, + "median_all": 13400.0, + "mean_men": 20163.0, + "median_men": 17200.0, + "mean_women": 12902.0, + "median_women": 10300.0, + "mean_unknown": 18780.0, + "median_unknown": 15100.0 + }, + "1990": { + "mean_all": 17633.0, + "median_all": 14000.0, + "mean_men": 20990.0, + "median_men": 17800.0, + "mean_women": 13669.0, + "median_women": 10900.0, + "mean_unknown": 19937.0, + "median_unknown": 16500.0 + }, + "1991": { + "mean_all": 18182.0, + "median_all": 14400.0, + "mean_men": 21455.0, + "median_men": 17900.0, + "mean_women": 14342.0, + "median_women": 11400.0, + "mean_unknown": 21272.0, + "median_unknown": 18250.0 + }, + "1992": { + "mean_all": 18887.0, + "median_all": 14900.0, + "mean_men": 22199.0, + "median_men": 18400.0, + "mean_women": 15034.0, + "median_women": 11900.0, + "mean_unknown": 22037.0, + "median_unknown": 18800.0 + }, + "1993": { + "mean_all": 19327.0, + "median_all": 15100.0, + "mean_men": 22662.0, + "median_men": 18700.0, + "mean_women": 15455.0, + "median_women": 12100.0, + "mean_unknown": 22841.0, + "median_unknown": 20150.0 + }, + "1994": { + "mean_all": 20022.0, + "median_all": 15600.0, + "mean_men": 23576.0, + "median_men": 19400.0, + "mean_women": 15930.0, + "median_women": 12400.0, + "mean_unknown": 23137.0, + "median_unknown": 18700.0 + }, + "1995": { + "mean_all": 20629.0, + "median_all": 16200.0, + "mean_men": 24224.0, + "median_men": 20000.0, + "mean_women": 16504.0, + "median_women": 12900.0, + "mean_unknown": 23835.0, + "median_unknown": 19100.0 + }, + "1996": { + "mean_all": 21357.0, + "median_all": 16800.0, + "mean_men": 25066.0, + "median_men": 20800.0, + "mean_women": 17129.0, + "median_women": 13400.0, + "mean_unknown": 24950.0, + "median_unknown": 20200.0 + }, + "1997": { + "mean_all": 22386.0, + "median_all": 17600.0, + "mean_men": 26274.0, + "median_men": 21900.0, + "mean_women": 17985.0, + "median_women": 14100.0, + "mean_unknown": 24905.0, + "median_unknown": 20500.0 + }, + "1998": { + "mean_all": 23525.0, + "median_all": 18600.0, + "mean_men": 27582.0, + "median_men": 23100.0, + "mean_women": 18958.0, + "median_women": 14900.0, + "mean_unknown": 26290.0, + "median_unknown": 21800.0 + }, + "1999": { + "mean_all": 24580.0, + "median_all": 19400.0, + "mean_men": 28802.0, + "median_men": 24100.0, + "mean_women": 19840.0, + "median_women": 15600.0, + "mean_unknown": 28665.0, + "median_unknown": 23700.0 + }, + "2000": { + "mean_all": 25757.0, + "median_all": 20300.0, + "mean_men": 30149.0, + "median_men": 25200.0, + "mean_women": 20851.0, + "median_women": 16400.0, + "mean_unknown": 30797.0, + "median_unknown": 25450.0 + }, + "2001": { + "mean_all": 26739.0, + "median_all": 21000.0, + "mean_men": 31141.0, + "median_men": 25700.0, + "mean_women": 21826.0, + "median_women": 17100.0, + "mean_unknown": 32920.0, + "median_unknown": 26500.0 + }, + "2002": { + "mean_all": 27364.0, + "median_all": 21300.0, + "mean_men": 31743.0, + "median_men": 25900.0, + "mean_women": 22499.0, + "median_women": 17500.0, + "mean_unknown": 33686.0, + "median_unknown": 26800.0 + }, + "2003": { + "mean_all": 28009.0, + "median_all": 21700.0, + "mean_men": 32396.0, + "median_men": 26300.0, + "mean_women": 23154.0, + "median_women": 18000.0, + "mean_unknown": 34133.0, + "median_unknown": 29900.0 + }, + "2004": { + "mean_all": 28913.0, + "median_all": 22500.0, + "mean_men": 33396.0, + "median_men": 27200.0, + "mean_women": 23965.0, + "median_women": 18500.0, + "mean_unknown": 34542.0, + "median_unknown": 29100.0 + }, + "2005": { + "mean_all": 29745.0, + "median_all": 23100.0, + "mean_men": 34341.0, + "median_men": 28000.0, + "mean_women": 24685.0, + "median_women": 19000.0, + "mean_unknown": 36241.0, + "median_unknown": 30600.0 + }, + "2006": { + "mean_all": 30953.0, + "median_all": 24000.0, + "mean_men": 35764.0, + "median_men": 29100.0, + "mean_women": 25696.0, + "median_women": 19700.0, + "mean_unknown": 36799.0, + "median_unknown": 32500.0 + } + } + }, + "ssb_chart_3_birth_year": { + "source": "ssb", + "caption_line": 851, + "description": "Chart 3. Number of individuals in EPUF, by year of birth", + "unit": "thousands of persons, 2 decimals", + "rows": { + "1870": { + "thousands": 1.81 + }, + "1871": { + "thousands": 2.02 + }, + "1872": { + "thousands": 2.91 + }, + "1873": { + "thousands": 3.07 + }, + "1874": { + "thousands": 3.8 + }, + "1875": { + "thousands": 4.43 + }, + "1876": { + "thousands": 5.15 + }, + "1877": { + "thousands": 5.4 + }, + "1878": { + "thousands": 6.09 + }, + "1879": { + "thousands": 6.69 + }, + "1880": { + "thousands": 7.98 + }, + "1881": { + "thousands": 8.12 + }, + "1882": { + "thousands": 9.41 + }, + "1883": { + "thousands": 9.58 + }, + "1884": { + "thousands": 11.28 + }, + "1885": { + "thousands": 11.48 + }, + "1886": { + "thousands": 12.17 + }, + "1887": { + "thousands": 12.09 + }, + "1888": { + "thousands": 14.58 + }, + "1889": { + "thousands": 14.28 + }, + "1890": { + "thousands": 14.9 + }, + "1891": { + "thousands": 14.91 + }, + "1892": { + "thousands": 16.89 + }, + "1893": { + "thousands": 16.85 + }, + "1894": { + "thousands": 17.47 + }, + "1895": { + "thousands": 17.76 + }, + "1896": { + "thousands": 18.32 + }, + "1897": { + "thousands": 17.95 + }, + "1898": { + "thousands": 19.24 + }, + "1899": { + "thousands": 18.1 + }, + "1900": { + "thousands": 21.26 + }, + "1901": { + "thousands": 19.04 + }, + "1902": { + "thousands": 21.04 + }, + "1903": { + "thousands": 20.82 + }, + "1904": { + "thousands": 21.73 + }, + "1905": { + "thousands": 22.72 + }, + "1906": { + "thousands": 22.88 + }, + "1907": { + "thousands": 23.82 + }, + "1908": { + "thousands": 24.66 + }, + "1909": { + "thousands": 24.63 + }, + "1910": { + "thousands": 25.67 + }, + "1911": { + "thousands": 25.57 + }, + "1912": { + "thousands": 26.9 + }, + "1913": { + "thousands": 26.94 + }, + "1914": { + "thousands": 28.23 + }, + "1915": { + "thousands": 27.87 + }, + "1916": { + "thousands": 27.95 + }, + "1917": { + "thousands": 27.89 + }, + "1918": { + "thousands": 29.69 + }, + "1919": { + "thousands": 29.09 + }, + "1920": { + "thousands": 31.37 + }, + "1921": { + "thousands": 31.88 + }, + "1922": { + "thousands": 31.1 + }, + "1923": { + "thousands": 30.8 + }, + "1924": { + "thousands": 31.58 + }, + "1925": { + "thousands": 30.6 + }, + "1926": { + "thousands": 30.24 + }, + "1927": { + "thousands": 30.31 + }, + "1928": { + "thousands": 29.77 + }, + "1929": { + "thousands": 28.74 + }, + "1930": { + "thousands": 29.29 + }, + "1931": { + "thousands": 27.62 + }, + "1932": { + "thousands": 28.09 + }, + "1933": { + "thousands": 26.57 + }, + "1934": { + "thousands": 27.49 + }, + "1935": { + "thousands": 27.83 + }, + "1936": { + "thousands": 27.59 + }, + "1937": { + "thousands": 28.6 + }, + "1938": { + "thousands": 29.36 + }, + "1939": { + "thousands": 29.08 + }, + "1940": { + "thousands": 30.51 + }, + "1941": { + "thousands": 31.77 + }, + "1942": { + "thousands": 34.95 + }, + "1943": { + "thousands": 36.29 + }, + "1944": { + "thousands": 34.97 + }, + "1945": { + "thousands": 34.76 + }, + "1946": { + "thousands": 40.96 + }, + "1947": { + "thousands": 45.44 + }, + "1948": { + "thousands": 44.12 + }, + "1949": { + "thousands": 44.74 + }, + "1950": { + "thousands": 44.61 + }, + "1951": { + "thousands": 46.41 + }, + "1952": { + "thousands": 47.56 + }, + "1953": { + "thousands": 48.33 + }, + "1954": { + "thousands": 50.15 + }, + "1955": { + "thousands": 51.31 + }, + "1956": { + "thousands": 51.62 + }, + "1957": { + "thousands": 53.2 + }, + "1958": { + "thousands": 52.99 + }, + "1959": { + "thousands": 52.81 + }, + "1960": { + "thousands": 53.23 + }, + "1961": { + "thousands": 52.82 + }, + "1962": { + "thousands": 52.83 + }, + "1963": { + "thousands": 52.14 + }, + "1964": { + "thousands": 51.36 + }, + "1965": { + "thousands": 48.96 + }, + "1966": { + "thousands": 46.94 + }, + "1967": { + "thousands": 46.01 + }, + "1968": { + "thousands": 46.17 + }, + "1969": { + "thousands": 47.14 + }, + "1970": { + "thousands": 48.49 + }, + "1971": { + "thousands": 46.51 + }, + "1972": { + "thousands": 43.63 + }, + "1973": { + "thousands": 42.08 + }, + "1974": { + "thousands": 41.98 + }, + "1975": { + "thousands": 41.79 + }, + "1976": { + "thousands": 41.82 + }, + "1977": { + "thousands": 42.7 + }, + "1978": { + "thousands": 42.5 + }, + "1979": { + "thousands": 43.7 + }, + "1980": { + "thousands": 44.64 + }, + "1981": { + "thousands": 44.28 + }, + "1982": { + "thousands": 44.48 + }, + "1983": { + "thousands": 43.64 + }, + "1984": { + "thousands": 43.44 + }, + "1985": { + "thousands": 43.77 + }, + "1986": { + "thousands": 43.33 + }, + "1987": { + "thousands": 42.94 + }, + "1988": { + "thousands": 43.78 + }, + "1989": { + "thousands": 44.93 + }, + "1990": { + "thousands": 45.79 + }, + "1991": { + "thousands": 45.0 + }, + "1992": { + "thousands": 44.42 + }, + "1993": { + "thousands": 43.47 + }, + "1994": { + "thousands": 42.48 + }, + "1995": { + "thousands": 41.91 + }, + "1996": { + "thousands": 41.29 + }, + "1997": { + "thousands": 41.25 + }, + "1998": { + "thousands": 41.63 + }, + "1999": { + "thousands": 41.68 + }, + "2000": { + "thousands": 42.53 + }, + "2001": { + "thousands": 41.99 + }, + "2002": { + "thousands": 41.77 + }, + "2003": { + "thousands": 42.26 + }, + "2004": { + "thousands": 42.51 + }, + "2005": { + "thousands": 42.5 + }, + "2006": { + "thousands": 41.24 + } + } + }, + "ssb_chart_4_birth_year_sex": { + "source": "ssb", + "caption_line": 991, + "description": "Chart 4. Number of individuals in EPUF, by year of birth and sex", + "unit": "thousands of persons, 2 decimals", + "rows": { + "1870": { + "men_thousands": 1.48, + "women_thousands": 0.33 + }, + "1871": { + "men_thousands": 1.61, + "women_thousands": 0.4 + }, + "1872": { + "men_thousands": 2.29, + "women_thousands": 0.61 + }, + "1873": { + "men_thousands": 2.41, + "women_thousands": 0.65 + }, + "1874": { + "men_thousands": 2.89, + "women_thousands": 0.9 + }, + "1875": { + "men_thousands": 3.29, + "women_thousands": 1.14 + }, + "1876": { + "men_thousands": 3.79, + "women_thousands": 1.35 + }, + "1877": { + "men_thousands": 3.9, + "women_thousands": 1.49 + }, + "1878": { + "men_thousands": 4.29, + "women_thousands": 1.79 + }, + "1879": { + "men_thousands": 4.52, + "women_thousands": 2.15 + }, + "1880": { + "men_thousands": 5.35, + "women_thousands": 2.61 + }, + "1881": { + "men_thousands": 5.38, + "women_thousands": 2.71 + }, + "1882": { + "men_thousands": 6.2, + "women_thousands": 3.17 + }, + "1883": { + "men_thousands": 6.19, + "women_thousands": 3.35 + }, + "1884": { + "men_thousands": 7.15, + "women_thousands": 4.09 + }, + "1885": { + "men_thousands": 7.08, + "women_thousands": 4.37 + }, + "1886": { + "men_thousands": 7.56, + "women_thousands": 4.58 + }, + "1887": { + "men_thousands": 7.25, + "women_thousands": 4.8 + }, + "1888": { + "men_thousands": 8.7, + "women_thousands": 5.83 + }, + "1889": { + "men_thousands": 8.43, + "women_thousands": 5.81 + }, + "1890": { + "men_thousands": 8.66, + "women_thousands": 6.2 + }, + "1891": { + "men_thousands": 8.45, + "women_thousands": 6.4 + }, + "1892": { + "men_thousands": 9.63, + "women_thousands": 7.2 + }, + "1893": { + "men_thousands": 9.47, + "women_thousands": 7.34 + }, + "1894": { + "men_thousands": 9.62, + "women_thousands": 7.8 + }, + "1895": { + "men_thousands": 9.77, + "women_thousands": 7.95 + }, + "1896": { + "men_thousands": 9.99, + "women_thousands": 8.28 + }, + "1897": { + "men_thousands": 9.71, + "women_thousands": 8.2 + }, + "1898": { + "men_thousands": 10.17, + "women_thousands": 9.02 + }, + "1899": { + "men_thousands": 9.57, + "women_thousands": 8.5 + }, + "1900": { + "men_thousands": 11.24, + "women_thousands": 9.98 + }, + "1901": { + "men_thousands": 10.01, + "women_thousands": 9.0 + }, + "1902": { + "men_thousands": 11.12, + "women_thousands": 9.87 + }, + "1903": { + "men_thousands": 10.92, + "women_thousands": 9.86 + }, + "1904": { + "men_thousands": 11.19, + "women_thousands": 10.51 + }, + "1905": { + "men_thousands": 11.69, + "women_thousands": 10.98 + }, + "1906": { + "men_thousands": 11.72, + "women_thousands": 11.11 + }, + "1907": { + "men_thousands": 12.32, + "women_thousands": 11.46 + }, + "1908": { + "men_thousands": 12.62, + "women_thousands": 12.0 + }, + "1909": { + "men_thousands": 12.78, + "women_thousands": 11.81 + }, + "1910": { + "men_thousands": 13.22, + "women_thousands": 12.39 + }, + "1911": { + "men_thousands": 13.18, + "women_thousands": 12.33 + }, + "1912": { + "men_thousands": 13.88, + "women_thousands": 12.94 + }, + "1913": { + "men_thousands": 13.74, + "women_thousands": 13.14 + }, + "1914": { + "men_thousands": 14.41, + "women_thousands": 13.75 + }, + "1915": { + "men_thousands": 14.3, + "women_thousands": 13.51 + }, + "1916": { + "men_thousands": 14.41, + "women_thousands": 13.47 + }, + "1917": { + "men_thousands": 14.27, + "women_thousands": 13.58 + }, + "1918": { + "men_thousands": 15.16, + "women_thousands": 14.46 + }, + "1919": { + "men_thousands": 14.98, + "women_thousands": 14.05 + }, + "1920": { + "men_thousands": 15.92, + "women_thousands": 15.39 + }, + "1921": { + "men_thousands": 16.24, + "women_thousands": 15.57 + }, + "1922": { + "men_thousands": 15.62, + "women_thousands": 15.41 + }, + "1923": { + "men_thousands": 15.63, + "women_thousands": 15.13 + }, + "1924": { + "men_thousands": 15.82, + "women_thousands": 15.73 + }, + "1925": { + "men_thousands": 15.22, + "women_thousands": 15.34 + }, + "1926": { + "men_thousands": 15.36, + "women_thousands": 14.86 + }, + "1927": { + "men_thousands": 15.38, + "women_thousands": 14.91 + }, + "1928": { + "men_thousands": 15.08, + "women_thousands": 14.67 + }, + "1929": { + "men_thousands": 14.5, + "women_thousands": 14.23 + }, + "1930": { + "men_thousands": 14.91, + "women_thousands": 14.36 + }, + "1931": { + "men_thousands": 14.0, + "women_thousands": 13.6 + }, + "1932": { + "men_thousands": 14.33, + "women_thousands": 13.74 + }, + "1933": { + "men_thousands": 13.44, + "women_thousands": 13.11 + }, + "1934": { + "men_thousands": 13.98, + "women_thousands": 13.49 + }, + "1935": { + "men_thousands": 13.98, + "women_thousands": 13.82 + }, + "1936": { + "men_thousands": 13.96, + "women_thousands": 13.62 + }, + "1937": { + "men_thousands": 14.42, + "women_thousands": 14.17 + }, + "1938": { + "men_thousands": 14.75, + "women_thousands": 14.6 + }, + "1939": { + "men_thousands": 14.82, + "women_thousands": 14.24 + }, + "1940": { + "men_thousands": 15.54, + "women_thousands": 14.95 + }, + "1941": { + "men_thousands": 16.15, + "women_thousands": 15.6 + }, + "1942": { + "men_thousands": 17.89, + "women_thousands": 17.05 + }, + "1943": { + "men_thousands": 18.56, + "women_thousands": 17.71 + }, + "1944": { + "men_thousands": 17.8, + "women_thousands": 17.17 + }, + "1945": { + "men_thousands": 17.87, + "women_thousands": 16.87 + }, + "1946": { + "men_thousands": 21.03, + "women_thousands": 19.93 + }, + "1947": { + "men_thousands": 23.44, + "women_thousands": 21.98 + }, + "1948": { + "men_thousands": 22.71, + "women_thousands": 21.4 + }, + "1949": { + "men_thousands": 23.0, + "women_thousands": 21.73 + }, + "1950": { + "men_thousands": 22.97, + "women_thousands": 21.63 + }, + "1951": { + "men_thousands": 23.92, + "women_thousands": 22.46 + }, + "1952": { + "men_thousands": 24.48, + "women_thousands": 23.05 + }, + "1953": { + "men_thousands": 24.8, + "women_thousands": 23.51 + }, + "1954": { + "men_thousands": 25.81, + "women_thousands": 24.32 + }, + "1955": { + "men_thousands": 26.43, + "women_thousands": 24.87 + }, + "1956": { + "men_thousands": 26.8, + "women_thousands": 24.8 + }, + "1957": { + "men_thousands": 27.59, + "women_thousands": 25.59 + }, + "1958": { + "men_thousands": 27.43, + "women_thousands": 25.55 + }, + "1959": { + "men_thousands": 27.24, + "women_thousands": 25.57 + }, + "1960": { + "men_thousands": 27.5, + "women_thousands": 25.72 + }, + "1961": { + "men_thousands": 27.32, + "women_thousands": 25.5 + }, + "1962": { + "men_thousands": 27.24, + "women_thousands": 25.59 + }, + "1963": { + "men_thousands": 26.93, + "women_thousands": 25.19 + }, + "1964": { + "men_thousands": 26.59, + "women_thousands": 24.77 + }, + "1965": { + "men_thousands": 25.22, + "women_thousands": 23.72 + }, + "1966": { + "men_thousands": 24.18, + "women_thousands": 22.75 + }, + "1967": { + "men_thousands": 23.76, + "women_thousands": 22.25 + }, + "1968": { + "men_thousands": 23.93, + "women_thousands": 22.23 + }, + "1969": { + "men_thousands": 24.16, + "women_thousands": 22.98 + }, + "1970": { + "men_thousands": 24.98, + "women_thousands": 23.5 + }, + "1971": { + "men_thousands": 23.99, + "women_thousands": 22.52 + }, + "1972": { + "men_thousands": 22.6, + "women_thousands": 21.02 + }, + "1973": { + "men_thousands": 21.49, + "women_thousands": 20.59 + }, + "1974": { + "men_thousands": 21.39, + "women_thousands": 20.58 + }, + "1975": { + "men_thousands": 21.33, + "women_thousands": 20.45 + }, + "1976": { + "men_thousands": 21.43, + "women_thousands": 20.39 + }, + "1977": { + "men_thousands": 21.9, + "women_thousands": 20.8 + }, + "1978": { + "men_thousands": 21.8, + "women_thousands": 20.7 + }, + "1979": { + "men_thousands": 22.27, + "women_thousands": 21.42 + }, + "1980": { + "men_thousands": 22.6, + "women_thousands": 22.03 + }, + "1981": { + "men_thousands": 22.67, + "women_thousands": 21.6 + }, + "1982": { + "men_thousands": 22.64, + "women_thousands": 21.84 + }, + "1983": { + "men_thousands": 22.48, + "women_thousands": 21.16 + }, + "1984": { + "men_thousands": 22.03, + "women_thousands": 21.41 + }, + "1985": { + "men_thousands": 22.2, + "women_thousands": 21.56 + }, + "1986": { + "men_thousands": 22.08, + "women_thousands": 21.25 + }, + "1987": { + "men_thousands": 21.92, + "women_thousands": 21.02 + }, + "1988": { + "men_thousands": 22.31, + "women_thousands": 21.46 + }, + "1989": { + "men_thousands": 23.03, + "women_thousands": 21.9 + }, + "1990": { + "men_thousands": 23.41, + "women_thousands": 22.38 + }, + "1991": { + "men_thousands": 22.98, + "women_thousands": 22.03 + }, + "1992": { + "men_thousands": 22.91, + "women_thousands": 21.51 + }, + "1993": { + "men_thousands": 22.32, + "women_thousands": 21.16 + }, + "1994": { + "men_thousands": 21.76, + "women_thousands": 20.72 + }, + "1995": { + "men_thousands": 21.44, + "women_thousands": 20.47 + }, + "1996": { + "men_thousands": 21.23, + "women_thousands": 20.07 + }, + "1997": { + "men_thousands": 20.99, + "women_thousands": 20.26 + }, + "1998": { + "men_thousands": 21.27, + "women_thousands": 20.37 + }, + "1999": { + "men_thousands": 21.42, + "women_thousands": 20.26 + }, + "2000": { + "men_thousands": 21.6, + "women_thousands": 20.93 + }, + "2001": { + "men_thousands": 21.45, + "women_thousands": 20.55 + }, + "2002": { + "men_thousands": 21.32, + "women_thousands": 20.45 + }, + "2003": { + "men_thousands": 21.58, + "women_thousands": 20.68 + }, + "2004": { + "men_thousands": 21.68, + "women_thousands": 20.83 + }, + "2005": { + "men_thousands": 21.77, + "women_thousands": 20.73 + }, + "2006": { + "men_thousands": 21.07, + "women_thousands": 20.18 + } + } + }, + "rsn_table_8_pct_below_max": { + "source": "rsn", + "caption_line": 653, + "description": "Percentage of all, male and female workers with earnings below the taxable maximum, 1951-2006 (Supplement and EPUF columns; EPUF columns are the reproduction target)", + "unit": "percent, 1 decimal", + "rows": { + "1951": { + "supplement_all": 75.5, + "supplement_men": 64.6, + "supplement_women": 96.7, + "epuf_all": 75.4, + "epuf_men": 64.7, + "epuf_women": 96.6 + }, + "1952": { + "supplement_all": 72.1, + "supplement_men": 60.0, + "supplement_women": 95.4, + "epuf_all": 72.2, + "epuf_men": 60.1, + "epuf_women": 95.3 + }, + "1953": { + "supplement_all": 68.8, + "supplement_men": 55.5, + "supplement_women": 93.8, + "epuf_all": 68.8, + "epuf_men": 55.5, + "epuf_women": 93.8 + }, + "1954": { + "supplement_all": 68.4, + "supplement_men": 55.4, + "supplement_women": 93.0, + "epuf_all": 68.4, + "epuf_men": 55.4, + "epuf_women": 93.1 + }, + "1955": { + "supplement_all": 74.4, + "supplement_men": 63.4, + "supplement_women": 95.9, + "epuf_all": 74.7, + "epuf_men": 63.8, + "epuf_women": 95.8 + }, + "1956": { + "supplement_all": 71.6, + "supplement_men": 59.7, + "supplement_women": 94.5, + "epuf_all": 71.8, + "epuf_men": 59.9, + "epuf_women": 94.6 + }, + "1957": { + "supplement_all": 70.1, + "supplement_men": 58.7, + "supplement_women": 93.1, + "epuf_all": 70.2, + "epuf_men": 58.8, + "epuf_women": 93.0 + }, + "1958": { + "supplement_all": 69.4, + "supplement_men": 58.4, + "supplement_women": 91.8, + "epuf_all": 69.6, + "epuf_men": 58.6, + "epuf_women": 91.7 + }, + "1959": { + "supplement_all": 73.3, + "supplement_men": 62.7, + "supplement_women": 94.3, + "epuf_all": 73.3, + "epuf_men": 62.6, + "epuf_women": 94.2 + }, + "1960": { + "supplement_all": 72.0, + "supplement_men": 60.9, + "supplement_women": 93.5, + "epuf_all": 71.9, + "epuf_men": 60.7, + "epuf_women": 93.4 + }, + "1961": { + "supplement_all": 70.8, + "supplement_men": 59.6, + "supplement_women": 92.4, + "epuf_all": 70.8, + "epuf_men": 59.6, + "epuf_women": 92.4 + }, + "1962": { + "supplement_all": 68.8, + "supplement_men": 57.1, + "supplement_women": 91.1, + "epuf_all": 68.8, + "epuf_men": 57.0, + "epuf_women": 91.1 + }, + "1963": { + "supplement_all": 67.5, + "supplement_men": 55.5, + "supplement_women": 90.0, + "epuf_all": 67.4, + "epuf_men": 55.4, + "epuf_women": 90.0 + }, + "1964": { + "supplement_all": 65.5, + "supplement_men": 53.1, + "supplement_women": 88.5, + "epuf_all": 65.5, + "epuf_men": 53.0, + "epuf_women": 88.5 + }, + "1965": { + "supplement_all": 63.9, + "supplement_men": 51.0, + "supplement_women": 87.3, + "epuf_all": 63.9, + "epuf_men": 50.8, + "epuf_women": 87.4 + }, + "1966": { + "supplement_all": 75.8, + "supplement_men": 64.4, + "supplement_women": 95.6, + "epuf_all": 75.7, + "epuf_men": 64.2, + "epuf_women": 95.7 + }, + "1967": { + "supplement_all": 73.6, + "supplement_men": 61.5, + "supplement_women": 94.2, + "epuf_all": 74.0, + "epuf_men": 62.0, + "epuf_women": 94.5 + }, + "1968": { + "supplement_all": 78.6, + "supplement_men": 68.0, + "supplement_women": 96.3, + "epuf_all": 78.6, + "epuf_men": 67.9, + "epuf_women": 96.3 + }, + "1969": { + "supplement_all": 75.5, + "supplement_men": 62.8, + "supplement_women": 96.0, + "epuf_all": 75.8, + "epuf_men": 63.9, + "epuf_women": 95.0 + }, + "1970": { + "supplement_all": 74.0, + "supplement_men": 61.8, + "supplement_women": 93.5, + "epuf_all": 73.9, + "epuf_men": 61.6, + "epuf_women": 93.5 + }, + "1971": { + "supplement_all": 71.7, + "supplement_men": 59.1, + "supplement_women": 91.7, + "epuf_all": 71.6, + "epuf_men": 58.9, + "epuf_women": 91.8 + }, + "1972": { + "supplement_all": 75.0, + "supplement_men": 62.9, + "supplement_women": 93.9, + "epuf_all": 74.9, + "epuf_men": 62.7, + "epuf_women": 93.8 + }, + "1973": { + "supplement_all": 79.7, + "supplement_men": 68.9, + "supplement_women": 96.2, + "epuf_all": 79.6, + "epuf_men": 68.6, + "epuf_women": 96.2 + }, + "1974": { + "supplement_all": 84.9, + "supplement_men": 76.2, + "supplement_women": 97.8, + "epuf_all": 84.8, + "epuf_men": 76.0, + "epuf_women": 97.8 + }, + "1975": { + "supplement_all": 84.9, + "supplement_men": 76.4, + "supplement_women": 97.5, + "epuf_all": 85.0, + "epuf_men": 76.4, + "epuf_women": 97.5 + }, + "1976": { + "supplement_all": 85.1, + "supplement_men": 76.3, + "supplement_women": 97.5, + "epuf_all": 85.0, + "epuf_men": 76.2, + "epuf_women": 97.5 + }, + "1977": { + "supplement_all": 85.2, + "supplement_men": 76.3, + "supplement_women": 97.5, + "epuf_all": 85.2, + "epuf_men": 76.3, + "epuf_women": 97.5 + }, + "1978": { + "supplement_all": 84.6, + "supplement_men": 75.4, + "supplement_women": 97.1, + "epuf_all": 84.6, + "epuf_men": 75.4, + "epuf_women": 97.3 + }, + "1979": { + "supplement_all": 90.0, + "supplement_men": 83.6, + "supplement_women": 98.6, + "epuf_all": 90.1, + "epuf_men": 83.7, + "epuf_women": 98.8 + }, + "1980": { + "supplement_all": 91.2, + "supplement_men": 85.5, + "supplement_women": 98.8, + "epuf_all": 91.3, + "epuf_men": 85.5, + "epuf_women": 98.9 + }, + "1981": { + "supplement_all": 92.4, + "supplement_men": 87.4, + "supplement_women": 99.0, + "epuf_all": 92.4, + "epuf_men": 87.3, + "epuf_women": 99.0 + }, + "1982": { + "supplement_all": 92.9, + "supplement_men": 88.3, + "supplement_women": 98.9, + "epuf_all": 92.9, + "epuf_men": 88.2, + "epuf_women": 99.0 + }, + "1983": { + "supplement_all": 93.7, + "supplement_men": 89.6, + "supplement_women": 99.0, + "epuf_all": 93.7, + "epuf_men": 89.6, + "epuf_women": 99.0 + }, + "1984": { + "supplement_all": 93.6, + "supplement_men": 89.4, + "supplement_women": 98.9, + "epuf_all": 93.6, + "epuf_men": 89.4, + "epuf_women": 98.9 + }, + "1985": { + "supplement_all": 93.5, + "supplement_men": 89.3, + "supplement_women": 98.8, + "epuf_all": 93.5, + "epuf_men": 89.3, + "epuf_women": 98.8 + }, + "1986": { + "supplement_all": 93.8, + "supplement_men": 89.7, + "supplement_women": 98.7, + "epuf_all": 93.8, + "epuf_men": 89.8, + "epuf_women": 98.7 + }, + "1987": { + "supplement_all": 93.9, + "supplement_men": 89.9, + "supplement_women": 98.6, + "epuf_all": 93.8, + "epuf_men": 89.9, + "epuf_women": 98.6 + }, + "1988": { + "supplement_all": 93.5, + "supplement_men": 89.4, + "supplement_women": 98.3, + "epuf_all": 93.5, + "epuf_men": 89.4, + "epuf_women": 98.4 + }, + "1989": { + "supplement_all": 93.8, + "supplement_men": 90.1, + "supplement_women": 98.3, + "epuf_all": 93.8, + "epuf_men": 90.0, + "epuf_women": 98.3 + }, + "1990": { + "supplement_all": 94.3, + "supplement_men": 90.9, + "supplement_women": 98.4, + "epuf_all": 94.3, + "epuf_men": 90.9, + "epuf_women": 98.4 + }, + "1991": { + "supplement_all": 94.4, + "supplement_men": 91.1, + "supplement_women": 98.3, + "epuf_all": 94.4, + "epuf_men": 91.1, + "epuf_women": 98.3 + }, + "1992": { + "supplement_all": 94.3, + "supplement_men": 91.0, + "supplement_women": 98.1, + "epuf_all": 94.3, + "epuf_men": 91.0, + "epuf_women": 98.1 + }, + "1993": { + "supplement_all": 94.4, + "supplement_men": 91.3, + "supplement_women": 98.1, + "epuf_all": 94.4, + "epuf_men": 91.3, + "epuf_women": 98.1 + }, + "1994": { + "supplement_all": 94.6, + "supplement_men": 91.4, + "supplement_women": 98.1, + "epuf_all": 94.6, + "epuf_men": 91.5, + "epuf_women": 98.1 + }, + "1995": { + "supplement_all": 94.2, + "supplement_men": 91.0, + "supplement_women": 97.9, + "epuf_all": 94.2, + "epuf_men": 91.0, + "epuf_women": 97.9 + }, + "1996": { + "supplement_all": 93.9, + "supplement_men": 90.6, + "supplement_women": 97.7, + "epuf_all": 93.9, + "epuf_men": 90.6, + "epuf_women": 97.7 + }, + "1997": { + "supplement_all": 93.8, + "supplement_men": 90.5, + "supplement_women": 97.6, + "epuf_all": 93.8, + "epuf_men": 90.5, + "epuf_women": 97.6 + }, + "1998": { + "supplement_all": 93.7, + "supplement_men": 90.3, + "supplement_women": 97.5, + "epuf_all": 93.7, + "epuf_men": 90.3, + "epuf_women": 97.5 + }, + "1999": { + "supplement_all": 93.9, + "supplement_men": 90.7, + "supplement_women": 97.5, + "epuf_all": 93.9, + "epuf_men": 90.7, + "epuf_women": 97.5 + }, + "2000": { + "supplement_all": 93.8, + "supplement_men": 90.6, + "supplement_women": 97.4, + "epuf_all": 93.8, + "epuf_men": 90.6, + "epuf_women": 97.4 + }, + "2001": { + "supplement_all": 94.1, + "supplement_men": 91.0, + "supplement_women": 97.5, + "epuf_all": 94.0, + "epuf_men": 91.0, + "epuf_women": 97.4 + }, + "2002": { + "supplement_all": 94.6, + "supplement_men": 91.8, + "supplement_women": 97.7, + "epuf_all": 94.5, + "epuf_men": 91.7, + "epuf_women": 97.6 + }, + "2003": { + "supplement_all": 94.5, + "supplement_men": 91.8, + "supplement_women": 97.5, + "epuf_all": 94.5, + "epuf_men": 91.7, + "epuf_women": 97.5 + }, + "2004": { + "supplement_all": 94.1, + "supplement_men": 91.2, + "supplement_women": 97.3, + "epuf_all": 94.1, + "epuf_men": 91.2, + "epuf_women": 97.3 + }, + "2005": { + "supplement_all": 93.9, + "supplement_men": 91.0, + "supplement_women": 97.1, + "epuf_all": 93.9, + "epuf_men": 90.9, + "epuf_women": 97.1 + }, + "2006": { + "supplement_all": 94.0, + "supplement_men": 91.1, + "supplement_women": 97.1, + "epuf_all": 93.9, + "epuf_men": 91.0, + "epuf_women": 97.1 + } + } + } + } +} diff --git a/data/external/epuf_2006/rsn2012-01.source.txt b/data/external/epuf_2006/rsn2012-01.source.txt new file mode 100644 index 00000000..af1b4225 --- /dev/null +++ b/data/external/epuf_2006/rsn2012-01.source.txt @@ -0,0 +1,2028 @@ +Source: https://www.ssa.gov/policy/docs/rsnotes/rsn2012-01.html (Compson, M. 2012. 'Comparing Earnings Estimates from the 2006 Earnings Public-Use File and the Annual Statistical Supplement.' Research and Statistics Note No. 2012-01, SSA). Retrieved 2026-10-01 via browser DOM extraction (curl returns 403). + +Source element:
+--- +Social Security +Comparing Earnings Estimates from the 2006 Earnings Public-Use File and the Annual Statistical Supplement +by Michael Compson +Research and Statistics Note No. 2012-01 (released January 2012) +You are here: Social Security Administration > Research, Statistics & Policy Analysis > Research and Statistics Notes +EmailSave/Print + +Michael Compson is with the Division of Policy Evaluation, Office of Research, Evaluation, and Statistics, Office of Retirement and Disability Policy, Social Security Administration. + +Acknowledgments: The author gratefully acknowledges the assistance of many individuals in the process of creating the 2006 Earnings Public-Use File and this note: John Hennessey for graciously sharing his programming and methodological expertise; Russell Hudson for his programming expertise and sharing his vast knowledge of the earnings data; Scott Muller and Greg Diez for sharing programmatic and earnings knowledge; Sirisha Anne, Brenda South, Stu Friedrich, and Randall Miles for their assistance in providing the data extracts used in the process of creating EPUF; Susan Grad, Howard Iams, Hilary Waldron, and Anya Olsen, for their comments on previous drafts of the paper; and finally, Bill Davis and Justin Ronca for their statistical expertise. + +The findings and conclusions presented in this paper are those of the author and do not necessarily represent the views of the Social Security Administration. + +Introduction +Selected Abbreviations +CWHS Continuous Work History Sample +EPUF Earnings Public-Use File +ESF Earnings Suspense File +MEF Master Earnings File +OCACT Office of the Chief Actuary +ORES Office of Research, Evaluation, and Statistics +SSA Social Security Administration +SSN Social Security number + +The Social Security Administration (SSA) recently released the 2006 Earnings Public-Use File (EPUF).1 The EPUF contains earnings information for individuals drawn from a systematic random 1-percent sample of all Social Security numbers (SSNs) issued before January 2007. EPUF consists of two linkable subfiles. One contains selected demographic and aggregate earnings information for all 4,348,254 individuals in the file, and the second contains annual earnings records for the 3,131,424 individuals who had positive earnings in at least 1 year from 1951 through 2006.2 + +Evaluating the accuracy of the EPUF estimates was a critical step in developing the data file. Starting with 1939 data, SSA has published annual estimates of the number of workers and the value of the earnings covered under the programs it administers. The estimates first appeared in the Social Security Yearbook and, beginning with data for 1949, have been published in the Annual Statistical Supplement to the Social Security Bulletin (hereafter referred to simply as the Supplement). The Office of Research, Evaluation, and Statistics (ORES) produces these estimates using the Continuous Work History Sample (CWHS) sampling frame.3 + +Given that the CWHS and EPUF represent two distinct sampling frames, one expects differences in the earnings estimates derived from each. Besides the different sampling techniques, there are four reasons why the two sets of estimates will differ. First, the two estimates are based on different measures of earnings: The Supplement uses Social Security taxable earnings and EPUF uses capped Social Security taxable earnings. Second, the Supplement estimates are adjusted using factors developed by SSA's Office of the Chief Actuary (OCACT) to account for delinquent or fraudulent reporting of Form W-2 and Form 1040 Schedule SE information. Third, ORES and OCACT use different methodologies for updating historical estimates. Finally, EPUF removes some individuals and some earnings records (which are set equal to $0) from the underlying 1-percent sample to "clean" the data and to prevent disclosing personal information. + +This note identifies and explains the differences between data in EPUF and estimates in the Supplement. It first highlights the factors that contribute to expected differences between the two estimates. It then compares EPUF and Supplement estimates, in turn focusing on earnings, number of workers with earnings, median earnings by sex and age group, and the percentage of workers with earnings below the taxable maximum by sex. After accounting for the expected differences, the note finds that remaining differences between EPUF and Supplement estimates are relatively small. + +Expected Differences in the Estimates + +This discussion distinguishes between the EPUF's underlying sample and the final EPUF data file. The underlying sample refers to a file containing earnings records for 4,413,024 individuals, before data cleaning and disclosure prevention procedures (discussed later) led to the removal of some earnings records. The final EPUF (or, simply, EPUF) contains the earnings records for 4,348,254 individuals. The underlying sample and the EPUF use different earnings measures, explained in the following section. + +Different Measures of Earnings + +All of the earnings data needed to administer the Social Security programs are contained in the Master Earnings File (MEF).4 The MEF consists of 20 segments, each containing specific data fields used for various administrative purposes. The Supplement earnings estimates analyzed here are taken from the MEF summary segment using the CWHS sampling frame.5 In general, the annual earnings data on the MEF summary segment are a running total of an individual's earnings up to the taxable maximum for each job in a given year, plus any taxable self-employment income. For the self-employed, "taxable earnings consists of net self-employment income which, when combined with any taxable wages for that individual, is at or below any applicable annual maximum taxable amount" (SSA 2011, G17). + +MEF data reflect Social Security taxable earnings; that is, all earnings covered under the program subject to the payroll tax. Note that if an individual has more than one employer in a given year, the amount of earnings in this field may exceed the taxable maximum.6 + +The Supplement and the 1-percent MEF sample that underlies the EPUF use the same earnings measure, Social Security taxable earnings. However, in the final EPUF, earnings data for a given year are capped at the taxable maximum.7 Capped Social Security taxable earnings reflect a worker's covered earnings that are subject to the employee share of the payroll tax. + +The following scenario illustrates the differences between the taxable earnings amount in the Supplement tables and the capped taxable earnings contained in EPUF. For a given year, assume the taxable maximum is $50,000 and an individual has covered earnings from two jobs. If the individual earns $60,000 in his first job and $15,000 in a second job, taxable earnings, as shown in the Supplement, would be $65,000 ($50,000 from the first job and $15,000 from the second job). However, the EPUF record would reflect only the capped taxable amount of covered earnings, or the individual's total covered earnings subject to the employee share of the payroll tax ($50,000). Given the difference between taxable earnings (Supplement) and capped taxable earnings (EPUF), one would expect the earnings amount in EPUF to be less than the Supplement earnings estimate. The difference between the two measures of earnings is the amount of covered earnings above the taxable maximum earned from multiple jobs, and it accounts for most of the differences between the Supplement and EPUF earnings estimates. + +Adjustments to Taxable Earnings + +In the Supplement, the estimates of annual taxable earnings and the number of workers with covered earnings reflect adjustments to the raw data pulled from the MEF summary segment. The adjustments attempt to account for two key issues: (1) earnings data for the most recent years are incomplete, and (2) some earnings data reported on W-2 and Schedule SE tax forms may be erroneous or fraudulent. + +In general, by the time data are extracted to generate earnings estimates for the Supplement, approximately 98 percent of the current tax year's earnings data have been posted to the MEF.8 To account for the "missing" data, OCACT generates adjustment factors for the number of workers and the amount of taxable earnings in the extract. The adjustment factors are applied to the raw estimates to approximate the final earnings data expected to be posted to the MEF for the current tax year.9 + +In addition, employers may make errors when reporting employees' Social Security covered earnings, or individuals may use an SSN fraudulently. SSA has a number of procedures that attempt to identify and correct improperly reported earnings information. If these procedures cannot assign earnings information to an SSN, the record is placed in the Earnings Suspense File (ESF). Once the earnings are posted to the ESF, SSA takes additional steps to try to assign the earnings to the appropriate worker. The amount of taxable earnings data posted to the ESF has increased dramatically in recent years (Chart 1), causing a commensurate shortfall in earnings posted to the MEF. OCACT generates adjustment factors to approximate the number of workers and the amount of earnings currently in the ESF that are expected eventually to be posted to the MEF. + +Chart 1. +Value of earnings in the ESF, 1937–2000 (in billions of dollars) +Show as table +SOURCE: SSA (2002). + +These adjustment factors are used solely to generate earnings estimates in the Supplement, and are not included in the EPUF microdata. Instead, the earnings data underlying the EPUF estimates reflect only the earnings data actually posted on the MEF when the data were extracted. + +The adjustment factors are relatively large for the most recent years' estimates and decrease for each earlier year until the adjustments are minimal. With each passing year, the number of additional earnings data items posted to the MEF for a given tax year decreases. With the growing size of the ESF, one would expect to see greater differences between the Supplement estimates and the EPUF estimates for the most recent years, because both the adjustment factors and the amount of earnings not yet reported on the MEF (thus missing from EPUF) are increasing. + +Differences in Historical Estimates + +Data published in the Supplement reflect OCACT estimates of worker counts and covered earnings amounts for all earnings years. When generating the current-year estimates of taxable earnings, ORES revises the latest 3 years of estimates and considers OCACT estimates for all prior years to be relatively unchanged. Thus, Supplement estimates for all but the last 3 years are frozen and do not reflect any W-2 and SE information that may have been posted to the MEF in the intervening years. The differences between the historical estimates in the Supplement and those in EPUF (which include updated earnings data) should be minor. + +Data Cleaning and Disclosure Prevention Procedures + +In creating EPUF, records for some individuals were removed from the underlying sample because of data "cleaning" or because they were included in an existing public-use data file called the New Beneficiary Data System.10 In addition, annual earnings for individuals with earnings at ages 14 or younger or 86 or older were "zeroed out" (set equal to $0) to minimize the risk of personal data disclosure.11 + +Comparing the Estimates + +These comparisons account for two alternative measures of Social Security covered earnings: taxable earnings, as used in the Supplement and the underlying EPUF sample; and earnings capped at the taxable maximum in a given year, as contained in the final EPUF. Directly comparing final EPUF and Supplement earnings estimates would yield somewhat misleading results because (1) each source uses a distinct measure of earnings and (2) the earnings data in EPUF have been adjusted by data cleaning and disclosure prevention procedures. + +In lieu of beginning with a direct comparison, we can compare the estimates for taxable Social Security earnings in the Supplement with those in the underlying EPUF sample. Because these two sources use the same earnings measure, we would expect their estimates to differ only because of (1) differing sampling techniques, (2) OCACT's adjustments to account for delinquent, fraudulent, or erroneous reporting of earnings, and (3) ORES' freezing of historical estimates. Because both sources were created using random sampling, one would expect minimal differences between them. If the OCACT adjustment factors are minimal for all but the most recent years, then one would expect the largest differences for those years. If this comparison reveals substantial differences between the estimates, something is clearly wrong. + +After comparing Supplement and underlying EPUF sample estimates, the next step is to isolate the effects of the two key differences in the earnings data between the underlying EPUF sample and the final EPUF. First, EPUF records reflect earnings capped at the taxable maximum in a given year. Second, some earnings records were removed from the underlying sample because of data "cleaning," and some annual earnings records were zeroed out to protect against personal data disclosure. Therefore, EPUF's capped taxable earnings amounts will be lower than the taxable earnings estimates in the underlying EPUF sample, and will thus differ even further from the Supplement estimates. + +Finally, having established the context of the differences incrementally, we can compare EPUF and Supplement earnings estimates directly. Those comparisons will examine the differences between taxable and capped taxable Social Security earnings and the effects of the data cleaning and disclosure prevention procedures. + +Taxable Earnings in the Underlying EPUF Sample + +Table 1 compares the taxable earnings in the underlying EPUF sample with the taxable earnings in Table 4.B1 in the 2008 Supplement.12 Alongside columns respectively presenting estimates from the Supplement and the underlying EPUF sample, a third column expresses the underlying EPUF sample estimate as a percentage of the Supplement estimate. For 1951–1979 and 1988–1999, the underlying EPUF sample estimates equal at least 99 percent of the Supplement estimates. For 4 years between 1980 and 1987, and in each year 2000 through 2004, the underlying EPUF sample estimate drops to between 98 percent and 99 percent of the Supplement estimate. As expected, the most recent years reflect the largest differences between the two. + +Table 1. +Comparing Supplement and underlying EPUF sample estimates: Taxable earnings, 1951–2006 +Year Supplement +(millions of dollars) Underlying EPUF sample a +(millions of dollars) Underlying EPUF sample estimate as a percentage of the Supplement estimate +1951 120,770 120,685 99.93 +1952 128,640 128,780 100.11 +1953 135,870 135,793 99.94 +1954 133,520 133,418 99.92 +1955 157,540 157,049 99.69 +1956 170,720 170,557 99.90 +1957 181,380 181,804 100.23 +1958 180,720 180,134 99.68 +1959 202,310 201,490 99.59 +1960 207,000 206,733 99.87 +1961 209,640 209,146 99.76 +1962 219,050 218,722 99.85 +1963 225,550 225,218 99.85 +1964 236,390 235,980 99.83 +1965 250,730 249,802 99.63 +1966 312,540 311,661 99.72 +1967 329,960 327,447 99.24 +1968 375,840 374,553 99.66 +1969 402,550 401,416 99.72 +1970 415,600 414,246 99.67 +1971 426,960 425,568 99.67 +1972 484,110 482,467 99.66 +1973 561,850 559,107 99.51 +1974 636,760 634,040 99.57 +1975 664,660 663,172 99.78 +1976 737,700 735,122 99.65 +1977 816,550 812,115 99.46 +1978 915,600 912,637 99.68 +1979 1,067,000 1,066,210 99.93 +1980 1,180,700 1,168,010 98.93 +1981 1,294,100 1,289,800 99.67 +1982 1,365,300 1,353,330 99.12 +1983 1,454,100 1,440,070 99.04 +1984 1,608,800 1,582,920 98.39 +1985 1,722,600 1,705,990 99.04 +1986 1,844,400 1,818,070 98.57 +1987 1,960,000 1,939,170 98.94 +1988 2,088,400 2,082,980 99.74 +1989 2,239,500 2,224,970 99.35 +1990 2,358,000 2,345,130 99.45 +1991 2,422,500 2,407,820 99.39 +1992 2,532,900 2,518,450 99.43 +1993 2,636,100 2,617,920 99.31 +1994 2,785,200 2,770,150 99.46 +1995 2,919,100 2,902,080 99.42 +1996 3,073,500 3,056,440 99.44 +1997 3,285,000 3,265,320 99.40 +1998 3,524,900 3,499,190 99.27 +1999 3,749,600 3,715,600 99.09 +2000 4,008,500 3,965,170 98.92 +2001 4,167,900 4,116,730 98.77 +2002 4,250,100 4,191,910 98.63 +2003 4,355,000 4,292,200 98.56 +2004 4,553,400 b 4,477,300 98.33 +2005 4,765,900 b 4,653,930 97.65 +2006 5,047,755 b 4,884,310 96.76 +SOURCES: SSA (2009, table 4.B1) and author's calculations using underlying EPUF sample. +a. Weighted estimates. +b. 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +Chart 2, which graphs the difference between the estimates expressed as a percentage of the Supplement estimate, shows relatively small differences between the estimates for most years. Except for 1967 and 1977, the estimates for 1951–1979 differ by less than one-half of one percentage point. For 1980–1988, the differences between the estimates are much more volatile and depart from the 1951–1979 trend line. This observation might be due to the transition from quarterly to annual wage reporting for tax year 1978, or to the substantial growth in earnings records assigned to the ESF during that period (Chart 1). It is possible that fewer earnings from the ESF were posted to the MEF during these years than had been expected.13 Although the variance in annual estimates from 1980 to 1988 is two to three times that seen in the other years between 1951 and 1997, the differences are still relatively small, only once exceeding 1.5 percentage points. + +Chart 2. +Percentage point difference between Supplement and underlying EPUF sample estimates of taxable earnings, 1951–2006 +Show as table +SOURCES: SSA (2009, Table 4.B1) and author's calculations using underlying EPUF sample. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +From 1989 through 1997, the difference in estimates is nearly stationary at one-half of one percentage point. However, from 1998 to 2004, there is a steady increase in the gap between the taxable earnings estimates in the underlying EPUF sample and the Supplement. One possible explanation for the growing gap is the increase in earnings assigned to the ESF that are not recorded in the MEF but are reflected in the Supplement estimates. Also, the difference between the estimates for the two most recent years (2005 and 2006) is much larger because the data in the MEF for those years are incomplete. These findings support the initial expectations about differences between the estimates. + +Capped Taxable Earnings in EPUF + +Chart 3 presents the percentage of earnings removed from the underlying EPUF sample due to capping earnings at the annual taxable maximum, removing records from the file for data cleaning, and zeroing out some annual earnings values because of data disclosure concerns.14 The bottom line in Chart 3 reveals that most of the earnings removed from the underlying EPUF sample are the result of capping earnings at the taxable maximum, as opposed to the data cleaning and disclosure prevention procedures (the distance between the lines). + +Chart 3. +Percentage of taxable earnings removed from the underlying EPUF sample, by reason, 1951–2006 +Show as table +SOURCE: Author's calculations using the underlying EPUF sample. + +The amount of earnings removed from the underlying EPUF sample expressed as a percentage of total earnings in that sample (top line in Chart 3) starts at 2.5 percent for 1951 and peaks at just over 3.5 percent for 1965. Beginning with 1966, there is a clear downward trend in the percentage of earnings removed from the underlying sample until 1983 (0.8 percent). From 1984 through 2006, the percentage of earnings removed is less than 1 percent, with the single exception of 2000. + +Comparing EPUF Capped Taxable Earnings and Supplement Taxable Earnings Estimates + +Table 2 shows taxable earnings estimates from Supplement Table 4.B1, weighted capped taxable earnings from the final EPUF, and the latter expressed as a percentage of the former. For years with complete data available, the percentages range from a low of 96.08 percent in 1965 to a high of 98.94 percent in 1988. As expected, the percentages are lower in years with incomplete data, especially 2006. The EPUF estimates are less than 97 percent of the Supplement estimates in only 6 years, with 1971 being the most recent before 2005. + +Table 2. +Comparing Supplement taxable earnings estimates with EPUF capped taxable earnings estimates for 1951–2006 +Year Supplement taxable earnings +(millions of dollars) EPUF capped taxable earnings a +(millions of dollars) EPUF estimate as a percentage of the Supplement estimate +1951 120,770 117,612 97.39 +1952 128,640 125,022 97.19 +1953 135,870 131,531 96.81 +1954 133,520 129,544 97.02 +1955 157,540 153,306 97.31 +1956 170,720 165,936 97.20 +1957 181,380 176,699 97.42 +1958 180,720 175,292 97.00 +1959 202,310 196,513 97.13 +1960 207,000 201,464 97.33 +1961 209,640 203,746 97.19 +1962 219,050 212,491 97.01 +1963 225,550 218,571 96.91 +1964 236,390 228,341 96.60 +1965 250,730 240,891 96.08 +1966 312,540 304,076 97.29 +1967 329,960 318,841 96.63 +1968 375,840 366,269 97.45 +1969 402,550 390,979 97.13 +1970 415,600 403,196 97.02 +1971 426,960 413,893 96.94 +1972 484,110 470,758 97.24 +1973 561,850 547,967 97.53 +1974 636,760 624,356 98.05 +1975 664,660 653,777 98.36 +1976 737,700 724,777 98.25 +1977 816,550 800,761 98.07 +1978 915,600 897,444 98.02 +1979 1,067,000 1,053,555 98.74 +1980 1,180,700 1,155,400 97.86 +1981 1,294,100 1,277,422 98.71 +1982 1,365,300 1,341,341 98.25 +1983 1,454,100 1,428,558 98.24 +1984 1,608,800 1,569,718 97.57 +1985 1,722,600 1,691,658 98.20 +1986 1,844,400 1,803,448 97.78 +1987 1,960,000 1,923,928 98.16 +1988 2,088,400 2,066,191 98.94 +1989 2,239,500 2,207,592 98.58 +1990 2,358,000 2,328,233 98.74 +1991 2,422,500 2,391,171 98.71 +1992 2,532,900 2,500,096 98.70 +1993 2,636,100 2,598,236 98.56 +1994 2,785,200 2,748,015 98.66 +1995 2,919,100 2,877,705 98.58 +1996 3,073,500 3,028,315 98.53 +1997 3,285,000 3,233,638 98.44 +1998 3,524,900 3,463,966 98.27 +1999 3,749,600 3,678,614 98.11 +2000 4,008,500 3,920,050 97.79 +2001 4,167,900 4,076,775 97.81 +2002 4,250,100 4,158,184 97.84 +2003 4,355,000 4,259,092 97.80 +2004 4,553,400 b 4,439,555 97.50 +2005 4,765,900 b 4,612,334 96.78 +2006 5,047,755 b 4,837,317 95.83 +SOURCES: SSA (2009, table 4.B1) and author's calculations using EPUF. +a. Weighted estimates. +b. 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +Chart 4 illustrates the effect of changing the measurement from the taxable earnings used in the underlying EPUF sample to the capped taxable earnings used in the final EPUF. Chart 4's top line shows the percentage point difference between EPUF and Supplement earnings estimates and its bottom line shows the percentage point difference between underlying EPUF sample and Supplement earnings estimates (from Chart 2). Chart 4 provides several points of interest. First, the lines differ widely from 1951 to 1980. Second, the volatility in the differences between the two estimates during 1980–1987 occurs for both earnings measurements, as the two lines move in roughly parallel patterns. Third, beginning in 1981, the gap between the two lines narrows and remains consistent thereafter. + +Chart 4. +Comparing earnings estimates: Percentage point differences between underlying EPUF sample and Supplement estimates and between final EPUF and Supplement estimates: 1951–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, various editions; and author's calculations using EPUF underlying sample and final EPUF. +NOTES: Supplement and underlying EPUF sample use taxable earnings; final EPUF uses capped taxable earnings. +Charted values are the percentage point differences between the indicated estimates and the Supplement estimate. +2008 Supplement estimates for 2004–2006 were based on preliminary data. + +In Chart 5, the black line tracks the spread between the lines shown in Chart 4; that is, it shows the percentage-point difference between EPUF's capped taxable earnings and the Supplement's estimate minus the percentage-point difference between the underlying EPUF sample's taxable earnings and the Supplement estimate. The differences are relatively small and have narrowed considerably over time. Specifically, the gap peaks at 3.6 percentage points in 1965 and drops to just over 1 percentage point in 1980. From 1981 through 2006, the gap remains steady between 0.7 and 1.1 percentage points. + +Chart 5. +Comparing the percentage point spread between the differences in estimates in Chart 4 with the proportion of workers whose earnings exceed the taxable maximum, 1951–2006 +Show as table +SOURCES: SSA (2009, Table 4.B4) and author's calculations using EPUF and the underlying EPUF sample. +NOTES: "Percentage point spread" equals the percentage-point difference between the final EPUF earnings estimate and the Supplement earnings estimate minus the percentage-point difference between the underlying EPUF sample earnings estimate and the Supplement estimate. +2008 Supplement estimates for 2004–2006 are based on preliminary data. + +One possible explanation for the relatively large gap between estimates for 1951–1976 is the much higher percentage of individuals who had earnings above the taxable maximum during those years. As previously noted, the major difference between the taxable earnings in the underlying EPUF sample and the capped earnings in EPUF is that only the latter excludes earnings for workers who have more than one employer and combined earnings above the taxable maximum. As a result, one would expect to see some correlation between the difference in the estimates and the percentage of workers with earnings above the taxable maximum in a given year. The red line in Chart 5 shows the percentage of workers with earnings above the taxable maximum using the scale to the right of the graph. As expected, changes in the percentage of individuals with earnings above the taxable maximum mirror the changes in the differences between taxable earnings and EPUF earnings estimates. The volatility in the percentage of individuals with earnings above the taxable maximum from 1951 to 1970 reflects Congress' ad hoc adjustments of the taxable maximum during these years. Legislation enacted in 1972 instituted automatic annual increases that took effect with the taxable maximum for 1975.15 + +Chart 6 presents the number of workers whose combined taxable earnings from multiple employers exceed the taxable maximum in a given year. The pattern mirrors those of both lines in Chart 5. These findings support initial expectations about capped taxable earnings in EPUF relative to Supplement estimates. + +Chart 6. +Number of workers in the underlying EPUF sample with multiple employers and earnings exceeding the taxable maximum, 1951–2006 +Show as table +SOURCE: Author's calculations using the underlying EPUF sample. + +Comparing the aggregate earnings estimates derived from the underlying EPUF sample, the final EPUF file, and the Supplement leads to two conclusions: (1) taxable earnings estimates in the underlying EPUF sample and the Supplement do not differ widely; and (2) most of the differences between the final EPUF and Supplement earnings estimates stem from the use of two different measures (taxable and capped taxable earnings) and from OCACT adjustments incorporated in the Supplement estimates to account for delinquent posting of earnings data and potentially fraudulent use of SSNs. + +The next sections compare Supplement and final EPUF estimates of the number of workers by sex and age, the median value of taxable earnings by sex and age, and the percentage of workers with earnings below the taxable maximum by sex. + +Number of Workers + +Supplement Table 4.B3 contains estimates of the number of workers with covered earnings in a given year, by sex. Table 3 compares Supplement and underlying EPUF sample estimates of the number of workers for 1951–2006.16 Alongside columns presenting the estimates themselves, a third column shows the underlying EPUF sample estimate expressed as a percentage of the Supplement estimate. The estimates differ very little: With one exception (1978), the underlying EPUF sample estimate is within 1 percentage point of the Supplement estimate from 1951 through 1999. As expected, the biggest differences between the estimates occur for the most recent years, when the data are incomplete and OCACT's adjustment factors play a more prominent role in the Supplement estimates. From 2000 through 2004, the percentages drop below 99 percent; for 2005 and 2006, they drop further, to less than 98 percent. + +The next column shows the number of annual earnings records in the underlying EPUF sample removed because of data cleaning or zeroed out to meet data disclosure requirements. The final column reveals that the percentage of underlying EPUF sample records removed or zeroed out is very small, less than 1 percent each year. + +Table 3. +Comparing Supplement and underlying EPUF sample estimates: Number of workers with any earnings during the year, 1951–2006 +Year Supplement (thousands) Underlying EPUF sample (thousands) Underlying EPUF sample estimate as a percentage of the Supplement estimate Earnings records removed or zeroed out from underlying EPUF sample (thousands) Underlying EPUF sample earnings records removed or zeroed out (%) +1951 58,120 57,907 99.63 441 0.76 +1952 59,580 59,501 99.87 462 0.78 +1953 60,840 60,589 99.59 458 0.76 +1954 59,610 59,447 99.73 393 0.66 +1955 65,200 65,039 99.75 452 0.69 +1956 67,610 67,596 99.98 473 0.70 +1957 70,590 70,627 100.05 467 0.66 +1958 69,770 69,901 100.19 418 0.60 +1959 71,700 71,477 99.69 422 0.59 +1960 72,530 72,428 99.86 427 0.59 +1961 72,820 72,702 99.84 420 0.58 +1962 74,280 74,220 99.92 413 0.56 +1963 75,540 75,458 99.89 427 0.57 +1964 77,430 77,360 99.91 431 0.56 +1965 80,680 80,447 99.71 463 0.58 +1966 84,600 84,520 99.91 521 0.62 +1967 87,040 86,465 99.34 535 0.62 +1968 89,380 89,169 99.76 574 0.64 +1969 92,060 92,080 100.02 619 0.67 +1970 93,090 92,659 99.54 607 0.65 +1971 93,340 92,893 99.52 602 0.65 +1972 96,240 95,793 99.54 653 0.68 +1973 99,830 99,501 99.67 732 0.74 +1974 101,330 101,068 99.74 744 0.74 +1975 100,200 100,067 99.87 678 0.68 +1976 102,600 102,524 99.93 684 0.67 +1977 105,800 105,753 99.96 728 0.69 +1978 110,600 109,178 98.71 782 0.72 +1979 112,700 111,792 99.19 757 0.68 +1980 113,000 112,364 99.44 690 0.61 +1981 113,000 112,447 99.51 645 0.57 +1982 111,800 110,998 99.28 590 0.53 +1983 112,100 112,093 99.99 572 0.51 +1984 116,300 116,425 100.11 632 0.54 +1985 119,800 119,949 100.12 672 0.56 +1986 122,900 122,294 99.51 640 0.52 +1987 125,600 125,350 99.80 664 0.53 +1988 129,600 129,312 99.78 714 0.55 +1989 131,700 131,774 100.06 738 0.56 +1990 133,600 132,705 99.33 667 0.50 +1991 133,000 132,114 99.33 598 0.45 +1992 134,000 132,967 99.23 598 0.45 +1993 136,100 135,061 99.24 626 0.46 +1994 138,200 137,921 99.80 673 0.49 +1995 141,000 140,160 99.40 661 0.47 +1996 143,400 142,468 99.35 674 0.47 +1997 146,145 145,132 99.31 685 0.47 +1998 148,786 147,955 99.44 707 0.48 +1999 151,333 150,355 99.35 697 0.46 +2000 154,732 152,906 98.82 712 0.47 +2001 155,416 153,131 98.53 666 0.43 +2002 154,893 152,564 98.50 608 0.40 +2003 154,576 152,634 98.74 570 0.37 +2004 156,250 a 154,106 98.63 556 0.36 +2005 158,913 a 155,594 97.91 534 0.34 +2006 161,205 a 156,814 97.28 534 0.34 +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B3, various editions; and author's calculations using underlying EPUF sample. +a. 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +Table 4 compares the Supplement and final EPUF estimates of the number of covered workers, with detail by sex. From 1951 through 2004, the final EPUF estimates represent at least 98 percent of the Supplement estimates. As expected, the percentages drop for 2005 and 2006 because of incomplete data and OCACT adjustments. + +Table 4. +Comparing Supplement and EPUF estimates: Number of all, male, and female workers with any earnings during the year, 1951–2006 +Year Supplement +(thousands) EPUF a +(thousands) EPUF estimate as a percentage of Supplement estimate +All b Men Women All b Men Women All Men Women +1951 58,120 38,520 19,600 57,467 38,067 19,366 98.88 98.82 98.80 +1952 59,580 39,190 20,390 59,038 38,718 20,284 99.09 98.79 99.48 +1953 60,840 39,800 21,040 60,131 39,271 20,825 98.83 98.67 98.98 +1954 59,610 39,090 20,520 59,054 38,690 20,332 99.07 98.98 99.08 +1955 65,200 43,140 22,060 64,587 42,686 21,862 99.06 98.95 99.10 +1956 67,610 44,620 22,990 67,123 44,187 22,893 99.28 99.03 99.58 +1957 70,590 47,190 23,400 70,161 46,833 23,286 99.39 99.24 99.51 +1958 69,770 46,690 23,080 69,483 46,418 23,029 99.59 99.42 99.78 +1959 71,700 47,630 24,070 71,055 47,117 23,904 99.10 98.92 99.31 +1960 72,530 47,900 24,630 72,000 47,460 24,509 99.27 99.08 99.51 +1961 72,820 47,990 24,830 72,282 47,551 24,701 99.26 99.09 99.48 +1962 74,280 48,650 25,360 73,807 48,259 25,519 99.36 99.20 100.63 +1963 75,540 49,280 26,260 75,031 48,895 26,108 99.33 99.22 99.42 +1964 77,430 50,260 27,170 76,929 49,917 26,983 99.35 99.32 99.31 +1965 80,680 51,990 28,690 79,984 51,437 28,518 99.14 98.94 99.40 +1966 84,600 53,570 30,870 83,999 53,197 30,774 99.29 99.30 99.69 +1967 87,040 54,820 32,220 85,930 54,000 31,901 98.72 98.50 99.01 +1968 89,380 55,870 33,510 88,595 55,192 33,373 99.12 98.79 99.59 +1969 92,060 56,980 35,080 91,462 56,423 35,007 99.35 99.02 99.79 +1970 93,090 57,330 35,760 92,053 56,545 35,475 98.89 98.63 99.20 +1971 93,340 57,320 36,020 92,291 56,568 35,691 98.88 98.69 99.09 +1972 96,240 58,610 37,630 95,141 57,824 37,284 98.86 98.66 99.08 +1973 99,830 60,220 39,610 98,769 59,349 39,384 98.94 98.55 99.43 +1974 101,330 60,520 40,810 100,324 59,752 40,538 99.01 98.73 99.33 +1975 100,200 59,520 40,680 99,389 58,914 40,440 99.19 98.98 99.41 +1976 102,600 60,340 42,260 101,839 59,817 41,989 99.26 99.13 99.36 +1977 105,800 61,620 44,180 105,025 61,129 43,862 99.27 99.20 99.28 +1978 110,600 63,960 46,640 108,397 62,538 45,825 98.01 97.78 98.25 +1979 112,700 64,529 48,171 111,035 63,513 47,490 98.52 98.43 98.59 +1980 113,000 64,288 48,712 111,674 63,431 48,210 98.83 98.67 98.97 +1981 113,000 63,984 49,016 111,802 63,282 48,489 98.94 98.90 98.93 +1982 111,800 63,089 48,711 110,408 62,280 48,097 98.75 98.72 98.74 +1983 112,100 62,881 49,219 111,520 62,568 48,921 99.48 99.50 99.40 +1984 116,300 64,700 51,600 115,793 64,463 51,298 99.56 99.63 99.41 +1985 119,800 66,113 53,687 119,277 65,912 53,334 99.56 99.70 99.34 +1986 122,900 67,412 55,488 121,654 66,831 54,793 98.99 99.14 98.75 +1987 125,600 68,591 57,009 124,686 68,171 56,484 99.27 99.39 99.08 +1988 129,600 70,596 59,004 128,598 70,096 58,471 99.23 99.29 99.10 +1989 131,700 71,517 60,183 131,036 71,173 59,833 99.50 99.52 99.42 +1990 133,600 72,291 61,309 132,038 71,467 60,542 98.83 98.86 98.75 +1991 133,000 71,787 61,213 131,516 70,968 60,520 98.88 98.86 98.87 +1992 134,000 72,016 61,984 132,369 71,162 61,180 98.78 98.81 98.70 +1993 136,100 73,154 62,946 134,435 72,201 62,207 98.78 98.70 98.83 +1994 138,200 73,989 64,211 137,247 73,432 63,788 99.31 99.25 99.34 +1995 141,000 75,444 65,556 139,500 74,509 64,965 98.94 98.76 99.10 +1996 143,400 76,241 67,158 141,794 75,513 66,256 98.88 99.05 98.66 +1997 146,145 77,498 68,647 144,448 76,681 67,741 98.84 98.95 98.68 +1998 148,786 78,671 70,115 147,247 77,959 69,264 98.97 99.09 98.79 +1999 151,333 80,042 71,291 149,657 79,138 70,495 98.89 98.87 98.88 +2000 154,732 81,654 73,078 152,194 80,278 71,892 98.36 98.31 98.38 +2001 155,416 82,006 73,410 152,465 80,389 72,053 98.10 98.03 98.15 +2002 154,893 81,568 73,325 151,956 79,953 71,980 98.10 98.02 98.17 +2003 154,576 81,263 73,313 152,064 79,843 72,199 98.37 98.25 98.48 +2004 156,250 c 82,008 c 74,242 c 153,551 80,526 73,001 98.27 98.19 98.33 +2005 158,913 c 83,202 c 75,711 c 155,060 81,236 73,801 97.58 97.64 97.48 +2006 161,205 c 84,181 c 77,024 c 156,280 81,576 74,681 96.94 96.91 96.96 +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B3, various editions; and author's calculations using EPUF. +a. Weighted estimates. +b. Includes a small number of workers whose sex was coded as "unknown." +c. 2008 Supplement estimates for 2004–2006 were based on preliminary data. +Workers by Age + +Supplement Table 4.B5 shows the estimated number of workers by age group. Unfortunately, some age categories are not defined consistently throughout the 1951–2006 period. Specifically, subcategories for those aged 60 or older from 1951 to 1959 differ from those used from 1960 through 2006. As a result, estimates for those aged 60 or older are shown only for 1960 and later. + +Charts 7 and 8 compare EPUF and Supplement estimates of the number of workers with earnings by age group from 1951 to 2006. Both charts show EPUF estimates expressed as a percentage of the Supplement estimate. + +Chart 7 looks at workers younger than age 60. In general, the differences between the estimates are very small, although estimates for individuals younger than age 20 clearly diverge starting in 1971. Data disclosure restrictions require EPUF to zero out earnings for those aged 14 or younger, accounting for much of this divergence. When the estimates for the number of workers in this age category are adjusted to include the earnings that were zeroed out, there is virtually no difference between the EPUF and Supplement estimates. + +Chart 7. +EPUF estimates of the number of workers as a percentage of the Supplement estimate, workers younger than age 60 by age group, 1951–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B5, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +Chart 8 focuses on workers aged 60 or older. Although EPUF and Supplement estimates differ somewhat more for the 60–71 age group than for their younger counterparts, they differ much more for individuals aged 72 or older. For that group, the EPUF estimates are lower than the Supplement estimates across all years, and there is a distinct gap between the estimates for 1985 through 1998. The gap begins to narrow in 1999, but it remains somewhat larger than that for workers aged 60–71. The finding raises two critical questions: Why does this large gap occur only for 1985–1998, and why only for workers aged 72 or older? + +Chart 8. +EPUF estimates of the number of workers as a percentage of the Supplement estimate, workers aged 60 or older by age group, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B5, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +The first attempt to answer these questions involves evaluating how the EPUF data cleaning and disclosure prevention requirements affect the estimated number of workers aged 72 or older. Chart 9 presents three measures of workers aged 72 or older as percentages of the Supplement estimate. The top line shows the full underlying EPUF sample estimate. The middle line represents the underlying sample after removing records because of data cleaning (for example, records with dubious age-at-earnings values) and for disclosure prevention (individuals that overlapped with the New Beneficiary Data System). The bottom line, showing the final EPUF after zeroing out earnings for workers aged 86 or older, replicates Chart 8's line for workers aged 72 or older. The short distance between the bottom line and the middle line shows the minimal effect of zeroing out the earnings of individuals aged 86 or older. The distance between the middle line and the top line shows that the effect of removing individuals for data cleaning and disclosure prevention is also generally small, although it is somewhat larger than the effect of zeroing out earnings for individuals aged 86 or older.17 + +Chart 9. +Effects of EPUF data cleaning and disclosure prevention measures: Estimated number of workers aged 72 or older as a percentage of the Supplement estimate, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B5, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +More significantly, the EPUF estimates (bottom line) and those from the underlying EPUF sample (top line) differ very consistently across the years. Thus, the distinct gap between the EPUF and Supplement estimates from 1985 through 1998 clearly does not result from the data cleaning or the disclosure prevention procedures applied to the underlying EPUF sample. It seems very peculiar that the estimates from the underlying EPUF sample are extremely close to the Supplement estimates except for these particular years. What, then, explains this anomalous gap? + +A second approach is to compare the number of workers aged 72 or older in the EPUF with the number of workers in the active file within the 2008 version of the CWHS. The active file contains individuals in the 1-percent CWHS who have had any covered earnings since the program's inception. One would expect these two distinct 1-percent samples to produce very similar estimates of the number of workers aged 72 or older. The top line in Chart 10 shows the number of workers in EPUF expressed as a percentage of the number of workers in the active CWHS file and confirms that the estimates are indeed very similar. The bottom line shows the number of workers in the active CWHS file aged 72 or older as a percentage of the Supplement estimates. The gap between these two ratios is nearly identical to the differences between the EPUF and Supplement estimates for this age group. + +Chart 10. +Comparison of estimates of number of workers aged 72 or older: EPUF, CWHS, and Supplement, 1980–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, various editions; and author's calculations using 2008 CWHS active file and EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +The fact that the estimates from two distinct 1-percent samples are nearly the same indicates that there may be problems with the Supplement estimates for older workers during this period. One possible explanation is that a programming or coding error affected only those workers, and the error was corrected as part of the Y2K adjustments made to the MEF. Nonetheless, the Supplement estimates reflect the earnings data in the MEF at that time. Given the close relationship between EPUF's underlying 1-percent sample and the active CWHS file, the number of workers in EPUF aged 72 or older is presumably correct. + +Charts 11–14 compare EPUF and Supplement estimates of the number of workers by age group and sex. For men younger than 60, Chart 11 reveals very little difference between the estimates. As expected, EPUF estimates as a percentage of Supplement estimates decline slightly for the most recent years. As was seen with all workers, estimates of the number of men aged 60 or older (Chart 12) differ more widely than estimates of the number of younger men. The distinct gap between EPUF and Supplement estimates of all workers aged 72 or older from 1985 through 1998 also occurs for men. + +Chart 11. +EPUF estimates of the number of male workers as a percentage of the Supplement estimate, workers younger than 60 by age group, 1951–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B5, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. +Chart 12. +EPUF estimates of the number of male workers as a percentage of the Supplement estimate, workers aged 60 or older by age group, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B5, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +For female workers younger than age 60, Chart 13 reveals that EPUF and Supplement estimates differ slightly more than do those of their male counterparts. After 1980, the estimates differ only minimally. As was true for men, EPUF and Supplement estimates for female workers aged 60 or older (Chart 14) differ more than those for younger women. In general, the EPUF estimates of older female workers appear to slightly exceed Supplement estimates from 1960 through 1974 but are lower from 1975 onward. + +Chart 13. +EPUF estimates of the number of female workers as a percentage of the Supplement estimate, workers younger than age 60 by age group, 1951–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B5, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. +Chart 14. +EPUF estimates of the number of female workers as a percentage of the Supplement estimate, workers aged 60 or older by age group, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B5, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. +Median Earnings By Sex and Age + +This section compares EPUF estimates of median earnings with those presented in Supplement Table 4.B6. In turns, the discussion examines median earnings for all workers, workers by sex, all workers by age, and then workers by sex and age. + +Table 5 compares the median earnings for all, male, and female workers for 1951–2006. The EPUF estimate for all workers is at least 98.44 percent of the Supplement estimate in all years, and in fact slightly exceeds the Supplement estimate for most years. The pattern for men is very similar. For women, the EPUF estimate is much lower than the Supplement estimate in many years; for nine in particular, the EPUF estimate represents less than 98 percent of the Supplement estimate. + +Table 5. +Comparing Supplement and EPUF estimates: Median earnings for all, male, and female workers, 1951–2006 +Year Supplement (dollars) EPUF (dollars) EPUF estimate as a percentage of Supplement estimate +All Men Women All Men Women All Men Women +1951 2,097 2,838 1,192 2,100 2,900 1,200 100.14 102.18 100.67 +1952 2,258 3,046 1,278 2,300 3,100 1,300 101.86 101.77 101.72 +1953 2,400 3,275 1,357 2,400 3,300 1,300 100.00 100.76 95.80 +1954 2,425 3,263 1,374 2,400 3,300 1,400 98.97 101.13 101.89 +1955 2,438 3,315 1,351 2,400 3,300 1,300 98.44 99.55 96.23 +1956 2,599 3,546 1,454 2,600 3,500 1,500 100.04 98.70 103.16 +1957 2,651 3,538 1,544 2,700 3,600 1,500 101.85 101.75 97.15 +1958 2,674 3,516 1,589 2,700 3,500 1,600 100.97 99.54 100.69 +1959 2,837 3,783 1,634 2,800 3,800 1,600 98.70 100.45 97.92 +1960 2,894 3,879 1,679 2,900 3,900 1,700 100.21 100.54 101.25 +1961 2,938 3,936 1,742 2,900 3,900 1,700 98.71 99.09 97.59 +1962 3,058 4,132 1,808 3,100 4,100 1,800 101.37 99.23 99.56 +1963 3,149 4,266 1,856 3,100 4,300 1,800 98.44 100.80 96.98 +1964 3,298 4,480 1,945 3,300 4,500 1,900 100.06 100.45 97.69 +1965 3,414 4,685 1,984 3,400 4,754 2,000 99.59 101.47 100.81 +1966 3,566 5,010 2,082 3,600 5,000 2,000 100.95 99.80 96.06 +1967 3,716 5,208 2,259 3,700 5,200 2,200 99.57 99.85 97.39 +1968 3,945 5,546 2,435 4,000 5,600 2,400 101.39 100.97 98.56 +1969 4,173 5,933 2,585 4,200 6,000 2,600 100.65 101.13 100.58 +1970 4,375 6,180 2,735 4,400 6,200 2,700 100.57 100.32 98.72 +1971 4,605 6,475 2,882 4,600 6,500 2,900 99.89 100.39 100.62 +1972 4,870 6,923 2,983 4,900 7,000 3,000 100.62 101.11 100.57 +1973 5,184 7,473 3,148 5,200 7,500 3,100 100.31 100.36 98.48 +1974 5,531 7,972 3,435 5,500 8,000 3,400 99.44 100.35 98.98 +1975 5,803 8,250 3,730 5,800 8,300 3,700 99.95 100.61 99.20 +1976 6,235 8,883 4,063 6,300 8,900 4,100 101.04 100.19 100.91 +1977 6,630 9,489 4,358 6,700 9,600 4,300 101.06 101.17 98.67 +1978 7,204 10,279 4,856 7,300 10,400 4,900 101.33 101.18 100.91 +1979 7,930 11,258 5,433 7,900 11,300 5,400 99.62 100.37 99.39 +1980 8,549 11,963 6,012 8,600 12,000 6,000 100.60 100.31 99.80 +1981 9,361 12,941 6,690 9,400 13,000 6,700 100.42 100.46 100.15 +1982 9,924 13,318 7,232 9,900 13,300 7,200 99.76 99.86 99.56 +1983 10,322 13,687 7,618 10,300 13,700 7,600 99.79 100.09 99.76 +1984 10,757 14,360 7,878 10,900 14,500 7,900 101.33 100.97 100.28 +1985 11,265 14,959 8,293 11,400 15,100 8,300 101.20 100.94 100.08 +1986 11,831 15,579 8,796 11,900 15,600 8,800 100.58 100.13 100.05 +1987 12,327 16,073 9,261 12,300 16,100 9,300 99.78 100.17 100.42 +1988 12,825 16,613 9,753 12,900 16,600 9,800 100.58 99.92 100.48 +1989 13,314 17,014 10,265 13,400 17,200 10,300 100.65 101.09 100.34 +1990 13,898 17,582 10,837 14,000 17,800 10,900 100.73 101.24 100.58 +1991 14,278 17,765 11,369 14,400 17,900 11,400 100.85 100.76 100.27 +1992 14,739 18,208 11,842 14,900 18,400 11,900 101.09 101.05 100.49 +1993 15,000 18,430 12,093 15,100 18,700 12,100 100.67 101.47 100.06 +1994 15,560 19,249 12,422 15,600 19,400 12,400 100.26 100.78 99.82 +1995 16,108 19,907 12,897 16,200 20,000 12,900 100.57 100.47 100.02 +1996 16,712 20,779 13,335 16,800 20,800 13,400 100.53 100.10 100.49 +1997 17,562 21,814 14,043 17,600 21,900 14,100 100.22 100.39 100.41 +1998 18,513 23,028 14,834 18,600 23,100 14,900 100.47 100.31 100.44 +1999 19,265 23,927 15,465 19,400 24,100 15,600 100.70 100.72 100.87 +2000 20,225 25,032 16,287 20,300 25,200 16,400 100.37 100.67 100.69 +2001 20,905 25,643 17,037 21,000 25,700 17,100 100.45 100.22 100.37 +2002 21,193 25,765 17,461 21,300 25,900 17,500 100.50 100.52 100.22 +2003 21,610 26,173 17,845 21,700 26,300 18,000 100.42 100.49 100.87 +2004 22,342 a 27,074 a 18,427 a 22,500 27,200 18,500 100.71 100.47 100.40 +2005 22,983 a 27,895 a 18,892 a 23,100 28,000 19,000 100.51 100.38 100.57 +2006 23,832 a 28,916 a 19,586 a 24,000 29,100 19,700 100.70 100.64 100.58 +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B6, various editions; and author's calculations using EPUF. +a. 2008 Supplement estimates were based on preliminary data. + +Chart 15 reveals the minimal differences between the EPUF and Supplement estimates of median earnings for all workers younger than age 60. Chart 16 shows much more variation for workers aged 60 or older. The greatest variation is for individuals aged 72 or older and it occurs during the same years that showed the greatest differences in the estimated numbers of individuals with earnings (Chart 8). + +Chart 15. +EPUF estimates of median earnings as a percentage of the Supplement estimate, all workers younger than age 60 by age group, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B6, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. +Chart 16. +EPUF estimates of median earnings as a percentage of the Supplement estimate, all workers aged 60 or older by age group, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B6, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +For men younger than age 60, EPUF median earnings estimates differ substantially from Supplement estimates for 1960–1973 (Chart 17). The greatest difference appears for 1965, when the EPUF estimate is approximately 74 percent of the Supplement estimate for those aged 35–49. How and why do such large differences occur, and why only from 1960 through 1973?18 + +Chart 17. +EPUF estimates of median earnings as a percentage of the Supplement estimate, male workers younger than age 60 by age group, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B6, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +Supplement Table 4.B6 alerts readers that "the amount of median earnings includes estimates above the taxable maximum." For 1951–1977, those estimates are based on data from earnings reports filed quarterly by employers. SSA began collecting "detailed" earnings information annually from W-2 forms in 1978, but earnings above the taxable maximum were still open to some conjecture through 1993.19 Starting in 1994, all covered earnings were subject to the Medicare payroll tax; thus, records reflected actual earnings, and estimates of amounts above the taxable maximum were no longer necessary. + +If adjustments for earnings above the taxable maximum were made for all years from 1951 through 2006, why do the relatively large differences occur only from 1960 through 1973? Adjustments would affect median earnings only if the preadjustment median value exceeds the taxable maximum. In other words, if the preadjustment median value is less than the taxable maximum, then the additional earnings would not affect the median. + +The methodology SSA used through 1994 to estimate earnings above the taxable maximum is not readily available. However, we can determine whether EPUF estimates of median earnings appear reasonable for the years in which they are much lower than Supplement estimates. If EPUF's median earnings for men in certain age groups is greater than or equal to the taxable maximum in a given year, then we know that any earnings above the taxable maximum will affect the median. Table 6 presents EPUF estimates of median earnings for men as a percentage of the taxable maximum for 1960–1980.20 Shaded cells indicate the years in which one should expect the Supplement medians to be greater than the taxable maximum. Table 7 presents the median earnings values from Supplement Table 4.B6 expressed as a percentage of the taxable maximum; the same cells are shaded as those in Table 6, with one exception (1973, for individuals aged 35–39). + +Tables 6 and 7 explain the findings in Chart 17. The EPUF estimates of median earnings for some age categories of male workers are much lower than the Supplement estimates because the EPUF estimates do not account for earnings above the taxable maximum, while the Supplement estimates do. The Supplement's adjustments for earnings above the taxable maximum increase the estimated median earnings for some age groups in years when the median value exceeds the taxable maximum. However, the median values fall below the taxable maximums for all age groups after 1973, and adjustments for earnings above the taxable maximum no longer affect median values. Thus, EPUF and Supplement median earnings estimates differ minimally from 1973 through 2006. + +Table 6. +EPUF estimates of median earnings for men as a percentage of the taxable maximum amount, by age group, 1960–1980 +Year 19 or younger 20–24 25–29 30–34 35–39 40–44 45–49 50–54 55–59 60–61 62–64 65–69 70–71 72 or older +1960 12.89 44.42 82.35 100.00 100.00 100.00 100.00 98.44 91.50 83.75 79.85 48.44 24.96 28.44 +1961 12.90 43.53 82.98 100.00 100.00 100.00 100.00 100.00 94.64 86.56 81.68 48.57 25.00 29.17 +1962 13.43 44.73 88.10 100.00 100.00 100.00 100.00 100.00 100.00 92.19 85.53 49.23 25.00 29.86 +1963 12.76 46.19 91.73 100.00 100.00 100.00 100.00 100.00 100.00 95.31 88.95 47.57 24.90 29.00 +1964 13.26 50.04 97.70 100.00 100.00 100.00 100.00 100.00 100.00 100.00 94.11 49.84 25.00 29.38 +1965 14.61 54.89 100.00 100.00 100.00 100.00 100.00 100.00 100.00 100.00 98.94 54.73 25.00 30.67 +1966 12.03 40.86 83.00 98.10 100.00 100.00 100.00 98.25 91.12 83.17 76.10 36.83 22.25 22.92 +1967 12.06 39.27 86.99 100.00 100.00 100.00 100.00 100.00 95.02 87.53 80.01 38.30 22.59 24.85 +1968 10.94 35.98 79.27 93.79 99.95 100.00 100.00 94.55 86.13 80.19 72.24 32.19 20.55 21.74 +1969 11.78 39.51 85.73 100.00 100.00 100.00 100.00 100.00 93.45 85.45 78.02 32.39 20.96 22.83 +1970 11.82 42.31 88.49 100.00 100.00 100.00 100.00 100.00 97.55 91.07 81.52 36.14 21.31 23.53 +1971 11.84 44.75 90.82 100.00 100.00 100.00 100.00 100.00 100.00 97.12 84.95 37.09 21.53 24.24 +1972 11.37 45.91 82.72 100.00 100.00 100.00 100.00 100.00 98.81 90.00 78.99 32.14 18.55 22.20 +1973 10.81 42.19 73.24 93.84 100.00 100.00 100.00 99.13 91.04 83.00 70.85 25.66 18.22 20.01 +1974 9.70 36.94 62.86 81.75 87.96 90.55 90.83 87.32 80.61 73.20 62.89 20.45 16.65 17.56 +1975 8.91 34.58 60.13 79.54 86.27 89.06 89.56 86.78 79.28 71.85 61.60 19.73 16.15 17.09 +1976 9.02 34.22 59.48 78.65 87.14 89.26 90.57 87.71 81.08 72.67 60.93 18.61 16.34 16.47 +1977 8.84 34.19 58.07 77.66 87.56 89.62 90.79 87.64 81.34 75.14 60.82 18.44 16.03 16.64 +1978 9.30 35.17 58.91 77.69 89.00 91.47 92.57 89.86 83.72 76.80 63.09 21.92 16.95 16.77 +1979 8.05 29.64 49.30 64.39 74.42 77.11 77.20 75.92 70.85 63.77 53.65 19.03 14.51 14.26 +1980 7.22 27.09 45.98 59.99 69.66 72.70 72.88 71.57 67.16 60.41 51.21 18.77 14.09 13.43 +SOURCE: Author's calculations using EPUF. +Table 7. +Supplement estimates of median earnings for men as a percentage of the taxable maximum amount, by age group, 1960–1980 +Year 19 or younger 20–24 25–29 30–34 35–39 40–44 45–49 50–54 55–59 60–61 62–64 65–69 70–71 72 or older +1960 12.81 44.08 82.13 100.65 107.81 107.65 103.21 97.96 92.00 82.96 79.42 44.00 25.15 27.92 +1961 12.96 43.29 82.42 102.56 110.42 110.81 107.77 100.90 94.69 84.90 82.60 44.17 25.58 28.60 +1962 13.46 44.19 87.19 107.38 116.25 118.06 113.44 106.33 100.77 92.08 85.98 46.73 24.75 29.17 +1963 12.75 46.08 90.98 111.75 120.42 122.44 117.94 110.77 104.54 97.23 89.56 48.10 24.77 28.79 +1964 13.44 49.83 97.13 117.67 126.06 128.60 126.44 117.31 110.69 101.06 93.83 52.52 24.79 29.75 +1965 14.79 54.35 103.27 126.15 135.02 135.81 132.69 123.35 116.27 104.02 99.67 54.75 25.96 30.06 +1966 12.44 40.56 82.58 97.32 104.56 106.42 104.56 98.03 90.95 83.88 76.61 36.14 21.92 23.47 +1967 12.09 38.97 86.53 102.05 108.38 110.14 109.12 102.94 94.71 88.30 80.71 37.82 22.29 23.36 +1968 10.87 35.74 78.90 93.51 99.37 101.35 100.33 94.73 86.41 80.82 72.51 33.91 20.53 21.55 +1969 11.67 39.33 85.26 100.08 105.60 108.10 107.33 101.95 93.95 86.99 77.94 35.96 21.18 22.62 +1970 11.92 42.06 87.53 104.24 109.33 111.36 112.22 107.31 98.40 90.40 82.77 37.53 21.31 23.88 +1971 12.05 31.62 90.68 108.50 112.55 118.35 117.22 112.79 104.71 95.36 86.83 38.10 21.40 24.55 +1972 11.47 45.68 82.28 102.89 109.22 111.33 110.67 107.44 99.80 90.03 79.64 32.26 18.69 22.34 +1973 10.82 42.01 72.94 93.61 99.35 102.13 101.94 99.47 91.68 83.19 71.55 25.91 18.06 20.52 +1974 9.66 36.88 62.85 81.45 87.47 90.14 90.27 87.70 80.91 73.86 62.61 21.33 16.48 17.61 +1975 8.84 34.54 60.03 79.22 86.04 88.89 89.40 87.02 80.07 73.74 61.70 20.53 16.14 16.82 +1976 8.90 33.99 58.92 78.59 86.46 89.05 90.27 87.68 81.44 73.41 62.10 19.37 15.92 16.94 +1977 8.86 34.09 57.73 77.35 86.85 89.36 90.13 88.12 82.27 74.32 62.32 19.02 15.78 16.52 +1978 9.28 34.95 58.55 77.24 88.82 90.96 92.20 89.79 84.54 76.71 63.15 21.89 16.86 17.39 +1979 7.96 29.66 49.37 64.23 74.17 76.72 77.08 75.45 71.27 64.76 53.63 19.40 14.66 14.52 +1980 7.17 27.05 45.87 59.81 69.08 72.28 72.96 71.01 67.90 61.54 50.97 18.93 14.12 13.63 +SOURCE: SSA, Annual Statistical Supplement to the Social Security Bulletin, various editions. + +Chart 18 presents EPUF estimates of median earnings as a percentage of Supplement estimates for male workers aged 60 or older and reveals more divergence than was seen for younger workers, especially for men aged 72 or older. Most of the variation occurs in the same years for which EPUF and Supplement estimates of number of workers vary. + +Chart 18. +EPUF estimates of median earnings as a percentage of the Supplement estimate, male workers aged 60 or older by age group, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B6, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. + +Chart 19 shows minimal differences between EPUF and Supplement median earnings estimates for female workers younger than age 60. Chart 20 reveals much more variation between the estimates for female workers aged 60 or older, mirroring the pattern of divergence seen for older men. + +Chart 19. +EPUF estimates of median earnings as a percentage of the Supplement estimate, female workers younger than age 60 by age group, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B6, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. +Chart 20. +EPUF estimates of median earnings as a percentage of the Supplement estimate, female workers aged 60 or older by age group, 1960–2006 +Show as table +SOURCES: SSA, Annual Statistical Supplement to the Social Security Bulletin, Table 4.B6, various editions; and author's calculations using EPUF. +NOTE: 2008 Supplement estimates for 2004–2006 were based on preliminary data. +Percentage of Workers with Earnings Below the Taxable Maximum + +Supplement Table 4.B4 contains estimates of the percentage of all workers with earnings below the taxable maximum amount beginning in 1951. Table 8 compares the EPUF estimates with those found in the Supplement. Few of the estimates differ by more than one-tenth of a percentage point. For all workers, the largest difference between the estimates occurs in 1967, where the EPUF estimate is 0.6 percent greater than the Supplement estimate. The largest difference in the estimates of workers by sex is seen for 1969, in which EPUF estimates are 1.7 percent higher for men and 1.0 percent lower for women than the Supplement estimates. Apart from these and scattered other modest differences, the EPUF and Supplement estimates scarcely differ. + +Table 8. +Comparing Supplement and EPUF estimates: Percentage of all, male, and female workers with earnings below the taxable maximum amount, 1951–2006 +Year Supplement a EPUF EPUF estimate as a percentage of Supplement estimate +All Men Women All Men Women All Men Women +1951 75.5 64.6 96.7 75.4 64.7 96.6 99.9 100.1 99.9 +1952 72.1 60.0 95.4 72.2 60.1 95.3 100.2 100.2 99.9 +1953 68.8 55.5 93.8 68.8 55.5 93.8 100.0 100.0 100.0 +1954 68.4 55.4 93.0 68.4 55.4 93.1 100.0 100.0 100.1 +1955 74.4 63.4 95.9 74.7 63.8 95.8 100.4 100.7 99.9 +1956 71.6 59.7 94.5 71.8 59.9 94.6 100.2 100.4 100.1 +1957 70.1 58.7 93.1 70.2 58.8 93.0 100.1 100.2 99.9 +1958 69.4 58.4 91.8 69.6 58.6 91.7 100.2 100.3 99.9 +1959 73.3 62.7 94.3 73.3 62.6 94.2 99.9 99.9 99.9 +1960 72.0 60.9 93.5 71.9 60.7 93.4 99.8 99.7 99.9 +1961 70.8 59.6 92.4 70.8 59.6 92.4 100.0 99.9 100.0 +1962 68.8 57.1 91.1 68.8 57.0 91.1 100.0 99.9 100.0 +1963 67.5 55.5 90.0 67.4 55.4 90.0 99.9 99.8 100.0 +1964 65.5 53.1 88.5 65.5 53.0 88.5 100.0 99.8 100.0 +1965 63.9 51.0 87.3 63.9 50.8 87.4 100.0 99.7 100.1 +1966 75.8 64.4 95.6 75.7 64.2 95.7 99.9 99.7 100.1 +1967 73.6 61.5 94.2 74.0 62.0 94.5 100.6 100.8 100.3 +1968 78.6 68.0 96.3 78.6 67.9 96.3 100.0 99.9 100.0 +1969 75.5 62.8 96.0 75.8 63.9 95.0 100.4 101.7 99.0 +1970 74.0 61.8 93.5 73.9 61.6 93.5 99.8 99.7 100.0 +1971 71.7 59.1 91.7 71.6 58.9 91.8 99.9 99.6 100.1 +1972 75.0 62.9 93.9 74.9 62.7 93.8 99.9 99.7 99.9 +1973 79.7 68.9 96.2 79.6 68.6 96.2 99.9 99.6 100.0 +1974 84.9 76.2 97.8 84.8 76.0 97.8 99.9 99.7 100.0 +1975 84.9 76.4 97.5 85.0 76.4 97.5 100.1 100.0 100.1 +1976 85.1 76.3 97.5 85.0 76.2 97.5 99.9 99.9 100.0 +1977 85.2 76.3 97.5 85.2 76.3 97.5 99.9 99.9 100.0 +1978 84.6 75.4 97.1 84.6 75.4 97.3 100.0 99.9 100.2 +1979 90.0 83.6 98.6 90.1 83.7 98.8 100.2 100.1 100.2 +1980 91.2 85.5 98.8 91.3 85.5 98.9 100.1 100.0 100.1 +1981 92.4 87.4 99.0 92.4 87.3 99.0 100.0 99.9 100.0 +1982 92.9 88.3 98.9 92.9 88.2 99.0 100.0 99.9 100.1 +1983 93.7 89.6 99.0 93.7 89.6 99.0 100.0 100.0 100.0 +1984 93.6 89.4 98.9 93.6 89.4 98.9 100.0 100.0 100.0 +1985 93.5 89.3 98.8 93.5 89.3 98.8 100.0 100.0 100.0 +1986 93.8 89.7 98.7 93.8 89.8 98.7 100.0 100.1 100.0 +1987 93.9 89.9 98.6 93.8 89.9 98.6 99.9 100.0 100.0 +1988 93.5 89.4 98.3 93.5 89.4 98.4 100.0 100.0 100.1 +1989 93.8 90.1 98.3 93.8 90.0 98.3 100.0 99.9 100.0 +1990 94.3 90.9 98.4 94.3 90.9 98.4 100.0 100.0 100.0 +1991 94.4 91.1 98.3 94.4 91.1 98.3 100.0 100.0 100.0 +1992 94.3 91.0 98.1 94.3 91.0 98.1 100.0 100.0 100.0 +1993 94.4 91.3 98.1 94.4 91.3 98.1 100.0 100.0 100.0 +1994 94.6 91.4 98.1 94.6 91.5 98.1 100.0 100.1 100.0 +1995 94.2 91.0 97.9 94.2 91.0 97.9 100.0 99.9 100.0 +1996 93.9 90.6 97.7 93.9 90.6 97.7 100.0 100.0 100.0 +1997 93.8 90.5 97.6 93.8 90.5 97.6 100.0 100.0 100.0 +1998 93.7 90.3 97.5 93.7 90.3 97.5 100.0 100.0 100.0 +1999 93.9 90.7 97.5 93.9 90.7 97.5 100.0 100.0 100.0 +2000 93.8 90.6 97.4 93.8 90.6 97.4 100.0 100.0 100.0 +2001 94.1 91.0 97.5 94.0 91.0 97.4 99.9 100.0 99.9 +2002 94.6 91.8 97.7 94.5 91.7 97.6 99.9 99.9 99.9 +2003 94.5 91.8 97.5 94.5 91.7 97.5 100.0 99.9 100.0 +2004 94.1 b 91.2 b 97.3 b 94.1 91.2 97.3 100.0 100.0 100.0 +2005 93.9 b 91.0 b 97.1 b 93.9 90.9 97.1 100.0 99.9 100.0 +2006 94.0 b 91.1 b 97.1 b 93.9 91.0 97.1 99.9 99.8 100.0 +SOURCES: SSA (2009, Table 4.B4) and author's calculations using EPUF. +a. From 1937 to 1950, relates to wage and salary workers. Beginning in 1951, includes self-employed workers. +b. 2008 Supplement estimates were based on preliminary data. +Summary + +This analysis compares the earnings data contained in EPUF with estimates published in the Annual Statistical Supplement to the Social Security Bulletin. The analysis presents four reasons why one should expect differences between the estimates beyond those due to the different sampling frames used to generate the respective 1-percent samples. + +First, the Supplement estimates are based on taxable earnings, which can sum to more than the Social Security taxable maximum for multiple jobholders, whereas the EPUF reflects only capped taxable earnings. Second, EPUF data cleaning and disclosure prevention measures reduce the number of records with earnings and the amount of earnings reported. Third, the Supplement estimates reflect adjustments to account for delinquent, erroneous, and potentially fraudulent reporting of earnings information to SSA. Fourth, the Supplement updates only the three most recent years of estimates. As a result, older estimates are frozen and do not reflect any subsequent changes in the MEF. EPUF earnings data reflect the continuously updated MEF and contain the most recent earnings data reported to SSA. + +The analysis began by comparing estimates of taxable earnings in the underlying EPUF sample with those in the Supplement. Those estimates proved very similar and supported the expectation that the biggest differences would be for the most recent years. Although there was some divergence between the estimates from the underlying EPUF sample and the Supplement estimates from 1980 through 1988, those differences were relatively minor. + +In general, the other differences between EPUF and Supplement earnings estimates are relatively small after accounting for expected differences. The key differences are largely attributable to EPUF's use of capped taxable earnings and the removal of some records due to data cleaning and disclosure prevention procedures. + +There were, however, two unexpected differences between EPUF and Supplement estimates: Specifically, estimates of the number of workers by age group and sex, and the value of median earnings by age and sex. The distribution of individuals who have earnings when they are 72 years old or older in EPUF is nearly identical to that in the active file of the CWHS, indicating that EPUF represents the current state of the earnings data contained in the MEF, even though it differs from the Supplement estimates. Median earnings estimates differ because Supplement estimates are adjusted to account for estimated earnings above the taxable maximum and EPUF estimates are not. + +Appendix + +EPUF's two linkable subfiles differ in structure and in the ways the data cleaning and disclosure protection procedures affect them. The demographic and aggregate earnings subfile uses a person-record format containing a single record for each of the 4,348,254 individuals in the EPUF. Each record contains the individual's EPUF identification code, year of birth, sex, aggregate taxable earnings from 1937 through 1950, aggregate quarters of coverage earned from 1937 through 1950, and quarters of coverage earned in 1951 and 1952. Appendix Table A-2 presents an illustrative listing of 20 hypothetical demographic and aggregate earnings subfile records. The annual earnings subfile is a vertical-event history file that contains a single record for each year with positive earnings for each person in EPUF. Every earnings-year record contains the individual's EPUF identification code, capped taxable earnings, and earned quarters of coverage. The annual earnings subfile contains 60,326,474 records for the 3,131,424 individuals who had at least 1 year of positive earnings from 1951 through 2006. Appendix Table A-3 presents an illustrative listing of 41 earnings years for four hypothetical earners. + +Nearly 28 percent of the individuals in EPUF had no positive annual earnings from 1951 through 2006. These individuals have a record in the demographic and aggregate earnings subfile, but no records in the annual earnings subfile. + +The MEF 1-percent sample underlying the EPUF contained records for 4,413,024 individuals. Data "cleaning" led to the removal of records for 28,770 individuals; those records had dubious or missing year-of-birth values, coding errors, or other issues. Then, to protect against disclosure of personal data, earnings records for individuals aged 14 or younger or 86 or older were zeroed out, effectively removing those records from the annual earnings subfile (because the subfile only contains records with positive earnings values). However, setting those earnings equal to $0 does not affect the individual's record in the demographic and aggregate earnings subfile. + +Table A-1. +Taxable earnings amounts removed from underlying EPUF sample by reason for removal, 1951–2006 +Year Total taxable earnings in underlying EPUF sample (million $) Capping (earnings exceeding the taxable maximum) Data cleaning and disclosure prevention Total earnings removed from underlying EPUF sample +Dollars (in millions) As a percentage of taxable earnings Dollars (in millions) As a percentage of taxable earnings Dollars (in millions) As a percentage of taxable earnings +1951 1,206.9 24.8 2.06 5.7 0.47 30.5 2.53 +1952 1,287.8 31.3 2.43 5.9 0.46 37.2 2.89 +1953 1,357.9 36.3 2.67 6.0 0.44 42.3 3.11 +1954 1,334.2 32.7 2.45 5.9 0.44 38.5 2.89 +1955 1,570.5 30.2 1.92 7.0 0.44 37.2 2.37 +1956 1,705.6 38.3 2.25 7.5 0.44 45.8 2.69 +1957 1,818.0 43.0 2.37 7.6 0.42 50.6 2.78 +1958 1,801.3 40.6 2.25 7.4 0.41 48.0 2.67 +1959 2,014.9 41.2 2.04 8.1 0.40 49.3 2.45 +1960 2,067.3 44.0 2.13 8.2 0.40 52.1 2.52 +1961 2,091.5 45.3 2.17 8.1 0.39 53.4 2.55 +1962 2,187.2 53.4 2.44 8.3 0.38 61.7 2.82 +1963 2,252.2 57.4 2.55 8.5 0.38 65.9 2.92 +1964 2,359.8 66.9 2.84 8.8 0.37 75.7 3.21 +1965 2,498.0 79.1 3.17 9.2 0.37 88.3 3.54 +1966 3,116.6 63.6 2.04 11.3 0.36 74.9 2.40 +1967 3,274.5 73.4 2.24 11.6 0.36 85.0 2.60 +1968 3,745.5 68.5 1.83 13.1 0.35 81.6 2.18 +1969 4,014.2 89.2 2.22 13.7 0.34 102.9 2.56 +1970 4,142.5 95.2 2.30 13.8 0.33 108.9 2.63 +1971 4,255.7 101.1 2.38 14.1 0.33 115.2 2.71 +1972 4,824.7 99.5 2.06 15.6 0.32 115.2 2.39 +1973 5,591.1 91.4 1.63 17.6 0.32 109.0 1.95 +1974 6,340.4 74.4 1.17 19.7 0.31 94.0 1.48 +1975 6,631.7 70.9 1.07 20.1 0.30 91.0 1.37 +1976 7,351.2 78.8 1.07 21.5 0.29 100.3 1.37 +1977 8,121.2 87.0 1.07 22.8 0.28 109.8 1.35 +1978 9,126.4 122.7 1.34 24.3 0.27 147.0 1.61 +1979 10,662.1 93.7 0.88 27.3 0.26 121.0 1.13 +1980 11,680.1 92.1 0.79 28.2 0.24 120.3 1.03 +1981 12,898.0 89.7 0.70 28.2 0.22 118.0 0.91 +1982 13,533.3 85.8 0.63 28.0 0.21 113.8 0.84 +1983 14,400.7 80.5 0.56 28.3 0.20 108.9 0.76 +1984 15,829.2 96.0 0.61 29.2 0.18 125.2 0.79 +1985 17,059.9 105.7 0.62 30.0 0.18 135.7 0.80 +1986 18,180.7 108.5 0.60 30.4 0.17 138.9 0.76 +1987 19,391.7 114.6 0.59 30.3 0.16 144.8 0.75 +1988 20,829.8 130.6 0.63 30.2 0.14 160.8 0.77 +1989 22,249.7 135.5 0.61 30.7 0.14 166.2 0.75 +1990 23,451.3 130.9 0.56 30.8 0.13 161.7 0.69 +1991 24,078.2 130.3 0.54 29.8 0.12 160.0 0.67 +1992 25,184.5 146.3 0.58 30.6 0.12 177.0 0.70 +1993 26,179.2 158.5 0.61 31.2 0.12 189.8 0.72 +1994 27,701.5 182.0 0.66 32.2 0.12 214.2 0.77 +1995 29,020.8 202.9 0.70 33.0 0.11 235.9 0.81 +1996 30,564.4 239.0 0.78 33.9 0.11 272.8 0.89 +1997 32,654.2 271.4 0.83 35.5 0.11 306.9 0.94 +1998 34,991.9 303.9 0.87 37.3 0.11 341.2 0.98 +1999 37,156.0 318.3 0.86 38.9 0.10 357.3 0.96 +2000 39,651.7 398.2 1.00 40.2 0.10 438.4 1.11 +2001 41,167.3 345.0 0.84 40.5 0.10 385.5 0.94 +2002 41,919.1 283.0 0.68 40.1 0.10 323.1 0.77 +2003 42,922.0 275.9 0.64 39.7 0.09 315.6 0.74 +2004 44,773.0 319.6 0.71 40.7 0.09 360.3 0.80 +2005 46,539.3 358.1 0.77 40.5 0.09 398.6 0.86 +2006 48,843.1 411.4 0.84 40.4 0.08 451.8 0.93 +Total 871,600.1 7,387.7 0.85 1,267.6 0.15 8,655.3 0.99 +SOURCE: Author's calculations using underlying EPUF sample. +Table A-2. +Illustrative examples of person records in the EPUF Demographic and Aggregate Earnings subfile +ID number Year of birth (YOB) Sex a Total covered earnings ($) (TOT_COV_EARN3750) Quarters of coverage 1937–1950 (QC3750) Quarters of coverage 1951–1952 (QC5152) +1 1973 1 0 0 0 +2 1976 2 0 0 0 +3 1917 2 9,300 18 3 +4 1947 2 0 0 0 +5 1983 1 0 0 0 +6 1927 2 0 0 0 +7 1995 2 0 0 0 +8 1996 2 0 0 0 +9 1931 1 39 0 2 +10 1984 2 0 0 0 +11 1961 2 0 0 0 +12 1983 2 0 0 0 +13 1914 2 13,100 26 0 +14 1918 1 9,400 18 7 +15 1932 2 225 2 0 +16 1978 2 0 0 0 +17 1937 1 0 0 0 +18 1945 2 0 0 0 +19 1985 1 0 0 0 +20 1921 1 15,900 31 6 +SOURCE: Author's reconstruction based on EPUF. +a. 1 = male, 2 = female. +Table A-3. +Illustrative examples of earnings-year records in the EPUF Annual Earnings subfile +ID number Year with earnings (YEAR_EARN) Quarters of coverage (ANNUAL_QTRS) Capped taxable earnings ($) (ANNUAL_EARNINGS) +1 1998 4 7,500 +1 1999 4 10,000 +1 2000 4 16,200 +1 2001 4 24,000 +1 2002 4 15,900 +1 2004 3 3,600 +1 2005 4 20,500 +1 2006 4 24,300 +2 1993 2 1,600 +2 1994 4 2,600 +2 1995 3 2,100 +2 1996 4 4,500 +2 1997 4 7,600 +2 1998 4 22,700 +2 1999 4 16,900 +2 2000 4 26,300 +2 2001 4 33,200 +2 2002 4 36,300 +2 2003 4 41,900 +2 2004 4 42,100 +2 2005 4 38,500 +2 2006 4 29,800 +3 1951 0 550 +3 1952 0 325 +3 1953 4 575 +3 1954 3 2,000 +3 1955 3 1,600 +4 1966 1 675 +4 1967 4 3,200 +4 1968 4 4,000 +4 1969 4 4,400 +4 1970 4 4,800 +4 1971 4 5,000 +4 1972 4 5,300 +4 1973 4 5,800 +4 1974 4 6,300 +4 1975 4 7,200 +4 1976 4 8,000 +4 1977 4 8,600 +4 1978 4 6,600 +4 1980 4 3,000 +SOURCE: Author's reconstruction based on EPUF. +Notes + + 1 For an introduction to the EPUF, see Compson (2011). + + 2 See appendix for more details on the structure of the two subfiles. + + 3 The CWHS is a longitudinal database produced by ORES for internal research and statistical purposes. SSA is authorized to share the CWHS with the Treasury Department's Offices of Economic Policy and Tax Analysis and with the Congressional Budget Office. For more information about the CWHS, see Buckler (1988) and Smith (1989). + + 4 For information on the MEF, see Olsen and Hudson (2009). + + 5 Some Supplement tables are based on CWHS annual files. However, this analysis examines Supplement earnings tables based on the MEF 1-percent sample, an extract of earnings data from the MEF summary segment using the CWHS sampling frame, which selects a random sample of records based on certain serial digits of the SSN. + + 6 Although other circumstances may account for records with taxable earnings above the taxable maximum, the vast majority of cases involve earnings from multiple employers. + + 7 Capping earnings at the taxable maximum in a given year eliminates the need to top-code this data field. + + 8 Posting all the information from the W-2s and selected information from Schedule SE is a massive annual undertaking. The MEF is continuously updated as additional W-2 and Schedule SE information is reported, or previously reported earnings are corrected. For more details, see Olsen and Hudson (2009). + + 9 For example, suppose that the total amount of taxable earnings on the MEF was $98 and the expected total amount of earnings posted to the MEF was $100. The adjustment factor in this case would be 1.0204082. ORES would multiply the aggregate earnings on the MEF for this tax year by the adjustment factor to generate an estimate of $100 in the Supplement. + +10 For more details, see Compson (2011). + +11 For example, if an individual has annual earnings in each year between ages 12 and 62, the EPUF earnings records would reflect $0 for ages 12, 13, and 14 years old and all of the individual's other earnings records would remain unchanged. + +12 Supplement figures cited in this note are primarily from the 2008 edition, the most recent Supplement consulted for this analysis. + +13 As noted earlier, Supplement estimates make use of OCACT adjustment factors for the number of workers and the amount of earnings reported to the ESF. Those adjustment factors are beyond the scope of this analysis. + +14 Appendix Table A-1 contains the data for Chart 3. + +15 Taxable maximums for 1979 through 1981 were set by legislation. Those for 1990 through 1992 were set using a transitional rule. See SSA (2011, Tables 2.A3 and 2.A18). + +16 Supplement Tables 4.B3, 4.B5, and 4.B6 present annual data only for the most recent years. Data for prior periods are shown only for selected years—specifically, for 1937 and then at 5-year intervals from 1940 until annual coverage begins. Therefore, beginning with Table 3, most of this note's charts and tables draw data from various editions of the Supplement, always using the most recent edition that presented data for a particular year. + +17 There is no overlap between the individuals removed from the file due to dubious age values and those whose earnings at ages 86 or older were zeroed out. See appendix for more information. + +18 As previously noted, the age subcategories used in the Supplement for individuals aged 60 or older are not consistent throughout the 1951–2006 period. For that reason, the analysis is limited to 1960 through 2006. + +19 The cap for covered earnings subject to the Medicare payroll tax was higher than the taxable maximum for the Social Security program in 1992 and 1993, and was removed altogether in 1994. + +20 The period 1960–1980 contains the only years in which men's median taxable earnings in EPUF are equal to the taxable maximum. + +References + +Buckler, Warren. 1988. "Commentary: Continuous Work History Sample." Social Security Bulletin 51(4): 12, 56. + +Compson, Michael. 2011. "The 2006 Earnings Public-Use Microdata File: An Introduction." Social Security Bulletin 71(4): 33–59. + +Olsen, Anya, and Russell Hudson. 2009. "Social Security Administration's Master Earnings File: Background Information." Social Security Bulletin 69(3): 29–45. + +Smith, Creston M. 1989. "The Social Security Administration's Continuous Work History Sample." Social Security Bulletin 52(10): 20–28. + +[SSA] Social Security Administration. 2002. Congressional Response Report: Status of the Social Security Administration's Earnings Suspense File. Report No. A-03-03-23038. Baltimore, MD: SSA, Office of the Inspector General. + +———. 2009. Annual Statistical Supplement to the Social Security Bulletin, 2008. Washington, DC: SSA, ORES. + +———. 2011. Annual Statistical Supplement to the Social Security Bulletin, 2010. Washington, DC: SSA, ORES. + +==== APPENDIX (added at extraction): chart "Show as table" equivalents ==== +These tables are hidden in the page default view (Show as table toggles) and therefore absent from the visible text above. Extracted from the page DOM 2026-10-01; cells tab-separated. + +### Table equivalent for Chart 1. Value of earnings in the ESF, 1937–2000 (in billions of dollars) +Year Earnings(billions of dollars) +1937 0.32 +1938 0.15 +1939 0.13 +1940 0.10 +1941 0.16 +1942 0.24 +1943 0.24 +1944 0.18 +1945 0.20 +1946 0.22 +1947 0.23 +1948 0.24 +1949 0.19 +1950 0.21 +1951 0.33 +1952 0.31 +1953 0.28 +1954 0.26 +1955 0.42 +1956 0.44 +1957 0.48 +1958 0.43 +1959 0.46 +1960 0.43 +1961 0.39 +1962 0.42 +1963 0.42 +1964 0.48 +1965 0.57 +1966 0.77 +1967 0.97 +1968 1.10 +1969 1.30 +1970 1.36 +1971 1.37 +1972 1.77 +1973 2.17 +1974 2.20 +1975 1.97 +1976 2.26 +1977 3.02 +1978 3.60 +1979 5.16 +1980 6.22 +1981 7.09 +1982 6.84 +1983 7.32 +1984 8.49 +1985 10.49 +1986 11.79 +1987 12.36 +1988 10.10 +1989 7.42 +1990 9.29 +1991 9.82 +1992 11.43 +1993 14.76 +1994 16.26 +1995 18.66 +1996 22.30 +1997 26.20 +1998 31.20 +1999 39.00 +2000 49.40 + + +### Table equivalent for Chart 2. Percentage point difference between Supplement and underlying EPUF sample estimates of taxable earnings, 1951–2006 +Year Percentage point difference +1951 0.07 +1952 -0.11 +1953 0.06 +1954 0.08 +1955 0.31 +1956 0.10 +1957 -0.23 +1958 0.32 +1959 0.41 +1960 0.13 +1961 0.24 +1962 0.15 +1963 0.15 +1964 0.17 +1965 0.37 +1966 0.28 +1967 0.76 +1968 0.34 +1969 0.28 +1970 0.33 +1971 0.33 +1972 0.34 +1973 0.49 +1974 0.43 +1975 0.22 +1976 0.35 +1977 0.54 +1978 0.32 +1979 0.07 +1980 1.07 +1981 0.33 +1982 0.88 +1983 0.96 +1984 1.61 +1985 0.96 +1986 1.43 +1987 1.06 +1988 0.26 +1989 0.65 +1990 0.55 +1991 0.61 +1992 0.57 +1993 0.69 +1994 0.54 +1995 0.58 +1996 0.56 +1997 0.60 +1998 0.73 +1999 0.91 +2000 1.08 +2001 1.23 +2002 1.37 +2003 1.44 +2004 1.67 +2005 2.35 +2006 3.24 + + +### Table equivalent for Chart 3. Percentage of taxable earnings removed from the underlying EPUF sample, by reason, 1951–2006 +Year Capping taxable earnings Capping taxable earnings, data cleaning, and disclosure prevention +1951 2.06 2.54 +1952 2.43 2.90 +1953 2.67 3.13 +1954 2.45 2.90 +1955 1.92 2.37 +1956 2.25 2.70 +1957 2.37 2.79 +1958 2.25 2.67 +1959 2.04 2.46 +1960 2.13 2.53 +1961 2.17 2.56 +1962 2.44 2.83 +1963 2.55 2.93 +1964 2.84 3.22 +1965 3.17 3.55 +1966 2.04 2.41 +1967 2.24 2.60 +1968 1.83 2.18 +1969 2.22 2.57 +1970 2.30 2.64 +1971 2.38 2.72 +1972 2.06 2.39 +1973 1.63 1.95 +1974 1.17 1.49 +1975 1.07 1.38 +1976 1.07 1.37 +1977 1.07 1.36 +1978 1.34 1.61 +1979 0.88 1.14 +1980 0.79 1.03 +1981 0.70 0.92 +1982 0.63 0.84 +1983 0.56 0.76 +1984 0.61 0.79 +1985 0.62 0.80 +1986 0.60 0.76 +1987 0.59 0.75 +1988 0.63 0.77 +1989 0.61 0.75 +1990 0.56 0.69 +1991 0.54 0.67 +1992 0.58 0.70 +1993 0.61 0.73 +1994 0.66 0.77 +1995 0.70 0.81 +1996 0.78 0.89 +1997 0.83 0.94 +1998 0.87 0.98 +1999 0.86 0.96 +2000 1.00 1.11 +2001 0.84 0.94 +2002 0.68 0.77 +2003 0.64 0.74 +2004 0.71 0.81 +2005 0.77 0.86 +2006 0.84 0.93 + + +### Table equivalent for Chart 4. Comparing earnings estimates: Percentage point differences between underlying EPUF sample and Supplement estimates and between final EPUF and Supplement estimates: 1951–2006 +Year Underlying EPUF sample Final EPUF +1951 0.07 2.61 +1952 -0.11 2.81 +1953 0.06 3.19 +1954 0.08 2.98 +1955 0.31 2.69 +1956 0.10 2.80 +1957 -0.23 2.58 +1958 0.32 3.00 +1959 0.41 2.87 +1960 0.13 2.67 +1961 0.24 2.81 +1962 0.15 2.99 +1963 0.15 3.09 +1964 0.17 3.40 +1965 0.37 3.92 +1966 0.28 2.71 +1967 0.76 3.37 +1968 0.34 2.55 +1969 0.28 2.87 +1970 0.33 2.98 +1971 0.33 3.06 +1972 0.34 2.76 +1973 0.49 2.47 +1974 0.43 1.95 +1975 0.22 1.64 +1976 0.35 1.75 +1977 0.54 1.93 +1978 0.32 1.98 +1979 0.07 1.26 +1980 1.07 2.14 +1981 0.33 1.29 +1982 0.88 1.75 +1983 0.96 1.76 +1984 1.61 2.43 +1985 0.96 1.80 +1986 1.43 2.22 +1987 1.06 1.84 +1988 0.26 1.06 +1989 0.65 1.42 +1990 0.55 1.26 +1991 0.61 1.29 +1992 0.57 1.30 +1993 0.69 1.44 +1994 0.54 1.34 +1995 0.58 1.42 +1996 0.56 1.47 +1997 0.60 1.56 +1998 0.73 1.73 +1999 0.91 1.89 +2000 1.08 2.21 +2001 1.23 2.19 +2002 1.37 2.16 +2003 1.44 2.20 +2004 1.67 2.50 +2005 2.35 3.22 +2006 3.24 4.17 + + +### Table equivalent for Chart 5. Comparing the percentage point spread between the differences in estimates in Chart 4 with the proportion of workers whose earnings exceed the taxable maximum, 1951–2006 +Year Percentage point spread between lines in Chart 4 Percentage of workers with earnings exceeding the taxable maximum +1951 2.54 24.50 +1952 2.92 27.90 +1953 3.13 31.20 +1954 2.90 31.60 +1955 2.38 25.60 +1956 2.70 28.40 +1957 2.81 29.90 +1958 2.68 30.60 +1959 2.46 26.70 +1960 2.54 28.00 +1961 2.57 29.20 +1962 2.84 31.20 +1963 2.94 32.50 +1964 3.23 34.50 +1965 3.55 36.10 +1966 2.43 24.20 +1967 2.61 26.40 +1968 2.21 21.40 +1969 2.59 24.50 +1970 2.65 26.00 +1971 2.73 28.30 +1972 2.42 25.00 +1973 1.98 20.30 +1974 1.52 15.10 +1975 1.42 15.10 +1976 1.40 14.90 +1977 1.39 14.80 +1978 1.66 15.40 +1979 1.19 10.00 +1980 1.07 8.80 +1981 0.96 7.60 +1982 0.87 7.10 +1983 0.80 6.30 +1984 0.82 6.40 +1985 0.84 6.50 +1986 0.79 6.20 +1987 0.78 6.10 +1988 0.80 6.50 +1989 0.77 6.20 +1990 0.71 5.70 +1991 0.68 5.60 +1992 0.73 5.70 +1993 0.75 5.60 +1994 0.80 5.40 +1995 0.84 5.80 +1996 0.91 6.10 +1997 0.96 6.20 +1998 1.00 6.30 +1999 0.98 6.10 +2000 1.13 6.20 +2001 0.96 5.90 +2002 0.79 5.40 +2003 0.76 5.50 +2004 0.83 5.90 +2005 0.87 6.10 +2006 0.93 6.00 + + +### Table equivalent for Chart 6. Number of workers in the underlying EPUF sample with multiple employers and earnings exceeding the taxable maximum, 1951–2006 +Year Number of workers +1951 33,355 +1952 40,350 +1953 45,188 +1954 39,582 +1955 34,601 +1956 41,842 +1957 46,422 +1958 43,792 +1959 40,621 +1960 42,240 +1961 42,634 +1962 48,174 +1963 51,602 +1964 57,770 +1965 65,870 +1966 46,683 +1967 51,712 +1968 45,030 +1969 55,196 +1970 56,187 +1971 57,329 +1972 50,485 +1973 42,432 +1974 30,207 +1975 26,629 +1976 26,557 +1977 27,506 +1978 30,445 +1979 18,870 +1980 16,227 +1981 13,761 +1982 12,063 +1983 10,538 +1984 11,687 +1985 12,386 +1986 11,835 +1987 12,016 +1988 13,462 +1989 13,169 +1990 12,051 +1991 11,599 +1992 11,851 +1993 12,061 +1994 12,633 +1995 14,190 +1996 15,467 +1997 16,650 +1998 17,807 +1999 17,445 +2000 19,858 +2001 17,209 +2002 14,078 +2003 13,785 +2004 15,473 +2005 16,298 +2006 16,772 + + +### Table equivalent for Chart 7. EPUF estimates of the number of workers as a percentage of the Supplement estimate, workers younger than age 60 by age group, 1951–2006 +Year Age group +Under 20 20–24 25–29 30–34 35–39 40–44 45–49 50–54 55–59 +1951 98.78 100.02 98.28 97.73 97.11 98.68 98.27 99.18 104.65 +1952 98.11 101.06 98.83 97.31 97.37 98.95 98.87 97.90 105.83 +1953 98.50 100.41 99.03 97.76 96.02 98.43 98.15 98.46 103.07 +1954 98.42 100.47 99.57 98.16 96.58 98.36 98.15 98.52 101.94 +1955 98.14 100.31 99.33 98.13 97.32 98.18 97.90 99.33 99.89 +1956 98.39 99.79 99.69 98.41 97.90 97.55 98.96 99.02 101.19 +1957 98.19 99.92 100.12 98.74 97.72 97.68 99.23 98.77 100.81 +1958 98.64 100.25 100.58 99.16 98.35 97.12 99.11 99.44 100.95 +1959 98.47 99.64 100.21 99.08 97.94 96.69 98.25 98.21 100.86 +1960 98.92 99.48 100.87 99.43 98.13 97.26 98.14 98.85 101.39 +1961 98.89 99.64 100.36 99.63 97.97 97.57 97.79 99.65 100.22 +1962 98.97 99.44 100.19 100.27 98.62 97.77 97.72 99.54 100.35 +1963 98.38 99.72 100.14 100.56 99.02 98.07 97.09 99.35 100.30 +1964 98.71 100.05 99.51 100.45 99.83 98.26 96.97 99.42 100.42 +1965 98.26 99.93 99.44 100.47 99.61 98.02 97.41 98.73 100.13 +1966 98.13 99.39 100.23 100.18 100.32 98.52 97.77 98.31 101.18 +1967 97.44 99.19 98.65 99.60 100.16 98.57 97.22 97.92 100.50 +1968 97.44 99.60 99.38 100.10 100.65 99.38 98.34 97.24 101.61 +1969 96.84 99.89 99.81 99.94 100.87 99.77 98.86 97.51 101.21 +1970 96.98 99.41 99.37 99.41 100.54 99.57 98.30 97.47 99.77 +1971 96.50 99.35 99.12 100.27 99.94 99.97 98.56 97.50 99.06 +1972 97.29 99.25 99.07 98.96 99.67 99.96 99.04 97.52 98.68 +1973 96.78 99.70 99.29 99.32 99.83 100.16 99.26 98.24 97.51 +1974 97.17 99.55 99.42 99.79 99.51 100.41 99.40 98.71 97.10 +1975 97.34 99.62 99.77 100.26 99.71 100.42 99.51 98.62 97.62 +1976 97.46 99.38 99.68 100.15 100.25 100.12 99.84 99.03 98.05 +1977 97.09 99.98 99.63 99.98 99.65 100.13 100.23 99.50 97.68 +1978 94.72 99.01 98.56 98.55 98.56 99.17 99.18 98.38 97.50 +1979 95.73 99.66 98.84 98.85 99.35 99.12 99.78 99.03 98.11 +1980 96.80 99.50 99.32 99.39 99.58 99.02 99.97 99.35 98.05 +1981 96.19 100.25 99.06 99.44 99.45 99.65 99.67 99.67 98.32 +1982 96.10 99.74 99.25 99.47 99.42 98.63 99.78 99.64 98.09 +1983 96.60 100.51 100.12 100.08 99.97 99.50 100.21 100.07 99.32 +1984 96.12 100.59 100.53 99.74 100.04 100.17 100.00 100.57 99.45 +1985 96.27 100.89 100.25 99.86 100.22 100.16 99.49 100.35 99.09 +1986 96.03 100.02 99.98 99.01 99.58 99.57 99.53 99.33 98.67 +1987 96.91 100.40 100.45 99.97 98.95 99.51 99.19 100.10 99.26 +1988 96.04 100.26 100.19 100.39 99.02 99.28 99.75 100.36 99.00 +1989 95.77 100.59 100.66 100.72 99.37 99.40 100.27 100.08 99.61 +1990 95.41 99.79 100.10 99.78 99.00 98.43 99.69 99.13 98.81 +1991 95.59 99.77 100.03 100.01 98.81 98.57 99.44 99.54 98.43 +1992 95.14 99.86 99.78 99.51 99.30 98.68 99.02 98.88 98.97 +1993 95.20 99.39 99.79 99.60 99.49 98.86 98.73 98.99 99.27 +1994 95.82 99.88 100.36 100.26 100.24 99.24 99.00 99.78 99.08 +1995 95.84 98.92 99.85 99.95 99.67 99.32 98.84 99.66 98.54 +1996 95.65 98.94 100.03 99.75 99.76 98.93 98.79 99.47 99.00 +1997 95.86 98.75 99.87 99.91 99.42 99.39 98.75 99.38 98.68 +1998 95.83 99.19 99.59 99.90 99.76 99.76 99.19 98.90 99.24 +1999 95.35 99.19 98.93 99.67 99.68 99.64 98.97 99.49 99.20 +2000 95.16 98.72 98.32 98.98 99.28 99.00 98.58 98.63 99.06 +2001 95.55 98.19 98.16 98.66 98.87 98.81 98.03 98.41 98.64 +2002 95.65 98.00 97.90 98.62 98.84 98.88 98.39 98.41 98.59 +2003 96.26 98.34 98.40 98.60 98.75 98.93 98.85 98.97 98.61 +2004 96.57 98.50 98.26 98.29 98.65 98.89 98.68 98.47 98.61 +2005 95.35 97.92 97.54 97.33 98.02 98.37 97.75 97.92 98.20 +2006 94.85 97.88 96.71 96.78 97.18 97.71 97.22 96.72 97.63 + + +### Table equivalent for Chart 8. EPUF estimates of the number of workers as a percentage of the Supplement estimate, workers aged 60 or older by age group, 1960–2006 +Year Age group +60–61 62–64 65–69 70–71 72 or older +1960 101.65 102.18 101.18 102.98 96.89 +1961 102.91 102.04 101.29 101.23 98.23 +1962 101.74 102.65 101.43 101.04 97.32 +1963 101.87 102.24 100.43 104.07 95.74 +1964 101.12 101.43 99.29 100.63 96.02 +1965 100.62 100.01 99.55 100.42 95.24 +1966 99.52 100.30 100.71 98.72 95.04 +1967 99.88 98.66 98.24 100.84 94.00 +1968 100.62 98.43 97.49 98.42 92.88 +1969 100.22 98.86 99.84 101.02 97.26 +1970 99.80 98.67 96.74 101.37 95.43 +1971 101.23 99.21 97.42 97.38 95.09 +1972 102.05 98.62 98.98 98.55 95.34 +1973 100.42 100.30 98.97 98.73 94.09 +1974 98.83 99.69 99.51 99.27 93.36 +1975 97.73 100.29 99.14 97.79 94.06 +1976 98.35 98.72 100.17 100.66 93.37 +1977 98.64 97.99 100.29 99.49 93.33 +1978 96.06 96.66 97.66 98.29 93.10 +1979 95.60 97.26 97.65 97.23 92.97 +1980 98.43 95.63 96.58 96.70 93.50 +1981 99.51 95.36 96.25 97.65 92.91 +1982 97.18 95.58 95.55 98.34 92.34 +1983 97.09 98.14 96.74 94.42 92.40 +1984 97.66 98.30 95.83 95.77 92.49 +1985 98.29 97.85 97.78 95.66 90.67 +1986 98.25 96.87 96.84 95.18 89.50 +1987 97.75 98.27 97.30 95.44 85.45 +1988 98.20 98.59 97.07 93.61 86.43 +1989 98.52 98.39 97.71 94.30 86.61 +1990 97.59 97.59 97.90 94.40 86.23 +1991 97.75 97.48 97.95 96.54 86.96 +1992 98.07 97.68 98.03 95.93 87.19 +1993 97.23 98.94 97.97 94.49 87.75 +1994 99.57 99.30 98.69 97.06 87.82 +1995 99.35 98.50 98.51 96.72 86.44 +1996 97.43 99.54 98.26 99.89 86.86 +1997 98.28 98.28 98.42 99.78 86.45 +1998 98.49 98.88 97.28 99.18 87.58 +1999 98.38 98.99 98.53 99.84 91.02 +2000 98.13 97.87 97.99 97.13 90.45 +2001 98.02 97.87 96.78 97.77 91.73 +2002 97.32 97.53 97.45 98.49 91.83 +2003 97.95 97.78 97.94 97.58 92.65 +2004 99.08 96.98 97.08 97.15 93.27 +2005 98.61 97.49 95.98 96.98 92.05 +2006 97.78 97.24 95.92 94.83 91.53 + + +### Table equivalent for Chart 9. Effects of EPUF data cleaning and disclosure prevention measures: Estimated number of workers aged 72 or older as a percentage of the Supplement estimate, 1960–2006 +Year Underlying EPUF sample After removing records showing dubious age at earnings Final EPUF (after zeroing out earnings for ages 86 or older) +1960 102.42 98.51 96.89 +1961 104.00 100.11 98.23 +1962 102.99 99.20 97.32 +1963 101.47 97.74 95.74 +1964 101.67 98.00 96.02 +1965 101.00 97.24 95.24 +1966 100.93 97.19 95.04 +1967 99.52 95.94 94.00 +1968 98.60 94.94 92.88 +1969 103.20 99.41 97.26 +1970 101.42 97.68 95.43 +1971 100.87 97.18 95.09 +1972 101.54 97.74 95.34 +1973 100.36 96.58 94.09 +1974 99.98 96.02 93.36 +1975 100.35 96.66 94.06 +1976 99.88 96.18 93.37 +1977 99.94 96.19 93.33 +1978 99.48 96.08 93.10 +1979 99.11 95.88 92.97 +1980 99.38 96.33 93.50 +1981 98.60 95.58 92.91 +1982 98.47 95.42 92.34 +1983 98.90 95.69 92.40 +1984 98.99 95.55 92.49 +1985 97.17 93.80 90.67 +1986 96.10 92.66 89.50 +1987 91.59 88.28 85.45 +1988 92.62 89.01 86.43 +1989 92.84 89.36 86.61 +1990 92.41 88.71 86.23 +1991 93.29 89.53 86.96 +1992 93.55 89.77 87.19 +1993 95.27 90.77 87.75 +1994 95.79 91.00 87.82 +1995 94.87 89.65 86.44 +1996 95.36 89.98 86.86 +1997 95.17 89.74 86.45 +1998 96.37 90.88 87.58 +1999 99.69 94.48 91.02 +2000 98.80 94.06 90.45 +2001 99.84 95.36 91.73 +2002 99.21 95.24 91.83 +2003 99.96 96.46 92.65 +2004 100.58 97.37 93.27 +2005 98.68 95.92 92.05 +2006 97.98 95.61 91.53 + + +### Table equivalent for Chart 10. Comparison of estimates of number of workers aged 72 or older: EPUF, CWHS, and Supplement, 1980–2006 +Year EPUF as a percentage of CWHS CWHS as a percentage of Supplement +1980 100.50 98.91 +1981 100.60 98.04 +1982 100.60 97.87 +1983 101.10 97.79 +1984 100.90 98.11 +1985 99.30 97.90 +1986 98.90 97.17 +1987 98.20 93.24 +1988 99.10 93.43 +1989 98.90 93.86 +1990 99.30 93.05 +1991 99.80 93.51 +1992 99.50 94.06 +1993 100.30 95.01 +1994 100.20 95.59 +1995 99.80 95.04 +1996 100.00 95.36 +1997 99.50 95.62 +1998 100.40 95.98 +1999 100.30 99.42 +2000 100.00 98.84 +2001 101.30 98.58 +2002 100.70 98.52 +2003 101.10 98.86 +2004 101.90 98.70 +2005 100.30 98.44 +2006 99.80 97.96 + + +### Table equivalent for Chart 11. EPUF estimates of the number of male workers as a percentage of the Supplement estimate, workers younger than 60 by age group, 1951–2006 +Year Age group +Under 20 20–24 25–29 30–34 35–39 40–44 45–49 50–54 55–59 +1951 97.71 100.23 99.01 98.47 96.73 99.29 98.77 98.50 103.17 +1952 95.89 101.02 99.79 97.72 97.24 99.38 98.58 97.37 104.39 +1953 95.81 100.52 99.87 98.43 96.52 98.78 98.07 98.79 101.21 +1954 95.62 101.62 100.42 98.49 97.35 97.89 98.43 99.09 100.49 +1955 96.05 100.57 100.09 98.56 98.03 97.44 98.41 99.37 99.00 +1956 96.42 99.43 99.99 98.95 98.58 96.84 99.31 99.20 99.90 +1957 97.04 99.54 100.57 99.34 98.03 97.62 99.80 98.17 99.93 +1958 97.91 99.86 100.70 99.62 98.78 97.01 99.48 99.08 100.09 +1959 98.05 99.04 100.23 99.39 98.01 97.30 97.96 98.05 99.99 +1960 98.30 99.24 100.51 99.62 98.16 98.01 97.77 98.95 100.28 +1961 98.03 99.53 100.15 99.47 98.17 98.44 97.49 100.05 99.21 +1962 98.12 99.20 99.94 100.00 99.22 98.18 97.45 100.11 99.40 +1963 97.66 99.56 99.67 100.44 99.44 98.66 97.01 99.79 99.58 +1964 98.40 99.45 99.40 101.10 100.29 98.80 97.50 98.76 99.51 +1965 97.61 99.16 99.17 100.32 99.96 98.61 98.00 97.98 99.38 +1966 97.23 98.75 99.85 99.77 100.40 98.67 98.79 97.35 100.72 +1967 96.42 98.80 98.60 99.31 100.52 98.71 97.89 97.15 100.07 +1968 96.71 99.10 98.78 99.68 100.72 99.51 98.92 96.74 101.05 +1969 95.82 99.44 99.27 98.91 101.13 100.44 99.02 98.01 99.70 +1970 95.94 99.09 98.91 98.90 100.28 100.08 98.51 98.14 98.53 +1971 95.13 99.06 99.00 99.96 99.75 100.14 98.69 98.68 97.90 +1972 96.41 98.73 98.88 99.04 99.14 100.40 99.29 98.06 98.02 +1973 95.96 99.02 98.83 99.13 99.08 100.35 99.20 98.74 96.61 +1974 96.37 98.99 99.14 99.58 98.41 100.78 100.03 98.66 97.31 +1975 96.65 99.29 99.58 99.98 99.33 100.33 100.12 98.73 97.76 +1976 97.37 98.78 99.72 99.62 100.13 100.13 100.49 99.11 98.69 +1977 97.06 99.86 99.46 99.54 99.56 99.41 101.20 99.87 98.33 +1978 94.05 98.97 98.21 98.01 98.26 98.15 99.85 98.81 98.10 +1979 95.20 99.75 98.61 98.82 98.91 98.24 100.48 99.56 98.40 +1980 96.32 99.47 98.68 99.54 99.10 98.54 99.92 100.01 98.50 +1981 95.51 100.67 98.77 99.49 98.93 99.71 99.39 100.39 98.95 +1982 95.47 100.29 99.14 99.18 98.92 98.86 99.04 100.62 98.34 +1983 96.81 100.41 100.40 99.89 99.62 99.34 99.68 101.17 99.51 +1984 96.84 100.88 100.70 99.53 99.88 99.90 99.23 101.50 100.17 +1985 96.99 101.40 100.66 99.46 100.14 99.91 99.20 100.58 99.84 +1986 96.69 100.55 100.54 98.73 99.52 98.85 99.73 99.25 99.66 +1987 96.62 101.09 100.90 99.81 99.21 98.96 99.52 99.53 100.84 +1988 95.64 100.88 100.27 100.57 99.23 98.94 99.62 99.73 100.09 +1989 95.04 101.23 101.00 100.89 99.47 99.33 99.62 99.25 100.42 +1990 95.17 100.46 100.19 99.97 98.73 98.57 98.92 98.55 98.80 +1991 95.22 100.45 99.85 100.35 98.30 98.79 98.58 99.26 97.99 +1992 94.77 100.36 100.00 99.93 99.06 98.73 98.21 98.98 98.27 +1993 94.21 99.70 100.16 99.56 99.64 98.63 98.19 98.65 98.49 +1994 94.75 99.96 100.88 100.48 100.46 98.88 98.87 99.02 98.12 +1995 94.61 98.85 100.26 100.01 99.99 98.57 98.74 98.92 97.97 +1996 95.62 99.55 100.84 99.78 100.33 98.52 98.93 98.85 98.96 +1997 95.25 99.19 100.63 99.95 100.19 99.04 98.79 98.82 98.72 +1998 95.30 99.86 100.27 100.29 99.92 99.95 99.02 98.54 99.13 +1999 94.74 99.44 99.26 99.49 99.71 99.93 98.85 99.35 98.91 +2000 94.78 98.57 98.63 98.89 99.30 99.39 98.14 98.79 98.87 +2001 95.20 98.24 98.14 98.69 98.82 99.08 97.43 98.55 98.36 +2002 95.02 97.88 98.16 98.77 98.82 99.19 97.87 98.24 98.29 +2003 95.17 98.23 98.55 98.79 98.39 99.03 99.14 98.64 98.33 +2004 96.13 98.25 98.38 98.61 98.36 98.93 98.91 98.04 98.66 +2005 95.29 98.04 97.48 97.71 97.96 98.63 98.15 97.36 98.38 +2006 94.10 97.92 96.77 96.73 97.53 97.61 97.62 96.13 97.76 + + +### Table equivalent for Chart 12. EPUF estimates of the number of male workers as a percentage of the Supplement estimate, workers aged 60 or older by age group, 1960–2006 +Year Age group +60–61 62–64 65–69 70–71 72 or older +1960 101.45 100.49 100.49 104.10 94.99 +1961 100.96 101.26 100.35 100.98 96.33 +1962 100.91 101.50 100.78 99.97 95.54 +1963 100.80 101.39 100.24 102.43 94.88 +1964 100.02 102.19 100.28 98.04 96.13 +1965 98.73 100.13 99.93 101.50 94.44 +1966 98.23 100.60 101.15 97.34 93.37 +1967 98.34 97.50 99.90 100.17 92.75 +1968 99.15 97.45 98.30 98.89 90.13 +1969 100.14 97.50 100.18 104.95 95.00 +1970 100.45 97.55 97.14 102.80 94.53 +1971 101.26 98.57 97.63 98.75 95.88 +1972 101.12 98.82 98.07 98.99 96.16 +1973 99.57 100.13 98.26 99.08 94.29 +1974 96.82 99.39 99.83 97.43 94.87 +1975 95.87 99.54 98.75 98.25 95.12 +1976 97.44 97.27 99.27 101.03 93.99 +1977 98.26 96.48 99.51 99.01 94.88 +1978 96.45 94.87 97.28 97.59 93.18 +1979 96.60 96.52 97.28 95.78 93.47 +1980 99.42 95.81 95.02 95.89 93.67 +1981 99.80 96.33 94.21 98.79 92.61 +1982 97.56 95.86 94.64 99.86 92.08 +1983 97.20 98.20 96.64 95.47 92.98 +1984 96.88 97.78 95.75 94.08 93.24 +1985 97.30 98.14 97.43 94.98 92.14 +1986 98.52 96.55 97.19 92.89 89.67 +1987 97.69 97.36 96.48 94.98 86.50 +1988 98.44 98.26 96.24 95.30 87.11 +1989 99.53 98.05 96.92 92.89 87.78 +1990 98.57 98.32 98.24 94.75 87.46 +1991 99.51 97.62 98.45 97.98 87.78 +1992 99.68 98.61 98.03 96.65 87.10 +1993 97.90 100.18 98.04 95.29 87.83 +1994 99.67 101.54 99.32 97.21 87.05 +1995 98.49 99.01 99.80 97.95 86.11 +1996 95.93 99.73 99.54 103.55 86.96 +1997 97.39 97.40 99.96 101.32 86.88 +1998 97.66 97.97 98.05 99.86 88.71 +1999 97.55 97.08 100.01 101.61 91.83 +2000 97.43 96.55 98.42 97.42 91.13 +2001 98.22 96.33 96.54 99.58 92.99 +2002 97.29 96.77 96.46 101.95 92.63 +2003 97.47 97.85 96.51 97.12 94.00 +2004 97.84 97.58 95.85 97.72 94.15 +2005 98.33 97.72 95.32 97.10 92.89 +2006 98.29 96.73 95.32 93.71 92.42 + + +### Table equivalent for Chart 13. EPUF estimates of the number of female workers as a percentage of the Supplement estimate, workers younger than age 60 by age group, 1951–2006 +Year Age group +Under 20 20–24 25–29 30–34 35–39 40–44 45–49 50–54 55–59 +1951 100.03 99.69 96.84 96.49 97.83 97.31 97.15 100.66 108.17 +1952 100.86 101.03 96.95 96.33 97.57 97.97 99.40 98.99 109.11 +1953 101.91 100.20 97.36 96.24 94.94 97.62 98.25 97.64 107.24 +1954 101.84 99.05 97.84 97.34 94.90 99.19 97.55 97.23 105.14 +1955 100.72 99.83 97.75 97.09 95.72 99.63 96.79 99.19 101.77 +1956 100.84 100.14 98.96 97.15 96.39 98.87 98.18 98.59 104.02 +1957 99.73 100.43 98.96 97.24 96.91 97.76 98.05 99.91 102.66 +1958 99.58 100.80 100.15 97.97 97.31 97.27 98.34 100.03 102.76 +1959 98.96 100.53 99.96 98.24 97.69 95.43 98.74 98.45 102.64 +1960 99.70 99.79 101.45 98.88 97.94 95.75 98.73 98.61 103.55 +1961 100.06 99.72 100.64 99.90 97.45 95.82 98.23 98.89 102.18 +1962 100.17 99.71 100.61 100.74 97.30 96.91 98.14 98.48 102.11 +1963 99.44 99.87 101.04 100.63 98.10 96.87 97.14 98.55 101.61 +1964 99.13 100.93 100.42 98.78 98.81 97.18 95.95 100.50 102.03 +1965 99.22 101.05 99.91 100.56 98.81 96.88 96.33 99.98 101.46 +1966 99.47 100.26 100.89 100.86 100.05 98.17 95.98 99.85 101.96 +1967 98.94 99.69 98.65 100.07 99.33 98.24 96.05 99.12 101.19 +1968 98.43 100.24 100.38 100.82 100.37 99.10 97.31 97.96 102.53 +1969 98.23 100.46 100.67 101.83 100.24 98.59 98.50 96.62 103.67 +1970 98.35 99.80 100.08 100.31 100.84 98.65 97.86 96.34 101.72 +1971 98.32 99.68 99.23 100.79 100.11 99.58 98.27 95.59 100.85 +1972 98.41 99.87 99.32 98.72 100.45 99.14 98.55 96.58 99.65 +1973 97.79 100.50 99.96 99.54 100.96 99.71 99.24 97.37 98.84 +1974 98.15 100.17 99.78 100.06 101.22 99.68 98.38 98.68 96.65 +1975 98.17 99.96 99.98 100.62 100.26 100.38 98.50 98.36 97.30 +1976 97.54 100.06 99.56 100.90 100.37 99.95 98.79 98.82 96.97 +1977 97.11 100.08 99.80 100.56 99.71 101.08 98.71 98.87 96.59 +1978 95.51 99.02 98.95 99.28 98.91 100.53 98.10 97.67 96.51 +1979 96.33 99.52 99.06 98.83 99.91 100.27 98.66 98.18 97.62 +1980 97.33 99.52 100.07 99.12 100.15 99.60 99.90 98.32 97.32 +1981 96.94 99.75 99.37 99.34 100.07 99.49 99.96 98.55 97.36 +1982 96.78 99.06 99.32 99.78 100.01 98.26 100.64 98.21 97.66 +1983 96.37 100.59 99.71 100.22 100.40 99.63 100.83 98.49 98.96 +1984 95.29 100.23 100.29 99.92 100.17 100.45 100.92 99.22 98.37 +1985 95.49 100.28 99.71 100.28 100.26 100.40 99.80 99.91 98.01 +1986 95.30 99.40 99.28 99.30 99.57 100.38 99.25 99.30 97.29 +1987 97.19 99.62 99.90 100.12 98.58 100.10 98.74 100.72 97.11 +1988 96.48 99.56 100.07 100.11 98.68 99.64 99.85 101.06 97.50 +1989 96.54 99.87 100.23 100.49 99.16 99.42 100.97 101.04 98.44 +1990 95.66 99.03 99.96 99.52 99.25 98.22 100.53 99.80 98.70 +1991 95.97 99.00 100.21 99.56 99.34 98.28 100.39 99.86 98.89 +1992 95.54 99.29 99.51 98.98 99.54 98.56 99.88 98.74 99.76 +1993 96.26 99.03 99.34 99.60 99.27 99.05 99.29 99.32 100.17 +1994 96.97 99.77 99.75 99.95 99.95 99.58 99.09 100.60 100.20 +1995 97.14 98.98 99.36 99.86 99.28 100.10 98.89 100.43 99.22 +1996 95.70 98.26 99.13 99.68 99.07 99.32 98.55 100.12 99.06 +1997 96.49 98.27 99.02 99.84 98.52 99.74 98.64 99.93 98.60 +1998 96.34 98.48 98.83 99.43 99.55 99.52 99.30 99.26 99.30 +1999 95.95 98.91 98.54 99.88 99.60 99.29 99.03 99.58 99.51 +2000 95.56 98.86 97.96 99.06 99.24 98.53 98.99 98.40 99.22 +2001 95.89 98.10 98.17 98.61 98.89 98.50 98.60 98.21 98.91 +2002 96.27 98.12 97.60 98.42 98.85 98.49 98.91 98.51 98.88 +2003 97.33 98.44 98.22 98.37 99.13 98.79 98.50 99.24 98.89 +2004 96.96 98.74 98.14 97.90 98.99 98.80 98.42 98.87 98.50 +2005 95.40 97.79 97.57 96.89 98.08 98.07 97.29 98.46 97.95 +2006 95.58 97.82 96.61 96.81 96.77 97.78 96.76 97.30 97.43 + + +### Table equivalent for Chart 14. EPUF estimates of the number of female workers as a percentage of the Supplement estimate, workers aged 60 or older by age group, 1960–2006 +Year Age group +60–61 62–64 65–69 70–71 72 or older +1960 102.08 106.05 102.26 99.68 101.16 +1961 107.04 103.77 102.93 100.87 102.36 +1962 103.43 105.22 102.49 102.66 100.76 +1963 103.98 104.07 100.55 107.05 96.89 +1964 103.16 99.86 97.16 105.60 94.77 +1965 104.17 99.72 98.68 97.92 96.33 +1966 101.88 99.68 99.80 101.12 98.48 +1967 102.66 100.85 94.96 101.99 96.13 +1968 103.22 100.22 95.88 97.50 98.52 +1969 100.33 101.33 99.15 93.27 101.67 +1970 98.71 100.62 95.99 98.38 96.93 +1971 101.16 100.27 97.04 94.79 93.14 +1972 103.55 98.22 100.58 97.70 93.38 +1973 101.79 100.52 100.20 98.05 93.54 +1974 102.07 100.13 98.90 102.77 90.16 +1975 100.65 101.51 99.73 96.98 91.72 +1976 99.64 101.05 101.64 100.00 91.97 +1977 99.11 100.35 101.50 100.38 90.12 +1978 95.36 99.45 98.24 99.56 92.87 +1979 93.95 98.31 98.22 99.83 91.91 +1980 96.82 95.26 98.99 98.08 93.07 +1981 98.99 93.89 99.26 95.78 93.20 +1982 96.54 95.07 96.79 95.90 92.80 +1983 96.85 97.96 96.61 92.74 91.32 +1984 98.68 98.94 95.82 98.21 91.17 +1985 99.58 89.45 98.16 96.50 88.15 +1986 97.75 97.31 96.11 98.53 89.14 +1987 97.76 99.44 98.39 95.90 83.64 +1988 97.79 98.85 98.09 90.71 85.02 +1989 97.09 98.74 98.70 96.32 84.68 +1990 96.27 96.54 97.31 93.72 84.13 +1991 95.44 97.23 97.19 94.33 85.52 +1992 95.94 96.47 97.93 94.77 87.26 +1993 96.24 97.31 97.79 93.01 87.51 +1994 99.32 96.33 97.80 97.17 88.85 +1995 100.34 97.70 96.73 94.68 86.88 +1996 99.30 99.17 96.46 94.81 86.77 +1997 99.37 99.28 96.25 97.48 85.75 +1998 99.40 99.92 96.08 98.47 85.77 +1999 99.37 101.41 96.54 97.26 89.71 +2000 98.98 99.41 97.24 96.66 89.35 +2001 97.82 99.75 96.93 95.19 89.64 +2002 97.31 98.43 98.70 94.07 90.58 +2003 98.45 97.66 99.69 98.10 90.57 +2004 100.47 96.21 98.72 95.93 91.89 +2005 98.89 97.14 96.82 96.71 90.70 +2006 97.22 97.78 96.66 96.41 89.96 + + +### Table equivalent for Chart 15. EPUF estimates of median earnings as a percentage of the Supplement estimate, all workers younger than age 60 by age group, 1960–2006 +Year Age group +Under 20 20–24 25–29 30–34 35–39 40–44 45–49 50–54 55–59 +1960 100.68 100.24 99.65 100.81 100.24 100.23 98.35 99.66 99.69 +1961 100.11 99.23 100.45 100.21 100.16 100.48 98.61 99.76 100.61 +1962 100.80 100.10 100.80 100.66 100.22 99.92 99.00 99.59 100.00 +1963 100.72 100.25 99.82 100.57 100.29 100.45 99.79 99.21 100.38 +1964 99.45 100.42 99.88 101.03 100.47 100.55 100.61 99.07 98.82 +1965 101.25 101.01 99.36 100.80 100.66 100.81 101.10 98.86 99.40 +1966 96.05 100.42 99.98 100.42 99.67 100.45 101.12 99.13 98.92 +1967 98.68 100.30 100.11 100.09 100.31 100.81 100.37 98.64 99.49 +1968 100.13 100.66 100.36 99.99 100.28 100.78 100.55 99.83 99.07 +1969 100.72 100.33 100.43 100.20 100.34 100.31 100.86 100.41 98.88 +1970 100.22 100.13 100.54 100.03 100.46 100.76 100.32 100.67 98.89 +1971 98.63 99.96 100.17 100.26 100.35 99.74 100.34 100.54 98.87 +1972 99.18 100.25 100.21 100.14 100.48 100.30 100.47 100.27 98.90 +1973 99.71 100.32 99.78 99.76 100.45 100.19 99.90 100.26 99.22 +1974 100.16 100.26 99.92 100.39 99.34 100.29 99.90 99.51 99.83 +1975 99.67 100.58 99.79 100.25 99.71 100.19 100.32 99.39 99.05 +1976 101.34 100.57 100.56 99.11 100.14 99.60 100.39 100.21 100.00 +1977 98.69 100.11 100.47 99.91 100.16 100.25 100.29 100.52 100.02 +1978 100.84 100.41 100.29 100.34 99.93 99.49 100.57 100.10 100.31 +1979 100.79 100.21 99.61 100.15 98.83 99.20 100.68 99.91 100.41 +1980 100.51 100.39 99.75 100.45 99.77 99.65 99.81 99.85 99.83 +1981 100.35 100.45 99.72 100.48 99.38 99.92 99.64 99.85 99.56 +1982 99.35 100.19 99.59 99.39 99.57 100.04 99.91 100.00 100.66 +1983 99.50 99.77 99.50 100.11 99.87 99.45 99.62 100.91 99.54 +1984 99.65 100.40 100.19 100.36 100.55 100.18 100.29 101.12 100.50 +1985 99.50 100.29 99.77 100.09 100.57 100.47 99.89 100.88 100.79 +1986 99.51 99.74 99.96 99.18 100.21 99.18 99.70 99.47 99.33 +1987 99.67 100.23 99.55 99.62 100.37 99.90 99.54 99.51 99.62 +1988 99.38 99.79 99.85 99.90 100.02 99.94 99.37 99.44 99.55 +1989 100.52 99.59 100.20 100.28 101.00 100.65 100.22 100.38 100.48 +1990 100.05 99.26 99.90 100.21 100.80 101.05 100.40 100.30 100.40 +1991 99.22 99.53 99.80 100.11 100.49 101.01 100.16 100.20 99.86 +1992 100.05 99.87 100.42 100.36 100.61 100.99 100.62 100.38 99.35 +1993 99.65 100.62 100.22 100.31 100.94 101.08 100.52 100.58 99.73 +1994 99.55 101.17 100.01 100.13 100.08 100.30 99.78 99.28 99.60 +1995 100.29 100.55 100.40 99.97 100.29 99.04 99.50 99.47 100.15 +1996 99.51 100.89 100.28 100.06 100.41 99.31 100.47 99.26 100.15 +1997 99.54 100.43 100.25 100.31 100.18 99.64 99.94 99.35 100.01 +1998 98.87 99.74 100.47 100.16 100.09 100.15 99.77 99.83 99.95 +1999 99.93 99.88 100.33 100.32 100.64 100.24 99.60 99.88 99.92 +2000 100.05 99.89 99.89 99.82 100.89 100.54 99.28 100.37 99.34 +2001 99.63 99.44 100.18 99.76 100.33 100.57 99.12 100.10 99.98 +2002 99.74 100.19 100.14 100.05 100.21 100.34 99.98 99.50 99.84 +2003 100.96 100.76 100.00 99.93 100.26 100.18 100.18 99.62 99.92 +2004 100.70 99.68 100.00 99.75 100.17 100.64 100.38 99.41 100.07 +2005 99.56 99.57 99.90 100.12 99.64 100.58 100.82 99.19 99.96 +2006 99.26 99.51 100.46 100.45 99.97 99.85 100.68 99.50 100.23 + + +### Table equivalent for Chart 16. EPUF estimates of median earnings as a percentage of the Supplement estimate, all workers aged 60 or older by age group, 1960–2006 +Year Age group +60–61 62–64 65–69 70–71 72 or older +1960 101.82 99.73 103.77 102.74 95.85 +1961 102.01 98.35 103.15 102.49 96.85 +1962 100.89 100.24 101.38 103.68 94.86 +1963 98.90 100.97 98.03 101.22 95.49 +1964 99.30 100.36 96.23 101.40 95.54 +1965 100.47 99.04 103.01 102.13 97.11 +1966 99.45 99.84 102.34 100.00 97.93 +1967 98.56 99.90 102.07 100.11 102.78 +1968 99.26 99.72 100.17 99.77 99.23 +1969 98.93 99.15 96.66 100.64 100.11 +1970 99.97 99.11 99.09 101.46 98.51 +1971 101.49 97.24 98.77 102.61 97.45 +1972 98.80 97.76 99.81 99.33 98.32 +1973 99.59 98.39 97.99 100.67 96.92 +1974 98.45 98.83 99.42 103.05 98.13 +1975 98.32 99.38 99.44 99.76 100.90 +1976 99.85 96.93 100.09 103.66 99.53 +1977 100.91 97.34 100.41 102.86 100.31 +1978 100.04 98.17 99.74 99.54 96.42 +1979 99.35 99.50 98.56 98.69 99.64 +1980 99.84 100.01 99.50 100.35 99.20 +1981 99.57 100.20 97.90 99.44 97.66 +1982 98.39 102.22 98.27 99.97 96.60 +1983 98.37 99.92 97.12 97.68 99.26 +1984 100.51 99.09 98.82 97.16 97.76 +1985 100.48 97.42 99.51 97.78 97.55 +1986 99.37 99.50 99.22 94.45 95.41 +1987 98.86 99.14 99.18 97.91 93.10 +1988 98.41 98.99 99.58 100.25 90.95 +1989 99.85 99.35 98.13 104.94 93.72 +1990 99.62 95.90 97.61 102.03 92.87 +1991 99.66 98.84 97.74 99.65 96.33 +1992 101.62 97.54 97.04 97.07 97.08 +1993 100.73 99.10 96.23 98.68 93.69 +1994 98.93 97.22 99.47 100.15 89.90 +1995 97.43 98.74 98.66 100.53 93.74 +1996 98.83 97.93 98.56 96.51 93.15 +1997 99.04 99.59 99.18 96.86 92.85 +1998 100.25 98.38 100.71 98.67 96.28 +1999 100.82 98.44 99.21 102.17 97.42 +2000 99.69 99.48 100.03 98.41 99.70 +2001 100.37 98.93 98.95 96.68 100.51 +2002 100.82 99.71 99.83 99.06 101.51 +2003 100.06 100.85 97.95 96.42 101.84 +2004 99.09 101.87 99.46 98.77 99.12 +2005 98.15 101.22 99.20 100.13 99.51 +2006 99.65 100.10 98.95 102.12 97.09 + + +### Table equivalent for Chart 17. EPUF estimates of median earnings as a percentage of the Supplement estimate, male workers younger than age 60 by age group, 1960–2006 +Year Age group +Under 20 20–24 25–29 30–34 35–39 40–44 45–49 50–54 55–59 +1960 100.57 100.76 100.28 99.36 92.75 92.90 96.89 100.49 99.45 +1961 99.54 100.56 100.68 97.50 90.57 90.24 92.79 99.11 99.95 +1962 99.77 101.23 101.05 93.13 86.02 84.70 88.15 94.04 99.23 +1963 100.05 100.24 100.83 89.49 83.04 81.67 84.79 90.28 95.66 +1964 98.66 100.42 100.59 84.99 79.33 77.76 79.09 85.24 90.34 +1965 98.75 100.98 96.83 79.27 74.06 73.63 75.37 81.07 86.01 +1966 96.68 100.74 100.51 100.80 95.64 93.96 95.64 100.23 100.18 +1967 99.75 100.77 100.54 98.00 92.27 90.80 91.64 97.14 100.32 +1968 100.62 100.67 100.48 100.30 100.58 98.67 99.67 99.81 99.67 +1969 100.96 100.44 100.56 99.92 94.69 92.50 93.17 98.09 99.47 +1970 99.11 100.59 101.10 95.93 91.46 89.80 89.11 93.19 99.14 +1971 98.26 100.70 100.15 92.17 88.85 84.50 85.31 88.66 95.51 +1972 99.19 100.51 100.54 97.19 91.56 89.82 90.36 93.07 99.00 +1973 99.90 100.42 100.40 100.25 100.65 97.91 98.09 99.65 99.30 +1974 100.41 100.16 100.02 100.36 100.57 100.46 100.62 99.56 99.63 +1975 100.86 100.11 100.17 100.40 100.27 100.19 100.18 99.72 99.01 +1976 101.45 100.66 100.94 100.08 100.78 100.23 100.33 100.03 99.55 +1977 99.75 100.29 100.59 100.41 100.82 100.30 100.74 99.46 98.87 +1978 100.29 100.62 100.61 100.57 100.20 100.56 100.40 100.08 99.02 +1979 101.10 99.95 99.86 100.25 100.34 100.51 100.16 100.62 99.41 +1980 100.76 100.12 100.24 100.31 100.84 100.59 99.89 100.79 98.91 +1981 100.29 100.54 99.82 100.51 99.99 100.09 99.98 100.01 99.96 +1982 99.20 100.62 99.95 99.61 100.45 100.77 100.52 100.15 99.58 +1983 97.95 99.87 99.68 99.33 100.25 100.21 100.65 100.32 99.86 +1984 98.56 100.51 99.88 100.25 101.15 101.45 101.66 101.96 100.65 +1985 100.02 100.84 99.96 100.03 101.32 101.68 101.51 100.73 101.51 +1986 100.46 100.20 99.83 99.30 100.45 100.09 100.30 100.14 99.50 +1987 99.76 100.63 99.53 99.40 100.27 100.42 99.71 100.45 98.95 +1988 99.81 100.13 99.58 100.15 100.08 100.60 99.92 100.57 98.72 +1989 100.17 100.11 100.32 100.67 100.97 101.24 101.76 101.63 100.30 +1990 98.60 99.88 100.38 100.46 101.31 101.29 102.05 101.57 100.22 +1991 98.51 100.81 100.71 99.87 100.49 101.53 101.51 101.26 101.12 +1992 99.20 99.79 100.63 100.32 100.63 101.24 102.08 100.98 100.85 +1993 99.07 100.38 101.21 100.29 100.92 101.76 101.79 101.28 101.88 +1994 100.56 101.79 100.29 100.09 99.54 100.50 100.11 100.63 100.50 +1995 99.48 100.60 100.78 100.22 100.00 99.92 100.05 100.49 100.89 +1996 99.64 100.21 100.33 100.62 99.91 99.20 101.02 99.90 101.03 +1997 101.01 100.84 99.69 100.83 99.91 99.51 100.17 100.97 100.43 +1998 98.82 99.85 100.31 100.59 99.83 99.75 100.22 101.18 100.34 +1999 99.12 99.90 99.98 100.69 100.41 99.69 99.89 100.69 100.14 +2000 100.19 99.66 99.68 100.12 101.52 99.86 99.56 100.34 99.13 +2001 99.62 99.07 100.27 99.83 101.04 100.07 99.53 100.23 100.08 +2002 99.86 99.70 100.37 99.47 100.63 100.43 99.50 99.89 99.77 +2003 100.99 100.60 100.00 99.80 100.51 100.16 99.84 99.87 99.72 +2004 100.38 99.89 100.18 99.52 100.24 100.39 99.86 99.43 100.09 +2005 100.33 100.43 99.32 100.22 99.66 100.43 100.54 99.57 100.30 +2006 99.81 100.07 100.48 100.43 99.88 100.40 100.33 99.85 100.90 + + +### Table equivalent for Chart 18. EPUF estimates of median earnings as a percentage of the Supplement estimate, male workers aged 60 or older by age group, 1960–2006 +Year Age group +60–61 62–64 65–69 70–71 72 or older +1960 100.96 100.54 110.09 99.24 101.87 +1961 101.96 98.88 109.96 97.72 101.97 +1962 100.12 99.47 105.36 101.01 102.39 +1963 98.03 99.32 98.90 100.52 100.71 +1964 98.95 100.30 94.89 100.84 98.76 +1965 96.13 99.27 99.96 96.31 102.02 +1966 99.15 99.34 101.91 101.48 97.64 +1967 99.13 99.13 101.27 101.34 106.37 +1968 99.22 99.63 94.93 100.11 100.89 +1969 98.23 100.10 90.08 98.97 100.96 +1970 100.75 98.50 96.31 100.03 98.53 +1971 101.84 97.83 97.33 100.64 98.75 +1972 99.96 99.18 99.64 99.26 99.35 +1973 99.77 99.03 99.05 100.92 97.52 +1974 99.12 100.46 95.86 101.01 99.68 +1975 97.43 99.83 96.10 100.08 101.61 +1976 99.01 98.11 96.11 102.67 97.22 +1977 101.10 97.58 96.92 101.57 100.73 +1978 100.13 99.91 100.15 100.50 96.43 +1979 98.46 100.04 98.09 99.00 98.17 +1980 98.16 100.47 99.20 99.77 98.57 +1981 98.03 98.88 98.10 99.70 96.78 +1982 98.61 100.30 99.76 99.58 97.16 +1983 99.32 98.26 97.98 98.35 99.28 +1984 100.88 98.92 99.24 96.48 98.18 +1985 101.64 97.29 99.42 99.04 94.06 +1986 101.40 98.93 100.23 96.11 93.16 +1987 99.05 98.35 100.67 98.60 91.52 +1988 97.13 99.16 99.24 98.17 89.26 +1989 99.62 99.77 98.51 104.43 94.24 +1990 98.95 99.26 98.33 99.18 91.39 +1991 99.09 98.78 99.92 95.33 94.18 +1992 99.44 100.25 98.49 99.23 94.63 +1993 100.56 99.92 98.76 103.17 91.40 +1994 99.31 95.04 101.62 96.36 88.77 +1995 98.31 97.49 100.24 101.30 92.76 +1996 100.09 96.30 97.62 96.80 90.65 +1997 99.43 101.45 99.50 94.35 92.64 +1998 100.56 97.22 100.81 99.88 96.06 +1999 102.21 101.43 98.22 104.88 97.74 +2000 101.48 99.99 101.46 96.00 99.47 +2001 99.68 102.04 97.63 95.16 98.38 +2002 99.11 101.59 99.44 99.73 99.10 +2003 99.29 99.98 98.63 97.29 101.29 +2004 98.44 99.31 99.70 100.92 100.01 +2005 97.59 98.64 98.92 100.52 99.86 +2006 99.06 98.67 99.77 100.68 96.16 + + +### Table equivalent for Chart 19. EPUF estimates of median earnings as a percentage of the Supplement estimate, female workers younger than age 60 by age group, 1960–2006 +Year Age group +Under 20 20–24 25–29 30–34 35–39 40–44 45–49 50–54 55–59 +1960 100.00 98.58 97.66 100.70 99.68 99.84 99.20 99.60 99.30 +1961 95.64 96.42 99.38 99.68 99.65 99.49 99.76 99.73 99.65 +1962 103.36 98.94 98.41 98.13 100.17 100.08 98.21 100.51 99.07 +1963 101.98 100.36 98.92 97.25 99.79 99.15 99.88 98.64 99.27 +1964 93.91 99.73 98.51 98.52 99.82 99.46 98.64 98.82 98.54 +1965 95.13 99.96 99.55 97.30 100.20 100.84 99.05 99.62 98.69 +1966 97.41 100.22 97.73 97.12 97.02 99.26 99.19 100.49 98.38 +1967 99.95 99.26 99.27 99.87 97.66 99.64 99.66 99.18 98.67 +1968 98.53 100.72 99.89 100.64 98.70 99.11 100.07 100.95 98.42 +1969 99.11 100.10 99.38 99.00 98.85 99.50 100.50 100.15 98.99 +1970 101.13 99.92 98.57 100.30 99.22 99.63 99.12 100.24 99.58 +1971 98.14 98.66 99.90 98.26 99.79 98.13 98.91 100.68 99.59 +1972 99.27 99.60 99.45 99.45 99.68 99.59 99.50 99.75 99.41 +1973 99.85 99.54 98.62 97.46 99.50 98.23 99.08 99.40 98.44 +1974 99.72 100.22 99.87 99.07 98.68 98.02 99.22 99.43 99.37 +1975 98.04 101.26 99.31 98.16 99.05 99.36 99.18 98.92 98.90 +1976 101.21 100.28 100.05 98.63 98.64 100.01 99.89 99.39 98.38 +1977 98.23 100.20 100.22 99.74 97.84 99.52 100.22 99.57 99.43 +1978 100.86 100.20 100.47 99.98 98.86 98.92 100.33 99.66 99.75 +1979 100.17 100.55 99.76 100.19 98.75 98.03 99.24 98.71 100.08 +1980 100.48 101.02 99.57 100.35 100.00 98.71 100.81 98.74 99.46 +1981 100.11 100.83 99.50 101.09 99.54 99.44 100.43 98.22 99.18 +1982 99.62 98.92 99.42 100.00 99.87 99.24 99.72 99.25 98.21 +1983 100.88 98.70 99.18 101.12 100.54 99.26 99.13 100.10 97.34 +1984 99.97 99.90 99.49 101.18 100.02 99.84 99.59 100.31 99.55 +1985 99.46 99.58 99.12 99.93 100.07 100.57 99.31 101.44 99.05 +1986 98.48 99.35 99.09 98.67 100.72 99.39 99.67 99.90 99.37 +1987 99.73 99.93 98.86 99.30 101.05 99.76 99.45 99.23 99.85 +1988 98.83 99.31 99.76 99.21 100.77 99.81 99.25 98.27 99.76 +1989 100.87 98.33 99.66 99.62 101.39 99.68 99.78 98.07 100.76 +1990 101.53 98.25 100.11 99.74 101.06 101.29 99.74 98.25 100.33 +1991 99.67 98.28 99.32 99.88 100.37 101.49 99.97 98.14 100.24 +1992 100.41 99.75 99.34 99.80 100.18 101.08 99.62 99.11 98.47 +1993 100.34 101.06 98.67 99.89 100.32 100.50 99.47 100.14 97.67 +1994 97.95 100.56 98.66 100.18 100.03 99.76 99.21 99.76 98.00 +1995 101.16 100.58 99.70 99.69 100.19 98.95 99.82 99.42 99.02 +1996 99.66 100.80 99.94 99.49 100.57 99.54 100.00 99.39 99.24 +1997 98.12 99.99 100.86 99.32 100.15 99.55 99.93 99.39 99.12 +1998 98.76 99.63 100.90 99.23 100.36 99.94 99.54 99.70 99.89 +1999 100.40 99.35 100.52 100.57 100.57 100.20 99.74 99.88 100.63 +2000 99.77 99.51 99.79 100.19 100.33 100.06 99.87 100.52 100.03 +2001 99.47 100.28 100.08 100.23 100.36 100.70 99.64 100.22 99.86 +2002 99.66 100.23 99.78 100.19 99.78 99.94 100.47 99.22 99.97 +2003 100.68 100.37 100.03 100.27 99.75 100.30 100.25 99.59 100.51 +2004 101.03 99.11 99.73 100.43 99.65 100.17 100.53 100.18 100.45 +2005 98.99 98.62 100.62 100.45 99.94 100.42 100.93 99.66 100.31 +2006 98.56 99.03 100.39 101.09 99.95 99.42 101.17 99.98 100.14 + + +### Table equivalent for Chart 20. EPUF estimates of median earnings as a percentage of the Supplement estimate, female workers aged 60 or older by age group, 1960–2006 +Year Age group +60–61 62–64 65–69 70–71 72 or older +1960 103.94 99.25 101.09 99.11 92.66 +1961 100.56 99.22 100.59 104.06 97.94 +1962 101.10 100.04 99.78 103.48 96.25 +1963 100.43 104.38 100.25 97.77 95.92 +1964 100.73 102.84 100.17 95.24 97.25 +1965 98.83 98.65 99.34 104.84 98.52 +1966 99.57 99.94 101.75 102.19 93.24 +1967 99.31 99.53 101.15 97.76 95.21 +1968 101.93 97.37 101.78 97.08 95.35 +1969 97.82 103.69 100.78 101.41 98.34 +1970 96.74 100.31 99.98 105.01 98.32 +1971 99.91 98.59 99.41 104.97 93.78 +1972 98.60 96.10 99.12 98.55 100.45 +1973 98.99 98.37 100.31 103.08 99.57 +1974 97.14 100.75 99.36 110.56 95.72 +1975 100.85 96.92 102.79 94.88 98.40 +1976 101.72 99.21 100.02 101.63 100.45 +1977 97.07 99.16 98.05 110.47 99.01 +1978 98.08 99.67 100.07 95.08 94.43 +1979 98.69 98.77 101.44 98.59 100.93 +1980 98.57 98.54 102.36 98.94 96.03 +1981 100.54 99.53 99.61 100.31 98.99 +1982 99.37 100.87 99.83 100.13 93.38 +1983 97.23 100.48 96.40 98.66 99.70 +1984 100.07 95.84 100.21 98.26 95.31 +1985 99.20 97.12 98.00 97.20 99.47 +1986 99.62 100.23 100.00 96.34 96.60 +1987 98.40 103.34 97.58 94.77 90.88 +1988 95.83 98.90 99.59 97.23 92.41 +1989 98.46 97.93 97.54 109.32 91.26 +1990 98.74 92.52 96.77 107.03 94.80 +1991 97.72 96.77 96.02 100.00 96.91 +1992 102.14 95.48 95.88 91.21 98.40 +1993 101.21 96.90 94.00 96.00 97.60 +1994 98.96 98.70 96.72 105.52 95.24 +1995 100.49 98.65 97.03 101.11 93.70 +1996 99.82 96.55 97.37 94.37 97.11 +1997 97.67 97.34 97.98 97.46 93.88 +1998 98.55 99.52 100.62 94.93 98.40 +1999 99.85 97.68 98.81 100.77 97.44 +2000 99.01 98.72 98.26 102.87 99.34 +2001 100.82 95.75 100.50 99.49 102.32 +2002 101.11 96.98 101.73 97.90 102.73 +2003 101.04 102.11 98.75 96.72 104.09 +2004 99.51 103.45 99.81 98.89 98.24 +2005 99.00 104.75 101.05 101.55 97.94 +2006 98.90 101.19 98.09 103.03 98.51 + diff --git a/data/external/epuf_2006/ssb_v71n4p33.source.txt b/data/external/epuf_2006/ssb_v71n4p33.source.txt new file mode 100644 index 00000000..5e3ac926 --- /dev/null +++ b/data/external/epuf_2006/ssb_v71n4p33.source.txt @@ -0,0 +1,1362 @@ +Source: https://www.ssa.gov/policy/docs/ssb/v71n4/v71n4p33.html (Compson, M. 2011. 'The 2006 Earnings Public-Use Microdata File: An Introduction.' Social Security Bulletin 71(4): 33-59; page range as cited in Compson 2012 references). Retrieved 2026-10-01 via browser page-text extraction (curl returns 403). + +Title: The 2006 Earnings Public-Use Microdata File: An Introduction +URL: https://www.ssa.gov/policy/docs/ssb/v71n4/v71n4p33.html +Source element:
+--- +Social Security +The 2006 Earnings Public-Use Microdata File: An Introduction +by Michael Compson +Social Security Bulletin, Vol. 71, No. 4, 2011 (released November 2011) +You are here: Social Security Administration > Research, Statistics & Policy Analysis > Social Security Bulletin > Vol. 71, No. 4 +EmailSave/Print + +This article introduces the 2006 Earnings Public-Use File (EPUF) and provides important background information on the file's data fields. The EPUF contains selected demographic and earnings information for 4.3 million individuals drawn from a 1-percent sample of all Social Security numbers issued before January 2007. The data file provides aggregate earnings for 1937 to 1950 and annual earnings data for 1951 to 2006. The article focuses on four key items: (1) the Social Security Administration's experiences collecting earnings data over the years and their effect on the data fields included in EPUF; (2) the steps taken to "clean" the underlying administrative data and to minimize the risk of personal data disclosure; (3) the potential limitations of using EPUF data to estimate Social Security benefits for some individuals; and (4) frequency distributions and statistical tabulations of the data in the file, to provide a point of reference for EPUF users. + +Michael Compson is with the Division of Policy Evaluation, Office of Research, Evaluation, and Statistics, Office of Retirement and Disability Policy, Social Security Administration. + +Acknowledgments: The author gratefully acknowledges the assistance of many individuals in the process of creating the 2006 Earnings Public-Use File and this article: John Hennessey, for graciously sharing his programming and methodological expertise; Russell Hudson, for his programming expertise and sharing his vast knowledge of the earnings data; Paul Davies, for his guidance and support throughout the project; Scott Muller, Greg Diez, and Bill Piet, for sharing programmatic and earnings knowledge; Sirisha Anne, Brenda South, Stu Friedrich, and Randall Miles, for their assistance in providing the data extracts used in the process of creating EPUF; Bill Davis and Justin Ronca, for their statistical expertise; and Susan Grad, Howard Iams, Hilary Waldron, and Anya Olsen, for their comments on previous drafts of the article. + +Contents of this publication are not copyrighted; any items may be reprinted, but citation of the Social Security Bulletin as the source is requested. The findings and conclusions presented in the Bulletin are those of the authors and do not necessarily represent the views of the Social Security Administration. + +Introduction +Selected Abbreviations +BEPUF Benefits and Earnings Public-Use File +EPUF Earnings Public-Use File +IRS Internal Revenue Service +MEF Master Earnings File +QC quarter of coverage +SSA Social Security Administration +SSN Social Security number +YOB year of birth + +This article introduces the 2006 Earnings Public-Use File (EPUF), a data file containing earnings records for individuals drawn from a 1-percent sample of all Social Security numbers (SSNs) issued before January 2007. EPUF is the latest public-use data file released by the Social Security Administration (SSA) to contain earnings data from its administrative files. EPUF comprises a much larger sample than previously released public-use files containing earnings histories, and significantly enhances the ability of researchers and policy analysts to analyze SSA programs. + +EPUF consists of two linkable files. One contains selected demographic and aggregate earnings information for all 4,348,254 individuals in the file, and the second contains annual earnings records for the 3,131,424 individuals who had positive earnings in at least 1 year during 1951–2006. EPUF data reflect capped Social Security taxable earnings. As such, the earnings data contained in EPUF do not present complete measures of the number of workers or the amount of wage-and-salary and self-employment income in the US economy. + +The data fields included in EPUF are nearly identical to those in SSA's most recent public-use file containing administrative earnings, the 2004 Benefits and Earnings Public-Use File (BEPUF). This was done (1) to address the critical need to meet data disclosure standards, (2) because of the complexity of the earnings data that SSA has collected over the life of the program, and (3) to maximize EPUF's timeliness. SSA plans to continue working on data disclosure standards for several key detailed earnings data fields from its administrative files. Combining this work with direct feedback from EPUF users, SSA hopes to include new data fields in future releases. + +This article informs potential users about the EPUF and provides background information about the data contained in the file. Specifically, the article discusses SSA's experiences collecting earnings data over the years and the effect of those experiences on the data fields included in EPUF; the steps taken to "clean" the data and to minimize the risk of personal data disclosure; and the potential limitations of using the data to estimate benefits for some individuals. Finally, the article presents frequency distributions and statistical tabulations of the data to provide points of reference for EPUF users. + +Developing the Earnings Public-Use File + +In 2006, SSA released BEPUF, a data file based on a systematic random 1-percent sample of all individuals who were receiving Social Security benefits in December 2004. The file contains benefit and earnings information for the 473,366 individuals in the sample. SSA and Internal Revenue Service (IRS) Data Review Boards reviewed the file to assess the risk of personal data disclosure before approving its release to the public. + +The critical question in the initial EPUF development phase involved which data fields to include in the file. Users would undoubtedly like SSA to include all of the data fields from its administrative files. However, SSA has a legal obligation to protect the confidentiality of the individuals included in the file. This creates a tradeoff between the user's need for complete and accurate data and the need to ensure that the file's data fields do not disclose individual identities. Because BEPUF met the disclosure standards set by SSA and the IRS, its data fields served as a starting point for selecting fields for EPUF. + +A second critical issue was the need to balance the desire to add data fields with the time needed to prepare the underlying data and conduct the required data-disclosure analysis. SSA originally hoped to include earnings data fields beyond those included in BEPUF. However, choosing fields to add to the file was complicated by more than data-disclosure limitations. Reconciling the types of earnings data in SSA's administrative files with the different data-collection timelines over the life of the program made seemingly simple choices fairly complicated. + +To include new data fields would be much more complex because the additional fields would come from the detailed segment of the Master Earnings File (MEF).1 For each individual, the detailed segment is likely to contain more than one earnings record in a given year. As a result, working with the detailed segment of the MEF is much more complicated and would take more time and effort than working with data fields from the summary segment of the MEF, as was done for BEPUF. + +In addition, the only earnings data field that is available for all years from 1951 through 2006 is taxable earnings. Other fields of interest, such as noncovered earnings, covered earnings above the taxable maximum, and contributions to 401(k) retirement plans, are only available for selected years.2 Consider self-employment income: From 1951 through 1977, self-employment income is included in the earnings data field only to the extent that it is covered under the Social Security program. If an individual had wage-and-salary earnings above the taxable maximum and also had self-employment income, none of the self-employment income would be included in the earnings record. This produces undercounts of both the number of individuals with self-employment income and the dollar amount of that income. From 1978 through 1993, the detailed segment of the MEF contains a separate value for covered self-employment income. However, the amount reported in this field is still limited to earnings covered under the program. The full amount of self-employment income does not appear in the MEF until 1994, when the cap for covered earnings subject to the Medicare Hospital Insurance payroll tax was eliminated. As a result, the administrative files do not contain a complete history of an individual's self-employment income. + +After accounting for all of these considerations, SSA designed EPUF to contain nine data fields in two linkable data tables. The first linkable file contains a single record for each of the 4,348,254 individuals included in EPUF. Each record contains the following data fields: + +ID (a unique identification number) +year of birth (YOB) +sex +aggregate capped Social Security taxable earnings from 1937 through 1950 +aggregate quarters of coverage (QCs) earned from 1937 through 1950 +aggregate QCs earned in 1951 and 1952 + +The second linkable file contains 60,326,474 earnings records with positive earnings values. There are 3,131,424 individuals in this file who had positive earnings for at least 1 year during 1951–2006. Each of the records in this file contains the following data fields: + +ID (a unique identification number) +the year(s) when the individual had taxable Social Security earnings +the amount of capped Social Security taxable earnings for each of those years +the number of QCs earned for each year (except 1951 and 1952) based on the amount of capped Social Security taxable earnings + +These data fields are identical to those included in the BEPUF with one minor exception. EPUF contains multiple data fields for the QCs: aggregate QCs earned 1937–1950 and aggregate QCs earned in 1951 and 1952 in the first linkable file; and annual QCs earned from 1953 through 2006 in the second linkable file. By contrast, the BEPUF contains a single aggregate value for QCs earned as of December 31, 2004. Because of this difference, an EPUF user can determine an individual's eligibility for retired-worker and disabled-worker benefits at any given time. + +Overview of Earnings Records + +SSA's primary objective in collecting earnings data is to meet the operational needs of the program.3 As a result, the data contained in EPUF will be, in some aspects, somewhat limited from a researcher's perspective. However, the uniqueness of the data and the large sample size should outweigh these limitations in many cases. + +To use EPUF appropriately, users must understand the nature of its earnings data. For example, analysts must be aware that the earnings data in EPUF do not reflect all workers in the US labor market, nor the aggregate earnings generated by those workers.4 Putting the EPUF earnings data in their proper context requires an understanding of three measures of earnings distinct to the Social Security program: covered earnings, Social Security taxable earnings, and capped Social Security taxable earnings. + +The first measure refers to earnings "covered" for purposes of determining eligibility for the Social Security program. The Social Security Act defines the types of employment covered under the program, and coverage has expanded significantly over the years.5 Currently, nearly all types of employment are covered under Social Security. There are three primary exceptions: "state and local government employees whose employer has not elected to be covered under Social Security and who are participating in an employer-provided pension plan, current Federal civilian workers hired before 1984 who have not elected to be covered, and self-employed workers earning less than $400 in a calendar year" (Board of Trustees, 2010). "Covered earnings" has two components: wage-and-salary earnings from covered employment, and self-employment income covered under the program. + +The second measure is called Social Security taxable earnings because it reflects all covered earnings that are subject to the payroll tax.6 The annual earnings data in the MEF summary segment are a running total of an individual's taxable earnings up to the taxable maximum for each job in a given year, plus any taxable self-employment income. For the self-employed, "taxable earnings consists of net self-employment income which, when combined with any taxable wages for that individual, is at or below any applicable annual maximum taxable amount" (SSA 2009, G.17). If an individual has more than one employer, the amount of earnings in this data field may be greater than the taxable maximum in a given year. + +EPUF uses the third measure, capped Social Security taxable earnings, defined as the total amount of a worker's taxable earnings (including any taxable self-employment income) up to the taxable maximum in a given year. It does not include any earnings beyond the taxable maximum, as the previous measure can when a worker has multiple employers. This measure allows an observer to determine total amounts contributed to the program by workers and self-employed individuals.7 The primary reason EPUF uses this measure is that capped taxable earnings do not need to be top-coded for data disclosure purposes. Second, because the IRS and SSA approved BEPUF for release using capped taxable earnings, using the same measure in EPUF was deemed likely to expedite its approval. + +Two adjustments were made in moving the taxable earnings data from the MEF summary segment to the capped taxable earnings information contained in EPUF. First, all earnings values were top-coded at the taxable maximum in a given year. Second, any records with negative covered earnings were set to zero (this occurred very infrequently). + +Through 2006, SSA used three distinct mechanisms to collect the earnings data required to administer its programs: (1) paper and microfilm records that yield an individual's total covered earnings from 1937 through 1950, (2) quarterly earnings data reported by the individual's employer from 1951 through 1977, and (3) annual earnings reported by the individual's employer on Form W-2 from 1978 through 2006 (Chart 1). + +Chart 1. +Types of earnings data available from Social Security administrative files, 1937–2006 +Show as table +SOURCE: SSA. +a. From 1978 to 1990, data for only that portion of self-employment income that it is taxable for Social Security purposes are available. In general, during this period there is no way to distinguish between amounts of covered earnings from wages and salary, self-employment income, and earnings from agriculture. Beginning in 1991, the taxable maximum earnings amounts for Social Security and Medicare differed. Beginning in 1994, the cap on taxable Medicare covered earnings was eliminated, and data on total earnings amounts from each source became available. +b. Beginning in 1991 the Medicare taxable maximum earnings amount exceeded the Social Security taxable maximum, until the Medicare taxable maximum was eliminated altogether in 1994. + +In the years since the adoption of Form W-2, three additional types of earnings data have been collected to reflect expanded data needs: (1) aggregate deferred compensation, used to calculate the national average wage index, beginning in 1990; (2) Medicare taxable wage-and-salary and self-employment income, beginning in 1991; and (3) detailed items for the deferred compensation field, beginning in 2004.8 These changes are also reflected in Chart 1. + +1937–1950 Earnings Data + +Before the arrival of electronic data storage, SSA stored earnings data on either paper or microfilm. Given the limited storage capacity of early computers and the prohibitive costs associated with converting these data to electronic format, the earnings data for 1937–1950 on the MEF summary segment are available only as an aggregate number. As a result, the data extract from which EPUF is drawn contains two data fields for aggregate taxable earnings—one for 1937–2006, and the other for 1951–2006. The EPUF data field for aggregate Social Security taxable earnings from 1937–1950 was generated by subtracting the 1951–2006 aggregate earnings from the 1937–2006 aggregate earnings. + +Another data field of interest is the QCs earned during this period. An individual can earn up to four QCs in a year depending on his or her taxable earnings amount. QCs determine an individual's eligibility for retirement and disability benefits and a family's eligibility for survivor benefits. The MEF summary segment contains no annual values for QCs for 1937–1953. Instead, the extract contains data fields from the MEF that contain the "known" aggregate number of QCs earned during the following periods: 1947–2006, 1951–2006, 1947–1952, and 1953–2006. For EPUF, these data fields are manipulated to generate the aggregate number of QCs earned for the periods 1947–1950 and 1951–1952. + +Because the MEF has no known values for QCs from 1937 through 1946, SSA devised a three-step method to estimate the aggregate number of QCs earned by individuals with covered earnings during these years.9 The first step assigns one QC for each $500 of aggregate taxable earnings from 1937 through 1950. The second step subtracts the known sum of QCs earned from 1947 through 1950. (The QCs from 1947 through 1950 are generated by subtracting the known number of QCs earned from 1951 through 2006 from the known number of QCs earned from 1947 through 2006.) If the resulting number is positive, this value is assigned to the number of QCs earned from 1937 to 1946. If this number is negative, a value of 0 is assigned for the number QCs earned from 1937 to 1946. The final step adds the estimated QCs from 1937 to 1946 to the known QCs from 1947 to 1950 for the estimated number of QCs earned from 1937 to 1950.10 + +1951–1977 Earnings Data + +From 1951 through 1977, the earnings data used to administer Social Security came from two sources: the individual's employer and the IRS. SSA required employers to report covered wage-and-salary income quarterly. For the self-employed, the IRS processed the annual Social Security taxable self-employment income reported on the individual's Form 1040 on Schedule C and Schedule SE and transferred the data to SSA. Values in these data fields were added together to create a single entry for taxable Social Security earnings, which is stored on the Summary Earnings Record. As a result, it is not possible to determine whether covered earnings in a given year are from wages and salaries or from self-employment income. The MEF also contains separate indicators for the presence of self-employment income (Schedule C) or agriculture income (Schedule F) in a given year. However, if there are combinations among salary and wages, self-employment income, and income from agriculture, the amounts attributable to each source cannot be determined. As a result, these flags were not included in EPUF.11 + +As previously noted, the MEF has no annual values for the number of QCs earned in 1951 and 1952. This value is estimated by manipulating data used to calculate QCs from 1937 through 1950. Beginning in 1953, the MEF contains annual QC values based on quarterly earnings data. + +1978–2006 Earnings Data + +In 1978, SSA earnings data underwent major changes involving sources, processing, and types of data collected. Because requiring quarterly earnings reports had led to processing delays and administrative burdens, new legislation required employers to report their employee's earnings annually on Form W-2. The legislation also made SSA responsible for processing the W-2 earnings data. The source for self-employed taxable earnings, Form 1040 Schedule SE, remained unchanged. + +The move to annual collection of earnings data resulted in three significant changes in the types of data collected: + +The W-2 included earnings from employment that was not covered under Social Security. Prior to 1978, SSA was only concerned with taxable earnings from covered employment. +The ability to store data electronically and the need for more detailed earnings information to administer the program led SSA to establish separate data fields for taxable wage-and-salary income and taxable self-employment income. Prior to 1978, administrative data contained a single entry for all taxable earnings. +The W-2 allowed SSA to capture covered wage-and-salary income above the taxable maximum. Earnings reported to SSA for all previous years were capped at the taxable maximum. + +It is important to note that the inclusion of taxable self-employment income on an individual's earnings record reflects the reporting criteria used during two distinct periods. For 1978 through 1993, self-employment income appears on an individual's earnings record only when Social Security or Medicare taxes were due on that income. It was not until 1994, when the cap for taxable earnings subject to the Medicare payroll tax was eliminated, that SSA's earnings data began to include uncapped values for covered self-employment income. + +Several examples illustrate how the amount of taxable self-employment income differs from the amount of self-employment income reported for federal income tax purposes across these two periods. Suppose an individual earned $25,000 in covered wages and $25,000 in self-employment income, and assume a taxable maximum of $40,000. Prior to 1994, the individual's earnings record for that year would contain $25,000 for wage-and-salary income and only $15,000 for self-employment income. Now consider an individual with self-employment income of $55,000 and no covered wages. In this example, the individual's earnings record would have $40,000 for taxable self-employment income. From 1994 onward, there is no cap on the amount of covered earnings subject to the Medicare payroll tax. As a result, the full amount of both wage-and-salary and self-employment income in the examples above would be included in the individual's earnings record on the MEF, but is not in EPUF. + +The Revenue Act of 1978 also affected the earnings data collected by SSA by allowing the elective deferral of wage earnings.12 Elective deferrals enabled individuals to postpone the receipt and the taxation of certain types of earnings. This led to the creation of 401(k) retirement plans, 403(b) plans for employees of nonprofit organizations, and 457 plans for state and local government employees. From 1978 through 1983, these elective deferrals were not covered under Social Security. As a result, the taxable earnings data in EPUF for these years do not include contributions to these plans. + +Starting in 1984, elective deferrals are covered under the program and are reflected in the taxable earnings in EPUF (up to the taxable maximum). In 1990, SSA was required to include elective deferrals in the calculations of the average wage index, and created a separate data field in the MEF detailed section to capture this information. + +Data on annual QCs earned during 1978–2006 are based on taxable earnings in a given year. As noted earlier, the MEF contains annual QC values after 1952. + +Sample Selection, Data Cleaning, and Disclosure Protection + +EPUF consists of earnings records drawn from a 1-percent sample of the MEF (the "underlying EPUF sample"). A series of data cleaning and disclosure protection procedures produced the final EPUF. This section describes the process of selecting the underlying EPUF sample, the data cleaning steps, and the disclosure protections that were applied to the data to produce the EPUF. + +Sample Selection + +The sample universe for the EPUF is all SSNs issued before January 2007. Thus, any individual who does not have an SSN cannot be included in the EPUF. The EPUF sample was created using a systematic sampling process that closely approximates a random sample. For each area-group combination, an algorithm selects 100 out of the possible 10,000 SSNs.13 SSA then determines if the SSNs have been issued. The sampling algorithm is systematic in that it avoids any overlap between the BEPUF, EPUF, and any potential future public-use samples generated using the algorithm.14 SSA has determined that the design effect for the systematic random sample is effectively equal to one.15 + +The SSNs generated using this algorithm were checked for inclusion in the Numident file to confirm their presence in the Social Security administrative files.16 A final check verified that none of the SSNs in the sample overlapped those in the BEPUF. The individuals in the resulting underlying EPUF sample numbered 4,413,024.17 Note that the sample is not strictly representative of the US population because the sampling universe (all SSNs issued) includes individuals in Puerto Rico and the US territories. + +Data Cleaning + +A number of analyses were undertaken to determine if there were any problems with the data and, if so, what to do about them. Three key issues were identified: (1) a coding error incorrectly assigned a YOB value equal to 1900 to many individuals, (2) some YOB values were missing, and (3) some extreme age values occurred for individuals who had taxable earnings (values ranged from -47 years to 179 years).18 Several other smaller issues were discovered in the process of generating the EPUF and a number of steps were taken to "clean" the data before releasing the file to the public. + +The first check involved graphing the distribution of individuals in the underlying sample by their YOB. This graph produced an abnormally large spike in the number of individuals with a YOB value equal to 1900. For these 24,843 individuals, a check against the Numident file confirmed a YOB value of 1900 on 21,269 records. There were 3,464 individuals whose YOB value was missing on the Numident file; these were removed from EPUF. This left 110 individuals with an alternative (non-1900) YOB value on the Numident file. The Numident's alternative value was assigned for those individuals. + +The next data-cleaning issue involved the 13,405 individuals in the underlying sample whose MEF records had a missing value for YOB. The overwhelming majority (12,142) also had a missing value for YOB on the Numident file; these individuals were removed from EPUF. Of the remaining 1,263 individuals, 1,234 had a single YOB value on the Numident file; for them, the Numident YOB was used. This left 29 individuals who had multiple YOB values on the Numident file; for these, we assigned a "best" YOB value. + +The analysis of the age at which an individual in the underlying sample recorded taxable earnings found 77,458 individuals who either had age values of less than 14 or greater than 79, or had earnings during 1937–1950 but a YOB value after 1950. Again, MEF records were validated against the Numident file. Records for 5,810 individuals were removed for one of the following reasons: there was no logical choice among multiple alternative YOB values on the Numident, age when recording taxable earnings was either negative or greater than 100, or the YOB value was after 1950 although earnings were recorded during 1937–1950. + +The final adjustments included removing 5,935 individuals whose YOB value was before 1870, removing 1,096 individuals whose YOB value was equal to 2007, and removing 4 individuals who were assigned a missing YOB value. Individuals born before 1870 were removed because they were unlikely to have received Social Security benefits. The data for the underlying sample were extracted in 2007 and it is possible that a small number of individuals who were enumerated after December 31, 2006 were part of the sample. + +Data "cleaning" procedures resulted in the removal of records for 28,451 individuals from the underlying sample. The effect of removing these individuals on the number of earnings records and on the amount of earnings by year is discussed later in conjunction with the effect of the data disclosure procedures. + +Disclosure Protection + +The most critical determinant of whether data fields can be included in the public-use file is disclosure risk. To protect confidentiality, SSA removes all identifying information, evaluates disclosure risk posed by administrative earnings data for individuals that overlap other public-use files,19 and modifies any distinguishing characteristics that could identify individuals in the file. The data disclosure procedures applied to the EPUF fall into three broad categories: (1) removing any identifiable information from the file and evaluating the disclosure risk of public-use file overlap, (2) adjusting the earnings amounts to create a range of uncertainty between the amount of earnings reported to SSA and the amount released in EPUF, and (3) zeroing out earnings records because of age considerations. These categories are described in detail below. + +Removing identifiable information and evaluating disclosure risk from public-use file overlap. To minimize disclosure risk, the following steps were taken: + +All SSNs were removed from the file. +The records in the final EPUF were randomly sequenced. +Where possible, EPUF sample records were checked for overlap with other public-use files. + +As previously noted, there is no overlap between individuals in BEPUF and EPUF. There were 319 individuals in the underlying EPUF sample who were included in the New Beneficiary Data System (NBDS). These individuals were removed from the sample.20 + +Although minimal overlap between individuals in EPUF and individuals in the Synthetic SIPP Beta files (SSB) is likely, the SSA and IRS have concluded that there is no disclosure risk because all of the earnings data in the SSB are synthetic.21 + +The number of individuals in EPUF who are potentially included in the public-use files created from the 1964 Pilot Link Study, the 1973 Exact Match Study, and the Retirement History Study is very small (see text box). SSA and the IRS have determined that disclosure resulting from overlap of these files is very unlikely. + +PREVIOUS PUBLIC-USE DATA FILES WITH EARNINGS DATA + +SSA has released a number of public-use microdata files that contain earnings data from its administrative files. The first six items listed below are products of two interagency studies undertaken in the 1970s and 1980s: the 1963 Pilot Link Study and the 1973 Exact Match Study, conducted by SSA, the Census Bureau, and the IRS. SSA produced items 7 and 8 independently. + +The 1964 Current Population Survey—Administrative Record Pilot Link File +The 1973 Current Population Survey—Summary Earnings Record Exact Match File +The 1973 Current Population Survey—Administrative Record Exact Match File +The Social Security Longitudinal Earnings Exact Match Public Use File, 1937–1975 +The 1972 Augmented Individual Income Tax Model Exact Match File +The Retirement History Longitudinal Survey, 1969–1973, and Summary of Social Security Earnings: Merged Data +The New Beneficiary Data System +The 2004 Beneficiary and Earnings Public-Use File + +The 1963 Pilot Link Study matched data from Census Bureau's Current Population Survey with SSA and IRS administrative data files. The 1973 Exact Match Study refined the 1963 Pilot Link Study processes. The primary objective of both studies was to improve the quality of statistical output related to income distribution and redistribution. + +The Retirement History Study matched survey data with Social Security administrative data to create public-use data files useful for researching retirement decisions and circumstances. + +The New Beneficiary Data System consists of two separate surveys. The original survey was the New Beneficiary Survey, a nationally representative survey of beneficiaries who were in payment status during a 12-month period from mid-1980 to mid-1981. In 1992, SSA conducted the New Beneficiary Followup (NBF) survey and attached limited earnings data to all 18,599 individuals in the original survey. + +The 2004 Beneficiary and Earnings Public-Use file, released in 2006, is a systematic random sample of individuals who were on the benefit rolls as of December 2004. + +Adjusting earnings to create a range of uncertainty and limit potential disclosure. With a few exceptions, the earnings amounts in EPUF were random-rounded to a base of $25, $100, or $1,000, depending on the amount of earnings reported to SSA.22 Specifically, + +earnings greater than $100 and less than $1,000 were random-rounded to a base of $25; +earnings greater than $1,000 and less than $50,000 were random-rounded to a base of $100; and +earnings greater than $50,000 were random-rounded to a base of $1,000. + +Using this process, earnings near the taxable cap could be rounded up to the taxable maximum, and very low earnings could be rounded down to zero. SSA was concerned that this could affect two key research issues: (1) analyses of the differences between workers and nonworkers (as defined in terms of covered employment) and (2) analyses comparing individuals with earnings above and below the taxable maximum in a given year. To maintain the integrity of the data in these two areas, and to eliminate the possibility of rounding down to zero or rounding up to the taxable maximum in a given year, the following steps were taken: + +All annual earnings values less than $100 were replaced with the average amount of all earnings less than $100 in a given year. +All annual earnings within the random rounding base of the taxable maximum ($100 or $1,000, depending on the taxable maximum in a given year) were replaced by the average of all values within the rounding base for that year. +Any values for the aggregate amount of earnings from 1937 to 1950 greater than $37,000 were replaced with $41,500 (the average value of all aggregate earnings amounts greater than $37,000). +Any values for the aggregate amount of earnings from 1937 to 1950 that were less than $100 were replaced with $39 (the average dollar amount for all values of aggregate earnings less than $100). + +These adjustments to the random-rounding process may reduce the amount of uncertainty between the earnings reported to SSA and those contained in EPUF for a select group of individuals. Consider an individual with $100 in earnings. We know that the actual value of earnings reported to SSA for this individual had to be between $100 and $124. This creates a range of uncertainty of only $25 instead of plus or minus $25. However, this limited range of uncertainty only occurs for the $100 value of earnings. + +Second, consider an individual with earnings of $95,250 in a year when the taxable maximum was $96,000. This individual's earnings value was replaced with the average value for all individuals with earnings from $95,001 and $95,999. In this case, we know the actual value of earnings reported to SSA to within $1,000. This is a much smaller range of uncertainty than the difference of plus or minus $1,000 that applies to earnings greater than $50,000 and not within the random-rounding base of the taxable maximum. + +Third, the random-rounding process may also affect the number of annual QCs included in EPUF for 1953–2006. On the MEF, QCs are calculated based on the quarterly earnings (1951 to 1977) and on annual earnings (1978 to 2006) recorded for a given year. However, the random-rounding process can change the value of earnings by plus or minus $25, $100, or $1,000, depending on the amount of taxable earnings in a given year. Thus, QCs based on randomly rounded earnings values may differ from those based on the MEF. + +This potential discrepancy raises questions about the effectiveness of the random-rounding process. Consider a case in which the amount of earnings on the MEF is $735 and the rounded earnings value is $750 for a year in which $250 are needed to earn a QC. The QCs based on MEF earnings would be two, and the rounded-earnings QC value would be three. By using the MEF QC value in EPUF we would know that the actual earnings reported to SSA would be between $725 and $750. In addition to reducing the range of uncertainty for the individual's earnings, this could affect analyses of eligibility for benefits. + +In this light, the question arises: What is the appropriate value for QCs to include in EPUF? A comparison of the QC measure on the MEF with that based on randomly rounded earnings found the following four items: + +Of 60,326,474 records with positive earnings, QC values differed on only 175,609 (0.29 percent). +When records differed, the maximum difference was plus or minus one QC. +The aggregate number of QCs based on randomly rounded earnings (213,915,632) was 39,389 fewer than the aggregate number of quarters on the MEF, a difference of only 0.018 percent. +The net impact of random rounding on total QCs earned at the individual level was very small. Among those whose records were affected, nearly 97 percent had a net difference of plus or minus one quarter over their work histories. + +Given the very small differences between the two QC measures, SSA included the MEF measure in EPUF because it reflects an individual's actual number of QCs earned. + +Zeroing out earnings for certain ages. When the BEPUF was created, the IRS requested that SSA zero out all earnings for individuals born after 1937 who had earnings at ages 14 or younger to prevent disclosure of potentially identifiable data. + +SSA applied these same data disclosure procedures to EPUF. In addition to zeroing out any earnings for individuals who were very young, SSA assigned a value of zero to any earnings records that had a positive value when the individual was aged 86 or older. + +Table 1 shows the number of records that SSA either removed from the underlying EPUF sample because of data cleaning or assigned a value of $0 because of data disclosure procedures, along with the dollar value of earnings represented by these omitted records.23 Table 2 shows the number of records and the value of earnings represented in the entire underlying EPUF sample, in the omitted records, and in the resulting final EPUF, revealing that the omitted records are a very small share of the original underlying sample. + +Table 1. +Earnings records removed from underlying EPUF sample or with earnings values set to zero for data cleaning or disclosure protection procedures, 1951–2006 +Year Records removed for data cleaning Records with earnings values set to zero for individuals aged— Total +14 or younger 86 or older +Records Dollar amount Records Dollar amount Records Dollar amount Records Dollar amount +1951 2,759 5,665,897 1,646 254,528 0 0 4,405 5,920,425 +1952 2,829 5,941,257 1,793 283,133 0 0 4,622 6,224,390 +1953 2,805 6,027,761 1,778 316,999 0 0 4,583 6,344,760 +1954 2,712 5,880,985 1,216 211,168 0 0 3,928 6,092,153 +1955 3,024 6,959,324 1,496 269,778 0 0 4,520 7,229,102 +1956 3,113 7,458,390 1,560 298,590 56 77,183 4,729 7,834,164 +1957 3,085 7,594,978 1,494 304,594 88 140,290 4,667 8,039,862 +1958 3,032 7,390,087 1,036 235,218 115 179,890 4,183 7,805,195 +1959 3,037 8,135,307 1,048 247,442 135 204,584 4,220 8,587,334 +1960 2,997 8,186,207 1,129 246,054 148 273,315 4,274 8,705,575 +1961 2,945 8,086,654 1,080 238,310 170 315,373 4,195 8,640,337 +1962 2,937 8,339,769 1,022 241,864 173 340,236 4,132 8,921,869 +1963 2,928 8,465,681 1,158 260,460 182 358,582 4,268 9,084,723 +1964 2,919 8,789,314 1,208 286,514 181 397,263 4,308 9,473,091 +1965 2,987 9,166,718 1,454 366,245 189 425,929 4,630 9,958,893 +1966 3,035 11,318,086 1,963 477,524 210 506,443 5,208 12,302,053 +1967 3,027 11,629,233 2,128 544,917 193 511,459 5,348 12,685,609 +1968 3,071 13,106,921 2,459 707,891 212 549,174 5,742 14,363,986 +1969 3,084 13,678,081 2,887 903,985 217 567,872 6,188 15,149,938 +1970 3,084 13,777,730 2,758 987,296 225 563,126 6,067 15,328,153 +1971 3,060 14,117,871 2,758 966,145 203 579,624 6,021 15,663,640 +1972 3,069 15,613,850 3,224 1,254,230 234 680,321 6,527 17,548,401 +1973 3,069 17,630,854 4,007 1,565,846 246 870,503 7,322 20,067,203 +1974 3,096 19,670,766 4,083 1,828,581 258 950,736 7,437 22,450,084 +1975 2,948 20,124,329 3,587 1,817,022 247 1,082,987 6,782 23,024,338 +1976 2,965 21,504,597 3,606 2,023,184 270 1,142,883 6,841 24,670,664 +1977 2,972 22,805,353 4,035 2,484,999 275 1,228,865 7,282 26,519,217 +1978 2,948 24,277,547 4,569 3,479,281 299 1,459,620 7,816 29,216,447 +1979 2,927 27,336,728 4,339 3,915,380 302 1,615,747 7,568 32,867,855 +1980 2,852 28,188,933 3,754 4,130,883 296 1,694,111 6,902 34,013,927 +1981 2,736 28,247,820 3,433 4,092,412 278 1,680,975 6,447 34,021,207 +1982 2,557 28,006,503 3,019 4,123,014 320 1,963,325 5,896 34,092,842 +1983 2,498 28,325,155 2,886 4,092,376 339 2,175,128 5,723 34,592,659 +1984 2,525 29,220,576 3,474 4,682,009 325 2,140,629 6,324 36,043,213 +1985 2,482 30,028,067 3,893 5,404,605 344 2,151,727 6,719 37,584,399 +1986 2,452 30,415,341 3,593 5,086,159 358 2,245,808 6,403 37,747,309 +1987 2,403 30,272,513 3,896 5,377,760 345 2,220,378 6,644 37,870,651 +1988 2,410 30,171,045 4,402 4,589,446 324 2,461,835 7,136 37,222,326 +1989 2,336 30,739,323 4,693 4,514,906 354 3,015,574 7,383 38,269,803 +1990 2,293 30,787,395 4,039 4,082,369 337 3,115,513 6,669 37,985,278 +1991 2,198 29,839,368 3,427 3,380,565 354 3,031,322 5,979 36,251,255 +1992 2,151 30,622,053 3,444 3,320,321 385 3,233,655 5,980 37,176,029 +1993 2,311 31,248,868 3,453 3,833,342 497 3,287,167 6,261 38,369,376 +1994 2,331 32,203,088 3,847 4,116,755 554 3,072,048 6,732 39,391,891 +1995 2,334 33,036,888 3,725 4,345,292 548 3,489,519 6,607 40,871,699 +1996 2,318 33,864,278 3,868 4,744,775 553 3,596,750 6,739 42,205,802 +1997 2,305 35,451,643 3,928 5,780,153 614 4,349,378 6,847 45,581,174 +1998 2,308 37,255,636 4,126 6,576,731 638 4,517,465 7,072 48,349,833 +1999 2,284 38,915,191 4,010 7,408,910 678 5,136,825 6,972 51,460,925 +2000 2,250 40,225,040 4,122 7,885,400 751 5,085,548 7,123 53,195,988 +2001 2,184 40,499,362 3,712 7,971,572 764 5,649,651 6,660 54,120,585 +2002 2,078 40,125,933 3,271 7,919,378 733 6,126,470 6,082 54,171,781 +2003 1,986 39,695,001 2,869 7,885,607 848 7,454,773 5,703 55,035,381 +2004 1,936 40,701,220 2,686 8,262,664 933 8,533,980 5,555 57,497,864 +2005 1,845 40,491,527 2,582 8,311,535 915 9,109,953 5,342 57,913,014 +2006 1,759 40,382,967 2,584 8,320,514 999 9,476,470 5,342 58,179,951 +Total 148,586 1,267,641,009 163,257 177,256,628 19,212 125,037,983 331,055 1,569,935,621 +SOURCE: Author's calculations based on underlying EPUF sample. +Table 2. +Earnings records contained in the underlying EPUF sample, affected by data cleaning or disclosure protection procedures, and included in final EPUF, 1951–2006 +Year Records from the underlying EPUF sample with positive earnings Records affected by data cleaning or disclosure protection procedures a Final EPUF Final EPUF as a percentage of underlying EPUF sample +Records Dollar amount Records Dollar amount Records Dollar amount Records Dollar amount +1951 579,071 1,182,038,005 4,405 5,920,425 574,666 1,176,121,621 99.24 99.50 +1952 595,005 1,256,504,791 4,622 6,224,390 590,383 1,250,218,697 99.22 99.50 +1953 605,891 1,321,673,609 4,583 6,344,760 601,308 1,315,308,988 99.24 99.52 +1954 594,469 1,301,518,421 3,928 6,092,153 590,541 1,295,436,078 99.34 99.53 +1955 650,393 1,540,292,673 4,520 7,229,102 645,873 1,533,057,873 99.31 99.53 +1956 675,958 1,667,196,602 4,729 7,834,164 671,229 1,659,358,545 99.30 99.53 +1957 706,274 1,775,031,770 4,667 8,039,862 701,607 1,766,986,216 99.34 99.55 +1958 699,009 1,760,718,703 4,183 7,805,195 694,826 1,752,916,336 99.40 99.56 +1959 714,773 1,973,721,356 4,220 8,587,334 710,553 1,965,128,948 99.41 99.56 +1960 724,277 2,023,372,141 4,274 8,705,575 720,003 2,014,641,299 99.41 99.57 +1961 727,019 2,046,121,645 4,195 8,640,337 722,824 2,037,456,281 99.42 99.58 +1962 742,198 2,133,834,749 4,132 8,921,869 738,066 2,124,909,855 99.44 99.58 +1963 754,582 2,194,781,542 4,268 9,084,723 750,314 2,185,708,897 99.43 99.59 +1964 773,598 2,292,872,077 4,308 9,473,091 769,290 2,283,413,867 99.44 99.59 +1965 804,466 2,418,879,156 4,630 9,958,893 799,836 2,408,907,420 99.42 99.59 +1966 845,200 3,053,032,399 5,208 12,302,053 839,992 3,040,762,112 99.38 99.60 +1967 864,648 3,201,085,410 5,348 12,685,609 859,300 3,188,408,570 99.38 99.60 +1968 891,688 3,677,060,356 5,742 14,363,986 885,946 3,662,694,039 99.36 99.61 +1969 920,804 3,924,915,106 6,188 15,149,938 914,616 3,909,791,660 99.33 99.61 +1970 926,593 4,047,308,546 6,067 15,328,153 920,526 4,031,955,717 99.35 99.62 +1971 928,927 4,154,580,909 6,021 15,663,640 922,906 4,138,931,362 99.35 99.62 +1972 957,932 4,725,131,546 6,527 17,548,401 951,405 4,707,580,541 99.32 99.63 +1973 995,014 5,499,708,261 7,322 20,067,203 987,692 5,479,673,083 99.26 99.64 +1974 1,010,681 6,266,031,784 7,437 22,450,084 1,003,244 6,243,556,827 99.26 99.64 +1975 1,000,671 6,560,822,942 6,782 23,024,338 993,889 6,537,771,640 99.32 99.65 +1976 1,025,235 7,272,380,800 6,841 24,670,664 1,018,394 7,247,765,424 99.33 99.66 +1977 1,057,528 8,034,161,719 7,282 26,519,217 1,050,246 8,007,612,706 99.31 99.67 +1978 1,091,783 9,003,657,698 7,816 29,216,447 1,083,967 8,974,444,824 99.28 99.68 +1979 1,117,921 10,568,459,651 7,568 32,867,855 1,110,353 10,535,550,984 99.32 99.69 +1980 1,123,641 11,588,053,871 6,902 34,013,927 1,116,739 11,553,996,366 99.39 99.71 +1981 1,124,468 12,808,231,847 6,447 34,021,207 1,118,021 12,774,215,295 99.43 99.73 +1982 1,109,975 13,447,471,166 5,896 34,092,842 1,104,079 13,413,406,844 99.47 99.75 +1983 1,120,926 14,320,140,280 5,723 34,592,659 1,115,203 14,285,581,480 99.49 99.76 +1984 1,164,250 15,733,184,777 6,324 36,043,213 1,157,926 15,697,179,349 99.46 99.77 +1985 1,199,486 16,954,192,478 6,719 37,584,399 1,192,767 16,916,577,414 99.44 99.78 +1986 1,222,942 18,072,210,162 6,403 37,747,309 1,216,539 18,034,475,665 99.48 99.79 +1987 1,253,504 19,277,082,505 6,644 37,870,651 1,246,860 19,239,275,056 99.47 99.80 +1988 1,293,120 20,699,177,394 7,136 37,222,326 1,285,984 20,661,907,215 99.45 99.82 +1989 1,317,740 22,114,192,632 7,383 38,269,803 1,310,357 22,075,919,050 99.44 99.83 +1990 1,327,049 23,320,377,715 6,669 37,985,278 1,320,380 23,282,326,410 99.50 99.84 +1991 1,321,141 23,947,887,306 5,979 36,251,255 1,315,162 23,911,705,384 99.55 99.85 +1992 1,329,671 25,038,192,482 5,980 37,176,029 1,323,691 25,000,961,124 99.55 99.85 +1993 1,350,606 26,020,626,627 6,261 38,369,376 1,344,345 25,982,355,871 99.54 99.85 +1994 1,379,206 27,519,441,609 6,732 39,391,891 1,372,474 27,480,153,319 99.51 99.86 +1995 1,401,604 28,817,889,800 6,607 40,871,699 1,394,997 28,777,048,663 99.53 99.86 +1996 1,424,677 30,325,434,565 6,739 42,205,802 1,417,938 30,283,145,483 99.53 99.86 +1997 1,451,322 32,381,811,355 6,847 45,581,174 1,444,475 32,336,383,309 99.53 99.86 +1998 1,479,545 34,688,002,415 7,072 48,349,833 1,472,473 34,639,656,847 99.52 99.86 +1999 1,503,546 36,837,645,411 6,972 51,460,925 1,496,574 36,786,136,938 99.54 99.86 +2000 1,529,060 39,253,537,670 7,123 53,195,988 1,521,937 39,200,496,095 99.53 99.86 +2001 1,531,311 40,822,309,702 6,660 54,120,585 1,524,651 40,767,753,758 99.57 99.87 +2002 1,525,643 41,636,130,619 6,082 54,171,781 1,519,561 41,581,840,812 99.60 99.87 +2003 1,526,341 42,646,073,822 5,703 55,035,381 1,520,638 42,590,915,589 99.63 99.87 +2004 1,541,064 44,453,363,308 5,555 57,497,864 1,535,509 44,395,547,826 99.64 99.87 +2005 1,555,944 46,181,182,273 5,342 57,913,014 1,550,602 46,123,343,357 99.66 99.87 +2006 1,568,139 48,431,660,720 5,342 58,179,951 1,562,797 48,373,174,994 99.66 99.88 +Total 60,657,529 864,212,398,878 331,055 1,569,935,621 60,326,474 862,641,549,923 99.45 99.82 +SOURCE: Author's calculations based on underlying EPUF sample. +a. Includes records removed because of data cleaning and records with earnings values set zero for indivudals with earnings at age 14 or younger or at age 86 or older. + +After all of the data cleaning and data disclosure procedures were applied, several steps were taken to evaluate the validity of the data contained in EPUF. A forthcoming Research and Statistics Note compares the data in the underlying sample and the final EPUF with the earnings estimates published by SSA in the Annual Statistical Supplement to the Social Security Bulletin. + +Caveats on Using EPUF Data + +Any user should be fully aware of three caveats on using the EPUF: (1) earnings data in EPUF are capped taxable Social Security earnings, (2) EPUF does not contain all of the information needed to calculate benefits accurately for everyone in the file, and (3) there may be some errors in the administrative data underlying EPUF. + +Capped Taxable Social Security Earnings + +As previously noted, earnings data in EPUF are limited to capped taxable Social Security earnings. The file excludes data for workers whose only earnings are from noncovered employment. Additionally, the file does not contain covered earnings above the taxable maximum. + +Table 3 compares the number of workers covered under the Social Security program with all US workers. Although the percentage working in covered employment has increased dramatically over time—from 55 percent in 1939 to nearly 94 percent in 2006—6 percent of the US workforce in 2006 still worked in noncovered employment. + +Table 3. +Civilian workers covered by the Social Security system, selected years 1939–2006 +Year Paid civilian workers a +(millions) Workers in covered employment +or self-employment +Number (millions) As a percentage of paid civilian workers +1939 43.6 24.0 55.0 +1944 51.2 30.8 60.2 +1949 56.7 34.3 60.5 +1955 62.8 51.8 82.5 +1960 64.6 55.7 86.2 +1965 71.6 62.7 87.6 +1970 77.8 69.9 89.8 +1975 86.0 77.9 90.6 +1980 99.4 89.3 89.8 +1985 107.7 100.0 92.9 +1990 117.8 111.7 94.8 +1991 117.1 110.3 94.2 +1992 118.7 111.9 94.3 +1993 121.3 114.6 94.5 +1994 124.6 117.9 94.6 +1995 125.0 118.1 94.5 +1996 127.7 120.7 94.5 +1997 130.6 123.4 94.5 +1998 132.6 125.1 94.4 +1999 134.6 127.0 94.4 +2000 137.7 130.0 94.4 +2001 136.1 128.2 94.1 +2002 136.5 128.2 93.9 +2003 138.4 129.9 93.9 +2004 140.2 131.5 93.8 +2005 142.8 133.8 93.7 +2006 146.0 136.7 93.6 +SOURCE: Unpublished data from SSA's Office of the Chief Actuary. +NOTE: Data for 1939, 1944, and 1949 are monthly averages; data for all other years are as of December. +a. Includes wage-and-salary earners and the self-employed. + +Chart 2 shows that the amount of covered earnings expressed as a percentage of all earnings in the economy increased from approximately 70 percent in 1950 to nearly 85 percent in 2006. This represents a large increase in the share of earnings covered under the program, but it also reveals that approximately 15 percent of earnings in 2006 were not in covered employment. + +Chart 2. +Social Security earnings (weighted) as a percentage of all earnings +Show as table +SOURCES: Bureau of Economic Analysis National Income and Product Account; SSA (2009a); 2006 EPUF. + +However, noncovered earnings account for only part of the earnings "missing" from EPUF. Chart 2 also shows taxable Social Security earnings and the capped taxable Social Security earnings measure used in EPUF. As a percentage of total earnings in the economy, EPUF's capped taxable earnings ranges from around 55 percent in the early 1950s to 78 percent in 1986, then declines gradually to 70 percent by 2006. + +The relatively large differences between covered and taxable earnings from 1951 through the mid-1970s stem from the low taxable maximum earnings amounts during those years. The jagged pattern of the differences results from ad hoc changes to the taxable maximum. Prior to the 1972 Social Security Amendments, the taxable maximum was set by statute. From 1937 to 1950, the taxable maximum was $3,000. The first increase in the taxable maximum, to $3,600, occurred in 1951, and it increased four more times through 1971. The 1972 amendments provided an automatic annual increase in the taxable maximum proportional to the increase in the national average wage. The key point for EPUF users is that using different methodologies for increasing the taxable maximum has affected the number (and proportion) of workers with earnings at or above the taxable maximum. For example, in 1951, nearly 25 percent of workers with covered earnings had earnings equal to or greater than the taxable maximum. In 1960 and 1970, the percentages of workers with earnings at or above the taxable maximum were 28 percent and 26 percent, respectively. In 1980, the percentage dropped to 9 percent and by 2006, it had dropped even further, to 6 percent (SSA 2009, Table 4.B4).24 + +Chart 2 reveals that the earnings in EPUF do not account for a significant portion of the total earnings in the economy from 1951 through 2006. Thus, using EPUF to analyze work patterns for individuals with a mix of covered and noncovered earnings may produce inaccurate results. Suppose an individual started working in a noncovered job in 1945 that was redefined as covered employment in 1955. This individual's work history in the EPUF would begin in 1955, with no indication that he or she really started working in 1945. Another example is an individual who worked in covered employment during high school and college and subsequently worked in a job that was not covered. This would result in a covered work history that starts in the individual's early work years and stops shortly thereafter. + +Limitations on Estimating Benefits + +One expected use of EPUF is to evaluate how programmatic changes affect benefit amounts. However, such analysis is limited to estimating an individual's primary benefits; that is, benefits based on one's own earnings record. For example, auxiliary benefits—those to which individuals would be entitled based on their spouses' or parents' earnings record—cannot be estimated because there is no way to identify a spousal or parental link among individuals in EPUF.25 This is problematic because many female beneficiaries receive part or all of their benefits based on a current or former spouse's higher earnings. Nevertheless, analysts can make reasoned assumptions about family size and estimate hypothetical family benefits based on an individual's own earnings records. + +Analysts cannot use EPUF to estimate disability benefits because the file does not contain information about an individual's period(s) of disability. In addition, any calculation of retirement benefits for a disabled beneficiary would be inaccurate because it would exclude periods of disability. However, one can use EPUF to determine an individual's insured status in a given year and to estimate hypothetical disability benefits that could be awarded if an individual became disabled. + +The EPUF does not contain a date of death for deceased individuals. As a result, one cannot determine if a string of years with zero earnings reflects that the individual has retired, become disabled, or died. + +The accuracy of estimates for primary benefits may be affected by the lack of detailed information for some individuals in the file. When calculating an individual's benefit amount, SSA uses the certified earnings record, which includes any ancillary earnings information such as military credits, railroad employment income, or having multiple SSNs.26 Because EPUF omits this information, estimates of benefits for individuals who had these sources of income or had multiple SSNs are suspect. Although the number of individuals having multiple SSNs or railroad income is relatively small, accurate assessments of the effects of programmatic changes on these individuals would require such information. The number of individuals with military credits is likely to be much larger, but the impact on benefits is likely to be relatively small for those with limited military service. + +Incomplete information in the EPUF also hinders accurate estimates of benefits for individuals with earnings during 1937–1950. Recall that SSA had to estimate the number of QCs associated with earnings from this period. Consider an individual who applies for benefits but is a couple of quarters short of being eligible. In such a case, SSA reviews the microfilm record to determine the individual's actual amount of covered earnings during the period. SSA posts this amount to the detailed segment of the MEF then determines the QCs earned using the usual procedures. However, EPUF does not include the information from the microfilm. Therefore, analysts should exercise caution when using EPUF data on QCs for this period, and should note this fact in any analysis using that data field. + +The user should also note that precise computation of monthly benefits paid is not possible with the EPUF because age at entitlement, on which monthly benefit amounts are based, cannot be observed in the file. With EPUF, it is also not possible to adjust benefits for workers subject to the Windfall Elimination Provision, which reduces benefits of "individuals who have only minimal Social Security coverage and will receive a pension based on years of work in noncovered employment" (SSA 2009). + +Errors in Underlying Earnings Data + +SSA has been collecting data on individual workers covered under the program since its inception. The agency uses administrative files to determine eligibility for benefits, to determine benefit amounts, to estimate future benefit payments, and for a variety of other purposes. + +Each year, capturing the earnings data reported on Form W-2 and used for program purposes is a massive undertaking. For earnings reported in tax year 2006, SSA processed W-2s for nearly 155 million workers and generated approximately 250 million wage items. SSA processed nearly 80 percent of the wage items reported on the W-2s electronically, and the remaining 20 percent were scanned using character recognition software or keyed in manually. In addition, SSA received information on self-employment income from the IRS based on data reported on Schedule SE. This information accounted for approximately 20 million items posted to the MEF. In total, SSA posted nearly 270 million earnings-related items for tax year 2006 to its MEF. + +With so many items posted every year, the MEF is clearly susceptible to missing or erroneous earnings data. Each step of the process introduces potential errors. The employer may enter an incorrect amount for a given individual, or may put the correct information in the wrong box on the W-2. In addition, the SSN may not be valid or the name on the W-2 may not match the one to which the SSN was enumerated.27 Errors can also arise as SSA posts the data in the MEF. + +SSA has an elaborate set of checks to identify and correct improperly reported earnings information.28 The agency verifies that the information on all the W-2s submitted by an employer corresponds to the amounts reported by the employer on Form W-3. SSA continuously updates the MEF as corrected W-2s (W-2c's) and delinquent W-2s stream in throughout the year. Workers may also file amended tax returns to correct errors reported in previous filings. + +If SSA detects errors in a worker's earning record, it sends a letter to the employer seeking clarification. In response, the employer may file a W-2c. In some instances, an employer files a W-2c and the employee supplies information to correct the same error; the resulting double-correction also produces errors on the MEF. + +Another opportunity to catch earnings-record errors arises when SSA mails out its annual Social Security statement to workers aged 25 or older. Errors detected by the worker can be resolved at any SSA field office.29 Finally, workers can catch errors in their earnings data when they apply for benefits. Applicants see their complete earnings histories and can direct SSA to correct any verifiable errors they spot. Nevertheless, despite extensive efforts to ensure accurate earnings records, the EPUF may contain erroneous information. + +Highlights from the EPUF + +This section presents statistical highlights of the earnings data for the 4,384,254 individuals whose records are included in EPUF. Figures cited are unweighted. + +Individuals by YOB + +There are five distinct trends in the distribution of individuals by birth year in EPUF (Chart 3). The first is a steep increase in the number of individuals in the file, starting with 1,813 born in 1870 and peaking at 31,877 born in 1921. The second is a steady decline from 31,104 born in 1922 to 26,568 in 1933. The third trend is a dramatic increase to nearly 53,000 who were born in 1962, nearly doubling the number of individuals born in 1933. The fourth is a steep decline from 52,138 individuals born in 1963 to 41,792 born in 1975. The final trend reflects relatively flat numbers of individuals born from 1976 through 2006, from 41,822 to 41,241, respectively. + +Chart 3. +Number of individuals in EPUF, by year of birth +Show as table +SOURCE: Author's calculations based on the 2006 EPUF. + +Chart 4 presents the distribution of individuals by YOB and sex.30 For birth years from 1870 to about 1925, men outnumber women in EPUF. With a few exceptions, the numbers of women and men in the file are nearly the same for birth years from 1926 to 1947. The number of men born from 1948 to 2006 is consistently higher than the number of women, although not by very much. + +Chart 4. +Number of individuals in EPUF, by year of birth and sex +Show as table +SOURCE: Author's calculations based on the 2006 EPUF. +Workers and Nonworkers + +There are four distinct categories of individuals in EPUF depending on whether they had any Social Security taxable earnings and, if so, the period in which they were earned. The four categories are nonworkers (individuals with no taxable earnings), workers with taxable earnings during 1937–1950 only, workers with taxable earnings during 1951–2006 only, and workers with taxable earnings in both periods. More than one-half of the individuals in EPUF had earnings during 1951–2006 only, about 4 percent had earnings only during 1937–1950, and 16 percent had earnings in both periods (Chart 5). + +Chart 5. +Percentage distribution of individuals in EPUF, by capped Social Security taxable earnings status +SOURCE: Author's calculations based on the 2006 EPUF. + +Initially, the 24.7-percent figure for individuals in EPUF who did not have any earnings seems very large. However, Chart 6 reveals that the bulk of these individuals (68 percent) were born after 1987. Thus, the main reason so many individuals in EPUF have no earnings is that most of them are not old enough to participate in the labor market.31 + +Chart 6. +Cumulative distribution of individuals in EPUF with no capped Social Security taxable earnings, by year of birth +Show as table +SOURCE: Author's calculations based on the 2006 EPUF. + +Chart 7 presents the distribution by sex of individuals in EPUF in each earner status. Women outnumber men among those who do not have any earnings (52 percent versus 48 percent). Among individuals with earnings during 1937–1950 only, a large majority are men (57 percent versus 43 percent). This result was expected because women were much less active in the labor market during that period. Individuals in EPUF with earnings during both periods skew even more towards men, 61 percent versus 39 percent. Individuals with earnings during 1951–2006 only are more evenly distributed between men (51 percent) and women (49 percent), reflecting women's substantial increases in labor force participation during the period. + +Chart 7. +Percentage distribution of individuals in EPUF in each capped Social Security taxable earnings status, by sex +Show as table +SOURCE: Author's calculations based on the 2006 EPUF. +NOTE: Rounded components of percentage distributions do not necessarily sum to 100. + +Individuals in EPUF with any earnings during 1937–1950 number 874,287. Approximately 60 percent are men (523,465) and 40 percent are women (350,229). There are also records for 593 individuals whose sex is unknown and who had earnings during this period. Appendix Chart A1 presents the distribution of individuals with earnings during this period by YOB and sex. The average and median values for all earnings during this period are $9,106 and $4,600, respectively (not shown). The average earnings for men ($11,990) is much higher than that for women ($7,521). The median earnings for men and women diverge even more, at $7,900 and $1,800, respectively. + +Earnings in EPUF + +Chart 8 shows that the gap between the number of men and women with earnings in a given year has decreased significantly between 1951 and 2006. Chart 9 shows a slow but steady climb in aggregate earnings for men and women over the same period.32 The difference between the total amount of earnings for men and women has been increasing over time. However, women's taxable earnings as a percentage of all taxable earnings has increased from 22.1 percent in 1951 to 39.7 percent in 2006 (see Table A2). Table 4 presents the average and median earnings of men, women, and individuals with unknown sex in the EPUF. + +Chart 8. +Number of individuals with capped Social Security taxable earnings in EPUF, by sex, 1951–2006 +SOURCE: Author's calculations based on the 2006 EPUF. +Chart 9. +Aggregate amount of capped Social Security taxable earnings in EPUF, by sex of earner, 1951–2006 +SOURCE: Author's calculations based on the 2006 EPUF. +Table 4. +Average and median Social Security taxable earnings in EPUF, by sex, 1951–2006 (in dollars) +Year All workers Men Women Sex unknown +Mean Median Mean Median Mean Median Mean Median +1951 2,047 2,100 2,404 2,900 1,344 1,200 1,978 1,950 +1952 2,118 2,300 2,482 3,100 1,423 1,300 1,904 1,950 +1953 2,187 2,400 2,553 3,300 1,499 1,300 2,043 2,000 +1954 2,194 2,400 2,544 3,300 1,527 1,400 1,886 1,700 +1955 2,374 2,400 2,779 3,300 1,583 1,300 1,932 1,600 +1956 2,472 2,600 2,884 3,500 1,678 1,500 1,897 1,400 +1957 2,518 2,700 2,900 3,600 1,752 1,500 1,874 1,450 +1958 2,523 2,700 2,881 3,500 1,801 1,600 1,914 1,500 +1959 2,766 2,800 3,204 3,800 1,903 1,600 2,040 1,600 +1960 2,798 2,900 3,239 3,900 1,945 1,700 2,161 1,800 +1961 2,819 2,900 3,248 3,900 1,994 1,700 2,190 1,800 +1962 2,879 3,100 3,313 4,100 2,059 1,800 2,439 2,100 +1963 2,913 3,100 3,345 4,300 2,104 1,800 2,534 2,200 +1964 2,968 3,300 3,402 4,500 2,166 1,900 2,717 2,700 +1965 3,012 3,400 3,459 4,754 2,206 2,000 2,871 2,900 +1966 3,620 3,600 4,312 5,000 2,424 2,000 3,548 3,300 +1967 3,710 3,700 4,380 5,200 2,576 2,200 3,580 3,500 +1968 4,134 4,000 4,944 5,600 2,796 2,400 4,099 3,800 +1969 4,275 4,200 5,093 6,000 2,956 2,600 4,090 3,900 +1970 4,380 4,400 5,175 6,200 3,113 2,700 4,214 4,200 +1971 4,485 4,600 5,259 6,500 3,257 2,900 4,409 4,650 +1972 4,948 4,900 5,893 7,000 3,482 3,000 5,067 5,100 +1973 5,548 5,200 6,744 7,500 3,745 3,100 5,776 5,450 +1974 6,223 5,500 7,653 8,000 4,115 3,400 6,572 5,950 +1975 6,578 5,800 8,023 8,300 4,473 3,700 6,854 6,400 +1976 7,117 6,300 8,693 8,900 4,870 4,100 7,806 6,950 +1977 7,625 6,700 9,343 9,600 5,229 4,300 8,384 7,500 +1978 8,279 7,300 10,132 10,400 5,750 4,900 8,816 8,200 +1979 9,488 7,900 11,790 11,300 6,410 5,400 10,383 9,400 +1980 10,346 8,600 12,804 12,000 7,112 6,000 11,052 9,600 +1981 11,426 9,400 14,106 13,000 7,927 6,700 12,280 10,300 +1982 12,149 9,900 14,844 13,300 8,659 7,200 13,362 10,950 +1983 12,810 10,300 15,613 13,700 9,224 7,600 13,917 11,400 +1984 13,556 10,900 16,572 14,500 9,766 7,900 14,365 11,300 +1985 14,183 11,400 17,303 15,100 10,325 8,300 15,037 12,000 +1986 14,824 11,900 18,002 15,600 10,948 8,800 16,204 12,950 +1987 15,430 12,300 18,636 16,100 11,560 9,300 16,257 12,700 +1988 16,067 12,900 19,304 16,600 12,186 9,800 16,943 13,250 +1989 16,847 13,400 20,163 17,200 12,902 10,300 18,780 15,100 +1990 17,633 14,000 20,990 17,800 13,669 10,900 19,937 16,500 +1991 18,182 14,400 21,455 17,900 14,342 11,400 21,272 18,250 +1992 18,887 14,900 22,199 18,400 15,034 11,900 22,037 18,800 +1993 19,327 15,100 22,662 18,700 15,455 12,100 22,841 20,150 +1994 20,022 15,600 23,576 19,400 15,930 12,400 23,137 18,700 +1995 20,629 16,200 24,224 20,000 16,504 12,900 23,835 19,100 +1996 21,357 16,800 25,066 20,800 17,129 13,400 24,950 20,200 +1997 22,386 17,600 26,274 21,900 17,985 14,100 24,905 20,500 +1998 23,525 18,600 27,582 23,100 18,958 14,900 26,290 21,800 +1999 24,580 19,400 28,802 24,100 19,840 15,600 28,665 23,700 +2000 25,757 20,300 30,149 25,200 20,851 16,400 30,797 25,450 +2001 26,739 21,000 31,141 25,700 21,826 17,100 32,920 26,500 +2002 27,364 21,300 31,743 25,900 22,499 17,500 33,686 26,800 +2003 28,009 21,700 32,396 26,300 23,154 18,000 34,133 29,900 +2004 28,913 22,500 33,396 27,200 23,965 18,500 34,542 29,100 +2005 29,745 23,100 34,341 28,000 24,685 19,000 36,241 30,600 +2006 30,953 24,000 35,764 29,100 25,696 19,700 36,799 32,500 +SOURCE: Author's calculations based on the 2006 EPUF. +Summary + +The 2006 EPUF contains earnings data for individuals drawn from a 1-percent sample of all SSNs issued before January 2007. The file contains limited demographic information and earnings data related to the Social Security program for 4,348,254 individuals. Although the file contains limited data fields, it is much larger than other public-use files with earnings histories. EPUF will provide policymakers and researchers with a unique tool to evaluate the Social Security programs and potential reforms. + +Appendix +Table A1. +Number and percentage distribution of individuals with Social Security taxable earnings records in EPUF, by sex, 1951–2006 +Year All workers Men Women Sex unknown +Number Percentage of workers Number Percentage of workers Number Percentage of workers +1951 574,666 380,673 66.2 193,655 33.7 338 0.1 +1952 590,383 387,176 65.6 202,841 34.4 366 0.1 +1953 601,308 392,710 65.3 208,254 34.6 344 0.1 +1954 590,541 386,904 65.5 203,317 34.4 320 0.1 +1955 645,873 426,862 66.1 218,624 33.8 387 0.1 +1956 671,229 441,870 65.8 228,933 34.1 426 0.1 +1957 701,607 468,328 66.8 232,861 33.2 418 0.1 +1958 694,826 464,175 66.8 230,290 33.1 361 0.1 +1959 710,553 471,169 66.3 239,044 33.6 340 a +1960 720,003 474,604 65.9 245,085 34.0 314 a +1961 722,824 475,513 65.8 247,008 34.2 303 a +1962 738,066 482,590 65.4 255,187 34.6 289 a +1963 750,314 488,952 65.2 261,077 34.8 285 a +1964 769,290 499,171 64.9 269,834 35.1 285 a +1965 799,836 514,368 64.3 285,184 35.7 284 a +1966 839,992 531,966 63.3 307,743 36.6 283 a +1967 859,300 540,003 62.8 319,006 37.1 291 a +1968 885,946 551,920 62.3 333,731 37.7 295 a +1969 914,616 564,231 61.7 350,067 38.3 318 a +1970 920,526 565,453 61.4 354,749 38.5 324 a +1971 922,906 565,675 61.3 356,911 38.7 320 a +1972 951,405 578,237 60.8 372,840 39.2 328 a +1973 987,692 593,494 60.1 393,844 39.9 354 a +1974 1,003,244 597,517 59.6 405,375 40.4 352 a +1975 993,889 589,138 59.3 404,403 40.7 348 a +1976 1,018,394 598,171 58.7 419,885 41.2 338 a +1977 1,050,246 611,288 58.2 438,619 41.8 339 a +1978 1,083,967 625,380 57.7 458,246 42.3 341 a +1979 1,110,353 635,128 57.2 474,898 42.8 327 a +1980 1,116,739 634,313 56.8 482,099 43.2 327 a +1981 1,118,021 632,816 56.6 484,894 43.4 311 a +1982 1,104,079 622,799 56.4 480,974 43.6 306 a +1983 1,115,203 625,683 56.1 489,213 43.9 307 a +1984 1,157,926 644,631 55.7 512,978 44.3 317 a +1985 1,192,767 659,120 55.3 533,338 44.7 309 a +1986 1,216,539 668,310 54.9 547,925 45.0 304 a +1987 1,246,860 681,710 54.7 564,843 45.3 307 a +1988 1,285,984 700,961 54.5 584,711 45.5 312 a +1989 1,310,357 711,727 54.3 598,334 45.7 296 a +1990 1,320,380 714,671 54.1 605,422 45.9 287 a +1991 1,315,162 709,678 54.0 605,204 46.0 280 a +1992 1,323,691 711,615 53.8 611,804 46.2 272 a +1993 1,344,345 722,012 53.7 622,065 46.3 268 a +1994 1,372,474 734,324 53.5 637,884 46.5 266 a +1995 1,394,997 745,091 53.4 649,650 46.6 256 a +1996 1,417,938 755,129 53.3 662,564 46.7 245 a +1997 1,444,475 766,814 53.1 677,412 46.9 249 a +1998 1,472,473 779,589 52.9 692,640 47.0 244 a +1999 1,496,574 791,384 52.9 704,947 47.1 243 a +2000 1,521,937 802,776 52.7 718,923 47.2 238 a +2001 1,524,651 803,891 52.7 720,525 47.3 235 a +2002 1,519,561 799,527 52.6 719,799 47.4 235 a +2003 1,520,638 798,428 52.5 721,985 47.5 225 a +2004 1,535,509 805,264 52.4 730,008 47.5 237 a +2005 1,550,602 812,364 52.4 738,007 47.6 231 a +2006 1,562,797 815,763 52.2 746,806 47.8 228 a +Total 60,326,474 34,553,056 57.3 25,756,465 42.7 16,953 a +SOURCE: Author's calculations based on the 2006 EPUF. +NOTE: Rounded components of percentage distributions do not necessarily sum to 100. +a. Less than 0.05 percent +Table A2. +Dollar amount and percentage distribution of Social Security taxable earnings in EPUF, by sex of earner, 1951–2006 +Year Total Social Security taxable earnings ($) Men Women Sex unknown +Dollar amount Percentage of earnings Dollar amount Percentage of earnings Dollar amount Percentage of earnings +1951 1,176,121,621 915,224,528 77.8 260,228,626 22.1 668,467 0.1 +1952 1,250,218,697 960,951,736 76.9 288,570,223 23.1 696,739 0.1 +1953 1,315,308,988 1,002,401,906 76.2 312,204,394 23.7 702,689 0.1 +1954 1,295,436,078 984,354,316 76.0 310,478,153 24.0 603,609 a +1955 1,533,057,873 1,186,138,562 77.4 346,171,624 22.6 747,687 a +1956 1,659,358,545 1,274,501,991 76.8 384,048,272 23.1 808,282 a +1957 1,766,986,216 1,358,130,591 76.9 408,072,212 23.1 783,413 a +1958 1,752,916,336 1,337,517,626 76.3 414,707,883 23.7 690,827 a +1959 1,965,128,948 1,509,520,746 76.8 454,914,691 23.1 693,511 a +1960 2,014,641,300 1,537,199,839 76.3 476,762,888 23.7 678,572 a +1961 2,037,456,281 1,544,306,338 75.8 492,486,504 24.2 663,439 a +1962 2,124,909,855 1,598,792,149 75.2 525,412,919 24.7 704,788 a +1963 2,185,708,897 1,635,775,204 74.8 549,211,363 25.1 722,331 a +1964 2,283,413,867 1,698,087,380 74.4 584,552,087 25.6 774,400 a +1965 2,408,907,420 1,779,058,958 73.9 629,033,153 26.1 815,308 a +1966 3,040,762,112 2,293,932,086 75.4 745,826,027 24.5 1,003,999 a +1967 3,188,408,570 2,365,472,074 74.2 821,894,805 25.8 1,041,691 a +1968 3,662,694,039 2,728,439,824 74.5 933,045,098 25.5 1,209,116 a +1969 3,909,791,660 2,873,795,305 73.5 1,034,695,870 26.5 1,300,485 a +1970 4,031,955,717 2,926,141,698 72.6 1,104,448,529 27.4 1,365,490 a +1971 4,138,931,362 2,975,093,757 71.9 1,162,426,686 28.1 1,410,920 a +1972 4,707,580,541 3,407,572,244 72.4 1,298,346,419 27.6 1,661,877 a +1973 5,479,673,083 4,002,814,306 73.0 1,474,814,111 26.9 2,044,666 a +1974 6,243,556,827 4,573,069,433 73.2 1,668,173,966 26.7 2,313,428 a +1975 6,537,771,640 4,726,502,691 72.3 1,808,883,849 27.7 2,385,100 a +1976 7,247,765,424 5,200,093,565 71.7 2,045,033,268 28.2 2,638,591 a +1977 8,007,612,706 5,711,058,117 71.3 2,293,712,581 28.6 2,842,008 a +1978 8,974,444,824 6,336,610,720 70.6 2,634,827,857 29.4 3,006,247 a +1979 10,535,550,984 7,488,124,641 71.1 3,044,030,994 28.9 3,395,348 a +1980 11,553,996,366 8,121,707,068 70.3 3,428,675,206 29.7 3,614,092 a +1981 12,774,215,295 8,926,653,455 69.9 3,843,742,790 30.1 3,819,050 a +1982 13,413,406,844 9,244,523,741 68.9 4,164,794,202 31.0 4,088,900 a +1983 14,285,581,480 9,768,685,099 68.4 4,512,623,779 31.6 4,272,602 a +1984 15,697,179,349 10,682,698,768 68.1 5,009,926,755 31.9 4,553,826 a +1985 16,916,577,414 11,405,063,900 67.4 5,506,867,114 32.6 4,646,400 a +1986 18,034,475,665 12,031,058,617 66.7 5,998,490,972 33.3 4,926,076 a +1987 19,239,275,056 12,704,633,159 66.0 6,529,650,970 33.9 4,990,927 a +1988 20,661,907,215 13,531,532,531 65.5 7,125,088,330 34.5 5,286,353 a +1989 22,075,919,050 14,350,553,706 65.0 7,719,806,564 35.0 5,558,780 a +1990 23,282,326,410 15,001,089,862 64.4 8,275,514,770 35.5 5,721,778 a +1991 23,911,705,385 15,225,958,913 63.7 8,679,790,242 36.3 5,956,230 a +1992 25,000,961,124 15,797,304,161 63.2 9,197,663,036 36.8 5,993,927 a +1993 25,982,355,871 16,362,219,545 63.0 9,614,015,049 37.0 6,121,278 a +1994 27,480,153,319 17,312,328,296 63.0 10,161,670,536 37.0 6,154,487 a +1995 28,777,048,662 18,048,809,034 62.7 10,722,137,749 37.3 6,101,879 a +1996 30,283,145,482 18,928,028,662 62.5 11,349,003,953 37.5 6,112,867 a +1997 32,336,383,309 20,147,226,145 62.3 12,182,955,785 37.7 6,201,379 a +1998 34,639,656,847 21,502,279,695 62.1 13,130,962,491 37.9 6,414,661 a +1999 36,786,136,937 22,793,062,944 62.0 13,986,108,356 38.0 6,965,637 a +2000 39,200,496,095 24,202,981,172 61.7 14,990,185,170 38.2 7,329,753 a +2001 40,767,753,758 25,034,170,600 61.4 15,725,846,857 38.6 7,736,301 a +2002 41,581,840,812 25,379,005,293 61.0 16,194,919,207 38.9 7,916,312 a +2003 42,590,915,589 25,866,065,725 60.7 16,717,169,849 39.3 7,680,015 a +2004 44,395,547,826 26,892,533,184 60.6 17,494,828,170 39.4 8,186,472 a +2005 46,123,343,358 27,897,078,736 60.5 18,217,892,871 39.5 8,371,751 a +2006 48,373,174,994 29,174,561,654 60.3 19,190,223,246 39.7 8,390,094 a +Total 862,641,549,921 554,262,495,993 64.3 308,177,569,073 35.7 201,484,854 a +SOURCE: Author's calculations based on the 2006 EPUF. +NOTE: Rounded components of percentage distributions do not necessarily sum to 100. +a. Less than 0.05 percent +Chart A1. +Number of individuals in EPUF with capped Social Security taxable earnings during 1937–1950, by year of birth and sex +Show as table +SOURCE: Author's calculations based on the 2006 EPUF. +Notes + + 1 The MEF contains all of the earnings data collected to administer the Social Security programs. + + 2 Noncovered earnings are wage and salary income not covered under the Social Security programs. + + 3 For a discussion of SSA earnings data, see Olsen and Hudson (2009). + + 4 This limitation is discussed later in the article. + + 5 For historical changes in coverage, see SSA (2009, Table 2.A1). + + 6 SSA's Office of Research, Evaluation, and Statistics uses this measure to generate its published estimates of earnings. + + 7 Technically, this is not always correct because some earnings are reported on the Earnings Suspense File and not posted on the MEF. For a detailed discussion, see GAO (2005). + + 8 The average wage index is calculated annually using wages subject to federal income taxes and contributions to deferred compensation plans. The index is used in determining an individual's retirement benefit amount as well as to determine several other key dollar amounts in the administration of the Social Security programs. For more detail, see SSA (2010). + + 9 This process is done because of the prohibitive costs associated with going back to the microfilm to determine the exact number of QCs earned by individuals with earnings during the 1937–1946 period. + +10 For individuals with earnings during this period who did not meet program criteria for benefits or coverage (using this technique to estimate QCs), a detailed manual search of microfilm records determines if the individual was eligible for benefits and, if so, the benefit amount. + +11 Including these flags would have created serious data disclosure problems because they provide much more individually identifiable information. + +12 For a detailed discussion of deferred earnings in SSA data, see Pattison and Waldron (2008). + +13 For a description of the three components of the SSN (area, group, and serial number), see Puckett (2009). + +14 Nonoverlapping samples are important from a data disclosure perspective if SSA decides to release any additional public-use data files. + +15 The sample design is equal to the ratio of the variance of the systematic random sample for EPUF and the variance assuming a simple random sample without replacement. + +16 The Numident is a master file of all SSNs ever assigned. It contains the identifying information given when an individual applies for an SSN. + +17 This includes 319 individuals who were ultimately removed from the underlying EPUF sample because they were also in the New Beneficiary Data Systems (discussed in the data disclosure section of the article). + +18 The source for YOB data in EPUF is the MEF summary record, which may not contain the same value that appears in the Numident or Master Beneficiary Record files. + +19 See the text box for a brief description of the other public-use data files that contain earnings data from Social Security administrative files. To evaluate the disclosure risk for individuals in EPUF who are included in other publicly available data files, SSA considers four key points: the potential magnitude of the overlap between files, the possibility of matching records across files with any certainty, the additional information that would be revealed in the unlikely event that records could be matched with any certainty, and the ability to reidentify someone in EPUF based on publicly available data. + +20 Thus, the total number of individuals removed from the underlying EPUF sample because of data cleaning and data disclosure is 28,770. + +21 The SSB is a set of files containing individual-level data synthesized from Census Bureau's Survey of Income Program Participation (SIPP) results linked to various Social Security administrative files. The Census Bureau produces the SSB, which is the result of an interagency project that also includes SSA and IRS. + +22 Under random rounding, a multiple of the rounding base will not change, while a number that is not a multiple of the base will round to either of the two closest multiples of the base. For example, when random-rounding to a base of $25, the value $550 will not change. However, a value of $562 may round to either $550 or $575. The random-rounding process provides some uncertainty about the actual number reported on the individual's SSA earnings record. For example, if the earnings contained in EPUF are $550 we know the actual amount reported to SSA was between $526 and $574. The interval of uncertainty increases with the amount of earnings reported. + +23 Unless otherwise noted, the numbers of records and the amounts of earnings shown in the charts and tables are unweighted. + +24 Additionally, in many years, the percentage of individuals with earnings at or above the taxable maximum differs substantially by sex. + +25 SSA cannot determine married-couple or parent-child relationships in the file based on the information derived from the MEF. SSA establishes such linkages after an individual applies for benefits. In any event, linking currently or previously married individuals or indicating a familial relationship in EPUF would create serious data disclosure risks. + +26 An electronic folder (created when an individual applies for benefits) contains the certified earnings record, which summarizes all the earnings records from the MEF and provides the basis for computing an individual's benefits. + +27 Enumeration is the process by which SSA assigns a unique SSN for every person in order to create a work and benefit record for the Social Security program. SSA verifies all of the information on the SSN application. + +28 Earnings that cannot be properly assigned to an individual's earnings records on the MEF are placed on the Earnings Suspense File. The amount of earnings assigned to the Earnings Suspense File has grown dramatically over the past 20 years (GAO 2005). + +29 In March 2011, budget constraints led the SSA to suspend the production and mailing of printed statements. The agency is working toward developing an online alternative. + +30 This chart omits individuals whose sex is unknown. Appendix Table A2 shows distributions by sex, including individuals of unknown sex. + +31 Recall that any earnings reported before the individual was 15 years old were assigned a value of zero for data disclosure reasons. + +32 Appendix Tables A1–A2 present the data underlying Charts 8–9. + +References + +[Board of Trustees] Board of Trustees of the Old-Age, Survivors, and Disability Insurance Trust Funds. 2010. Annual Report of the Board of Trustees of the Old-Age, Survivors, and Disability Insurance Trust Funds, 2010. Washington, DC: SSA. + +[GAO] Government Accountability Office. 2005. Better Coordination Among Federal Agencies Could Reduce Unidentified Earnings Reports. Report no. GAO-05-154. Washington, DC: Government Printing Office. + +Olsen, Anya, and Russell Hudson. 2009. "Social Security Administration's Master Earnings File: Background Information." Social Security Bulletin 69(3): 29–45. + +Pattison, David, and Hilary Waldron. 2008. "Trends in Elective Deferrals of Earnings from 1990–2001 in Social Security Administrative Data." Research and Statistical Note No. 2008-03. Washington, DC: SSA. + +Puckett, Carolyn. 2009. "The Story of the Social Security Number." Social Security Bulletin 69(2): 55–74. + +[SSA] Social Security Administration. 2009. Annual Statistical Supplement to the Social Security Bulletin, 2008. Washington, DC: SSA. + +———. 2010. "Automatic Increases: National Average Wage Index." http://www.socialsecurity.gov/OACT/COLA/AWI.html. + + + +==== APPENDIX (added at extraction): chart "Show as table" equivalents ==== +The tables below are hidden in the page's default view ("Show as table" toggles under each chart) and so are absent from the visible page text above. Extracted 2026-10-01 from the page DOM ( captions "Table equivalent for Chart N"), cells tab-separated. Charts 5, 8 and 9 have no table equivalent on the page (Charts 8-9 data are Tables A1-A2). + +### Table equivalent for Chart 1. Types of earnings data available from Social Security administrative files, 1937–2006 +Time period Type of earnings data available +1937–1950 Aggregate covered earnings +1951–1977 Data reported quarterly by employer +1978–2006 Wage and salary and tip income (covered and noncovered) reported annually by employer on Form W-2 Social Security–covered self-employment income a reported annually on Form 1040 SE +1990–2006 Aggregate deferred compensation +1991–2006 Taxable Medicare earnings above the Social Security taxable maximum b +2004–2006 Detailed deferred compensation + +### Table equivalent for Chart 2. Social Security earnings (weighted) as a percentage of all earnings +Year Social Security covered earnings Social Security taxable earnings Capped Social Security taxable earnings in EPUF +1951 69.51 56.38 54.62 +1952 69.89 56.22 54.63 +1953 71.75 56.35 54.33 +1954 71.74 55.73 53.84 +1955 76.45 61.42 59.65 +1956 78.87 62.10 60.02 +1957 81.27 63.02 61.15 +1958 81.13 62.00 60.03 +1959 82.23 65.24 63.21 +1960 81.95 63.97 62.11 +1961 81.12 62.82 60.83 +1962 81.48 61.76 59.77 +1963 81.39 60.73 58.70 +1964 81.70 59.51 57.40 +1965 82.23 58.62 56.11 +1966 83.39 66.71 64.89 +1967 84.66 66.15 63.75 +1968 84.22 68.81 67.01 +1969 84.39 67.56 65.46 +1970 84.37 65.96 63.96 +1971 83.70 63.85 61.76 +1972 84.09 65.88 63.96 +1973 83.50 68.32 66.51 +1974 84.25 71.84 70.41 +1975 84.30 71.14 69.89 +1976 84.77 71.50 70.17 +1977 84.21 71.62 70.17 +1978 84.84 71.10 69.65 +1979 85.19 74.38 73.40 +1980 85.90 76.32 74.66 +1981 85.71 76.44 75.43 +1982 86.06 77.47 76.09 +1983 86.43 77.81 76.42 +1984 86.67 77.43 75.51 +1985 86.89 77.28 77.26 +1986 88.03 77.99 77.97 +1987 87.71 76.85 76.85 +1988 87.68 75.27 75.25 +1989 87.87 76.31 76.29 +1990 87.05 75.91 75.91 +1991 86.76 76.14 76.12 +1992 86.11 74.75 74.73 +1993 85.73 74.76 74.75 +1994 86.04 74.95 74.95 +1995 86.47 74.20 74.20 +1996 85.42 73.18 73.17 +1997 85.66 72.92 72.92 +1998 85.70 72.39 72.37 +1999 85.79 72.01 72.00 +2000 85.38 71.01 71.00 +2001 84.49 71.58 71.56 +2002 83.88 72.19 72.19 +2003 83.50 71.74 71.74 +2004 83.14 70.51 70.49 +2005 83.65 70.44 70.38 +2006 83.71 70.00 70.08 + +### Table equivalent for Chart 3. Number of individuals in EPUF, by year of birth +Year of birth Number (in thousands) +1870 1.81 +1871 2.02 +1872 2.91 +1873 3.07 +1874 3.80 +1875 4.43 +1876 5.15 +1877 5.40 +1878 6.09 +1879 6.69 +1880 7.98 +1881 8.12 +1882 9.41 +1883 9.58 +1884 11.28 +1885 11.48 +1886 12.17 +1887 12.09 +1888 14.58 +1889 14.28 +1890 14.90 +1891 14.91 +1892 16.89 +1893 16.85 +1894 17.47 +1895 17.76 +1896 18.32 +1897 17.95 +1898 19.24 +1899 18.10 +1900 21.26 +1901 19.04 +1902 21.04 +1903 20.82 +1904 21.73 +1905 22.72 +1906 22.88 +1907 23.82 +1908 24.66 +1909 24.63 +1910 25.67 +1911 25.57 +1912 26.90 +1913 26.94 +1914 28.23 +1915 27.87 +1916 27.95 +1917 27.89 +1918 29.69 +1919 29.09 +1920 31.37 +1921 31.88 +1922 31.10 +1923 30.80 +1924 31.58 +1925 30.60 +1926 30.24 +1927 30.31 +1928 29.77 +1929 28.74 +1930 29.29 +1931 27.62 +1932 28.09 +1933 26.57 +1934 27.49 +1935 27.83 +1936 27.59 +1937 28.60 +1938 29.36 +1939 29.08 +1940 30.51 +1941 31.77 +1942 34.95 +1943 36.29 +1944 34.97 +1945 34.76 +1946 40.96 +1947 45.44 +1948 44.12 +1949 44.74 +1950 44.61 +1951 46.41 +1952 47.56 +1953 48.33 +1954 50.15 +1955 51.31 +1956 51.62 +1957 53.20 +1958 52.99 +1959 52.81 +1960 53.23 +1961 52.82 +1962 52.83 +1963 52.14 +1964 51.36 +1965 48.96 +1966 46.94 +1967 46.01 +1968 46.17 +1969 47.14 +1970 48.49 +1971 46.51 +1972 43.63 +1973 42.08 +1974 41.98 +1975 41.79 +1976 41.82 +1977 42.70 +1978 42.50 +1979 43.70 +1980 44.64 +1981 44.28 +1982 44.48 +1983 43.64 +1984 43.44 +1985 43.77 +1986 43.33 +1987 42.94 +1988 43.78 +1989 44.93 +1990 45.79 +1991 45.00 +1992 44.42 +1993 43.47 +1994 42.48 +1995 41.91 +1996 41.29 +1997 41.25 +1998 41.63 +1999 41.68 +2000 42.53 +2001 41.99 +2002 41.77 +2003 42.26 +2004 42.51 +2005 42.50 +2006 41.24 + +### Table equivalent for Chart 4. Number of individuals in EPUF, by year of birth and sex +Year of birth Men (thousands) Women (thousands) +1870 1.48 0.33 +1871 1.61 0.40 +1872 2.29 0.61 +1873 2.41 0.65 +1874 2.89 0.90 +1875 3.29 1.14 +1876 3.79 1.35 +1877 3.90 1.49 +1878 4.29 1.79 +1879 4.52 2.15 +1880 5.35 2.61 +1881 5.38 2.71 +1882 6.20 3.17 +1883 6.19 3.35 +1884 7.15 4.09 +1885 7.08 4.37 +1886 7.56 4.58 +1887 7.25 4.80 +1888 8.70 5.83 +1889 8.43 5.81 +1890 8.66 6.20 +1891 8.45 6.40 +1892 9.63 7.20 +1893 9.47 7.34 +1894 9.62 7.80 +1895 9.77 7.95 +1896 9.99 8.28 +1897 9.71 8.20 +1898 10.17 9.02 +1899 9.57 8.50 +1900 11.24 9.98 +1901 10.01 9.00 +1902 11.12 9.87 +1903 10.92 9.86 +1904 11.19 10.51 +1905 11.69 10.98 +1906 11.72 11.11 +1907 12.32 11.46 +1908 12.62 12.00 +1909 12.78 11.81 +1910 13.22 12.39 +1911 13.18 12.33 +1912 13.88 12.94 +1913 13.74 13.14 +1914 14.41 13.75 +1915 14.30 13.51 +1916 14.41 13.47 +1917 14.27 13.58 +1918 15.16 14.46 +1919 14.98 14.05 +1920 15.92 15.39 +1921 16.24 15.57 +1922 15.62 15.41 +1923 15.63 15.13 +1924 15.82 15.73 +1925 15.22 15.34 +1926 15.36 14.86 +1927 15.38 14.91 +1928 15.08 14.67 +1929 14.50 14.23 +1930 14.91 14.36 +1931 14.00 13.60 +1932 14.33 13.74 +1933 13.44 13.11 +1934 13.98 13.49 +1935 13.98 13.82 +1936 13.96 13.62 +1937 14.42 14.17 +1938 14.75 14.60 +1939 14.82 14.24 +1940 15.54 14.95 +1941 16.15 15.60 +1942 17.89 17.05 +1943 18.56 17.71 +1944 17.80 17.17 +1945 17.87 16.87 +1946 21.03 19.93 +1947 23.44 21.98 +1948 22.71 21.40 +1949 23.00 21.73 +1950 22.97 21.63 +1951 23.92 22.46 +1952 24.48 23.05 +1953 24.80 23.51 +1954 25.81 24.32 +1955 26.43 24.87 +1956 26.80 24.80 +1957 27.59 25.59 +1958 27.43 25.55 +1959 27.24 25.57 +1960 27.50 25.72 +1961 27.32 25.50 +1962 27.24 25.59 +1963 26.93 25.19 +1964 26.59 24.77 +1965 25.22 23.72 +1966 24.18 22.75 +1967 23.76 22.25 +1968 23.93 22.23 +1969 24.16 22.98 +1970 24.98 23.50 +1971 23.99 22.52 +1972 22.60 21.02 +1973 21.49 20.59 +1974 21.39 20.58 +1975 21.33 20.45 +1976 21.43 20.39 +1977 21.90 20.80 +1978 21.80 20.70 +1979 22.27 21.42 +1980 22.60 22.03 +1981 22.67 21.60 +1982 22.64 21.84 +1983 22.48 21.16 +1984 22.03 21.41 +1985 22.20 21.56 +1986 22.08 21.25 +1987 21.92 21.02 +1988 22.31 21.46 +1989 23.03 21.90 +1990 23.41 22.38 +1991 22.98 22.03 +1992 22.91 21.51 +1993 22.32 21.16 +1994 21.76 20.72 +1995 21.44 20.47 +1996 21.23 20.07 +1997 20.99 20.26 +1998 21.27 20.37 +1999 21.42 20.26 +2000 21.60 20.93 +2001 21.45 20.55 +2002 21.32 20.45 +2003 21.58 20.68 +2004 21.68 20.83 +2005 21.77 20.73 +2006 21.07 20.18 + +### Table equivalent for Chart 6. Cumulative distribution of individuals in EPUF with no capped Social Security taxable earnings, by year of birth +Year of birth Cumulative percentage +1870 0.07 +1871 0.13 +1872 0.22 +1873 0.31 +1874 0.41 +1875 0.54 +1876 0.69 +1877 0.83 +1878 1.00 +1879 1.19 +1880 1.41 +1881 1.62 +1882 1.86 +1883 2.10 +1884 2.38 +1885 2.67 +1886 2.95 +1887 3.25 +1888 3.60 +1889 3.93 +1890 4.27 +1891 4.60 +1892 4.96 +1893 5.33 +1894 5.71 +1895 6.08 +1896 6.44 +1897 6.80 +1898 7.17 +1899 7.51 +1900 7.92 +1901 8.25 +1902 8.60 +1903 8.92 +1904 9.25 +1905 9.58 +1906 9.91 +1907 10.22 +1908 10.53 +1909 10.83 +1910 11.14 +1911 11.42 +1912 11.73 +1913 12.01 +1914 12.31 +1915 12.58 +1916 12.85 +1917 13.11 +1918 13.39 +1919 13.66 +1920 13.96 +1921 14.22 +1922 14.49 +1923 14.73 +1924 14.97 +1925 15.20 +1926 15.44 +1927 15.67 +1928 15.89 +1929 16.10 +1930 16.33 +1931 16.53 +1932 16.74 +1933 16.94 +1934 17.14 +1935 17.34 +1936 17.53 +1937 17.73 +1938 17.94 +1939 18.13 +1940 18.34 +1941 18.54 +1942 18.75 +1943 18.95 +1944 19.16 +1945 19.36 +1946 19.58 +1947 19.81 +1948 20.04 +1949 20.29 +1950 20.53 +1951 20.77 +1952 21.02 +1953 21.28 +1954 21.55 +1955 21.85 +1956 22.13 +1957 22.42 +1958 22.71 +1959 22.99 +1960 23.27 +1961 23.54 +1962 23.81 +1963 24.09 +1964 24.37 +1965 24.64 +1966 24.92 +1967 25.21 +1968 25.50 +1969 25.78 +1970 26.09 +1971 26.40 +1972 26.72 +1973 27.05 +1974 27.38 +1975 27.72 +1976 28.05 +1977 28.37 +1978 28.68 +1979 29.00 +1980 29.33 +1981 29.66 +1982 30.00 +1983 30.33 +1984 30.68 +1985 31.08 +1986 31.53 +1987 32.12 +1988 33.09 +1989 34.83 +1990 37.67 +1991 41.43 +1992 45.54 +1993 49.56 +1994 53.49 +1995 57.37 +1996 61.19 +1997 65.01 +1998 68.86 +1999 72.72 +2000 76.66 +2001 80.54 +2002 84.41 +2003 88.32 +2004 92.25 +2005 96.18 +2006 100.00 + +### Table equivalent for Chart 7. Percentage distribution of individuals in EPUF in each capped Social Security taxable earnings status, by sex +Earnings status Men (%) Women (%) +No earnings 47.9 52.0 +Earnings during 1937–1950 only 56.6 43.2 +Earnings during 1951–2006 only 50.8 49.2 +Earnings during both periods 60.7 39.3 + +### Table equivalent for Chart A1. Number of individuals in EPUF with capped Social Security taxable earnings during 1937–1950, by year of birth and sex +Year of birth Men (thousands) Women (thousands) +1870 0.93 0.11 +1871 1.06 0.15 +1872 1.59 0.25 +1873 1.72 0.23 +1874 2.05 0.35 +1875 2.32 0.43 +1876 2.68 0.49 +1877 2.85 0.55 +1878 3.06 0.67 +1879 3.27 0.85 +1880 3.86 1.00 +1881 3.86 1.07 +1882 4.53 1.27 +1883 4.47 1.32 +1884 5.21 1.66 +1885 5.21 1.76 +1886 5.56 1.91 +1887 5.21 2.05 +1888 6.31 2.47 +1889 6.26 2.53 +1890 6.36 2.65 +1891 6.29 2.82 +1892 7.25 3.28 +1893 7.13 3.31 +1894 7.23 3.62 +1895 7.45 3.78 +1896 7.64 4.04 +1897 7.38 3.99 +1898 7.84 4.51 +1899 7.39 4.15 +1900 8.76 4.96 +1901 7.80 4.76 +1902 8.85 5.18 +1903 8.78 5.27 +1904 9.06 5.70 +1905 9.49 6.13 +1906 9.48 6.12 +1907 10.17 6.60 +1908 10.36 7.01 +1909 10.59 6.98 +1910 10.84 7.47 +1911 10.98 7.62 +1912 11.53 8.08 +1913 11.54 8.40 +1914 12.12 9.00 +1915 12.00 9.08 +1916 12.16 9.24 +1917 12.03 9.64 +1918 12.71 10.27 +1919 12.49 10.18 +1920 13.19 11.08 +1921 13.62 11.52 +1922 12.87 11.42 +1923 12.95 11.34 +1924 13.06 11.93 +1925 12.46 11.63 +1926 12.40 11.07 +1927 12.23 10.99 +1928 11.80 10.55 +1929 11.03 9.88 +1930 10.80 9.26 +1931 9.58 8.27 +1932 8.61 7.26 +1933 6.14 4.86 +1934 4.12 2.78 +1935 1.75 0.89 +1936 0.70 0.26 +1937 0.23 0.07 +1938 0.08 0.03 +1939 0.03 0.02 +1940 0.02 0.01 +1941 0.02 0.01 +1942 0.01 0.01 +1943 0.01 0.01 +1944 0.01 0.01 +1945 0.01 0.01 +1946 0.02 0.02 +1947 0.01 0.03 +1948 0.01 0.02 +1949 0.01 0.02 +1950 0.01 0.02 + +(Hidden-table transcription verified 2026-10-01: SHA-256 of the canonical data rows of each table equivalent matches the page DOM for Charts 2, 3, 4, 6, 7, A1.) diff --git a/docs/amendments/gate_epuf_registration_proposal.md b/docs/amendments/gate_epuf_registration_proposal.md new file mode 100644 index 00000000..5a832c04 --- /dev/null +++ b/docs/amendments/gate_epuf_registration_proposal.md @@ -0,0 +1,375 @@ +# gate_epuf registration (proposal): generated earnings histories against SSA's Earnings Public-Use File + +- **Registration id**: `2026-10-02-epuf-covered-earnings` +- **Gate**: `gate_epuf` (new; not in `gates.yaml`) +- **Surface**: tranche G, the gate-1 generator's earnings on the four even + reference years 1998-2004, by sex and birth cohort, scored against SSA's 2006 + Earnings Public-Use File (EPUF). Tranche R, the career statistics, is + registered report-only. +- **Ceremony stage**: PROPOSAL (draft). This is the first step of the lock + ceremony (proposal, adversarial referee, fixes, verification, ratify by + merge, flip). **It edits no `gates.yaml` cell and no committed + `runs/*.json`.** The proposed entry is + `docs/design/gate_epuf_block_draft.yaml` with `locked: false`; the flip + copies it into `gates.yaml` in a separate ratifying PR. +- **Class**: new gate, unlocked. No model has been scored against it. +- **Evidence base**: `runs/epuf_gate_floors_v1.json` (floors, bridges, + partition, operating characteristic, bite demonstrations); + `data/external/epuf_2006/` (provenance, SSA's documentation, published + tables, disclosure constants); `runs/gate1_rank_knn_v5.json` (the gate-1 run + whose generator this gate scores). + +## 1. Summary + +Gate 1 scores the model's generated earnings histories against held-out PSID +records. Experts who work with administrative earnings will ask how those +histories compare with SSA's own records. DYNASIM and MINT start from surveys +matched to SSA earnings, and CBOLT from the Continuous Work History Sample; all +three are confidential. EPUF is public: a 1 percent sample of Social Security +numbers issued before 2007, with year of birth, sex and capped taxable earnings +for each year from 1951 to 2006 +(). + +This proposal registers a gate that scores the gate-1 generator against EPUF. +Three facts shape it. + +1. **The generator and EPUF overlap in four years.** The gate-1 generator + redraws earnings on each held-out person's observed PSID periods, which are + the even reference years 1998 to 2022 at ages 25 to 59 + (`scripts/run_gate1_candidate10.py:258-298`). EPUF ends in 2006, and its + 2005 and 2006 are short from late posting. The scoreable overlap is 1998, + 2000, 2002 and 2004. Nothing in the repository generates a career: the + careers that benefit figures rest on are observed PSID earnings from 1968 + with rule-based fills (`src/populace_dynamics/estimates/career.py:964-1076`). +2. **The PSID itself sits at some distance from EPUF.** PSID labor income + counts noncovered work, the gate-1 panel holds heads and spouses who stay + in the survey, and earnings are reported, not filed. A generator trained on + the PSID inherits that distance. A gate that demands agreement with EPUF to + within sampling noise would fail every PSID-trained generator, and the + better the generator copied the PSID the more surely it would fail. +3. **A 20-seed mean has noise that its seeds share.** Each seed scores + generated values against the same realised PSID sample, so averaging over + seeds removes only part of the noise. + +The design that follows from these: score the mean over the gate's 20 +registered seeds; accept a cell when the generated value lies between EPUF and +the PSID's own position, plus a tolerance priced from a real-data floor that +includes the shared noise; and gate a cell only when that whole acceptance +band stays inside a power cap, so that a pass always means "within the cap of +EPUF". Cells that cannot meet that are published with the reason. + +The four career statistics the request named (years without earnings by age +62, rank persistence ten years apart, the share at the taxable maximum by age, +and the AIME under the 35-year rule) cannot be scored on generated histories, +because no generator produces careers. They are registered as tranche R, +report-only, with their EPUF reference values in the floor artifact. + +## 2. What is scored + +**Candidate.** Any generator that emits gate 1's candidate panel: for a +holdout drawn by `populace_dynamics.harness.panel.split_panel_by_person` +(`fraction=0.2`, seed `s`) from gate 1's filtered panel, the holdout's persons +on their observed periods with generated `earnings`. The first registered +candidate is the gate-1 passing generator (`runs/gate1_rank_knn_v5.json`, +candidate 11). + +**Seeds.** The 20 seeds 0-19, the set gate 1's `c2st_mean_rule` already +registers (`gates.yaml:209-216`). The scored quantity for a cell is the mean +of its 20 per-seed values, then the cell's transform (log for shares, identity +for rank correlations). + +**Support.** A person of gate 1's filtered panel (age 25-59, reference years +1998-2022, positive weight) is in the support if all four hold: + +1. the person has a row at each of 1998, 2000, 2002 and 2004; +2. the person's last in-filter period is 2006 or later. The generator keeps + each person's last period at its real value, so this rule keeps real values + out of the window: every scored value is generated; +3. sex is coded male or female (`ER32000`, read by + `populace_dynamics.data.deaths.read_death_records`); +4. birth year, `floor(median(period - age) + 0.5)` over the person's rows, lies + in 1947-1973. + +A support person's weight is their 2004-row weight. The support depends only on +the real panel, never on generated values. The EPUF side is every EPUF person +with sex 1 or 2 born 1947-1973, with weight 1; EPUF has no presence condition +to mirror, so each statistic carries its own conditioning (section 3). + +**Units.** PSID-side and candidate-side earnings pass through EPUF's +measurement operator (`populace_dynamics.harness.epuf_operator.epuf_measure`): +cap at the year's contribution and benefit base, replace positive values below +$100 with the year's EPUF bottom code, replace values within one rounding base +below the cap with the year's EPUF band mean, and round the rest to SSA's base +($25, $100 or $1,000). The operator preserves whether a person-year is +positive and whether it is exactly at the cap. SSA rounded at random and did +not publish the probabilities; the operator rounds half up. EPUF is used as +published. + +**Validation only.** No candidate may use EPUF in fitting, tuning or +calibration. A candidate that does is scored and labelled a calibration check. + +## 3. Cells + +Cohort bands: c0 = born 1947-1955, c1 = 1956-1964, c2 = 1965-1973. Every +statistic is computed within sex and cohort band. A sex-level cell is the +unweighted mean of its three band values, which holds cohort composition at +one-third each on both sides. + +| Cell | Statistic | Conditioning | Metric and cap | +|---|---|---|---| +| `r6` | Weighted Spearman correlation of 1998 and 2004 earnings (average ranks for ties) | positive in 1998 and in 2004 | absolute gap, 0.15 | +| `zint` | Share with no earnings in 2000 or in 2002 | positive in 1998 and in 2004 | log ratio, ln 1.5 | +| `d_anyzero` | Share with no earnings in at least one of 1998, 2000, 2002 | positive in 2004 | log ratio, ln 1.5 | +| `q_atmax` | Share of positive person-years exactly at the wage base, 1998-2004 | positive person-years | log ratio, ln 1.5 | +| `mpers` | Share at the wage base in 1998 | at the wage base in 2004 | log ratio, ln 1.5 | +| `q_sexratio` | Men's `q_atmax` over women's | as `q_atmax` | log ratio, ln 1.5 | + +Each statistic conditions on covered earnings at one or both ends of its span. +EPUF has no date of death and no record of arrival or departure, so an EPUF +year without earnings can be a year after death or before arrival; a person +with earnings at the end of a span was alive and in covered work then. + +How these stand to the request's four candidates: + +| Requested | Here | Why | +|---|---|---| +| Years with zero capped earnings by age 62 | `zint` and `d_anyzero` (interior and earlier zero years inside the window); the by-62 count is tranche R | the generator emits four window years, not careers | +| Rank persistence ten years apart | `r6`, six years apart | the longest generated span inside EPUF's reliable years is 1998 to 2004 | +| Share at the taxable maximum by age | `q_atmax`, `mpers`, `q_sexratio` by sex and cohort band | adopted; within four calendar years a cohort band is an age band | +| AIME under the 35-year rule | tranche R only | needs a career | + +The generator never sees sex: its inputs are age, period and earnings ranks, +and its levels are quantiles of sex-pooled age-by-period marginals +(`scripts/run_gate1_candidate10.py:557-562`). Gate 1 scores sex-pooled +moments. Cells by sex are therefore where this gate tests something gate 1 +does not. + +## 4. Floor, tolerance and acceptance interval + +Write `theta_E` for a cell's EPUF value, `theta_P` for its value on the real +PSID support, both on the cell's metric scale, and `B = theta_P - theta_E` +for the bridge. + +**Floor.** For replicates `b = 0..99`, on the real PSID support: + + e_b = [m(A_b) - m(B_b)] / 2 + + pooled(m(H_b0), ..., m(H_b19)) - pooled(m(T_b0), ..., m(T_b19)) + +`A_b`, `B_b` are person-disjoint halves (split seed `b`, fraction 0.5). +`H_bj`, `T_bj` are a 20% holdout and its complement under the gate's split +function (seed `1000 + 20b + j`). `pooled` is the 20-seed estimate of +section 2. The first term stands for the noise the 20 seeds share: a faithful +generator's mean differs from the real value by the realised sample's own +deviation from its conditional law, which is the same on every seed. The +second term stands for the noise that averages down: who falls in each +holdout, each seed's draws and each seed's fit. + +**Tolerance.** `t = round(mean|e_b| + 4 * sd|e_b|, 3)`, the house formula +(sd with `ddof=1`), with `k = 4` on every cell. `sigma` is the root mean +square of `e_b`. + +**Acceptance.** With `G` the candidate's estimate less `theta_E`, a cell +passes iff + + min(0, B) - t <= G <= max(0, B) + t + +The bridge is never subtracted. Subtracting it would cancel `theta_E` and +turn the gate into a second gate 1. The interval is one-sided in the bridge: +it reaches from EPUF to the PSID's position and `t` beyond each, so a +candidate that overshoots EPUF on the far side from the PSID fails. + +**Faithful-candidate pass probability.** A candidate that reproduces the +PSID has `G = B + noise`. Per cell the probability is +`Phi((upper - B)/sigma) - Phi((lower - B)/sigma)`. The gate's is the product +over gated cells, reported beside the share of floor replicates in which +every gated cell's `B + e_b` lies inside its interval. + +## 5. Which cells gate + +A cell's reason for not gating is the first of these that applies: + +1. `undefined_on_some_split`: the statistic is undefined on some floor split. +2. `below_20_events`: fewer than 20 events on some half, some 20% holdout of + the 2,000 floor splits, or some real gate-seed holdout. Events are the + smaller of a share's numerator and its complement, or a correlation's + pairs. +3. `epuf_sampling_not_negligible`: EPUF's own sampling sd (50 random groups) + exceeds 0.1 `sigma`. +4. `noise_exceeds_cap`: `t + 0.8416 sigma` exceeds the cap. +5. `bridge_exceeds_budget`: `|B| + t + 0.8416 sigma` exceeds the cap. + +Rules 4 and 5 make the cap bind on the 80 percent power point, not on the +tolerance: a candidate whose distance from EPUF reaches the cap fails with +probability at least 0.8, and a pass certifies a distance below the cap. + +Among eligible cells: + +- `r6`: gate all six sex-by-cohort cells if every one is eligible; otherwise + gate each eligible sex-level cell. +- participation: per sex, gate `zint` if eligible, otherwise `d_anyzero` if + eligible. +- tail: gate each eligible sex-level `q_atmax` and `mpers` cell and + `q_sexratio`. +- every other cohort-level cell is reported. + +**No gated cell.** If no cell gates, the registration does not lock as a +pass-or-fail gate. It publishes as `report_only_bridge_dominated`, with the +bridge table as its finding. + +**Pauses.** The ceremony pauses if the faithful-candidate pass probability of +the gated surface is below 0.90, or if a gated family's bite demonstration +fails less than 90 percent of the time (section 6). + +**Pass rule.** The gate passes iff every gated cell passes on the 20-seed +estimate. A verdict attaches to the registered candidate only if the run +reproduces that candidate's committed gate-1 artifact exactly. + +## 6. Bite demonstrations + +Each is a perturbation of the real PSID support, scored on the 20 gate +holdouts as a candidate would be, over 50 perturbation seeds. No candidate is +generated. + +| Bite | Perturbation | Required of | +|---|---|---| +| `bd1` | With probability 0.10 (and, reported, 0.05) a person takes a same-sex, same-band donor's 1998-2002 earnings | persistence, if gated | +| `bd2` | Everyone takes the 1998-2002 path of a donor in the same band and 2004 class (no earnings, or decile of 2004 earnings), drawn from both sexes | reported | +| `bd2c` | As `bd2`, donors of the person's own sex: the control that isolates pooling the sexes | reported | +| `bd3` | In 1998-2002, half of each year's top 8 percent of positive earners move to a rank drawn uniformly from 0.5 to 0.92 | tail, if gated | +| `bd4` | Each positive 1998-2002 person-year becomes zero with probability 0.03 | participation, if gated | + +The real gate-seed holdouts are also scored as a training copy and must pass. + +## 7. Results of the floor build + +*Filled by the floor build, which runs after the rules above are committed +and pushed (section 10).* + +## 8. Tranche R: career statistics, report-only + +Report-only, computed once in the post-lock run, never gated. The statistics +are the request's four, on annual capped histories at ages 22-61, by sex and +birth cohort (1930-1934, 1935-1939, 1940-1944: the cohorts whose whole window +lies inside 1951-2006): + +- years without earnings (mean, quartiles, share with ten or more, share with + all 40); +- Spearman correlations 1980 to 1990 and 1994 to 2004, among those positive in + both years; +- share of positive person-years at the wage base, by age band; +- AIME under the 35-year rule through age 61 (quartiles, 90th percentile, + share zero), matching `populace_dynamics.ss.statutory_aime.aime`. + +The floor artifact holds their EPUF values twice: on EPUF as published, and +on EPUF masked the way the career assembler builds a PSID career (nothing +before 1968; each odd year from 1997 filled with the mean of its neighbours). +The difference is exact and involves no PSID: it is what those two rules +alone do to administrative careers. The post-lock run adds the PSID career +product's values beside the masked EPUF values. Survival to the PSID's +observation years has no EPUF counterpart and is named as a difference, not +corrected. + +Why report-only: the career product is observed PSID earnings with fixed +fill rules. It has no generator to hold out and no faithful-candidate null, +and its distance from EPUF is the bridge itself. A career-completion model, +when one exists, becomes gate-eligible on these cells by amendment. + +## 9. What a pass certifies + +A pass certifies, for each gated cell and only those: the generated value's +distance from EPUF is below the cell's cap, and no larger than the PSID's own +distance plus noise. + +Not certified, at the same prominence: + +- careers, years without earnings by age 62, and the 35-year AIME; +- any year before 1998, and 2006; +- ages outside the support's range in the window, about 25 to 57; +- the forward earnings law of `gate_m6`, which this gate does not touch; +- that the PSID agrees with EPUF. The bridge is published per cell; a pass + that rests on a large bridge says the generator is no worse than its source; +- levels by age, which the generator takes from PSID marginals. + +## 10. Blindness and forking paths + +**Order of commits.** The first commit of the pull request holds the reader, +operator, cell statistics, gate algebra, floor builder, their tests and +sections 1-6 and 8-13 of this document. It was pushed before any real-PSID +value in EPUF units existed. The second commit adds the floor artifact, the +draft block and section 7. The artifact records the first commit's sha and +the sha256 of each derivation file; a test fails if one changes afterwards. + +**Who has seen what, at the first commit.** The drafting session and the +design panel saw: EPUF-only values of every cell; EPUF subsampled to PSID +scale; gate 1's committed artifacts, including that candidate 11's sex-pooled +log autocorrelation is above the PSID reference at two and four years and +below it at ten on all five seeds. No one had computed a real-PSID value in +EPUF units, a bridge, or any candidate value under this gate's measurement. + +**After the floor build.** The bridges are then known, and with the gate-1 +battery they suggest how the first candidate will score. That is why the +partition is mechanical and fixed first. Any later change to a rule is +recorded in a forks ledger in this document with the partition before and +after, and no cell may be redefined on account of its own bridge. + +**Before lock.** No candidate is generated. Tranche R's PSID side is not +computed. + +## 11. Considered and rejected + +1. **EPUF-centred tolerance with no bridge.** A faithful candidate's pass + probability falls toward zero as the bridge grows relative to the noise. + `gate_w1` amendment 1 demoted ten cells for this. +2. **Subtracting the bridge.** EPUF cancels and the gate re-runs gate 1. +3. **A symmetric band `|G| <= |B| + t`.** It accepts overshoot past EPUF by + the full bridge. +4. **Per-seed scoring with a 4-of-5 rule.** At 20 percent holdouts the + per-seed noise is more than twice the 20-seed noise, which leaves almost no + cell inside the caps. +5. **A floor from 20%/80% splits alone, divided by the square root of 20.** It + omits the noise the seeds share, which + `tests/harness/test_epuf_gate.py::test_floor_prices_a_faithful_generator` + shows by simulation: a faithful generator's 20-seed mean spreads about as + widely as the two-term floor and well beyond the one-term floor. The + artifact records each cell's shared-noise share of the floor variance. +6. **Gating the career product.** It is observed data, not a generator + (section 8). +7. **Including 2006.** EPUF's 2006 worker count is 97.3 percent of the + Supplement's from late posting (Compson 2012). +8. **A gated PSID-against-PSID leg in EPUF units.** It would keep the gate + from being empty when bridges are large, but a gate named for EPUF should + not pass on a comparison that leaves EPUF out. The model-against-PSID term + is published in every run's decomposition instead. +9. **Random rounding in the operator.** It adds noise, and scored values + would depend on a rounding seed. +10. **The planning documents' fixed bands** (one point on the share at the + maximum, 0.05 on correlations; `docs/evaluation-and-model-selection.md`). + They are not priced from a floor. + +## 12. The lock flip (not in this pull request) + +Ratification is by merge of a flip PR after an adversarial referee round and +a verification round. The flip: + +1. copies `docs/design/gate_epuf_block_draft.yaml` into `gates.yaml` after + `gate_m6`, with `locked: true`; +2. extends the gate-set allowlists in `tests/test_gates_derivations.py` and + `tests/test_gate_w1_derivations.py`; +3. re-pins `CONTRACT_BLOB_LIVE` (`tests/test_gate_w1_candidate4_pin.py`) and + runs `scripts/build_legacy_manifest.py --transition`; +4. registers the first run on issue #42 with the run script, the commit and + a forecast. + +The post-lock run regenerates candidate 11 on seeds 0-19, asserts exact +reproduction of `runs/gate1_rank_knn_v5.json`, scores the panels with +`populace_dynamics.harness.epuf_run.score_candidate`, computes tranche R, and +publishes the result whatever it is. + +## 13. Ceremony checklist + +- [x] **Proposal** (this document, the floor artifact, the draft block) +- [ ] Adversarial referee round +- [ ] Fixes +- [ ] Verification round +- [ ] Ratify by merge of the flip PR +- [ ] Registration of the first run on issue #42 diff --git a/scripts/build_epuf_gate_floors.py b/scripts/build_epuf_gate_floors.py new file mode 100644 index 00000000..8d2e2a48 --- /dev/null +++ b/scripts/build_epuf_gate_floors.py @@ -0,0 +1,1042 @@ +"""Pre-lock floors for the proposed EPUF covered-earnings gate. + +Writes ``runs/epuf_gate_floors_v1.json`` (exclusive-create, with the +``.env.json`` sidecar) and ``runs/epuf_gate_floors_v1.inputs.json``. +The artifact holds, for every window cell of +:mod:`populace_dynamics.harness.epuf_cells`: + +- the EPUF reference value and EPUF's own sampling sd; +- the real-PSID value on the gate's support and the bridge (PSID minus + EPUF); +- the 100 real-data floor replicates, the tolerance and the realised + sigma (:mod:`populace_dynamics.harness.epuf_gate`); +- the acceptance interval, the demotion reason or the gated flag, and + the faithful-candidate pass probability; +- the real gate-seed holdouts scored as a training copy, and the bite + demonstrations (perturbed real data). + +It also holds the EPUF-only reference values of the report-only career +tranche, on true EPUF careers and on EPUF careers masked the way the +repository's career assembler builds a PSID career. + +**Candidate-blind.** This builder generates no candidate and imports no +generator: it reads EPUF and, through the existing loaders +``data.family.family_earnings_panel`` and +``data.deaths.read_death_records``, the real PSID panel of gate 1's +view. The partition rules, ``k``, the caps and the bite doses are code +constants committed before the first PSID floor was computed. + +Usage:: + + uv run python scripts/build_epuf_gate_floors.py --stage epuf # EPUF only + uv run python scripts/build_epuf_gate_floors.py # full build +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import subprocess +import time +from collections.abc import Callable, Mapping +from pathlib import Path + +import numpy as np +import pandas as pd + +from populace_dynamics.artifacts import write_new +from populace_dynamics.cola_track_a.statutory import captured_ssa_parameters +from populace_dynamics.data import epuf +from populace_dynamics.harness import epuf_gate as gate +from populace_dynamics.harness.epuf_cells import ( + CAREER_AGES, + CAREER_COHORT_BANDS, + COHORT_BANDS, + SEXES, + WINDOW_YEARS, + WindowArrays, + career_cells, + cell_ids, + mask_as_career_assembler, + metric, + transform, + window_frame, +) +from populace_dynamics.harness.epuf_operator import ( + CONSTANTS_SHA256, + disclosure_constants, + epuf_measure, +) + +ROOT = Path(__file__).resolve().parents[1] +ARTIFACT = ROOT / "runs" / "epuf_gate_floors_v1.json" +INPUTS = ROOT / "runs" / "epuf_gate_floors_v1.inputs.json" +SCHEMA_VERSION = "epuf_gate_floors.v1" + +#: Gate 1's locked view filter (gates.yaml views.psid_family_earnings_*). +AGE_MIN, AGE_MAX = 25, 59 +PERIOD_MIN, PERIOD_MAX = 1998, 2022 +#: The filtered panel's committed size (runs/noise_floor_psid_family_9822.json). +PANEL_REFERENCE = "runs/noise_floor_psid_family_9822.json" +GATE1_RUN = "runs/gate1_rank_knn_v5.json" +#: A support person's anchor (last in-filter period) must lie after the +#: window, so that every window value of a candidate is generated. +MIN_ANCHOR_PERIOD = 2006 +PSID_SEX_LABELS = {"male": "men", "female": "women"} +EPUF_SEX_LABELS = {1: "men", 2: "women"} + +EPUF_GROUPS = 50 +EPUF_GROUP_SEED = 20261001 + +#: Bite demonstrations: perturbations of real PSID histories, each +#: scored on the 20 gate holdouts exactly as a candidate would be. +BITE_SEEDS = tuple(range(50)) +BITE_SEED_BASE = 7300 +BITE_REQUIRED_FAIL_SHARE = 0.90 +BD1_SHARES = (0.10, 0.05) +BD3_RANK_ABOVE = 0.92 +BD3_MOVE_PROBABILITY = 0.5 +BD3_TARGET_RANKS = (0.5, 0.92) +BD4_ZERO_PROBABILITY = 0.03 +#: Which bite a gated family needs to see fail before the gate may lock. +BITE_REQUIREMENT = { + "persistence": "bd1_persistence_loss_0.10", + "tail": "bd3_top_tail_compression", + "participation": "bd4_participation_loss", +} + +DERIVATION_CORE = ( + "src/populace_dynamics/data/epuf.py", + "src/populace_dynamics/harness/epuf_operator.py", + "src/populace_dynamics/harness/epuf_cells.py", + "src/populace_dynamics/harness/epuf_gate.py", + "scripts/build_epuf_gate_floors.py", +) + +CONCEPT_DELTAS = [ + { + "delta": "deaths, departures and arrivals", + "direction": ( + "EPUF records none of them, so an EPUF year without earnings " + "may follow death or precede arrival" + ), + "handling": ( + "every statistic conditions on covered earnings at one or both " + "ends of its span; what remains is in the bridge" + ), + }, + { + "delta": "noncovered employment", + "direction": ( + "PSID labor income counts it; EPUF shows no earnings (6.4 " + "percent of 2006 workers were noncovered, Compson 2011 Table 3)" + ), + "handling": "in the bridge; the repository's crosswalk is unbuilt", + }, + { + "delta": "frame", + "direction": ( + "the PSID panel is heads and spouses of responding families who " + "stay through 2006; EPUF is every Social Security number issued " + "before 2007" + ), + "handling": "in the bridge; cells are within sex and cohort band", + }, + { + "delta": "reporting", + "direction": ( + "PSID earnings are survey reports and EPUF's are employer and " + "tax filings; whether that lowers the PSID's rank persistence " + "is measured by the r6 bridge, not assumed" + ), + "handling": "in the bridge", + }, + { + "delta": "birth year", + "direction": ( + "the PSID birth year is derived from age at interview and can " + "sit one year below EPUF's year of birth" + ), + "handling": "nine-year cohort bands; in the bridge", + }, + { + "delta": "posting", + "direction": ( + "EPUF 2005-2006 are short from late posting and 1998-2004 drift " + "down slightly against the Supplement (Compson 2012)" + ), + "handling": "the window ends in 2004; the drift is in the bridge", + }, + { + "delta": "disclosure", + "direction": "EPUF values are bottom-coded, banded and rounded", + "handling": "the same operator is applied to PSID-side earnings", + }, +] + + +# --- splits --------------------------------------------------------------- + + +def holdout_mask( + universe_ids: np.ndarray, *, seed: int, fraction: float +) -> np.ndarray: + """Which persons of the sorted universe a split draws. + + Identical to ``populace_dynamics.harness.panel.split_panel_by_person`` + on a panel with those persons (the gate-1 split function); the + builder asserts the equality on the gate seeds. + """ + return np.random.default_rng(seed).random(len(universe_ids)) < fraction + + +def _sha256_ids(ids: np.ndarray) -> str: + text = "\n".join(str(int(value)) for value in np.sort(ids)) + return hashlib.sha256(text.encode()).hexdigest() + + +# --- EPUF side ------------------------------------------------------------ + + +def wage_bases() -> dict[int, float]: + return { + year: float(row["wage_base"]) + for year, row in disclosure_constants().items() + } + + +def epuf_window( + demographic: pd.DataFrame, annual: pd.DataFrame +) -> tuple[WindowArrays, dict[str, object]]: + """EPUF's window frame: every person with a coded sex in the bands.""" + persons = pd.DataFrame( + { + "person_id": demographic["person_id"], + "sex": demographic["sex"].map(EPUF_SEX_LABELS), + "birth_year": demographic["birth_year"], + "weight": 1.0, + } + ) + frame = window_frame(annual, persons, wage_bases=wage_bases()) + counts = { + "n_persons": int(len(frame)), + "n_sex_unspecified_dropped": int((demographic["sex"] == 3).sum()), + "by_sex_and_band": _support_counts(frame), + } + return WindowArrays(frame, wage_bases=wage_bases()), counts + + +def _support_counts(frame: pd.DataFrame) -> dict[str, int]: + out = {} + for sex in SEXES: + for band, (low, high) in COHORT_BANDS.items(): + out[f"{sex}.{band}"] = int( + ( + (frame["sex"] == sex) + & frame["birth_year"].between(low, high) + ).sum() + ) + return out + + +def epuf_sampling_sd(arrays: WindowArrays) -> dict[str, float]: + """EPUF's own sampling sd per cell, by random groups. + + Persons are dealt at random into 50 groups; a cell's sd is the sd of + its 50 transformed group values over the square root of 50. + """ + rng = np.random.default_rng(EPUF_GROUP_SEED) + group = rng.integers(0, EPUF_GROUPS, size=len(arrays)) + values: dict[str, list[float]] = {cell_id: [] for cell_id in cell_ids()} + for index in range(EPUF_GROUPS): + for cell_id, cell in arrays.cells(group == index).items(): + values[cell_id].append(transform(cell_id, cell.value)) + return { + cell_id: float(np.std(series, ddof=1) / np.sqrt(EPUF_GROUPS)) + for cell_id, series in values.items() + } + + +def career_reference( + demographic: pd.DataFrame, annual: pd.DataFrame +) -> dict[str, object]: + """EPUF-only reference values of the report-only career tranche.""" + low = min(a for a, _ in CAREER_COHORT_BANDS.values()) + high = max(b for _, b in CAREER_COHORT_BANDS.values()) + persons = demographic[ + demographic["sex"].isin(EPUF_SEX_LABELS) + & demographic["birth_year"].between(low, high) + ].reset_index(drop=True) + years = np.arange(epuf.EPUF_FIRST_YEAR, epuf.EPUF_LAST_YEAR + 1) + annual = annual[annual["person_id"].isin(persons["person_id"])] + row = pd.Series( + np.arange(len(persons)), index=persons["person_id"].to_numpy() + ) + matrix = np.zeros((len(persons), len(years)), dtype=np.float64) + matrix[ + row.loc[annual["person_id"].to_numpy()].to_numpy(), + annual["year"].to_numpy() - years[0], + ] = annual["earnings"].to_numpy() + masked = mask_as_career_assembler(matrix, years) + nawi = captured_ssa_parameters().nawi + out: dict[str, object] = {} + for sex_code, sex in EPUF_SEX_LABELS.items(): + for band, (band_low, band_high) in CAREER_COHORT_BANDS.items(): + select = ( + (persons["sex"] == sex_code) + & persons["birth_year"].between(band_low, band_high) + ).to_numpy() + birth = persons.loc[select, "birth_year"].to_numpy() + kwargs = dict(wage_bases=wage_bases(), nawi=nawi) + out[f"{sex}.{band}"] = { + "epuf": career_cells(matrix[select], years, birth, **kwargs), + "epuf_masked_as_career_assembler": career_cells( + masked[select], years, birth, **kwargs + ), + } + return out + + +# --- PSID side ------------------------------------------------------------ + + +def psid_support() -> tuple[pd.DataFrame, np.ndarray, dict[str, object]]: + """The gate's PSID support, its split universe and its counts. + + Reads the real PSID only through the existing loaders. The universe + is every person of gate 1's filtered panel (the persons a gate split + draws from); the support is the subset the window cells score. + """ + from populace_dynamics.data.deaths import read_death_records + from populace_dynamics.data.family import family_earnings_panel + + raw = family_earnings_panel() + panel = raw[ + (raw["age"] >= AGE_MIN) + & (raw["age"] <= AGE_MAX) + & (raw["period"] >= PERIOD_MIN) + & (raw["period"] <= PERIOD_MAX) + & (raw["weight"] > 0) + ].reset_index(drop=True) + reference = json.loads((ROOT / PANEL_REFERENCE).read_text()) + observed = { + "n_person_periods": int(len(panel)), + "n_persons": int(panel["person_id"].nunique()), + } + expected = {key: int(reference[key]) for key in observed} + if observed != expected: + raise ValueError( + f"filtered panel {observed} is not gate 1's {expected} " + f"({PANEL_REFERENCE})" + ) + sex = read_death_records()[["person_id", "sex"]] + return support_from_panel(panel, sex) + + +def support_from_panel( + panel: pd.DataFrame, sex_records: pd.DataFrame +) -> tuple[pd.DataFrame, np.ndarray, dict[str, object]]: + """Apply the support rules to a filtered panel (real or synthetic).""" + if panel.duplicated(["person_id", "period"]).any(): + raise ValueError("panel has duplicate person-periods") + universe = np.sort(panel["person_id"].unique()) + grouped = panel.groupby("person_id") + anchor = grouped["period"].max() + in_window = panel[panel["period"].isin(WINDOW_YEARS)] + n_window = in_window.groupby("person_id")["period"].nunique() + all_four = n_window.reindex(universe, fill_value=0) == len(WINDOW_YEARS) + late_anchor = anchor.reindex(universe) >= MIN_ANCHOR_PERIOD + birth = np.floor( + (panel["period"] - panel["age"]).groupby(panel["person_id"]).median() + + 0.5 + ).astype(int) + coded = sex_records[sex_records["sex"].isin(PSID_SEX_LABELS)] + coded = coded.drop_duplicates(["person_id", "sex"]) + if coded["person_id"].duplicated().any(): + raise ValueError("a person has two coded sexes") + sex = ( + coded.set_index("person_id")["sex"] + .map(PSID_SEX_LABELS) + .reindex(universe) + ) + low = min(a for a, _ in COHORT_BANDS.values()) + high = max(b for _, b in COHORT_BANDS.values()) + in_bands = birth.reindex(universe).between(low, high) + keep = ( + all_four.to_numpy() + & late_anchor.to_numpy() + & sex.notna().to_numpy() + & in_bands.to_numpy() + ) + ids = universe[keep] + weight = ( + panel[panel["period"] == WINDOW_YEARS[-1]] + .set_index("person_id")["weight"] + .reindex(ids) + ) + persons = pd.DataFrame( + { + "person_id": ids, + "sex": sex.reindex(ids).to_numpy(), + "birth_year": birth.reindex(ids).to_numpy(), + "weight": weight.to_numpy(), + } + ) + rows = in_window[in_window["person_id"].isin(ids)] + measured = pd.DataFrame( + { + "person_id": rows["person_id"].to_numpy(), + "year": rows["period"].to_numpy(), + "earnings": _measure_rows(rows), + } + ) + frame = window_frame(measured, persons, wage_bases=wage_bases()) + counts = { + "n_universe_persons": int(len(universe)), + "n_present_all_four_years": int(all_four.sum()), + "n_and_anchor_2006_or_later": int((all_four & late_anchor).sum()), + "n_and_sex_coded": int( + ( + all_four.to_numpy() + & late_anchor.to_numpy() + & sex.notna().to_numpy() + ).sum() + ), + "n_support_persons": int(len(frame)), + "by_sex_and_band": _support_counts(frame), + } + return frame, universe, counts + + +def _measure_rows(rows: pd.DataFrame) -> np.ndarray: + """Apply the EPUF operator to window rows, year by year, in place.""" + out = np.empty(len(rows), dtype=np.float64) + periods = rows["period"].to_numpy() + earnings = rows["earnings"].to_numpy(dtype=np.float64) + for year in WINDOW_YEARS: + select = periods == year + out[select] = epuf_measure(earnings[select], year) + return out + + +# --- floors --------------------------------------------------------------- + + +def _finite(value): + """Replace non-finite floats with None, recursively (strict JSON).""" + if isinstance(value, dict): + return {key: _finite(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [_finite(item) for item in value] + if isinstance(value, float) and not np.isfinite(value): + return None + return value + + +def _values(cells) -> dict[str, float]: + return {cell_id: cell.value for cell_id, cell in cells.items()} + + +def _events(cells) -> dict[str, int]: + return {cell_id: cell.events for cell_id, cell in cells.items()} + + +def build_floors( + arrays: WindowArrays, + universe: np.ndarray, + epuf_values: Mapping[str, float], + epuf_sd: Mapping[str, float], + *, + n_replicates: int = gate.N_FLOOR_REPLICATES, + progress: Callable[[str], None] | None = None, +) -> dict[str, object]: + """Floors, tolerances, partition, OC and the training copy. + + ``arrays`` is the PSID support (real or, in tests, synthetic); + ``universe`` the sorted person ids every split draws from. + """ + ids = cell_ids() + position = np.searchsorted(universe, arrays.person_id) + if not (universe[position] == arrays.person_id).all(): + raise ValueError("support persons are not all in the split universe") + + def on(seed: int, fraction: float) -> np.ndarray: + return holdout_mask(universe, seed=seed, fraction=fraction)[position] + + full = arrays.cells() + replicates: dict[str, list[float]] = {cell_id: [] for cell_id in ids} + common_terms: dict[str, list[float]] = {cell_id: [] for cell_id in ids} + min_events = {cell_id: np.iinfo(np.int64).max for cell_id in ids} + + def track(cells) -> None: + for cell_id, count in _events(cells).items(): + min_events[cell_id] = min(min_events[cell_id], count) + + for b in range(n_replicates): + half = on(gate.half_split_seed(b), gate.HALF_FRACTION) + side_a, side_b = arrays.cells(half), arrays.cells(~half) + track(side_a) + track(side_b) + holdouts: dict[str, list[float]] = {cell_id: [] for cell_id in ids} + complements: dict[str, list[float]] = {cell_id: [] for cell_id in ids} + for j in range(len(gate.GATE_SEEDS)): + drawn = on(gate.holdout_split_seed(b, j), gate.HOLDOUT_FRACTION) + held, rest = arrays.cells(drawn), arrays.cells(~drawn) + track(held) + for cell_id in ids: + holdouts[cell_id].append(held[cell_id].value) + complements[cell_id].append(rest[cell_id].value) + for cell_id in ids: + common, averaging = gate.floor_terms( + cell_id, + side_a[cell_id].value, + side_b[cell_id].value, + holdouts[cell_id], + complements[cell_id], + ) + replicates[cell_id].append(common + averaging) + common_terms[cell_id].append(common) + if progress and (b + 1) % 10 == 0: + progress(f"floor replicate {b + 1}/{n_replicates}") + + gate_seed_cells = {} + for seed in gate.GATE_SEEDS: + held = arrays.cells(on(seed, gate.HOLDOUT_FRACTION)) + track(held) + gate_seed_cells[seed] = held + + floors: dict[str, gate.CellFloor] = {} + cell_block: dict[str, dict[str, object]] = {} + for cell_id in ids: + series = np.asarray(replicates[cell_id], dtype=np.float64) + psid_value = full[cell_id].value + epuf_value = float(epuf_values[cell_id]) + bridge = transform(cell_id, psid_value) - transform( + cell_id, epuf_value + ) + defined = bool(np.isfinite(series).all() and np.isfinite(bridge)) + t = gate.tolerance(series) if defined else float("nan") + sigma = gate.realized_sigma(series) if defined else float("nan") + floors[cell_id] = gate.CellFloor( + cell_id=cell_id, + defined=defined, + min_events=int(min_events[cell_id]), + bridge=float(bridge), + t=t, + sigma=sigma, + epuf_sampling_sd=float(epuf_sd[cell_id]), + ) + magnitude = np.abs(series) + cell_block[cell_id] = { + "metric": metric(cell_id), + "cap": gate.CAPS[metric(cell_id)], + "epuf_value": epuf_value, + "epuf_sampling_sd": float(epuf_sd[cell_id]), + "psid_value": float(psid_value), + "psid_n": int(full[cell_id].n), + "bridge_psid_minus_epuf": float(bridge), + "min_events": int(min_events[cell_id]), + "floor": { + "replicates": [float(value) for value in series], + "mean_abs": float(magnitude.mean()) if defined else None, + "sd_abs": float(magnitude.std(ddof=1)) if defined else None, + "realized_sigma": sigma if defined else None, + "shared_noise_variance_share": ( + float( + np.mean(np.square(common_terms[cell_id])) + / np.mean(np.square(series)) + ) + if defined and np.any(series != 0) + else None + ), + "tolerance": t if defined else None, + }, + } + + reasons = { + cell_id: gate.demotion_reason(floor) + for cell_id, floor in floors.items() + } + gated, report_only = gate.adopt_ladder(reasons) + + per_seed_real = { + seed: _values(cells) for seed, cells in gate_seed_cells.items() + } + registered = {} + for cell_id in ids: + floor = floors[cell_id] + block = cell_block[cell_id] + block["eligibility"] = reasons[cell_id] or "eligible" + block["gated"] = cell_id in gated + if cell_id in report_only: + block["report_reason"] = report_only[cell_id] + if not floor.defined: + continue + lower, upper = gate.hull(floor.bridge, floor.t) + block["lower"] = lower + block["upper"] = upper + block["minimum_detectable_gap_80"] = gate.minimum_detectable_gap( + floor.bridge, floor.t, floor.sigma + ) + block["faithful_pass_probability"] = gate.faithful_pass_probability( + floor.bridge, floor.sigma, lower, upper + ) + block["real_gate_holdouts"] = gate.score_cell( + cell_id, + [per_seed_real[seed][cell_id] for seed in gate.GATE_SEEDS], + epuf_value=block["epuf_value"], + lower=lower, + upper=upper, + ) + if cell_id in gated: + registered[cell_id] = { + "epuf_value": block["epuf_value"], + "psid_value": block["psid_value"], + "lower": lower, + "upper": upper, + } + + analytic = float( + np.prod( + [cell_block[c]["faithful_pass_probability"] for c in gated] or [1] + ) + ) + joint = [ + all( + cell_block[c]["lower"] + <= floors[c].bridge + replicates[c][b] + <= cell_block[c]["upper"] + for c in gated + ) + for b in range(n_replicates) + ] + training_copy = gate.score_run(per_seed_real, registered) + status = ( + "lockable_pending_referee_round" + if gated + else "report_only_bridge_dominated" + ) + return _finite( + { + "cells": cell_block, + "gate_partition": { + "status": status, + "gated": gated, + "n_gated": len(gated), + "report_only": report_only, + "n_report_only": len(report_only), + }, + "registered": registered, + "faithful_candidate_oc": { + "method": ( + "per cell, the normal probability that bridge + noise " + "falls inside the interval at the cell's realised sigma; " + "analytic_product multiplies the gated cells; " + "empirical_joint is the share of floor replicates in " + "which every gated cell's bridge + e_b is inside" + ), + "analytic_product": analytic, + "empirical_joint": float(np.mean(joint)) if gated else None, + "n_replicates": n_replicates, + "pause_below": gate.OC_PAUSE, + "pause": bool(gated) and analytic < gate.OC_PAUSE, + }, + "training_copy": training_copy, + "real_gate_seed_values": { + str(seed): values for seed, values in per_seed_real.items() + }, + } + ) + + +# --- bite demonstrations -------------------------------------------------- + + +def _year_columns() -> list[str]: + return [f"e{year}" for year in WINDOW_YEARS] + + +def perturb_persistence( + frame: pd.DataFrame, rng: np.random.Generator, share: float +) -> pd.DataFrame: + """BD1: a share of persons take a same-sex, same-band donor's 1998-2002.""" + out = frame.copy() + early = _year_columns()[:3] + band = _band_labels(frame) + for _, index in frame.groupby([frame["sex"], band]).indices.items(): + chosen = index[rng.random(len(index)) < share] + donors = rng.choice(index, size=len(chosen)) + out.iloc[chosen, [out.columns.get_loc(c) for c in early]] = frame.iloc[ + donors + ][early].to_numpy() + return out + + +def perturb_sex_blind( + frame: pd.DataFrame, rng: np.random.Generator, *, same_sex: bool +) -> pd.DataFrame: + """BD2 / BD2c: everyone takes a donor's 1998-2002 path. + + The donor shares the person's cohort band and 2004 class (no + earnings, or the decile of 2004 earnings among the band's positive + persons). BD2 draws donors from both sexes, as a generator that never + sees sex would; BD2c restricts them to the person's own sex and is + the control that isolates what pooling the sexes does. + """ + out = frame.copy() + early = _year_columns()[:3] + last = frame[_year_columns()[3]].to_numpy() + band = _band_labels(frame).to_numpy() + klass = np.zeros(len(frame), dtype=int) + for label in COHORT_BANDS: + positive = (band == label) & (last > 0) + if positive.sum() == 0: + continue + edges = np.quantile(last[positive], np.linspace(0.1, 0.9, 9)) + klass[positive] = 1 + np.searchsorted( + edges, last[positive], side="right" + ) + keys = [band, klass] + ([frame["sex"].to_numpy()] if same_sex else []) + groups = pd.DataFrame({i: key for i, key in enumerate(keys)}) + for _, index in groups.groupby(list(groups.columns)).indices.items(): + donors = rng.choice(index, size=len(index)) + out.iloc[index, [out.columns.get_loc(c) for c in early]] = frame.iloc[ + donors + ][early].to_numpy() + return out + + +def perturb_top_tail( + frame: pd.DataFrame, rng: np.random.Generator +) -> pd.DataFrame: + """BD3: half of each early year's top 8 percent move down the ranks.""" + out = frame.copy() + for column in _year_columns()[:3]: + values = frame[column].to_numpy() + positive = np.flatnonzero(values > 0) + ordered = np.sort(values[positive]) + rank = np.searchsorted(ordered, values[positive], side="right") / len( + ordered + ) + move = (rank > BD3_RANK_ABOVE) & ( + rng.random(len(positive)) < BD3_MOVE_PROBABILITY + ) + target = rng.uniform(*BD3_TARGET_RANKS, size=int(move.sum())) + replacement = np.quantile(ordered, target, method="lower") + column_values = values.copy() + column_values[positive[move]] = replacement + out[column] = column_values + return out + + +def perturb_participation( + frame: pd.DataFrame, rng: np.random.Generator +) -> pd.DataFrame: + """BD4: each positive 1998-2002 person-year becomes zero at random.""" + out = frame.copy() + for column in _year_columns()[:3]: + values = frame[column].to_numpy().copy() + drop = (values > 0) & (rng.random(len(values)) < BD4_ZERO_PROBABILITY) + values[drop] = 0.0 + out[column] = values + return out + + +def _band_labels(frame: pd.DataFrame) -> pd.Series: + labels = pd.Series("", index=frame.index, dtype=object) + for label, (low, high) in COHORT_BANDS.items(): + labels[frame["birth_year"].between(low, high)] = label + return labels + + +def bite_demonstrations( + frame: pd.DataFrame, + universe: np.ndarray, + registered: Mapping[str, Mapping[str, float]], +) -> dict[str, object]: + """Score each perturbation on the 20 gate holdouts, 50 times.""" + position = np.searchsorted(universe, frame["person_id"].to_numpy()) + masks = { + seed: holdout_mask( + universe, seed=seed, fraction=gate.HOLDOUT_FRACTION + )[position] + for seed in gate.GATE_SEEDS + } + perturbations: dict[str, Callable] = { + f"bd1_persistence_loss_{share:.2f}": ( + lambda f, r, share=share: perturb_persistence(f, r, share) + ) + for share in BD1_SHARES + } + perturbations["bd2_sex_blind_donors"] = lambda f, r: perturb_sex_blind( + f, r, same_sex=False + ) + perturbations["bd2c_same_sex_donors_control"] = ( + lambda f, r: perturb_sex_blind(f, r, same_sex=True) + ) + perturbations["bd3_top_tail_compression"] = perturb_top_tail + perturbations["bd4_participation_loss"] = perturb_participation + + out: dict[str, object] = {} + for index, (name, perturb) in enumerate(perturbations.items()): + fails = 0 + cell_fails = {cell_id: 0 for cell_id in registered} + for seed in BITE_SEEDS: + rng = np.random.default_rng([BITE_SEED_BASE, index, seed]) + arrays = WindowArrays(perturb(frame, rng), wage_bases=wage_bases()) + per_seed = { + s: _values(arrays.cells(mask)) for s, mask in masks.items() + } + scored = gate.score_run(per_seed, registered) + fails += not scored["pass"] + for cell_id, cell in scored["cells"].items(): + cell_fails[cell_id] += not cell["pass"] + out[name] = { + "fail_share": fails / len(BITE_SEEDS) if registered else None, + "cell_fail_share": { + cell_id: count / len(BITE_SEEDS) + for cell_id, count in cell_fails.items() + }, + "n_perturbation_seeds": len(BITE_SEEDS), + } + gated_families = { + family + for family, stats in gate.FAMILIES.items() + if any(cell_id.split(".")[0] in stats for cell_id in registered) + } + requirements = {} + for family in sorted(gated_families): + name = BITE_REQUIREMENT[family] + share = out[name]["fail_share"] + requirements[family] = { + "bite": name, + "required_fail_share": BITE_REQUIRED_FAIL_SHARE, + "fail_share": share, + "met": share is not None and share >= BITE_REQUIRED_FAIL_SHARE, + } + out["requirements"] = requirements + out["pause"] = any(not row["met"] for row in requirements.values()) + return _finite(out) + + +# --- artifact ------------------------------------------------------------- + + +def _git(*args: str) -> str: + return subprocess.run( + ["git", *args], cwd=ROOT, capture_output=True, text=True, check=True + ).stdout.strip() + + +def _file_sha256(relative: str) -> str: + return hashlib.sha256((ROOT / relative).read_bytes()).hexdigest() + + +def design_block() -> dict[str, object]: + return { + "window_years": list(WINDOW_YEARS), + "cohort_bands": {k: list(v) for k, v in COHORT_BANDS.items()}, + "gate_seeds": list(gate.GATE_SEEDS), + "holdout_fraction": gate.HOLDOUT_FRACTION, + "floor": { + "n_replicates": gate.N_FLOOR_REPLICATES, + "half_split_seed": "b", + "holdout_split_seed": "1000 + 20 * b + j", + "replicate": ( + "e_b = [m(A_b) - m(B_b)] / 2 + pooled(m(H_bj)) - " + "pooled(m(T_bj)), j = 0..19" + ), + }, + "k": gate.K_TOLERANCE, + "tolerance": "round(mean|e_b| + k * sd|e_b| (ddof=1), 3)", + "interval": "[min(0, bridge) - t, max(0, bridge) + t]", + "eligibility": "abs(bridge) + t + 0.8416 * sigma <= cap", + "caps": gate.CAPS, + "min_events": gate.MIN_EVENTS, + "epuf_noise_share_max": gate.EPUF_NOISE_SHARE_MAX, + "oc_pause_below": gate.OC_PAUSE, + "support": { + "universe": ( + "gate 1's filtered PSID family panel: age 25-59, reference " + "years 1998-2022, positive weight" + ), + "rules": [ + "a row at each of 1998, 2000, 2002 and 2004", + "last in-filter period 2006 or later", + "sex coded male or female (ER32000)", + "birth year floor(median(period - age) + 0.5) in 1947-1973", + ], + "weight": "the person's 2004-row weight", + "epuf": ( + "every EPUF person with sex 1 or 2 born 1947-1973, weight 1" + ), + }, + } + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + parser.add_argument( + "--stage", + choices=("epuf", "full"), + default="full", + help="'epuf' computes and prints the EPUF side only and writes nothing", + ) + args = parser.parse_args() + started = time.time() + + def say(message: str) -> None: + print(f"[{time.time() - started:6.1f}s] {message}", flush=True) + + demographic = epuf.read_demographic() + annual = epuf.read_annual() + say("EPUF read") + epuf_arrays, epuf_counts = epuf_window(demographic, annual) + epuf_cells = epuf_arrays.cells() + epuf_values = _values(epuf_cells) + epuf_sd = epuf_sampling_sd(epuf_arrays) + say(f"EPUF window: {len(epuf_arrays):,} persons") + if args.stage == "epuf": + print(json.dumps(epuf_values, indent=1)) + return + + careers = career_reference(demographic, annual) + del demographic, annual + say("EPUF career reference done") + frame, universe, psid_counts = psid_support() + arrays = WindowArrays(frame, wage_bases=wage_bases()) + say(f"PSID support: {len(arrays):,} persons") + + from populace_dynamics.harness.panel import split_panel_by_person + + gate1 = json.loads((ROOT / GATE1_RUN).read_text()) + committed_holdouts = { + int(row["seed"]): int(row["n_persons"]) for row in gate1["per_seed"] + } + ids_frame = pd.DataFrame({"person_id": universe}) + holdout_ids = {} + for seed in gate.GATE_SEEDS: + drawn = holdout_mask( + universe, seed=seed, fraction=gate.HOLDOUT_FRACTION + ) + left, _ = split_panel_by_person( + ids_frame, "person_id", fraction=gate.HOLDOUT_FRACTION, seed=seed + ) + if set(left["person_id"]) != set(universe[drawn]): + raise AssertionError(f"seed {seed}: not the gate-1 split") + if seed in committed_holdouts and ( + int(drawn.sum()) != committed_holdouts[seed] + ): + raise AssertionError( + f"seed {seed}: {int(drawn.sum())} holdout persons, " + f"{GATE1_RUN} has {committed_holdouts[seed]}" + ) + holdout_ids[str(seed)] = { + "n_persons": int(drawn.sum()), + "n_support_persons": int( + np.isin(arrays.person_id, universe[drawn]).sum() + ), + "sha256_sorted_person_ids": _sha256_ids(universe[drawn]), + } + + built = build_floors(arrays, universe, epuf_values, epuf_sd, progress=say) + bites = bite_demonstrations(frame, universe, built["registered"]) + say("bite demonstrations done") + + payload = { + "schema_version": SCHEMA_VERSION, + "run": "epuf_gate_floors_v1", + "status": "DRAFT_NOT_OPERATIVE", + "purpose": ( + "Pre-lock floors, bridges, partition and operating " + "characteristic of the proposed EPUF covered-earnings gate " + "(docs/amendments/gate_epuf_registration_proposal.md). No " + "candidate was generated or scored to build it." + ), + "ceremony": { + "step": "pre-lock floor", + "draft_block": "docs/design/gate_epuf_block_draft.yaml", + "gates_yaml_untouched": True, + }, + "candidate_blind": { + "generated_candidates": 0, + "psid_read_through": [ + "populace_dynamics.data.family.family_earnings_panel", + "populace_dynamics.data.deaths.read_death_records", + ], + }, + "design": design_block(), + "inputs": { + "epuf_sha256": dict(epuf.EPUF_SHA256), + "disclosure_constants_sha256": CONSTANTS_SHA256, + "psid_panel": {**psid_counts, "reference": PANEL_REFERENCE}, + "gate1_run": GATE1_RUN, + }, + "epuf_support": epuf_counts, + "holdout_ids": holdout_ids, + **built, + "bite_demonstrations": bites, + "ceremony_pause": bool( + built["faithful_candidate_oc"]["pause"] or bites["pause"] + ), + "tranche_r_epuf_reference": { + "note": ( + "EPUF only. Report-only career tranche: the original four " + "career statistics on true EPUF careers and on EPUF careers " + "masked as the career assembler builds a PSID career " + "(nothing before 1968; odd years from 1997 filled with the " + "neighbour mean). The PSID side is computed once, after " + "lock." + ), + "ages": list(CAREER_AGES), + "cells": careers, + }, + "concept_deltas": CONCEPT_DELTAS, + "revision_pins": { + "head_sha": _git("rev-parse", "HEAD"), + "origin_master_sha": _git("rev-parse", "origin/master"), + "derivation_core_sha256": { + path: _file_sha256(path) for path in DERIVATION_CORE + }, + }, + "elapsed_seconds": round(time.time() - started, 1), + } + write_new(ARTIFACT, payload, sidecar=True) + INPUTS.write_text( + json.dumps( + { + "artifact": ARTIFACT.name, + "status": "SOURCE_INPUT_DIGESTS", + "official_source": { + "url": ( + "https://www.ssa.gov/policy/docs/microdata/epuf/" + "epuf2006_csv_files.zip" + ), + "archive_sha256": ( + "0bb97275cc35a1bb42d34d26acbc9df720d4f875854ba1d02c" + "50323d2357003b" + ), + "archive_bytes": 291602034, + "archive_members": [ + epuf.DEMOGRAPHIC_FILE, + epuf.ANNUAL_FILE, + ], + "retrieved": "2026-10-01", + "provenance": "data/external/epuf_2006/provenance.md", + }, + "staged_inputs": [ + {"path": name, "sha256": digest} + for name, digest in epuf.EPUF_SHA256.items() + ], + }, + indent=2, + ) + + "\n" + ) + say(f"wrote {ARTIFACT.relative_to(ROOT)}") + print(json.dumps(built["gate_partition"], indent=1)) + + +if __name__ == "__main__": + main() diff --git a/scripts/extract_epuf_disclosure_constants.py b/scripts/extract_epuf_disclosure_constants.py new file mode 100644 index 00000000..cd2ae1de --- /dev/null +++ b/scripts/extract_epuf_disclosure_constants.py @@ -0,0 +1,123 @@ +"""Read EPUF's per-year disclosure constants off the pinned bytes. + +SSA's disclosure operator (EPUF dictionary; Compson 2011) replaces every +annual value below $100 with one per-year mean, and every value within +one rounding base below the taxable maximum with one per-year band +mean. Neither constant is printed in the documentation, but each is +readable from the file: a year has exactly one distinct value below +$100, and exactly one value inside the band that is not a multiple of +the rounding base. This script records both for 1951-2006 so that +``populace_dynamics.harness.epuf_operator`` can apply the same operator +to survey-side and model-side earnings without the microdata staged. + +Usage:: + + uv run python scripts/extract_epuf_disclosure_constants.py + +Writes ``data/external/epuf_2006/disclosure_constants.json``. It reads +EPUF only (no PSID, no model output). +""" + +from __future__ import annotations + +import json +from pathlib import Path + +from populace_dynamics.cola_track_a.statutory import load_statutory_capture +from populace_dynamics.data import epuf + +ROOT = Path(__file__).resolve().parents[1] +OUT = ROOT / "data" / "external" / "epuf_2006" / "disclosure_constants.json" + +#: SSA's rounding bases by earnings level (Compson 2011, "Disclosure +#: protection"): $25 from $100 to $999, $100 from $1,000 to $49,999 and +#: $1,000 from $50,000. +BOTTOM_CODE_BELOW = 100 +BASE_BREAKS = ((1_000, 25), (50_000, 100)) +TOP_BASE = 1_000 + + +def rounding_base(value: float) -> int: + for upper, base in BASE_BREAKS: + if value < upper: + return base + return TOP_BASE + + +def wage_base_by_year() -> dict[int, int]: + points = { + int(year): float(value) + for year, value in load_statutory_capture()[ + "wage_base_change_points" + ].items() + } + return { + year: int(points[max(y for y in points if y <= year)]) + for year in range(epuf.EPUF_FIRST_YEAR, epuf.EPUF_LAST_YEAR + 1) + } + + +def build() -> dict: + annual = epuf.read_annual() + caps = wage_base_by_year() + years = {} + for year, values in annual.groupby("year")["earnings"]: + year = int(year) + cap = caps[year] + base = rounding_base(cap) + below = sorted( + int(v) for v in values[values < BOTTOM_CODE_BELOW].unique() + ) + in_band = values[(values > cap - base) & (values < cap)] + off_grid = sorted( + int(v) for v in in_band[in_band % base != 0].unique() + ) + if len(below) != 1 or len(off_grid) != 1: + raise ValueError( + f"{year}: expected one bottom code and one band mean, got " + f"{below} and {off_grid}" + ) + years[str(year)] = { + "wage_base": cap, + "band_base": base, + "bottom_code": below[0], + "band_mean": off_grid[0], + "n_bottom_coded": int((values == below[0]).sum()), + "n_band_mean": int((values == off_grid[0]).sum()), + "n_at_wage_base": int((values == cap).sum()), + "n_positive": int(len(values)), + } + return { + "schema_version": "epuf_disclosure_constants.v1", + "generator": "scripts/extract_epuf_disclosure_constants.py", + "source": { + "annual_sha256": epuf.EPUF_SHA256[epuf.ANNUAL_FILE], + "wage_base": ( + "data/external/track_a_statutory_parameters.json " + "wage_base_change_points" + ), + }, + "rule": { + "bottom_code_below": BOTTOM_CODE_BELOW, + "rounding_bases": [ + {"from": 100, "below": 1_000, "base": 25}, + {"from": 1_000, "below": 50_000, "base": 100}, + {"from": 50_000, "below": None, "base": 1_000}, + ], + "band": ( + "values strictly between the wage base less one rounding " + "base (the base at the wage base) and the wage base are " + "replaced by band_mean" + ), + }, + "years": years, + } + + +def main() -> None: + OUT.write_text(json.dumps(build(), indent=1) + "\n") + print(f"wrote {OUT.relative_to(ROOT)}") + + +if __name__ == "__main__": + main() diff --git a/scripts/extract_epuf_published_tables.py b/scripts/extract_epuf_published_tables.py new file mode 100644 index 00000000..9ad451b9 --- /dev/null +++ b/scripts/extract_epuf_published_tables.py @@ -0,0 +1,223 @@ +"""Extract SSA's published EPUF tables into a committed JSON. + +The tables are the reproduction targets for +``populace_dynamics.data.epuf``: every value here is printed by SSA in +Compson (2011, Social Security Bulletin 71(4)) or Compson (2012, +Research and Statistics Note 2012-01) and is recomputed from the staged +EPUF bytes by ``tests/data/test_epuf.py``. Sources are the page texts +committed beside the output (``data/external/epuf_2006/*.source.txt``, +retrieved 2026-10-01 through the in-app browser because www.ssa.gov +answers curl with HTTP 403); each table records the 1-based line of +its caption in that text and the text's SHA-256. + +Usage:: + + uv run python scripts/extract_epuf_published_tables.py + +Writes ``data/external/epuf_2006/published_tables.json``. Deterministic: +re-running on the same texts reproduces the same bytes. +""" + +from __future__ import annotations + +import hashlib +import json +import re +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +FOLDER = ROOT / "data" / "external" / "epuf_2006" +SSB = FOLDER / "ssb_v71n4p33.source.txt" +RSN = FOLDER / "rsn2012-01.source.txt" +OUT = FOLDER / "published_tables.json" + +SSB_URL = "https://www.ssa.gov/policy/docs/ssb/v71n4/v71n4p33.html" +RSN_URL = "https://www.ssa.gov/policy/docs/rsnotes/rsn2012-01.html" + +_YEAR = re.compile(r"^(18|19|20)\d\d$") +_FOOTNOTE = re.compile(r"\s+[a-z]$") + + +def _lines(path: Path) -> list[str]: + return path.read_text(encoding="utf-8").replace("\xa0", " ").splitlines() + + +def _sha256(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def _number(cell: str) -> float: + return float(_FOOTNOTE.sub("", cell.strip()).replace(",", "")) + + +def _caption_line(lines: list[str], caption: str) -> int: + matches = [i for i, line in enumerate(lines) if line.strip() == caption] + if len(matches) != 1: + raise ValueError(f"caption {caption!r} found {len(matches)} times") + return matches[0] + + +def _rows(lines: list[str], start: int) -> list[list[str]]: + """Tab-split year rows after ``start`` until the first non-year row + that follows at least one year row.""" + rows: list[list[str]] = [] + for line in lines[start + 1 :]: + cells = line.split("\t") + if _YEAR.match(cells[0].strip()): + rows.append(cells) + elif rows: + break + return rows + + +def _table(lines, caption, columns, *, kind=float): + start = _caption_line(lines, caption) + out = {} + for cells in _rows(lines, start): + if len(cells) < len(columns) + 1: + raise ValueError(f"short row under {caption!r}: {cells}") + values = [_number(cell) for cell in cells[1 : len(columns) + 1]] + out[cells[0].strip()] = { + name: kind(value) + for name, value in zip(columns, values, strict=False) + } + return start + 1, out + + +def build() -> dict: + ssb = _lines(SSB) + rsn = _lines(RSN) + tables = {} + + line, rows = _table( + ssb, + "Table A1.", + ["all", "men", "men_pct", "women", "women_pct", "unknown"], + ) + tables["ssb_table_a1_records"] = { + "source": "ssb", + "caption_line": line, + "description": ( + "Number of individuals with taxable earnings records in " + "EPUF, by sex, 1951-2006 (persons with an annual row)" + ), + "unit": "persons", + "rows": { + year: { + key: int(row[key]) + for key in ("all", "men", "women", "unknown") + } + for year, row in rows.items() + }, + } + + line, rows = _table( + ssb, + "Table 4.", + [ + "mean_all", + "median_all", + "mean_men", + "median_men", + "mean_women", + "median_women", + "mean_unknown", + "median_unknown", + ], + ) + tables["ssb_table_4_mean_median"] = { + "source": "ssb", + "caption_line": line, + "description": ( + "Average and median taxable earnings in EPUF, by sex, " + "1951-2006 (dollars; means rounded to the dollar)" + ), + "unit": "dollars", + "rows": rows, + } + + for key, caption, columns in ( + ( + "ssb_chart_3_birth_year", + "### Table equivalent for Chart 3. Number of individuals in " + "EPUF, by year of birth", + ["thousands"], + ), + ( + "ssb_chart_4_birth_year_sex", + "### Table equivalent for Chart 4. Number of individuals in " + "EPUF, by year of birth and sex", + ["men_thousands", "women_thousands"], + ), + ): + line, rows = _table(ssb, caption, columns) + tables[key] = { + "source": "ssb", + "caption_line": line, + "description": caption.removeprefix("### Table equivalent for "), + "unit": "thousands of persons, 2 decimals", + "rows": rows, + } + + line, rows = _table( + rsn, + "Table 8.", + [ + "supplement_all", + "supplement_men", + "supplement_women", + "epuf_all", + "epuf_men", + "epuf_women", + ], + ) + tables["rsn_table_8_pct_below_max"] = { + "source": "rsn", + "caption_line": line, + "description": ( + "Percentage of all, male and female workers with earnings " + "below the taxable maximum, 1951-2006 (Supplement and EPUF " + "columns; EPUF columns are the reproduction target)" + ), + "unit": "percent, 1 decimal", + "rows": rows, + } + + return { + "schema_version": "epuf_published_tables.v1", + "generator": "scripts/extract_epuf_published_tables.py", + "sources": { + "ssb": { + "citation": ( + "Compson, Michael. 2011. 'The 2006 Earnings Public-Use " + "Microdata File: An Introduction.' Social Security " + "Bulletin 71(4)." + ), + "url": SSB_URL, + "text": str(SSB.relative_to(ROOT)), + "text_sha256": _sha256(SSB), + }, + "rsn": { + "citation": ( + "Compson, Michael. 2012. 'Comparing Earnings Estimates " + "from the 2006 Earnings Public-Use File and the Annual " + "Statistical Supplement.' Research and Statistics Note " + "No. 2012-01." + ), + "url": RSN_URL, + "text": str(RSN.relative_to(ROOT)), + "text_sha256": _sha256(RSN), + }, + }, + "retrieved": "2026-10-01", + "tables": tables, + } + + +def main() -> None: + OUT.write_text(json.dumps(build(), indent=1, sort_keys=False) + "\n") + print(f"wrote {OUT.relative_to(ROOT)}") + + +if __name__ == "__main__": + main() diff --git a/src/populace_dynamics/data/epuf.py b/src/populace_dynamics/data/epuf.py new file mode 100644 index 00000000..bf3a14d9 --- /dev/null +++ b/src/populace_dynamics/data/epuf.py @@ -0,0 +1,270 @@ +"""SSA's 2006 Earnings Public-Use File (EPUF), read byte-pinned. + +EPUF is a 1 percent systematic sample of Social Security numbers +issued before January 2007 (Compson 2011, Social Security Bulletin +71(4); https://www.ssa.gov/policy/docs/microdata/epuf/index.html). +It has two linked files: + +- ``EPUF2006_DEMOGRAPHIC.csv``: one row per sampled person (4,384,254 + rows; the "4,348,254" printed in parts of the SSB article is a digit + transposition, see the article's own arithmetic and the dictionary) + with year of birth, sex (1 male, 2 female, 3 unspecified), aggregate + 1937-1950 capped taxable earnings and quarters of coverage, and + 1951-1952 quarters of coverage. +- ``EPUF2006_ANNUAL.csv``: one row per person-year with positive + capped taxable earnings, 1951-2006 (60,326,474 rows over 3,131,424 + persons). **A year with zero earnings has no row.** + +``ANNUAL_EARNINGS`` is capped Social Security taxable earnings: covered +wages plus covered self-employment income, summed over employers and +capped at the year's contribution and benefit base. SSA applied a +disclosure operator before release (dictionary; SSB pp. 33-59): values +below $100 are replaced by one per-year mean, values within one +rounding base below the cap by one per-year band mean, and the rest are +random-rounded to $25 ($100-$999), $100 ($1,000-$49,999) or $1,000 +($50,000 and over). The operator preserves each person-year's +worker/non-worker and at-maximum/below-maximum status by design. +Earnings at ages 14 and younger (cohorts born after 1937) and 86 and +older were zeroed, so rows exist only at calendar-year ages 15-85. + +The CSV headers differ from the dictionary's names (``TOT_COV_EARN3750`` +/ ``QC3750`` / ``QC5152`` / ``YEAR_EARN`` against the dictionary's +``AE3750`` / ``TC3750`` / ``TC5152`` / ``YEAR``); this reader renames +them to snake_case. ``ANNUAL_QTRS`` is the literal ``"."`` for every +1951-1952 row and is read as a missing value. + +Staging: the extracted members live outside the repository under +``~/PolicyEngine/epuf-data/csv`` (override with +``POPULACE_DYNAMICS_EPUF_DIR``, which names the folder holding the two +CSVs). The download record (URL, retrieval date, bytes, SHA-256 and +the 2026-10-01 verification against the live server) is +``data/external/epuf_2006/provenance.md``. Every read verifies the +SHA-256 in :data:`EPUF_SHA256` unless the caller opts out, so a file +with other bytes is refused rather than silently read. +""" + +from __future__ import annotations + +import hashlib +import os +from collections.abc import Iterable +from functools import lru_cache +from pathlib import Path + +import numpy as np +import pandas as pd + +__all__ = [ + "ANNUAL_FILE", + "DEMOGRAPHIC_FILE", + "EPUF_ANNUAL_ROWS", + "EPUF_EARNER_PERSONS", + "EPUF_PERSONS", + "EPUF_SHA256", + "EPUFNotStagedError", + "epuf_status", + "read_annual", + "read_demographic", +] + +DEMOGRAPHIC_FILE = "EPUF2006_DEMOGRAPHIC.csv" +ANNUAL_FILE = "EPUF2006_ANNUAL.csv" + +#: SHA-256 of the two data members of ``epuf2006_csv_files.zip`` (zip +#: SHA-256 0bb97275cc35a1bb42d34d26acbc9df720d4f875854ba1d02c50323d2357003b, +#: 291,602,034 bytes, byte-identical to what www.ssa.gov served on +#: 2026-10-01; data/external/epuf_2006/provenance.md). +EPUF_SHA256: dict[str, str] = { + DEMOGRAPHIC_FILE: ( + "195db459ca7b7c810162cb6e432371e8787eba8331787d2ba1eace1a0da2ccb0" + ), + ANNUAL_FILE: ( + "a47315b56214df66fb9f9abcb2caa60779c8b3d091ded199323672c27e3ea105" + ), +} + +#: Row counts of the pinned bytes (asserted on every full read). +EPUF_PERSONS = 4_384_254 +EPUF_EARNER_PERSONS = 3_131_424 +EPUF_ANNUAL_ROWS = 60_326_474 + +EPUF_FIRST_YEAR = 1951 +EPUF_LAST_YEAR = 2006 + +_DATA_DIR_ENV = "POPULACE_DYNAMICS_EPUF_DIR" +_DEFAULT_DATA_DIR = Path("~/PolicyEngine/epuf-data/csv").expanduser() +_README_POINTER = ( + "stage the members of SSA's epuf2006_csv_files.zip under " + "~/PolicyEngine/epuf-data/csv (or POPULACE_DYNAMICS_EPUF_DIR); see " + "data/external/epuf_2006/provenance.md" +) + +_DEMOGRAPHIC_COLUMNS = { + "ID": "person_id", + "YOB": "birth_year", + "SEX": "sex", + "TOT_COV_EARN3750": "earnings_1937_1950", + "QC3750": "qc_1937_1950", + "QC5152": "qc_1951_1952", +} +_ANNUAL_COLUMNS = { + "ID": "person_id", + "YEAR_EARN": "year", + "ANNUAL_EARNINGS": "earnings", + "ANNUAL_QTRS": "quarters", +} + + +class EPUFNotStagedError(FileNotFoundError): + """The EPUF members are missing or are not the pinned bytes.""" + + +def _resolve_data_dir(data_dir: Path | None) -> Path: + """Resolve the EPUF folder from argument, env var, then default.""" + if data_dir is not None: + return Path(data_dir).expanduser() + env_value = os.environ.get(_DATA_DIR_ENV) + if env_value: + return Path(env_value).expanduser() + return _DEFAULT_DATA_DIR + + +def _file_sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as handle: + for block in iter(lambda: handle.read(1 << 22), b""): + digest.update(block) + return digest.hexdigest() + + +@lru_cache(maxsize=8) +def _cached_sha256(path: str, size: int, mtime_ns: int) -> str: + # Keyed on size and mtime so a replaced file is re-hashed. + del size, mtime_ns + return _file_sha256(Path(path)) + + +def _sha256(path: Path) -> str: + stat = path.stat() + return _cached_sha256(str(path), stat.st_size, stat.st_mtime_ns) + + +def epuf_status(*, data_dir: Path | None = None) -> dict[str, object]: + """Where EPUF is staged and whether the staged bytes are the pinned ones. + + ``staged`` says whether both members exist; ``pinned`` whether both + hash to :data:`EPUF_SHA256`. Only the two members are read, to hash + them. + """ + directory = _resolve_data_dir(data_dir) + paths = {name: directory / name for name in EPUF_SHA256} + staged = all(path.is_file() for path in paths.values()) + hashes = ( + {name: _sha256(path) for name, path in paths.items()} if staged else {} + ) + return { + "directory": str(directory), + "staged": staged, + "sha256": hashes, + "pinned_sha256": dict(EPUF_SHA256), + "pinned": staged and hashes == EPUF_SHA256, + } + + +def _member_path(name: str, data_dir: Path | None, verify: bool) -> Path: + path = _resolve_data_dir(data_dir) / name + if not path.is_file(): + raise EPUFNotStagedError( + f"No {name} under {path.parent}; {_README_POINTER}." + ) + if verify: + observed = _sha256(path) + if observed != EPUF_SHA256[name]: + raise EPUFNotStagedError( + f"{path} has SHA-256 {observed}, not the pinned " + f"{EPUF_SHA256[name]}; nothing was read. {_README_POINTER}." + ) + return path + + +def read_demographic( + *, data_dir: Path | None = None, verify: bool = True +) -> pd.DataFrame: + """Read the demographic member: one row per sampled person. + + Columns: ``person_id`` (int32), ``birth_year`` (int16), ``sex`` + (int8; 1 male, 2 female, 3 unspecified), ``earnings_1937_1950`` + (int32; SSA top-codes it at $41,500 and bottom-codes it at $39), + ``qc_1937_1950`` and ``qc_1951_1952`` (int8). + """ + path = _member_path(DEMOGRAPHIC_FILE, data_dir, verify) + frame = pd.read_csv( + path, + dtype={ + "ID": "int32", + "YOB": "int16", + "SEX": "int8", + "TOT_COV_EARN3750": "int32", + "QC3750": "int8", + "QC5152": "int8", + }, + ).rename(columns=_DEMOGRAPHIC_COLUMNS) + if len(frame) != EPUF_PERSONS: + raise ValueError( + f"{path} has {len(frame):,} persons; the pinned file has " + f"{EPUF_PERSONS:,}." + ) + return frame + + +def read_annual( + *, + years: Iterable[int] | None = None, + data_dir: Path | None = None, + verify: bool = True, +) -> pd.DataFrame: + """Read the annual member: one row per person-year with earnings. + + Columns: ``person_id`` (int32), ``year`` (int16), ``earnings`` + (int32, capped taxable earnings after SSA's disclosure operator, + always positive), ``quarters`` (nullable Int8; missing for every + 1951-1952 row). ``years`` keeps only those calendar years; a person + with no row in a year had zero capped taxable earnings that year. + """ + path = _member_path(ANNUAL_FILE, data_dir, verify) + frame = pd.read_csv( + path, + dtype={ + "ID": "int32", + "YEAR_EARN": "int16", + "ANNUAL_EARNINGS": "int32", + "ANNUAL_QTRS": "category", + }, + ).rename(columns=_ANNUAL_COLUMNS) + if len(frame) != EPUF_ANNUAL_ROWS: + raise ValueError( + f"{path} has {len(frame):,} rows; the pinned file has " + f"{EPUF_ANNUAL_ROWS:,}." + ) + # ``ANNUAL_QTRS`` is "." (missing) for 1951-1952 and 0-4 otherwise; + # decoding the six categories is far faster than parsing 60M strings. + labels = frame["quarters"].cat.categories + decoded = np.array( + [-1 if label == "." else int(label) for label in labels], + dtype="int8", + )[frame["quarters"].cat.codes.to_numpy()] + frame["quarters"] = pd.arrays.IntegerArray( + np.where(decoded < 0, 0, decoded).astype("int8"), decoded < 0 + ) + if years is not None: + wanted = np.asarray(sorted({int(year) for year in years})) + outside = wanted[ + (wanted < EPUF_FIRST_YEAR) | (wanted > EPUF_LAST_YEAR) + ] + if outside.size: + raise ValueError( + f"EPUF annual earnings cover {EPUF_FIRST_YEAR}-" + f"{EPUF_LAST_YEAR}; asked for {outside.tolist()}." + ) + frame = frame[frame["year"].isin(wanted)].reset_index(drop=True) + return frame diff --git a/src/populace_dynamics/harness/epuf_cells.py b/src/populace_dynamics/harness/epuf_cells.py new file mode 100644 index 00000000..f9af95e0 --- /dev/null +++ b/src/populace_dynamics/harness/epuf_cells.py @@ -0,0 +1,468 @@ +"""Cell statistics shared by EPUF, real PSID and candidate histories. + +Two families of cells, each computed by ONE function whatever the +source, so a difference between sources can never be a difference of +definition. + +**Window cells** (tranche G of the proposed EPUF gate). The support is +persons with earnings histories at the four even reference years +1998, 2000, 2002 and 2004, in EPUF's capped, disclosed units +(:mod:`populace_dynamics.harness.epuf_operator`), by sex and three +birth-cohort bands (1947-1955, 1956-1964, 1965-1973). The five +statistics: + +- ``r6``: weighted Spearman rank correlation between 1998 and 2004 + earnings, among persons positive in both years. +- ``zint``: among persons positive in 1998 and in 2004, the weighted + share with no earnings in 2000 or in 2002. +- ``d_anyzero``: among persons positive in 2004, the weighted share with + no earnings in at least one of 1998, 2000 and 2002. +- ``q_atmax``: among positive person-years of the four years, the + weighted share exactly at the year's wage base. +- ``mpers``: among persons at the wage base in 2004, the weighted share + also at the wage base in 1998. + +Each statistic conditions on covered earnings at one or both ends of +its span. EPUF records no deaths, departures or arrivals, so an EPUF +person-year with no earnings may be a year after death or abroad; a +person with earnings at the end of a span was alive and in covered work +then. A sex-level cell is the unweighted mean of its three cohort-band +values, which fixes the cohort composition at one-third each on every +side. ``q_sexratio`` is men's ``q_atmax`` over women's. + +**Career cells** (tranche R, report only). The original four career +statistics, on annual capped histories from age 22 to 61 for birth +cohorts whose whole window lies inside 1951-2006: years without +earnings, 10-year rank correlations, the share at the wage base by age +band, and the AIME under the 35-year rule. +:func:`mask_as_career_assembler` rewrites an annual history the way the +repository's career assembler builds a PSID career +(:func:`populace_dynamics.estimates.career.build_career`): nothing +before 1968, and each odd year from 1997 filled with the mean of its +two neighbours. +""" + +from __future__ import annotations + +from collections.abc import Mapping, Sequence +from dataclasses import dataclass + +import numpy as np +import pandas as pd + +__all__ = [ + "CAREER_AGES", + "CAREER_COHORT_BANDS", + "COHORT_BANDS", + "CellValue", + "METRIC_OF", + "SEXES", + "STATISTICS", + "WINDOW_YEARS", + "WindowArrays", + "career_cells", + "cell_ids", + "mask_as_career_assembler", + "metric", + "transform", + "weighted_spearman", + "window_frame", +] + +WINDOW_YEARS: tuple[int, ...] = (1998, 2000, 2002, 2004) +SEXES: tuple[str, ...] = ("men", "women") +COHORT_BANDS: dict[str, tuple[int, int]] = { + "c0": (1947, 1955), + "c1": (1956, 1964), + "c2": (1965, 1973), +} +STATISTICS: tuple[str, ...] = ( + "r6", + "zint", + "d_anyzero", + "q_atmax", + "mpers", +) +#: How a cell's distance from EPUF is measured: the absolute gap of a +#: rank correlation, or the log ratio of a share. +METRIC_OF: dict[str, str] = { + "r6": "abs_gap", + "zint": "log_ratio", + "d_anyzero": "log_ratio", + "q_atmax": "log_ratio", + "mpers": "log_ratio", + "q_sexratio": "log_ratio", +} + +CAREER_AGES: tuple[int, int] = (22, 61) +CAREER_COHORT_BANDS: dict[str, tuple[int, int]] = { + "1930-1934": (1930, 1934), + "1935-1939": (1935, 1939), + "1940-1944": (1940, 1944), +} +_CAREER_PAIRS: tuple[tuple[int, int], ...] = ((1980, 1990), (1994, 2004)) +_CAREER_AGE_BANDS: tuple[tuple[int, int], ...] = ( + (25, 34), + (35, 44), + (45, 54), + (55, 61), +) +_COMPUTATION_YEARS = 35 + + +@dataclass(frozen=True) +class CellValue: + """One cell: its value on the natural scale and its event counts. + + ``events`` is the count the minimum-events rule reads: for a share, + the smaller of the unweighted numerator and its complement; for a + correlation, the number of pairs; for a ratio of two shares, the + smaller of the two shares' events. + """ + + value: float + events: int + n: int + + +def cell_ids() -> list[str]: + """Every window cell id: band-level, sex-level and the sex ratio.""" + ids = [ + f"{stat}.{sex}.{band}" + for stat in STATISTICS + for sex in SEXES + for band in COHORT_BANDS + ] + ids += [f"{stat}.{sex}" for stat in STATISTICS for sex in SEXES] + return [*ids, "q_sexratio"] + + +def metric(cell_id: str) -> str: + """The metric of a cell id.""" + return METRIC_OF[cell_id.split(".")[0]] + + +def transform(cell_id: str, value: float) -> float: + """Put a cell value on its metric's scale (log for shares).""" + if metric(cell_id) == "abs_gap": + return float(value) + if not np.isfinite(value) or value <= 0.0: + return float("nan") + return float(np.log(value)) + + +def _weighted_midranks(values: np.ndarray, weights: np.ndarray) -> np.ndarray: + order = np.argsort(values, kind="stable") + sorted_values = values[order] + sorted_weights = weights[order] + starts = np.flatnonzero( + np.r_[True, sorted_values[1:] != sorted_values[:-1]] + ) + group_weight = np.add.reduceat(sorted_weights, starts) + below = np.cumsum(group_weight) - group_weight + group_rank = below + 0.5 * group_weight + counts = np.diff(np.r_[starts, len(sorted_values)]) + ranks = np.empty(len(values), dtype=np.float64) + ranks[order] = np.repeat(group_rank, counts) + return ranks + + +def weighted_spearman( + x: np.ndarray, y: np.ndarray, weights: np.ndarray +) -> float: + """Weighted Pearson correlation of weighted mid-ranks. + + With unit weights this is Spearman's rho with average ranks for ties. + Returns NaN when either variable is constant or fewer than three + pairs remain. + """ + x = np.asarray(x, dtype=np.float64) + y = np.asarray(y, dtype=np.float64) + weights = np.asarray(weights, dtype=np.float64) + if len(x) < 3: + return float("nan") + rank_x = _weighted_midranks(x, weights) + rank_y = _weighted_midranks(y, weights) + total = weights.sum() + dx = rank_x - (weights * rank_x).sum() / total + dy = rank_y - (weights * rank_y).sum() / total + var_x = (weights * dx * dx).sum() + var_y = (weights * dy * dy).sum() + if var_x <= 0.0 or var_y <= 0.0: + return float("nan") + return float((weights * dx * dy).sum() / np.sqrt(var_x * var_y)) + + +def window_frame( + earnings: pd.DataFrame, + persons: pd.DataFrame, + *, + wage_bases: Mapping[int, float], +) -> pd.DataFrame: + """One row per person: the four window years side by side. + + ``earnings`` is long (``person_id``, ``year``, ``earnings``), already + in EPUF units; a person-year absent from it has zero earnings. + ``persons`` has ``person_id``, ``sex`` (``"men"`` / ``"women"``), + ``birth_year`` and ``weight`` and defines who is in the frame; + persons outside the cohort bands are dropped. ``wage_bases`` maps + each window year to its wage base. + """ + lo = min(low for low, _ in COHORT_BANDS.values()) + hi = max(high for _, high in COHORT_BANDS.values()) + frame = persons.loc[ + persons["sex"].isin(SEXES) & persons["birth_year"].between(lo, hi), + ["person_id", "sex", "birth_year", "weight"], + ].copy() + if frame["person_id"].duplicated().any(): + raise ValueError("persons has duplicate person_id") + rows = earnings.loc[ + earnings["year"].isin(WINDOW_YEARS) + & earnings["person_id"].isin(frame["person_id"]) + ] + if rows.duplicated(["person_id", "year"]).any(): + raise ValueError("earnings has duplicate person-years") + wide = rows.pivot(index="person_id", columns="year", values="earnings") + frame = frame.set_index("person_id") + for year in WINDOW_YEARS: + column = ( + wide[year].reindex(frame.index) + if year in wide.columns + else pd.Series(np.nan, index=frame.index) + ) + values = column.fillna(0.0).to_numpy(dtype=np.float64) + cap = float(wage_bases[year]) + if (values < 0).any() or (values > cap).any(): + raise ValueError( + f"{year} earnings fall outside [0, {cap:,.0f}]; apply " + "epuf_measure first" + ) + frame[f"e{year}"] = values + return frame.reset_index() + + +class WindowArrays: + """A window frame as arrays, for cells on any subset of its persons.""" + + def __init__( + self, frame: pd.DataFrame, *, wage_bases: Mapping[int, float] + ) -> None: + self.person_id = frame["person_id"].to_numpy() + self.weight = frame["weight"].to_numpy(dtype=np.float64) + if (self.weight <= 0).any(): + raise ValueError("window weights must be positive") + sex = frame["sex"].to_numpy() + self.sex = np.where(sex == SEXES[0], 0, 1) + birth = frame["birth_year"].to_numpy() + self.band = np.full(len(frame), -1) + for index, (low, high) in enumerate(COHORT_BANDS.values()): + self.band[(birth >= low) & (birth <= high)] = index + if (self.band < 0).any(): + raise ValueError("a person lies outside the cohort bands") + self.earnings = np.column_stack( + [frame[f"e{year}"].to_numpy(np.float64) for year in WINDOW_YEARS] + ) + caps = np.array([float(wage_bases[y]) for y in WINDOW_YEARS]) + self.positive = self.earnings > 0.0 + self.at_max = self.earnings == caps + + def __len__(self) -> int: + return len(self.person_id) + + @staticmethod + def _share(weight, numerator, denominator) -> CellValue: + n = int(denominator.sum()) + hits = int((numerator & denominator).sum()) + total = weight[denominator].sum() + value = ( + float(weight[numerator & denominator].sum() / total) + if total > 0 + else float("nan") + ) + return CellValue(value, min(hits, n - hits), n) + + def _band_cells(self, select: np.ndarray) -> dict[str, CellValue]: + weight = self.weight + positive = self.positive + at_max = self.at_max + both = select & positive[:, 0] & positive[:, 3] + r6 = CellValue( + weighted_spearman( + self.earnings[both, 0], self.earnings[both, 3], weight[both] + ), + int(both.sum()), + int(both.sum()), + ) + interior_zero = ~positive[:, 1] | ~positive[:, 2] + zint = self._share(weight, interior_zero, both) + any_zero = ~positive[:, 0] | interior_zero + d_anyzero = self._share(weight, any_zero, select & positive[:, 3]) + years = positive.shape[1] + stacked_weight = np.tile(weight, years) + q_atmax = self._share( + stacked_weight, + at_max.T.ravel(), + (positive & select[:, None]).T.ravel(), + ) + mpers = self._share(weight, at_max[:, 0], select & at_max[:, 3]) + return { + "r6": r6, + "zint": zint, + "d_anyzero": d_anyzero, + "q_atmax": q_atmax, + "mpers": mpers, + } + + def cells(self, mask: np.ndarray | None = None) -> dict[str, CellValue]: + """Every window cell on the persons selected by ``mask``.""" + mask = np.ones(len(self), dtype=bool) if mask is None else mask + out: dict[str, CellValue] = {} + for sex_index, sex in enumerate(SEXES): + by_band: dict[str, list[CellValue]] = {s: [] for s in STATISTICS} + for band_index, band in enumerate(COHORT_BANDS): + select = ( + mask & (self.sex == sex_index) & (self.band == band_index) + ) + for stat, cell in self._band_cells(select).items(): + out[f"{stat}.{sex}.{band}"] = cell + by_band[stat].append(cell) + for stat, cells in by_band.items(): + out[f"{stat}.{sex}"] = CellValue( + float(np.mean([cell.value for cell in cells])), + int(sum(cell.events for cell in cells)), + int(sum(cell.n for cell in cells)), + ) + men = out[f"q_atmax.{SEXES[0]}"] + women = out[f"q_atmax.{SEXES[1]}"] + ratio = ( + men.value / women.value + if women.value and np.isfinite(women.value) + else float("nan") + ) + out["q_sexratio"] = CellValue( + float(ratio), min(men.events, women.events), men.n + women.n + ) + return out + + +# --- career cells (tranche R, report only) ------------------------------- + + +def mask_as_career_assembler( + earnings: np.ndarray, years: Sequence[int] +) -> np.ndarray: + """Rewrite annual histories the way the career assembler builds one. + + ``earnings`` is persons by years. Years before 1968 become zero (the + assembler's careers start at ``max(1968, birth_year + 22)``) and each + odd year from 1997 becomes the mean of its two neighbours (the + assembler's structural-gap rule, which fills the years the biennial + PSID did not collect). A filled odd year whose neighbours are both + zero stays zero. + """ + years = np.asarray(years) + out = np.asarray(earnings, dtype=np.float64).copy() + out[:, years < 1968] = 0.0 + position = {int(year): index for index, year in enumerate(years)} + for year in years[(years >= 1997) & (years % 2 == 1)]: + left = position.get(int(year) - 1) + right = position.get(int(year) + 1) + if left is None or right is None: + raise ValueError(f"{year} lacks a neighbour year to fill from") + out[:, position[int(year)]] = (out[:, left] + out[:, right]) / 2.0 + return out + + +def _quantiles(values: np.ndarray, qs=(0.25, 0.5, 0.75, 0.9)) -> dict: + return {f"p{int(q * 100)}": float(np.quantile(values, q)) for q in qs} + + +def career_cells( + earnings: np.ndarray, + years: Sequence[int], + birth_year: np.ndarray, + *, + wage_bases: Mapping[int, float], + nawi: Mapping[int, float], +) -> dict[str, object]: + """The four career statistics for one sex and cohort band. + + ``earnings`` is persons by years of capped annual earnings, unweighted + (EPUF is a simple random sample; a weighted source passes replicated + or pre-weighted rows). Every person's ages 22-61 must lie inside + ``years``. + """ + years = np.asarray(years) + earnings = np.asarray(earnings, dtype=np.float64) + birth_year = np.asarray(birth_year) + n = len(birth_year) + first_age, last_age = CAREER_AGES + span = last_age - first_age + 1 + start = birth_year + first_age - years[0] + if (start < 0).any() or (start + span > len(years)).any(): + raise ValueError("a career window falls outside the supplied years") + columns = start[:, None] + np.arange(span)[None, :] + rows = np.arange(n)[:, None] + window = earnings[rows, columns] + window_years = years[columns] + caps = np.vectorize(lambda y: float(wage_bases[int(y)]))(window_years) + positive = window > 0.0 + + zero_years = (~positive).sum(axis=1) + out: dict[str, object] = { + "n_persons": int(n), + "zero_years": { + "mean": float(zero_years.mean()), + **_quantiles(zero_years), + "share_10_or_more": float((zero_years >= 10).mean()), + "share_all_40": float((zero_years == span).mean()), + }, + } + + position = {int(year): index for index, year in enumerate(years)} + rank = {} + for first, second in _CAREER_PAIRS: + a = earnings[:, position[first]] + b = earnings[:, position[second]] + both = (a > 0) & (b > 0) + rank[f"{first}_{second}"] = { + "spearman": weighted_spearman( + a[both], b[both], np.ones(int(both.sum())) + ), + "n_pairs": int(both.sum()), + } + out["rank_persistence_10yr"] = rank + + ages = first_age + np.arange(span) + at_max = window == caps + by_age = {} + for low, high in _CAREER_AGE_BANDS: + in_band = (ages >= low) & (ages <= high) + denominator = positive[:, in_band].sum() + by_age[f"{low}-{high}"] = { + "share_at_max": ( + float(at_max[:, in_band].sum() / denominator) + if denominator + else float("nan") + ), + "n_positive_person_years": int(denominator), + } + out["at_max_by_age"] = by_age + + index_year = birth_year + 60 + index_value = np.vectorize(lambda y: float(nawi[int(y)]))(index_year) + year_value = np.vectorize(lambda y: float(nawi[int(y)]))(window_years) + factor = np.where( + window_years < index_year[:, None], + index_value[:, None] / year_value, + 1.0, + ) + indexed = window * factor + top = np.sort(indexed, axis=1)[:, -_COMPUTATION_YEARS:] + aime = np.floor(top.sum(axis=1) / (_COMPUTATION_YEARS * 12)) + out["aime_35yr_through_age_61"] = { + **_quantiles(aime), + "mean": float(aime.mean()), + "share_zero": float((aime == 0).mean()), + } + return out diff --git a/src/populace_dynamics/harness/epuf_gate.py b/src/populace_dynamics/harness/epuf_gate.py new file mode 100644 index 00000000..8de96434 --- /dev/null +++ b/src/populace_dynamics/harness/epuf_gate.py @@ -0,0 +1,373 @@ +"""The algebra of the proposed EPUF covered-earnings gate. + +Everything that turns floors into tolerances, partitions cells into +gated and report-only, and scores a run lives here, so that the floor +builder, the post-lock runner and the binding tests share one +derivation. Nothing in this module reads data. + +**The scored quantity.** A candidate generates earnings for the gate's +20 registered holdouts (seeds 0-19). For each cell the candidate's +estimate is the mean of its 20 per-seed values, put on the cell's metric +scale (log for shares, identity for rank correlations), and its distance +from EPUF is ``G = estimate - EPUF value``. + +**The bridge.** Real PSID earnings sit at their own distance from EPUF, +``B = PSID value - EPUF value``, for reasons no generator trained on the +PSID controls (who the PSID samples, what it counts as earnings, how +people report). The gate neither subtracts ``B`` (that would cancel +EPUF out of the comparison and re-run gate 1) nor ignores it (then a +faithful generator fails wherever the PSID itself differs from EPUF). +It accepts a candidate that lies between EPUF and the PSID's own +position, plus noise:: + + min(0, B) - t <= G <= max(0, B) + t + +**The noise.** A faithful generator's 20-seed mean differs from the +real PSID value by two things. One averages down across seeds (which +persons fall in each holdout, each seed's draws, each seed's fit). The +other does not: every seed scores generated values against the same +realised PSID sample, whose own deviation from its conditional law is +common to all 20. For floor replicate ``b`` the real-data analogue is:: + + e_b = [m(A_b) - m(B_b)] / 2 + + pooled(m(H_b0), ..., m(H_b19)) - pooled(m(T_b0), ..., m(T_b19)) + +where ``A_b``/``B_b`` are person-disjoint halves of the PSID support +(the common term) and ``H_bj``/``T_bj`` are a 20% holdout and its 80% +complement under the gate's own split function (the term that averages +down). ``t`` is the house tolerance on ``|e_b|``: mean plus four +standard deviations, rounded to three decimals. + +**Which cells gate.** A cell gates only if a candidate whose distance +from EPUF reaches the metric's cap would fail it with probability at +least 0.8, that is ``|B| + t + 0.8416 * sigma <= cap``. A pass therefore +always means "within the cap of EPUF". Cells whose bridge or noise is +too large for that are reported with the reason. +""" + +from __future__ import annotations + +import math +from collections.abc import Mapping, Sequence +from dataclasses import dataclass + +import numpy as np +from scipy.stats import norm + +from populace_dynamics.harness.epuf_cells import ( + COHORT_BANDS, + SEXES, + metric, + transform, +) + +__all__ = [ + "CAPS", + "EPUF_NOISE_SHARE_MAX", + "FAMILIES", + "GATE_SEEDS", + "HALF_FRACTION", + "HOLDOUT_FRACTION", + "K_TOLERANCE", + "MIN_EVENTS", + "N_FLOOR_REPLICATES", + "OC_PAUSE", + "ROUNDING", + "Z_POWER_80", + "CellFloor", + "adopt_ladder", + "demotion_reason", + "faithful_pass_probability", + "floor_replicate", + "floor_terms", + "half_split_seed", + "holdout_split_seed", + "hull", + "minimum_detectable_gap", + "pooled_estimate", + "realized_sigma", + "score_cell", + "score_run", + "tolerance", +] + +K_TOLERANCE = 4.0 +ROUNDING = 3 +#: The standard normal's 80th percentile. +Z_POWER_80 = 0.8416212335729143 +#: Power caps by metric, the house values (gates.yaml gate_m6 +#: ``metric_caps``): ln(1.5) for log ratios, 0.15 for correlation gaps. +CAPS: dict[str, float] = {"log_ratio": math.log(1.5), "abs_gap": 0.15} +MIN_EVENTS = 20 +N_FLOOR_REPLICATES = 100 +GATE_SEEDS: tuple[int, ...] = tuple(range(20)) +HOLDOUT_FRACTION = 0.2 +HALF_FRACTION = 0.5 +#: The ceremony pauses if the faithful-candidate pass probability of the +#: gated surface is below this (gates.yaml gate_m6 ``oc_before_lock``). +OC_PAUSE = 0.90 +#: A cell is demoted if EPUF's own sampling sd exceeds this share of the +#: cell's realised sigma, because the floor does not price it. +EPUF_NOISE_SHARE_MAX = 0.1 + +#: The gate's families and the order in which each tries its cells. +FAMILIES: dict[str, tuple[str, ...]] = { + "persistence": ("r6",), + "participation": ("zint", "d_anyzero"), + "tail": ("q_atmax", "mpers", "q_sexratio"), +} + + +def half_split_seed(replicate: int) -> int: + """Split seed of floor replicate ``b``'s person-disjoint halves.""" + return int(replicate) + + +def holdout_split_seed(replicate: int, draw: int) -> int: + """Split seed of floor replicate ``b``'s ``j``-th 20%/80% split. + + Offset by 1000 so that no floor split reuses a gate seed (0-19). + """ + return 1000 + len(GATE_SEEDS) * int(replicate) + int(draw) + + +def pooled_estimate(cell_id: str, values: Sequence[float]) -> float: + """The 20-seed estimate: the mean of the values, then the transform. + + Averaging before the log keeps a share cell stable when one seed has + few events; a mean of logs would not be. + """ + values = np.asarray(values, dtype=np.float64) + if not np.isfinite(values).all(): + return float("nan") + return transform(cell_id, float(values.mean())) + + +def floor_terms( + cell_id: str, + half_a: float, + half_b: float, + holdouts: Sequence[float], + complements: Sequence[float], +) -> tuple[float, float]: + """The two terms of a floor replicate (module docstring). + + The first is the noise the 20 seeds share, the second the noise that + averages down across them. + """ + common = (transform(cell_id, half_a) - transform(cell_id, half_b)) / 2.0 + averaging = pooled_estimate(cell_id, holdouts) - pooled_estimate( + cell_id, complements + ) + return float(common), float(averaging) + + +def floor_replicate( + cell_id: str, + half_a: float, + half_b: float, + holdouts: Sequence[float], + complements: Sequence[float], +) -> float: + """One real-data floor replicate ``e_b`` of a cell: the terms' sum.""" + return float( + sum(floor_terms(cell_id, half_a, half_b, holdouts, complements)) + ) + + +def tolerance(replicates: Sequence[float]) -> float: + """``round(mean|e| + 4 * sd|e|, 3)``, the house floor formula.""" + magnitude = np.abs(np.asarray(replicates, dtype=np.float64)) + return round( + float(magnitude.mean() + K_TOLERANCE * magnitude.std(ddof=1)), + ROUNDING, + ) + + +def realized_sigma(replicates: Sequence[float]) -> float: + """Root mean square of the floor replicates.""" + values = np.asarray(replicates, dtype=np.float64) + return float(np.sqrt(np.mean(values * values))) + + +def hull(bridge: float, t: float) -> tuple[float, float]: + """The acceptance interval for ``G``, rounded outward to 3 decimals.""" + scale = 10**ROUNDING + lower = math.floor((min(0.0, bridge) - t) * scale + 1e-9) / scale + upper = math.ceil((max(0.0, bridge) + t) * scale - 1e-9) / scale + return lower, upper + + +def minimum_detectable_gap(bridge: float, t: float, sigma: float) -> float: + """The distance from EPUF that fails with probability at least 0.8.""" + return abs(bridge) + t + Z_POWER_80 * sigma + + +def faithful_pass_probability( + bridge: float, sigma: float, lower: float, upper: float +) -> float: + """Pass probability of a candidate centred on the PSID's position.""" + if sigma <= 0.0: + return float(lower <= bridge <= upper) + return float( + norm.cdf((upper - bridge) / sigma) - norm.cdf((lower - bridge) / sigma) + ) + + +@dataclass(frozen=True) +class CellFloor: + """What the floor builder knows about one cell before partitioning.""" + + cell_id: str + defined: bool + min_events: int + bridge: float + t: float + sigma: float + epuf_sampling_sd: float + + +def demotion_reason(cell: CellFloor) -> str | None: + """Why a cell cannot gate, or ``None`` if it can. + + The checks run in this order, so a reason names the first failure. + """ + cap = CAPS[metric(cell.cell_id)] + if not cell.defined: + return "undefined_on_some_split" + if cell.min_events < MIN_EVENTS: + return "below_20_events" + if cell.epuf_sampling_sd > EPUF_NOISE_SHARE_MAX * cell.sigma: + return "epuf_sampling_not_negligible" + if minimum_detectable_gap(0.0, cell.t, cell.sigma) > cap: + return "noise_exceeds_cap" + if minimum_detectable_gap(cell.bridge, cell.t, cell.sigma) > cap: + return "bridge_exceeds_budget" + return None + + +def adopt_ladder( + reasons: Mapping[str, str | None], +) -> tuple[list[str], dict[str, str]]: + """Choose the gated cells from each cell's demotion reason. + + Returns the gated cell ids and a reason for every other cell. The + rules, fixed before any PSID floor existed: + + - ``r6``: gate all six sex-by-cohort cells if every one is eligible; + otherwise gate each eligible sex-level cell. + - participation: per sex, gate ``zint`` if eligible, else + ``d_anyzero`` if eligible. + - tail: gate each eligible sex-level ``q_atmax`` and ``mpers`` cell + and ``q_sexratio``. + - every other cohort-level cell is reported, never gated. + """ + gated: list[str] = [] + report: dict[str, str] = {} + + def note(cell_id: str, default: str) -> None: + report[cell_id] = reasons[cell_id] or default + + band_r6 = [f"r6.{sex}.{band}" for sex in SEXES for band in COHORT_BANDS] + if all(reasons[cell_id] is None for cell_id in band_r6): + gated.extend(band_r6) + for sex in SEXES: + note(f"r6.{sex}", "superseded_by_cohort_rung") + else: + for cell_id in band_r6: + note(cell_id, "cohort_rung_not_adopted") + for sex in SEXES: + cell_id = f"r6.{sex}" + if reasons[cell_id] is None: + gated.append(cell_id) + else: + note(cell_id, "") + + for sex in SEXES: + zint, d_any = f"zint.{sex}", f"d_anyzero.{sex}" + if reasons[zint] is None: + gated.append(zint) + note(d_any, "superseded_by_zint") + else: + note(zint, "") + if reasons[d_any] is None: + gated.append(d_any) + else: + note(d_any, "") + + tail = [f"{stat}.{sex}" for stat in ("q_atmax", "mpers") for sex in SEXES] + for cell_id in [*tail, "q_sexratio"]: + if reasons[cell_id] is None: + gated.append(cell_id) + else: + note(cell_id, "") + + for cell_id in reasons: + if cell_id not in gated and cell_id not in report: + note(cell_id, "reported_by_cohort") + return gated, report + + +def score_cell( + cell_id: str, + per_seed_values: Sequence[float], + *, + epuf_value: float, + lower: float, + upper: float, +) -> dict[str, object]: + """Score one cell of a run against its registered interval.""" + estimate = pooled_estimate(cell_id, per_seed_values) + gap = estimate - transform(cell_id, epuf_value) + passed = bool(np.isfinite(gap) and lower <= gap <= upper) + return { + "estimate": estimate, + "gap_from_epuf": gap, + "lower": lower, + "upper": upper, + "pass": passed, + } + + +def score_run( + per_seed_cells: Mapping[int, Mapping[str, float]], + gated: Mapping[str, Mapping[str, float]], +) -> dict[str, object]: + """Score a candidate's 20 per-seed cell values against the gate. + + ``per_seed_cells`` maps each gate seed to its cell values on the + natural scale. ``gated`` maps each gated cell id to its registered + ``epuf_value``, ``psid_value``, ``lower`` and ``upper``. The gate + passes iff every gated cell passes. Each cell also reports the + decomposition of its gap into the model's distance from the PSID and + the PSID's distance from EPUF. + """ + if set(per_seed_cells) != set(GATE_SEEDS): + raise ValueError( + f"a run scores exactly seeds {GATE_SEEDS[0]}-{GATE_SEEDS[-1]}; " + f"got {sorted(per_seed_cells)}" + ) + cells = {} + for cell_id, registered in gated.items(): + values = [per_seed_cells[seed][cell_id] for seed in GATE_SEEDS] + result = score_cell( + cell_id, + values, + epuf_value=registered["epuf_value"], + lower=registered["lower"], + upper=registered["upper"], + ) + source = transform(cell_id, registered["psid_value"]) - transform( + cell_id, registered["epuf_value"] + ) + result["source_term_psid_minus_epuf"] = source + result["model_term_candidate_minus_psid"] = ( + result["gap_from_epuf"] - source + ) + cells[cell_id] = result + return { + "cells": cells, + "n_gated": len(cells), + "n_pass": sum(bool(cell["pass"]) for cell in cells.values()), + "pass": bool(cells) and all(cell["pass"] for cell in cells.values()), + } diff --git a/src/populace_dynamics/harness/epuf_operator.py b/src/populace_dynamics/harness/epuf_operator.py new file mode 100644 index 00000000..e37a9350 --- /dev/null +++ b/src/populace_dynamics/harness/epuf_operator.py @@ -0,0 +1,136 @@ +"""EPUF's measurement operator, for survey-side and model-side earnings. + +SSA released EPUF's annual earnings after capping them at the year's +contribution and benefit base and applying a disclosure operator +(:mod:`populace_dynamics.data.epuf`). To score any other earnings +history against EPUF in the same units, :func:`epuf_measure` applies the +same steps to it: + +1. negative values become zero and values above the wage base become the + wage base; +2. a positive value below $100 becomes that year's EPUF bottom code; +3. a value strictly inside the band one rounding base below the wage + base becomes that year's EPUF band mean; +4. every other value is rounded to SSA's base for its level ($25 from + $100, $100 from $1,000, $1,000 from $50,000). + +Steps 2-4 cannot change whether a person-year is positive or whether it +sits exactly at the wage base, so participation and at-maximum +statistics depend only on step 1; the rest affects only how values tie +in rank statistics. The per-year constants are EPUF's own, read off the +pinned bytes into ``data/external/epuf_2006/disclosure_constants.json``. + +One step is not SSA's. SSA rounded at random to one of the two +neighbouring multiples and did not publish the direction probabilities; +this operator rounds half up, deterministically, so that a scored value +never depends on a rounding seed. EPUF itself is used as published and +is never passed through this function: SSA's random rounding left a few +grid values inside the band (68,000 in 1998, for one) that step 3 would +move. +""" + +from __future__ import annotations + +import hashlib +import json +from functools import lru_cache +from pathlib import Path + +import numpy as np + +__all__ = [ + "CONSTANTS_PATH", + "CONSTANTS_SHA256", + "disclosure_constants", + "epuf_measure", + "rounding_base", + "wage_base", +] + +_ROOT = Path(__file__).resolve().parents[3] +CONSTANTS_PATH = ( + _ROOT / "data" / "external" / "epuf_2006" / "disclosure_constants.json" +) +#: SHA-256 of the committed constants; other bytes are refused. +CONSTANTS_SHA256 = ( + "ba1f39f238278243de19b8a9d194abedffeabd855f5b97779b685d852f62a881" +) + +_BOTTOM_CODE_BELOW = 100.0 +_BASE_25_BELOW = 1_000.0 +_BASE_100_BELOW = 50_000.0 + + +@lru_cache(maxsize=1) +def disclosure_constants() -> dict[int, dict[str, int]]: + """Per-year wage base, band base, bottom code and band mean.""" + raw = CONSTANTS_PATH.read_bytes() + observed = hashlib.sha256(raw).hexdigest() + if observed != CONSTANTS_SHA256: + raise ValueError( + f"{CONSTANTS_PATH} has SHA-256 {observed}, not the pinned " + f"{CONSTANTS_SHA256}; regenerate it with " + "scripts/extract_epuf_disclosure_constants.py and re-pin" + ) + years = json.loads(raw)["years"] + return { + int(year): { + key: int(row[key]) + for key in ("wage_base", "band_base", "bottom_code", "band_mean") + } + for year, row in years.items() + } + + +def wage_base(year: int) -> int: + """The contribution and benefit base of an EPUF year (1951-2006).""" + constants = disclosure_constants() + if int(year) not in constants: + raise ValueError( + f"EPUF covers 1951-2006; no disclosure constants for {year}" + ) + return constants[int(year)]["wage_base"] + + +def rounding_base(values: np.ndarray) -> np.ndarray: + """SSA's rounding base at each earnings level.""" + values = np.asarray(values, dtype=np.float64) + return np.where( + values < _BASE_25_BELOW, + 25.0, + np.where(values < _BASE_100_BELOW, 100.0, 1_000.0), + ) + + +def epuf_measure(earnings: np.ndarray, year: int) -> np.ndarray: + """Express one year's earnings in EPUF's capped, disclosed units. + + ``earnings`` are nominal dollars of ``year``. Missing values are + refused: a history with gaps has to be resolved to zeros or dropped + by the caller, because EPUF codes a year without earnings as zero. + """ + values = np.asarray(earnings, dtype=np.float64) + if np.isnan(values).any(): + raise ValueError("epuf_measure refuses missing earnings") + row = disclosure_constants().get(int(year)) + if row is None: + raise ValueError( + f"EPUF covers 1951-2006; no disclosure constants for {year}" + ) + cap = float(row["wage_base"]) + capped = np.clip(values, 0.0, cap) + base = rounding_base(capped) + # Round half up (np.round rounds half to even). + rounded = np.floor(capped / base + 0.5) * base + out = np.where(capped > 0.0, rounded, 0.0) + out = np.where( + (capped > 0.0) & (capped < _BOTTOM_CODE_BELOW), + float(row["bottom_code"]), + out, + ) + out = np.where( + (capped > cap - float(row["band_base"])) & (capped < cap), + float(row["band_mean"]), + out, + ) + return np.where(capped >= cap, cap, out) diff --git a/src/populace_dynamics/harness/epuf_run.py b/src/populace_dynamics/harness/epuf_run.py new file mode 100644 index 00000000..8a7a19f6 --- /dev/null +++ b/src/populace_dynamics/harness/epuf_run.py @@ -0,0 +1,115 @@ +"""From a candidate's generated panels to the EPUF gate's verdict. + +The post-lock run generates a candidate panel for each of the gate's 20 +registered holdouts and hands them here. This module is the whole path +from those panels to a verdict, fixed and tested before lock, so the +run script adds only the generator call and the reproduction check. + +A candidate panel is gate 1's candidate-panel shape: the holdout's +persons on their observed periods, with generated ``earnings`` +(``person_id``, ``period``, ``earnings``; other columns are ignored). +The gate's support is fixed by the real panel alone (who is present in +every window year, whose last period is 2006 or later, sex, birth +year, the 2004 weight), so it is read from the support frame the floor +builder computed, never from the candidate. +""" + +from __future__ import annotations + +from collections.abc import Mapping + +import numpy as np +import pandas as pd + +from populace_dynamics.harness import epuf_gate as gate +from populace_dynamics.harness.epuf_cells import ( + WINDOW_YEARS, + WindowArrays, + window_frame, +) +from populace_dynamics.harness.epuf_operator import ( + disclosure_constants, + epuf_measure, +) + +__all__ = ["candidate_window_cells", "score_candidate"] + + +def _wage_bases() -> dict[int, float]: + return { + year: float(row["wage_base"]) + for year, row in disclosure_constants().items() + } + + +def candidate_window_cells( + candidate: pd.DataFrame, support: pd.DataFrame +) -> dict[str, float]: + """One seed's window cells from its generated candidate panel. + + ``support`` is the gate's support frame (``person_id``, ``sex``, + ``birth_year``, ``weight``). The seed's scored persons are the + support persons the candidate panel holds; each must have a + generated row at every window year, because a support person is + present at all four and none of the four is their anchor. + """ + held = support[support["person_id"].isin(candidate["person_id"])] + if held.empty: + raise ValueError("the candidate panel holds no support person") + rows = candidate[ + candidate["period"].isin(WINDOW_YEARS) + & candidate["person_id"].isin(held["person_id"]) + ] + if rows.duplicated(["person_id", "period"]).any(): + raise ValueError("candidate panel has duplicate person-periods") + per_person = rows.groupby("person_id")["period"].nunique() + complete = per_person.reindex(held["person_id"], fill_value=0) + if (complete != len(WINDOW_YEARS)).any(): + raise ValueError( + "a support person lacks a generated row in a window year; the " + "candidate panel is not the holdout's observed periods" + ) + earnings = rows["earnings"].to_numpy(dtype=np.float64) + periods = rows["period"].to_numpy() + measured = np.empty(len(rows), dtype=np.float64) + for year in WINDOW_YEARS: + select = periods == year + measured[select] = epuf_measure(earnings[select], year) + long = pd.DataFrame( + { + "person_id": rows["person_id"].to_numpy(), + "year": periods, + "earnings": measured, + } + ) + wage_bases = _wage_bases() + frame = window_frame( + long, + held[["person_id", "sex", "birth_year", "weight"]], + wage_bases=wage_bases, + ) + cells = WindowArrays(frame, wage_bases=wage_bases).cells() + return {cell_id: cell.value for cell_id, cell in cells.items()} + + +def score_candidate( + candidates: Mapping[int, pd.DataFrame], + support: pd.DataFrame, + registered: Mapping[str, Mapping[str, float]], +) -> dict[str, object]: + """Score the 20 generated panels against the registered intervals. + + ``candidates`` maps each gate seed to its candidate panel and + ``registered`` is the floor artifact's ``registered`` block. Returns + :func:`populace_dynamics.harness.epuf_gate.score_run`'s result with + every cell's 20 per-seed values attached (gated or not). + """ + per_seed = { + int(seed): candidate_window_cells(panel, support) + for seed, panel in candidates.items() + } + scored = gate.score_run(per_seed, registered) + scored["per_seed_values"] = { + str(seed): values for seed, values in sorted(per_seed.items()) + } + return scored diff --git a/tests/README-tiers.md b/tests/README-tiers.md index c17af96a..28e081fd 100644 --- a/tests/README-tiers.md +++ b/tests/README-tiers.md @@ -39,9 +39,9 @@ pytest --collect-only -q -m oracle_policyengine | tail -1 | Tier | Tests at HEAD | |---|---:| -| `unit` | 5,678 | -| `artifact` | 3,331 | +| `unit` | 5,796 | +| `artifact` | 3,344 | | `integration_psid` | 1,341 | | `reproduction_legacy` | 520 | | `oracle_policyengine` | 215 | -| **Total** | **11,085** | +| **Total** | **11,216** | diff --git a/tests/data/test_epuf.py b/tests/data/test_epuf.py new file mode 100644 index 00000000..95220bb2 --- /dev/null +++ b/tests/data/test_epuf.py @@ -0,0 +1,253 @@ +"""The byte-pinned EPUF reader and its reproduction of SSA's tables. + +The refusal tests run anywhere. The reproduction tests need the staged +EPUF members (``~/PolicyEngine/epuf-data/csv`` or +``POPULACE_DYNAMICS_EPUF_DIR``) and skip unless the staged bytes are the +pinned ones. Their targets are SSA's own published numbers, extracted +by ``scripts/extract_epuf_published_tables.py`` into +``data/external/epuf_2006/published_tables.json``. +""" + +from __future__ import annotations + +import hashlib +import json +from decimal import ROUND_HALF_UP, Decimal +from pathlib import Path + +import pandas as pd +import pytest + +from populace_dynamics.cola_track_a.statutory import load_statutory_capture +from populace_dynamics.data import epuf + +ROOT = Path(__file__).resolve().parents[2] +PUBLISHED = ROOT / "data" / "external" / "epuf_2006" / "published_tables.json" + +_STATUS = epuf.epuf_status() +needs_pinned_epuf = pytest.mark.skipif( + not _STATUS["pinned"], + reason="EPUF members not staged, or not the pinned bytes", +) + + +def _round_half_up(value: float, places: str) -> float: + return float( + Decimal(repr(float(value))).quantize( + Decimal(places), rounding=ROUND_HALF_UP + ) + ) + + +def _published() -> dict: + return json.loads(PUBLISHED.read_text(encoding="utf-8"))["tables"] + + +def _wage_base() -> dict[int, float]: + points = { + int(year): float(value) + for year, value in load_statutory_capture()[ + "wage_base_change_points" + ].items() + } + out = {} + for year in range(epuf.EPUF_FIRST_YEAR, epuf.EPUF_LAST_YEAR + 1): + out[year] = points[max(y for y in points if y <= year)] + return out + + +# --- refusals (no data needed) ------------------------------------------- + + +def test_missing_folder_is_refused(tmp_path): + with pytest.raises(epuf.EPUFNotStagedError, match="No EPUF2006"): + epuf.read_demographic(data_dir=tmp_path) + status = epuf.epuf_status(data_dir=tmp_path) + assert status["staged"] is False + assert status["pinned"] is False + + +def test_unpinned_bytes_are_refused_before_reading(tmp_path): + (tmp_path / epuf.DEMOGRAPHIC_FILE).write_text( + '"ID","YOB","SEX","TOT_COV_EARN3750","QC3750","QC5152"\n' + '"1","1973","1","0","0","0"\n' + ) + (tmp_path / epuf.ANNUAL_FILE).write_text( + '"ID","YEAR_EARN","ANNUAL_EARNINGS","ANNUAL_QTRS"\n' + '"1","1998","7500","4"\n' + ) + with pytest.raises(epuf.EPUFNotStagedError, match="not the pinned"): + epuf.read_annual(data_dir=tmp_path) + status = epuf.epuf_status(data_dir=tmp_path) + assert status["staged"] is True + assert status["pinned"] is False + + +def test_unverified_read_of_other_bytes_checks_row_counts(tmp_path): + (tmp_path / epuf.DEMOGRAPHIC_FILE).write_text( + '"ID","YOB","SEX","TOT_COV_EARN3750","QC3750","QC5152"\n' + '"1","1973","1","0","0","0"\n' + ) + with pytest.raises(ValueError, match="persons; the pinned file has"): + epuf.read_demographic(data_dir=tmp_path, verify=False) + + +def test_env_var_names_the_folder(tmp_path, monkeypatch): + monkeypatch.setenv("POPULACE_DYNAMICS_EPUF_DIR", str(tmp_path)) + assert epuf.epuf_status()["directory"] == str(tmp_path) + + +def test_published_tables_record_their_sources(): + payload = json.loads(PUBLISHED.read_text(encoding="utf-8")) + for source in payload["sources"].values(): + text = ROOT / source["text"] + assert hashlib.sha256(text.read_bytes()).hexdigest() == ( + source["text_sha256"] + ) + tables = payload["tables"] + assert set(tables) == { + "ssb_table_a1_records", + "ssb_table_4_mean_median", + "ssb_chart_3_birth_year", + "ssb_chart_4_birth_year_sex", + "rsn_table_8_pct_below_max", + } + assert len(tables["ssb_table_a1_records"]["rows"]) == 56 + assert len(tables["rsn_table_8_pct_below_max"]["rows"]) == 56 + assert len(tables["ssb_chart_3_birth_year"]["rows"]) == 137 + + +# --- reproduction against SSA's published tables ------------------------- + + +@pytest.fixture(scope="module") +def frames(): + demographic = epuf.read_demographic() + annual = epuf.read_annual().merge( + demographic[["person_id", "birth_year", "sex"]], + on="person_id", + how="left", + validate="many_to_one", + ) + return demographic, annual + + +@needs_pinned_epuf +def test_counts_match_the_pinned_file(frames): + demographic, annual = frames + assert len(demographic) == epuf.EPUF_PERSONS == 4_384_254 + assert annual["person_id"].nunique() == epuf.EPUF_EARNER_PERSONS + assert len(annual) == epuf.EPUF_ANNUAL_ROWS + assert annual["birth_year"].notna().all() + assert not annual.duplicated(["person_id", "year"]).any() + assert (annual["earnings"] > 0).all() + assert annual.loc[annual["year"] <= 1952, "quarters"].isna().all() + assert annual.loc[annual["year"] > 1952, "quarters"].notna().all() + + +@needs_pinned_epuf +def test_rows_exist_only_at_ages_15_to_85(frames): + _, annual = frames + age = annual["year"] - annual["birth_year"] + assert int(age.min()) == 15 + assert int(age.max()) == 85 + + +@needs_pinned_epuf +def test_every_year_tops_out_exactly_at_the_wage_base(frames): + _, annual = frames + cap = annual["year"].map(_wage_base()) + assert (annual["earnings"] <= cap).all() + top = annual.groupby("year")["earnings"].max() + assert top.to_dict() == { + year: int(value) for year, value in _wage_base().items() + } + + +@needs_pinned_epuf +def test_ssb_table_a1_records_by_sex(frames): + _, annual = frames + counts = annual.groupby(["year", "sex"]).size().unstack(fill_value=0) + rows = _published()["ssb_table_a1_records"]["rows"] + for year, row in rows.items(): + got = counts.loc[int(year)] + assert { + "all": int(got.sum()), + "men": int(got[1]), + "women": int(got[2]), + "unknown": int(got[3]), + } == row, year + + +@needs_pinned_epuf +def test_ssb_table_4_means_and_medians(frames): + _, annual = frames + rows = _published()["ssb_table_4_mean_median"]["rows"] + groups = {"all": None, "men": 1, "women": 2, "unknown": 3} + for year, row in rows.items(): + in_year = annual[annual["year"] == int(year)] + for label, sex in groups.items(): + values = ( + in_year["earnings"] + if sex is None + else in_year.loc[in_year["sex"] == sex, "earnings"] + ) + mean = _round_half_up(values.mean(), "1") + median = float(values.median()) + assert median == row[f"median_{label}"], (year, label) + # The sex-unknown group (300-500 records a year) misses SSA's + # rounded mean by one dollar in 1963 and 1992. + slack = 1 if label == "unknown" else 0 + assert abs(mean - row[f"mean_{label}"]) <= slack, (year, label) + + +@needs_pinned_epuf +def test_ssb_charts_3_and_4_birth_year_counts(frames): + demographic, _ = frames + tables = _published() + by_year = demographic.groupby("birth_year").size() + by_sex = ( + demographic.groupby(["birth_year", "sex"]).size().unstack(fill_value=0) + ) + for year, row in tables["ssb_chart_3_birth_year"]["rows"].items(): + got = _round_half_up(by_year.get(int(year), 0) / 1000, "0.01") + assert got == row["thousands"], year + for year, row in tables["ssb_chart_4_birth_year_sex"]["rows"].items(): + got = ( + _round_half_up(by_sex.loc[int(year), 1] / 1000, "0.01"), + _round_half_up(by_sex.loc[int(year), 2] / 1000, "0.01"), + ) + assert got == (row["men_thousands"], row["women_thousands"]), year + + +@needs_pinned_epuf +def test_rsn_table_8_share_below_the_maximum(frames): + _, annual = frames + below = annual["earnings"] < annual["year"].map(_wage_base()) + frame = pd.DataFrame( + {"year": annual["year"], "sex": annual["sex"], "below": below} + ) + rows = _published()["rsn_table_8_pct_below_max"]["rows"] + for year, row in rows.items(): + in_year = frame[frame["year"] == int(year)] + got = { + "epuf_all": _round_half_up(100 * in_year["below"].mean(), "0.1"), + "epuf_men": _round_half_up( + 100 * in_year.loc[in_year["sex"] == 1, "below"].mean(), "0.1" + ), + "epuf_women": _round_half_up( + 100 * in_year.loc[in_year["sex"] == 2, "below"].mean(), "0.1" + ), + } + assert got == {key: row[key] for key in got}, year + + +@needs_pinned_epuf +def test_year_filter_keeps_only_those_years(): + annual = epuf.read_annual(years=[2004]) + assert set(annual["year"].unique()) == {2004} + assert len(annual) == int( + _published()["ssb_table_a1_records"]["rows"]["2004"]["all"] + ) + with pytest.raises(ValueError, match="cover 1951-2006"): + epuf.read_annual(years=[2007]) diff --git a/tests/harness/test_epuf_cells.py b/tests/harness/test_epuf_cells.py new file mode 100644 index 00000000..4eb37094 --- /dev/null +++ b/tests/harness/test_epuf_cells.py @@ -0,0 +1,342 @@ +"""Window and career cell statistics: worked cases and invariants.""" + +from __future__ import annotations + +import numpy as np +import pandas as pd +import pytest +from hypothesis import given, settings +from hypothesis import strategies as st +from scipy.stats import spearmanr + +from populace_dynamics.cola_track_a.statutory import captured_ssa_parameters +from populace_dynamics.harness import epuf_cells as ec +from populace_dynamics.harness.epuf_operator import disclosure_constants +from populace_dynamics.ss import statutory_aime + +WAGE_BASES = { + year: float(row["wage_base"]) + for year, row in disclosure_constants().items() +} +CAP = {year: WAGE_BASES[year] for year in ec.WINDOW_YEARS} + + +def _frame(rows): + """rows: (sex, birth_year, weight, e1998, e2000, e2002, e2004).""" + frame = pd.DataFrame( + rows, + columns=["sex", "birth_year", "weight", *_columns()], + ) + frame.insert(0, "person_id", np.arange(len(frame)) + 1) + return frame + + +def _columns(): + return [f"e{year}" for year in ec.WINDOW_YEARS] + + +def _random_frame(rng, n=600): + sex = rng.choice(ec.SEXES, size=n) + birth = rng.integers(1947, 1974, size=n) + weight = rng.uniform(0.5, 3.0, size=n) + earnings = {} + for year in ec.WINDOW_YEARS: + draw = rng.lognormal(10.3, 0.9, size=n) + draw[rng.random(n) < 0.12] = 0.0 + earnings[f"e{year}"] = np.minimum(np.round(draw, -2), CAP[year]) + return pd.DataFrame( + { + "person_id": np.arange(n) + 1, + "sex": sex, + "birth_year": birth, + "weight": weight, + **earnings, + } + ) + + +def _cells(frame, mask=None): + return ec.WindowArrays(frame, wage_bases=WAGE_BASES).cells(mask) + + +# --- weighted Spearman ---------------------------------------------------- + + +@settings(max_examples=150, deadline=None) +@given( + data=st.lists( + st.tuples(st.integers(0, 12), st.integers(0, 12), st.integers(1, 4)), + min_size=4, + max_size=40, + ) +) +def test_unit_weight_spearman_matches_scipy(data): + x = np.array([row[0] for row in data], dtype=float) + y = np.array([row[1] for row in data], dtype=float) + ours = ec.weighted_spearman(x, y, np.ones(len(x))) + theirs = spearmanr(x, y).statistic + if np.isnan(theirs): + assert np.isnan(ours) + else: + assert ours == pytest.approx(theirs, abs=1e-12) + + +@settings(max_examples=150, deadline=None) +@given( + data=st.lists( + st.tuples(st.integers(0, 12), st.integers(0, 12), st.integers(1, 4)), + min_size=4, + max_size=30, + ) +) +def test_integer_weights_equal_repeated_rows(data): + x = np.array([row[0] for row in data], dtype=float) + y = np.array([row[1] for row in data], dtype=float) + w = np.array([row[2] for row in data]) + weighted = ec.weighted_spearman(x, y, w.astype(float)) + repeated = ec.weighted_spearman( + np.repeat(x, w), np.repeat(y, w), np.ones(int(w.sum())) + ) + if np.isnan(repeated): + assert np.isnan(weighted) + else: + assert weighted == pytest.approx(repeated, abs=1e-12) + + +@settings(max_examples=100, deadline=None) +@given(seed=st.integers(0, 10_000)) +def test_spearman_is_bounded_and_invariant_to_increasing_transforms(seed): + rng = np.random.default_rng(seed) + x, y = rng.normal(size=50), rng.normal(size=50) + w = rng.uniform(0.5, 2, size=50) + rho = ec.weighted_spearman(x, y, w) + assert -1 <= rho <= 1 + assert ec.weighted_spearman(np.exp(x), 3 * y + 7, w) == pytest.approx( + rho, abs=1e-12 + ) + assert ec.weighted_spearman(x, y, 5 * w) == pytest.approx(rho, abs=1e-12) + + +def test_spearman_is_nan_without_variation_or_pairs(): + ones = np.ones(5) + assert np.isnan(ec.weighted_spearman(ones, np.arange(5.0), ones)) + assert np.isnan(ec.weighted_spearman(ones[:2], ones[:2], ones[:2])) + + +# --- window cells --------------------------------------------------------- + + +def test_worked_window_cells_for_one_band(): + cap98, cap04 = CAP[1998], CAP[2004] + frame = _frame( + [ + # positive throughout, at the maximum in 1998 and 2004 + ("men", 1950, 1.0, cap98, 50_000, 50_000, cap04), + # an interior zero + ("men", 1950, 2.0, 30_000, 0, 20_000, 40_000), + # zero in 1998, positive in 2004 + ("men", 1950, 1.0, 0, 10_000, 10_000, 20_000), + # at the maximum in 2004 only + ("men", 1950, 1.0, 40_000, 40_000, 40_000, cap04), + # no earnings in 2004 + ("men", 1950, 5.0, 10_000, 10_000, 10_000, 0), + ] + ) + cells = _cells(frame) + # positive in 1998 and 2004: persons 1, 2, 4 (weights 1, 2, 1) + assert cells["zint.men.c0"].value == pytest.approx(2 / 4) + assert cells["zint.men.c0"].n == 3 + assert cells["zint.men.c0"].events == 1 + # positive in 2004: persons 1-4 (weights 1, 2, 1, 1); any earlier zero: 2, 3 + assert cells["d_anyzero.men.c0"].value == pytest.approx(3 / 5) + # positive person-years: 4 + 3 + 3 + 4 + 3 = 17; at max: 2 + 1 = 3 + assert cells["q_atmax.men.c0"].n == 17 + # weights: at max 1 + 1 + 1 = 3 over 4*1 + 3*2 + 3*1 + 4*1 + 3*5 = 32 + assert cells["q_atmax.men.c0"].value == pytest.approx(3 / 32) + # at max in 2004: persons 1 and 4; also at max in 1998: person 1 + assert cells["mpers.men.c0"].value == pytest.approx(1 / 2) + assert cells["r6.men.c0"].n == 3 + + +def test_sex_level_cell_is_the_mean_of_its_three_bands(): + frame = _random_frame(np.random.default_rng(1)) + cells = _cells(frame) + for stat in ec.STATISTICS: + for sex in ec.SEXES: + bands = [cells[f"{stat}.{sex}.{band}"] for band in ec.COHORT_BANDS] + assert cells[f"{stat}.{sex}"].value == pytest.approx( + np.mean([cell.value for cell in bands]) + ) + assert cells[f"{stat}.{sex}"].events == sum( + cell.events for cell in bands + ) + assert cells["q_sexratio"].value == pytest.approx( + cells["q_atmax.men"].value / cells["q_atmax.women"].value + ) + + +def test_cell_ids_match_what_is_computed(): + cells = _cells(_random_frame(np.random.default_rng(2))) + assert sorted(cells) == sorted(ec.cell_ids()) + assert len(ec.cell_ids()) == 5 * 2 * 3 + 5 * 2 + 1 + assert {ec.metric(cell_id) for cell_id in cells} == { + "abs_gap", + "log_ratio", + } + + +@settings(max_examples=40, deadline=None) +@given(seed=st.integers(0, 10_000), scale=st.floats(0.1, 50)) +def test_cells_ignore_weight_scale_and_row_order(seed, scale): + rng = np.random.default_rng(seed) + frame = _random_frame(rng, n=300) + base = _cells(frame) + scaled = frame.assign(weight=frame["weight"] * scale) + shuffled = frame.sample(frac=1.0, random_state=seed).reset_index(drop=True) + for other in (_cells(scaled), _cells(shuffled)): + for cell_id, cell in base.items(): + if np.isnan(cell.value): + assert np.isnan(other[cell_id].value) + else: + assert other[cell_id].value == pytest.approx( + cell.value, rel=1e-9, abs=1e-12 + ) + assert other[cell_id].events == cell.events + + +@settings(max_examples=40, deadline=None) +@given(seed=st.integers(0, 10_000)) +def test_shares_and_correlations_stay_in_range(seed): + cells = _cells(_random_frame(np.random.default_rng(seed), n=300)) + for cell_id, cell in cells.items(): + if np.isnan(cell.value) or cell_id == "q_sexratio": + continue + low = -1.0 if cell_id.startswith("r6") else 0.0 + assert low <= cell.value <= 1.0 + assert 0 <= cell.events <= cell.n + + +def test_mask_selects_persons(): + frame = _random_frame(np.random.default_rng(3)) + mask = np.arange(len(frame)) % 2 == 0 + masked = _cells(frame, mask) + subset = _cells(frame[mask].reset_index(drop=True)) + for cell_id, cell in subset.items(): + assert masked[cell_id].events == cell.events + if not np.isnan(cell.value): + assert masked[cell_id].value == pytest.approx(cell.value) + + +def test_window_frame_fills_absent_years_with_zero_and_checks_units(): + persons = pd.DataFrame( + { + "person_id": [1, 2, 3, 4], + "sex": ["men", "women", "men", None], + "birth_year": [1950, 1960, 1930, 1950], + "weight": [1.0, 1.0, 1.0, 1.0], + } + ) + earnings = pd.DataFrame( + { + "person_id": [1, 1, 2, 3], + "year": [1998, 2004, 2000, 1998], + "earnings": [100.0, 200.0, 300.0, 400.0], + } + ) + frame = ec.window_frame(earnings, persons, wage_bases=WAGE_BASES) + assert frame["person_id"].tolist() == [1, 2] # 3 out of band, 4 uncoded + assert frame.loc[0, _columns()].tolist() == [100.0, 0.0, 0.0, 200.0] + assert frame.loc[1, _columns()].tolist() == [0.0, 300.0, 0.0, 0.0] + over = earnings.assign(earnings=1e6) + with pytest.raises(ValueError, match="epuf_measure"): + ec.window_frame(over, persons, wage_bases=WAGE_BASES) + + +def test_transform_is_log_for_shares_and_identity_for_correlations(): + assert ec.transform("r6.men", 0.7) == 0.7 + assert ec.transform("zint.men", 0.05) == pytest.approx(np.log(0.05)) + assert np.isnan(ec.transform("zint.men", 0.0)) + assert np.isnan(ec.transform("q_sexratio", float("nan"))) + + +# --- career cells --------------------------------------------------------- + +YEARS = np.arange(1951, 2007) + + +def test_mask_zeroes_before_1968_and_fills_odd_years_from_1997(): + history = np.arange(1.0, len(YEARS) + 1)[None, :] * 100 + masked = ec.mask_as_career_assembler(history, YEARS) + assert (masked[0, YEARS < 1968] == 0).all() + untouched = (YEARS >= 1968) & ~((YEARS >= 1997) & (YEARS % 2 == 1)) + assert (masked[0, untouched] == history[0, untouched]).all() + for year in (1997, 1999, 2001, 2003, 2005): + index = year - 1951 + assert ( + masked[0, index] + == (history[0, index - 1] + history[0, index + 1]) / 2 + ) + + +def test_career_zero_years_and_at_max_shares(): + birth = np.array([1940, 1940]) + histories = np.zeros((2, len(YEARS))) + # person 0: at the wage base every year of ages 22-61 (1962-2001) + for year in range(1962, 2002): + histories[0, year - 1951] = WAGE_BASES[year] + # person 1: earnings only at ages 30-39 + histories[1, 1970 - 1951 : 1980 - 1951] = 1_000.0 + cells = ec.career_cells( + histories, + YEARS, + birth, + wage_bases=WAGE_BASES, + nawi=captured_ssa_parameters().nawi, + ) + assert cells["zero_years"]["mean"] == pytest.approx((0 + 30) / 2) + assert cells["zero_years"]["share_10_or_more"] == 0.5 + assert cells["zero_years"]["share_all_40"] == 0.0 + assert cells["at_max_by_age"]["35-44"]["share_at_max"] == pytest.approx( + 10 / 15 + ) + assert cells["at_max_by_age"]["45-54"]["share_at_max"] == 1.0 + + +@settings(max_examples=60, deadline=None) +@given(seed=st.integers(0, 10_000), birth=st.integers(1930, 1944)) +def test_career_aime_matches_the_statutory_oracle(seed, birth): + rng = np.random.default_rng(seed) + history = np.where( + rng.random(len(YEARS)) < 0.25, + 0.0, + np.minimum( + rng.lognormal(9.0, 1.0, size=len(YEARS)), + [WAGE_BASES[year] for year in YEARS], + ), + ) + params = captured_ssa_parameters() + cells = ec.career_cells( + history[None, :], + YEARS, + np.array([birth]), + wage_bases=WAGE_BASES, + nawi=params.nawi, + ) + through_61 = { + int(year): float(value) + for year, value in zip(YEARS, history, strict=True) + if birth + 22 <= year <= birth + 61 + } + expected = statutory_aime.aime(through_61, birth, params) + assert cells["aime_35yr_through_age_61"]["p50"] == expected + + +def test_career_window_outside_the_years_is_refused(): + with pytest.raises(ValueError, match="outside the supplied years"): + ec.career_cells( + np.zeros((1, len(YEARS))), + YEARS, + np.array([1920]), + wage_bases=WAGE_BASES, + nawi=captured_ssa_parameters().nawi, + ) diff --git a/tests/harness/test_epuf_gate.py b/tests/harness/test_epuf_gate.py new file mode 100644 index 00000000..01d95073 --- /dev/null +++ b/tests/harness/test_epuf_gate.py @@ -0,0 +1,340 @@ +"""The EPUF gate's algebra: tolerances, intervals, partition and scoring.""" + +from __future__ import annotations + +import math + +import numpy as np +import pytest +from hypothesis import given, settings +from hypothesis import strategies as st + +from populace_dynamics.harness import epuf_gate as gate +from populace_dynamics.harness.epuf_cells import cell_ids, transform + +bridges = st.floats(-0.5, 0.5, allow_nan=False) +sigmas = st.floats(1e-4, 0.2, allow_nan=False) + + +def _floor(cell_id="r6.men", **overrides): + values = dict( + cell_id=cell_id, + defined=True, + min_events=100, + bridge=0.0, + t=0.03, + sigma=0.01, + epuf_sampling_sd=0.0005, + ) + values.update(overrides) + return gate.CellFloor(**values) + + +def test_constants_are_the_house_values(): + assert gate.K_TOLERANCE == 4.0 + assert gate.CAPS == {"log_ratio": math.log(1.5), "abs_gap": 0.15} + assert gate.MIN_EVENTS == 20 + assert gate.GATE_SEEDS == tuple(range(20)) + assert gate.N_FLOOR_REPLICATES == 100 + assert gate.OC_PAUSE == 0.90 + + +def test_floor_split_seeds_never_reuse_a_gate_seed(): + seeds = { + gate.holdout_split_seed(b, j) + for b in range(gate.N_FLOOR_REPLICATES) + for j in range(len(gate.GATE_SEEDS)) + } + assert len(seeds) == gate.N_FLOOR_REPLICATES * len(gate.GATE_SEEDS) + assert min(seeds) == 1000 + assert not seeds & set(gate.GATE_SEEDS) + + +def test_tolerance_is_mean_plus_four_sd_of_the_magnitudes(): + replicates = [0.01, -0.02, 0.03, -0.005, 0.0] + magnitude = np.abs(replicates) + assert gate.tolerance(replicates) == round( + magnitude.mean() + 4 * magnitude.std(ddof=1), 3 + ) + assert gate.realized_sigma(replicates) == pytest.approx( + math.sqrt(np.mean(np.square(replicates))) + ) + + +def test_pooled_estimate_averages_before_the_log(): + values = [0.02, 0.08] + assert gate.pooled_estimate("zint.men", values) == pytest.approx( + math.log(0.05) + ) + assert gate.pooled_estimate("r6.men", [0.6, 0.8]) == pytest.approx(0.7) + assert math.isnan(gate.pooled_estimate("r6.men", [0.6, float("nan")])) + + +def test_floor_replicate_combines_the_common_and_averaging_terms(): + value = gate.floor_replicate( + "zint.men", 0.06, 0.04, [0.05, 0.07], [0.05, 0.05] + ) + expected = (math.log(0.06) - math.log(0.04)) / 2 + ( + math.log(0.06) - math.log(0.05) + ) + assert value == pytest.approx(expected) + assert gate.floor_replicate( + "r6.men", 0.7, 0.7, [0.7] * 3, [0.7] * 3 + ) == pytest.approx(0.0) + + +@settings(max_examples=300, deadline=None) +@given(bridge=bridges, t=st.floats(0.001, 0.2)) +def test_interval_contains_zero_and_the_bridge(bridge, t): + lower, upper = gate.hull(bridge, t) + assert lower <= min(0.0, bridge) - t + 1e-12 + assert upper >= max(0.0, bridge) + t - 1e-12 + assert lower <= 0.0 <= upper + assert lower <= bridge <= upper + # Rounded outward by less than one unit of the third decimal. + assert min(0.0, bridge) - t - lower < 1e-3 + assert upper - max(0.0, bridge) - t < 1e-3 + + +@settings(max_examples=300, deadline=None) +@given(bridge=bridges, t=st.floats(0.001, 0.2)) +def test_interval_never_extends_past_epuf_by_more_than_t(bridge, t): + lower, upper = gate.hull(bridge, t) + if bridge >= 0: + assert lower >= -t - 1e-3 + else: + assert upper <= t + 1e-3 + + +@settings(max_examples=300, deadline=None) +@given(bridge=bridges, sigma=sigmas) +def test_faithful_pass_probability_is_at_least_its_no_bridge_value( + bridge, sigma +): + t = 3.2 * sigma + with_bridge = gate.faithful_pass_probability( + bridge, sigma, *gate.hull(bridge, t) + ) + without = gate.faithful_pass_probability(0.0, sigma, *gate.hull(0.0, t)) + assert 0.0 <= with_bridge <= 1.0 + # A bridge only widens the side facing EPUF. Outward rounding of the + # interval (at most 1e-3) can move either probability slightly. + assert with_bridge >= without - 1e-3 / sigma * 0.4 + + +@settings(max_examples=300, deadline=None) +@given(bridge=bridges, sigma=sigmas, k=st.floats(2.5, 5)) +def test_a_gated_cell_always_certifies_within_the_cap(bridge, sigma, k): + cell = _floor(bridge=bridge, t=round(k * sigma, 3), sigma=sigma) + if gate.demotion_reason(cell) is None: + lower, upper = gate.hull(cell.bridge, cell.t) + cap = gate.CAPS["abs_gap"] + assert max(abs(lower), abs(upper)) <= cap + assert gate.minimum_detectable_gap(bridge, cell.t, sigma) <= cap + + +def test_demotion_reasons_fire_in_their_registered_order(): + assert gate.demotion_reason(_floor()) is None + assert ( + gate.demotion_reason(_floor(defined=False, min_events=0)) + == "undefined_on_some_split" + ) + assert ( + gate.demotion_reason(_floor(min_events=19, sigma=1.0)) + == "below_20_events" + ) + assert ( + gate.demotion_reason(_floor(epuf_sampling_sd=0.002)) + == "epuf_sampling_not_negligible" + ) + assert ( + gate.demotion_reason(_floor(t=0.14, sigma=0.04, bridge=0.5)) + == "noise_exceeds_cap" + ) + assert ( + gate.demotion_reason(_floor(bridge=-0.12)) == "bridge_exceeds_budget" + ) + # log-ratio cells use the ln(1.5) cap + assert gate.demotion_reason(_floor("zint.men", bridge=0.3)) is None + assert ( + gate.demotion_reason(_floor("zint.men", bridge=0.4)) + == "bridge_exceeds_budget" + ) + + +def _reasons(**overrides): + reasons = dict.fromkeys(cell_ids()) + reasons.update(overrides) + return reasons + + +def test_ladder_gates_the_cohort_rung_when_all_six_r6_cells_qualify(): + gated, report = gate.adopt_ladder(_reasons()) + assert {c for c in gated if c.startswith("r6")} == { + f"r6.{sex}.{band}" + for sex in ("men", "women") + for band in ("c0", "c1", "c2") + } + assert report["r6.men"] == "superseded_by_cohort_rung" + assert "zint.men" in gated and report["d_anyzero.men"] == ( + "superseded_by_zint" + ) + assert {"q_atmax.men", "mpers.women", "q_sexratio"} <= set(gated) + assert report["zint.men.c0"] == "reported_by_cohort" + assert set(gated) | set(report) == set(cell_ids()) + assert not set(gated) & set(report) + + +def test_ladder_falls_back_to_sex_level_cells_one_sex_at_a_time(): + gated, report = gate.adopt_ladder( + _reasons( + **{ + "r6.men.c2": "bridge_exceeds_budget", + "r6.women": "noise_exceeds_cap", + "zint.men": "below_20_events", + "zint.women": "below_20_events", + "d_anyzero.women": "bridge_exceeds_budget", + "q_sexratio": "noise_exceeds_cap", + } + ) + ) + assert "r6.men" in gated and "r6.women" not in gated + assert report["r6.men.c0"] == "cohort_rung_not_adopted" + assert report["r6.men.c2"] == "bridge_exceeds_budget" + assert report["r6.women"] == "noise_exceeds_cap" + assert "d_anyzero.men" in gated + assert report["zint.men"] == "below_20_events" + assert report["d_anyzero.women"] == "bridge_exceeds_budget" + assert "q_sexratio" not in gated + + +def test_ladder_can_gate_nothing(): + gated, report = gate.adopt_ladder( + dict.fromkeys(cell_ids(), "bridge_exceeds_budget") + ) + assert gated == [] + assert set(report) == set(cell_ids()) + + +def _registered(): + return { + "r6.men": { + "epuf_value": 0.70, + "psid_value": 0.66, + "lower": -0.07, + "upper": 0.03, + }, + "zint.women": { + "epuf_value": 0.065, + "psid_value": 0.060, + "lower": -0.2, + "upper": 0.12, + }, + } + + +def _run(r6, zint): + return { + seed: {"r6.men": r6, "zint.women": zint} for seed in gate.GATE_SEEDS + } + + +def test_score_run_passes_between_epuf_and_the_psid_and_fails_beyond(): + assert gate.score_run(_run(0.66, 0.060), _registered())["pass"] + assert gate.score_run(_run(0.70, 0.065), _registered())["pass"] + too_low = gate.score_run(_run(0.60, 0.060), _registered()) + assert not too_low["pass"] + assert not too_low["cells"]["r6.men"]["pass"] + assert too_low["cells"]["zint.women"]["pass"] + overshoot = gate.score_run(_run(0.75, 0.060), _registered()) + assert not overshoot["cells"]["r6.men"]["pass"] + + +def test_score_run_decomposes_the_gap_into_model_and_source_terms(): + scored = gate.score_run(_run(0.64, 0.060), _registered()) + cell = scored["cells"]["r6.men"] + assert cell["gap_from_epuf"] == pytest.approx(-0.06) + assert cell["source_term_psid_minus_epuf"] == pytest.approx(-0.04) + assert cell["model_term_candidate_minus_psid"] == pytest.approx(-0.02) + share = scored["cells"]["zint.women"] + assert share["source_term_psid_minus_epuf"] == pytest.approx( + transform("zint.women", 0.060) - transform("zint.women", 0.065) + ) + + +def test_score_run_requires_exactly_the_gate_seeds(): + partial = {seed: {"r6.men": 0.7, "zint.women": 0.06} for seed in range(5)} + with pytest.raises(ValueError, match="seeds 0-19"): + gate.score_run(partial, _registered()) + + +def test_a_run_with_no_gated_cells_does_not_pass(): + empty = {seed: {} for seed in gate.GATE_SEEDS} + assert gate.score_run(empty, {})["pass"] is False + + +def test_an_undefined_estimate_fails_its_cell(): + scored = gate.score_run(_run(float("nan"), 0.06), _registered()) + assert not scored["cells"]["r6.men"]["pass"] + + +def test_floor_terms_sum_to_the_replicate(): + args = ("zint.men", 0.06, 0.04, [0.05, 0.07], [0.05, 0.05]) + common, averaging = gate.floor_terms(*args) + assert common == pytest.approx((math.log(0.06) - math.log(0.04)) / 2) + assert gate.floor_replicate(*args) == pytest.approx(common + averaging) + + +def _spearman(x, y): + from populace_dynamics.harness.epuf_cells import weighted_spearman + + return weighted_spearman(x, y, np.ones(len(x))) + + +def test_floor_prices_a_faithful_generator(): + """The two-term floor matches a faithful generator's 20-seed spread. + + A population where earnings rank ``y`` depends on an anchor ``x`` with + correlation 0.6. A faithful generator redraws ``y`` for each 20% + holdout from the true conditional law. Its 20-seed mean correlation + differs from the realised sample's by noise the seeds share, which a + floor built from 20%/80% splits alone cannot see. + """ + rho, n, n_seeds = 0.6, 1500, 20 + rng = np.random.default_rng(20261002) + + def draw_y(x, generator): + return rho * x + math.sqrt(1 - rho**2) * generator.normal(size=len(x)) + + faithful = [] + two_term, one_term = [], [] + for replication in range(160): + x = rng.normal(size=n) + y = draw_y(x, rng) + real = _spearman(x, y) + per_seed = [] + for _ in range(n_seeds): + held = rng.random(n) < gate.HOLDOUT_FRACTION + per_seed.append(_spearman(x[held], draw_y(x[held], rng))) + faithful.append(float(np.mean(per_seed)) - real) + if replication < 60: + half = rng.random(n) < gate.HALF_FRACTION + holdouts, complements = [], [] + for _ in range(n_seeds): + held = rng.random(n) < gate.HOLDOUT_FRACTION + holdouts.append(_spearman(x[held], y[held])) + complements.append(_spearman(x[~held], y[~held])) + common, averaging = gate.floor_terms( + "r6.men", + _spearman(x[half], y[half]), + _spearman(x[~half], y[~half]), + holdouts, + complements, + ) + two_term.append(common + averaging) + one_term.append(averaging) + spread = float(np.std(faithful, ddof=1)) + sigma = gate.realized_sigma(two_term) + naive = gate.realized_sigma(one_term) + assert 0.75 <= spread / sigma <= 1.25 + assert spread / naive > 1.5 diff --git a/tests/harness/test_epuf_operator.py b/tests/harness/test_epuf_operator.py new file mode 100644 index 00000000..aa6ea5d0 --- /dev/null +++ b/tests/harness/test_epuf_operator.py @@ -0,0 +1,121 @@ +"""EPUF's measurement operator: status invariants on every input.""" + +from __future__ import annotations + +import numpy as np +import pytest +from hypothesis import given, settings +from hypothesis import strategies as st + +from populace_dynamics.harness.epuf_operator import ( + disclosure_constants, + epuf_measure, + rounding_base, + wage_base, +) + +YEARS = sorted(disclosure_constants()) +year_strategy = st.sampled_from(YEARS) +earnings_strategy = st.lists( + st.floats(min_value=-1e5, max_value=5e5, allow_nan=False), + min_size=1, + max_size=40, +) + + +def test_constants_cover_1951_to_2006(): + assert YEARS == list(range(1951, 2007)) + assert wage_base(1951) == 3_600 + assert wage_base(2006) == 94_200 + with pytest.raises(ValueError, match="1951-2006"): + wage_base(2007) + + +def test_worked_values_for_1998(): + # 1998: wage base 68,400, bottom code 57, band (67,400, 68,400) -> 68,001. + values = np.array( + [-5, 0, 50, 99.9, 100, 112, 990, 1049, 1050, 49_960, 67_400] + ) + assert epuf_measure(values, 1998).tolist() == [ + 0, + 0, + 57, + 57, + 100, + 100, + 1_000, + 1_000, + 1_100, + 50_000, + 67_000, + ] + band = epuf_measure(np.array([67_401, 68_000, 68_399]), 1998) + assert band.tolist() == [68_001, 68_001, 68_001] + assert epuf_measure(np.array([68_400, 1e6]), 1998).tolist() == [ + 68_400, + 68_400, + ] + + +def test_missing_earnings_and_unknown_years_are_refused(): + with pytest.raises(ValueError, match="missing"): + epuf_measure(np.array([1.0, np.nan]), 1998) + with pytest.raises(ValueError, match="1951-2006"): + epuf_measure(np.array([1.0]), 2010) + + +@settings(max_examples=300, deadline=None) +@given(values=earnings_strategy, year=year_strategy) +def test_output_stays_between_zero_and_the_wage_base(values, year): + out = epuf_measure(np.array(values), year) + assert (out >= 0).all() + assert (out <= wage_base(year)).all() + + +@settings(max_examples=300, deadline=None) +@given(values=earnings_strategy, year=year_strategy) +def test_positive_status_is_preserved(values, year): + values = np.array(values) + out = epuf_measure(values, year) + assert ((out > 0) == (values > 0)).all() + + +@settings(max_examples=300, deadline=None) +@given(values=earnings_strategy, year=year_strategy) +def test_at_maximum_status_is_preserved(values, year): + values = np.array(values) + out = epuf_measure(values, year) + assert ((out == wage_base(year)) == (values >= wage_base(year))).all() + + +@settings(max_examples=300, deadline=None) +@given(values=earnings_strategy, year=year_strategy) +def test_values_land_on_the_grid_or_a_disclosure_constant(values, year): + row = disclosure_constants()[year] + out = epuf_measure(np.array(values), year) + special = np.isin( + out, [0, row["bottom_code"], row["band_mean"], row["wage_base"]] + ) + on_grid = np.mod(out, rounding_base(out)) == 0 + assert (special | on_grid).all() + + +@pytest.mark.parametrize("year", YEARS) +def test_operator_is_weakly_increasing_in_every_year(year): + grid = np.arange(0, wage_base(year) + 50, 1.0) + assert (np.diff(epuf_measure(grid, year)) >= 0).all() + + +@settings(max_examples=200, deadline=None) +@given(values=earnings_strategy, year=year_strategy) +def test_rounding_moves_a_value_by_at_most_half_a_base(values, year): + row = disclosure_constants()[year] + values = np.clip(np.array(values), 0, row["wage_base"]) + ordinary = (values >= 100) & ( + values <= row["wage_base"] - row["band_base"] + ) + out = epuf_measure(values, year) + assert ( + np.abs(out[ordinary] - values[ordinary]) + <= rounding_base(values[ordinary]) / 2 + ).all() diff --git a/tests/test_epuf_gate_floor_builder.py b/tests/test_epuf_gate_floor_builder.py new file mode 100644 index 00000000..e4231c27 --- /dev/null +++ b/tests/test_epuf_gate_floor_builder.py @@ -0,0 +1,410 @@ +"""The EPUF floor builder's pipeline on synthetic panels. + +No PSID and no EPUF: an invented panel in gate 1's panel shape runs +through the builder's own support, floor, partition and bite functions. +The artifact the builder writes from real data is bound separately. +""" + +from __future__ import annotations + +import importlib.util +import sys +from pathlib import Path + +import numpy as np +import pandas as pd +import pytest + +from populace_dynamics.harness import epuf_gate as gate +from populace_dynamics.harness.epuf_cells import ( + COHORT_BANDS, + WINDOW_YEARS, + WindowArrays, + cell_ids, + transform, +) +from populace_dynamics.harness.panel import split_panel_by_person + +ROOT = Path(__file__).resolve().parents[1] + + +def _load_builder(): + name = "build_epuf_gate_floors" + if name in sys.modules: + return sys.modules[name] + spec = importlib.util.spec_from_file_location( + name, ROOT / "scripts" / f"{name}.py" + ) + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + spec.loader.exec_module(module) + return module + + +builder = _load_builder() +WAGE_BASES = builder.wage_bases() + + +def _invented_panel(n_persons=3000, seed=0): + """An invented long panel in gate 1's panel shape (not PSID).""" + rng = np.random.default_rng(seed) + rows = [] + sexes = [] + for person in range(1, n_persons + 1): + birth = int(rng.integers(1940, 1980)) + sexes.append( + (person, rng.choice(["male", "female", "na"], p=[0.48, 0.5, 0.02])) + ) + permanent = rng.normal(10.2, 0.6) + last = int(rng.choice([2002, 2004, 2006, 2010, 2022])) + skip = int(rng.choice([0, 0, 0, 2000])) + for period in range(1998, last + 1, 2): + if period == skip: + continue + age = period + 1 - birth + if not 25 <= age <= 59: + continue + earnings = ( + 0.0 + if rng.random() < 0.1 + else float(np.exp(permanent + rng.normal(0, 0.5))) + ) + rows.append((person, period, earnings, age, rng.uniform(0.5, 2))) + panel = pd.DataFrame( + rows, columns=["person_id", "period", "earnings", "age", "weight"] + ) + sex = pd.DataFrame(sexes, columns=["person_id", "sex"]) + return panel, sex + + +@pytest.fixture(scope="module") +def support(): + panel, sex = _invented_panel() + frame, universe, counts = builder.support_from_panel(panel, sex) + return panel, sex, frame, universe, counts + + +def test_holdout_mask_is_the_gate_one_split_function(): + universe = np.arange(1000, 3000, 3) + ids = pd.DataFrame({"person_id": universe}) + for seed in (0, 7, 1019): + for fraction in (0.2, 0.5): + left, right = split_panel_by_person( + ids, "person_id", fraction=fraction, seed=seed + ) + mask = builder.holdout_mask(universe, seed=seed, fraction=fraction) + assert set(left["person_id"]) == set(universe[mask]) + assert set(right["person_id"]) == set(universe[~mask]) + + +def test_support_applies_every_rule(support): + panel, sex, frame, universe, counts = support + assert counts["n_universe_persons"] == panel["person_id"].nunique() + assert len(frame) == counts["n_support_persons"] > 200 + assert ( + counts["n_present_all_four_years"] + >= counts["n_and_anchor_2006_or_later"] + >= counts["n_and_sex_coded"] + >= counts["n_support_persons"] + ) + periods = panel.groupby("person_id")["period"].agg(set) + anchor = panel.groupby("person_id")["period"].max() + coded = sex.set_index("person_id")["sex"] + for person in frame["person_id"]: + assert set(WINDOW_YEARS) <= periods[person] + assert anchor[person] >= builder.MIN_ANCHOR_PERIOD + assert coded[person] in ("male", "female") + low = min(a for a, _ in COHORT_BANDS.values()) + high = max(b for _, b in COHORT_BANDS.values()) + assert frame["birth_year"].between(low, high).all() + assert set(frame["sex"]) == {"men", "women"} + assert sum(counts["by_sex_and_band"].values()) == len(frame) + + +def test_support_weight_is_the_2004_row_weight(support): + panel, _, frame, _, _ = support + weights = panel[panel["period"] == 2004].set_index("person_id")["weight"] + assert ( + frame["weight"].to_numpy() + == weights.reindex(frame["person_id"]).to_numpy() + ).all() + + +def test_support_earnings_are_in_epuf_units(support): + panel, _, frame, _, _ = support + for year in WINDOW_YEARS: + raw = ( + panel[panel["period"] == year] + .set_index("person_id")["earnings"] + .reindex(frame["person_id"]) + .to_numpy() + ) + assert ( + frame[f"e{year}"].to_numpy() == builder.epuf_measure(raw, year) + ).all() + + +def test_support_refuses_conflicting_sex_and_duplicate_rows(support): + panel, sex, *_ = support + conflicted = pd.concat( + [sex, pd.DataFrame({"person_id": [1], "sex": ["male"]})] + ) + conflicted.loc[conflicted["person_id"] == 1, "sex"] = ["male", "female"] + with pytest.raises(ValueError, match="two coded sexes"): + builder.support_from_panel(panel, conflicted) + with pytest.raises(ValueError, match="duplicate person-periods"): + builder.support_from_panel(pd.concat([panel, panel.head(1)]), sex) + + +@pytest.fixture(scope="module") +def built(support): + _, _, frame, universe, _ = support + arrays = WindowArrays(frame, wage_bases=WAGE_BASES) + # Use the support's own values as the "EPUF" reference, so that every + # bridge is zero and the partition depends on noise and events alone. + reference = {cell_id: c.value for cell_id, c in arrays.cells().items()} + sd = dict.fromkeys(reference, 0.0) + out = builder.build_floors( + arrays, universe, reference, sd, n_replicates=12 + ) + return frame, universe, arrays, out + + +def test_floors_cover_every_cell_and_partition_it_once(built): + _, _, _, out = built + assert sorted(out["cells"]) == sorted(cell_ids()) + partition = out["gate_partition"] + assert set(partition["gated"]) | set(partition["report_only"]) == set( + cell_ids() + ) + assert not set(partition["gated"]) & set(partition["report_only"]) + assert partition["n_gated"] == len(partition["gated"]) + assert set(out["registered"]) == set(partition["gated"]) + + +def test_floor_values_follow_the_registered_algebra(built): + _, _, _, out = built + for cell_id, cell in out["cells"].items(): + floor = cell["floor"] + if floor["tolerance"] is None: + assert cell["eligibility"] == "undefined_on_some_split" + continue + replicates = floor["replicates"] + assert len(replicates) == 12 + assert None not in replicates + assert floor["tolerance"] == gate.tolerance(replicates) + assert floor["realized_sigma"] == pytest.approx( + gate.realized_sigma(replicates) + ) + bridge = cell["bridge_psid_minus_epuf"] + assert bridge == pytest.approx( + transform(cell_id, cell["psid_value"]) + - transform(cell_id, cell["epuf_value"]) + ) + assert (cell["lower"], cell["upper"]) == gate.hull( + bridge, floor["tolerance"] + ) + expected = gate.demotion_reason( + gate.CellFloor( + cell_id, + True, + cell["min_events"], + bridge, + floor["tolerance"], + floor["realized_sigma"], + cell["epuf_sampling_sd"], + ) + ) + assert cell["eligibility"] == (expected or "eligible") + if cell["gated"]: + assert expected is None + assert cell["minimum_detectable_gap_80"] <= cell["cap"] + + +def test_real_data_pass_as_their_own_training_copy(built): + _, _, _, out = built + if out["gate_partition"]["gated"]: + assert out["training_copy"]["pass"] + oc = out["faithful_candidate_oc"] + assert 0.0 <= oc["analytic_product"] <= 1.0 + + +def test_build_floors_is_deterministic(built): + frame, universe, arrays, out = built + reference = {c: v["epuf_value"] for c, v in out["cells"].items()} + again = builder.build_floors( + arrays, + universe, + reference, + dict.fromkeys(reference, 0.0), + n_replicates=12, + ) + assert again["cells"] == out["cells"] + assert again["gate_partition"] == out["gate_partition"] + + +def test_a_large_bridge_demotes_instead_of_widening_the_gate(built): + frame, universe, arrays, out = built + reference = {c: v["epuf_value"] for c, v in out["cells"].items()} + shifted = dict(reference) + shifted["r6.men"] = reference["r6.men"] + 0.3 + shifted["r6.women"] = reference["r6.women"] + 0.3 + for band in COHORT_BANDS: + shifted[f"r6.men.{band}"] = reference[f"r6.men.{band}"] + 0.3 + moved = builder.build_floors( + arrays, universe, shifted, dict.fromkeys(shifted, 0.0), n_replicates=12 + ) + assert "r6.men" not in moved["gate_partition"]["gated"] + assert moved["cells"]["r6.men"]["eligibility"] in ( + "bridge_exceeds_budget", + "noise_exceeds_cap", + ) + + +def test_perturbations_change_only_the_early_years(support): + _, _, frame, _, _ = support + rng = np.random.default_rng(0) + for perturbed in ( + builder.perturb_persistence(frame, rng, 0.5), + builder.perturb_sex_blind(frame, rng, same_sex=False), + builder.perturb_sex_blind(frame, rng, same_sex=True), + builder.perturb_top_tail(frame, rng), + builder.perturb_participation(frame, rng), + ): + fixed = ["person_id", "sex", "birth_year", "weight", "e2004"] + pd.testing.assert_frame_equal(perturbed[fixed], frame[fixed]) + assert len(perturbed) == len(frame) + for year in WINDOW_YEARS: + assert perturbed[f"e{year}"].between(0, WAGE_BASES[year]).all() + + +def test_participation_loss_only_removes_earnings(support): + _, _, frame, _, _ = support + perturbed = builder.perturb_participation(frame, np.random.default_rng(1)) + for year in WINDOW_YEARS[:3]: + before, after = frame[f"e{year}"], perturbed[f"e{year}"] + changed = before != after + assert (after[changed] == 0).all() + assert 0 < changed.mean() < 0.1 + + +def test_top_tail_compression_never_raises_a_value(support): + _, _, frame, _, _ = support + perturbed = builder.perturb_top_tail(frame, np.random.default_rng(2)) + for year in WINDOW_YEARS[:3]: + assert (perturbed[f"e{year}"] <= frame[f"e{year}"]).all() + + +def test_same_sex_control_keeps_donors_within_sex(support): + _, _, frame, _, _ = support + # Tag every early-year value with its owner's sex, then permute. + tagged = frame.copy() + marker = np.where(tagged["sex"] == "men", 1.0, 2.0) + for year in WINDOW_YEARS[:3]: + tagged[f"e{year}"] = marker + control = builder.perturb_sex_blind( + tagged, np.random.default_rng(3), same_sex=True + ) + pooled = builder.perturb_sex_blind( + tagged, np.random.default_rng(3), same_sex=False + ) + assert (control["e1998"].to_numpy() == marker).all() + assert (pooled["e1998"].to_numpy() != marker).any() + + +def test_bite_demonstrations_report_every_perturbation(built): + frame, universe, _, out = built + bites = builder.bite_demonstrations(frame, universe, out["registered"]) + assert { + "bd1_persistence_loss_0.10", + "bd1_persistence_loss_0.05", + "bd2_sex_blind_donors", + "bd2c_same_sex_donors_control", + "bd3_top_tail_compression", + "bd4_participation_loss", + } <= set(bites) + for family, row in bites["requirements"].items(): + assert row["bite"] == builder.BITE_REQUIREMENT[family] + assert row["met"] == (row["fail_share"] >= 0.90) + assert bites["pause"] == any( + not row["met"] for row in bites["requirements"].values() + ) + + +# --- from candidate panels to a verdict ---------------------------------- + + +def _holdout_panels(panel, universe): + return { + seed: panel[ + panel["person_id"].isin( + universe[ + builder.holdout_mask( + universe, seed=seed, fraction=gate.HOLDOUT_FRACTION + ) + ] + ) + ] + for seed in gate.GATE_SEEDS + } + + +def test_a_candidate_equal_to_the_real_panel_scores_as_the_training_copy( + support, built +): + from populace_dynamics.harness.epuf_run import score_candidate + + panel, _, frame, universe, _ = support + _, _, _, out = built + scored = score_candidate( + _holdout_panels(panel, universe), frame, out["registered"] + ) + expected = out["training_copy"] + assert scored["pass"] == expected["pass"] + for cell_id, cell in expected["cells"].items(): + assert scored["cells"][cell_id]["gap_from_epuf"] == pytest.approx( + cell["gap_from_epuf"], abs=1e-12 + ) + assert sorted(scored["per_seed_values"]) == sorted( + str(seed) for seed in gate.GATE_SEEDS + ) + for seed, values in out["real_gate_seed_values"].items(): + for cell_id, value in values.items(): + got = scored["per_seed_values"][seed][cell_id] + if value is None: + assert np.isnan(got) + else: + assert got == pytest.approx(value, abs=1e-12) + + +def test_a_candidate_missing_a_window_row_is_refused(support): + from populace_dynamics.harness.epuf_run import candidate_window_cells + + panel, _, frame, universe, _ = support + holdout = _holdout_panels(panel, universe)[0] + person = frame.loc[ + frame["person_id"].isin(holdout["person_id"]), "person_id" + ].iloc[0] + broken = holdout[ + ~((holdout["person_id"] == person) & (holdout["period"] == 2000)) + ] + with pytest.raises(ValueError, match="lacks a generated row"): + candidate_window_cells(broken, frame) + with pytest.raises(ValueError, match="holds no support person"): + candidate_window_cells(holdout.iloc[0:0], frame) + + +def test_generated_earnings_change_the_score_but_not_the_support( + support, built +): + from populace_dynamics.harness.epuf_run import candidate_window_cells + + panel, _, frame, universe, _ = support + holdout = _holdout_panels(panel, universe)[0] + real = candidate_window_cells(holdout, frame) + shuffled = holdout.copy() + rng = np.random.default_rng(5) + shuffled["earnings"] = rng.permutation(shuffled["earnings"].to_numpy()) + generated = candidate_window_cells(shuffled, frame) + assert set(generated) == set(real) + assert generated["r6.men"] != pytest.approx(real["r6.men"]) diff --git a/tests/tier_counts.json b/tests/tier_counts.json index 9ce3f503..d71f3fce 100644 --- a/tests/tier_counts.json +++ b/tests/tier_counts.json @@ -1,8 +1,8 @@ { "schema_version": 1, "counts": { - "unit": 5678, - "artifact": 3331, + "unit": 5796, + "artifact": 3344, "integration_psid": 1341, "reproduction_legacy": 520, "oracle_policyengine": 215 From 970a9db721bf471308b4fd2666bf0d6e925250ca Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 09:50:16 -0400 Subject: [PATCH 2/9] EPUF career cells: rank every year after 1950 in the AIME The report-only career AIME ranked only ages 22-61. The statute ranks every year after 1950 through the cutoff, including years before age 22, and its oracle test had been built the same way, so it matched by construction. The test now passes the oracle every year through age 61. The career-assembler mask now starts each career at max(1968, birth year + 22), as build_career does, rather than at 1968 for everyone. For the cohorts it is applied to (born 1930-1944) the two agree. Neither cell enters the gate: both belong to tranche R, which is report-only. Found after the first floor build, whose outputs are preserved in the evidence folder (epuf-20261001/first-floor-build). Co-Authored-By: Claude Opus 5.5 --- scripts/build_epuf_gate_floors.py | 4 ++- src/populace_dynamics/harness/epuf_cells.py | 35 +++++++++++++-------- tests/harness/test_epuf_cells.py | 30 ++++++++++-------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/scripts/build_epuf_gate_floors.py b/scripts/build_epuf_gate_floors.py index 8d2e2a48..b5ff59fd 100644 --- a/scripts/build_epuf_gate_floors.py +++ b/scripts/build_epuf_gate_floors.py @@ -278,7 +278,9 @@ def career_reference( row.loc[annual["person_id"].to_numpy()].to_numpy(), annual["year"].to_numpy() - years[0], ] = annual["earnings"].to_numpy() - masked = mask_as_career_assembler(matrix, years) + masked = mask_as_career_assembler( + matrix, years, persons["birth_year"].to_numpy() + ) nawi = captured_ssa_parameters().nawi out: dict[str, object] = {} for sex_code, sex in EPUF_SEX_LABELS.items(): diff --git a/src/populace_dynamics/harness/epuf_cells.py b/src/populace_dynamics/harness/epuf_cells.py index f9af95e0..ef6adc58 100644 --- a/src/populace_dynamics/harness/epuf_cells.py +++ b/src/populace_dynamics/harness/epuf_cells.py @@ -349,20 +349,23 @@ def cells(self, mask: np.ndarray | None = None) -> dict[str, CellValue]: def mask_as_career_assembler( - earnings: np.ndarray, years: Sequence[int] + earnings: np.ndarray, years: Sequence[int], birth_year: np.ndarray ) -> np.ndarray: """Rewrite annual histories the way the career assembler builds one. - ``earnings`` is persons by years. Years before 1968 become zero (the - assembler's careers start at ``max(1968, birth_year + 22)``) and each - odd year from 1997 becomes the mean of its two neighbours (the - assembler's structural-gap rule, which fills the years the biennial - PSID did not collect). A filled odd year whose neighbours are both - zero stays zero. + ``earnings`` is persons by years. Each person's years before + ``max(1968, birth_year + 22)`` become zero (the assembler's careers + start there and count earlier years as zero), and each odd year from + 1997 becomes the mean of its two neighbours (the assembler's + structural-gap rule, which fills the years the biennial PSID did not + collect). A filled odd year whose neighbours are both zero stays + zero. """ years = np.asarray(years) + birth_year = np.asarray(birth_year) out = np.asarray(earnings, dtype=np.float64).copy() - out[:, years < 1968] = 0.0 + start = np.maximum(1968, birth_year + 22) + out[years[None, :] < start[:, None]] = 0.0 position = {int(year): index for index, year in enumerate(years)} for year in years[(years >= 1997) & (years % 2 == 1)]: left = position.get(int(year) - 1) @@ -390,7 +393,8 @@ def career_cells( ``earnings`` is persons by years of capped annual earnings, unweighted (EPUF is a simple random sample; a weighted source passes replicated or pre-weighted rows). Every person's ages 22-61 must lie inside - ``years``. + ``years``, which must start in 1951 or later; the AIME ranks every + supplied year through age 61. """ years = np.asarray(years) earnings = np.asarray(earnings, dtype=np.float64) @@ -449,15 +453,20 @@ def career_cells( } out["at_max_by_age"] = by_age + # The AIME ranks every year after 1950 through the cutoff (age 61), + # including years before age 22 (42 USC 415(b)(2)); the number of + # computation years is 35 for every cohort here (born 1929 or later). + cutoff = birth_year + last_age + through = years[None, :] <= cutoff[:, None] index_year = birth_year + 60 index_value = np.vectorize(lambda y: float(nawi[int(y)]))(index_year) - year_value = np.vectorize(lambda y: float(nawi[int(y)]))(window_years) + year_value = np.array([float(nawi[int(y)]) for y in years]) factor = np.where( - window_years < index_year[:, None], - index_value[:, None] / year_value, + years[None, :] < index_year[:, None], + index_value[:, None] / year_value[None, :], 1.0, ) - indexed = window * factor + indexed = np.where(through, earnings * factor, 0.0) top = np.sort(indexed, axis=1)[:, -_COMPUTATION_YEARS:] aime = np.floor(top.sum(axis=1) / (_COMPUTATION_YEARS * 12)) out["aime_35yr_through_age_61"] = { diff --git a/tests/harness/test_epuf_cells.py b/tests/harness/test_epuf_cells.py index 4eb37094..0bab4d82 100644 --- a/tests/harness/test_epuf_cells.py +++ b/tests/harness/test_epuf_cells.py @@ -264,18 +264,21 @@ def test_transform_is_log_for_shares_and_identity_for_correlations(): YEARS = np.arange(1951, 2007) -def test_mask_zeroes_before_1968_and_fills_odd_years_from_1997(): - history = np.arange(1.0, len(YEARS) + 1)[None, :] * 100 - masked = ec.mask_as_career_assembler(history, YEARS) - assert (masked[0, YEARS < 1968] == 0).all() - untouched = (YEARS >= 1968) & ~((YEARS >= 1997) & (YEARS % 2 == 1)) - assert (masked[0, untouched] == history[0, untouched]).all() - for year in (1997, 1999, 2001, 2003, 2005): - index = year - 1951 - assert ( - masked[0, index] - == (history[0, index - 1] + history[0, index + 1]) / 2 - ) +def test_mask_zeroes_before_the_assembler_start_and_fills_odd_years(): + history = np.tile(np.arange(1.0, len(YEARS) + 1) * 100, (2, 1)) + births = np.array([1940, 1950]) + masked = ec.mask_as_career_assembler(history, YEARS, births) + # born 1940: career starts 1968; born 1950: at age 22, 1972 + for row, start in ((0, 1968), (1, 1972)): + assert (masked[row, YEARS < start] == 0).all() + untouched = (YEARS >= start) & ~((YEARS >= 1997) & (YEARS % 2 == 1)) + assert (masked[row, untouched] == history[row, untouched]).all() + for year in (1997, 1999, 2001, 2003, 2005): + index = year - 1951 + assert ( + masked[row, index] + == (history[row, index - 1] + history[row, index + 1]) / 2 + ) def test_career_zero_years_and_at_max_shares(): @@ -322,10 +325,11 @@ def test_career_aime_matches_the_statutory_oracle(seed, birth): wage_bases=WAGE_BASES, nawi=params.nawi, ) + # Every year after 1950 through age 61, including years before 22. through_61 = { int(year): float(value) for year, value in zip(YEARS, history, strict=True) - if birth + 22 <= year <= birth + 61 + if year <= birth + 61 } expected = statutory_aime.aime(through_61, birth, params) assert cells["aime_35yr_through_age_61"]["p50"] == expected From ce8d500066837f18943ca1ae0e6130a999c10b65 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 09:55:08 -0400 Subject: [PATCH 3/9] EPUF gate floors: two persistence cells gate; the bite pause fires Adds the floor artifact the rules-first commit's builder produced, the draft gates.yaml block it renders (locked: false, not in gates.yaml), the test that binds the two, and the proposal's results. - Support: 5,769 PSID persons present at 1998-2004 with a last period of 2006 or later; EPUF side 1,311,282 persons born 1947-1973. - Gated: 1998-2004 rank persistence by sex. PSID 0.668 vs EPUF 0.711 (men) and 0.640 vs 0.672 (women); faithful-candidate pass probability 0.9986. - Reported: zero-year and maximum cells, unpowered at PSID scale or with a bridge past the cap (PSID men at the maximum 17.8% vs EPUF 11.6%). - Pause: the registered persistence bite fails the gate 44% of the time, against 90% required. Options are listed for the referee round; no rule was changed to clear it. - Tranche R, EPUF only: the career assembler's rules cut the median AIME of men born 1940-1944 by 10% and 1930-1934 by 36%. Co-Authored-By: Claude Opus 5.5 --- .../gate_epuf_registration_proposal.md | 180 +- docs/design/gate_epuf_block_draft.yaml | 190 + runs/epuf_gate_floors_v1.inputs.json | 25 + runs/epuf_gate_floors_v1.json | 7325 +++++++++++++++++ runs/epuf_gate_floors_v1.json.env.json | 19 + scripts/render_gate_epuf_block_draft.py | 253 + tests/README-tiers.md | 4 +- tests/test_gate_epuf_block_draft.py | 194 + tests/tier_counts.json | 2 +- 9 files changed, 8177 insertions(+), 15 deletions(-) create mode 100644 docs/design/gate_epuf_block_draft.yaml create mode 100644 runs/epuf_gate_floors_v1.inputs.json create mode 100644 runs/epuf_gate_floors_v1.json create mode 100644 runs/epuf_gate_floors_v1.json.env.json create mode 100644 scripts/render_gate_epuf_block_draft.py create mode 100644 tests/test_gate_epuf_block_draft.py diff --git a/docs/amendments/gate_epuf_registration_proposal.md b/docs/amendments/gate_epuf_registration_proposal.md index 5a832c04..3c782809 100644 --- a/docs/amendments/gate_epuf_registration_proposal.md +++ b/docs/amendments/gate_epuf_registration_proposal.md @@ -242,8 +242,146 @@ The real gate-seed holdouts are also scored as a training copy and must pass. ## 7. Results of the floor build -*Filled by the floor build, which runs after the rules above are committed -and pushed (section 10).* +All numbers in this section come from `runs/epuf_gate_floors_v1.json`. +`tests/test_gate_epuf_block_draft.py` recomputes every tolerance, interval, +partition and pass probability from the floor replicates stored there. + +### 7.1 Support + +| | Persons | +|---|---:| +| gate 1's filtered panel | 22,300 | +| with a row at each of 1998, 2000, 2002, 2004 | 6,323 | +| and last in-filter period 2006 or later | 5,775 | +| and coded sex | 5,775 | +| and born 1947-1973 (the support) | 5,769 | + +By sex and cohort band: men 898 / 926 / 679 and women 1,059 / 1,269 / 938 +(c0 / c1 / c2). EPUF's side is 1,311,282 persons. The builder asserted that +its split function draws gate 1's holdouts: each gate seed's holdout size +equals `runs/gate1_rank_knn_v5.json`'s for seeds 0-4. + +### 7.2 The PSID against EPUF + +Sex-level cells. "Bridge" is the PSID's distance from EPUF on the cell's +metric scale (log ratio for shares, difference for correlations). + +| Cell | EPUF | PSID | Bridge | Tolerance `t` | Outcome | +|---|---:|---:|---:|---:|---| +| `r6.men` | 0.711 | 0.668 | -0.043 | 0.079 | **gated** | +| `r6.women` | 0.672 | 0.640 | -0.032 | 0.078 | **gated** | +| `zint.men` | 0.051 | 0.049 | -0.040 | 0.381 | below 20 events | +| `zint.women` | 0.066 | 0.070 | +0.062 | 0.381 | below 20 events | +| `d_anyzero.men` | 0.128 | 0.097 | -0.278 | 0.283 | bridge exceeds budget | +| `d_anyzero.women` | 0.180 | 0.151 | -0.176 | 0.212 | bridge exceeds budget | +| `q_atmax.men` | 0.116 | 0.178 | +0.425 | 0.164 | bridge exceeds budget | +| `q_atmax.women` | 0.036 | 0.039 | +0.087 | 0.358 | noise exceeds cap | +| `mpers.men` | 0.594 | 0.613 | +0.031 | 0.196 | below 20 events | +| `mpers.women` | 0.478 | 0.516 | +0.077 | — | undefined on some split | +| `q_sexratio` | 3.25 | 4.56 | +0.338 | 0.379 | noise exceeds cap | + +What the table says, and what it does not: + +- **Rank persistence.** On the support, PSID earnings ranks persist less + from 1998 to 2004 than EPUF's do: 0.668 against 0.711 for men, 0.640 + against 0.672 for women. The bridge measures the gap; it does not say how + much of it is reporting error, frame or noncovered work. +- **The taxable maximum.** Among positive person-years, 17.8 percent of the + PSID support's men are at the wage base, against 11.6 percent of EPUF's + men born in the same years. The support is people who stayed in the survey + as heads or spouses through 2006, a more attached group than every EPUF + earner. A log gap of 0.42 exceeds the cap, so the cell is reported. +- **Zero years.** Given covered earnings in 2004, fewer PSID men and women + had a zero year in 1998-2002 than EPUF's (9.7 against 12.8 percent for + men). EPUF counts noncovered spells and years before arrival as zeros; the + PSID counts noncovered earnings as earnings. +- **Power.** Interior zero years and persistence at the maximum are too rare + at the PSID's size for the 20-event rule. No cohort-band cell is powered + within the caps. + +### 7.3 Gated surface and operating characteristic + +Two cells gate, by the ladder's fallback to sex-level persistence: + +| Cell | Interval for `G` | Realised sigma | Shared-noise share of floor variance | Faithful pass probability | +|---|---|---:|---:|---:| +| `r6.men` | [-0.122, 0.079] | 0.0246 | 0.78 | 0.9993 | +| `r6.women` | [-0.111, 0.078] | 0.0248 | 0.73 | 0.9993 | + +The gate's faithful-candidate pass probability is 0.9986 by product, and in +100 of 100 floor replicates every gated cell's `B + e_b` lies inside its +interval. The real gate-seed holdouts, scored as a candidate, pass (`G` = +-0.044 for men and -0.045 for women). About three-quarters of each cell's +floor variance is the term the 20 seeds share, which a floor of 20%/80% +splits alone would have left out. + +### 7.4 Bite demonstrations, and the pause + +| Bite | Fails the gate | `r6.men` | `r6.women` | +|---|---:|---:|---:| +| `bd1`, donor early years for 10% of persons | 0.44 | 0.16 | 0.30 | +| `bd1`, for 5% of persons | 0.00 | 0.00 | 0.00 | +| `bd2`, donors from both sexes | 0.00 | 0.00 | 0.00 | +| `bd2c`, donors of the same sex (control) | 0.00 | 0.00 | 0.00 | +| `bd3`, top-tail compression | 0.42 | 0.42 | 0.00 | +| `bd4`, participation loss | 0.00 | 0.00 | 0.00 | + +The registered requirement for the gated persistence family is that `bd1` +at 10 percent fails at least 90 percent of the time. It fails 44 percent of +the time, so **the ceremony pauses** (section 5). Giving 10 percent of +persons a donor's early years lowers the 1998-2004 correlation by about a +tenth, roughly 0.07; the gate fails a shortfall from the PSID of about +`t + 0.84 sigma`, 0.10, four times in five. Sex-blind donors move neither +cell, so the cells by sex add no catch for a generator that ignores sex, at +least on persistence. + +### 7.5 What the pause asks the referee round to decide + +The rules forbid choosing among these by looking at more results, so this +proposal stops here and lists them, with what each costs: + +- **(a) Lock the two persistence cells as they stand** and restate the bite + requirement at what the gate demonstrably detects: a shortfall of 0.10 in + the 1998-2004 rank correlation, at 80 percent power. The certified claim + would be honest, and comparable in resolution to gate 1's battery + tolerances (0.06 to 0.07 on log autocorrelation). But the requirement + would be relaxed after the result was seen, which the forks ledger must + record. +- **(b) Redesign the surface for power**, without the bridges: pool the + sexes, or score persistence on everyone present in 1998 and 2004 rather + than in all four years. Either is a fork. Neither is computed here, + because searching redesigns after seeing the bridges is what the ledger + exists to prevent. +- **(c) Publish EPUF as a benchmark, not a gate.** Every gate-1 candidate + run would carry the per-cell table and its decomposition into the model's + distance from the PSID and the PSID's distance from EPUF, with no pass or + fail. A gate would follow when a generator covers more of EPUF's years. + +The drafting session recommends (a). It is the only pass-or-fail test of +the generator against administrative records, its power matches gate 1's +comparable bands, and the relaxation is disclosed. The decision belongs to +the referee round and the maintainer. + +### 7.6 Tranche R on EPUF alone + +These numbers use no PSID. They compare EPUF careers as published with the +same careers rewritten by the career assembler's two rules (section 8). + +| Cohort | Mean zero years, ages 22-61 | Median AIME | 25th percentile AIME | +|---|---|---|---| +| men 1930-1934 | 13.9 -> 23.7 | $1,551 -> $1,000 | $429 -> $135 | +| men 1935-1939 | 13.0 -> 19.7 | $1,999 -> $1,548 | $611 -> $316 | +| men 1940-1944 | 12.9 -> 15.7 | $2,491 -> $2,240 | $758 -> $560 | +| women 1930-1934 | 23.2 -> 28.3 | $344 -> $182 | $57 -> $1 | +| women 1935-1939 | 21.5 -> 24.9 | $528 -> $367 | $110 -> $26 | +| women 1940-1944 | 19.2 -> 20.9 | $835 -> $698 | $202 -> $114 | + +The rules alone lower the median AIME of men born 1940-1944 by 10 percent, +and of those born 1930-1934 by 36 percent, because they count earnings +before 1968 as zero. A cohort born in 1946 or later loses no year to that +rule, so the table shows the size of the effect where it applies, not across +the repository's benefit cohorts. The PSID career product's +own values are computed once, after lock, beside these. ## 8. Tranche R: career statistics, report-only @@ -257,12 +395,14 @@ lies inside 1951-2006): - Spearman correlations 1980 to 1990 and 1994 to 2004, among those positive in both years; - share of positive person-years at the wage base, by age band; -- AIME under the 35-year rule through age 61 (quartiles, 90th percentile, - share zero), matching `populace_dynamics.ss.statutory_aime.aime`. +- AIME under the 35-year rule, ranking every year after 1950 through age 61 + (quartiles, 90th percentile, share zero), matching + `populace_dynamics.ss.statutory_aime.aime`. The floor artifact holds their EPUF values twice: on EPUF as published, and on EPUF masked the way the career assembler builds a PSID career (nothing -before 1968; each odd year from 1997 filled with the mean of its neighbours). +before `max(1968, birth year + 22)`; each odd year from 1997 filled with the +mean of its neighbours). The difference is exact and involves no PSID: it is what those two rules alone do to administrative careers. The post-lock run adds the PSID career product's values beside the masked EPUF values. Survival to the PSID's @@ -292,12 +432,28 @@ Not certified, at the same prominence: ## 10. Blindness and forking paths -**Order of commits.** The first commit of the pull request holds the reader, -operator, cell statistics, gate algebra, floor builder, their tests and -sections 1-6 and 8-13 of this document. It was pushed before any real-PSID -value in EPUF units existed. The second commit adds the floor artifact, the -draft block and section 7. The artifact records the first commit's sha and -the sha256 of each derivation file; a test fails if one changes afterwards. +**Order of commits.** + +1. `eec910d6` holds the reader, operator, cell statistics, gate algebra, + floor builder, their tests and sections 1-6 and 8-13 of this document. It + was pushed (2026-10-02 13:37 UTC) before any real-PSID value in EPUF units + existed. +2. The floor builder then ran once. While reading its output the drafting + session found a bug in the report-only career AIME (fork 1 below), fixed it + in the next commit, and rebuilt. The first build's outputs are preserved in + the evidence folder with their hashes + (`epuf-20261001/first-floor-build/`, artifact SHA-256 `369bf5ec…7e378`). + The rebuild's window cells, floors, partition and bites are identical to the + first build's; only tranche R's EPUF values differ. +3. The next commit adds the rebuilt artifact, the draft block and section 7. + The artifact records the commit it was built at and the SHA-256 of each + derivation file; a test fails if one changes afterwards. + +**Forks ledger.** + +| # | Change after the first floor build | Partition before | Partition after | Why it is not a self-rescue | +|---|---|---|---|---| +| 1 | Career AIME ranks every year after 1950 through age 61, not only ages 22-61; the career-assembler mask starts at `max(1968, birth year + 22)` | `r6.men`, `r6.women` | unchanged | tranche R is report-only and enters no gated rule; the statute fixes the definition | **Who has seen what, at the first commit.** The drafting session and the design panel saw: EPUF-only values of every cell; EPUF subsampled to PSID @@ -368,7 +524,7 @@ publishes the result whatever it is. ## 13. Ceremony checklist - [x] **Proposal** (this document, the floor artifact, the draft block) -- [ ] Adversarial referee round +- [ ] Adversarial referee round, including the bite pause (section 7.5) - [ ] Fixes - [ ] Verification round - [ ] Ratify by merge of the flip PR diff --git a/docs/design/gate_epuf_block_draft.yaml b/docs/design/gate_epuf_block_draft.yaml new file mode 100644 index 00000000..44dbafb2 --- /dev/null +++ b/docs/design/gate_epuf_block_draft.yaml @@ -0,0 +1,190 @@ +# gate_epuf block draft (registration proposal; lock flip PENDING). +# +# The `gates.gate_epuf` block exactly as the lock flip will add it under the +# top-level `gates:` key of gates.yaml, after gate_m6, with `locked: true`. +# Until then it lives here with `locked: false` and edits no gates.yaml byte: +# any change to gates.yaml moves runs/legacy_manifest_v1.json's pin and three +# others, which only a ratified flip may move. +# +# Rendered by scripts/render_gate_epuf_block_draft.py from +# runs/epuf_gate_floors_v1.json; tests/test_gate_epuf_block_draft.py requires +# this file to equal a fresh render. Proposal and rationale: +# docs/amendments/gate_epuf_registration_proposal.md. +gates: + gate_epuf: + id: epuf_covered_earnings + status: paused_pending_referee_round + locked: false + kind: external_anchor + proposal: docs/amendments/gate_epuf_registration_proposal.md + floor_run: runs/epuf_gate_floors_v1.json + floor_run_sha256: 33e75b96199ce748f0b9aaab0d77d1925405eede93d5e883fa329fde4d87e686 + external_anchor: + source: SSA 2006 Earnings Public-Use File (EPUF), https://www.ssa.gov/policy/docs/microdata/epuf/ + provenance: data/external/epuf_2006/provenance.md + members_sha256: + EPUF2006_DEMOGRAPHIC.csv: 195db459ca7b7c810162cb6e432371e8787eba8331787d2ba1eace1a0da2ccb0 + EPUF2006_ANNUAL.csv: a47315b56214df66fb9f9abcb2caa60779c8b3d091ded199323672c27e3ea105 + disclosure_constants_sha256: ba1f39f238278243de19b8a9d194abedffeabd855f5b97779b685d852f62a881 + covers: 'Tranche G: a candidate generator''s earnings on gate 1''s held-out persons + at the even reference years 1998, 2000, 2002 and 2004, in EPUF''s capped and + disclosed units, scored on the mean of the 20 registered seeds against EPUF + with an allowance for the PSID''s own measured distance from EPUF. Gated cells, + and nothing else: rank persistence of capped earnings from 1998 to 2004 (men; + r6.men); rank persistence of capped earnings from 1998 to 2004 (women; r6.women). + Every other cell is report-only.' + not_certified: + - careers, years without earnings by age 62, and the 35-year AIME (tranche R, + report-only) + - any year before 1998, and 2006 + - ages outside the support's window range (about 25-57) + - the forward earnings law certified by gate_m6 + - that the PSID agrees with EPUF (the bridge is published per cell) + - earnings levels by age, which the generator takes from PSID marginals + validation_only: No candidate may use EPUF in fitting, tuning or calibration; + a candidate that does is scored and labelled a calibration check. + candidate_protocol: + panel: 'gate 1''s candidate panel: for each gate seed s, populace_dynamics.harness.panel.split_panel_by_person(filtered_panel, + ''person_id'', fraction=0.2, seed=s) draws the holdout; the candidate emits + the holdout''s persons on their observed periods with generated earnings' + gate_seeds: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + support: + universe: 'gate 1''s filtered PSID family panel: age 25-59, reference years + 1998-2022, positive weight' + rules: + - a row at each of 1998, 2000, 2002 and 2004 + - last in-filter period 2006 or later + - sex coded male or female (ER32000) + - birth year floor(median(period - age) + 0.5) in 1947-1973 + weight: the person's 2004-row weight + epuf: every EPUF person with sex 1 or 2 born 1947-1973, weight 1 + scoring: populace_dynamics.harness.epuf_run.score_candidate + reproduction: a verdict attaches to a registered candidate only if the run + reproduces that candidate's committed gate-1 artifact exactly + scoring: + estimator: mean over the 20 gate seeds of the per-seed value, then log for + shares, identity for rank correlations + floor: + n_replicates: 100 + half_split_seed: b + holdout_split_seed: 1000 + 20 * b + j + replicate: e_b = [m(A_b) - m(B_b)] / 2 + pooled(m(H_bj)) - pooled(m(T_bj)), + j = 0..19 + k: 4.0 + tolerance: round(mean|e_b| + k * sd|e_b| (ddof=1), 3) + interval: '[min(0, bridge) - t, max(0, bridge) + t]' + eligibility: abs(bridge) + t + 0.8416 * sigma <= cap + caps: + log_ratio: 0.405465 + abs_gap: 0.15 + min_events: 20 + pass_rule: the gate passes iff every gated cell's 20-seed estimate lies inside + its interval + gated_cells: + r6.men: + metric: abs_gap + cap: 0.15 + epuf_value: 0.710865 + psid_value: 0.668048 + bridge_psid_minus_epuf: -0.042817 + tolerance: 0.079 + realized_sigma: 0.024628 + lower: -0.122 + upper: 0.079 + faithful_pass_probability: 0.999348 + r6.women: + metric: abs_gap + cap: 0.15 + epuf_value: 0.672103 + psid_value: 0.639784 + bridge_psid_minus_epuf: -0.032318 + tolerance: 0.078 + realized_sigma: 0.02477 + lower: -0.111 + upper: 0.078 + faithful_pass_probability: 0.99925 + report_only: + r6.men.c0: noise_exceeds_cap + r6.men.c1: bridge_exceeds_budget + r6.men.c2: noise_exceeds_cap + r6.women.c0: noise_exceeds_cap + r6.women.c1: cohort_rung_not_adopted + r6.women.c2: noise_exceeds_cap + zint.men: below_20_events + d_anyzero.men: bridge_exceeds_budget + zint.women: below_20_events + d_anyzero.women: bridge_exceeds_budget + q_atmax.men: bridge_exceeds_budget + q_atmax.women: noise_exceeds_cap + mpers.men: below_20_events + mpers.women: undefined_on_some_split + q_sexratio: noise_exceeds_cap + zint.men.c0: below_20_events + zint.men.c1: below_20_events + zint.men.c2: below_20_events + zint.women.c0: below_20_events + zint.women.c1: below_20_events + zint.women.c2: below_20_events + d_anyzero.men.c0: below_20_events + d_anyzero.men.c1: below_20_events + d_anyzero.men.c2: below_20_events + d_anyzero.women.c0: below_20_events + d_anyzero.women.c1: below_20_events + d_anyzero.women.c2: below_20_events + q_atmax.men.c0: bridge_exceeds_budget + q_atmax.men.c1: bridge_exceeds_budget + q_atmax.men.c2: below_20_events + q_atmax.women.c0: below_20_events + q_atmax.women.c1: below_20_events + q_atmax.women.c2: below_20_events + mpers.men.c0: below_20_events + mpers.men.c1: below_20_events + mpers.men.c2: below_20_events + mpers.women.c0: below_20_events + mpers.women.c1: below_20_events + mpers.women.c2: undefined_on_some_split + faithful_candidate_oc: + analytic_product: 0.998599 + empirical_joint: 1.0 + pause_below: 0.9 + bite_requirements: + persistence: + bite: bd1_persistence_loss_0.10 + required_fail_share: 0.9 + fail_share: 0.44 + met: false + ceremony_pause: true + lock_ceremony: + exists: true + stage: proposal + next: + - adversarial referee round + - fixes + - verification round + - ratify by merge of the flip PR + - 'registration of the first run on issue #42' + history: + - id: 2026-10-02-epuf-registration-proposal + proposed: '2026-10-02' + content: Registration proposed with the rules committed before the floor build + (commit 970a9db721bf); floors in runs/epuf_gate_floors_v1.json. diff --git a/runs/epuf_gate_floors_v1.inputs.json b/runs/epuf_gate_floors_v1.inputs.json new file mode 100644 index 00000000..9bf63ae3 --- /dev/null +++ b/runs/epuf_gate_floors_v1.inputs.json @@ -0,0 +1,25 @@ +{ + "artifact": "epuf_gate_floors_v1.json", + "status": "SOURCE_INPUT_DIGESTS", + "official_source": { + "url": "https://www.ssa.gov/policy/docs/microdata/epuf/epuf2006_csv_files.zip", + "archive_sha256": "0bb97275cc35a1bb42d34d26acbc9df720d4f875854ba1d02c50323d2357003b", + "archive_bytes": 291602034, + "archive_members": [ + "EPUF2006_DEMOGRAPHIC.csv", + "EPUF2006_ANNUAL.csv" + ], + "retrieved": "2026-10-01", + "provenance": "data/external/epuf_2006/provenance.md" + }, + "staged_inputs": [ + { + "path": "EPUF2006_DEMOGRAPHIC.csv", + "sha256": "195db459ca7b7c810162cb6e432371e8787eba8331787d2ba1eace1a0da2ccb0" + }, + { + "path": "EPUF2006_ANNUAL.csv", + "sha256": "a47315b56214df66fb9f9abcb2caa60779c8b3d091ded199323672c27e3ea105" + } + ] +} diff --git a/runs/epuf_gate_floors_v1.json b/runs/epuf_gate_floors_v1.json new file mode 100644 index 00000000..f014618a --- /dev/null +++ b/runs/epuf_gate_floors_v1.json @@ -0,0 +1,7325 @@ +{ + "schema_version": "epuf_gate_floors.v1", + "run": "epuf_gate_floors_v1", + "status": "DRAFT_NOT_OPERATIVE", + "purpose": "Pre-lock floors, bridges, partition and operating characteristic of the proposed EPUF covered-earnings gate (docs/amendments/gate_epuf_registration_proposal.md). No candidate was generated or scored to build it.", + "ceremony": { + "step": "pre-lock floor", + "draft_block": "docs/design/gate_epuf_block_draft.yaml", + "gates_yaml_untouched": true + }, + "candidate_blind": { + "generated_candidates": 0, + "psid_read_through": [ + "populace_dynamics.data.family.family_earnings_panel", + "populace_dynamics.data.deaths.read_death_records" + ] + }, + "design": { + "window_years": [ + 1998, + 2000, + 2002, + 2004 + ], + "cohort_bands": { + "c0": [ + 1947, + 1955 + ], + "c1": [ + 1956, + 1964 + ], + "c2": [ + 1965, + 1973 + ] + }, + "gate_seeds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "holdout_fraction": 0.2, + "floor": { + "n_replicates": 100, + "half_split_seed": "b", + "holdout_split_seed": "1000 + 20 * b + j", + "replicate": "e_b = [m(A_b) - m(B_b)] / 2 + pooled(m(H_bj)) - pooled(m(T_bj)), j = 0..19" + }, + "k": 4.0, + "tolerance": "round(mean|e_b| + k * sd|e_b| (ddof=1), 3)", + "interval": "[min(0, bridge) - t, max(0, bridge) + t]", + "eligibility": "abs(bridge) + t + 0.8416 * sigma <= cap", + "caps": { + "log_ratio": 0.4054651081081644, + "abs_gap": 0.15 + }, + "min_events": 20, + "epuf_noise_share_max": 0.1, + "oc_pause_below": 0.9, + "support": { + "universe": "gate 1's filtered PSID family panel: age 25-59, reference years 1998-2022, positive weight", + "rules": [ + "a row at each of 1998, 2000, 2002 and 2004", + "last in-filter period 2006 or later", + "sex coded male or female (ER32000)", + "birth year floor(median(period - age) + 0.5) in 1947-1973" + ], + "weight": "the person's 2004-row weight", + "epuf": "every EPUF person with sex 1 or 2 born 1947-1973, weight 1" + } + }, + "inputs": { + "epuf_sha256": { + "EPUF2006_DEMOGRAPHIC.csv": "195db459ca7b7c810162cb6e432371e8787eba8331787d2ba1eace1a0da2ccb0", + "EPUF2006_ANNUAL.csv": "a47315b56214df66fb9f9abcb2caa60779c8b3d091ded199323672c27e3ea105" + }, + "disclosure_constants_sha256": "ba1f39f238278243de19b8a9d194abedffeabd855f5b97779b685d852f62a881", + "psid_panel": { + "n_universe_persons": 22300, + "n_present_all_four_years": 6323, + "n_and_anchor_2006_or_later": 5775, + "n_and_sex_coded": 5775, + "n_support_persons": 5769, + "by_sex_and_band": { + "men.c0": 898, + "men.c1": 926, + "men.c2": 679, + "women.c0": 1059, + "women.c1": 1269, + "women.c2": 938 + }, + "reference": "runs/noise_floor_psid_family_9822.json" + }, + "gate1_run": "runs/gate1_rank_knn_v5.json" + }, + "epuf_support": { + "n_persons": 1311282, + "n_sex_unspecified_dropped": 3054, + "by_sex_and_band": { + "men.c0": 217559, + "men.c1": 244637, + "men.c2": 214306, + "women.c0": 204942, + "women.c1": 228276, + "women.c2": 201562 + } + }, + "holdout_ids": { + "0": { + "n_persons": 4427, + "n_support_persons": 1122, + "sha256_sorted_person_ids": "4cb1de0fb3e0ac3fce77701d869d6ae4fa9021b0166ca9b131315f3ad3357374" + }, + "1": { + "n_persons": 4495, + "n_support_persons": 1123, + "sha256_sorted_person_ids": "03010683999147a0aaeea472616e199599110605f90835ec892582f65bee9834" + }, + "2": { + "n_persons": 4477, + "n_support_persons": 1156, + "sha256_sorted_person_ids": "b3991d08922cf61bd14cb6ad1338c5f466bbb9f982a2485d080614f3fb52d3bb" + }, + "3": { + "n_persons": 4464, + "n_support_persons": 1145, + "sha256_sorted_person_ids": "a6354930f9c93095b22a67240aca70f5cd178debde11c9901710919954605f01" + }, + "4": { + "n_persons": 4530, + "n_support_persons": 1216, + "sha256_sorted_person_ids": "ba890a7017580d411bdbf320ee8cfc7faa5c1b261ffa99718aef63685f0bafe0" + }, + "5": { + "n_persons": 4514, + "n_support_persons": 1199, + "sha256_sorted_person_ids": "ea7c6074fff5592249c44000982c4c348d192263a316f676d47331500ed4c5f1" + }, + "6": { + "n_persons": 4476, + "n_support_persons": 1185, + "sha256_sorted_person_ids": "0a419703d9d010a1fab433122940f99b14df9068b816f16fe7c79659b3073895" + }, + "7": { + "n_persons": 4415, + "n_support_persons": 1135, + "sha256_sorted_person_ids": "819edeab9b1bd0ef0e1ee61264fc078792b106a59850f544a7c23f909d01886d" + }, + "8": { + "n_persons": 4336, + "n_support_persons": 1135, + "sha256_sorted_person_ids": "6f5a5df17b9a2d5f6dd29ee7eb3b9ce9a268e781cc63748ab1da54a7870736c9" + }, + "9": { + "n_persons": 4570, + "n_support_persons": 1150, + "sha256_sorted_person_ids": "5c50d7ff89ba8e4dd62f07a26c0545504d2a735038f5c1402183fa9e2496eeaf" + }, + "10": { + "n_persons": 4472, + "n_support_persons": 1168, + "sha256_sorted_person_ids": "9802ae0db85b3f4b65a424142e1835a572c63b7c051b2bf696a140602aee60fa" + }, + "11": { + "n_persons": 4517, + "n_support_persons": 1172, + "sha256_sorted_person_ids": "8c0fb2d1be76e8b061065b56541a6480b29a3c4f6a973caaa59b3c5d409f6863" + }, + "12": { + "n_persons": 4371, + "n_support_persons": 1074, + "sha256_sorted_person_ids": "ecde12f32dcc3396d5dc06c892f7780923689b5497ee5f76409795798355fd9b" + }, + "13": { + "n_persons": 4500, + "n_support_persons": 1176, + "sha256_sorted_person_ids": "3e5cf7ea85e667d2d3fbc2db59644fe3dc0bde40f724465c4773ebbb5d49e7dc" + }, + "14": { + "n_persons": 4522, + "n_support_persons": 1203, + "sha256_sorted_person_ids": "ac1c6fe33ba8589207fa97dec38a7aef0619f02526cdcab6d6f27bfb6fec21aa" + }, + "15": { + "n_persons": 4431, + "n_support_persons": 1197, + "sha256_sorted_person_ids": "e1ee767d29f165d31bf311573d74e383682fd74673fafbe30af94386d7310dc0" + }, + "16": { + "n_persons": 4449, + "n_support_persons": 1091, + "sha256_sorted_person_ids": "a03afcf9dbcdfacdc904700ca6a4af87662a367b8be1e3d517615ba93b7bc108" + }, + "17": { + "n_persons": 4500, + "n_support_persons": 1219, + "sha256_sorted_person_ids": "952dca2e5073733757a5b4e221165e0ef653829a1aab446b431e023abe338425" + }, + "18": { + "n_persons": 4484, + "n_support_persons": 1161, + "sha256_sorted_person_ids": "0b916d24ac009af2f7627d9c17a090356b4be32534aedb62495474a52407d0df" + }, + "19": { + "n_persons": 4442, + "n_support_persons": 1114, + "sha256_sorted_person_ids": "b523492d09cc174b732365471e5d7f43898666c45e70bb362f4f0a257f6ac7f5" + } + }, + "cells": { + "r6.men.c0": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7370421835844408, + "epuf_sampling_sd": 0.0018305516902764774, + "psid_value": 0.6672906355952744, + "psid_n": 761, + "bridge_psid_minus_epuf": -0.0697515479891665, + "min_events": 117, + "floor": { + "replicates": [ + -0.021057863545390687, + 0.005396951744537859, + -0.022140410128426824, + 0.025021545388600075, + 0.08090669852605714, + 0.05185027865511649, + 0.016794308434623928, + -0.10011827388689826, + -0.024237969517333424, + -0.013245233208305951, + -0.04216234141941877, + 0.010716703700710761, + 0.0006821034331753739, + -0.0008204335464723211, + 0.011027202618145215, + 0.0053241259492661785, + -0.019671686265050614, + -0.019331781853036745, + -0.04742270569341556, + 0.03397612606842643, + -0.011605842253357979, + -0.04885139883534573, + -0.04916743681449015, + -0.013474994749749392, + 0.040763563650294654, + 0.03567329519440554, + -0.03316450288499512, + -0.07985433330656666, + 0.0006265838940183177, + -0.003987738693373211, + 0.05290865061354899, + -0.004554467118761507, + 0.018015630812510064, + -0.021894293171350276, + 0.011863273084325832, + 0.01740196798047622, + 0.029875797972318374, + -0.01951656760773801, + -0.005593398659512583, + -0.014945415799800188, + 0.03927087480527963, + -0.03142262465626888, + 0.07861098001423272, + -0.12246342620200945, + -0.087649243277725, + -0.040477640372615864, + 0.06769334395409582, + 0.10905652523773424, + -0.0745428129563484, + -0.014444356631236221, + 0.001428319951245427, + 0.04077191644635836, + 0.03126801311893557, + -0.00582044137729959, + -0.04444123730715843, + -0.016177171436451143, + 0.00018819190183044787, + 0.02721703000343173, + -0.04368975633898614, + 0.004681596715681913, + -0.006304469830752668, + -0.0405106857812782, + 0.008806625317474281, + -0.06309129364433164, + -0.10621244899640575, + -0.04551930831053469, + 0.0645692946861004, + 0.009522525304856755, + -0.058785493066160766, + -0.0061032307925567575, + 0.05892139382187411, + -0.029212646938726994, + -0.05367027567368576, + -0.026882717053679672, + -0.0006696469747782263, + 0.07605402317137755, + 0.004180502089620841, + -0.08641595573349009, + -0.04166965308123255, + -0.011463380582869276, + -0.0770682986643067, + 0.0006048175205705109, + 0.04427714704983621, + 0.007990478634442633, + -0.015854755774779294, + -0.035144739897731925, + 0.01474565439819836, + 0.03937408778116824, + -0.04431453238230115, + 0.06143695254986736, + -0.0013879727248156115, + 0.00540336989636786, + -0.017501200590685828, + -0.009153705439037929, + -0.004518229782560945, + -0.07530319514502642, + 0.05915339320332369, + 0.05671152801268187, + -0.07748287213549782, + -0.0159521519989152 + ], + "mean_abs": 0.03408904053818175, + "sd_abs": 0.02875212805809537, + "realized_sigma": 0.04450259210432828, + "shared_noise_variance_share": 0.7182212591062277, + "tolerance": 0.149 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.219, + "upper": 0.149, + "minimum_detectable_gap_80": 0.2562058744532035, + "faithful_pass_probability": 0.9996008668738419, + "real_gate_holdouts": { + "estimate": 0.6743897728658892, + "gap_from_epuf": -0.06265241071855165, + "lower": -0.219, + "upper": 0.149, + "pass": true + } + }, + "r6.men.c1": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7517419621933827, + "epuf_sampling_sd": 0.0016814240619831553, + "psid_value": 0.7364055754959135, + "psid_n": 800, + "bridge_psid_minus_epuf": -0.015336386697469284, + "min_events": 120, + "floor": { + "replicates": [ + 0.01195576149536709, + -0.011219621670494784, + 0.013234877643894472, + -0.027217841496278983, + -0.003270938433287851, + -0.025532376989664318, + -0.021209633500452685, + 4.866123392899269e-06, + -0.06641866832389959, + 0.046116105545360886, + -0.0579049771738554, + -0.02487693371448424, + 0.04017544128320011, + 0.0007210050851538252, + -0.019895475130828455, + -0.04944754580043331, + -0.025344122978150696, + 0.004528678415250342, + 0.038497607130094924, + 0.012431885808830756, + 0.008602925993228927, + -0.03365723315457164, + 0.017149924312509057, + -0.002539862527080994, + 0.028305713310952885, + 0.08355329648234372, + -0.008868715681024097, + 0.027506876417028925, + 0.026171000423383106, + 0.08892044677715683, + -0.03778826771514182, + -0.0192152366799197, + -0.03423153659661682, + 0.0015768350387953545, + 0.03170184284576949, + -0.012485798989317232, + 0.007977856688259288, + 0.00887184107297917, + -0.013010500724199625, + -0.012568059579313506, + 0.003067329251639439, + 0.02437243533903255, + -0.054139043749243776, + -0.021362647557728542, + -0.031546458863387916, + -0.000572605775903845, + -0.006015345846570153, + -0.04674480399546532, + -0.007234298370190573, + -0.029806262446545106, + -0.028733019802124338, + -0.057941806353586756, + -0.03753264844793469, + -0.02693768054803275, + 0.03223527774839707, + 0.02137571785987763, + -0.05595723930827712, + 0.010734066350931493, + 0.008314704662883254, + 0.013260694685304164, + -0.006212162467210791, + 0.012944519198155147, + 0.010228999360785196, + -0.0414946055712182, + -0.0029705689817093317, + 0.04935760839837444, + 0.0011230328622329755, + 0.013105726364229353, + -0.06180819739705529, + -0.054209626673627664, + -0.015736164361947358, + -0.027062052547180415, + 0.01862721346634394, + 0.04097384531849618, + -0.001515614908966234, + -0.003800415764501297, + -0.022586709984411257, + -0.05532237365879483, + 0.027229610357893064, + -0.03204242165865284, + -0.013733170228488134, + -0.0012810727862572202, + -0.005637151434103815, + 0.02462089300216458, + 0.03054194604687238, + -0.04198390653207967, + 0.0012113801113280975, + -0.12193822326899306, + 0.03003353407680076, + -0.002641623797151882, + -0.021776385662239217, + -0.041076389479891395, + -0.0037397504996202757, + -0.03190534867499417, + -0.015554643086684417, + -0.017996525269547592, + 0.04768481575268052, + 0.007315752432949851, + 0.0629534774511597, + 0.018138169032649698 + ], + "mean_abs": 0.025627078496434662, + "sd_abs": 0.02158187008847976, + "realized_sigma": 0.03343451057834227, + "shared_noise_variance_share": 0.7892871921677226, + "tolerance": 0.112 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.128, + "upper": 0.112, + "minimum_detectable_gap_80": 0.15547558073432036, + "faithful_pass_probability": 0.9995538255975308, + "real_gate_holdouts": { + "estimate": 0.744942897785964, + "gap_from_epuf": -0.006799064407418731, + "lower": -0.128, + "upper": 0.112, + "pass": true + } + }, + "r6.men.c2": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.6438111652856673, + "epuf_sampling_sd": 0.001932701247990694, + "psid_value": 0.6004466040215929, + "psid_n": 621, + "bridge_psid_minus_epuf": -0.0433645612640744, + "min_events": 89, + "floor": { + "replicates": [ + 0.036239059227876735, + 0.034111370819834785, + -0.08977016650873579, + -0.008259532803103764, + -0.00466836934238779, + -0.025146463006230968, + 0.05499408162714925, + 0.06048267995408246, + -0.014208796631361376, + 0.01276510979394746, + 0.015068547796980747, + 0.095570841731905, + -0.056598926991726695, + 0.002837093143295555, + 0.013255518924018606, + -0.02233066193331562, + -0.03320428541939008, + 0.037669039173345464, + 0.020774095214502186, + -0.03246495895229701, + 0.04532059808539535, + -0.0035119836008826733, + -0.021597915964290726, + -0.06625979760158307, + 0.02422827275550332, + 0.05465560760929555, + 0.00890568498152755, + -0.0562207037577927, + -0.05664518567861154, + -0.0392369457254097, + -0.019066768905181997, + 0.007990876515124645, + 0.05089061325906452, + 0.04764605740031935, + 0.018470320023949105, + 0.051886962805775705, + 0.030091708941708872, + -0.04768938247107951, + 0.07673530525687727, + 0.05035123291656046, + -0.05978428136630454, + 0.014326140198183401, + -0.023756513538007562, + 0.04285909485313305, + -0.02392159887062112, + 0.08087933645467305, + 0.02803009304482501, + -0.0682510465936193, + -0.06020646929398149, + 0.004650137811546162, + 0.0713863070470594, + 0.08333227547169286, + 0.04172475028681577, + -0.07332963876011006, + 0.05181307342737085, + 0.020857373381929167, + 0.047476597837703804, + -0.017097969043722128, + -0.02284468436086534, + 0.04785735353991061, + 0.005222992433157492, + 0.0076408461420038876, + 0.018336288248974708, + -0.07086864288317096, + -0.07927866147554496, + -0.008383593022862235, + 0.015125390931530425, + -0.040071161516133325, + 0.05530196920616459, + -0.06073984434006224, + 0.03742459374201501, + 0.03715604166316866, + -0.05821394700748683, + -0.08218718837945233, + 0.06621899064745462, + 0.01770837560018751, + 0.03764790047638211, + -0.0035120723224087436, + -0.0546703685729214, + -0.04570613192480588, + 0.00871183781807, + -0.07346189804618686, + -0.013004575269209118, + -0.0280514297315827, + -0.12489948891489511, + 0.03349757398347969, + 0.09844685435869516, + -0.07479178668749353, + -0.044726412759420076, + -0.024811457798850578, + -0.014873680613234186, + -0.024482919871826936, + -0.015532411330050566, + 0.10747568845382549, + -0.04824694939455232, + -0.06002314869398678, + 0.0003721070815784766, + 0.06998653666592325, + 0.006544858189350411, + 0.03475565693887267 + ], + "mean_abs": 0.040403185315704665, + "sd_abs": 0.026781145783177748, + "realized_sigma": 0.04839912039924274, + "shared_noise_variance_share": 0.8781733988756965, + "tolerance": 0.148 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.192, + "upper": 0.148, + "minimum_detectable_gap_80": 0.23209828867832907, + "faithful_pass_probability": 0.9988949665049346, + "real_gate_holdouts": { + "estimate": 0.5818069602089632, + "gap_from_epuf": -0.06200420507670412, + "lower": -0.192, + "upper": 0.148, + "pass": true + } + }, + "r6.women.c0": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7177630429235712, + "epuf_sampling_sd": 0.0022793864174730115, + "psid_value": 0.6688335948077175, + "psid_n": 776, + "bridge_psid_minus_epuf": -0.048929448115853647, + "min_events": 121, + "floor": { + "replicates": [ + -0.025598767704403558, + 0.004324162885140037, + 0.015930166333267437, + -0.04689155487268737, + 0.016349694572241225, + 0.013566054117711224, + 0.013916401849683846, + -0.03050062593762276, + 0.00035086260248595735, + -0.03294753373468634, + -0.024423132963451055, + 0.05651446786833941, + -0.03796257194534797, + 0.036952136458281826, + -0.0822593653945386, + 0.005380637163796442, + 0.027039772218785507, + 0.04455534614791207, + -0.04955407808154705, + -0.001985010121798192, + -0.02821880407030114, + -0.0534250673524036, + 0.09632953643255576, + -0.050481519189487845, + 0.05435559156263153, + -0.004505804039738659, + -0.09388807084999717, + -0.040218172424239695, + 0.021610981967773557, + -0.0098136120107859, + -0.04628450754022406, + 0.0790928504638162, + -0.012333765099855398, + -0.028131000224770997, + 0.027525917603127503, + 0.022308237305243284, + -0.008727912204573529, + 0.016000440762479806, + -0.011290276939371291, + 0.03238917036683148, + -0.011464843410475933, + 0.07007307784834221, + 0.015445562328478268, + 0.02248302681565334, + -0.02630872373327131, + -0.05726664856778213, + -0.03039581892244586, + -0.010191692451961276, + 0.01345092789121316, + -0.005162743564838257, + -0.04432682917886277, + -0.0075007888279635115, + 0.11667661513072419, + -0.018601848146532374, + -0.058256204692082314, + 0.06877016972193134, + 0.0055004948239142926, + -0.006817002759317792, + -0.0163545480764844, + -0.03000091176470021, + -0.005563171906729614, + -0.08655215469157668, + 0.0402478690379684, + -0.00799682310190758, + 0.01956056653480065, + 0.024879672972170863, + -0.04231567748016968, + -0.07650372502440894, + -0.10009040866763597, + 0.06894130394636722, + -0.013055758457699573, + 0.03355833201159403, + 0.0704209405588247, + 0.0348435581144092, + 0.00869282324536541, + 0.04233360542821557, + -0.010119631620083336, + 0.06251601763203357, + -0.02300352466210115, + 0.06250296747944567, + -0.0674714146862056, + -0.04565143371726238, + -0.07946352756665304, + -0.029073202533154263, + 0.06978103146319636, + 0.07745803691123998, + -0.05758915225402983, + 0.00022739060758714125, + 0.006276030704074231, + -0.011122810089990165, + 0.018738982718483344, + -0.03480815367153306, + -0.02507582416385562, + -0.0038431344632028352, + -0.014980156004955336, + -0.07475173659921247, + 0.05283933654107281, + -0.049099382021192184, + -0.07227347790148447, + 0.07343063591402094 + ], + "mean_abs": 0.036366354431468254, + "sd_abs": 0.027040503363193486, + "realized_sigma": 0.045237027627251326, + "shared_noise_variance_share": 0.7252454351731714, + "tolerance": 0.145 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.194, + "upper": 0.145, + "minimum_detectable_gap_80": 0.2320018911106729, + "faithful_pass_probability": 0.9993200715125318, + "real_gate_holdouts": { + "estimate": 0.6318574755692126, + "gap_from_epuf": -0.08590556735435861, + "lower": -0.194, + "upper": 0.145, + "pass": true + } + }, + "r6.women.c1": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7026652344743403, + "epuf_sampling_sd": 0.0018466001551114115, + "psid_value": 0.7199216271832825, + "psid_n": 930, + "bridge_psid_minus_epuf": 0.017256392708942192, + "min_events": 148, + "floor": { + "replicates": [ + -0.012495614463988947, + -0.013268068329840732, + -0.021808945134435043, + 0.003459282966340682, + 0.006409564365645548, + -0.07298552329704089, + 0.02417423466997215, + -0.01889284423278048, + 0.027533196177212893, + -0.0034336834239842573, + -0.027157623948940834, + -0.015756779219479933, + -0.027465064136925788, + 0.006907323852385905, + 0.02199339232517039, + 0.044070360203807946, + 0.02193625900074303, + -0.021578968036096324, + -0.05485911329726334, + 0.0011586796476533712, + 0.014758310060015822, + -0.010831620390670205, + 0.05166698764171962, + 0.030670015409929474, + -0.053617830001822964, + -0.01116246693614853, + 0.015472616587935806, + -0.003267730635749533, + -0.006346332961541856, + 0.06186761450810885, + -0.001056615592264054, + 0.02906942845932281, + -0.010882821746472038, + 0.011274874901586629, + 0.012411046767446643, + -0.030098203828534342, + 0.051457037206824985, + -0.04832158311192475, + -0.0157439220395173, + 0.027597391691839335, + -0.0034325318070640987, + -0.011774914645492685, + 0.04260751540184449, + -0.0170598065994369, + 0.013404062752792545, + 0.037928515683807784, + 0.005659796262513228, + -0.06803342671320767, + 0.025543993780553997, + -0.0399563960143538, + 0.041448555382403496, + -0.0026376792297608254, + -0.04158609763361154, + -0.018777351867392156, + -0.02459364629036037, + 0.023641516602900203, + -0.021669129774723572, + -0.016262254655373454, + 0.010814826922454945, + -0.001003443103226087, + 0.000553583981614092, + -0.016374993750317923, + 0.007440738512325962, + 0.0031818058567170127, + -0.029631380625303405, + -0.028022676422357673, + -0.010484466189926822, + 0.029059541326916183, + -0.023940203579545016, + 0.001651380058835139, + 0.0699112847385665, + 0.03924891878514536, + 0.027602377465709038, + 0.011794247271936176, + 0.01602259414920204, + 0.015324081214608765, + 0.01726883298032661, + 0.00504448225595211, + 0.006828705569294491, + 0.010615859748085876, + 0.006424998054513853, + -0.03820186271626452, + -0.011260340237157718, + -0.0018808850775204333, + 0.005554176884328466, + -0.0004051667131188541, + 0.036607465595282884, + 0.027634093849734087, + -0.01148993392384301, + 0.03895075016638072, + 0.023036857873763805, + -0.02019312016615349, + 0.025840412723840356, + -0.0437301078600999, + -0.0036572195507122984, + -0.028146452105467457, + -0.06094789705088938, + 0.018414661472333727, + 0.004231638376235858, + 0.0038229391219454234 + ], + "mean_abs": 0.021931875663346298, + "sd_abs": 0.01724455244480441, + "realized_sigma": 0.027846148984085314, + "shared_noise_variance_share": 0.8079859780730623, + "tolerance": 0.091 + }, + "eligibility": "eligible", + "gated": false, + "report_reason": "cohort_rung_not_adopted", + "lower": -0.091, + "upper": 0.109, + "minimum_detectable_gap_80": 0.13169230296718323, + "faithful_pass_probability": 0.999456689357935, + "real_gate_holdouts": { + "estimate": 0.7252632586986001, + "gap_from_epuf": 0.022598024224259827, + "lower": -0.091, + "upper": 0.109, + "pass": true + } + }, + "r6.women.c2": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.5958794147877823, + "epuf_sampling_sd": 0.002163351705962211, + "psid_value": 0.5305971313131903, + "psid_n": 670, + "bridge_psid_minus_epuf": -0.06528228347459197, + "min_events": 101, + "floor": { + "replicates": [ + 0.10490601974383912, + -0.049314288499141073, + 0.010352014054280378, + -0.02597200810672534, + 0.02535370431684794, + 0.0518698373173235, + -0.10891350465849209, + 0.02067772516017874, + 0.036937875571853435, + 0.012375571789912138, + -0.019213584150096497, + -0.03251905106552003, + -0.01643157039886306, + 0.045749892898595435, + -0.05584954987391616, + -0.010132174448693437, + -0.006662614236828179, + -0.07329157361277813, + 0.03005766464998985, + -0.0037253920687714825, + 0.005006982000467952, + -0.01441776025392244, + 0.06100494148868377, + 0.01754342970816647, + 0.03898963344399747, + 0.061674154511149715, + -0.03217681791249055, + 0.03726431677067138, + -0.045830284128855925, + -0.04642262704767397, + 0.06909903392705449, + 0.033972166318559954, + 0.023524363611518967, + 0.030653790703022182, + -0.021705593164337234, + -0.019307561897643044, + -0.011227202295264915, + 0.05522162257604907, + -0.060533357834957086, + 0.011373680276743653, + -0.06516009109286902, + 0.04105277224293569, + -0.10290286580759447, + -0.06912593657376015, + 0.06321067096874095, + -0.09064528247206052, + -0.01673805651358007, + -0.017219137846226668, + 0.10990674903634495, + -0.016121176431398043, + -0.06479457589433071, + 0.024037657823169856, + -0.04845097121496644, + -0.05519287514862481, + 0.040812534024120634, + -0.059754319013949564, + -0.121164462599408, + 0.0012978415220585848, + 0.00802563129991446, + -0.01922462762898164, + -0.05263406449646835, + -0.06251037557024633, + -0.07331340624286814, + 0.03794024039579397, + -0.11215742799143702, + -0.0067290957054826905, + 0.02740531725248463, + -0.00903057397278767, + 0.005245922803151282, + 0.019096821334580683, + 0.015744092971736734, + -0.07384853213925968, + -0.07052719974009367, + -0.009115618567828193, + -0.049747291755972006, + 0.020780008606603062, + -0.009556800742561933, + 0.026213548790071817, + -0.07655278831239481, + -0.004018932726478575, + -0.07790052349302415, + 0.02761517637180172, + -0.020174757303220103, + -0.04990407996147492, + 0.06941339569768579, + 0.08025414086147978, + 0.056456478071275656, + 0.08307038931185856, + 0.07117740272772527, + 0.07794453100910506, + -0.05488289300067717, + -0.023898610904488304, + -0.08338064643796675, + 0.014818399014677242, + -0.007755773869001975, + 0.04881010880360803, + -0.0027498883874668145, + 0.07403016339205201, + 0.1289350573969411, + 0.05175030553163096 + ], + "mean_abs": 0.043391839533143746, + "sd_abs": 0.03060602988505856, + "realized_sigma": 0.05301144699724714, + "shared_noise_variance_share": 0.7584175456816651, + "tolerance": 0.166 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.232, + "upper": 0.166, + "minimum_detectable_gap_80": 0.27589784288990027, + "faithful_pass_probability": 0.9991629717379075, + "real_gate_holdouts": { + "estimate": 0.5248843871065718, + "gap_from_epuf": -0.07099502768121047, + "lower": -0.232, + "upper": 0.166, + "pass": true + } + }, + "zint.men.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.04612282019850528, + "epuf_sampling_sd": 0.014194897912778011, + "psid_value": 0.06374851572258607, + "psid_n": 761, + "bridge_psid_minus_epuf": 0.32363805830954506, + "min_events": 3, + "floor": { + "replicates": [ + -0.04655022311978052, + 0.15597766650080813, + 0.00878782017470936, + 0.2973885867304944, + 0.0035311813756737642, + 0.01621474114216115, + -0.41523657285641646, + -0.26060284375268905, + -0.06383197800957463, + -0.03394239742429561, + 0.466462997347203, + -0.04198290552652284, + -0.16904002791963646, + 0.12055732001787445, + -0.1602677810282298, + -0.03536330493517004, + 0.1367899766676084, + -0.029020646429642527, + -0.09666022931039753, + -0.003956650792959815, + -0.09221359998259637, + 0.1262261422623514, + 0.020919946963622982, + 0.17440405510751877, + 0.025553538231047, + -0.03493824111281629, + 0.17246362342858346, + -0.08259346276357404, + -0.18391773203979267, + 0.12421970520935122, + 0.08524741138498726, + -0.10806630715170851, + -0.16161588018957862, + 0.19082877808034926, + 0.29015279823634943, + 0.2874455224566492, + 0.16620602003264295, + 0.11037924741166694, + -0.1823534073523545, + 0.10087755382988561, + -0.18003585563913238, + -0.26480749539471393, + 0.27699252548319797, + -0.5050706075467057, + 0.40769368722964905, + -0.0573469130575448, + 0.17257819422642018, + -0.04776624174600275, + 0.12600856715560416, + 0.06882720240560203, + -0.021331389006895574, + 0.2318748900999319, + 0.17614285185276302, + 0.015719900230762862, + -0.10217717994297026, + -0.056061320788513, + 0.05202099364154078, + -0.0019270638298052312, + -0.461518243999711, + 0.24096766462623642, + 0.06323143463241432, + -0.45506414176261667, + 0.11715499996759271, + 0.04646432288698521, + 0.01916200414764946, + -0.21296992363884515, + 0.15861898376404482, + 0.005575320480244894, + -0.18503097441948513, + -0.08016962762229207, + -0.006998062912959568, + 0.07633347432294868, + -0.3949745081971232, + 0.10853057471565597, + 0.10852936641189714, + -0.13496707511650485, + 0.3421461728477171, + 0.15828275681009107, + -0.05919981328812596, + -0.07303438078028623, + -0.14314513226425363, + 0.06578406056619479, + 0.026473122724732345, + 0.08812854593896713, + 0.1261384560420602, + 0.141898826971822, + 0.04714434896700026, + 0.07442385669994178, + 0.03349800351339294, + -0.011939143744578828, + -0.11164180570974302, + -0.04213653513544213, + 0.2563818716736419, + -0.20521444620736173, + -0.3106305826125304, + -0.16473054701833534, + 0.06737737803681343, + 0.1743928723268655, + -0.028634930508075085, + 0.283955512836068 + ], + "mean_abs": 0.13959765510416275, + "sd_abs": 0.11754835741728505, + "realized_sigma": 0.18211794386816352, + "shared_noise_variance_share": 0.8052600092673866, + "tolerance": 0.61 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.61, + "upper": 0.934, + "minimum_detectable_gap_80": 1.0869123868836317, + "faithful_pass_probability": 0.9995979266730952, + "real_gate_holdouts": { + "estimate": -2.7819891329688065, + "gap_from_epuf": 0.2944583033383519, + "lower": -0.61, + "upper": 0.934, + "pass": true + } + }, + "zint.men.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.04939929809793205, + "epuf_sampling_sd": 0.009072210108223067, + "psid_value": 0.04302662854033297, + "psid_n": 800, + "bridge_psid_minus_epuf": -0.13811702314318808, + "min_events": 0, + "floor": { + "replicates": [ + -0.014328335055329378, + 0.09415714450228374, + 0.2414400187041459, + -0.23731707952033343, + -0.15615064451259997, + 0.3554436910456942, + 0.060918726485909014, + 0.11140018331568236, + 0.6677258723505699, + -0.3397582570602129, + -0.1214833164593625, + 0.04101819921134919, + -0.011276367869076154, + 0.1703464394908929, + 0.18273203280384265, + -0.1446267840752271, + 0.6804741571213866, + 0.13836492622884022, + 0.33395300834871633, + -0.5269205049976775, + 0.3767293022957232, + -0.30126797246759107, + 0.050482741486243876, + -0.3965517708081636, + 0.0063508668526415235, + -0.028861623906210276, + 0.3776464581044714, + -0.19396725395736825, + 0.2380839151997689, + 0.14796188804410693, + 0.274058786128516, + -0.050389709129245785, + 0.022916741064188173, + 0.37835233903150023, + 0.4509194739258231, + 0.28896466949624955, + 0.1781529989847126, + 0.10859799553454219, + 0.34674587483341934, + -0.059866966040254876, + -0.02253693957903158, + 0.3709092632999742, + -0.17302567008190595, + 0.1766068329613768, + 0.08019802288814937, + 0.17404957726141457, + 0.03039982992204604, + 0.17067747681459755, + 0.20162663379958534, + -0.2964312380904979, + -0.07268342933589711, + 0.4899361728062721, + 0.4214669869803016, + -0.10526303649709545, + -0.5244669295476705, + -0.1632279723047232, + -0.11801329270639349, + -0.03715614454738847, + -0.016013285409479883, + -0.5891457641657767, + -0.1723694647515588, + 0.13366308650811098, + -0.15226053228244285, + -0.008048706950201323, + -0.4368128900564252, + -0.0813794550675766, + 0.7197215938694841, + 0.25660162388825314, + 0.01578529967924358, + -0.25083813357746854, + -0.02922618213474837, + -0.05724732157956969, + -0.48429774942642734, + -0.07269592344999665, + 0.19591346068109328, + -0.2005852695704844, + -0.07206215321474674, + -0.026139012954925045, + -0.7941836435037055, + 0.19990703610219995, + -0.406692894195283, + -0.3121721374615063, + 0.2788883774906643, + -0.020409666879324995, + 0.2542045528804906, + 0.34617898890778, + -0.3045010455137751, + 0.3480892260341508, + -0.06783864107571858, + -0.07346901916863624, + 0.3324677447097244, + 0.02670920003222621, + -0.32342082140828143, + 0.11413764143435712, + -0.010162211423442091, + -0.0015658962422773204, + 0.1978324917559251, + 0.23694374518195072, + 0.3035840360253086, + -0.711064514636897 + ], + "mean_abs": 0.22170610927155834, + "sd_abs": 0.18296520108117634, + "realized_sigma": 0.28687122729012177, + "shared_noise_variance_share": 0.7910531798488605, + "tolerance": 0.954 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -1.093, + "upper": 0.954, + "minimum_detectable_gap_80": 1.3335539393316762, + "faithful_pass_probability": 0.9994932672059756, + "real_gate_holdouts": { + "estimate": -2.888252963039785, + "gap_from_epuf": 0.11956610039330329, + "lower": -1.093, + "upper": 0.954, + "pass": true + } + }, + "zint.men.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.05776751410682007, + "epuf_sampling_sd": 0.011481765143101334, + "psid_value": 0.04049494629719925, + "psid_n": 621, + "bridge_psid_minus_epuf": -0.35524939445916504, + "min_events": 0, + "floor": { + "replicates": [ + -0.4325132560574507, + 0.026435327397104746, + -0.09777216071751793, + 0.5676537831821507, + 0.13202966902985058, + -0.14187878346013605, + -0.2317921254254678, + -0.2885197965116282, + -0.14464689577383494, + -0.06997094017855399, + -0.3958852944550475, + 0.10923729330491971, + 0.3006550611333496, + 0.008907499320431667, + -0.2925846897974327, + -0.12373305088954756, + 0.014798475397111543, + -0.08811186147620487, + 0.12404772138833575, + -0.008383071695250655, + -0.015781441446637068, + 0.28377083510695233, + 0.34173624208352527, + 0.00670425210084824, + 0.21444763972561387, + 0.14863061377867348, + -0.1574485311431526, + -0.13124432701499944, + 0.1699951233861443, + 0.19162896249128147, + -0.15372372321197103, + -0.3917211052673488, + 0.17871979966512974, + -0.1643774892241996, + 0.009293547778314926, + -0.35714813760191055, + 0.0664524714949093, + -0.2563486090632283, + -0.24833350691463818, + 0.06065537717121172, + -0.15037860158905247, + -0.2204363783228105, + 0.26202566954463613, + 0.153192398905579, + 0.06637423752944382, + -0.2389761875111922, + 0.10016745130806637, + 0.5024789859472436, + 0.37912013044014214, + 0.01882748709995319, + -0.15220088841614055, + -0.24474398067426772, + 0.08393898120934629, + -0.11140877909727154, + -0.41168784840785344, + 0.18293173400502583, + 0.1294290167123926, + 0.3638209187666883, + 0.3369118842522607, + -0.36526823620863236, + -0.5526939034866287, + 0.3051494831950945, + 0.13813039161486773, + 0.274245362393956, + -0.10849468913806692, + 0.1503188775969566, + 0.06591443609678338, + -0.4639056069874741, + -0.07498069864732204, + 0.5840297586604746, + 0.14811250327184555, + -0.18347272531889725, + 0.28867943243205585, + -0.3651393976351487, + 0.02406261718624525, + -0.1707460900693094, + -0.060816434570763356, + 0.1847603352385061, + 0.27119075633197753, + -0.12786385530903566, + -0.05511163549857856, + -0.5095175008483253, + 0.04175633587846539, + 0.4849738723027388, + -0.26080508878078357, + -0.040584366888632095, + 0.51417864164003, + 0.49484712935411657, + 0.42761555808422425, + -0.008834539927055296, + 0.12268260452136404, + -0.23878982837755336, + 0.25589828574777007, + 0.25609384751024455, + 0.36604851300741625, + -0.00024704655081353444, + -0.10348457714473125, + 0.2022112726150449, + 0.03721354037718805, + -0.13333784768508372 + ], + "mean_abs": 0.20718977676131586, + "sd_abs": 0.14936403797743847, + "realized_sigma": 0.25497867220008874, + "shared_noise_variance_share": 0.84965212730423, + "tolerance": 0.805 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -1.161, + "upper": 0.805, + "minimum_detectable_gap_80": 1.3748448590909876, + "faithful_pass_probability": 0.9992086679522362, + "real_gate_holdouts": { + "estimate": -3.1854622085996853, + "gap_from_epuf": -0.33413350761798366, + "lower": -1.161, + "upper": 0.805, + "pass": true + } + }, + "zint.women.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.04953213817227809, + "epuf_sampling_sd": 0.013716525747986593, + "psid_value": 0.05188914732730771, + "psid_n": 776, + "bridge_psid_minus_epuf": 0.046487946027435445, + "min_events": 2, + "floor": { + "replicates": [ + -0.3122493831099178, + 0.09447402264576166, + 0.1572391779104818, + 0.32617470999187903, + -0.0820116506563553, + 0.11065392760922488, + -0.11579305314754706, + 0.39666083249205886, + -0.20801964677025775, + 0.26574360171447164, + -0.10394399988758929, + -0.14384959842774814, + -0.07642990698162855, + -0.13047907043188256, + 0.09411624576798827, + 0.32665312083507314, + 0.32712939095500904, + 0.007605535339593628, + 0.23876800570897472, + 0.2473437442283346, + 0.02420292358894205, + 0.052637628400742376, + 0.08133446557079593, + 0.08672437150861434, + 0.216300876127677, + -0.08813940374077012, + 0.2502878536518356, + -0.1125087223597594, + -0.23109413110884214, + 0.28701953527672575, + 0.1470707201685164, + 0.11809361777456218, + -0.16938093455289138, + -0.27731575418707743, + -0.003868805540703235, + -0.32366842442039334, + -0.39239089196769994, + -0.13786317068209164, + 0.2981864480370031, + -0.16673174924531975, + -0.028526418118344665, + 0.15084939499438077, + 0.05388167187048776, + -0.010701858046224366, + 0.24399014717225764, + -0.05049027368781167, + -0.2636642627302619, + -0.005031540485799457, + -0.39640623684038134, + 0.08163529544967929, + -0.13893977205704933, + 0.1394823926275186, + -0.4283741792800795, + 0.2291359729344129, + -0.14431936378427168, + -0.27035636690831577, + -0.31800926260437823, + -0.02628237250582388, + -0.13431862843760944, + 0.03087153394609765, + -0.21092347592188943, + 0.2677783642080187, + 0.13092152826657233, + 0.32448098332626896, + 0.27069702939233964, + -0.35873282157015196, + 0.08284375305297753, + -0.2208280987441409, + -0.02230080461567341, + -0.06688980327138472, + 0.11773701592910246, + 0.001482078838410894, + -0.10058768273910834, + -0.13437238903373605, + -0.13416781508739284, + 0.16562015150877807, + 0.23605343684831315, + -0.030250951107833934, + 0.22265232605126206, + -0.3277051121869856, + 0.10699562068825297, + 0.1806722068849873, + 0.2624773822561681, + 0.39455543927332637, + -0.115645922330601, + -0.10865303840323493, + -0.299374589669019, + -0.09930583091439282, + -0.17859487666285445, + -0.07388191520412124, + 0.025368921196273764, + -0.10687709583269589, + 0.149170979602969, + 0.04265256104391413, + 0.029874449540316927, + -0.23418300841287443, + -0.023926633995295044, + 0.06495056076142691, + 0.21042093412367602, + 0.0166064361689362 + ], + "mean_abs": 0.16526640021669603, + "sd_abs": 0.11053028345032793, + "realized_sigma": 0.19851387146645164, + "shared_noise_variance_share": 0.807120715910488, + "tolerance": 0.607 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.607, + "upper": 0.654, + "minimum_detectable_gap_80": 0.8205614354123654, + "faithful_pass_probability": 0.998396860296134, + "real_gate_holdouts": { + "estimate": -2.8552258175416814, + "gap_from_epuf": 0.1499077465356904, + "lower": -0.607, + "upper": 0.654, + "pass": true + } + }, + "zint.women.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.06229546347068492, + "epuf_sampling_sd": 0.009719862568026, + "psid_value": 0.07214555729600632, + "psid_n": 930, + "bridge_psid_minus_epuf": 0.14679710172798321, + "min_events": 4, + "floor": { + "replicates": [ + 0.13580325599168264, + 0.39415687369818353, + -0.0989286858415388, + 0.029921154426276075, + 0.15748393138947825, + -0.19602522351188978, + 0.06306565209790027, + -0.20884067697725306, + 0.05190547708264659, + 0.028326792679646662, + 0.03711573583526695, + -0.2512632814133682, + 0.02173669408569312, + -0.043278975337938785, + 0.007450711862019954, + -0.36063658764859086, + -0.08264916570299374, + -0.21939813190081314, + 0.0025806797302696527, + 0.1101275042058254, + 0.422589803263546, + 0.2607012035701639, + 0.2082016820968473, + -0.20942685333656752, + 0.0584000339906412, + 0.026073401102441718, + 0.0186346340839596, + -0.12278917918020094, + 0.0656858061204757, + 0.15274806343783243, + 0.09945903856340221, + 0.007636807271456991, + -0.13551137624427323, + -0.41022982435962696, + 0.0676318398723903, + -0.26244492642949635, + 0.013981740448352209, + -0.03719255389455367, + 0.14744089253591497, + 0.1604979585928148, + -0.12253245189927076, + -0.027598427389479596, + -0.01972884252814988, + 0.06857917581932171, + 0.0009047314723011901, + 0.26568230952705196, + 0.44198745757360114, + -0.14472233824230707, + -0.20442826419955962, + 0.2161045455787367, + 0.0766605569362373, + 0.050064694778060304, + 0.05680630039443191, + 0.14360040182550082, + -0.011265559268922365, + 0.10702382023140267, + 0.03936901437422802, + 0.1790990315801484, + -0.21536231005277573, + -0.32192952206484327, + -0.27704516517378064, + 0.07689623678253188, + -0.16100988855753018, + 0.14722927926072016, + 0.14411502790426822, + -0.042179685552598656, + -0.20080577037257608, + 0.4894768503911797, + 0.053259699669789384, + 0.13653244481573124, + 0.3524813979627144, + 0.2864938675965314, + 0.25345010169864346, + 0.05649213383067653, + -0.04441936805709634, + -0.1347206046587459, + 0.12393483282157858, + 0.14385900148187636, + 0.16011518157243265, + -0.11783264648256053, + 0.24226037707510706, + -0.3867534256676528, + -0.0849279949688364, + 0.049391287905437675, + 0.12346704276894349, + 0.12267410053795147, + 0.22023561232815458, + 0.1371341728578519, + -0.33227507262198297, + 0.06880897042303191, + 0.18397513969738966, + 0.04186181826614188, + 0.3308803598063821, + 0.11648809785199243, + 0.3278703545405717, + 0.029435734884602383, + -0.07555085079201973, + -0.41573888671122305, + 0.03266962070398316, + -0.1320320435895339 + ], + "mean_abs": 0.14958202714192917, + "sd_abs": 0.11753035374075863, + "realized_sigma": 0.18986846250447284, + "shared_noise_variance_share": 0.8397382082305642, + "tolerance": 0.62 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.62, + "upper": 0.767, + "minimum_detectable_gap_80": 0.9265944313575902, + "faithful_pass_probability": 0.999428657297769, + "real_gate_holdouts": { + "estimate": -2.6403871772898224, + "gap_from_epuf": 0.13547949603522236, + "lower": -0.62, + "upper": 0.767, + "pass": true + } + }, + "zint.women.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.08531100121766358, + "epuf_sampling_sd": 0.00981867541735719, + "psid_value": 0.0856936146279939, + "psid_n": 670, + "bridge_psid_minus_epuf": 0.004474897322680249, + "min_events": 3, + "floor": { + "replicates": [ + 0.06736233932160385, + -0.09061111766108576, + -0.05708120248201287, + 0.31669957625997425, + -0.08481582222579087, + -0.3160979097620302, + -0.038139374475324894, + 0.45985426174457067, + 0.03275657953012345, + -0.10774173013387123, + -0.19947574583066086, + -0.2861896591632431, + 0.21926313768117978, + -0.29328137461826054, + -0.28347478839181695, + 0.2646442087493528, + -0.1849301294312078, + -0.035396014353386684, + -0.09301272150407103, + -0.2195741937976794, + 0.056137921339340036, + 0.23937790583876262, + -0.14047119957304144, + 0.1859094413205853, + 0.27814604770307594, + -0.2986044825278864, + -0.056298496290390077, + 0.0017348824076806046, + 0.01017325534182989, + -0.06519068552896412, + 0.12203962167772109, + -0.16867211426084494, + -0.09394969963916688, + -0.23235102852426315, + 0.014954765798022018, + -0.14980694642133408, + 0.07565430481993407, + -0.10583798376130127, + 0.0989627766414658, + -0.29408491034122064, + 0.31665908118800323, + -0.007628087365198821, + 0.11898252469886406, + -0.0014352572540923259, + -0.2238664913710311, + 0.013956321486558343, + -0.04607866112209247, + -0.016185258027588967, + 0.11880600222063253, + 0.4007964422916157, + 0.13480793784392708, + 0.1880884894873296, + 0.1763014437322452, + 0.010053355198704983, + 0.12657822289057963, + -0.00024929508753879226, + -0.08554985741532506, + 0.15932918174110688, + 0.14364098769006062, + -0.08625853761406255, + 0.3328567749988025, + -0.07685835594713897, + 0.1362504996042364, + 0.22538754509112402, + 0.14134591880377378, + -0.07013953170660336, + -0.0045472627781959485, + 0.1460966900016203, + -0.07107514288286021, + 0.14745056553135027, + 0.2842568529549727, + 0.12253170183169759, + -0.11639069010250291, + 0.022738474077931725, + -0.003762448351361636, + 0.30479875950122026, + 0.07595901533400906, + 0.17473245694471085, + -0.009342038720254742, + 0.1635305462076153, + -0.05039934727519202, + 0.08134622982764461, + -0.1350346629426511, + -0.07311787884583731, + 0.2343391978633722, + -0.049099727696587214, + 0.1560439174239967, + 0.060376151324134986, + -0.27493003361898194, + 0.13045731459230625, + 0.07479415652960553, + 0.13236700353442155, + 0.1299223868718804, + 0.07654102425812925, + 0.23578093836427816, + -0.05574941851599413, + 0.012561101504733108, + -0.2417966409990835, + -0.13972032715031113, + -0.08485420853962822 + ], + "mean_abs": 0.13773294731651387, + "sd_abs": 0.10102474482569057, + "realized_sigma": 0.1705118877173041, + "shared_noise_variance_share": 0.8817502195582486, + "tolerance": 0.542 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.542, + "upper": 0.547, + "minimum_detectable_gap_80": 0.689981322602164, + "faithful_pass_probability": 0.9985925146505304, + "real_gate_holdouts": { + "estimate": -2.5301252781431414, + "gap_from_epuf": -0.0686734162413587, + "lower": -0.542, + "upper": 0.547, + "pass": true + } + }, + "d_anyzero.men.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.11174854735725806, + "epuf_sampling_sd": 0.007585313405558821, + "psid_value": 0.1134530894274814, + "psid_n": 799, + "bridge_psid_minus_epuf": 0.015138208107779327, + "min_events": 6, + "floor": { + "replicates": [ + -0.029260482752089034, + 0.13679940340352026, + 0.07705469085609784, + 0.03211843882554355, + 0.11486040798780706, + 0.12420331702839671, + -0.08472805696846142, + -0.017394716184427228, + 0.0513594287044119, + -0.07504824985709901, + 0.19470947082332035, + -0.017944257008175812, + -0.21212089047182103, + 0.14702773781452927, + -0.17263692314850942, + -0.058712522327699634, + 0.0948790734418099, + 0.000532453737849492, + -0.031637608479723855, + -0.08939389571787304, + -0.06303428197962746, + -0.03728791532102149, + 0.04991068288536882, + 0.15069911000644165, + 0.12875256584678807, + -0.02473594454620276, + 0.19137029363422775, + -0.1528167978379995, + -0.07101858935300953, + 0.05629640705349126, + 0.12665256829205207, + 0.02358951318768643, + -0.05116900147583481, + 0.005505775066714902, + 0.12152181937565709, + 0.12711814155260237, + 0.26134389943113423, + 0.2170629476904764, + -0.10755208999778598, + 0.08068822465977199, + -0.21743725376711165, + -0.4399993674953777, + 0.04966999278685402, + -0.38166438229874133, + 0.30253369163087784, + -0.14427931495436797, + 0.03382643904039284, + 0.17900625650349777, + -0.013263084423460025, + 0.11790077407303423, + -0.05711693333891632, + 0.23853782155829606, + 0.15503863826971154, + 0.07563099096699721, + 0.05716433293239098, + -0.0486419462268628, + -0.034845869234483295, + 0.03365655790440192, + -0.3310643471290158, + 0.22456728939646387, + 0.005632567952937428, + -0.11722496217237355, + 0.1514682746524818, + 0.18236053787325668, + -0.03313990167434788, + -0.13196447996922345, + -0.0354829512581043, + -0.0021651216942417673, + -0.03131002491104273, + -0.1243996501242397, + 0.008701661765123436, + -0.035794560727537617, + -0.2567737928687226, + 0.05999567870739897, + -0.014907482579986198, + -0.13447364324993272, + 0.03990929648699337, + 0.09374039569837755, + -0.16982539402228713, + -0.03604398511312845, + -0.06564932417713254, + 0.12024773983821091, + 0.11484309234561607, + 0.13013974449159083, + 0.08335522719666155, + -0.04127547915423446, + -0.033001403185783484, + 0.1984283533846234, + 0.09655320165224479, + -0.09412400890822048, + 0.029532335387060016, + -0.0580681280747144, + 0.3350060546151137, + -0.08278230773256245, + -0.05394757262015415, + -0.06495305287470621, + -0.13658136463223158, + 0.04261656171874795, + 0.15323644991315633, + -0.008899524722040697 + ], + "mean_abs": 0.10554949168790861, + "sd_abs": 0.08678853275361863, + "realized_sigma": 0.13637309895623315, + "shared_noise_variance_share": 0.7711407154923847, + "tolerance": 0.453 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.453, + "upper": 0.469, + "minimum_detectable_gap_80": 0.5829127038774854, + "faithful_pass_probability": 0.9992640616721213, + "real_gate_holdouts": { + "estimate": -2.1833041606992407, + "gap_from_epuf": 0.008199883913902806, + "lower": -0.453, + "upper": 0.469, + "pass": true + } + }, + "d_anyzero.men.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.1207520381057067, + "epuf_sampling_sd": 0.006516360998945018, + "psid_value": 0.1033160760107626, + "psid_n": 851, + "bridge_psid_minus_epuf": -0.15594618259593584, + "min_events": 7, + "floor": { + "replicates": [ + -0.3630472583763116, + 0.19875842577037606, + 0.03170176319690565, + -0.11008741749484008, + -0.040831275236310915, + -0.1492970981525985, + 0.2487602011171084, + 0.0548190984038075, + 0.504613989296346, + -0.29036442856700684, + 0.12885659585999187, + 0.07920212098254531, + -0.11069698496954228, + 0.018464859632182362, + 0.057798115425166774, + 0.11544044319366309, + 0.3100863906717619, + 0.038777620248873435, + 0.035486425245268016, + -0.11553323125600024, + 0.09047335804870227, + -0.15428477893440218, + 0.07053320989938472, + -0.1953139337664307, + -0.19461440344492442, + -0.009868440456330507, + -0.16963387023806842, + -0.1691046432814325, + 0.04853228630172479, + -0.03734370703512857, + 0.07760702602297265, + -0.04227023870274471, + -0.014655952218312729, + 0.4978105685982672, + 0.10759775442952213, + 0.2529414420731815, + 0.2569452965473855, + 0.1299994167384504, + -0.03704549784539801, + 0.17707381400322353, + -0.042430891021173256, + 0.12472791327462796, + 0.048853783328549394, + 0.09984769875219435, + 0.1239416711595398, + 0.18858478182750416, + 0.013108035081344394, + 0.1403039637631449, + 0.2408835347645646, + -0.1986816096299413, + -0.19956070906354717, + 0.17588563768551224, + 0.12777289441025608, + 0.04077494867544651, + -0.049750508916838854, + -0.16494241410318722, + -0.002379588857293724, + -0.017090638749129416, + -0.02709859607152665, + -0.212632436261184, + -0.2493189374521685, + -0.02162083766400902, + -0.01940893795773513, + -0.06288835520517844, + -0.1683055707345973, + 0.04887154723211351, + 0.3330629429760108, + -0.07519107534041791, + 0.052860685016435704, + -0.26020925392984307, + -0.17901474704340403, + -0.16413324072734414, + -0.09605009276201604, + -0.027051899038974536, + 0.23932190457881664, + 0.08598106532712668, + -0.09289102458354304, + -0.1874196773065091, + -0.1752121297029121, + -0.000948377443837245, + 0.00672859634187839, + 0.07973412648654521, + 0.055098641542078886, + -0.09315755218131261, + -0.10630130371360114, + 0.08117995687104007, + 0.20456419513547486, + 0.08784162642222038, + -0.04892541288154706, + -0.18397514314107055, + 0.3420062418751213, + -0.08483964998855065, + -0.4549379284924244, + 0.03155136447989082, + -0.05503701193409327, + 0.11011555987625088, + -0.04604424101609128, + 0.325685506209928, + 0.11472891247327799, + -0.26336798801745376 + ], + "mean_abs": 0.13291108898181944, + "sd_abs": 0.10762123927675528, + "realized_sigma": 0.1706805946977075, + "shared_noise_variance_share": 0.6564372184049466, + "tolerance": 0.563 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.719, + "upper": 0.563, + "minimum_detectable_gap_80": 0.862594595252379, + "faithful_pass_probability": 0.9995019900470593, + "real_gate_holdouts": { + "estimate": -2.160749939477582, + "gap_from_epuf": -0.046733831607891574, + "lower": -0.719, + "upper": 0.563, + "pass": true + } + }, + "d_anyzero.men.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.1530368274404898, + "epuf_sampling_sd": 0.005238972057206756, + "psid_value": 0.07515067155904992, + "psid_n": 650, + "bridge_psid_minus_epuf": -0.7111835422465012, + "min_events": 4, + "floor": { + "replicates": [ + -0.21141905137494454, + 0.026862770302403582, + -0.05400073395660665, + 0.41140416378920697, + 0.3701310151330095, + -0.21455557388624902, + -0.0901352660316348, + 0.10984983778473478, + -0.2201616288722681, + 0.03619345681469355, + -0.32295476997015893, + 0.015064433855552117, + 0.1410406414366696, + -0.054405886400692216, + 0.03725048226692218, + 0.03648770814289226, + 0.022131153840547757, + 0.004178563206376662, + 0.03660097188969602, + 0.06177030314361631, + 0.054928029370135745, + 0.31688921834394246, + 0.3419336038388969, + -0.07319635931448065, + 0.2713898242305153, + 0.1130854435999058, + 0.0679476366741325, + -0.044813573311728305, + 0.34036753402030273, + 0.14750954725116872, + -0.27110246049391806, + -0.30411675873626565, + 0.3723100371053074, + -0.04525448701682966, + 0.10778246319526841, + 0.06418390134547591, + 0.07465914096871318, + -0.169110957079871, + -0.2576303553114989, + 0.09253753909046969, + -0.08920441204866458, + -0.3444572154665353, + 0.2513462787914371, + 0.07636903519485139, + 0.049067996252233126, + -0.03803106822641, + -0.029119077430062257, + 0.2819687934049129, + 0.03652228820260772, + 0.06474132975426605, + -0.14990632800195858, + -0.27482314333165925, + -0.0005052178219340231, + -0.03880409094010395, + -0.24448794602911206, + 0.09265556542403619, + 0.08753983644687002, + 0.2832970506279602, + 0.10926451044923713, + -0.079466373532731, + -0.3254034510364232, + 0.27641198594914784, + 0.060762560852406944, + 0.01466470625932459, + -0.18625497626877796, + 0.23143277417054842, + -0.04793938602231562, + -0.22785174400275543, + -0.07682021180509357, + 0.27853862536410134, + -0.06868193135767453, + -0.20773634488178372, + 0.24818792040273951, + -0.07411901320526271, + -0.024435813770844694, + 0.012768420804408098, + 0.08716032656419492, + -0.11322664688495765, + 0.11556483406781437, + -0.029280700397253057, + -0.16115352962413199, + -0.007504161772715401, + 0.011542571229546716, + 0.28258312068018054, + -0.018822747941898532, + -0.1439425933119396, + 0.06832318934126391, + 0.06746002696414077, + 0.2818057395593796, + 0.03425873728890516, + 0.15968068828639548, + 0.0693740231562967, + 0.030835182513816006, + -0.012622762034519397, + 0.14755715924707946, + 0.05755756258623279, + -0.03820157029896509, + -0.07071479610971343, + -0.023606905579299786, + -0.11783500204166786 + ], + "mean_abs": 0.13141549283411202, + "sd_abs": 0.10933328178693909, + "realized_sigma": 0.17059970866936366, + "shared_noise_variance_share": 0.8197671429192506, + "tolerance": 0.569 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -1.281, + "upper": 0.569, + "minimum_detectable_gap_80": 1.4237638795039906, + "faithful_pass_probability": 0.9995812267827784, + "real_gate_holdouts": { + "estimate": -2.5016111633847213, + "gap_from_epuf": -0.6245344790563103, + "lower": -1.281, + "upper": 0.569, + "pass": true + } + }, + "d_anyzero.women.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.14444050852127366, + "epuf_sampling_sd": 0.006938591086387653, + "psid_value": 0.10727608634965125, + "psid_n": 834, + "bridge_psid_minus_epuf": -0.2974619594432444, + "min_events": 7, + "floor": { + "replicates": [ + -0.020123356335037368, + -0.01306206117043951, + 0.1476619583568648, + 0.32802853294551226, + -0.06942273184275294, + -0.016621415502744874, + -0.12859055891887428, + 0.2996108457127994, + -0.15427353721910775, + 0.1698602153071409, + 0.03581159402781653, + -0.015289136575569406, + 0.028898553839364904, + 0.14427138564433384, + 0.00844411191680039, + 0.11215558812069104, + 0.09212677485978271, + 0.013582679202676085, + 0.21642994598254428, + -0.06020739472129688, + 0.10665936916464358, + -0.06131836218811593, + -0.03250458523861077, + 0.010725813506375914, + 0.08804574512555052, + -0.1219694686395345, + 0.07230995734777368, + -0.07595855519959427, + -0.12021675852169023, + 0.19235602259767548, + 0.018847765685482187, + 0.05233217736242324, + -0.09752481067538343, + -0.12711552858086694, + -0.01893515003429802, + -0.24990516224361947, + -0.18045058191407648, + -0.026738845832260605, + 0.08481544855639078, + -0.015655199762610206, + 0.042489892055552314, + 0.12396583611282908, + 0.008144610151723963, + -0.016306969279003436, + 0.10577342232905407, + 0.03954827005018835, + -0.1878400285722115, + 0.01572957057658031, + -0.24347867997790162, + 0.02364491747119235, + -0.11799101013170654, + 0.09465513285383387, + -0.09085246352403531, + 0.14223689091489367, + -0.09902861127954043, + -0.13791491165357805, + -0.24077654617287436, + -0.1330508018099592, + 0.07921521531973852, + -0.04261953679209918, + -0.2113706547021459, + 0.14977596038270646, + 0.055346995171236424, + 0.2014020750041623, + 0.2324179694492412, + -0.2119000014897503, + 0.10834379971614028, + -0.2854811774579602, + -0.055115143763993846, + -0.12520282254489246, + 0.0021130973792089502, + -0.18148053473223635, + -0.0006191476675723173, + -0.22021964107148673, + -0.09899826889176144, + 0.013717556515621787, + 0.0626442995833063, + 0.0252761339922023, + 0.11078332407804825, + -0.0630040466231887, + 0.06645291686753407, + -0.036999678754178866, + 0.1768333294632014, + 0.18077674569112756, + -0.14034949537085661, + -0.02170450848411054, + -0.16705088821853797, + -0.10621253354219995, + 0.07505214718031494, + -0.24150334994121803, + -0.12180668700133057, + -0.12384254805168515, + 0.1982352949822379, + 0.10985910883137273, + -0.08530133795021588, + -0.05796832010324082, + 0.13737721998662566, + 0.02099284460104034, + 0.30097448330282384, + 0.10433007286889762 + ], + "mean_abs": 0.10702957164817235, + "sd_abs": 0.07827503305548618, + "realized_sigma": 0.13236706614196123, + "shared_noise_variance_share": 0.7790638644577595, + "tolerance": 0.42 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.718, + "upper": 0.42, + "minimum_detectable_gap_80": 0.8288648929340693, + "faithful_pass_probability": 0.9992560876085015, + "real_gate_holdouts": { + "estimate": -2.186808462523323, + "gap_from_epuf": -0.25192090058446737, + "lower": -0.718, + "upper": 0.42, + "pass": true + } + }, + "d_anyzero.women.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.18121376454974378, + "epuf_sampling_sd": 0.005907556785781356, + "psid_value": 0.15932157915084325, + "psid_n": 1021, + "bridge_psid_minus_epuf": -0.12875268394030193, + "min_events": 15, + "floor": { + "replicates": [ + 0.1322823309654655, + 0.16785611248860266, + -0.013820184984114414, + 0.03624483616738172, + 0.04825469509435931, + 0.02081210605191841, + 0.010676882140787103, + -0.0023636982116762573, + -0.060013208049847444, + 0.009636663990038818, + 0.0034192069186129714, + 0.007291552139760293, + 0.010849169803740066, + 0.13383595862989828, + 0.03927608819891626, + -0.16605902413055362, + 0.10902282183531387, + 0.01078575137391291, + 0.07196113431358808, + 0.13227503105820204, + 0.23009859056847481, + 0.055623557925539746, + 0.21842694518483807, + -0.09317265446137502, + 0.027753524760368187, + 0.16235209039276743, + -0.008230191315222513, + -0.05771094278553712, + -0.09465019298252719, + 0.13099334248023764, + 0.07641880567827652, + -0.11052226588270142, + 0.021757362998970242, + -0.15499201994379297, + -0.006368758180960721, + -0.12533016738581515, + 0.07712311509670433, + -0.05014891337378946, + 0.16547081479407277, + 0.027285837326386786, + -0.06374566175521479, + -0.04270451114854723, + 0.14136150605826125, + -0.01040524849632618, + 0.07003031279531957, + 0.039209372027868006, + 0.16389130500041527, + -0.06810615694622435, + -0.05591537484579412, + 0.07245269944111077, + 0.07287952087629246, + 0.13730040383350117, + -0.04170826299142072, + -0.06854937100303349, + -0.07248932337348468, + 0.09746634264897391, + -0.03019530335922349, + 0.05490187406490854, + -0.11032712605559503, + -0.14003932713962086, + -0.191419986287087, + -0.026178587089460525, + -0.08408289434465732, + 0.16893207692625323, + -0.011009952426729197, + -0.03263469221267046, + -0.15534194256306433, + 0.15478733989621973, + 0.09678519620970272, + 0.08084901632301955, + 0.06379574263512333, + 0.1251663683475185, + 0.09981565935585901, + 0.15124941467162045, + 0.013112522624175171, + -0.097163118538373, + 0.08462225346147134, + -0.16000489728673395, + 0.27714013657963166, + -0.005112632885726498, + 0.02447329367860862, + -0.11917764405552178, + -0.006636103632803758, + 0.01933693292672445, + 0.0476437503755911, + 0.022933321971606357, + 0.014402393318956874, + 0.012496542117265586, + -0.02823215501745191, + -0.009419840643037802, + 0.20960923052905267, + 0.0360278180109882, + 0.08884055853876471, + -0.027790132323703864, + 0.2074291942490698, + 0.038333150001632066, + 0.0067701619554140224, + -0.28517291807527634, + 0.03557898843693896, + -0.15442538546053175 + ], + "mean_abs": 0.08108779499910222, + "sd_abs": 0.06586539015226778, + "realized_sigma": 0.10425976031781281, + "shared_noise_variance_share": 0.8332751932740721, + "tolerance": 0.345 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.474, + "upper": 0.345, + "minimum_detectable_gap_80": 0.5614999120309959, + "faithful_pass_probability": 0.9995331122412535, + "real_gate_holdouts": { + "estimate": -1.808562059297702, + "gap_from_epuf": -0.10048413433818548, + "lower": -0.474, + "upper": 0.345, + "pass": true + } + }, + "d_anyzero.women.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.21506408205915595, + "epuf_sampling_sd": 0.005405600768118903, + "psid_value": 0.18668260282743956, + "psid_n": 754, + "bridge_psid_minus_epuf": -0.1415261760999349, + "min_events": 13, + "floor": { + "replicates": [ + -0.07792183798813335, + -0.03940744410876984, + -0.04343657794878342, + 0.14693024600374438, + -0.05305620284289936, + -0.04328324092496927, + 0.01705563985672154, + 0.2199548569898826, + 0.03373791200225784, + -0.045153429787722854, + -0.09204997827458306, + -0.16829826711349005, + 0.10867213019949873, + -0.2013481790529269, + -0.029186680766952744, + 0.2617894665765649, + -0.021837562857652704, + 0.036602665712578863, + 0.029124444871476696, + -0.10273247308602296, + 0.002664196196948354, + 0.14912153989713262, + -0.050901366767989176, + 0.07964249081273156, + 0.08981134331149543, + -0.059310857980187426, + -0.08297587959485275, + 0.12150567734275242, + 0.039106878866450256, + -0.06502026100721714, + 0.006817961773541326, + -0.036873128287411516, + -0.049291540904339515, + -0.20047436009077468, + 0.06702429555861289, + -0.016511568280761835, + 0.048412825547791805, + -0.05672082046496629, + 0.19996098222363945, + -0.2187243962228168, + -0.057606782510344345, + 0.039032328209208766, + -0.08540571440807765, + 0.03934135801911132, + -0.1757226604968235, + -0.10378699656423473, + -0.03142256980935787, + -0.09121027399792947, + 0.11946037469102544, + 0.20950965799053411, + 0.0700009789734436, + 0.12488444885660366, + 0.14731427641383976, + 0.04152962686714279, + 0.01394488834477925, + 0.05830416657343995, + -0.11994803383253638, + -0.0001367409958056287, + 0.028156351236734323, + 0.03784723338546947, + 0.1819480068054118, + 0.11278807157211668, + 0.08961195200726169, + -0.017067530194204372, + 0.04308279278753224, + 0.07262798713545005, + 0.09565277823827267, + 0.19124304070329656, + -0.23961164314356553, + 0.10430759277625579, + 0.07456283499910576, + 0.07375105187042796, + 0.019919837555936404, + -0.01477969695660053, + 0.041933018041058534, + 0.21885325246453802, + -0.046855336485522314, + 0.05356484808124007, + 0.0011562204574586676, + -0.002040648435235992, + 0.04030097495784024, + 0.04097180841313652, + -0.011713220110509903, + 0.01303818492521569, + 0.16324270217796089, + 0.0264459710423528, + -0.17055742799012585, + 0.11653608044854868, + -0.08985325800336441, + 0.08980054118350522, + 0.19376605905833322, + 0.07675212190082825, + -0.0686484098816249, + 0.033559542065267345, + 0.07488255026172386, + -0.021781258460202957, + 0.008231106599279503, + -0.12796659509847297, + 0.15973730196234792, + -0.03198465403908757 + ], + "mean_abs": 0.08262144979564708, + "sd_abs": 0.06402161859293053, + "realized_sigma": 0.10432681312644755, + "shared_noise_variance_share": 0.7491023487968095, + "tolerance": 0.339 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.481, + "upper": 0.339, + "minimum_detectable_gap_80": 0.5683298372581467, + "faithful_pass_probability": 0.9994288778480935, + "real_gate_holdouts": { + "estimate": -1.6851184774499817, + "gap_from_epuf": -0.14829923827471303, + "lower": -0.481, + "upper": 0.339, + "pass": true + } + }, + "q_atmax.men.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.15384588473191108, + "epuf_sampling_sd": 0.005687323396499473, + "psid_value": 0.22561493263149526, + "psid_n": 3219, + "bridge_psid_minus_epuf": 0.38287835533939907, + "min_events": 76, + "floor": { + "replicates": [ + 0.006268685924624817, + -0.06896157523881219, + -0.10736535434214345, + 0.009809698333810402, + 0.021413338562194406, + 0.06790947318243346, + -0.07983344782546675, + -0.027532304530521357, + 0.02760053337609336, + -0.0514393446196485, + 0.0719505769082811, + -0.04121058188815041, + -0.11704566781748127, + -0.08721754537211557, + -0.05048162440363735, + 0.08269285775315183, + 0.06507796191611226, + 0.09955747917297675, + -0.02880405748015591, + -0.061770402170215566, + 0.009798995421709034, + -0.02913558626663526, + -0.005306509864348885, + 0.045349053163840636, + 0.015873904996704602, + -0.05032111183866317, + -0.07260515730103267, + 0.03406762329277613, + -0.06594104446621807, + 0.05343256122032136, + -0.042029934707843664, + 0.1799505976702117, + -0.03815374511172265, + -0.11969250201631465, + -0.09660977202977439, + -0.003346920904507944, + -0.011746728185735189, + -0.12321117698678286, + -0.08720033595971421, + -0.10459949434018478, + -0.0845386794828098, + -0.08516967906407436, + 0.014754349692642776, + 0.08385497822013599, + -0.002928533950293244, + 0.01322929854039634, + -0.02292125024718983, + 0.012159815137235519, + 0.07732732724329183, + 0.016750723788165223, + -0.04801041608027945, + -0.20623864678802528, + 0.08296337412535193, + -0.048546391364383545, + -0.045197065125143654, + 0.1472851931689595, + 0.011018295050580162, + -0.011764679117148513, + 0.07934367153176003, + -0.010892772217998559, + 0.09088637401617294, + -0.0966682567558611, + 0.0426477525380794, + -0.08882224550986417, + -0.03172439513420455, + 0.047438640569666846, + 0.17632818683030382, + 0.023241245788923948, + -0.06135038447035168, + 0.0002076527781937898, + 0.02478098341365831, + -0.013961397266538222, + 0.13169922512580734, + -0.10209687137056689, + 0.008917280725322163, + 0.03421656171441412, + -0.04889091610871299, + -0.041806641048157234, + -0.06957059302666535, + -0.008506119703374004, + 0.015346606752661196, + 0.1136912041391992, + -0.12531139417489523, + -0.06048714094073426, + 0.01722875461217177, + -0.03998221750138231, + -0.012843583462227914, + 0.10469144781803641, + 0.05989198595879608, + -0.09728379351999439, + -0.03438940306391125, + 0.068085539184645, + -0.08029637796343203, + 0.07231944767347342, + -0.03850095836419232, + -0.07189132042339652, + -0.024567563796850433, + 0.11136414615486878, + -0.15072484340041603, + -0.11114914440961032 + ], + "mean_abs": 0.06021019003708668, + "sd_abs": 0.0435041867060745, + "realized_sigma": 0.07415493983983475, + "shared_noise_variance_share": 0.6511498444615121, + "tolerance": 0.234 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.234, + "upper": 0.617, + "minimum_detectable_gap_80": 0.679288727282926, + "faithful_pass_probability": 0.9992035275388971, + "real_gate_holdouts": { + "estimate": -1.503582209399558, + "gap_from_epuf": 0.36822171674614146, + "lower": -0.234, + "upper": 0.617, + "pass": true + } + }, + "q_atmax.men.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.12650910252315553, + "epuf_sampling_sd": 0.005533914747447267, + "psid_value": 0.19550268988820213, + "psid_n": 3402, + "bridge_psid_minus_epuf": 0.4352598760661004, + "min_events": 47, + "floor": { + "replicates": [ + -0.04013813878469119, + 0.02318613881884457, + -0.01302304647539898, + 0.07815243151769868, + 0.16435318475841731, + 0.06565373160080912, + -0.03208124686865721, + 0.06343039186616228, + -0.07536899573647127, + 0.009234866476144798, + -0.08924780363962104, + -0.11376830072939637, + -0.028630205491736338, + -0.06434220535118906, + 0.17555432949606176, + -0.013042895399761334, + -0.08125868363348587, + 0.02269483527410643, + -0.04731398903855022, + 0.05298895494803768, + -0.0742309355143852, + -0.08217965493039325, + 0.05484853226792108, + -0.041171018799089465, + 0.13154517575932667, + -0.07667301608609378, + -0.08230824786598678, + 0.05943633697891304, + 0.23366721920875322, + 0.092238616286062, + 0.03552862364941445, + -0.03098618377999518, + 0.07341933142693824, + -0.15788086856808792, + 0.1004205830666054, + -0.09680764281082821, + -0.027920637302293994, + -0.15876560405430817, + 0.037497075051844186, + -0.05198846122396583, + 0.049693431624255546, + 0.15926334173508427, + -0.01760871313926904, + -0.08018455309596362, + 0.019836250698934577, + -0.040415147338026536, + -0.023065175687228545, + -0.07149537869189537, + -0.06400376808967168, + 0.1583687960304916, + 0.014711037438157049, + 0.17423750240940172, + 0.07306900079249634, + 0.0840625346329974, + 0.05408809184939811, + -0.16065181009851004, + -0.08125769036009334, + 0.1612023285161448, + 0.09231026384044838, + 0.031102902989232906, + 0.013376277631312994, + 0.03025455444331504, + 0.19019350535084634, + 0.15757380041616642, + -0.08794543645450092, + -0.004814256123014227, + 0.02793457446632519, + 0.02745232967854938, + 0.17885721718850411, + 0.07956811246915174, + 0.03330981119073362, + -0.22769807491701732, + -0.07118273627683602, + 0.0289207203734535, + 0.16210178255183683, + 0.11321193083221504, + 0.008751699820555348, + -0.014336965101112487, + -0.07893750811884492, + -0.05714925348317956, + -0.07492072894073187, + 0.20205956543731163, + 0.019331357960828632, + 0.040874220056381416, + 0.10852307016538709, + 0.01773185725806692, + 0.023147777363521582, + 0.05242270789507286, + 0.09075489704321549, + -0.04989201688744449, + -0.03543858419878121, + 0.07429075476898062, + -0.012240288808053612, + -0.05516022100462714, + -0.06291604047820498, + 0.04723261030139969, + 0.0800658911997939, + -0.013336537929512948, + 0.002841063016242318, + -0.051995874501780226 + ], + "mean_abs": 0.07272352471696958, + "sd_abs": 0.054036462010903924, + "realized_sigma": 0.09044031668260008, + "shared_noise_variance_share": 0.7433058094147004, + "tolerance": 0.289 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.289, + "upper": 0.725, + "minimum_detectable_gap_80": 0.8003763669572352, + "faithful_pass_probability": 0.9993215394855008, + "real_gate_holdouts": { + "estimate": -1.5846878827692255, + "gap_from_epuf": 0.4827531339293092, + "lower": -0.289, + "upper": 0.725, + "pass": true + } + }, + "q_atmax.men.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.06812218003195328, + "epuf_sampling_sd": 0.008853612442503234, + "psid_value": 0.11162778379786058, + "psid_n": 2583, + "bridge_psid_minus_epuf": 0.49386711962403407, + "min_events": 11, + "floor": { + "replicates": [ + 0.09720674185722644, + -0.06694919856473058, + -0.0751324876865822, + 0.003259287628533558, + 0.05269804804247169, + 0.15749176937389153, + -0.17257518938530492, + 0.20554003383986963, + -0.14198229130598872, + -0.10282837216921292, + 0.08691086569062767, + 0.021092367672142398, + -0.06987862637968023, + -0.01998439539405461, + 0.05620795571241266, + -0.002115768545050578, + -0.2332713110743625, + -0.11619719264568706, + -0.05994414185292629, + -0.281423939451219, + 0.02004173777401097, + 0.022839041023165807, + -0.11389617157252285, + -0.05616524809427914, + 0.22955865813676524, + 0.1919266323391331, + -0.29449382820178416, + -0.1727771486524008, + -0.14417007116571456, + -0.04480130330044996, + 0.10689745523753347, + -0.041124295491419494, + 0.19232210072076272, + 0.019056426930049275, + 0.09510507437562277, + 0.17897221237150673, + 0.1933298535741763, + -0.05846907410329716, + 0.02999241579079337, + -0.13135391670061636, + -0.06394927666678707, + -0.09169105591412219, + -0.03152770142220729, + -0.01235972192206014, + 0.04292504684986165, + -0.043364350962640685, + 0.08215050154637793, + -0.002639596207686834, + -0.031884647845350944, + -0.0941459812123906, + -0.02951271539882705, + 0.18974105429436894, + -0.04453024476617773, + -0.009925147481549823, + -0.00030393611139989396, + 0.14241798234569658, + 0.3032198986649437, + -0.12090040162684712, + -0.10198666533204936, + -0.19400560807974965, + 0.02792953569577561, + 0.17398878828712339, + -0.0873347551679664, + -0.16521546421171807, + 0.15879528452474156, + -0.12884096066173734, + 0.1016672232325122, + -0.03536934248717438, + 0.22881961947349483, + -0.0557587504084911, + 0.18566001109099872, + 0.03676485444191968, + -0.13118025456028026, + 0.02259871537134872, + 0.029411781719150598, + 0.020001962503907178, + 0.09312352133481405, + 0.29447086823856605, + -0.05109355712787522, + 0.08509014857085306, + 0.0013147096679604342, + 0.012760393211193266, + -0.23376039281333127, + -0.011737749797011032, + -0.08335751580251682, + -0.017511835538311926, + 0.09718876615643302, + 0.09568890629498816, + 0.01215807415636605, + 0.1005279503687928, + 0.1866906339548322, + -0.09008763290476085, + -0.003527358685923687, + 0.056764455209855846, + 0.08152105972819279, + -0.09426593671544503, + 0.04602472318580375, + -0.1862074557581006, + 0.09667422232657441, + -0.06541330916318877 + ], + "mean_abs": 0.09679462665029108, + "sd_abs": 0.07538092293565783, + "realized_sigma": 0.12245268660006814, + "shared_noise_variance_share": 0.8053774807879254, + "tolerance": 0.398 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.398, + "upper": 0.892, + "minimum_detectable_gap_80": 0.9949259007747009, + "faithful_pass_probability": 0.9994256477510173, + "real_gate_holdouts": { + "estimate": -2.291135781796967, + "gap_from_epuf": 0.39531663908489234, + "lower": -0.398, + "upper": 0.892, + "pass": true + } + }, + "q_atmax.women.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.042625292841566825, + "epuf_sampling_sd": 0.0106813680069294, + "psid_value": 0.050342939872192335, + "psid_n": 3457, + "bridge_psid_minus_epuf": 0.16641058256012942, + "min_events": 4, + "floor": { + "replicates": [ + -0.24697741336864754, + 0.07840244916805661, + -0.05051952119093217, + 0.3336897977383302, + 0.01629802275268144, + 0.39991987136860296, + 0.10023937171785025, + -0.1662610989742701, + 0.11004613744479164, + 0.2279930391915883, + -0.02348072514037236, + 0.20076389847303444, + -0.36445311675351477, + 0.14230822817734512, + -0.148561599367117, + 0.04168695085310348, + -0.29435663277462165, + 0.032437520223510985, + 0.0954442729552496, + 0.24293608875447203, + 0.02435807487220143, + 0.20758988456581262, + 0.08946481283818275, + -0.05002974648923142, + 0.0035219465816311857, + 0.14517715161064704, + -0.08708113282368513, + 0.2520526603928954, + 0.15625920847864183, + 0.1914053751460063, + -0.05246212247915438, + -0.1194138519298733, + 0.20977465523046268, + -0.11132399361063827, + -0.16341926649983396, + -0.12050217967950605, + 0.14245898185219152, + -0.13712221301413874, + 0.193398157739892, + -0.09636685298622227, + -0.23456019888853907, + 0.1456817942293791, + -0.011384915050290934, + 0.38062387405535425, + -0.14651837071218243, + -0.2852669840767861, + -0.2797150239631785, + -0.23433934507725684, + -0.25202105983224365, + -0.17097724217701993, + 0.07292826052193879, + -0.22469317682557333, + 0.28018542153802883, + -0.0880734858888852, + 0.1353825899798915, + -0.2645796173661803, + 0.07383650580043599, + -0.24963730510186055, + 0.31450668803996296, + 0.11804316115845404, + 0.048058791894396435, + 0.15955612980580347, + 0.021690585045167632, + 0.18866532235889855, + 0.23120711503051994, + -0.035698477750898405, + -0.0037050289090336808, + 0.20651014686664126, + -0.014271904325657392, + -0.08411700206020423, + 0.06998430900671071, + -0.12469859244790427, + -0.04568538870201522, + 0.09634311187977973, + 0.15673035321387707, + 0.3066637472754292, + 0.31080007927645137, + -0.0030346531783256303, + 0.11189725701081499, + 0.16101854267262095, + -0.0710199497712034, + 0.104539186097109, + -0.007483922893344097, + 0.05608103555522015, + 0.15011498363719622, + -0.2590680124082967, + -0.27153376643937577, + -0.2345907447752269, + -0.06187230871318472, + 0.1314101420293765, + -0.06992698346963033, + 0.014887670187174074, + -0.12764546140662691, + -0.1646387254854338, + 0.20287472270679174, + -0.18967957728675233, + 0.05908013621003749, + -0.1328629825851224, + -0.11757993056897087, + -0.018626202363764444 + ], + "mean_abs": 0.14658766028793369, + "sd_abs": 0.0958910782206569, + "realized_sigma": 0.1749030875719111, + "shared_noise_variance_share": 0.9012734854997293, + "tolerance": 0.53 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.53, + "upper": 0.697, + "minimum_detectable_gap_80": 0.8436127348781127, + "faithful_pass_probability": 0.9987575921522331, + "real_gate_holdouts": { + "estimate": -3.0714377092740093, + "gap_from_epuf": 0.08386976394466039, + "lower": -0.53, + "upper": 0.697, + "pass": true + } + }, + "q_atmax.women.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.039300565125599984, + "epuf_sampling_sd": 0.009414582319136047, + "psid_value": 0.03892013301304321, + "psid_n": 4193, + "bridge_psid_minus_epuf": -0.009727223644806493, + "min_events": 4, + "floor": { + "replicates": [ + -0.5102752364735845, + -0.31016449839892846, + 0.19362111652266112, + -0.09435974655845669, + 0.24763541023352276, + -0.5335033430979987, + 0.12793013592400304, + -0.2913470315108686, + 0.16096648928414137, + -0.1480908365064324, + -0.15922996482339125, + 0.3561974704372113, + 0.04681767946440929, + -0.11043923043093451, + -0.4107328576477447, + 0.1303182657757973, + -0.17290711941359027, + 0.011336334122923564, + 0.19684371830232728, + 0.09688897446393363, + 0.04889199546739542, + 0.16321871951441924, + 0.02492867285079492, + -0.3618710741555653, + 0.09633711255991484, + 0.0850234589659391, + 0.015932456867683076, + -0.016487166199486314, + 0.006877924885762221, + -0.29493630499609313, + 0.2191816877606365, + 0.14021444974850605, + 0.15892520311204117, + -0.20038773075851402, + 0.05116237355961184, + 0.04468987289026183, + 0.3577781597309073, + -0.0003893564539905192, + -0.27547439350246417, + -0.030643309783154438, + -0.08965536030281318, + -0.10654517961665144, + 0.06353127287796956, + 0.17509348992315776, + -0.11323338210334044, + 0.11440058831622157, + 0.325335461183317, + 0.07270735245818538, + -0.0718248475975023, + -0.13854913228529453, + 0.0886327951579986, + 0.22883357285625938, + -0.2688324278799057, + -0.010548035260904198, + 0.1107827486759203, + 0.25335596474807454, + 0.11804559572809348, + -0.08823237039179421, + 0.1803702531853264, + -0.24016756986893162, + 0.12341555224950307, + -0.12472408698953052, + -0.13232957624472452, + 0.07960369113643018, + 0.016687429916489194, + 0.542500619742101, + 0.1976181366017873, + 0.22374049884639424, + -0.07877632479196683, + 0.5757580688678512, + 0.3828739535733474, + 0.4972872013031344, + 0.18593609044187565, + 0.1979230169285573, + -0.029530806763148343, + -0.14388282537820496, + 0.13856378711975736, + -0.10719319338716149, + -0.10545029649044335, + 0.22129985653351625, + -0.0636914864319198, + -0.09873937469096972, + 0.07306073994877194, + -0.33117714636401696, + -0.007444029590011558, + -0.39274608394678157, + 0.014732053109613119, + -0.028654671400161424, + -0.14999442594660461, + 0.18563982071125817, + 0.018868034921167842, + 0.014370648460311886, + -0.08110042494358094, + 0.24378510538693243, + -0.20822466227100866, + 0.21095674947692178, + 0.04628527779702951, + 0.13412832793128926, + -0.3101943324298324, + -0.7153797522583007 + ], + "mean_abs": 0.17195902444896075, + "sd_abs": 0.1419525410166041, + "realized_sigma": 0.2225284807648186, + "shared_noise_variance_share": 0.7468244272493322, + "tolerance": 0.74 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.75, + "upper": 0.74, + "minimum_detectable_gap_80": 0.9370119181311997, + "faithful_pass_probability": 0.9991834749723999, + "real_gate_holdouts": { + "estimate": -3.1970814987997955, + "gap_from_epuf": 0.0394348816242549, + "lower": -0.75, + "upper": 0.74, + "pass": true + } + }, + "q_atmax.women.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.025319243779007263, + "epuf_sampling_sd": 0.012871210974672668, + "psid_value": 0.027666318315116692, + "psid_n": 3099, + "bridge_psid_minus_epuf": 0.08865099774727714, + "min_events": 0, + "floor": { + "replicates": [ + 0.08166504591439261, + 0.01624933396642625, + -0.34284130842490046, + 0.7407080002105417, + 0.19875752722605555, + 0.20391204137799934, + -0.2430689316230965, + -0.0694133492209228, + 0.1800655127183508, + 0.1395151005813453, + -0.18453178907940182, + -0.5417905439327557, + 0.008846078809492175, + -0.38111138676691936, + 0.09352511695140664, + -0.4881707985526844, + -0.018722210232279934, + 0.07414433254210495, + 0.34290516937620974, + -0.0921789951107368, + 0.08167726249573803, + -0.05029377279518821, + -0.26948437106873846, + 0.4126512511850995, + 0.2060779977583196, + -0.11158494011500975, + -0.07847322066077189, + -0.13165154667954715, + -0.2530376564416785, + 0.16223644748598987, + 0.33563427602344675, + -0.29530360994964555, + 0.24430754010813693, + 0.10650328861463332, + -0.5290007814328344, + 0.03793913224626322, + -0.489331351562025, + -0.1439793197771777, + -0.10136255047666065, + -0.29706367864029004, + -0.13606327674793572, + -0.34691850593719575, + -0.09607525966776231, + 0.3644038001279759, + 0.26530544117288013, + -0.4296779254444911, + -0.13467708314134597, + -0.2996304773379488, + 0.03627787276409267, + -0.11804583569885985, + -0.05366862435799469, + 0.27218661069090033, + -0.040054994303141855, + -0.2765850868114159, + 0.12455697379572706, + 0.2779234673378048, + 0.28746499281819893, + 0.16395689520188417, + 0.004095727739597876, + 0.081043581629896, + -0.04249224569078103, + -0.2653920489920114, + 0.169461380526033, + 0.05906073729993566, + -0.03654041560287746, + 0.1353190989715498, + 0.18773163147387972, + 0.01733139394359351, + -0.16331737362529752, + -0.1932125854919855, + 0.2391030416287656, + -0.21234788382686087, + -0.3693728107442098, + 0.4220036737339399, + 0.018136041200808473, + 0.2234114519019863, + 0.07996282220244155, + -0.13188990659209732, + -0.2010300267986187, + 0.010921242475511184, + 0.18370510784057914, + -0.09042680481588095, + -0.12963554656327614, + 0.2986441009621481, + 0.13161071391471335, + 0.13681295946006888, + 0.15715708823046892, + 0.13512338444592342, + 0.22091681736835977, + -0.22290122277325009, + 0.1831429804550544, + 0.004639538215635897, + 0.034337866272266204, + 0.1477625150072872, + 0.059887517538184776, + 0.06800237772685302, + 0.015467582832888738, + 0.19163838847936798, + 0.3571474188661772, + 0.2173814738540567 + ], + "mean_abs": 0.18752708219207892, + "sd_abs": 0.1391503147494659, + "realized_sigma": 0.23309995398841543, + "shared_noise_variance_share": 0.8124685997245343, + "tolerance": 0.744 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.744, + "upper": 0.833, + "minimum_detectable_gap_80": 1.0288328685687969, + "faithful_pass_probability": 0.9991195408535404, + "real_gate_holdouts": { + "estimate": -3.6555248535496436, + "gap_from_epuf": 0.020665695150428487, + "lower": -0.744, + "upper": 0.833, + "pass": true + } + }, + "mpers.men.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.7825482702139276, + "epuf_sampling_sd": 0.003686401622664722, + "psid_value": 0.7501136516287285, + "psid_n": 155, + "bridge_psid_minus_epuf": -0.04233087713109862, + "min_events": 1, + "floor": { + "replicates": [ + 0.02366844521696393, + -0.04729073036875929, + 0.00020006975318637155, + 0.07210972372592535, + 0.04759705127104431, + -0.037717844076595536, + -0.036197761536218384, + -0.07678730524197695, + -0.02289237809451289, + 0.014206070896703255, + -0.09263366656103542, + 0.013751400476771147, + 0.045372704654683196, + -0.16472922401709622, + 0.028290773897475877, + 0.032672235220362555, + 0.05619046632360908, + -0.06337356901487366, + 0.0897476750021106, + 0.0290531910575981, + -0.013849619021810394, + -0.01926091207139599, + -0.047380657938624116, + -0.042827025781182165, + -0.06297485756640599, + -0.021507807514758337, + 0.06627676853893602, + -0.08377717489751996, + 0.029367561487031138, + 0.09254203590283779, + 0.041638684369397536, + -0.09290754921240428, + 0.05048507235783875, + 0.016717738759345152, + 0.04529236714649182, + 0.06453189393350198, + 0.15362989004106958, + -0.023861712656494755, + 0.0044237965173125615, + -0.0025727793639886143, + 0.026921821060059387, + 0.00440961455135061, + 0.13495718071117638, + 0.00790165518279437, + -0.048935514606838926, + -0.06308153551107917, + -0.002914109348047894, + 0.04771617176566191, + -0.024634063509057086, + 0.09163176752384503, + 0.011677009358410984, + 0.00015435282766726455, + 0.0018507431742127434, + -0.06328730950168784, + -0.014321440859930507, + -0.013492079101245336, + -0.05187183302351829, + 0.024188581295744, + 0.033439158937681054, + -0.01531545598424744, + 0.08226413571214611, + -0.09482537669150712, + -0.04636649134718021, + -0.07245332985292172, + -0.08027574058580379, + -0.05749978347955678, + 0.08177918710599787, + 0.0445820423529498, + 0.04972798972338599, + -0.044662576183377045, + 0.034420219538837366, + -0.08166012079302276, + 0.046556068923004845, + 0.0007608238467774198, + -0.019906377261165037, + 0.14265527906141826, + 0.02483202836327253, + -0.08779447423926859, + -0.019701209833739214, + -0.022116070721169445, + -0.11673914707308697, + 0.12299623225820619, + 0.06499810469341238, + -0.037322674566365996, + 0.028810033108506675, + -0.07532290409352449, + 0.11157843258482272, + -0.14292366106217974, + -0.04133669649783819, + 0.08804975280797017, + -0.0027813479390983997, + 0.04144661049012699, + -0.0558321451699343, + 0.027277033926300792, + -0.07982309270990529, + -0.08622063808966987, + 0.05139433673415905, + 0.022634333783161653, + -0.0070141560977058925, + -0.006296299038986292 + ], + "mean_abs": 0.0499864654766157, + "sd_abs": 0.03718480373002108, + "realized_sigma": 0.06218946263637177, + "shared_noise_variance_share": 0.7634506044898333, + "tolerance": 0.199 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.242, + "upper": 0.199, + "minimum_detectable_gap_80": 0.2936708493903585, + "faithful_pass_probability": 0.9992857388994426, + "real_gate_holdouts": { + "estimate": -0.28178872786078496, + "gap_from_epuf": -0.03658905656472905, + "lower": -0.242, + "upper": 0.199, + "pass": true + } + }, + "mpers.men.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.6662268006129747, + "epuf_sampling_sd": 0.004684632307432884, + "psid_value": 0.6599305131181035, + "psid_n": 136, + "bridge_psid_minus_epuf": -0.00949560770680724, + "min_events": 0, + "floor": { + "replicates": [ + 0.020253565942949164, + -0.014823423923427587, + 0.00533681559340396, + 0.05749498441989517, + 0.12574320810138195, + -0.04863380326159175, + -0.10871539104728212, + 0.05862400387063613, + -0.14946772460290864, + 0.018962098902648467, + -0.18083434072944046, + 0.05359270830107049, + 0.002078359517724726, + -0.011985658795294979, + 0.13497186886114523, + 0.009638313366686663, + -0.1037753712392015, + -0.03592331849086097, + 0.16477058040669593, + 0.001229763901411829, + -0.08188654999492859, + 0.1353706711811816, + 0.15250279399365355, + 0.06593798587205954, + -0.01452927927508238, + 0.07770309313951954, + 0.03145055348331774, + -1.1903201559387844e-05, + 0.02521291456464031, + -0.05292026155159693, + 0.04152261153137696, + 0.049944192543470545, + 0.0975935464824732, + -0.03123971858884636, + 0.0755403517561869, + 0.035460039462859916, + 0.0077928169323561725, + 0.01660315609452595, + 0.10192197311107618, + 0.1150581122673548, + 0.03483375557946353, + 0.1779285555354051, + -0.12244186316238054, + 0.0022561106332339154, + -0.1067954826208643, + -0.07919717589511968, + -0.029399937718480512, + 0.04611660216017102, + -0.03567738543937801, + 0.010763288272410687, + -0.07933919783137727, + -0.06396245697108582, + 0.037476710035576205, + -0.15520108135276856, + 0.13030643923160046, + -0.0019890787504318885, + -0.052065115902687475, + 0.12453169555165955, + -0.020471955844751893, + 0.08446742791201264, + -0.015608291818566322, + 0.06398790552649097, + -0.05530853620765269, + -0.03835895173541912, + 0.002892880549403981, + 0.04870147850023379, + -0.012922841399911122, + -0.05723355040739864, + 0.05478550641353758, + 0.016072132794438365, + 0.11702543871181625, + -0.021846606355395565, + -0.030869778650605834, + -0.02233940666583628, + 0.10614265615284438, + 0.017791742840970598, + -0.018250450152391906, + 0.038555075598661004, + 0.006280932692734692, + -0.10904096025523335, + -0.11644087075847653, + 0.07009812108030278, + 0.0749433808331258, + 0.0458820486458435, + 0.08997668681372603, + -0.07048102822734112, + -0.04623571701403245, + -0.023430850869819303, + 0.09177002729575373, + -0.045319543937190676, + -0.10407022047615122, + 0.05930786497372659, + -0.01998943135302031, + -0.11251677686936659, + -0.08131842949984502, + -0.11916247792760959, + 0.03919487783438089, + -0.18137529430920388, + -0.07751380847417885, + 0.026801532145960677 + ], + "mean_abs": 0.0626212325747318, + "sd_abs": 0.04707824062117016, + "realized_sigma": 0.07820240342702775, + "shared_noise_variance_share": 0.6009172983358492, + "tolerance": 0.251 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.261, + "upper": 0.251, + "minimum_detectable_gap_80": 0.326312410947429, + "faithful_pass_probability": 0.9989175986284126, + "real_gate_holdouts": { + "estimate": -0.39933093324817287, + "gap_from_epuf": 0.006794191703734742, + "lower": -0.261, + "upper": 0.251, + "pass": true + } + }, + "mpers.men.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.33371769653394834, + "epuf_sampling_sd": 0.014181248352802643, + "psid_value": 0.4279673072793644, + "psid_n": 70, + "bridge_psid_minus_epuf": 0.24875139218435527, + "min_events": 0, + "floor": { + "replicates": [ + 0.05056517893595791, + 0.10013725324718525, + 0.05650582609171406, + -0.39913928391921477, + 0.0643538605598234, + -0.0618714884055917, + 0.07455457401465537, + 0.0166827773160399, + 0.021294361935660755, + -0.19778388680197434, + -0.055868017603994014, + 0.10759594257335064, + -0.10633347525291381, + 0.15626987081922544, + -0.06931606322011757, + -0.016032034034211884, + -0.3060609135548298, + -0.20601163993128235, + 0.3324035252750533, + -0.045636067943886915, + 2.8848652273094633e-05, + 0.019702656002753782, + -0.19816747907905202, + 0.03344106179719614, + 0.13824512158859387, + 0.01927146205476149, + -0.17283040209314016, + -0.1556852564256035, + -0.2076623976869722, + -0.19008212359671683, + 0.0053326187658043755, + 0.006300123065727803, + 0.21792947972604315, + -0.019645566655051627, + -0.02201215466326284, + -0.1084806058303151, + 0.34216380355432324, + -0.07008753400209433, + 0.34001168819414596, + 0.15786069034455374, + -0.22099893296384376, + 0.12129486319726746, + -0.2035929830433768, + 0.29256464222395784, + -0.02188662647689632, + 0.07739877475651386, + 0.1511723202156125, + 0.1098561980617685, + -0.007329039853004926, + 0.1822418305814445, + -0.08662919604217151, + -0.048145811887065404, + 0.022217741862406104, + -0.30250222827404855, + 0.20316890543284755, + 0.21923487821555626, + 0.2844607997890592, + 0.009076920977804603, + -0.06089625904595225, + -0.06707802595276191, + -0.5364600856730649, + -0.06096566236286416, + 0.06722095561317604, + 0.17252751313793435, + -0.07460271627413417, + -0.19901819705719326, + 0.1023230431273559, + -0.13045882312939222, + -0.014829887082567272, + -0.43814889490576947, + 0.16633940361021238, + -0.04358368694073672, + -0.14073193171895337, + 0.030318926027152804, + 0.30740316310942256, + 0.012447267419427921, + 0.05944701040962491, + 0.11698348821356591, + -0.35762688467307313, + -0.05873565052865648, + -0.013736030201093818, + -0.028947574030545875, + 0.0015275852600315498, + -0.3429547536966415, + -0.2963763925908002, + -0.28224460319156164, + 0.22382128943513557, + 0.16681224705868752, + -0.17921556940404215, + -0.08289938563931054, + 0.2561383364002395, + -0.037984222715950144, + 0.13328837771656, + -0.017632539423700855, + 0.048497799374474126, + -0.1107506591296975, + -0.14639755494374396, + 0.35607839293191873, + 0.15549501649803155, + -0.13110387908754717 + ], + "mean_abs": 0.1366317949381242, + "sd_abs": 0.11478306965038826, + "realized_sigma": 0.17807764861317057, + "shared_noise_variance_share": 0.7458895636431065, + "tolerance": 0.596 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.596, + "upper": 0.845, + "minimum_detectable_gap_80": 0.9946253224819358, + "faithful_pass_probability": 0.9995923338005119, + "real_gate_holdouts": { + "estimate": -0.8934940703027577, + "gap_from_epuf": 0.20396579306070806, + "lower": -0.596, + "upper": 0.845, + "pass": true + } + }, + "mpers.women.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.6293929712460063, + "epuf_sampling_sd": 0.011046973203030577, + "psid_value": 0.7217471079262044, + "psid_n": 38, + "bridge_psid_minus_epuf": 0.13691899432519222, + "min_events": 0, + "floor": { + "replicates": [ + -0.14151666071075933, + 0.029569239126633895, + 0.15348510880068883, + 0.09914618793149624, + -0.16517751114170454, + 0.1695369939821576, + -0.04618313336836985, + -0.03555924257491508, + 0.028941397234955923, + 0.11188403224695659, + -0.0367820437143368, + 0.0006843820816516688, + 0.08626204971327595, + 0.22589367667987545, + -0.01829323785788403, + 0.07396098512903651, + -0.0665289815913287, + -0.2121706933190832, + 0.15231132810311598, + -0.07118809075413982, + 0.11505540946288761, + 0.14918920809545855, + 0.03249114283209334, + -0.1526456075807696, + 0.02485830248089621, + 0.0885580985378982, + -0.0258983627111804, + 0.19472537496534975, + -0.16178846826070017, + -0.06705038572312816, + -0.10212102594271005, + 0.033184348496232696, + 0.30397749128982243, + -0.04232419820252961, + -0.08948754830362435, + 0.05620891937052322, + -0.003556332473639068, + -0.14227541261696303, + -0.13705907009871546, + 0.016940448903943833, + 0.055337378619030986, + -0.08072129158749669, + -0.07329551083772767, + 0.1263233041765977, + -0.09441749829629553, + -0.23591683761217846, + -0.030032307160317573, + -0.16731047211423872, + -0.06889132687606231, + -0.016478708987741564, + 0.1156440749848516, + -0.16051874748262915, + -0.05642604666376638, + -0.01019916445649674, + 0.16347179124825084, + 0.005508518633712156, + 0.15741709825564157, + -0.033874875771541774, + 0.09392003099728571, + -0.07328371421076418, + 0.13314252498194262, + 0.054194424906284094, + 0.11680559836143967, + 0.11509784958432223, + -0.026398264692355733, + -0.11279526686786427, + -0.10045442570922919, + 0.16499715807492446, + -0.2830731844884389, + -0.37354789453115983, + -0.058434444410880915, + -0.26816731242295117, + 0.13135716042521026, + 0.05458453034816255, + 0.11446069312162094, + 0.011483686090387357, + -0.12237165704944653, + 0.21343337771120835, + -0.050617218999446906, + -0.08639448231784799, + -0.06093114520234014, + -0.11191409600589357, + -0.2635492794089256, + -0.15312765818379115, + -0.12794758705271483, + -0.09697886232817332, + -0.06363843132966508, + -0.035196045112727836, + -0.06886051387099648, + 0.1930459271779255, + -0.07501721355480656, + -0.12034059032453714, + 0.08479074863984029, + -0.206671898003019, + -0.01013962730454529, + -0.19992523467877432, + 0.1024601262125203, + -0.06129832564934344, + -0.24359554348896295, + 0.09696599043807973 + ], + "mean_abs": 0.10651664830446764, + "sd_abs": 0.07391735574872596, + "realized_sigma": 0.1294408517126356, + "shared_noise_variance_share": 0.6549111381255552, + "tolerance": 0.402 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.402, + "upper": 0.539, + "minimum_detectable_gap_80": 0.6478591636183093, + "faithful_pass_probability": 0.9990370758788346, + "real_gate_holdouts": { + "estimate": -0.3251898583203061, + "gap_from_epuf": 0.13780960348185867, + "lower": -0.402, + "upper": 0.539, + "pass": true + } + }, + "mpers.women.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.5392099056603774, + "epuf_sampling_sd": 0.012279417447860763, + "psid_value": 0.604826438632865, + "psid_n": 31, + "bridge_psid_minus_epuf": 0.11483660811939811, + "min_events": 0, + "floor": { + "replicates": [ + -0.7757517542092003, + -0.04371033872563998, + 0.006484845261138655, + 0.01004956389097425, + 0.26905313234245154, + -0.15397597722882816, + -0.17413695333797283, + -0.1975416447138753, + 0.5448173424210032, + -0.20013891048502688, + -0.0070129028309945385, + -0.2847451696120023, + -0.21155644761441902, + 0.17252748713512508, + 0.05461188919998519, + -0.2726559236324943, + -0.12048179928196937, + 0.41019630542182905, + 0.1402028206392107, + -0.11936353509218062, + -0.15604609286558735, + 0.19094115628502872, + 0.08347743573632493, + -0.33033302880306376, + -0.19823955771554647, + -0.39970344634456184, + -0.17887303412860564, + 0.267803882831321, + -0.06175534492849932, + 0.1252949410507285, + 0.06398245952189952, + -0.229080979581298, + -0.07149447208602919, + -0.1194508560336045, + 0.27234825384386124, + -0.08440553538665274, + 0.27207658792952955, + 0.07200989959524506, + 0.010582081378734759, + -0.23462656626740558, + -0.02634477654238973, + -0.380155876844039, + 0.2151865600572441, + 0.10280646211807073, + -0.1826866677411226, + 0.06286782839584718, + -0.050287196575101695, + 0.3800294934691151, + 0.17574832213382707, + 0.022168990365739716, + -0.26157648223716556, + 0.16172960602131994, + 0.06603635236065611, + -0.1885944467486351, + -0.015404954125387477, + -0.1132004682506337, + 0.3783931543601788, + -0.3377640633857202, + -0.2628995248397417, + 0.06214652777667684, + -0.12638045666905795, + 0.13933466754592344, + -0.0509580883373455, + -0.13169317708168532, + -0.30139894417831264, + 0.14760496986563568, + -0.04469607899335068, + -0.019751113889573457, + 0.16622339701895014, + -0.04755351759216003, + 0.15485487350766347, + 0.1864346532474565, + -0.1286708268710394, + 0.0904856401639004, + 0.19682863007749324, + 0.2601079150402822, + -0.22810120808943285, + -0.17427817605485257, + -0.13038677633771897, + -0.013376634220786943, + -0.029462415013100984, + -0.13824899833069107, + -0.16696088019538805, + -0.2192590732284345, + 0.06538197837035636, + -0.19690696592694554, + 0.10789184006684349, + -0.14647347544817949, + 0.021536215170427864, + -0.14245984548059623, + -0.032798183595845326, + 0.02071549642392334, + 0.03526451925887489, + -0.22137530250453238, + 0.10702687911680978, + 0.4321614332908081, + 0.12242244412980682, + 0.20998393376735697, + 0.08420314840380652, + -0.005885561495131225 + ], + "mean_abs": 0.1628310644373894, + "sd_abs": 0.12671027351555664, + "realized_sigma": 0.20593419829172754, + "shared_noise_variance_share": 0.8437671648805732, + "tolerance": 0.67 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.67, + "upper": 0.785, + "minimum_detectable_gap_80": 0.9581552021205311, + "faithful_pass_probability": 0.9993623849776376, + "real_gate_holdouts": { + "estimate": -0.5505793013167559, + "gap_from_epuf": 0.06707104720417201, + "lower": -0.67, + "upper": 0.785, + "pass": true + } + }, + "mpers.women.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.264336542486396, + "epuf_sampling_sd": 0.02862049424031705, + "psid_value": 0.22110258180986492, + "psid_n": 24, + "bridge_psid_minus_epuf": -0.17859630853783282, + "min_events": 0, + "floor": { + "replicates": [ + -0.8209305197648629, + 0.3852810623558961, + null, + null, + -0.2169001632372567, + 0.5805317915535866, + -0.6646614586899067, + 0.12882743941176533, + 0.03841560865285498, + 0.9820424963005379, + 0.15570301016941224, + -0.697179283272433, + 0.23631025857673693, + -1.159092707813549, + -0.11941478289078322, + -0.6074170146389863, + 0.6669444446563726, + 0.5695878723602353, + 0.1582153977395876, + -0.5265044581979729, + 0.2238496402486545, + 0.21273981279051968, + 0.12641360573606952, + 0.3076902912048698, + 0.7514106310882548, + -1.602559861610047, + -1.0252882356851567, + -0.5957408629174854, + -0.35787434431302456, + 1.2173221674836476, + null, + 0.1157554550281179, + null, + -0.3752462976062064, + null, + 0.07870348502878044, + 0.08312364971210295, + null, + 0.17348546999681058, + -0.9798745923874248, + 0.02495700898583164, + 0.22824911612969456, + 0.6291907730840782, + -0.5354157430331361, + null, + null, + null, + -0.09638480461139676, + 0.20536827767187849, + 0.11356325353638541, + -0.35327901911163695, + 0.5501699180232433, + 0.015474873054100446, + -0.2908009574150062, + -0.2523596044414903, + null, + -0.4103099667624358, + 0.007067633027929454, + -0.13420834854359154, + -0.1099536056621494, + -0.3202155264290566, + 0.24111604303143408, + 0.5778832931953334, + -0.048804843797585096, + 0.5626693288217296, + -0.8945915138681562, + null, + -0.3865613025761089, + null, + -0.491230576060684, + 0.07708895922186132, + null, + 0.4598088262677642, + 0.30140666589561305, + -0.46333730304086773, + -0.5224149246796168, + -0.2073262073742893, + -0.13804455716081354, + -0.29071029355679523, + 0.02709908203030509, + null, + 0.4935718457401631, + -0.6763771378164388, + -0.6978503127726994, + 0.2504180613710951, + 0.7054034200801091, + -0.4117837183851891, + 0.1948494765621952, + -0.3061650462019492, + -0.21632649045964936, + 0.1950856520204728, + 0.038125579815583954, + 0.6290036872388993, + 0.3308111869424537, + -0.9535578586626708, + 0.19588451626019499, + 0.037402589037917044, + 0.3298289268692397, + -0.28528777208584144, + -0.17039292936190376 + ], + "mean_abs": null, + "sd_abs": null, + "realized_sigma": null, + "shared_noise_variance_share": null, + "tolerance": null + }, + "eligibility": "undefined_on_some_split", + "gated": false, + "report_reason": "undefined_on_some_split" + }, + "r6.men": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7108651036878303, + "epuf_sampling_sd": 0.0011090717968760824, + "psid_value": 0.6680476050375935, + "psid_n": 2182, + "bridge_psid_minus_epuf": -0.04281749865023676, + "min_events": 368, + "floor": { + "replicates": [ + 0.00904565239261762, + 0.009429566964626046, + -0.032891899664422575, + -0.0034852763035942425, + 0.02432246358346024, + 0.00039047955307341953, + 0.0168595855204402, + -0.013210242603140854, + -0.03495514482419826, + 0.01521199404366741, + -0.028332923598764326, + 0.027136870572710525, + -0.005247127425117071, + 0.0009125548939920569, + 0.001462415470445011, + -0.022151360594827474, + -0.02607336488753026, + 0.007621978578519706, + 0.003949665550393888, + 0.0046476843083201325, + 0.014105893941755543, + -0.028673538530266773, + -0.017871809488757273, + -0.027424884959471152, + 0.03109918323891675, + 0.057960733095348216, + -0.011042511194830573, + -0.036189386882443386, + -0.009949200453736817, + 0.015231920786124675, + -0.0013154620022582386, + -0.005259609094518725, + 0.01155823582498594, + 0.009109533089254773, + 0.020678478651348087, + 0.018934377265644897, + 0.02264845453409542, + -0.019444703001946062, + 0.019377135291054726, + 0.007612585845815589, + -0.005815359103128359, + 0.002425316960315671, + 0.00023847424232714687, + -0.03365565963553513, + -0.04770576700391144, + 0.013276363435384686, + 0.029902697050783522, + -0.0019797751171167777, + -0.0473278602068401, + -0.013200160422078444, + 0.014693869065393494, + 0.02205412852148808, + 0.011820038319272308, + -0.03536258689514732, + 0.013202371289536663, + 0.008685306601785014, + -0.0027641498562477884, + 0.006951042436880384, + -0.019406578678989317, + 0.021933214980298932, + -0.0024312132882687854, + -0.006641773480372981, + 0.012457304309077877, + -0.05848484736624049, + -0.06282055981788681, + -0.0015150976450074571, + 0.026939239493287748, + -0.005814303282348998, + -0.021763907085683876, + -0.04035090060208252, + 0.026869941067313996, + -0.0063728859409129535, + -0.03108566973827609, + -0.02269868670487868, + 0.021344576254570036, + 0.029987327669021346, + 0.0064138975271971765, + -0.04841680057156439, + -0.023036803765420055, + -0.029737311388775833, + -0.027363210358241852, + -0.02471271777062467, + 0.008545140115507499, + 0.001519980635007967, + -0.03673743288093406, + -0.0145436908154441, + 0.0381346296227405, + -0.05245197405843932, + -0.019669137021640082, + 0.011327956984621745, + -0.012679346333429709, + -0.020051979818450194, + -0.012257787473452186, + 0.022138878113264426, + -0.02277327408793245, + -0.05110762303618693, + 0.03573677201252767, + 0.0446712723705186, + -0.0026615121649960494, + 0.012313891324202408 + ], + "mean_abs": 0.01981807862325246, + "sd_abs": 0.01469434082238032, + "realized_sigma": 0.024627640081819575, + "shared_noise_variance_share": 0.7755618412060957, + "tolerance": 0.079 + }, + "eligibility": "eligible", + "gated": true, + "lower": -0.122, + "upper": 0.079, + "minimum_detectable_gap_80": 0.1425446434758875, + "faithful_pass_probability": 0.9993478271525766, + "real_gate_holdouts": { + "estimate": 0.6670465436202722, + "gap_from_epuf": -0.04381856006755813, + "lower": -0.122, + "upper": 0.079, + "pass": true + } + }, + "r6.women": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.672102564061898, + "epuf_sampling_sd": 0.0011744622407952785, + "psid_value": 0.6397841177680634, + "psid_n": 2376, + "bridge_psid_minus_epuf": -0.03231844629383451, + "min_events": 407, + "floor": { + "replicates": [ + 0.02227054585848226, + -0.019419397981280506, + 0.001491078417704239, + -0.02313476000435749, + 0.016037654418244895, + -0.0025165439540020262, + -0.023607622712945198, + -0.009571915003408205, + 0.021607311450517364, + -0.008001881789586274, + -0.023598113687496147, + 0.002746212527779679, + -0.027286402160379086, + 0.029869784403087907, + -0.038705174314428215, + 0.013106274306303678, + 0.014104472327566897, + -0.016771731833654158, + -0.024785175576273577, + -0.0015172408476386567, + -0.002817837336605733, + -0.02622481599899862, + 0.06966715518765298, + -0.0007560246904642631, + 0.013242465001602088, + 0.015335294511754305, + -0.036864090724850584, + -0.002073862096439061, + -0.010188545040874575, + 0.0018771251498829744, + 0.007252636931522005, + 0.047378148413899424, + 0.00010259225506392688, + 0.004599221793279262, + 0.006077123735412138, + -0.009032509473644645, + 0.010500640902328773, + 0.007633493408867986, + -0.029189185604615253, + 0.0237867474451382, + -0.026685822103469647, + 0.03311697848192824, + -0.014949929359090453, + -0.021234238785847792, + 0.01676866999608756, + -0.03666113845201158, + -0.013824693057837456, + -0.031814752337131824, + 0.04963389023603737, + -0.020413438670196793, + -0.022557616563596672, + 0.004633063255148562, + 0.008879848760715292, + -0.030857358387516465, + -0.01401243898610749, + 0.010885789103627364, + -0.045777699183405796, + -0.007260471964211146, + 0.0008286367152950946, + -0.01674299416563596, + -0.019214550807194475, + -0.05514584133738032, + -0.008541599564191482, + 0.011041741050201115, + -0.04074274736064659, + -0.0032906997185565556, + -0.00846494213920379, + -0.018824919223426717, + -0.03959489648134351, + 0.029896501779927753, + 0.02419987308420124, + -0.0003470937808399688, + 0.009165372761480162, + 0.012507395606172311, + -0.008343958120468065, + 0.026145898416475633, + -0.0008025331274396641, + 0.03125801622601937, + -0.030909202468400454, + 0.023033298167017713, + -0.04631564670823857, + -0.018746040020575228, + -0.03696620836901032, + -0.026952722524049677, + 0.04824953468173698, + 0.0524356703532004, + 0.011824930470842931, + 0.03697729125639326, + 0.021987833169318793, + 0.03525749036183207, + -0.004369017469476544, + -0.02629996158072484, + -0.027538685959327402, + -0.010918281102875238, + -0.008797716474889805, + -0.018029359967023872, + -0.003619482965761145, + 0.014448480947730935, + 0.02029773929056422, + 0.04300129352253257 + ], + "mean_abs": 0.02006792746259624, + "sd_abs": 0.014592944093846679, + "realized_sigma": 0.02476986454942573, + "shared_noise_variance_share": 0.731808077498613, + "tolerance": 0.078 + }, + "eligibility": "eligible", + "gated": true, + "lower": -0.111, + "upper": 0.078, + "minimum_detectable_gap_80": 0.1311652902513562, + "faithful_pass_probability": 0.9992504698081728, + "real_gate_holdouts": { + "estimate": 0.6273350404581282, + "gap_from_epuf": -0.04476752360376979, + "lower": -0.111, + "upper": 0.078, + "pass": true + } + }, + "zint.men": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.051096544134419136, + "epuf_sampling_sd": 0.006633082948146222, + "psid_value": 0.049090030186706095, + "psid_n": 2182, + "bridge_psid_minus_epuf": -0.040060902463718406, + "min_events": 9, + "floor": { + "replicates": [ + -0.1401135608506665, + 0.10477379091127492, + 0.05137887584032286, + 0.20218646819539732, + -0.0062143897855735375, + 0.07206415282904399, + -0.21901929597349246, + -0.14967547574753737, + 0.11572859802185764, + -0.12155130349148169, + 0.058424322504289306, + 0.023741561989700566, + 0.010556055826274502, + 0.10782706628240235, + -0.09158784321993951, + -0.09114147197655931, + 0.2616340901720373, + 0.001210460672375513, + 0.08583665383066541, + -0.13771601555757096, + 0.061050121507771005, + 0.04781422866928686, + 0.11561871796611367, + -0.026213490498400827, + 0.07133203046324454, + 0.017210998394236565, + 0.13986043349299426, + -0.12664698250690742, + 0.037782189211846395, + 0.1494812565770285, + 0.06982160011215544, + -0.1649966528578941, + -0.012644565980883815, + 0.1480282255041192, + 0.2629664386901951, + 0.11345964136831621, + 0.14182164366568362, + 0.011222364113876448, + -0.04848537709386669, + 0.0460561633266654, + -0.11785104434413518, + -0.05123840571074778, + 0.13809106638165192, + -0.11468952723781056, + 0.20839513195677672, + -0.02865636461877563, + 0.11202858414729255, + 0.1694492982180802, + 0.21800705570015433, + -0.05049238837268555, + -0.07070341782021283, + 0.18056634902138846, + 0.22769752045864267, + -0.05204327731898806, + -0.2911584475940763, + -0.0173162997262597, + 0.024891968356806737, + 0.08877833268624413, + -0.09944807794965582, + -0.15556295420717214, + -0.13584357821182147, + -0.061349687247900686, + 0.04799709597237456, + 0.10011204745158553, + -0.1402627076447045, + -0.07293180459785442, + 0.2820984100004189, + -0.054305655123289664, + -0.09378255250522094, + 0.03575903765999433, + 0.03000039838373758, + -0.03196231507756675, + -0.23360151576093635, + -0.07169141197745632, + 0.11336152126289822, + -0.1634533272666252, + 0.11056179034635916, + 0.11159834093399335, + -0.13458384731412765, + -0.009442250964407872, + -0.19020012579734624, + -0.19605468713273777, + 0.10338151468408063, + 0.16196799012033614, + 0.060379472140769996, + 0.15427133030051987, + 0.059124178875652245, + 0.26792069695253695, + 0.10855344252764354, + -0.02346771855735552, + 0.08790408555451035, + -0.07483073601946688, + 0.08783253286456594, + 0.022928415424576798, + -0.0317416089438205, + -0.07171949393922361, + 0.055174365901295985, + 0.20372391905168996, + 0.0877326612602658, + -0.10706247664572888 + ], + "mean_abs": 0.10472630835904902, + "sd_abs": 0.06908154308488097, + "realized_sigma": 0.12526825879508746, + "shared_noise_variance_share": 0.7678354184999309, + "tolerance": 0.381 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.422, + "upper": 0.381, + "minimum_detectable_gap_80": 0.526489328958371, + "faithful_pass_probability": 0.9984639414144828, + "real_gate_holdouts": { + "estimate": -2.9377920785775298, + "gap_from_epuf": 0.036246334945345904, + "lower": -0.422, + "upper": 0.381, + "pass": true + } + }, + "zint.women": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.06571286762020886, + "epuf_sampling_sd": 0.006096057676295448, + "psid_value": 0.06990943975043597, + "psid_n": 2376, + "bridge_psid_minus_epuf": 0.06190592612052814, + "min_events": 18, + "floor": { + "replicates": [ + 0.000493108261421682, + 0.12552534805002002, + -0.020017171189385063, + 0.2137127567734607, + 0.004076921119741783, + -0.1670766728536719, + -0.022121514383216967, + 0.20378038080399818, + -0.018280284892326915, + 0.029972402634023565, + -0.09326130757375983, + -0.23444506517835073, + 0.07655898427030916, + -0.16469820904950327, + -0.08825274469670452, + 0.0730424654419759, + -0.02147068053969914, + -0.08725130447191698, + 0.022156521690507525, + 0.00829746166570744, + 0.171996741000761, + 0.20100432907605015, + 0.037460216769147126, + 0.026405902426941852, + 0.18606517473167372, + -0.1294071176952929, + 0.043594512827394016, + -0.06923136587434486, + -0.02764311101445549, + 0.09768290056536855, + 0.12445783205144667, + -0.03854194916184972, + -0.12647833792633434, + -0.3008658215710187, + 0.028882977583045255, + -0.22787383254397708, + -0.05949878619450111, + -0.0889106595271425, + 0.16539725093476676, + -0.10246421798318228, + 0.07800339922263144, + 0.026082815066698295, + 0.05562493154323023, + 0.022202849335754005, + -0.028429597716961075, + 0.08381615822314692, + 0.06441825657507794, + -0.054133135075801864, + -0.1166337463942353, + 0.2503236771741437, + 0.048046752606772936, + 0.12866453701842695, + -0.00545060644359574, + 0.11025452437322536, + 0.015367538820078241, + -0.027898488930152343, + -0.09646959769205377, + 0.11931117032744365, + -0.04579154458059609, + -0.13552164115499488, + -0.005461046670309333, + 0.06112241681988495, + 0.033801101145052526, + 0.22091655592153359, + 0.17473370073432526, + -0.12702333522273546, + -0.04588906099436252, + 0.16038495952288612, + -0.015481186934894975, + 0.09277728255694417, + 0.26561480536761284, + 0.14732862363034105, + 0.01173657598543576, + -0.0029201316844742475, + -0.04816039850266529, + 0.11635332660636544, + 0.1365199497442462, + 0.11378469746547037, + 0.10733280285331981, + -0.05016750755918564, + 0.0900516918211891, + -0.05061633640995855, + -0.017387789239716067, + 0.08651775654511873, + 0.10961788895399116, + -0.004089830250778581, + 0.06910392182409453, + 0.05195838731188829, + -0.2696518362416591, + 0.05970194465164802, + 0.09968910893282223, + 0.043520116545386234, + 0.20240355250181774, + 0.08250065780388671, + 0.21430927770782238, + -0.07026296226183537, + -0.02482001321393712, + -0.22225563998796782, + 0.010723175381815775, + -0.07462648605688083 + ], + "mean_abs": 0.09232117150839675, + "sd_abs": 0.07205852410579953, + "realized_sigma": 0.116891852992524, + "shared_noise_variance_share": 0.7837000411229423, + "tolerance": 0.381 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.381, + "upper": 0.443, + "minimum_detectable_gap_80": 0.54128459163072, + "faithful_pass_probability": 0.9993677658267089, + "real_gate_holdouts": { + "estimate": -2.6663061727814648, + "gap_from_epuf": 0.05615434569816369, + "lower": -0.381, + "upper": 0.443, + "pass": true + } + }, + "d_anyzero.men": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.12851247096781818, + "epuf_sampling_sd": 0.003778766947095098, + "psid_value": 0.09730661233243132, + "psid_n": 2300, + "bridge_psid_minus_epuf": -0.27815900488091083, + "min_events": 27, + "floor": { + "replicates": [ + -0.1903283184860194, + 0.13154144772960175, + 0.027172876835814153, + 0.07399663453554606, + 0.12344653164434494, + -0.0566699789110674, + 0.031170948296275647, + 0.04131130969578112, + 0.1347107694041425, + -0.11927017906917681, + 0.041323384438143096, + 0.025103171634741406, + -0.08493002971864239, + 0.05132140456841405, + -0.035587122322730425, + 0.028247620918516736, + 0.15290024120119527, + 0.015060373239285996, + 0.010053448879121518, + -0.0589827602590145, + 0.02289942935363687, + 0.013796524082233086, + 0.131110642093899, + -0.027682311952528904, + 0.05226392066087859, + 0.01582268713787638, + 0.03265465295798342, + -0.1303140518382413, + 0.07745214525078081, + 0.04676833378110401, + 0.00845586272365595, + -0.08279658599606066, + 0.06964140841532518, + 0.15909181739697198, + 0.11431624823211184, + 0.15545456703387317, + 0.20915048208181664, + 0.08786322049871309, + -0.11881871471958472, + 0.11815534086231794, + -0.11775645508903931, + -0.20739235395151034, + 0.10111498016851517, + -0.08983850457859055, + 0.1703356111251042, + 0.003149380068073082, + 0.010531823561399145, + 0.191080408457184, + 0.08893854628716213, + -0.006768654895150217, + -0.1288964674431985, + 0.08626954843260326, + 0.10622564168400461, + 0.03477581956734688, + -0.05661827453301571, + -0.05143487074618469, + 0.008692410650589233, + 0.0803218720457175, + -0.10545660861205497, + -0.0063822800347819175, + -0.16455277032281335, + 0.018859505029153567, + 0.06772626274968907, + 0.05238548632470841, + -0.11868333385134755, + 0.024712769598246087, + 0.092016803551761, + -0.08407225958007225, + -0.012399028923249178, + -0.0689727123294197, + -0.07655912223483385, + -0.1238948822738204, + -0.0687040937825989, + -0.004533970148011601, + 0.0721526608928671, + -0.017223261073371576, + 0.0049042927000042535, + -0.05819289736822353, + -0.09767502290530028, + -0.021867136418182165, + -0.06389964578276053, + 0.07274554374558595, + 0.06766515420466868, + 0.09081999224397186, + -0.00797364793384192, + -0.023425301350769256, + 0.07746505702521866, + 0.12592138788545926, + 0.09263743770847066, + -0.09014919919303943, + 0.17340591014962725, + -0.03465957383314944, + -0.022512819969987108, + -0.020836312410097646, + -0.0005322335163189251, + 0.029583938805666454, + -0.07824567105139746, + 0.11985293756741222, + 0.09332628916633823, + -0.12577759932035826 + ], + "mean_abs": 0.07421141935710207, + "sd_abs": 0.05211059838795353, + "realized_sigma": 0.09053007280844716, + "shared_noise_variance_share": 0.7204441525270843, + "tolerance": 0.283 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.562, + "upper": 0.283, + "minimum_detectable_gap_80": 0.6373510364334019, + "faithful_pass_probability": 0.9991416739993388, + "real_gate_holdouts": { + "estimate": -2.270246471934001, + "gap_from_epuf": -0.21851714291127466, + "lower": -0.562, + "upper": 0.283, + "pass": true + } + }, + "d_anyzero.women": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.1802394517100578, + "epuf_sampling_sd": 0.0031130699318153107, + "psid_value": 0.151093422775978, + "psid_n": 2609, + "bridge_psid_minus_epuf": -0.17638791473670734, + "min_events": 50, + "floor": { + "replicates": [ + 0.010153680097430784, + 0.0395633667127987, + 0.011553761121870787, + 0.14919244916441665, + -0.019898369470837896, + -0.014221332058080849, + -0.01968883583391179, + 0.15960575740005334, + -0.04252088152498923, + 0.026352190289331556, + -0.027995835393252788, + -0.06928748315709121, + 0.05617571766346585, + -0.0011915448620580804, + 0.003960392539886559, + 0.07747570022842665, + 0.051345930695844255, + 0.022319525310938393, + 0.08838634618092334, + -0.009469142300011724, + 0.10663016168996564, + 0.06616203368475482, + 0.051084183343682144, + 0.00264612164192235, + 0.06765209328250488, + 0.00341423824196585, + -0.01964262310548537, + 0.011874159913166205, + -0.043746251599051655, + 0.06452274151670001, + 0.036440374864393554, + -0.04134541721696494, + -0.03544419400657772, + -0.16659498284207408, + 0.021027345452591772, + -0.10756042396295085, + 0.00480142103424408, + -0.047140549194956916, + 0.16095492118366916, + -0.08335543581585825, + -0.03586164346578091, + 0.030635382761802332, + 0.017055429812710132, + 0.009604825495418301, + -0.021787644315861, + -0.019349988706166887, + 0.000964847145249581, + -0.05755065356097766, + -0.02735119201429448, + 0.11596718640775172, + 0.02728920505256438, + 0.1221859549715778, + 0.02595406870941741, + 0.028054017718809776, + -0.04194501363725711, + 0.026128823975225313, + -0.11542339836540128, + -0.011041994161186675, + -0.008163858700102056, + -0.04218023773586432, + -0.04074782775404373, + 0.07272403627938429, + 0.02092456095864359, + 0.09967549256117503, + 0.06808890407451773, + -0.029733534512762505, + 0.01158973134363872, + 0.06603444240279577, + -0.07597643237085949, + 0.04285532951529669, + 0.05366066465349939, + 0.03197023859639214, + 0.042999546923346954, + -0.0046783863755930355, + 0.0002789225763577541, + 0.05803561953688252, + 0.02658799155729763, + -0.026995784619142316, + 0.12257136273641767, + -0.01745977147394584, + 0.0410065707188928, + -0.033115159332053556, + 0.03492007121496188, + 0.0561086405370832, + 0.0508641542608157, + 0.013883731797356358, + -0.10414568484233244, + 0.02862446080920744, + -0.029238604390723122, + -0.022525483117415424, + 0.1255518937619975, + 0.016096421287819518, + 0.049834364765736106, + 0.030752417730713244, + 0.08316789869812857, + -0.008286874626800556, + 0.03901363646641465, + -0.14552178350010436, + 0.1499560196494364, + -0.0415789012115948 + ], + "mean_abs": 0.048446746358540994, + "sd_abs": 0.04092549486362834, + "realized_sigma": 0.06328692124968117, + "shared_noise_variance_share": 0.7715972613879603, + "tolerance": 0.212 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.389, + "upper": 0.212, + "minimum_detectable_gap_80": 0.4416515314678959, + "faithful_pass_probability": 0.9996095740293334, + "real_gate_holdouts": { + "estimate": -1.8716978845011494, + "gap_from_epuf": -0.15822885963913902, + "lower": -0.389, + "upper": 0.212, + "pass": true + } + }, + "q_atmax.men": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.11615905576233994, + "epuf_sampling_sd": 0.003100890006720793, + "psid_value": 0.17758180210585264, + "psid_n": 9204, + "bridge_psid_minus_epuf": 0.42447093741219777, + "min_events": 194, + "floor": { + "replicates": [ + 0.00843412274658717, + -0.03409200844396043, + -0.06577799315247546, + 0.033736627984672696, + 0.08057643434131645, + 0.08566294943381036, + -0.08154429470589009, + 0.05484388925103112, + -0.04543469460523175, + -0.03968069223271964, + 0.01627764560336664, + -0.05447794551379648, + -0.07446276793100892, + -0.06458483539317117, + 0.05488163417334657, + 0.029930238906929696, + -0.04988735741013994, + 0.026212166540517168, + -0.042112468709185835, + -0.0643332224917571, + -0.018829168047991063, + -0.03755413315246414, + -0.005641675764285203, + -0.00657668352727625, + 0.10290018286371716, + -0.008480890531639917, + -0.12200276997949977, + 0.0003235058290328441, + 0.026599418503463368, + 0.047069658783500556, + 0.0184972864190317, + 0.05637788507810737, + 0.05086279943366023, + -0.10367597783870541, + 0.016374367755696118, + -0.00018068351026057083, + 0.02559828125037955, + -0.12268184149291572, + -0.016577427555732993, + -0.09072301731655041, + -0.03078749195704311, + 0.00405111417495696, + -0.006340160420119645, + 0.004628323681505009, + 0.015028435065550627, + -0.018200968993455136, + -0.0007424787693890433, + -0.021380880099199473, + 0.002839749032820582, + 0.045815633719508475, + -0.020475838067010588, + 0.018121176320791466, + 0.05261229177605653, + 0.008065483961059994, + 0.0011692604619131242, + 0.0337615176964986, + 0.03590647009289105, + 0.029527118937377916, + 0.04665986446719084, + -0.032888018349156334, + 0.04988060606050426, + 0.007437347478792655, + 0.06948542312768768, + -0.014271552366700524, + -0.012327207631441128, + -0.0068954015778288635, + 0.10609551020096541, + 0.012485184254563353, + 0.08622360935022955, + 0.01830581187853275, + 0.061343107301697564, + -0.07926627623930049, + 0.002328910585863153, + -0.02759465077293788, + 0.06872471808442193, + 0.06062455386616983, + 0.0022164100216987004, + 0.03782362332483513, + -0.0689488635794937, + -0.0070878083635019795, + -0.019543253559266338, + 0.12447640105594082, + -0.09349077069652678, + -0.012901476892027364, + 0.029898266660784434, + -0.013835872391487536, + 0.023648999749985022, + 0.08362349906467037, + 0.061372718099296675, + -0.037889303580592504, + 0.011409445929664308, + 0.03734495567714213, + -0.03893367997892805, + 0.022626697660628192, + -0.02172649855071629, + -0.032592924097176734, + 0.0290765213086418, + 0.004017684186844006, + -0.04252381741050171, + -0.07903416733364765 + ], + "mean_abs": 0.03932807450199955, + "sd_abs": 0.031150968231388805, + "realized_sigma": 0.050073710043997056, + "shared_noise_variance_share": 0.7445235648728242, + "tolerance": 0.164 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.164, + "upper": 0.589, + "minimum_detectable_gap_80": 0.630614035028999, + "faithful_pass_probability": 0.9994914210835905, + "real_gate_holdouts": { + "estimate": -1.736333139873955, + "gap_from_epuf": 0.4164617168324696, + "lower": -0.164, + "upper": 0.589, + "pass": true + } + }, + "q_atmax.women": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.03574836724872469, + "epuf_sampling_sd": 0.00606052300187229, + "psid_value": 0.03897646373345075, + "psid_n": 10749, + "bridge_psid_minus_epuf": 0.08645337320704849, + "min_events": 27, + "floor": { + "replicates": [ + -0.24536006387987963, + -0.05952103981729295, + -0.03584511677245761, + 0.2594326322227296, + 0.13556650213510113, + 0.04604574276444917, + 0.02920239182759321, + -0.18311204220003163, + 0.14344689128193688, + 0.07803925154543867, + -0.10347987334448039, + 0.079644460543294, + -0.13553419268935385, + -0.06520938665589249, + -0.17399143490316948, + -0.047018487506690354, + -0.1844194978770599, + 0.03528537013947908, + 0.186935537924386, + 0.11544378659404808, + 0.04825990587601803, + 0.13154065697276263, + -0.016370337622008346, + -0.0460885569812397, + 0.08211326917471862, + 0.06480250988483527, + -0.04890672470991486, + 0.07489988113073398, + 0.011304272293922724, + 0.02529729883430054, + 0.12706349710018294, + -0.07277139905055052, + 0.20084562159880748, + -0.08824489661735702, + -0.17060065503681576, + -0.02322890185593174, + 0.07120806947083569, + -0.09083477658831751, + -0.032168501180461107, + -0.1138413890555039, + -0.15919293913844967, + -0.04038144182317449, + -0.005725460360337831, + 0.30604399467540855, + -0.03955548643956086, + -0.18334783799508925, + -0.043424504656244256, + -0.14264852704810904, + -0.12275107559471965, + -0.14639869478236878, + 0.05029177862319312, + 0.038775202475481496, + 0.024716622863362403, + -0.10342291514110702, + 0.12542988888340711, + 0.03549905429548672, + 0.1386350136704324, + -0.09338352008459361, + 0.1960431767409918, + -0.003695577286179086, + 0.05241300835707374, + -0.03352230867011552, + 0.006240440009228632, + 0.12436291491855611, + 0.09928743077921731, + 0.18991921733926653, + 0.10851257819563709, + 0.16939713662506928, + -0.06765473914205655, + 0.10544316153605271, + 0.2125975787737051, + 0.046950427330808564, + -0.04400950636287804, + 0.20401936896491835, + 0.06307802169299825, + 0.13682196236844102, + 0.1970692705720345, + -0.06736634004041786, + -0.03294719636326282, + 0.14754830781665018, + -0.009412127931885728, + -0.010419836985326114, + -0.006804575099132348, + -0.011646342710175617, + 0.09343361021693353, + -0.2050578370614029, + -0.06551638428758966, + -0.07537921496788091, + -0.02375570323909071, + 0.06912598987012375, + 0.020934913762387097, + 0.013161488163240254, + -0.07248692305697535, + 0.04631803546470348, + 0.03284959971181123, + 0.013724844803094882, + 0.04550961973033085, + 0.03488915833308259, + -0.06278691343983489, + -0.16835157710243465 + ], + "mean_abs": 0.09073013148033506, + "sd_abs": 0.0667141292305903, + "realized_sigma": 0.11241985610667196, + "shared_noise_variance_share": 0.7996190598281817, + "tolerance": 0.358 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.358, + "upper": 0.445, + "minimum_detectable_gap_80": 0.5390683111816352, + "faithful_pass_probability": 0.9992485362502166, + "real_gate_holdouts": { + "estimate": -3.2782390275913, + "gap_from_epuf": 0.05301165465813318, + "lower": -0.358, + "upper": 0.445, + "pass": true + } + }, + "mpers.men": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.5941642557869502, + "epuf_sampling_sd": 0.003462551711276296, + "psid_value": 0.6126704906753987, + "psid_n": 361, + "bridge_psid_minus_epuf": 0.03067144977867836, + "min_events": 10, + "floor": { + "replicates": [ + 0.02879396747458124, + -0.0008566422105176497, + 0.017076113628010786, + -0.0413131124883879, + 0.07976192112935224, + -0.0469874668640573, + -0.03615161036455747, + -0.006037868371096489, + -0.05762638558573141, + -0.03234493891707896, + -0.11525362772772965, + 0.04967649460145074, + -0.0046270963391473185, + -0.03401029015541973, + 0.044054250299758846, + 0.013176364820456893, + -0.08352481597315092, + -0.0863320320870255, + 0.17299500932479675, + 0.0017662606726903674, + -0.03453081189922669, + 0.04557363008060045, + -0.008217822412518033, + 0.013964867502223838, + -0.0003198872219154214, + 0.023854916439931262, + -0.0011138360922329782, + -0.06959479407454952, + -0.024463823840489507, + -0.024946916246465417, + 0.03358926864754169, + -0.01819065602761258, + 0.1080102389769246, + -0.006904664587984, + 0.04079875310966838, + 0.013277394081180033, + 0.14242379454686602, + -0.019689282736208513, + 0.11933601915723532, + 0.07789582730651137, + -0.026208708429585087, + 0.094175772396597, + -0.03563604950298624, + 0.07315273716243018, + -0.06270924265096234, + -0.03555131890318289, + 0.022466371332323543, + 0.061712820731880974, + -0.024372881058274287, + 0.08486655990228098, + -0.04366116337236958, + -0.03347046466810455, + 0.019614738262779402, + -0.15135794360850333, + 0.0882909553747489, + 0.04468722336158096, + 0.02265092027385096, + 0.05691411637962382, + -0.007276157037690217, + 0.008938108027363723, + -0.09409870646040358, + -0.02910288125058036, + -0.022225545628160676, + -0.0021699501533988252, + -0.04900378130126762, + -0.048227882677898876, + 0.052454976738579295, + -0.0316355906715961, + 0.037382520606727476, + -0.10921122255104715, + 0.09423133943382991, + -0.050824598765864676, + -0.02468052836512369, + -0.0002617450081405237, + 0.10050765367893277, + 0.06731717099428175, + 0.017347953070107974, + 0.0038501565359807255, + -0.0884415709745327, + -0.06173386511123474, + -0.091789785082669, + 0.06840851791839644, + 0.05459091616219425, + -0.07652445137037064, + -0.02241609130082417, + -0.11963937875423078, + 0.08002596852704297, + -0.029574223508213177, + -0.022856888760272726, + 0.0009154414142555911, + 0.019715109120236995, + 0.02956183486551653, + 0.0012306550716595088, + -0.03311902836924924, + -0.050467272385588346, + -0.10345056763012661, + 0.0029517660307466775, + 0.03024878880408438, + 0.005381027903544028, + -0.023311905916100717 + ], + "mean_abs": 0.046276669853330156, + "sd_abs": 0.037379483774143, + "realized_sigma": 0.059369889016767756, + "shared_noise_variance_share": 0.6199731556353196, + "tolerance": 0.196 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.196, + "upper": 0.227, + "minimum_detectable_gap_80": 0.2766384090100575, + "faithful_pass_probability": 0.9994609962051798, + "real_gate_holdouts": { + "estimate": -0.4918811315240385, + "gap_from_epuf": 0.028718341427559746, + "lower": -0.196, + "upper": 0.227, + "pass": true + } + }, + "mpers.women": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.4776464731309266, + "epuf_sampling_sd": 0.009017425791556429, + "psid_value": 0.5158920427896447, + "psid_n": 93, + "bridge_psid_minus_epuf": 0.07702666129718683, + "min_events": 0, + "floor": { + "replicates": [ + -0.41641599508056126, + 0.05581763343685381, + null, + 0.20177245310946001, + -0.002548071006900021, + 0.11146069434748912, + -0.1470071360631614, + -0.07299874782747545, + 0.22179957791335342, + 0.08050654630943188, + 0.00397892757118129, + -0.19109471080744367, + -0.0011514548702455385, + 0.050153305064907394, + 0.003052003455925878, + -0.13385065434347293, + 0.006231359397923908, + 0.1174910421040245, + 0.14834294311721347, + -0.15016091332105347, + 0.026160099481563948, + 0.17784716054567007, + 0.06679838168127339, + -0.15264103581406158, + 0.031162555789993163, + -0.29328014569566474, + -0.18716205928983815, + 0.10602902077582882, + -0.14563706660956477, + 0.15102554284884018, + 0.12404841709791953, + -0.050929711142149, + null, + -0.12244152064492297, + null, + 0.006533900509753665, + 0.11721417845521492, + null, + -0.03286414204329824, + -0.1887687821331681, + 0.02041636174214534, + -0.14432851455537216, + 0.13669431570608803, + 0.013155314315940525, + 0.004743812979697226, + null, + null, + 0.060704470836045354, + 0.06693194473772601, + 0.018009551772512067, + -0.09448204743222088, + 0.06081841992997, + 0.0031644098877188775, + -0.10724726512323846, + 0.03835828323418905, + 0.08527790657906908, + 0.1548039083519368, + -0.14095076991992528, + -0.0769471379423809, + -0.023345275287936673, + -0.03186102189788331, + 0.1154286682764652, + 0.11287733798433286, + -0.0038801296261344875, + -0.04544480775381238, + -0.1277091128765127, + 0.06686571277298226, + 0.029883706748795758, + null, + -0.26176908302277746, + 0.04346538288039947, + null, + 0.07498737861416394, + 0.10158839590464758, + 0.0778052677916834, + 0.037890515859538065, + -0.1732908798934919, + 0.014483002261755862, + -0.11461186632963655, + -0.03637636856783727, + null, + -0.03376279189770853, + -0.2509313095262008, + -0.2561120115438578, + 0.0034986956149389292, + -0.016146310698077926, + -0.03399056352118329, + -0.04489831379968501, + -0.06561667844273772, + 0.006294781419113604, + -0.021941542067019648, + -0.04013325961770203, + 0.14027375518989593, + -0.130005765399145, + -0.08707818261784617, + 0.10116748118812191, + 0.10141448968396927, + 0.09472836169699572, + -0.11173623894029786, + 0.023919888915225118 + ], + "mean_abs": null, + "sd_abs": null, + "realized_sigma": null, + "shared_noise_variance_share": null, + "tolerance": null + }, + "eligibility": "undefined_on_some_split", + "gated": false, + "report_reason": "undefined_on_some_split" + }, + "q_sexratio": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 3.249352759362286, + "epuf_sampling_sd": 0.007332280696240959, + "psid_value": 4.556129137837785, + "psid_n": 19953, + "bridge_psid_minus_epuf": 0.3380175642051493, + "min_events": 27, + "floor": { + "replicates": [ + 0.2693178760318813, + 0.07053226687575886, + 0.03605384483177099, + -0.1932290840286648, + -0.024929348227733628, + 0.1029779771368855, + -0.07309370555363692, + 0.2728196186445446, + -0.16360288796786893, + -0.06956266392141652, + 0.1436036634971385, + -0.09290127756317945, + 0.100999676083244, + 0.02796828200582102, + 0.29211821473727817, + 0.12288557763621721, + 0.16605770879153126, + 0.04031034219928675, + -0.20291496120878916, + -0.16117676836916972, + -0.042140323518769285, + -0.13938791876143708, + 0.0480330442044552, + 0.09858991048974786, + 0.06303090965456326, + -0.03911015052158673, + -0.044836144216222173, + -0.03958160239375352, + 0.044509588521762566, + 0.07787558615876566, + -0.08237328474271755, + 0.2017232858460829, + -0.07786933130088092, + 0.029467632996889148, + 0.23320037087501855, + 0.0922455280981489, + -0.011776142845465243, + 0.0029337674969807104, + 0.049707237063367216, + 0.051746765315515364, + 0.16031353592151, + 0.12076327674993603, + 0.05908751874215068, + -0.2713732530726469, + 0.09080225873285064, + 0.18765451835175595, + 0.07839629677831972, + 0.16186719810291517, + 0.18353772601373552, + 0.2405024026905569, + -0.02007344763668384, + 0.025750220547614333, + 0.059021880649625325, + 0.1361874234924776, + -0.10953239476761145, + 0.04392381495844466, + -0.0789948571362794, + 0.13930478518475187, + -0.0933643023349704, + 0.017896110443148983, + 0.01536993195609837, + 0.08089373620053353, + 0.10720548727618984, + -0.0890263747974237, + -0.06423048976274925, + -0.12392828405861445, + 0.05101658549688215, + -0.1259237755853927, + 0.19165846064126224, + -0.052471392679218964, + -0.12020204642220456, + -0.08514020732095018, + 0.13313868292950326, + -0.19658427715682258, + 0.03576544492959888, + -0.01808502916120569, + -0.17251434092392826, + 0.15940656217023141, + 0.019665971955032502, + -0.09172816307076792, + 0.020144580764050568, + 0.16385952210510046, + -0.0334140830209636, + 0.039905868012965695, + -0.025535184408501665, + 0.22729988172914362, + 0.1174736594031125, + 0.18872477649049257, + 0.117518007130886, + -0.0852385560136788, + 0.015478726052087444, + 0.06430547403165654, + 0.1098393869781108, + 0.014338906019941033, + 0.006614759659199776, + -0.014680147768798446, + 0.020251681137752886, + 0.009929782670549891, + 0.05733086397408704, + 0.1455046845475273 + ], + "mean_abs": 0.0978688526905515, + "sd_abs": 0.07030058245806704, + "realized_sigma": 0.12029572935881357, + "shared_noise_variance_share": 0.7113262842612574, + "tolerance": 0.379 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.379, + "upper": 0.718, + "minimum_detectable_gap_80": 0.8182610043416674, + "faithful_pass_probability": 0.9992077236128104, + "real_gate_holdouts": { + "estimate": 1.598397320948634, + "gap_from_epuf": 0.4199414954056251, + "lower": -0.379, + "upper": 0.718, + "pass": true + } + } + }, + "gate_partition": { + "status": "lockable_pending_referee_round", + "gated": [ + "r6.men", + "r6.women" + ], + "n_gated": 2, + "report_only": { + "r6.men.c0": "noise_exceeds_cap", + "r6.men.c1": "bridge_exceeds_budget", + "r6.men.c2": "noise_exceeds_cap", + "r6.women.c0": "noise_exceeds_cap", + "r6.women.c1": "cohort_rung_not_adopted", + "r6.women.c2": "noise_exceeds_cap", + "zint.men": "below_20_events", + "d_anyzero.men": "bridge_exceeds_budget", + "zint.women": "below_20_events", + "d_anyzero.women": "bridge_exceeds_budget", + "q_atmax.men": "bridge_exceeds_budget", + "q_atmax.women": "noise_exceeds_cap", + "mpers.men": "below_20_events", + "mpers.women": "undefined_on_some_split", + "q_sexratio": "noise_exceeds_cap", + "zint.men.c0": "below_20_events", + "zint.men.c1": "below_20_events", + "zint.men.c2": "below_20_events", + "zint.women.c0": "below_20_events", + "zint.women.c1": "below_20_events", + "zint.women.c2": "below_20_events", + "d_anyzero.men.c0": "below_20_events", + "d_anyzero.men.c1": "below_20_events", + "d_anyzero.men.c2": "below_20_events", + "d_anyzero.women.c0": "below_20_events", + "d_anyzero.women.c1": "below_20_events", + "d_anyzero.women.c2": "below_20_events", + "q_atmax.men.c0": "bridge_exceeds_budget", + "q_atmax.men.c1": "bridge_exceeds_budget", + "q_atmax.men.c2": "below_20_events", + "q_atmax.women.c0": "below_20_events", + "q_atmax.women.c1": "below_20_events", + "q_atmax.women.c2": "below_20_events", + "mpers.men.c0": "below_20_events", + "mpers.men.c1": "below_20_events", + "mpers.men.c2": "below_20_events", + "mpers.women.c0": "below_20_events", + "mpers.women.c1": "below_20_events", + "mpers.women.c2": "undefined_on_some_split" + }, + "n_report_only": 39 + }, + "registered": { + "r6.men": { + "epuf_value": 0.7108651036878303, + "psid_value": 0.6680476050375935, + "lower": -0.122, + "upper": 0.079 + }, + "r6.women": { + "epuf_value": 0.672102564061898, + "psid_value": 0.6397841177680634, + "lower": -0.111, + "upper": 0.078 + } + }, + "faithful_candidate_oc": { + "method": "per cell, the normal probability that bridge + noise falls inside the interval at the cell's realised sigma; analytic_product multiplies the gated cells; empirical_joint is the share of floor replicates in which every gated cell's bridge + e_b is inside", + "analytic_product": 0.9985987857839889, + "empirical_joint": 1.0, + "n_replicates": 100, + "pause_below": 0.9, + "pause": false + }, + "training_copy": { + "cells": { + "r6.men": { + "estimate": 0.6670465436202722, + "gap_from_epuf": -0.04381856006755813, + "lower": -0.122, + "upper": 0.079, + "pass": true, + "source_term_psid_minus_epuf": -0.04281749865023676, + "model_term_candidate_minus_psid": -0.0010010614173213694 + }, + "r6.women": { + "estimate": 0.6273350404581282, + "gap_from_epuf": -0.04476752360376979, + "lower": -0.111, + "upper": 0.078, + "pass": true, + "source_term_psid_minus_epuf": -0.03231844629383451, + "model_term_candidate_minus_psid": -0.012449077309935275 + } + }, + "n_gated": 2, + "n_pass": 2, + "pass": true + }, + "real_gate_seed_values": { + "0": { + "r6.men.c0": 0.7584076993820408, + "zint.men.c0": 0.058028039231156604, + "d_anyzero.men.c0": 0.10593136896875945, + "q_atmax.men.c0": 0.26667734142374017, + "mpers.men.c0": 0.8346978791445984, + "r6.men.c1": 0.7374905575477457, + "zint.men.c1": 0.07943290393080892, + "d_anyzero.men.c1": 0.08777476985650152, + "q_atmax.men.c1": 0.19869221652210475, + "mpers.men.c1": 0.8634920909289296, + "r6.men.c2": 0.7239705724068728, + "zint.men.c2": 0.015153415098541588, + "d_anyzero.men.c2": 0.04673717101893403, + "q_atmax.men.c2": 0.1316067917424688, + "mpers.men.c2": 0.44126765025343956, + "r6.men": 0.7399562764455531, + "zint.men": 0.050871452753502376, + "d_anyzero.men": 0.080147769948065, + "q_atmax.men": 0.19899211656277124, + "mpers.men": 0.7131525401089891, + "r6.women.c0": 0.5631930684974464, + "zint.women.c0": 0.05688061623748897, + "d_anyzero.women.c0": 0.11444347305940275, + "q_atmax.women.c0": 0.05065486862851886, + "mpers.women.c0": 0.6298451480601881, + "r6.women.c1": 0.7303241715845974, + "zint.women.c1": 0.06538502817384795, + "d_anyzero.women.c1": 0.14989122225845763, + "q_atmax.women.c1": 0.03328883497131927, + "mpers.women.c1": 0.15892176925494164, + "r6.women.c2": 0.642481414155306, + "zint.women.c2": 0.08619416576092499, + "d_anyzero.women.c2": 0.16959232806950833, + "q_atmax.women.c2": 0.03781695983257177, + "mpers.women.c2": 0.0, + "r6.women": 0.6453328847457832, + "zint.women": 0.06948660339075396, + "d_anyzero.women": 0.1446423411291229, + "q_atmax.women": 0.0405868878108033, + "mpers.women": 0.2629223057717099, + "q_sexratio": 4.902867090730817 + }, + "1": { + "r6.men.c0": 0.744723856065266, + "zint.men.c0": 0.09121820745384153, + "d_anyzero.men.c0": 0.1553432957807589, + "q_atmax.men.c0": 0.1891448282208163, + "mpers.men.c0": 0.6522563749510658, + "r6.men.c1": 0.703995382816119, + "zint.men.c1": 0.07298655859460879, + "d_anyzero.men.c1": 0.17049463700364548, + "q_atmax.men.c1": 0.22002904693628397, + "mpers.men.c1": 0.6355200558181616, + "r6.men.c2": 0.6450408126671987, + "zint.men.c2": 0.06414884156330447, + "d_anyzero.men.c2": 0.11027622008253585, + "q_atmax.men.c2": 0.09764195463137662, + "mpers.men.c2": 0.4735753455408396, + "r6.men": 0.6979200171828612, + "zint.men": 0.07611786920391826, + "d_anyzero.men": 0.14537138428898008, + "q_atmax.men": 0.16893860992949228, + "mpers.men": 0.5871172587700223, + "r6.women.c0": 0.785872551705493, + "zint.women.c0": 0.018248884015976193, + "d_anyzero.women.c0": 0.05202574114171492, + "q_atmax.women.c0": 0.026794562949800357, + "mpers.women.c0": 0.6886371898138405, + "r6.women.c1": 0.7087249426947722, + "zint.women.c1": 0.07283592205402131, + "d_anyzero.women.c1": 0.18226294490600656, + "q_atmax.women.c1": 0.023951762938473124, + "mpers.women.c1": 0.57430104490257, + "r6.women.c2": 0.43271262862588994, + "zint.women.c2": 0.07894717070238709, + "d_anyzero.women.c2": 0.14904408005937964, + "q_atmax.women.c2": 0.01512258789899191, + "mpers.women.c2": 0.0, + "r6.women": 0.6424367076753851, + "zint.women": 0.05667732559079486, + "d_anyzero.women": 0.12777758870236702, + "q_atmax.women": 0.021956304595755132, + "mpers.women": 0.4209794115721368, + "q_sexratio": 7.694309813963576 + }, + "2": { + "r6.men.c0": 0.6679140241615406, + "zint.men.c0": 0.09438955839930924, + "d_anyzero.men.c0": 0.14976747118620196, + "q_atmax.men.c0": 0.2204513932616166, + "mpers.men.c0": 0.8109160122089235, + "r6.men.c1": 0.754550548149083, + "zint.men.c1": 0.04205401474533761, + "d_anyzero.men.c1": 0.1070692958144441, + "q_atmax.men.c1": 0.19613612113980114, + "mpers.men.c1": 0.7828155390842664, + "r6.men.c2": 0.44945348119669404, + "zint.men.c2": 0.07108945161988178, + "d_anyzero.men.c2": 0.08394246232068486, + "q_atmax.men.c2": 0.11224766466894875, + "mpers.men.c2": 0.4043722304283604, + "r6.men": 0.6239726845024393, + "zint.men": 0.06917767492150954, + "d_anyzero.men": 0.11359307644044364, + "q_atmax.men": 0.1762783930234555, + "mpers.men": 0.6660345939071833, + "r6.women.c0": 0.6474282875986841, + "zint.women.c0": 0.05874682773830413, + "d_anyzero.women.c0": 0.10818756721840204, + "q_atmax.women.c0": 0.04525561100901698, + "mpers.women.c0": 0.7945184235556843, + "r6.women.c1": 0.7740355039110793, + "zint.women.c1": 0.07519599119054629, + "d_anyzero.women.c1": 0.1714514029642944, + "q_atmax.women.c1": 0.043545184115731175, + "mpers.women.c1": 0.7406425529799678, + "r6.women.c2": 0.4192594514967901, + "zint.women.c2": 0.09445461031077512, + "d_anyzero.women.c2": 0.1978842431324377, + "q_atmax.women.c2": 0.01879142794313749, + "mpers.women.c2": 0.0, + "r6.women": 0.6135744143355178, + "zint.women": 0.07613247641320851, + "d_anyzero.women": 0.15917440443837805, + "q_atmax.women": 0.03586407435596189, + "mpers.women": 0.5117203255118841, + "q_sexratio": 4.91518033544763 + }, + "3": { + "r6.men.c0": 0.7163311399032256, + "zint.men.c0": 0.06327941139811413, + "d_anyzero.men.c0": 0.10327368536418081, + "q_atmax.men.c0": 0.1935377157671773, + "mpers.men.c0": 0.8292630096929658, + "r6.men.c1": 0.8233604342177068, + "zint.men.c1": 0.06221630471564382, + "d_anyzero.men.c1": 0.14753949658270527, + "q_atmax.men.c1": 0.20833346855359353, + "mpers.men.c1": 0.5569468547641852, + "r6.men.c2": 0.5249274157042227, + "zint.men.c2": 0.08821127069996498, + "d_anyzero.men.c2": 0.13838202889256143, + "q_atmax.men.c2": 0.09934634013712725, + "mpers.men.c2": 0.10723148337371909, + "r6.men": 0.6882063299417185, + "zint.men": 0.07123566227124098, + "d_anyzero.men": 0.12973173694648252, + "q_atmax.men": 0.16707250815263272, + "mpers.men": 0.49781378261029, + "r6.women.c0": 0.5144302970646379, + "zint.women.c0": 0.07899144835075336, + "d_anyzero.women.c0": 0.14745325491073166, + "q_atmax.women.c0": 0.06175187189659646, + "mpers.women.c0": 0.7546827794561933, + "r6.women.c1": 0.7850050967801495, + "zint.women.c1": 0.05690518517768177, + "d_anyzero.women.c1": 0.1391476877616161, + "q_atmax.women.c1": 0.04930650318892865, + "mpers.women.c1": 0.5649993588142789, + "r6.women.c2": 0.5050872210463359, + "zint.women.c2": 0.054580210667106346, + "d_anyzero.women.c2": 0.15202069576888344, + "q_atmax.women.c2": 0.04833841048323521, + "mpers.women.c2": 0.32200709445731795, + "r6.women": 0.6015075382970411, + "zint.women": 0.06349228139851382, + "d_anyzero.women": 0.14620721281374374, + "q_atmax.women": 0.053132261856253436, + "mpers.women": 0.5472297442425967, + "q_sexratio": 3.144464442425558 + }, + "4": { + "r6.men.c0": 0.7416173076638203, + "zint.men.c0": 0.03780162811991782, + "d_anyzero.men.c0": 0.08403885374597622, + "q_atmax.men.c0": 0.23697494312202236, + "mpers.men.c0": 0.8568933087726661, + "r6.men.c1": 0.7028362496860576, + "zint.men.c1": 0.05764141589961347, + "d_anyzero.men.c1": 0.14116789743039165, + "q_atmax.men.c1": 0.23042387244301427, + "mpers.men.c1": 0.6457915780821084, + "r6.men.c2": 0.5214693295060072, + "zint.men.c2": 0.05685214605461556, + "d_anyzero.men.c2": 0.10080762105238622, + "q_atmax.men.c2": 0.10193080414602468, + "mpers.men.c2": 0.555278673031273, + "r6.men": 0.6553076289519617, + "zint.men": 0.05076506335804895, + "d_anyzero.men": 0.10867145740958468, + "q_atmax.men": 0.18977653990368712, + "mpers.men": 0.6859878532953491, + "r6.women.c0": 0.5412496850461953, + "zint.women.c0": 0.06930093143197602, + "d_anyzero.women.c0": 0.13079158749760453, + "q_atmax.women.c0": 0.027278971333667173, + "mpers.women.c0": 0.35648157133707276, + "r6.women.c1": 0.6439844123629458, + "zint.women.c1": 0.07544796066674522, + "d_anyzero.women.c1": 0.15670461145733044, + "q_atmax.women.c1": 0.028412495972593377, + "mpers.women.c1": 0.8093840909942193, + "r6.women.c2": 0.5848876309322432, + "zint.women.c2": 0.063658068327262, + "d_anyzero.women.c2": 0.18034351638464044, + "q_atmax.women.c2": 0.030228338079266916, + "mpers.women.c2": 0.0, + "r6.women": 0.5900405761137947, + "zint.women": 0.06946898680866108, + "d_anyzero.women": 0.15594657177985846, + "q_atmax.women": 0.028639935128509156, + "mpers.women": 0.38862188744376397, + "q_sexratio": 6.626290843612183 + }, + "5": { + "r6.men.c0": 0.7669028833331876, + "zint.men.c0": 0.06980728595229388, + "d_anyzero.men.c0": 0.1407913325110129, + "q_atmax.men.c0": 0.2028051548573487, + "mpers.men.c0": 0.7338146501675348, + "r6.men.c1": 0.7929489704174362, + "zint.men.c1": 0.047190453228405024, + "d_anyzero.men.c1": 0.07890986295092642, + "q_atmax.men.c1": 0.22362944259445297, + "mpers.men.c1": 0.541125346886553, + "r6.men.c2": 0.5906484087416669, + "zint.men.c2": 0.02640029551140005, + "d_anyzero.men.c2": 0.07606533198331607, + "q_atmax.men.c2": 0.13803625473696493, + "mpers.men.c2": 0.5079408983927098, + "r6.men": 0.7168334208307635, + "zint.men": 0.047799344897366314, + "d_anyzero.men": 0.0985888424817518, + "q_atmax.men": 0.18815695072958885, + "mpers.men": 0.5942936318155992, + "r6.women.c0": 0.7002795584793922, + "zint.women.c0": 0.06971873410183542, + "d_anyzero.women.c0": 0.12070103248369732, + "q_atmax.women.c0": 0.07596844563597259, + "mpers.women.c0": 0.7992132406747113, + "r6.women.c1": 0.5906669997727583, + "zint.women.c1": 0.07014584828231196, + "d_anyzero.women.c1": 0.19253138120719193, + "q_atmax.women.c1": 0.04016412770811913, + "mpers.women.c1": 0.7675157306190983, + "r6.women.c2": 0.6303705538408385, + "zint.women.c2": 0.06808722713831637, + "d_anyzero.women.c2": 0.19158532100360967, + "q_atmax.women.c2": 0.030652374924849506, + "mpers.women.c2": 0.1332072936793191, + "r6.women": 0.6404390373643296, + "zint.women": 0.06931726984082126, + "d_anyzero.women": 0.16827257823149966, + "q_atmax.women": 0.048928316089647074, + "mpers.women": 0.5666454216577096, + "q_sexratio": 3.8455635870412 + }, + "6": { + "r6.men.c0": 0.6486319729820161, + "zint.men.c0": 0.021645544769739646, + "d_anyzero.men.c0": 0.06830981247118394, + "q_atmax.men.c0": 0.25333065555643514, + "mpers.men.c0": 0.7358156451228237, + "r6.men.c1": 0.8102925240514764, + "zint.men.c1": 0.04592275107101376, + "d_anyzero.men.c1": 0.1193575374977073, + "q_atmax.men.c1": 0.21351351000414026, + "mpers.men.c1": 0.6843724242914213, + "r6.men.c2": 0.5464656756571502, + "zint.men.c2": 0.012060640123319673, + "d_anyzero.men.c2": 0.0809718470743396, + "q_atmax.men.c2": 0.08526674508758346, + "mpers.men.c2": 0.46550568245812574, + "r6.men": 0.668463390896881, + "zint.men": 0.02654297865469103, + "d_anyzero.men": 0.08954639901441026, + "q_atmax.men": 0.18403697021605295, + "mpers.men": 0.628564583957457, + "r6.women.c0": 0.8125041768859935, + "zint.women.c0": 0.049120030577171354, + "d_anyzero.women.c0": 0.10786690578256594, + "q_atmax.women.c0": 0.03311336407158906, + "mpers.women.c0": 0.7556543174334707, + "r6.women.c1": 0.7785316927707905, + "zint.women.c1": 0.08768941964891724, + "d_anyzero.women.c1": 0.1641014667850972, + "q_atmax.women.c1": 0.039930857880997185, + "mpers.women.c1": 0.3049272312817815, + "r6.women.c2": 0.3966074993236662, + "zint.women.c2": 0.08483200655657751, + "d_anyzero.women.c2": 0.24459881146616103, + "q_atmax.women.c2": 0.02539768749599886, + "mpers.women.c2": 0.0, + "r6.women": 0.66254778966015, + "zint.women": 0.07388048559422204, + "d_anyzero.women": 0.17218906134460807, + "q_atmax.women": 0.032813969816195034, + "mpers.women": 0.35352718290508406, + "q_sexratio": 5.608494529827452 + }, + "7": { + "r6.men.c0": 0.5625395107662263, + "zint.men.c0": 0.06554799794661191, + "d_anyzero.men.c0": 0.13804730630231574, + "q_atmax.men.c0": 0.20204260465654744, + "mpers.men.c0": 0.7086708685810197, + "r6.men.c1": 0.8095105516917578, + "zint.men.c1": 0.09399769799695346, + "d_anyzero.men.c1": 0.1420449905842445, + "q_atmax.men.c1": 0.24641158711515423, + "mpers.men.c1": 0.8222825037416116, + "r6.men.c2": 0.6127225937921047, + "zint.men.c2": 0.04771989547710749, + "d_anyzero.men.c2": 0.10790829703302843, + "q_atmax.men.c2": 0.10732150422918245, + "mpers.men.c2": 0.34698002536461636, + "r6.men": 0.6615908854166963, + "zint.men": 0.06908853047355762, + "d_anyzero.men": 0.12933353130652955, + "q_atmax.men": 0.18525856533362803, + "mpers.men": 0.6259777992290826, + "r6.women.c0": 0.610186965463988, + "zint.women.c0": 0.05858863770019305, + "d_anyzero.women.c0": 0.10777650375399359, + "q_atmax.women.c0": 0.04966993481198279, + "mpers.women.c0": 0.5976203183373623, + "r6.women.c1": 0.7289783188863721, + "zint.women.c1": 0.04042867847481688, + "d_anyzero.women.c1": 0.16810094519718768, + "q_atmax.women.c1": 0.03403935240239404, + "mpers.women.c1": 0.8206916449449828, + "r6.women.c2": 0.3788428511790168, + "zint.women.c2": 0.12282262391288508, + "d_anyzero.women.c2": 0.25187962066941555, + "q_atmax.women.c2": 0.006788896128220392, + "mpers.women.c2": 0.0, + "r6.women": 0.5726693785097923, + "zint.women": 0.073946646695965, + "d_anyzero.women": 0.17591902320686562, + "q_atmax.women": 0.030166061114199075, + "mpers.women": 0.47277065442744837, + "q_sexratio": 6.14129118920426 + }, + "8": { + "r6.men.c0": 0.6730113301687092, + "zint.men.c0": 0.04709522381622225, + "d_anyzero.men.c0": 0.11006049156936433, + "q_atmax.men.c0": 0.2418454771068807, + "mpers.men.c0": 0.7394832252553442, + "r6.men.c1": 0.7194819430709375, + "zint.men.c1": 0.09819601473789781, + "d_anyzero.men.c1": 0.19641025561390119, + "q_atmax.men.c1": 0.1446471715131597, + "mpers.men.c1": 0.5157314356237278, + "r6.men.c2": 0.6243955071706151, + "zint.men.c2": 0.04107992091264552, + "d_anyzero.men.c2": 0.051768540281067046, + "q_atmax.men.c2": 0.06026646157614255, + "mpers.men.c2": 0.40134499436825016, + "r6.men": 0.6722962601367538, + "zint.men": 0.062123719822255195, + "d_anyzero.men": 0.11941309582144417, + "q_atmax.men": 0.14891970339872765, + "mpers.men": 0.5521865517491074, + "r6.women.c0": 0.652630514116165, + "zint.women.c0": 0.0329916505683257, + "d_anyzero.women.c0": 0.07697361123040979, + "q_atmax.women.c0": 0.06884957260682532, + "mpers.women.c0": 0.8119113717147083, + "r6.women.c1": 0.8182480192134666, + "zint.women.c1": 0.05940053937827732, + "d_anyzero.women.c1": 0.16579218372944732, + "q_atmax.women.c1": 0.05968582044148681, + "mpers.women.c1": 0.788949873481915, + "r6.women.c2": 0.45788149969727443, + "zint.women.c2": 0.09533113221462042, + "d_anyzero.women.c2": 0.16420369854024852, + "q_atmax.women.c2": 0.015690543795473338, + "mpers.women.c2": 0.0, + "r6.women": 0.6429200110089687, + "zint.women": 0.06257444072040781, + "d_anyzero.women": 0.13565649783336856, + "q_atmax.women": 0.04807531228126182, + "mpers.women": 0.5336204150655411, + "q_sexratio": 3.097633615513126 + }, + "9": { + "r6.men.c0": 0.6448903649867037, + "zint.men.c0": 0.02049471591628514, + "d_anyzero.men.c0": 0.04578579856541182, + "q_atmax.men.c0": 0.2204323402213543, + "mpers.men.c0": 0.858611158750354, + "r6.men.c1": 0.805832766960875, + "zint.men.c1": 0.021916049124656774, + "d_anyzero.men.c1": 0.06121968031492753, + "q_atmax.men.c1": 0.19687708502753642, + "mpers.men.c1": 0.6668842116712895, + "r6.men.c2": 0.5866955955018507, + "zint.men.c2": 0.015993148896185194, + "d_anyzero.men.c2": 0.07075131455506822, + "q_atmax.men.c2": 0.08488842450580514, + "mpers.men.c2": 0.540049016728694, + "r6.men": 0.6791395758164764, + "zint.men": 0.019467971312375706, + "d_anyzero.men": 0.05925226447846919, + "q_atmax.men": 0.16739928325156528, + "mpers.men": 0.6885147957167792, + "r6.women.c0": 0.6231365428923387, + "zint.women.c0": 0.09135131403627726, + "d_anyzero.women.c0": 0.14870163324123675, + "q_atmax.women.c0": 0.06963184192748588, + "mpers.women.c0": 1.0, + "r6.women.c1": 0.7400497512986712, + "zint.women.c1": 0.09022496028628058, + "d_anyzero.women.c1": 0.1482670206879975, + "q_atmax.women.c1": 0.0485578600981394, + "mpers.women.c1": 0.6331853456054863, + "r6.women.c2": 0.6130711454135491, + "zint.women.c2": 0.10209855710619765, + "d_anyzero.women.c2": 0.2276906289922285, + "q_atmax.women.c2": 0.04516332003017142, + "mpers.women.c2": 0.4130208220248822, + "r6.women": 0.6587524798681864, + "zint.women": 0.09455827714291849, + "d_anyzero.women": 0.17488642764048756, + "q_atmax.women": 0.054451007351932236, + "mpers.women": 0.6820687225434562, + "q_sexratio": 3.0743101256073455 + }, + "10": { + "r6.men.c0": 0.6212427133674956, + "zint.men.c0": 0.07808806984784009, + "d_anyzero.men.c0": 0.11480864423850146, + "q_atmax.men.c0": 0.23699816948065236, + "mpers.men.c0": 0.6067807717512818, + "r6.men.c1": 0.6313616298392534, + "zint.men.c1": 0.05158922344045858, + "d_anyzero.men.c1": 0.14881186229704804, + "q_atmax.men.c1": 0.18134346685763886, + "mpers.men.c1": 0.5943382014298688, + "r6.men.c2": 0.5019702716744544, + "zint.men.c2": 0.029925733785611582, + "d_anyzero.men.c2": 0.06191678328386254, + "q_atmax.men.c2": 0.0934812053093778, + "mpers.men.c2": 0.382955689638204, + "r6.men": 0.5848582049604012, + "zint.men": 0.05320100902463675, + "d_anyzero.men": 0.10851242993980399, + "q_atmax.men": 0.17060761388255632, + "mpers.men": 0.5280248876064515, + "r6.women.c0": 0.47223864783191505, + "zint.women.c0": 0.05273075519188642, + "d_anyzero.women.c0": 0.1515183703221506, + "q_atmax.women.c0": 0.0258522617538916, + "mpers.women.c0": 0.5424415312921911, + "r6.women.c1": 0.6735684861345123, + "zint.women.c1": 0.08461218663352783, + "d_anyzero.women.c1": 0.1305658156395188, + "q_atmax.women.c1": 0.03216838866222512, + "mpers.women.c1": 0.7777019251399481, + "r6.women.c2": 0.45950821978648687, + "zint.women.c2": 0.0788368133294165, + "d_anyzero.women.c2": 0.1235060734018649, + "q_atmax.women.c2": 0.02581151359609841, + "mpers.women.c2": 0.5688400125234815, + "r6.women": 0.535105117917638, + "zint.women": 0.07205991838494359, + "d_anyzero.women": 0.1351967531211781, + "q_atmax.women": 0.027944054670738377, + "mpers.women": 0.6296611563185402, + "q_sexratio": 6.105327802024669 + }, + "11": { + "r6.men.c0": 0.6825358003294848, + "zint.men.c0": 0.05487004699899977, + "d_anyzero.men.c0": 0.08865147535038403, + "q_atmax.men.c0": 0.2399939487612004, + "mpers.men.c0": 0.8394081967056027, + "r6.men.c1": 0.7073629572853287, + "zint.men.c1": 0.06700353881551921, + "d_anyzero.men.c1": 0.11529181840795324, + "q_atmax.men.c1": 0.1781691322912252, + "mpers.men.c1": 0.6891900356217028, + "r6.men.c2": 0.6541773616478727, + "zint.men.c2": 0.031019319389782012, + "d_anyzero.men.c2": 0.06382445617516937, + "q_atmax.men.c2": 0.10331564576181448, + "mpers.men.c2": 0.6418588930494687, + "r6.men": 0.6813587064208955, + "zint.men": 0.050964301734766994, + "d_anyzero.men": 0.08925591664450222, + "q_atmax.men": 0.17382624227141338, + "mpers.men": 0.7234857084589247, + "r6.women.c0": 0.6305839231786088, + "zint.women.c0": 0.032183300812038275, + "d_anyzero.women.c0": 0.05926883002865709, + "q_atmax.women.c0": 0.04005141524307904, + "mpers.women.c0": 0.865193610173173, + "r6.women.c1": 0.7936135490637775, + "zint.women.c1": 0.07983011465230039, + "d_anyzero.women.c1": 0.17163196727244776, + "q_atmax.women.c1": 0.05125664572030125, + "mpers.women.c1": 0.45423751956222624, + "r6.women.c2": 0.414881022105308, + "zint.women.c2": 0.05109719509180044, + "d_anyzero.women.c2": 0.18035050691519092, + "q_atmax.women.c2": 0.024718444003158868, + "mpers.women.c2": 0.12026200060497476, + "r6.women": 0.6130261647825647, + "zint.women": 0.05437020351871303, + "d_anyzero.women": 0.13708376807209857, + "q_atmax.women": 0.038675501655513055, + "mpers.women": 0.479897710113458, + "q_sexratio": 4.4944793171579995 + }, + "12": { + "r6.men.c0": 0.6916577286112705, + "zint.men.c0": 0.03984308888550937, + "d_anyzero.men.c0": 0.07962559434349108, + "q_atmax.men.c0": 0.2515463888129417, + "mpers.men.c0": 0.75495312331371, + "r6.men.c1": 0.7436476473836336, + "zint.men.c1": 0.0710255339585582, + "d_anyzero.men.c1": 0.11793390452471553, + "q_atmax.men.c1": 0.21227895770084812, + "mpers.men.c1": 0.6236590243554032, + "r6.men.c2": 0.4820746880729034, + "zint.men.c2": 0.07431089989268741, + "d_anyzero.men.c2": 0.09705591782250371, + "q_atmax.men.c2": 0.122672135725799, + "mpers.men.c2": 0.28680450191353973, + "r6.men": 0.6391266880226025, + "zint.men": 0.06172650757891832, + "d_anyzero.men": 0.09820513889690345, + "q_atmax.men": 0.19549916074652962, + "mpers.men": 0.5551388831942177, + "r6.women.c0": 0.5572000975849147, + "zint.women.c0": 0.037766236505514875, + "d_anyzero.women.c0": 0.0958492492822864, + "q_atmax.women.c0": 0.018370651684227926, + "mpers.women.c0": 0.29711963976087574, + "r6.women.c1": 0.7369700656262805, + "zint.women.c1": 0.015837189794271175, + "d_anyzero.women.c1": 0.10293398935569978, + "q_atmax.women.c1": 0.050081206847850536, + "mpers.women.c1": 1.0, + "r6.women.c2": 0.6076446338510757, + "zint.women.c2": 0.10718920476456646, + "d_anyzero.women.c2": 0.2693387363371659, + "q_atmax.women.c2": 0.02328764493500522, + "mpers.women.c2": 0.0, + "r6.women": 0.6339382656874236, + "zint.women": 0.053597543688117505, + "d_anyzero.women": 0.15604065832505068, + "q_atmax.women": 0.030579834489027898, + "mpers.women": 0.43237321325362527, + "q_sexratio": 6.39307452159936 + }, + "13": { + "r6.men.c0": 0.6581108598194192, + "zint.men.c0": 0.07692565250127277, + "d_anyzero.men.c0": 0.14664809457480624, + "q_atmax.men.c0": 0.16453872869960856, + "mpers.men.c0": 0.5460685753250463, + "r6.men.c1": 0.7775891406815194, + "zint.men.c1": 0.019856529619383764, + "d_anyzero.men.c1": 0.05994589597711119, + "q_atmax.men.c1": 0.19484223725979732, + "mpers.men.c1": 0.6244713987710908, + "r6.men.c2": 0.5060900832465616, + "zint.men.c2": 0.05794802087603595, + "d_anyzero.men.c2": 0.08484226598172187, + "q_atmax.men.c2": 0.1117941209005673, + "mpers.men.c2": 0.39683168087940796, + "r6.men": 0.6472633612491667, + "zint.men": 0.05157673433223083, + "d_anyzero.men": 0.09714541884454643, + "q_atmax.men": 0.15705836228665773, + "mpers.men": 0.5224572183251817, + "r6.women.c0": 0.6241630423622132, + "zint.women.c0": 0.041317712078056436, + "d_anyzero.women.c0": 0.12439708311939152, + "q_atmax.women.c0": 0.05999375710119314, + "mpers.women.c0": 1.0, + "r6.women.c1": 0.6578245068353336, + "zint.women.c1": 0.08071844071715903, + "d_anyzero.women.c1": 0.17353891875606897, + "q_atmax.women.c1": 0.016417872567856668, + "mpers.women.c1": 0.0, + "r6.women.c2": 0.5886680186109523, + "zint.women.c2": 0.03835220136203151, + "d_anyzero.women.c2": 0.15384215537678286, + "q_atmax.women.c2": 0.023962808883504643, + "mpers.women.c2": 0.0, + "r6.women": 0.6235518559361664, + "zint.women": 0.05346278471908233, + "d_anyzero.women": 0.15059271908408112, + "q_atmax.women": 0.03345814618418482, + "mpers.women": 0.3333333333333333, + "q_sexratio": 4.694174071153318 + }, + "14": { + "r6.men.c0": 0.6327145188389686, + "zint.men.c0": 0.06555028912281312, + "d_anyzero.men.c0": 0.0886218994432345, + "q_atmax.men.c0": 0.2101868657878025, + "mpers.men.c0": 0.7485959252603547, + "r6.men.c1": 0.6389266752172174, + "zint.men.c1": 0.06385233902675334, + "d_anyzero.men.c1": 0.08038538056106763, + "q_atmax.men.c1": 0.20873381667819174, + "mpers.men.c1": 0.6695928182302756, + "r6.men.c2": 0.5549493977998854, + "zint.men.c2": 0.022505080399822127, + "d_anyzero.men.c2": 0.08680589734928035, + "q_atmax.men.c2": 0.084711179601421, + "mpers.men.c2": 0.23459320631706324, + "r6.men": 0.6088635306186905, + "zint.men": 0.050635902849796195, + "d_anyzero.men": 0.08527105911786081, + "q_atmax.men": 0.16787728735580507, + "mpers.men": 0.5509273166025644, + "r6.women.c0": 0.6153085982697875, + "zint.women.c0": 0.08984003425456578, + "d_anyzero.women.c0": 0.16097015813188345, + "q_atmax.women.c0": 0.05163267934360909, + "mpers.women.c0": 0.9612659607598879, + "r6.women.c1": 0.7832999957185174, + "zint.women.c1": 0.10410857158250816, + "d_anyzero.women.c1": 0.20643031068892484, + "q_atmax.women.c1": 0.04670403566621052, + "mpers.women.c1": 0.5125177462427999, + "r6.women.c2": 0.5107491816195047, + "zint.women.c2": 0.09505176859526909, + "d_anyzero.women.c2": 0.16072839656057442, + "q_atmax.women.c2": 0.01186736064485531, + "mpers.women.c2": 0.0, + "r6.women": 0.6364525918692698, + "zint.women": 0.09633345814411436, + "d_anyzero.women": 0.17604295512712756, + "q_atmax.women": 0.03673469188489164, + "mpers.women": 0.4912612356675626, + "q_sexratio": 4.569993070361104 + }, + "15": { + "r6.men.c0": 0.6742388712492521, + "zint.men.c0": 0.05347854901222566, + "d_anyzero.men.c0": 0.09762971151635937, + "q_atmax.men.c0": 0.25073598981687617, + "mpers.men.c0": 0.7857243191301211, + "r6.men.c1": 0.6582082527645828, + "zint.men.c1": 0.05064758830741425, + "d_anyzero.men.c1": 0.1170890430662094, + "q_atmax.men.c1": 0.2219151991109193, + "mpers.men.c1": 0.6826244838390615, + "r6.men.c2": 0.6728465807643471, + "zint.men.c2": 0.07366190683748658, + "d_anyzero.men.c2": 0.1068956423661012, + "q_atmax.men.c2": 0.09628640165677076, + "mpers.men.c2": 0.6447121050287521, + "r6.men": 0.6684312349260607, + "zint.men": 0.05926268138570883, + "d_anyzero.men": 0.10720479898289, + "q_atmax.men": 0.1896458635281887, + "mpers.men": 0.7043536359993116, + "r6.women.c0": 0.7144195879825712, + "zint.women.c0": 0.0737293108879775, + "d_anyzero.women.c0": 0.12105628101259172, + "q_atmax.women.c0": 0.036637777073597166, + "mpers.women.c0": 0.7500178954903365, + "r6.women.c1": 0.7460872038437824, + "zint.women.c1": 0.046873113582672106, + "d_anyzero.women.c1": 0.12287590553901545, + "q_atmax.women.c1": 0.053516047614433446, + "mpers.women.c1": 0.43152431396555857, + "r6.women.c2": 0.5828701378889998, + "zint.women.c2": 0.08908028135283526, + "d_anyzero.women.c2": 0.2347698443523592, + "q_atmax.women.c2": 0.03265324060848657, + "mpers.women.c2": 0.12749765651980857, + "r6.women": 0.681125643238451, + "zint.women": 0.06989423527449495, + "d_anyzero.women": 0.15956734363465544, + "q_atmax.women": 0.04093568843217239, + "mpers.women": 0.4363466219919012, + "q_sexratio": 4.6327757219087395 + }, + "16": { + "r6.men.c0": 0.6582683632944424, + "zint.men.c0": 0.07777196982225687, + "d_anyzero.men.c0": 0.1465279201228039, + "q_atmax.men.c0": 0.19763356842239319, + "mpers.men.c0": 0.7601567348180978, + "r6.men.c1": 0.7106979262774492, + "zint.men.c1": 0.0676072807170083, + "d_anyzero.men.c1": 0.14311368235678526, + "q_atmax.men.c1": 0.16034892682786567, + "mpers.men.c1": 0.6027916331456155, + "r6.men.c2": 0.6439219283662241, + "zint.men.c2": 0.0014629366316946057, + "d_anyzero.men.c2": 0.04043805175582596, + "q_atmax.men.c2": 0.09704969325216406, + "mpers.men.c2": 0.42244690698275766, + "r6.men": 0.6709627393127052, + "zint.men": 0.04894739572365326, + "d_anyzero.men": 0.11002655141180502, + "q_atmax.men": 0.1516773961674743, + "mpers.men": 0.5951317583154903, + "r6.women.c0": 0.7445505869965238, + "zint.women.c0": 0.0573464936003138, + "d_anyzero.women.c0": 0.10661626231302851, + "q_atmax.women.c0": 0.02420847999674458, + "mpers.women.c0": 0.5063164591475052, + "r6.women.c1": 0.7135221112431321, + "zint.women.c1": 0.081478432067636, + "d_anyzero.women.c1": 0.21609897250637203, + "q_atmax.women.c1": 0.041011366819136155, + "mpers.women.c1": 0.5466054823879153, + "r6.women.c2": 0.5196639887197123, + "zint.women.c2": 0.09865460814569284, + "d_anyzero.women.c2": 0.2005682924573052, + "q_atmax.women.c2": 0.018930532604971365, + "mpers.women.c2": 0.0, + "r6.women": 0.6592455623197894, + "zint.women": 0.07915984460454754, + "d_anyzero.women": 0.1744278424255686, + "q_atmax.women": 0.028050126473617366, + "mpers.women": 0.35097398051180684, + "q_sexratio": 5.407369421672125 + }, + "17": { + "r6.men.c0": 0.73208567974812, + "zint.men.c0": 0.082676445910168, + "d_anyzero.men.c0": 0.1639072692326339, + "q_atmax.men.c0": 0.21687645342074507, + "mpers.men.c0": 0.7525529771190848, + "r6.men.c1": 0.8502423514668278, + "zint.men.c1": 0.050469866906478075, + "d_anyzero.men.c1": 0.09255726593371882, + "q_atmax.men.c1": 0.22353897752357105, + "mpers.men.c1": 0.7425082234215821, + "r6.men.c2": 0.6864788414925715, + "zint.men.c2": 0.01913607929281029, + "d_anyzero.men.c2": 0.07054461328812055, + "q_atmax.men.c2": 0.08381734315529517, + "mpers.men.c2": 0.24421861584584853, + "r6.men": 0.7562689575691731, + "zint.men": 0.05076079736981879, + "d_anyzero.men": 0.10900304948482442, + "q_atmax.men": 0.1747442580332038, + "mpers.men": 0.5797599387955051, + "r6.women.c0": 0.7128471194328649, + "zint.women.c0": 0.031503816002706034, + "d_anyzero.women.c0": 0.08962542911595411, + "q_atmax.women.c0": 0.055597947096161934, + "mpers.women.c0": 0.6566308846585892, + "r6.women.c1": 0.6987498339374705, + "zint.women.c1": 0.05996523551304486, + "d_anyzero.women.c1": 0.16596626607253534, + "q_atmax.women.c1": 0.04540036958781714, + "mpers.women.c1": 0.9638795935981104, + "r6.women.c2": 0.5236494562513436, + "zint.women.c2": 0.10009008194410664, + "d_anyzero.women.c2": 0.193682706488078, + "q_atmax.women.c2": 0.03281875556159681, + "mpers.women.c2": 0.29495369907579905, + "r6.women": 0.6450821365405597, + "zint.women": 0.06385304448661917, + "d_anyzero.women": 0.14975813389218914, + "q_atmax.women": 0.044605690748525294, + "mpers.women": 0.6384880591108328, + "q_sexratio": 3.917532832713301 + }, + "18": { + "r6.men.c0": 0.5691579475871474, + "zint.men.c0": 0.0785839662351384, + "d_anyzero.men.c0": 0.11895109315793893, + "q_atmax.men.c0": 0.2273308012241293, + "mpers.men.c0": 0.8396658644946317, + "r6.men.c1": 0.7688230156580048, + "zint.men.c1": 0.04550761978873843, + "d_anyzero.men.c1": 0.13123573055008528, + "q_atmax.men.c1": 0.23231421207314676, + "mpers.men.c1": 0.6880706572884498, + "r6.men.c2": 0.5885998379492251, + "zint.men.c2": 0.0483378435309026, + "d_anyzero.men.c2": 0.07834808790773808, + "q_atmax.men.c2": 0.118053400281775, + "mpers.men.c2": 0.40747891503465844, + "r6.men": 0.6421936003981258, + "zint.men": 0.0574764765182598, + "d_anyzero.men": 0.10951163720525409, + "q_atmax.men": 0.19256613785968368, + "mpers.men": 0.64507181227258, + "r6.women.c0": 0.5480682711012463, + "zint.women.c0": 0.06744439953040111, + "d_anyzero.women.c0": 0.11096201591052199, + "q_atmax.women.c0": 0.06618735172834742, + "mpers.women.c0": 0.7296447256813866, + "r6.women.c1": 0.7265000762568846, + "zint.women.c1": 0.0999419833577436, + "d_anyzero.women.c1": 0.17004259267226463, + "q_atmax.women.c1": 0.05048715644812472, + "mpers.women.c1": 0.5241195909348664, + "r6.women.c2": 0.6472661216546016, + "zint.women.c2": 0.05838210352440299, + "d_anyzero.women.c2": 0.15089433456780396, + "q_atmax.women.c2": 0.022549146195994, + "mpers.women.c2": 0.0, + "r6.women": 0.6406114896709109, + "zint.women": 0.0752561621375159, + "d_anyzero.women": 0.14396631438353022, + "q_atmax.women": 0.04640788479082205, + "mpers.women": 0.4179214388720844, + "q_sexratio": 4.1494271658286594 + }, + "19": { + "r6.men.c0": 0.6428128850594452, + "zint.men.c0": 0.06120885242010446, + "d_anyzero.men.c0": 0.10665167440804141, + "q_atmax.men.c0": 0.22356245361182364, + "mpers.men.c0": 0.6943325470949332, + "r6.men.c1": 0.7516984305362697, + "zint.men.c1": 0.004354138806255288, + "d_anyzero.men.c1": 0.0464203246537008, + "q_atmax.men.c1": 0.20805696859142525, + "mpers.men.c1": 0.7831651821943473, + "r6.men.c2": 0.5192408208208362, + "zint.men.c2": 0.030165650190164137, + "d_anyzero.men.c2": 0.08077450502682551, + "q_atmax.men.c2": 0.09329613973394263, + "mpers.men.c2": 0.2790214156890242, + "r6.men": 0.637917378805517, + "zint.men": 0.031909547138841296, + "d_anyzero.men": 0.07794883469618924, + "q_atmax.men": 0.1749718539790638, + "mpers.men": 0.5855063816594349, + "r6.women.c0": 0.5668579888932699, + "zint.women.c0": 0.08305537586289401, + "d_anyzero.women.c0": 0.11030512461813208, + "q_atmax.women.c0": 0.03958788782863117, + "mpers.women.c0": 0.9506087093265538, + "r6.women.c1": 0.67658043603671, + "zint.women.c1": 0.07964810759571017, + "d_anyzero.women.c1": 0.1794570149404264, + "q_atmax.women.c1": 0.0297009561015539, + "mpers.women.c1": 0.15820877301409267, + "r6.women.c2": 0.5815850659325437, + "zint.women.c2": 0.025240796729521398, + "d_anyzero.women.c2": 0.11192525493718304, + "q_atmax.women.c2": 0.026368557271189592, + "mpers.women.c2": 0.0, + "r6.women": 0.6083411636208412, + "zint.women": 0.06264809339604187, + "d_anyzero.women": 0.13389579816524716, + "q_atmax.women": 0.03188580040045822, + "mpers.women": 0.36960582744688214, + "q_sexratio": 5.487453718632365 + } + }, + "bite_demonstrations": { + "bd1_persistence_loss_0.10": { + "fail_share": 0.44, + "cell_fail_share": { + "r6.men": 0.16, + "r6.women": 0.3 + }, + "n_perturbation_seeds": 50 + }, + "bd1_persistence_loss_0.05": { + "fail_share": 0.0, + "cell_fail_share": { + "r6.men": 0.0, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "bd2_sex_blind_donors": { + "fail_share": 0.0, + "cell_fail_share": { + "r6.men": 0.0, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "bd2c_same_sex_donors_control": { + "fail_share": 0.0, + "cell_fail_share": { + "r6.men": 0.0, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "bd3_top_tail_compression": { + "fail_share": 0.42, + "cell_fail_share": { + "r6.men": 0.42, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "bd4_participation_loss": { + "fail_share": 0.0, + "cell_fail_share": { + "r6.men": 0.0, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "requirements": { + "persistence": { + "bite": "bd1_persistence_loss_0.10", + "required_fail_share": 0.9, + "fail_share": 0.44, + "met": false + } + }, + "pause": true + }, + "ceremony_pause": true, + "tranche_r_epuf_reference": { + "note": "EPUF only. Report-only career tranche: the original four career statistics on true EPUF careers and on EPUF careers masked as the career assembler builds a PSID career (nothing before 1968; odd years from 1997 filled with the neighbour mean). The PSID side is computed once, after lock.", + "ages": [ + 22, + 61 + ], + "cells": { + "men.1930-1934": { + "epuf": { + "n_persons": 70660, + "zero_years": { + "mean": 13.868864987262949, + "p25": 2.0, + "p50": 8.0, + "p75": 25.0, + "p90": 39.0, + "share_10_or_more": 0.4651429380130201, + "share_all_40": 0.09602320973676762 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5782172197177455, + "n_pairs": 33809 + }, + "1994_2004": { + "spearman": 0.37918442395825036, + "n_pairs": 8984 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.46740013934045516, + "n_positive_person_years": 516720 + }, + "35-44": { + "share_at_max": 0.5189188334094634, + "n_positive_person_years": 505713 + }, + "45-54": { + "share_at_max": 0.28168440578661025, + "n_positive_person_years": 442055 + }, + "55-61": { + "share_at_max": 0.1655239045066384, + "n_positive_person_years": 256688 + } + }, + "aime_35yr_through_age_61": { + "p25": 429.0, + "p50": 1551.0, + "p75": 2468.0, + "p90": 2976.0, + "mean": 1515.0348995188226, + "share_zero": 0.08968298896122276 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 70660, + "zero_years": { + "mean": 23.7083215397679, + "p25": 15.0, + "p50": 20.0, + "p75": 34.0, + "p90": 40.0, + "share_10_or_more": 1.0, + "share_all_40": 0.15887347863005943 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5782172197177455, + "n_pairs": 33809 + }, + "1994_2004": { + "spearman": 0.37918442395825036, + "n_pairs": 8984 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.4707683475265525, + "n_positive_person_years": 10451 + }, + "35-44": { + "share_at_max": 0.5126409578800659, + "n_positive_person_years": 441976 + }, + "45-54": { + "share_at_max": 0.28168440578661025, + "n_positive_person_years": 442055 + }, + "55-61": { + "share_at_max": 0.1655239045066384, + "n_positive_person_years": 256688 + } + }, + "aime_35yr_through_age_61": { + "p25": 135.0, + "p50": 1000.0, + "p75": 1855.0, + "p90": 2401.0, + "mean": 1088.664265496745, + "share_zero": 0.1635578828191339 + } + } + }, + "men.1935-1939": { + "epuf": { + "n_persons": 71924, + "zero_years": { + "mean": 13.015516378399422, + "p25": 1.0, + "p50": 7.0, + "p75": 24.0, + "p90": 38.0, + "share_10_or_more": 0.4465825037539625, + "share_all_40": 0.0827540181302486 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.6448152280677847, + "n_pairs": 40517 + }, + "1994_2004": { + "spearman": 0.3430385542877868, + "n_pairs": 17307 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.4741670046615514, + "n_positive_person_years": 539949 + }, + "35-44": { + "share_at_max": 0.39699374332366855, + "n_positive_person_years": 511134 + }, + "45-54": { + "share_at_max": 0.2093870070750956, + "n_positive_person_years": 457803 + }, + "55-61": { + "share_at_max": 0.15327290962993553, + "n_positive_person_years": 271196 + } + }, + "aime_35yr_through_age_61": { + "p25": 611.0, + "p50": 1999.0, + "p75": 3208.0, + "p90": 3980.0, + "mean": 2003.4510177409488, + "share_zero": 0.07195094822312441 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 71924, + "zero_years": { + "mean": 19.67613035982426, + "p25": 10.0, + "p50": 15.0, + "p75": 30.0, + "p90": 40.0, + "share_10_or_more": 0.7852455369556754, + "share_all_40": 0.1204187753740059 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.6448152280677847, + "n_pairs": 40517 + }, + "1994_2004": { + "spearman": 0.3430385542877868, + "n_pairs": 17307 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.5093021332892343, + "n_positive_person_years": 217692 + }, + "35-44": { + "share_at_max": 0.39699374332366855, + "n_positive_person_years": 511134 + }, + "45-54": { + "share_at_max": 0.2093870070750956, + "n_positive_person_years": 457803 + }, + "55-61": { + "share_at_max": 0.12759454106016827, + "n_positive_person_years": 275145 + } + }, + "aime_35yr_through_age_61": { + "p25": 316.0, + "p50": 1547.5, + "p75": 2769.0, + "p90": 3629.0, + "mean": 1675.2360130137367, + "share_zero": 0.12386685946276625 + } + } + }, + "men.1940-1944": { + "epuf": { + "n_persons": 85938, + "zero_years": { + "mean": 12.859526635481394, + "p25": 1.0, + "p50": 7.0, + "p75": 24.0, + "p90": 38.0, + "share_10_or_more": 0.44158579440992346, + "share_all_40": 0.07283157625264726 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.646264405803841, + "n_pairs": 52149 + }, + "1994_2004": { + "spearman": 0.459118180816953, + "n_pairs": 35060 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.3897923679428147, + "n_positive_person_years": 644361 + }, + "35-44": { + "share_at_max": 0.26213208490341994, + "n_positive_person_years": 602143 + }, + "45-54": { + "share_at_max": 0.1982687936937196, + "n_positive_person_years": 556144 + }, + "55-61": { + "share_at_max": 0.15505817227620747, + "n_positive_person_years": 333836 + } + }, + "aime_35yr_through_age_61": { + "p25": 758.0, + "p50": 2491.0, + "p75": 4136.0, + "p90": 5273.0, + "mean": 2565.49358840094, + "share_zero": 0.06338290395401336 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 85938, + "zero_years": { + "mean": 15.666305941492704, + "p25": 5.0, + "p50": 10.0, + "p75": 26.0, + "p90": 39.0, + "share_10_or_more": 0.5098210337685308, + "share_all_40": 0.08992529498010193 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.646264405803841, + "n_pairs": 52149 + }, + "1994_2004": { + "spearman": 0.459118180816953, + "n_pairs": 35060 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.3969524096533309, + "n_positive_person_years": 570746 + }, + "35-44": { + "share_at_max": 0.26213208490341994, + "n_positive_person_years": 602143 + }, + "45-54": { + "share_at_max": 0.190118713204826, + "n_positive_person_years": 557478 + }, + "55-61": { + "share_at_max": 0.07738474076932603, + "n_positive_person_years": 347239 + } + }, + "aime_35yr_through_age_61": { + "p25": 560.0, + "p50": 2240.0, + "p75": 3962.0, + "p90": 5171.0, + "mean": 2401.2820870860387, + "share_zero": 0.09306709488235705 + } + } + }, + "women.1930-1934": { + "epuf": { + "n_persons": 68306, + "zero_years": { + "mean": 23.23403507744561, + "p25": 13.0, + "p50": 24.0, + "p75": 36.0, + "p90": 40.0, + "share_10_or_more": 0.816370450619272, + "share_all_40": 0.13789418206306914 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5505398027062716, + "n_pairs": 22989 + }, + "1994_2004": { + "spearman": 0.3718776181481541, + "n_pairs": 5942 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.07021585702373481, + "n_positive_person_years": 232654 + }, + "35-44": { + "share_at_max": 0.05917046049448984, + "n_positive_person_years": 301806 + }, + "45-54": { + "share_at_max": 0.021851518254839785, + "n_positive_person_years": 324188 + }, + "55-61": { + "share_at_max": 0.017649151107392805, + "n_positive_person_years": 199613 + } + }, + "aime_35yr_through_age_61": { + "p25": 57.0, + "p50": 344.0, + "p75": 887.0, + "p90": 1525.0, + "mean": 575.2575762012121, + "share_zero": 0.1289784206365473 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 68306, + "zero_years": { + "mean": 28.30464380874301, + "p25": 19.0, + "p50": 29.0, + "p75": 39.0, + "p90": 40.0, + "share_10_or_more": 1.0, + "share_all_40": 0.2301115568178491 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5505398027062716, + "n_pairs": 22989 + }, + "1994_2004": { + "spearman": 0.3718776181481541, + "n_pairs": 5942 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.03690652818991098, + "n_positive_person_years": 5392 + }, + "35-44": { + "share_at_max": 0.05844550747209552, + "n_positive_person_years": 269670 + }, + "45-54": { + "share_at_max": 0.021851518254839785, + "n_positive_person_years": 324188 + }, + "55-61": { + "share_at_max": 0.017649151107392805, + "n_positive_person_years": 199613 + } + }, + "aime_35yr_through_age_61": { + "p25": 1.0, + "p50": 182.0, + "p75": 673.0, + "p90": 1215.0, + "mean": 421.53147600503615, + "share_zero": 0.24476619916259187 + } + } + }, + "women.1935-1939": { + "epuf": { + "n_persons": 70451, + "zero_years": { + "mean": 21.490127890306738, + "p25": 10.0, + "p50": 21.0, + "p75": 34.0, + "p90": 40.0, + "share_10_or_more": 0.7701381101758669, + "share_all_40": 0.12092092376261515 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5678069951825434, + "n_pairs": 28608 + }, + "1994_2004": { + "spearman": 0.3491876980176582, + "n_pairs": 13174 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.06899211360541456, + "n_positive_person_years": 270973 + }, + "35-44": { + "share_at_max": 0.036601977764639054, + "n_positive_person_years": 345036 + }, + "45-54": { + "share_at_max": 0.0201991641353756, + "n_positive_person_years": 371352 + }, + "55-61": { + "share_at_max": 0.022266569103527794, + "n_positive_person_years": 225495 + } + }, + "aime_35yr_through_age_61": { + "p25": 110.0, + "p50": 528.0, + "p75": 1273.0, + "p90": 2114.0, + "mean": 825.1182098195909, + "share_zero": 0.10407233396261231 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 70451, + "zero_years": { + "mean": 24.921420561808915, + "p25": 15.0, + "p50": 24.0, + "p75": 37.0, + "p90": 40.0, + "share_10_or_more": 0.926629856212119, + "share_all_40": 0.1701324324707953 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5678069951825434, + "n_pairs": 28608 + }, + "1994_2004": { + "spearman": 0.3491876980176582, + "n_pairs": 13174 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.06106601080114203, + "n_positive_person_years": 116284 + }, + "35-44": { + "share_at_max": 0.036601977764639054, + "n_positive_person_years": 345036 + }, + "45-54": { + "share_at_max": 0.0201991641353756, + "n_positive_person_years": 371352 + }, + "55-61": { + "share_at_max": 0.018220695121260816, + "n_positive_person_years": 229629 + } + }, + "aime_35yr_through_age_61": { + "p25": 26.0, + "p50": 367.0, + "p75": 1064.0, + "p90": 1857.0, + "mean": 678.7997473421243, + "share_zero": 0.18045166143844657 + } + } + }, + "women.1940-1944": { + "epuf": { + "n_persons": 82476, + "zero_years": { + "mean": 19.21534749502886, + "p25": 8.0, + "p50": 17.0, + "p75": 31.0, + "p90": 39.0, + "share_10_or_more": 0.7021072796934866, + "share_all_40": 0.09477908724962414 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.546182245657991, + "n_pairs": 36701 + }, + "1994_2004": { + "spearman": 0.49476689183611483, + "n_pairs": 28822 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.052185278891862794, + "n_positive_person_years": 368763 + }, + "35-44": { + "share_at_max": 0.023083785263827306, + "n_positive_person_years": 452872 + }, + "45-54": { + "share_at_max": 0.028517795651471264, + "n_positive_person_years": 482646 + }, + "55-61": { + "share_at_max": 0.02789890602071119, + "n_positive_person_years": 287574 + } + }, + "aime_35yr_through_age_61": { + "p25": 202.0, + "p50": 835.0, + "p75": 1848.0, + "p90": 2963.0, + "mean": 1199.8868398079442, + "share_zero": 0.08391532082060235 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 82476, + "zero_years": { + "mean": 20.884584606430963, + "p25": 10.0, + "p50": 19.0, + "p75": 32.0, + "p90": 40.0, + "share_10_or_more": 0.7622823609292401, + "share_all_40": 0.11740385081720743 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.546182245657991, + "n_pairs": 36701 + }, + "1994_2004": { + "spearman": 0.49476689183611483, + "n_pairs": 28822 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.05248869878734264, + "n_positive_person_years": 328947 + }, + "35-44": { + "share_at_max": 0.023083785263827306, + "n_positive_person_years": 452872 + }, + "45-54": { + "share_at_max": 0.026930145160957278, + "n_positive_person_years": 484290 + }, + "55-61": { + "share_at_max": 0.013535773352026223, + "n_positive_person_years": 301719 + } + }, + "aime_35yr_through_age_61": { + "p25": 114.0, + "p50": 698.0, + "p75": 1687.0, + "p90": 2806.0, + "mean": 1088.7474295552645, + "share_zero": 0.12386633687375721 + } + } + } + } + }, + "concept_deltas": [ + { + "delta": "deaths, departures and arrivals", + "direction": "EPUF records none of them, so an EPUF year without earnings may follow death or precede arrival", + "handling": "every statistic conditions on covered earnings at one or both ends of its span; what remains is in the bridge" + }, + { + "delta": "noncovered employment", + "direction": "PSID labor income counts it; EPUF shows no earnings (6.4 percent of 2006 workers were noncovered, Compson 2011 Table 3)", + "handling": "in the bridge; the repository's crosswalk is unbuilt" + }, + { + "delta": "frame", + "direction": "the PSID panel is heads and spouses of responding families who stay through 2006; EPUF is every Social Security number issued before 2007", + "handling": "in the bridge; cells are within sex and cohort band" + }, + { + "delta": "reporting", + "direction": "PSID earnings are survey reports and EPUF's are employer and tax filings; whether that lowers the PSID's rank persistence is measured by the r6 bridge, not assumed", + "handling": "in the bridge" + }, + { + "delta": "birth year", + "direction": "the PSID birth year is derived from age at interview and can sit one year below EPUF's year of birth", + "handling": "nine-year cohort bands; in the bridge" + }, + { + "delta": "posting", + "direction": "EPUF 2005-2006 are short from late posting and 1998-2004 drift down slightly against the Supplement (Compson 2012)", + "handling": "the window ends in 2004; the drift is in the bridge" + }, + { + "delta": "disclosure", + "direction": "EPUF values are bottom-coded, banded and rounded", + "handling": "the same operator is applied to PSID-side earnings" + } + ], + "revision_pins": { + "head_sha": "970a9db721bf471308b4fd2666bf0d6e925250ca", + "origin_master_sha": "75cd35245f1a0c12e7a23b048a7d126c74ad8ecb", + "derivation_core_sha256": { + "src/populace_dynamics/data/epuf.py": "b101210f7aec5e52fe21d83cd8037af2abc591ec4649c4320fac4367c1b2fd4d", + "src/populace_dynamics/harness/epuf_operator.py": "dc46c3fdc7743aedbe6ced575f6c7878e5b28443f52c7e13575c2e481de27b74", + "src/populace_dynamics/harness/epuf_cells.py": "cc040adfbc2e627919767be916165736abe7a05e26cb99c3e03598ccbd504dc2", + "src/populace_dynamics/harness/epuf_gate.py": "03b4ba1df0eaf91bebc2367f239a8e6be3b2041d0f345c54c64ea8222db3a550", + "scripts/build_epuf_gate_floors.py": "3ac1cf0483568d385248d53611702d7b8d5977eab9da7ec7afb36b2a78cc4091" + } + }, + "elapsed_seconds": 204.0 +} diff --git a/runs/epuf_gate_floors_v1.json.env.json b/runs/epuf_gate_floors_v1.json.env.json new file mode 100644 index 00000000..b2b88eb6 --- /dev/null +++ b/runs/epuf_gate_floors_v1.json.env.json @@ -0,0 +1,19 @@ +{ + "environment": { + "python": "3.14.7", + "numpy": "2.5.3", + "pandas": "3.0.6", + "sklearn": "1.9.1", + "scipy": "1.18.1", + "platform": "macOS-26.6.2-arm64-arm-64bit-Mach-O", + "fitting_stack": { + "populace_fit": "absent", + "populace_frame": "absent" + } + }, + "contract": { + "blob_sha": "b0c39af1e13a705f90b85d3e6b9a91e1d3c5485c", + "head_sha": "970a9db721bf471308b4fd2666bf0d6e925250ca", + "path": "gates.yaml" + } +} diff --git a/scripts/render_gate_epuf_block_draft.py b/scripts/render_gate_epuf_block_draft.py new file mode 100644 index 00000000..90e7623b --- /dev/null +++ b/scripts/render_gate_epuf_block_draft.py @@ -0,0 +1,253 @@ +"""Render the proposed ``gates.gate_epuf`` block from its floor artifact. + +The block is the entry the lock flip will copy into ``gates.yaml``. It +is carried as ``docs/design/gate_epuf_block_draft.yaml`` with +``locked: false`` until then (the pattern gate_m6 used), because a byte +change to ``gates.yaml`` moves pins that only a ratified flip may move. +Every number in it comes from ``runs/epuf_gate_floors_v1.json``; +``tests/test_gate_epuf_block_draft.py`` requires the committed block to +equal this script's output. + +Usage:: + + uv run python scripts/render_gate_epuf_block_draft.py +""" + +from __future__ import annotations + +import hashlib +import json +from pathlib import Path + +import yaml + +ROOT = Path(__file__).resolve().parents[1] +ARTIFACT = ROOT / "runs" / "epuf_gate_floors_v1.json" +BLOCK = ROOT / "docs" / "design" / "gate_epuf_block_draft.yaml" +PROPOSAL = "docs/amendments/gate_epuf_registration_proposal.md" + +HEADER = """\ +# gate_epuf block draft (registration proposal; lock flip PENDING). +# +# The `gates.gate_epuf` block exactly as the lock flip will add it under the +# top-level `gates:` key of gates.yaml, after gate_m6, with `locked: true`. +# Until then it lives here with `locked: false` and edits no gates.yaml byte: +# any change to gates.yaml moves runs/legacy_manifest_v1.json's pin and three +# others, which only a ratified flip may move. +# +# Rendered by scripts/render_gate_epuf_block_draft.py from +# runs/epuf_gate_floors_v1.json; tests/test_gate_epuf_block_draft.py requires +# this file to equal a fresh render. Proposal and rationale: +# docs/amendments/gate_epuf_registration_proposal.md. +""" + + +def _sha256(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def _round(value, places=6): + return None if value is None else round(float(value), places) + + +STATISTIC_TEXT = { + "r6": "rank persistence of capped earnings from 1998 to 2004", + "zint": "zero years inside the window among persons positive at both ends", + "d_anyzero": "zero years before 2004 among persons positive in 2004", + "q_atmax": "the share of positive person-years at the taxable maximum", + "mpers": "persistence at the taxable maximum from 1998 to 2004", + "q_sexratio": "men's over women's share at the taxable maximum", +} + + +def covers(gated: list[str]) -> str: + """The scored surface in words: exactly the gated cells.""" + if not gated: + return ( + "Nothing is gated: every cell is report-only " + "(report_only_bridge_dominated)." + ) + parts = [] + for cell_id in gated: + stat, *rest = cell_id.split(".") + where = " ".join(rest) if rest else "both sexes" + parts.append(f"{STATISTIC_TEXT[stat]} ({where}; {cell_id})") + return ( + "Tranche G: a candidate generator's earnings on gate 1's held-out " + "persons at the even reference years 1998, 2000, 2002 and 2004, in " + "EPUF's capped and disclosed units, scored on the mean of the 20 " + "registered seeds against EPUF with an allowance for the PSID's own " + "measured distance from EPUF. Gated cells, and nothing else: " + + "; ".join(parts) + + ". Every other cell is report-only." + ) + + +def render_block(artifact: dict, artifact_sha256: str) -> dict: + partition = artifact["gate_partition"] + cells = artifact["cells"] + gated = partition["gated"] + design = artifact["design"] + oc = artifact["faithful_candidate_oc"] + if not gated: + status = "report_only_bridge_dominated" + elif artifact["ceremony_pause"]: + status = "paused_pending_referee_round" + else: + status = "draft_pending_referee_round" + bites = artifact["bite_demonstrations"] + gated_cells = {} + for cell_id in gated: + cell = cells[cell_id] + gated_cells[cell_id] = { + "metric": cell["metric"], + "cap": _round(cell["cap"]), + "epuf_value": _round(cell["epuf_value"]), + "psid_value": _round(cell["psid_value"]), + "bridge_psid_minus_epuf": _round(cell["bridge_psid_minus_epuf"]), + "tolerance": cell["floor"]["tolerance"], + "realized_sigma": _round(cell["floor"]["realized_sigma"]), + "lower": cell["lower"], + "upper": cell["upper"], + "faithful_pass_probability": _round( + cell["faithful_pass_probability"] + ), + } + return { + "gates": { + "gate_epuf": { + "id": "epuf_covered_earnings", + "status": status, + "locked": False, + "kind": "external_anchor", + "proposal": PROPOSAL, + "floor_run": "runs/epuf_gate_floors_v1.json", + "floor_run_sha256": artifact_sha256, + "external_anchor": { + "source": ( + "SSA 2006 Earnings Public-Use File (EPUF), " + "https://www.ssa.gov/policy/docs/microdata/epuf/" + ), + "provenance": "data/external/epuf_2006/provenance.md", + "members_sha256": artifact["inputs"]["epuf_sha256"], + "disclosure_constants_sha256": artifact["inputs"][ + "disclosure_constants_sha256" + ], + }, + "covers": covers(gated), + "not_certified": [ + "careers, years without earnings by age 62, and the " + "35-year AIME (tranche R, report-only)", + "any year before 1998, and 2006", + "ages outside the support's window range (about 25-57)", + "the forward earnings law certified by gate_m6", + "that the PSID agrees with EPUF (the bridge is published " + "per cell)", + "earnings levels by age, which the generator takes from " + "PSID marginals", + ], + "validation_only": ( + "No candidate may use EPUF in fitting, tuning or " + "calibration; a candidate that does is scored and " + "labelled a calibration check." + ), + "candidate_protocol": { + "panel": ( + "gate 1's candidate panel: for each gate seed s, " + "populace_dynamics.harness.panel." + "split_panel_by_person(filtered_panel, 'person_id', " + "fraction=0.2, seed=s) draws the holdout; the " + "candidate emits the holdout's persons on their " + "observed periods with generated earnings" + ), + "gate_seeds": design["gate_seeds"], + "support": design["support"], + "scoring": ( + "populace_dynamics.harness.epuf_run.score_candidate" + ), + "reproduction": ( + "a verdict attaches to a registered candidate only if " + "the run reproduces that candidate's committed gate-1 " + "artifact exactly" + ), + }, + "scoring": { + "estimator": ( + "mean over the 20 gate seeds of the per-seed value, " + "then log for shares, identity for rank correlations" + ), + "floor": design["floor"], + "k": design["k"], + "tolerance": design["tolerance"], + "interval": design["interval"], + "eligibility": design["eligibility"], + "caps": { + key: _round(value) + for key, value in design["caps"].items() + }, + "min_events": design["min_events"], + "pass_rule": ( + "the gate passes iff every gated cell's 20-seed " + "estimate lies inside its interval" + ), + }, + "gated_cells": gated_cells, + "report_only": dict(partition["report_only"]), + "faithful_candidate_oc": { + "analytic_product": _round(oc["analytic_product"]), + "empirical_joint": _round(oc["empirical_joint"]), + "pause_below": oc["pause_below"], + }, + "bite_requirements": { + family: { + "bite": row["bite"], + "required_fail_share": row["required_fail_share"], + "fail_share": row["fail_share"], + "met": row["met"], + } + for family, row in bites["requirements"].items() + }, + "ceremony_pause": artifact["ceremony_pause"], + "lock_ceremony": { + "exists": True, + "stage": "proposal", + "next": [ + "adversarial referee round", + "fixes", + "verification round", + "ratify by merge of the flip PR", + "registration of the first run on issue #42", + ], + }, + "history": [ + { + "id": "2026-10-02-epuf-registration-proposal", + "proposed": "2026-10-02", + "content": ( + "Registration proposed with the rules committed " + "before the floor build (commit " + f"{artifact['revision_pins']['head_sha'][:12]}); " + "floors in runs/epuf_gate_floors_v1.json." + ), + } + ], + } + } + } + + +def render() -> str: + artifact = json.loads(ARTIFACT.read_text(encoding="utf-8")) + block = render_block(artifact, _sha256(ARTIFACT)) + return HEADER + yaml.safe_dump( + block, sort_keys=False, width=79, allow_unicode=True + ) + + +def main() -> None: + BLOCK.write_text(render(), encoding="utf-8") + print(f"wrote {BLOCK.relative_to(ROOT)}") + + +if __name__ == "__main__": + main() diff --git a/tests/README-tiers.md b/tests/README-tiers.md index 28e081fd..313fa1f0 100644 --- a/tests/README-tiers.md +++ b/tests/README-tiers.md @@ -40,8 +40,8 @@ pytest --collect-only -q -m oracle_policyengine | tail -1 | Tier | Tests at HEAD | |---|---:| | `unit` | 5,796 | -| `artifact` | 3,344 | +| `artifact` | 3,353 | | `integration_psid` | 1,341 | | `reproduction_legacy` | 520 | | `oracle_policyengine` | 215 | -| **Total** | **11,216** | +| **Total** | **11,225** | diff --git a/tests/test_gate_epuf_block_draft.py b/tests/test_gate_epuf_block_draft.py new file mode 100644 index 00000000..6aed6e36 --- /dev/null +++ b/tests/test_gate_epuf_block_draft.py @@ -0,0 +1,194 @@ +"""Bind the EPUF gate's draft block to its committed floor artifact. + +Every tolerance, interval, partition and pass probability in +``docs/design/gate_epuf_block_draft.yaml`` is recomputed here from the +floor replicates stored in ``runs/epuf_gate_floors_v1.json`` with the +registered algebra (``populace_dynamics.harness.epuf_gate``), and the +block must equal a fresh render of the artifact. The derivation files +must still hash to the values the artifact recorded when it was built. +""" + +from __future__ import annotations + +import hashlib +import json +import math +from pathlib import Path + +import pytest +import yaml + +from populace_dynamics.harness import epuf_gate as gate +from populace_dynamics.harness.epuf_cells import cell_ids, transform + +ROOT = Path(__file__).resolve().parents[1] +ARTIFACT = ROOT / "runs" / "epuf_gate_floors_v1.json" +BLOCK = ROOT / "docs" / "design" / "gate_epuf_block_draft.yaml" +GATES = ROOT / "gates.yaml" + + +def _artifact() -> dict: + return json.loads(ARTIFACT.read_text(encoding="utf-8")) + + +def _block() -> dict: + return yaml.safe_load(BLOCK.read_text(encoding="utf-8"))["gates"][ + "gate_epuf" + ] + + +def _render(): + import importlib.util + + spec = importlib.util.spec_from_file_location( + "render_gate_epuf_block_draft", + ROOT / "scripts" / "render_gate_epuf_block_draft.py", + ) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module.render() + + +def test_block_is_the_render_of_the_committed_artifact(): + assert BLOCK.read_text(encoding="utf-8") == _render() + block = _block() + assert ( + block["floor_run_sha256"] + == hashlib.sha256(ARTIFACT.read_bytes()).hexdigest() + ) + + +def test_block_is_unlocked_and_gates_yaml_is_untouched(): + block = _block() + assert block["locked"] is False + artifact = _artifact() + if not artifact["gate_partition"]["gated"]: + assert block["status"] == "report_only_bridge_dominated" + elif artifact["ceremony_pause"]: + assert block["status"] == "paused_pending_referee_round" + else: + assert block["status"] == "draft_pending_referee_round" + assert block["ceremony_pause"] == artifact["ceremony_pause"] + gates = yaml.safe_load(GATES.read_text(encoding="utf-8"))["gates"] + assert "gate_epuf" not in gates + assert "gate_epuf" not in GATES.read_text(encoding="utf-8") + assert _artifact()["ceremony"]["gates_yaml_untouched"] is True + + +def test_derivation_files_are_the_ones_the_floor_was_built_with(): + recorded = _artifact()["revision_pins"]["derivation_core_sha256"] + assert set(recorded) == { + "src/populace_dynamics/data/epuf.py", + "src/populace_dynamics/harness/epuf_operator.py", + "src/populace_dynamics/harness/epuf_cells.py", + "src/populace_dynamics/harness/epuf_gate.py", + "scripts/build_epuf_gate_floors.py", + } + for path, digest in recorded.items(): + observed = hashlib.sha256((ROOT / path).read_bytes()).hexdigest() + assert observed == digest, path + + +def test_every_cell_is_derived_by_the_registered_algebra(): + artifact = _artifact() + assert sorted(artifact["cells"]) == sorted(cell_ids()) + reasons = {} + for cell_id, cell in artifact["cells"].items(): + replicates = cell["floor"]["replicates"] + assert len(replicates) == gate.N_FLOOR_REPLICATES + defined = None not in replicates and cell["psid_value"] is not None + if not defined: + reasons[cell_id] = "undefined_on_some_split" + assert cell["eligibility"] == "undefined_on_some_split" + continue + t = gate.tolerance(replicates) + sigma = gate.realized_sigma(replicates) + bridge = transform(cell_id, cell["psid_value"]) - transform( + cell_id, cell["epuf_value"] + ) + assert cell["floor"]["tolerance"] == t + assert cell["floor"]["realized_sigma"] == pytest.approx(sigma) + assert cell["bridge_psid_minus_epuf"] == pytest.approx(bridge) + assert (cell["lower"], cell["upper"]) == gate.hull(bridge, t) + assert cell["faithful_pass_probability"] == pytest.approx( + gate.faithful_pass_probability( + bridge, sigma, cell["lower"], cell["upper"] + ) + ) + reason = gate.demotion_reason( + gate.CellFloor( + cell_id, + True, + cell["min_events"], + bridge, + t, + sigma, + cell["epuf_sampling_sd"], + ) + ) + reasons[cell_id] = reason + assert cell["eligibility"] == (reason or "eligible") + gated, report = gate.adopt_ladder(reasons) + partition = artifact["gate_partition"] + assert partition["gated"] == gated + assert partition["report_only"] == report + + +def test_block_carries_the_artifact_partition_and_numbers(): + artifact = _artifact() + block = _block() + partition = artifact["gate_partition"] + assert list(block["gated_cells"]) == partition["gated"] + assert block["report_only"] == partition["report_only"] + for cell_id, row in block["gated_cells"].items(): + cell = artifact["cells"][cell_id] + assert row["lower"] == cell["lower"] + assert row["upper"] == cell["upper"] + assert row["tolerance"] == cell["floor"]["tolerance"] + assert max(abs(row["lower"]), abs(row["upper"])) <= cell["cap"] + assert cell["minimum_detectable_gap_80"] <= cell["cap"] + assert set(artifact["registered"]) == set(partition["gated"]) + + +def test_operating_characteristic_and_pauses(): + artifact = _artifact() + oc = artifact["faithful_candidate_oc"] + gated = artifact["gate_partition"]["gated"] + product = math.prod( + artifact["cells"][cell_id]["faithful_pass_probability"] + for cell_id in gated + ) + assert oc["analytic_product"] == pytest.approx(product if gated else 1.0) + assert oc["pause"] == (bool(gated) and product < gate.OC_PAUSE) + bites = artifact["bite_demonstrations"] + assert bites["pause"] == any( + not row["met"] for row in bites["requirements"].values() + ) + assert artifact["ceremony_pause"] == (oc["pause"] or bites["pause"]) + + +def test_real_gate_holdouts_pass_as_their_own_training_copy(): + artifact = _artifact() + if artifact["gate_partition"]["gated"]: + assert artifact["training_copy"]["pass"] is True + + +def test_the_floor_generated_no_candidate(): + artifact = _artifact() + assert artifact["candidate_blind"]["generated_candidates"] == 0 + source = (ROOT / "scripts" / "build_epuf_gate_floors.py").read_text( + encoding="utf-8" + ) + for forbidden in ("run_gate1_candidate", "populace.fit", "generate_"): + assert forbidden not in source + + +def test_gate_holdouts_are_gate_ones(): + artifact = _artifact() + gate1 = json.loads( + (ROOT / "runs" / "gate1_rank_knn_v5.json").read_text(encoding="utf-8") + ) + holdouts = artifact["holdout_ids"] + assert sorted(holdouts, key=int) == [str(s) for s in gate.GATE_SEEDS] + for row in gate1["per_seed"]: + assert holdouts[str(row["seed"])]["n_persons"] == row["n_persons"] diff --git a/tests/tier_counts.json b/tests/tier_counts.json index d71f3fce..9bbf7596 100644 --- a/tests/tier_counts.json +++ b/tests/tier_counts.json @@ -2,7 +2,7 @@ "schema_version": 1, "counts": { "unit": 5796, - "artifact": 3344, + "artifact": 3353, "integration_psid": 1341, "reproduction_legacy": 520, "oracle_policyengine": 215 From 246eab025107d70deb5efe1209089c0cd37d438a Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 16:55:49 -0400 Subject: [PATCH 4/9] Exclude the EPUF modules from the birth-evidence reducer CI shard 1 failed test_reducer_input_identity_matches_reviewed_branch: the five new opt-in modules (data/epuf.py and harness/epuf_{operator,cells, gate,run}.py) were not in POST_REVIEW_SOURCE_EXCLUSIONS or the test's matching tuple. Nothing historical imports them; the reachability test now asserts that for the five, as it does for the bridge modules. Co-Authored-By: Claude Opus 5.5 --- scripts/first_estimates_birth_evidence.py | 8 ++++++++ tests/estimates/test_birth_evidence_artifact.py | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/scripts/first_estimates_birth_evidence.py b/scripts/first_estimates_birth_evidence.py index c3962cd4..c7a6c051 100644 --- a/scripts/first_estimates_birth_evidence.py +++ b/scripts/first_estimates_birth_evidence.py @@ -342,6 +342,14 @@ Path("src/populace_dynamics/bridge/invented_population.py"), Path("src/populace_dynamics/bridge/population.py"), Path("src/populace_dynamics/bridge/population_summary.py"), + # The opt-in EPUF reader, measurement operator, cell statistics, gate + # algebra and scoring path (the proposed EPUF gate) read SSA's public + # earnings file after the fact; nothing historical imports them. + Path("src/populace_dynamics/data/epuf.py"), + Path("src/populace_dynamics/harness/epuf_operator.py"), + Path("src/populace_dynamics/harness/epuf_cells.py"), + Path("src/populace_dynamics/harness/epuf_gate.py"), + Path("src/populace_dynamics/harness/epuf_run.py"), ) POST_REVIEW_SHARED_SOURCE_BLOBS = { Path( diff --git a/tests/estimates/test_birth_evidence_artifact.py b/tests/estimates/test_birth_evidence_artifact.py index 163d7715..edd41d49 100644 --- a/tests/estimates/test_birth_evidence_artifact.py +++ b/tests/estimates/test_birth_evidence_artifact.py @@ -208,6 +208,11 @@ def test_post_review_sources_are_outside_historical_reducer_identity(): Path("src/populace_dynamics/bridge/invented_population.py"), Path("src/populace_dynamics/bridge/population.py"), Path("src/populace_dynamics/bridge/population_summary.py"), + Path("src/populace_dynamics/data/epuf.py"), + Path("src/populace_dynamics/harness/epuf_operator.py"), + Path("src/populace_dynamics/harness/epuf_cells.py"), + Path("src/populace_dynamics/harness/epuf_gate.py"), + Path("src/populace_dynamics/harness/epuf_run.py"), ) assert reducer.POST_REVIEW_SHARED_SOURCE_BLOBS == { Path( @@ -456,6 +461,18 @@ def test_post_review_exclusions_are_unreachable_from_birth_evidence(): "the opt-in PolicyEngine-US bridge became reachable from the " f"birth-evidence reducer: {sorted(bridge_modules & reachable)}" ) + epuf_modules = { + "populace_dynamics.data.epuf", + "populace_dynamics.harness.epuf_operator", + "populace_dynamics.harness.epuf_cells", + "populace_dynamics.harness.epuf_gate", + "populace_dynamics.harness.epuf_run", + } + assert epuf_modules.issubset(module_paths) + assert epuf_modules.isdisjoint(reachable), ( + "the opt-in EPUF modules became reachable from the birth-evidence " + f"reducer: {sorted(epuf_modules & reachable)}" + ) assert graph_exclusions.isdisjoint(reachable), ( "opt-in graph modules became reachable from the birth-evidence " f"reducer: {sorted(graph_exclusions & reachable)}" From d606ddeae8d064c9c57f3fc3f8e6600173ce64af Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 17:01:44 -0400 Subject: [PATCH 5/9] EPUF gate, referee round 1: the gate does not lock; cells report-only The independent referee (reviews/gate_epuf_round1_referee_20261002.md, verdict AMEND) found that the registered gate cannot fail the generator for anything gate 1 does not already catch, and rejected relaxing the bite requirement after the result. This commit takes that ruling. - The block's status is unlocked_report_only and it gates nothing. The two cells the registered rules selected are recorded beside the ruling. - runs/epuf_gate_supplement_v1.json stores each bite's per-seed estimates, mean shift and power under the gate's own noise model. The registered persistence bite shifts the correlation by 0.067 (men) while the cell's 90 percent detection point is 0.111, so the pause was built into the registration. It also stores the support's birth-year mix beside EPUF's. - runs/epuf_gate_floors_v1_first_build.json is the first floor build, frozen; a test checks its window results equal the rebuild's. - The block names the rules commit and the build commit separately and pins the scoring path's SHA-256. - The proposal states the outcome in plain words, corrects the wording the referee flagged, and lists what a gate with bite would need. - The paper's section on the PSID's limits no longer says the comparison is undesigned and unregistered. No derivation file changed: the floor artifact still binds to the code that built it. Co-Authored-By: Claude Opus 5.5 --- .../gate_epuf_registration_proposal.md | 471 +- docs/design/gate_epuf_block_draft.yaml | 91 +- paper/paper.qmd | 2 +- reviews/gate_epuf_round1_referee_20261002.md | 173 + runs/epuf_gate_floors_v1_first_build.json | 7325 +++++++++++++++++ runs/epuf_gate_supplement_v1.json | 965 +++ runs/epuf_gate_supplement_v1.json.env.json | 19 + scripts/build_epuf_gate_supplement.py | 231 + scripts/render_gate_epuf_block_draft.py | 232 +- tests/README-tiers.md | 4 +- tests/test_gate_epuf_block_draft.py | 133 +- tests/tier_counts.json | 2 +- 12 files changed, 9295 insertions(+), 353 deletions(-) create mode 100644 reviews/gate_epuf_round1_referee_20261002.md create mode 100644 runs/epuf_gate_floors_v1_first_build.json create mode 100644 runs/epuf_gate_supplement_v1.json create mode 100644 runs/epuf_gate_supplement_v1.json.env.json create mode 100644 scripts/build_epuf_gate_supplement.py diff --git a/docs/amendments/gate_epuf_registration_proposal.md b/docs/amendments/gate_epuf_registration_proposal.md index 3c782809..9b51ecd7 100644 --- a/docs/amendments/gate_epuf_registration_proposal.md +++ b/docs/amendments/gate_epuf_registration_proposal.md @@ -1,23 +1,59 @@ -# gate_epuf registration (proposal): generated earnings histories against SSA's Earnings Public-Use File +# gate_epuf registration: generated earnings histories against SSA's Earnings Public-Use File - **Registration id**: `2026-10-02-epuf-covered-earnings` -- **Gate**: `gate_epuf` (new; not in `gates.yaml`) +- **Gate**: `gate_epuf` (registered, unlocked; not in `gates.yaml`) - **Surface**: tranche G, the gate-1 generator's earnings on the four even reference years 1998-2004, by sex and birth cohort, scored against SSA's 2006 Earnings Public-Use File (EPUF). Tranche R, the career statistics, is - registered report-only. -- **Ceremony stage**: PROPOSAL (draft). This is the first step of the lock - ceremony (proposal, adversarial referee, fixes, verification, ratify by - merge, flip). **It edits no `gates.yaml` cell and no committed - `runs/*.json`.** The proposed entry is - `docs/design/gate_epuf_block_draft.yaml` with `locked: false`; the flip - copies it into `gates.yaml` in a separate ratifying PR. + report-only. +- **Ceremony stage**: CLOSED WITHOUT LOCK after referee round 1 + (`reviews/gate_epuf_round1_referee_20261002.md`). **The gate gates nothing.** + Every cell publishes report-only with each gate-1 candidate run. This + registration edits no `gates.yaml` cell and no committed `runs/*.json`; its + record is `docs/design/gate_epuf_block_draft.yaml` (`locked: false`, + `status: unlocked_report_only`). - **Class**: new gate, unlocked. No model has been scored against it. - **Evidence base**: `runs/epuf_gate_floors_v1.json` (floors, bridges, partition, operating characteristic, bite demonstrations); + `runs/epuf_gate_floors_v1_first_build.json` (the first build, frozen); + `runs/epuf_gate_supplement_v1.json` (bite shifts and power, birth-year mix); `data/external/epuf_2006/` (provenance, SSA's documentation, published tables, disclosure constants); `runs/gate1_rank_knn_v5.json` (the gate-1 run - whose generator this gate scores). + whose generator this gate would score). + +## Outcome, in plain words + +A gate here is a pass-or-fail test whose rules and thresholds are fixed and +published before the model is scored against it. + +This registration set out to make SSA's public earnings file such a test for +the model's generated earnings. **As registered, it cannot fail the generator +for anything gate 1 does not already catch, so it does not lock.** + +- The generator's earnings overlap EPUF in four years, 1998-2004. On that + overlap only two cells had the power the rules demand: how persistent + earnings ranks are from 1998 to 2004, for men and for women. +- Those two cells fail a generator only when its persistence falls about + 0.10 below the PSID's (four times in five), or about 0.11 below (nine times + in ten). The registered check on the gate's own bite asked for more: that + it catch a smaller shortfall, about 0.07, nine times in ten. The rules + could not deliver that, and the floor build showed it. That was a flaw in + the registration, foreseeable from numbers available before the build, not + a surprise in the data. +- A generator that ignores sex moved men's persistence toward EPUF's, which + the cells accept. They add no demonstrated catch beyond gate 1. +- With the PSID's distance from EPUF now public, the registered candidate's + verdict on these cells could largely be predicted. + +The independent referee ruled against loosening the check to fit the result, +and this registration takes that ruling (section 7.5). What EPUF does add is +measurement. On the generator's support the PSID's earnings ranks persist +less than SSA's records (0.668 against 0.711 for men). PSID men are at the +taxable maximum more often (17.8 against 11.6 percent of positive +person-years). Fewer PSID people have a zero year before covered work in 2004. +Every gate-1 run will publish these comparisons, and where the candidate sits +between the PSID and EPUF. Section 12 says what a gate with real bite would +need. ## 1. Summary @@ -30,17 +66,19 @@ numbers issued before 2007, with year of birth, sex and capped taxable earnings for each year from 1951 to 2006 (). -This proposal registers a gate that scores the gate-1 generator against EPUF. -Three facts shape it. +This registration scores the gate-1 generator against EPUF. Three facts shaped +it. 1. **The generator and EPUF overlap in four years.** The gate-1 generator redraws earnings on each held-out person's observed PSID periods, which are the even reference years 1998 to 2022 at ages 25 to 59 (`scripts/run_gate1_candidate10.py:258-298`). EPUF ends in 2006, and its 2005 and 2006 are short from late posting. The scoreable overlap is 1998, - 2000, 2002 and 2004. Nothing in the repository generates a career: the - careers that benefit figures rest on are observed PSID earnings from 1968 - with rule-based fills (`src/populace_dynamics/estimates/career.py:964-1076`). + 2000, 2002 and 2004. Nothing in the repository generates earnings for years + before 1998. The forward earnings law generates earnings from 2015 on + (`engine/forward_earnings.py`). The careers that benefit figures rest on + are observed PSID earnings from 1968, with rule-based fills + (`src/populace_dynamics/estimates/career.py:964-1076`). 2. **The PSID itself sits at some distance from EPUF.** PSID labor income counts noncovered work, the gate-1 panel holds heads and spouses who stay in the survey, and earnings are reported, not filed. A generator trained on @@ -51,26 +89,26 @@ Three facts shape it. generated values against the same realised PSID sample, so averaging over seeds removes only part of the noise. -The design that follows from these: score the mean over the gate's 20 -registered seeds; accept a cell when the generated value lies between EPUF and -the PSID's own position, plus a tolerance priced from a real-data floor that -includes the shared noise; and gate a cell only when that whole acceptance -band stays inside a power cap, so that a pass always means "within the cap of -EPUF". Cells that cannot meet that are published with the reason. +The design that followed: score the mean over the gate's 20 registered seeds; +accept a cell when the generated value lies between EPUF and the PSID's own +position, plus a tolerance set from a real-data floor that includes the shared +noise; and gate a cell only when that whole acceptance band stays inside a +power cap. Cells that could not meet that are published with the reason. -The four career statistics the request named (years without earnings by age -62, rank persistence ten years apart, the share at the taxable maximum by age, -and the AIME under the 35-year rule) cannot be scored on generated histories, -because no generator produces careers. They are registered as tranche R, -report-only, with their EPUF reference values in the floor artifact. +The four career statistics the request named are years without earnings by +age 62, rank persistence ten years apart, the share at the taxable maximum by +age, and the AIME under the 35-year rule. None can be scored on generated +histories, because nothing generates earnings for a career. They are registered +as tranche R, report-only, with their EPUF reference values in the floor +artifact. ## 2. What is scored **Candidate.** Any generator that emits gate 1's candidate panel: for a holdout drawn by `populace_dynamics.harness.panel.split_panel_by_person` (`fraction=0.2`, seed `s`) from gate 1's filtered panel, the holdout's persons -on their observed periods with generated `earnings`. The first registered -candidate is the gate-1 passing generator (`runs/gate1_rank_knn_v5.json`, +on their observed periods with generated `earnings`. The first candidate it +would score is the gate-1 passing generator (`runs/gate1_rank_knn_v5.json`, candidate 11). **Seeds.** The 20 seeds 0-19, the set gate 1's `c2st_mean_rule` already @@ -95,6 +133,13 @@ the real panel, never on generated values. The EPUF side is every EPUF person with sex 1 or 2 born 1947-1973, with weight 1; EPUF has no presence condition to mirror, so each statistic carries its own conditioning (section 3). +The PSID birth year is derived from age at interview, which is measured in +the wave after the income year, so it can sit a year below EPUF's year of +birth. The repository's career products take a marriage-history birth year +first (`estimates/career.py:650-656`); this registration does not. Within +each band the support's weighted mean birth year sits within 0.25 years of +EPUF's (`runs/epuf_gate_supplement_v1.json`, `birth_year_mix`). + **Units.** PSID-side and candidate-side earnings pass through EPUF's measurement operator (`populace_dynamics.harness.epuf_operator.epuf_measure`): cap at the year's contribution and benefit base, replace positive values below @@ -106,7 +151,8 @@ not publish the probabilities; the operator rounds half up. EPUF is used as published. **Validation only.** No candidate may use EPUF in fitting, tuning or -calibration. A candidate that does is scored and labelled a calibration check. +calibration, and EPUF enters nothing upstream of the model. A candidate that +uses it is scored and labelled a calibration check. ## 3. Cells @@ -138,11 +184,11 @@ How these stand to the request's four candidates: | Share at the taxable maximum by age | `q_atmax`, `mpers`, `q_sexratio` by sex and cohort band | adopted; within four calendar years a cohort band is an age band | | AIME under the 35-year rule | tranche R only | needs a career | -The generator never sees sex: its inputs are age, period and earnings ranks, +The generator never sees sex. Its inputs are age, period and earnings ranks, and its levels are quantiles of sex-pooled age-by-period marginals (`scripts/run_gate1_candidate10.py:557-562`). Gate 1 scores sex-pooled -moments. Cells by sex are therefore where this gate tests something gate 1 -does not. +moments, so cells by sex were meant to test something gate 1 does not. The +bite demonstrations found no such catch (section 7.4). ## 4. Floor, tolerance and acceptance interval @@ -161,12 +207,17 @@ function (seed `1000 + 20b + j`). `pooled` is the 20-seed estimate of section 2. The first term stands for the noise the 20 seeds share: a faithful generator's mean differs from the real value by the realised sample's own deviation from its conditional law, which is the same on every seed. The -second term stands for the noise that averages down: who falls in each -holdout, each seed's draws and each seed's fit. - -**Tolerance.** `t = round(mean|e_b| + 4 * sd|e_b|, 3)`, the house formula -(sd with `ddof=1`), with `k = 4` on every cell. `sigma` is the root mean -square of `e_b`. +term bounds that noise, and the bound is exact for a generator that draws +from the true law. A generator that copies donors from the same sample, as +candidate 11 does, has less of it, so for such a generator the floor is +conservative. The second term stands for the noise that averages down: who +falls in each holdout, each seed's draws and each seed's fit. + +**Tolerance.** `t = round(mean|e_b| + 4 * sd|e_b|, 3)`, with sd taken with +`ddof=1` and `k = 4` on every cell. The value 4 was fixed without an +operating-characteristic rule. House gates choose k against one (gate_m4) or +use 3 (gate_m6). For a single 20-seed decision, `k = 4` gives a per-cell false +fail rate near 7 in 10,000. `sigma` is the root mean square of `e_b`. **Acceptance.** With `G` the candidate's estimate less `theta_E`, a cell passes iff @@ -192,15 +243,16 @@ A cell's reason for not gating is the first of these that applies: 2. `below_20_events`: fewer than 20 events on some half, some 20% holdout of the 2,000 floor splits, or some real gate-seed holdout. Events are the smaller of a share's numerator and its complement, or a correlation's - pairs. + pairs. A sex-level cell sums its three bands' events; the house rule is + per cell, so a future registration should take the weakest band. 3. `epuf_sampling_not_negligible`: EPUF's own sampling sd (50 random groups) exceeds 0.1 `sigma`. 4. `noise_exceeds_cap`: `t + 0.8416 sigma` exceeds the cap. 5. `bridge_exceeds_budget`: `|B| + t + 0.8416 sigma` exceeds the cap. Rules 4 and 5 make the cap bind on the 80 percent power point, not on the -tolerance: a candidate whose distance from EPUF reaches the cap fails with -probability at least 0.8, and a pass certifies a distance below the cap. +tolerance. A candidate whose distance from EPUF reaches the cap fails with +probability at least 0.8, and passes up to one time in five. Among eligible cells: @@ -222,7 +274,9 @@ fails less than 90 percent of the time (section 6). **Pass rule.** The gate passes iff every gated cell passes on the 20-seed estimate. A verdict attaches to the registered candidate only if the run -reproduces that candidate's committed gate-1 artifact exactly. +reproduces that candidate's committed gate-1 artifact exactly. For seeds +5-19 that artifact stores only one statistic per seed, so a future +registration should commit digests of the generated panels. ## 6. Bite demonstrations @@ -230,21 +284,27 @@ Each is a perturbation of the real PSID support, scored on the 20 gate holdouts as a candidate would be, over 50 perturbation seeds. No candidate is generated. -| Bite | Perturbation | Required of | +| Bite | Perturbation, as computed | Required of | |---|---|---| -| `bd1` | With probability 0.10 (and, reported, 0.05) a person takes a same-sex, same-band donor's 1998-2002 earnings | persistence, if gated | +| `bd1` | With probability 0.10 (and, reported, 0.05) a person takes the 1998-2002 earnings of a donor drawn with replacement from the same sex and band, who can be the person themself | persistence, if gated | | `bd2` | Everyone takes the 1998-2002 path of a donor in the same band and 2004 class (no earnings, or decile of 2004 earnings), drawn from both sexes | reported | | `bd2c` | As `bd2`, donors of the person's own sex: the control that isolates pooling the sexes | reported | -| `bd3` | In 1998-2002, half of each year's top 8 percent of positive earners move to a rank drawn uniformly from 0.5 to 0.92 | tail, if gated | +| `bd3` | In each of 1998-2002, values whose rank among the year's positive values (ties at their highest rank, sexes and bands pooled) exceeds 0.92 move, with probability 0.5, to the value at a rank drawn uniformly from 0.5 to 0.92; every value at the cap is eligible to move | tail, if gated | | `bd4` | Each positive 1998-2002 person-year becomes zero with probability 0.03 | participation, if gated | The real gate-seed holdouts are also scored as a training copy and must pass. +These fail shares perturb the realised sample and score it on the fixed gate +holdouts. They therefore leave out the noise the seeds share, which a +generator's verdict includes. `runs/epuf_gate_supplement_v1.json` adds each +bite's mean shift and its power under the gate's own noise model. + ## 7. Results of the floor build -All numbers in this section come from `runs/epuf_gate_floors_v1.json`. -`tests/test_gate_epuf_block_draft.py` recomputes every tolerance, interval, -partition and pass probability from the floor replicates stored there. +The numbers in this section come from `runs/epuf_gate_floors_v1.json` and +`runs/epuf_gate_supplement_v1.json`. `tests/test_gate_epuf_block_draft.py` +recomputes every tolerance, interval, partition, pass probability, bite shift +and power figure from what those files store. ### 7.1 Support @@ -266,10 +326,10 @@ equals `runs/gate1_rank_knn_v5.json`'s for seeds 0-4. Sex-level cells. "Bridge" is the PSID's distance from EPUF on the cell's metric scale (log ratio for shares, difference for correlations). -| Cell | EPUF | PSID | Bridge | Tolerance `t` | Outcome | +| Cell | EPUF | PSID | Bridge | Tolerance `t` | Outcome under the registered rules | |---|---:|---:|---:|---:|---| -| `r6.men` | 0.711 | 0.668 | -0.043 | 0.079 | **gated** | -| `r6.women` | 0.672 | 0.640 | -0.032 | 0.078 | **gated** | +| `r6.men` | 0.711 | 0.668 | -0.043 | 0.079 | selected | +| `r6.women` | 0.672 | 0.640 | -0.032 | 0.078 | selected | | `zint.men` | 0.051 | 0.049 | -0.040 | 0.381 | below 20 events | | `zint.women` | 0.066 | 0.070 | +0.062 | 0.381 | below 20 events | | `d_anyzero.men` | 0.128 | 0.097 | -0.278 | 0.283 | bridge exceeds budget | @@ -284,88 +344,101 @@ What the table says, and what it does not: - **Rank persistence.** On the support, PSID earnings ranks persist less from 1998 to 2004 than EPUF's do: 0.668 against 0.711 for men, 0.640 - against 0.672 for women. The bridge measures the gap; it does not say how - much of it is reporting error, frame or noncovered work. + against 0.672 for women. The bridge measures the gap. It does not say how + much of it comes from reporting, from who the PSID samples, or from + noncovered work. - **The taxable maximum.** Among positive person-years, 17.8 percent of the PSID support's men are at the wage base, against 11.6 percent of EPUF's men born in the same years. The support is people who stayed in the survey - as heads or spouses through 2006, a more attached group than every EPUF - earner. A log gap of 0.42 exceeds the cap, so the cell is reported. + as heads or spouses through 2006, and EPUF is every Social Security number; + the artifact does not separate how much of the gap that difference + explains. A log gap of 0.42 exceeds the cap, so the cell is reported. - **Zero years.** Given covered earnings in 2004, fewer PSID men and women had a zero year in 1998-2002 than EPUF's (9.7 against 12.8 percent for - men). EPUF counts noncovered spells and years before arrival as zeros; the - PSID counts noncovered earnings as earnings. + men). EPUF records only covered earnings, so a year of noncovered work is a + zero there and not in the PSID; how much of the gap that accounts for is + not measured here. - **Power.** Interior zero years and persistence at the maximum are too rare at the PSID's size for the 20-event rule. No cohort-band cell is powered within the caps. -### 7.3 Gated surface and operating characteristic +### 7.3 The cells the rules selected, and their operating characteristic -Two cells gate, by the ladder's fallback to sex-level persistence: +The ladder fell back to sex-level persistence and selected two cells: | Cell | Interval for `G` | Realised sigma | Shared-noise share of floor variance | Faithful pass probability | |---|---|---:|---:|---:| | `r6.men` | [-0.122, 0.079] | 0.0246 | 0.78 | 0.9993 | | `r6.women` | [-0.111, 0.078] | 0.0248 | 0.73 | 0.9993 | -The gate's faithful-candidate pass probability is 0.9986 by product, and in -100 of 100 floor replicates every gated cell's `B + e_b` lies inside its -interval. The real gate-seed holdouts, scored as a candidate, pass (`G` = +The faithful-candidate pass probability of the two is 0.9986 by product, and +in 100 of 100 floor replicates both cells' `B + e_b` lie inside their +intervals. The real gate-seed holdouts, scored as a candidate, pass (`G` = -0.044 for men and -0.045 for women). About three-quarters of each cell's floor variance is the term the 20 seeds share, which a floor of 20%/80% splits alone would have left out. -### 7.4 Bite demonstrations, and the pause - -| Bite | Fails the gate | `r6.men` | `r6.women` | -|---|---:|---:|---:| -| `bd1`, donor early years for 10% of persons | 0.44 | 0.16 | 0.30 | -| `bd1`, for 5% of persons | 0.00 | 0.00 | 0.00 | -| `bd2`, donors from both sexes | 0.00 | 0.00 | 0.00 | -| `bd2c`, donors of the same sex (control) | 0.00 | 0.00 | 0.00 | -| `bd3`, top-tail compression | 0.42 | 0.42 | 0.00 | -| `bd4`, participation loss | 0.00 | 0.00 | 0.00 | - -The registered requirement for the gated persistence family is that `bd1` -at 10 percent fails at least 90 percent of the time. It fails 44 percent of -the time, so **the ceremony pauses** (section 5). Giving 10 percent of -persons a donor's early years lowers the 1998-2004 correlation by about a -tenth, roughly 0.07; the gate fails a shortfall from the PSID of about -`t + 0.84 sigma`, 0.10, four times in five. Sex-blind donors move neither -cell, so the cells by sex add no catch for a generator that ignores sex, at -least on persistence. - -### 7.5 What the pause asks the referee round to decide - -The rules forbid choosing among these by looking at more results, so this -proposal stops here and lists them, with what each costs: - -- **(a) Lock the two persistence cells as they stand** and restate the bite - requirement at what the gate demonstrably detects: a shortfall of 0.10 in - the 1998-2004 rank correlation, at 80 percent power. The certified claim - would be honest, and comparable in resolution to gate 1's battery - tolerances (0.06 to 0.07 on log autocorrelation). But the requirement - would be relaxed after the result was seen, which the forks ledger must - record. -- **(b) Redesign the surface for power**, without the bridges: pool the - sexes, or score persistence on everyone present in 1998 and 2004 rather - than in all four years. Either is a fork. Neither is computed here, - because searching redesigns after seeing the bridges is what the ledger - exists to prevent. -- **(c) Publish EPUF as a benchmark, not a gate.** Every gate-1 candidate - run would carry the per-cell table and its decomposition into the model's - distance from the PSID and the PSID's distance from EPUF, with no pass or - fail. A gate would follow when a generator covers more of EPUF's years. - -The drafting session recommends (a). It is the only pass-or-fail test of -the generator against administrative records, its power matches gate 1's -comparable bands, and the relaxation is disclosed. The decision belongs to -the referee round and the maintainer. +### 7.4 Bite demonstrations, and why the pause was built in + +| Bite | Fails the gate (fixed holdouts) | Mean shift, men / women | Power under the gate's noise model, men / women | +|---|---:|---|---| +| `bd1`, 10% of persons | 0.44 | -0.067 / -0.057 | 0.30 / 0.19 | +| `bd1`, 5% of persons | 0.00 | -0.033 / -0.030 | 0.03 / 0.02 | +| `bd2`, donors from both sexes | 0.00 | +0.056 / -0.006 | 0.00 / 0.00 | +| `bd2c`, same-sex donors (control) | 0.00 | +0.007 / +0.010 | 0.00 / 0.00 | +| `bd3`, top-tail compression | 0.42 | -0.076 / -0.005 | 0.45 / 0.00 | +| `bd4`, participation loss | 0.00 | +0.001 / -0.001 | 0.00 / 0.00 | + +The registered requirement for the persistence family is that `bd1` at 10 +percent fails at least 90 percent of the time. It fails 44 percent of the +time on the fixed holdouts, so **the ceremony paused** (section 5). + +The requirement could not have been met. Under the gate's own noise model the +two cells fail a shortfall from the PSID of 0.100 (men) and 0.100 (women) +four times in five, and of 0.111 and 0.110 nine times in ten +(`detection_points` in the supplement). `bd1` at 10 percent shifts the +correlation by about 0.07, inside both points, so a 90 percent requirement on +it was out of reach whatever the data showed. The eligibility rule promised +80 percent power at the first point; the bite asked for 90 percent at a smaller +shortfall. EPUF subsampled to PSID scale, which the design panel had before +the build, gave sigma near this size. So the pause comes from an internal +inconsistency of the registration that could have been seen in advance, not +from something the data revealed. + +Two more readings, both from the supplement: + +- Sex-blind donors (`bd2`) raise men's persistence by 0.056, toward EPUF's + value, where the interval accepts it. The cells by sex catch no sex-blind + generator here. +- No perturbation was shown to pass gate 1's battery and fail these cells. + Their catch beyond gate 1 is not demonstrated. + +### 7.5 Referee round 1 and the ruling + +Three options were put to the referee round: (a) lock the two persistence +cells and restate the bite requirement at what they demonstrably detect; +(b) redesign the surface for power; (c) publish the comparison report-only. + +The referee (`reviews/gate_epuf_round1_referee_20261002.md`, verdict AMEND) +rejected (a). A requirement rewritten to match a gate's demonstrated power no +longer tests anything. Locking now, with the bridges' signs known, would +choose a gate the registered candidate very likely passes. Candidate 11 +persists more than the PSID at two and four years in gate 1, which here moves +it toward EPUF, inside the interval. The referee also ruled that (b) cannot be +done blind, because every redesign it names is informed by the bridges. + +**Ruling: the gate does not lock.** Every cell publishes report-only with +each gate-1 candidate run: the candidate's 20-seed estimate, its distance +from EPUF, and that distance split into the candidate's distance from the +PSID and the PSID's distance from EPUF +(`populace_dynamics.harness.epuf_run.score_candidate`). The drafting +session had recommended (a); it withdraws that recommendation. A gate with +bite needs a fresh registration (section 12). ### 7.6 Tranche R on EPUF alone These numbers use no PSID. They compare EPUF careers as published with the -same careers rewritten by the career assembler's two rules (section 8). +same careers rewritten by two of the career assembler's rules (section 8). | Cohort | Mean zero years, ages 22-61 | Median AIME | 25th percentile AIME | |---|---|---|---| @@ -376,19 +449,17 @@ same careers rewritten by the career assembler's two rules (section 8). | women 1935-1939 | 21.5 -> 24.9 | $528 -> $367 | $110 -> $26 | | women 1940-1944 | 19.2 -> 20.9 | $835 -> $698 | $202 -> $114 | -The rules alone lower the median AIME of men born 1940-1944 by 10 percent, -and of those born 1930-1934 by 36 percent, because they count earnings -before 1968 as zero. A cohort born in 1946 or later loses no year to that -rule, so the table shows the size of the effect where it applies, not across -the repository's benefit cohorts. The PSID career product's -own values are computed once, after lock, beside these. +The two rules alone lower the median AIME of men born 1940-1944 by 10 percent, +and of those born 1930-1934 by 36 percent, because they count earnings before +1968 as zero. A cohort born in 1946 or later loses no year to that rule, so +the table shows the size of the effect where it applies, not across the +repository's benefit cohorts. ## 8. Tranche R: career statistics, report-only -Report-only, computed once in the post-lock run, never gated. The statistics -are the request's four, on annual capped histories at ages 22-61, by sex and -birth cohort (1930-1934, 1935-1939, 1940-1944: the cohorts whose whole window -lies inside 1951-2006): +Report-only and never gated. The statistics are the request's four, on annual +capped histories at ages 22-61, by sex and birth cohort (1930-1934, +1935-1939, 1940-1944: the cohorts whose whole window lies inside 1951-2006): - years without earnings (mean, quartiles, share with ten or more, share with all 40); @@ -400,76 +471,72 @@ lies inside 1951-2006): `populace_dynamics.ss.statutory_aime.aime`. The floor artifact holds their EPUF values twice: on EPUF as published, and -on EPUF masked the way the career assembler builds a PSID career (nothing -before `max(1968, birth year + 22)`; each odd year from 1997 filled with the -mean of its neighbours). -The difference is exact and involves no PSID: it is what those two rules -alone do to administrative careers. The post-lock run adds the PSID career -product's values beside the masked EPUF values. Survival to the PSID's -observation years has no EPUF counterpart and is named as a difference, not -corrected. +on EPUF rewritten by two of the career assembler's rules. Under those rules +nothing counts before `max(1968, birth year + 22)`, and each odd year from +1997 is filled with the mean of its neighbours. The mask does not apply the +assembler's exclusions of low-coverage and incomplete-domain persons +(`estimates/career.py:1581-1598`). For the cohorts used, `max(1968, birth year ++ 22)` is 1968 for everyone. The difference is exact and involves no PSID. A +run adds the PSID career product's values beside the masked EPUF values. +Survival to the PSID's observation years has no EPUF counterpart and is named +as a difference, not corrected. Why report-only: the career product is observed PSID earnings with fixed fill rules. It has no generator to hold out and no faithful-candidate null, -and its distance from EPUF is the bridge itself. A career-completion model, -when one exists, becomes gate-eligible on these cells by amendment. +and its distance from EPUF is the bridge itself. -## 9. What a pass certifies +## 9. What is published, and what is not certified -A pass certifies, for each gated cell and only those: the generated value's -distance from EPUF is below the cell's cap, and no larger than the PSID's own -distance plus noise. +Every gate-1 candidate run publishes each cell's 20-seed estimate, its +distance from EPUF, and the split of that distance into the candidate's +distance from the PSID and the PSID's distance from EPUF. Tranche R publishes +the career statistics beside the masked EPUF values. -Not certified, at the same prominence: +Nothing is certified. In particular: +- no pass or fail, on any cell; - careers, years without earnings by age 62, and the 35-year AIME; - any year before 1998, and 2006; -- ages outside the support's range in the window, about 25 to 57; -- the forward earnings law of `gate_m6`, which this gate does not touch; -- that the PSID agrees with EPUF. The bridge is published per cell; a pass - that rests on a large bridge says the generator is no worse than its source; -- levels by age, which the generator takes from PSID marginals. +- that the PSID agrees with EPUF. The bridge is published per cell. ## 10. Blindness and forking paths **Order of commits.** 1. `eec910d6` holds the reader, operator, cell statistics, gate algebra, - floor builder, their tests and sections 1-6 and 8-13 of this document. It - was pushed (2026-10-02 13:37 UTC) before any real-PSID value in EPUF units - existed. -2. The floor builder then ran once. While reading its output the drafting - session found a bug in the report-only career AIME (fork 1 below), fixed it - in the next commit, and rebuilt. The first build's outputs are preserved in - the evidence folder with their hashes - (`epuf-20261001/first-floor-build/`, artifact SHA-256 `369bf5ec…7e378`). - The rebuild's window cells, floors, partition and bites are identical to the - first build's; only tranche R's EPUF values differ. -3. The next commit adds the rebuilt artifact, the draft block and section 7. - The artifact records the commit it was built at and the SHA-256 of each - derivation file; a test fails if one changes afterwards. + floor builder, their tests and the rules (sections 2-6 and 8 of this + document). It was pushed on 2026-10-02 at 13:37 UTC, before any real-PSID + value in EPUF units existed, and PR #509 opened on it. +2. The floor builder then ran once, at that commit. While reading its output + the drafting session found a bug in the report-only career AIME (fork 1). + It fixed the bug in `970a9db7` and rebuilt. + `runs/epuf_gate_floors_v1_first_build.json` is the first build, frozen + (SHA-256 `369bf5ec4e62c0eaa2f70702a9173188c87e84a5544bb4470826781c1847e378`). + A test checks that its window cells, floors, partition and bites equal the + rebuild's; only tranche R differs. +3. `ce8d5000` added the rebuilt artifact, the draft block and section 7. + Neither artifact records its build time. The supplement records its own + (2026-10-02 20:55 UTC). +4. The round-1 commit adds the referee report, the supplement, the frozen + first build, the ruling and these corrections. **Forks ledger.** | # | Change after the first floor build | Partition before | Partition after | Why it is not a self-rescue | |---|---|---|---|---| -| 1 | Career AIME ranks every year after 1950 through age 61, not only ages 22-61; the career-assembler mask starts at `max(1968, birth year + 22)` | `r6.men`, `r6.women` | unchanged | tranche R is report-only and enters no gated rule; the statute fixes the definition | - -**Who has seen what, at the first commit.** The drafting session and the -design panel saw: EPUF-only values of every cell; EPUF subsampled to PSID -scale; gate 1's committed artifacts, including that candidate 11's sex-pooled -log autocorrelation is above the PSID reference at two and four years and -below it at ten on all five seeds. No one had computed a real-PSID value in -EPUF units, a bridge, or any candidate value under this gate's measurement. +| 1 | Career AIME ranks every year after 1950 through age 61, not only ages 22-61; the career-assembler mask starts at `max(1968, birth year + 22)` | `r6.men`, `r6.women` selected | unchanged | tranche R is report-only and enters no gated rule; the statute fixes the definition | +| 2 | Referee round 1: the gate does not lock; the two selected cells become report-only | `r6.men`, `r6.women` selected | nothing gated | it removes a pass-or-fail surface rather than rescuing one, and no rule or threshold was changed to reach it | -**After the floor build.** The bridges are then known, and with the gate-1 -battery they suggest how the first candidate will score. That is why the -partition is mechanical and fixed first. Any later change to a rule is -recorded in a forks ledger in this document with the partition before and -after, and no cell may be redefined on account of its own bridge. +**Who had seen what at the rules commit.** The drafting session and the +design panel had seen EPUF-only values of every cell, and EPUF subsampled to +PSID scale. They had also seen gate 1's committed artifacts. Those show that +candidate 11's sex-pooled log autocorrelation is above the PSID reference at +two and four years and below it at ten, on all five seeds. No one had +computed a real-PSID value in EPUF units, a bridge, or any candidate value +under this gate's measurement. -**Before lock.** No candidate is generated. Tranche R's PSID side is not -computed. +**Before any run.** No candidate has been generated. Tranche R's PSID side +has not been computed. ## 11. Considered and rejected @@ -483,11 +550,11 @@ computed. per-seed noise is more than twice the 20-seed noise, which leaves almost no cell inside the caps. 5. **A floor from 20%/80% splits alone, divided by the square root of 20.** It - omits the noise the seeds share, which + omits the noise the seeds share. The two-term floor bounds that noise, and + the bound is exact for a generator that draws from the true law. `tests/harness/test_epuf_gate.py::test_floor_prices_a_faithful_generator` - shows by simulation: a faithful generator's 20-seed mean spreads about as - widely as the two-term floor and well beyond the one-term floor. The - artifact records each cell's shared-noise share of the floor variance. + shows by simulation that such a generator's 20-seed mean spreads about as + widely as the two-term floor and well beyond the one-term floor. 6. **Gating the career product.** It is observed data, not a generator (section 8). 7. **Including 2006.** EPUF's 2006 worker count is 97.3 percent of the @@ -501,31 +568,43 @@ computed. 10. **The planning documents' fixed bands** (one point on the share at the maximum, 0.05 on correlations; `docs/evaluation-and-model-selection.md`). They are not priced from a floor. - -## 12. The lock flip (not in this pull request) - -Ratification is by merge of a flip PR after an adversarial referee round and -a verification round. The flip: - -1. copies `docs/design/gate_epuf_block_draft.yaml` into `gates.yaml` after - `gate_m6`, with `locked: true`; -2. extends the gate-set allowlists in `tests/test_gates_derivations.py` and - `tests/test_gate_w1_derivations.py`; -3. re-pins `CONTRACT_BLOB_LIVE` (`tests/test_gate_w1_candidate4_pin.py`) and - runs `scripts/build_legacy_manifest.py --transition`; -4. registers the first run on issue #42 with the run script, the commit and - a forecast. - -The post-lock run regenerates candidate 11 on seeds 0-19, asserts exact -reproduction of `runs/gate1_rank_knn_v5.json`, scores the panels with -`populace_dynamics.harness.epuf_run.score_candidate`, computes tranche R, and -publishes the result whatever it is. +11. **Locking with the bite requirement restated after the result** (option + (a)). Rejected in referee round 1 (section 7.5). + +## 12. What a gate with bite would need + +This surface cannot be rescued by retuning. The PSID's size sets the noise: +on about 2,500 people per sex, the 1998-2004 rank correlation has a realised +sigma of 0.025. Even with `k` chosen so a faithful generator passes 95 percent +of the time, a tolerance near two sigmas would leave a 90 percent detection +point near 0.08 below the PSID. And every redesign of these cells is now +informed by their bridges. + +A fresh EPUF gate, under a new registration id, would need all of these +before its floor is built: + +1. **Unseen ground.** Cells whose PSID-against-EPUF bridges no one has + computed. On the current generator there are none. A generator that + produced earnings for EPUF's earlier years would supply them. So would + careers, where the tranche R statistics become scoreable; the PSID records + earnings every year from 1968 to 1996. +2. **A consistent bite.** `k` set by a stated operating-characteristic rule, + and every bite dosed above its cell's own 90 percent detection point, + checked against EPUF subsampled to PSID scale before the build. +3. **A catch beyond gate 1.** A perturbation shown, before lock, to pass gate + 1's battery and fail the new gate. +4. **Bites under the gate's noise model**, with the noise the seeds share + included, as the supplement now computes them. +5. **The smaller house details** found in round 1: events counted on the + weakest band of a sex-level cell; panel digests for every scored seed; + the repository's birth-year precedence; a build timestamp in the artifact; + floor half-split seeds that do not reuse gate seeds. ## 13. Ceremony checklist -- [x] **Proposal** (this document, the floor artifact, the draft block) -- [ ] Adversarial referee round, including the bite pause (section 7.5) -- [ ] Fixes -- [ ] Verification round -- [ ] Ratify by merge of the flip PR -- [ ] Registration of the first run on issue #42 +- [x] Proposal: this document, the floor artifact, the draft block +- [x] Adversarial referee round 1 (verdict AMEND) +- [x] Fixes: the supplement, the frozen first build, separate rules and build + commits in the block, a pinned scoring path, corrected wording +- [x] Ruling: closed without lock; every cell report-only +- [ ] Verification of this record by an independent reviewer (PR #509) diff --git a/docs/design/gate_epuf_block_draft.yaml b/docs/design/gate_epuf_block_draft.yaml index 44dbafb2..049f77da 100644 --- a/docs/design/gate_epuf_block_draft.yaml +++ b/docs/design/gate_epuf_block_draft.yaml @@ -1,24 +1,37 @@ -# gate_epuf block draft (registration proposal; lock flip PENDING). +# gate_epuf registration record (unlocked; not in gates.yaml). # -# The `gates.gate_epuf` block exactly as the lock flip will add it under the -# top-level `gates:` key of gates.yaml, after gate_m6, with `locked: true`. -# Until then it lives here with `locked: false` and edits no gates.yaml byte: -# any change to gates.yaml moves runs/legacy_manifest_v1.json's pin and three -# others, which only a ratified flip may move. +# Round 1 of the referee review ruled that the gate does not lock as +# registered: as designed it cannot fail the generator for anything gate 1 +# does not already catch. The block records the registered rules, the +# partition they produced, and the ruling. It gates nothing; every cell +# publishes report-only with each gate-1 run. It edits no gates.yaml byte. # # Rendered by scripts/render_gate_epuf_block_draft.py from # runs/epuf_gate_floors_v1.json; tests/test_gate_epuf_block_draft.py requires -# this file to equal a fresh render. Proposal and rationale: +# this file to equal a fresh render. Proposal, results and ruling: # docs/amendments/gate_epuf_registration_proposal.md. gates: gate_epuf: id: epuf_covered_earnings - status: paused_pending_referee_round + status: unlocked_report_only locked: false kind: external_anchor proposal: docs/amendments/gate_epuf_registration_proposal.md + rules_commit: eec910d61a7e0afe21995957740e03d64acdffdc + floor_build_commit: 970a9db721bf471308b4fd2666bf0d6e925250ca floor_run: runs/epuf_gate_floors_v1.json floor_run_sha256: 33e75b96199ce748f0b9aaab0d77d1925405eede93d5e883fa329fde4d87e686 + first_floor_build: + path: runs/epuf_gate_floors_v1_first_build.json + sha256: 369bf5ec4e62c0eaa2f70702a9173188c87e84a5544bb4470826781c1847e378 + note: the build before the report-only career-AIME fix (proposal section 10); + its window cells, floors, partition and bites equal the floor run's + supplement: + path: runs/epuf_gate_supplement_v1.json + sha256: 1570f80e5b42c0890871a818e29f09bdf55fdafe26ba4a2aaa7cade4280ea676 + scoring_path: + module: src/populace_dynamics/harness/epuf_run.py + sha256: f1a3055a36f225b59adf2240e1398b18724f06364706d692faf4445b380de995 external_anchor: source: SSA 2006 Earnings Public-Use File (EPUF), https://www.ssa.gov/policy/docs/microdata/epuf/ provenance: data/external/epuf_2006/provenance.md @@ -26,21 +39,16 @@ gates: EPUF2006_DEMOGRAPHIC.csv: 195db459ca7b7c810162cb6e432371e8787eba8331787d2ba1eace1a0da2ccb0 EPUF2006_ANNUAL.csv: a47315b56214df66fb9f9abcb2caa60779c8b3d091ded199323672c27e3ea105 disclosure_constants_sha256: ba1f39f238278243de19b8a9d194abedffeabd855f5b97779b685d852f62a881 - covers: 'Tranche G: a candidate generator''s earnings on gate 1''s held-out persons - at the even reference years 1998, 2000, 2002 and 2004, in EPUF''s capped and - disclosed units, scored on the mean of the 20 registered seeds against EPUF - with an allowance for the PSID''s own measured distance from EPUF. Gated cells, - and nothing else: rank persistence of capped earnings from 1998 to 2004 (men; - r6.men); rank persistence of capped earnings from 1998 to 2004 (women; r6.women). - Every other cell is report-only.' + covers: 'Nothing is gated. Every cell is published report-only with each gate-1 + candidate run: the candidate''s 20-seed estimate, its distance from EPUF, and + that distance split into the candidate''s distance from the PSID and the PSID''s + distance from EPUF.' not_certified: + - 'anything: the gate is unlocked and gates no cell' - careers, years without earnings by age 62, and the 35-year AIME (tranche R, report-only) - any year before 1998, and 2006 - - ages outside the support's window range (about 25-57) - - the forward earnings law certified by gate_m6 - that the PSID agrees with EPUF (the bridge is published per cell) - - earnings levels by age, which the generator takes from PSID marginals validation_only: No candidate may use EPUF in fitting, tuning or calibration; a candidate that does is scored and labelled a calibration check. candidate_protocol: @@ -79,9 +87,7 @@ gates: weight: the person's 2004-row weight epuf: every EPUF person with sex 1 or 2 born 1947-1973, weight 1 scoring: populace_dynamics.harness.epuf_run.score_candidate - reproduction: a verdict attaches to a registered candidate only if the run - reproduces that candidate's committed gate-1 artifact exactly - scoring: + registered_scoring: estimator: mean over the 20 gate seeds of the per-seed value, then log for shares, identity for rank correlations floor: @@ -98,9 +104,8 @@ gates: log_ratio: 0.405465 abs_gap: 0.15 min_events: 20 - pass_rule: the gate passes iff every gated cell's 20-seed estimate lies inside - its interval - gated_cells: + gated_cells: {} + selected_by_registered_rules: r6.men: metric: abs_gap cap: 0.15 @@ -124,6 +129,8 @@ gates: upper: 0.078 faithful_pass_probability: 0.99925 report_only: + r6.men: not_locked_referee_round_1 + r6.women: not_locked_referee_round_1 r6.men.c0: noise_exceeds_cap r6.men.c1: bridge_exceeds_budget r6.men.c2: noise_exceeds_cap @@ -163,10 +170,9 @@ gates: mpers.women.c0: below_20_events mpers.women.c1: below_20_events mpers.women.c2: undefined_on_some_split - faithful_candidate_oc: + faithful_candidate_oc_of_selected_cells: analytic_product: 0.998599 empirical_joint: 1.0 - pause_below: 0.9 bite_requirements: persistence: bite: bd1_persistence_loss_0.10 @@ -174,17 +180,30 @@ gates: fail_share: 0.44 met: false ceremony_pause: true + referee_round_1: + report: reviews/gate_epuf_round1_referee_20261002.md + reviewer: independent Opus 5.5 lane (subfleet job 20261002-095515-epuf-gate-r1b), + reviewing head ce8d5000 + verdict: 'AMEND: do not lock as registered' + ruling: 'Not locked. The registered persistence bite could not be met by design: + the tolerance is about 3.2 realised sigmas (0.079) while giving 10 percent + of persons a donor''s early years shifts the 1998-2004 rank correlation by + about 0.07, so the pause was an internal inconsistency of the registration, + not a data surprise. The two cells the rules selected add no demonstrated + catch beyond gate 1, and with the bridge signs public the registered candidate''s + verdict is largely predictable. Relaxing the bite requirement after seeing + the result (option (a)) is rejected; the cells publish report-only with every + gate-1 run. A gate with bite needs a fresh registration (proposal section + 12).' lock_ceremony: - exists: true - stage: proposal - next: - - adversarial referee round - - fixes - - verification round - - ratify by merge of the flip PR - - 'registration of the first run on issue #42' + exists: false + stage: closed without lock (referee round 1) + required_for_any_future_lock: a fresh registration with a new id, its rules + fixed before anything is recomputed (proposal section 12) history: - id: 2026-10-02-epuf-registration-proposal proposed: '2026-10-02' - content: Registration proposed with the rules committed before the floor build - (commit 970a9db721bf); floors in runs/epuf_gate_floors_v1.json. + content: Rules committed and pushed before the floor build (commit eec910d61a7e); + floors built at commit 970a9db721bf. + - id: 2026-10-02-epuf-referee-round-1 + content: 'Referee round 1: AMEND. Ruling: not locked; report-only (referee_round_1).' diff --git a/paper/paper.qmd b/paper/paper.qmd index 4e81eeab..e3a3ad64 100644 --- a/paper/paper.qmd +++ b/paper/paper.qmd @@ -363,7 +363,7 @@ The model addresses these limits in two ways, and we plan a third. None removes **Gates scored on the PSID.** The gates that score the model against the PSID set most of their tolerances from the discrepancy between two disjoint halves of the real PSID panel (@sec-scoring). A smaller panel produces a wider floor and a looser tolerance. Gates 2, 2b, 2c, m4 and m6 demote to report-only any cell whose weaker half holds fewer than 20 events or whose tolerance would exceed a cap, ln(1.5) for most cells and 0.15 for gate m6's earnings correlations (`gates.yaml`). These rules price the PSID's sampling noise. They cannot detect a bias that both halves share, because both halves come from the same selected and attrited panel: such a gate tests whether the model reproduces the PSID, and leaves open how far the PSID departs from the population. Gate m6 scores only the people the PSID observed in each later wave, treats the PSID's record of deaths above age 85 as confounded by attrition, and certifies nothing about mortality drift (`gates.yaml`, gate_m6). -**A planned check against administrative earnings records.** We plan to set the earnings careers the model reads from the PSID, and those it generates, against the Social Security Administration's 2006 Earnings Public-Use File. The file holds annual earnings records for 1951 through 2006 from a 1 percent random sample of all Social Security numbers issued before 2007, 4,384,254 people in all [@ssa2011epuf; @ssa2011epufdict].^[SSA's article introducing the file gives 4,348,254 in three places and 4,384,254 in another; its own count of the underlying sample less the records it removed yields 4,384,254 [@compson2011epuf].] Its records come from the earnings posted to workers' Social Security records, so they do not depend on anyone continuing to answer a survey. They hold only earnings up to each year's taxable maximum from jobs Social Security covers, with wages and self-employment combined, and the file records each person's birth year and sex and nothing about marriage, children, disability or death [@compson2011epuf]. The file follows each person across years, so it can test change over time as well as single years. Moffitt and Zhang report that the PSID's earnings data have never been matched to government administrative records [@moffitt2020estimating]. The comparison would run by birth year and sex and cover the share of years with no covered earnings, the share of low-earnings years, movement into and out of covered work, and how persistent a worker's position stays over time. Selective attrition and weak low-end reporting would distort these statistics, and the PSID's own halves cannot reveal the distortion. The comparison has to put the model's earnings on the file's terms, capped at each year's taxable maximum and limited to covered work. It also has to put the two populations on common terms. The file records no deaths, so a run of years without earnings can mean retirement, disability or death [@compson2011epuf], and its sample of Social Security numbers includes the post-1968 immigrants the PSID largely leaves out. The file's own low end is coarse: SSA replaces every amount under $100 with that year's average and rounds amounts from $100 to $1,000 at random to a base of $25 [@ssa2011epufdict; @compson2011epuf]. We would register the comparison before running it, as we do every gate. The check is separate work, and we have not yet designed, registered or run it. +**A planned check against administrative earnings records.** We plan to set the earnings careers the model reads from the PSID, and those it generates, against the Social Security Administration's 2006 Earnings Public-Use File. The file holds annual earnings records for 1951 through 2006 from a 1 percent random sample of all Social Security numbers issued before 2007, 4,384,254 people in all [@ssa2011epuf; @ssa2011epufdict].^[SSA's article introducing the file gives 4,348,254 in three places and 4,384,254 in another; its own count of the underlying sample less the records it removed yields 4,384,254 [@compson2011epuf].] Its records come from the earnings posted to workers' Social Security records, so they do not depend on anyone continuing to answer a survey. They hold only earnings up to each year's taxable maximum from jobs Social Security covers, with wages and self-employment combined, and the file records each person's birth year and sex and nothing about marriage, children, disability or death [@compson2011epuf]. The file follows each person across years, so it can test change over time as well as single years. Moffitt and Zhang report that the PSID's earnings data have never been matched to government administrative records [@moffitt2020estimating]. The comparison would run by birth year and sex and cover the share of years with no covered earnings, the share of low-earnings years, movement into and out of covered work, and how persistent a worker's position stays over time. Selective attrition and weak low-end reporting would distort these statistics, and the PSID's own halves cannot reveal the distortion. The comparison has to put the model's earnings on the file's terms, capped at each year's taxable maximum and limited to covered work. It also has to put the two populations on common terms. The file records no deaths, so a run of years without earnings can mean retirement, disability or death [@compson2011epuf], and its sample of Social Security numbers includes the post-1968 immigrants the PSID largely leaves out. The file's own low end is coarse: SSA replaces every amount under $100 with that year's average and rounds amounts from $100 to $1,000 at random to a base of $25 [@ssa2011epufdict; @compson2011epuf]. We registered the rules for one part of this comparison before computing any of it, as we do every gate (`docs/amendments/gate_epuf_registration_proposal.md`). That part covers the generated earnings, which overlap the file only in the even years from 1998 to 2004. On that overlap the PSID is too small for the comparison to pass or fail the generator on anything gate 1 does not already test, so we report it and do not gate it. We have not yet scored the model's earnings against the file, and we have not run the comparison of careers. | Limit | What it does to the model | What the model does today | What remains open | |---|---|---|---| diff --git a/reviews/gate_epuf_round1_referee_20261002.md b/reviews/gate_epuf_round1_referee_20261002.md new file mode 100644 index 00000000..2c7ab45e --- /dev/null +++ b/reviews/gate_epuf_round1_referee_20261002.md @@ -0,0 +1,173 @@ + + +# Referee report: `gate_epuf` registration (PR #509, branch `epuf-gate-registration-20261001`) + +## Verdict: AMEND. Do not lock as proposed: reject option (a) and adopt option (c) + +As measurement code, the rules-first machinery is mostly sound: the reader, operator, cells, gate algebra and ladder hold up. The gated surface should not lock. The pre-registered pause fired. The remedy the drafting session recommends, (a), relaxes a pre-registered requirement after the result was seen, and it would lock a gate whose first verdict can largely be predicted from public information. Publish tranche G as a report-only benchmark (option (c)), after the record fixes below. If a pass-or-fail EPUF gate is still wanted, it should come from a fresh registration whose rules are fixed before anything is recomputed (option (b), gate_m6 style). + +**What I could not do.** This session had no shell, so I ran no tests and no Python. The evidence is code reading plus hand arithmetic on the values committed in `runs/epuf_gate_floors_v1.json`. I read no PSID microdata. I also could not check the push-time chronology against git. + +--- + +## Findings + +### 1. SERIOUS: Option (a) is a self-serving fork; the right remedy is (c) + +- **It rescues the gate after the fact.** (a) restates the bite requirement "at what the gate demonstrably detects" (proposal §7.5). Any gate passes a requirement written to match its own demonstrated power, so the requirement no longer tests anything. + - `no_self_rescue` (`gates.yaml:565-568`) literally covers only committed candidate verdicts, so it is not breached. + - The proposal's own rule is breached: "Any later change to a rule is recorded… no cell may be redefined on account of its own bridge" (§10). So is the purpose the forks ledger exists for. +- **The first verdict is largely predictable.** §10 discloses that candidate 11's log autocorrelation is above the PSID at 2 and 4 years. Both r6 bridges are negative: EPUF persists more than the PSID (`B = -0.043` for men, `-0.032` for women). The interval stretches from the PSID's position to `t = 0.079` past EPUF, which is about 0.12 above the PSID. A candidate that persists more than the PSID therefore moves toward EPUF and lands inside. Choosing to lock now, with the bridge signs known, picks a gate the registered candidate very likely passes. +- **House precedent for a pause is a candidate-blind redesign, not a relaxed requirement.** gate_m6 v1 hit its OC pause. It went through a pinned-ladder redesign that used only truth-side arithmetic, adjudicated publicly before v2 (`gates.yaml:5858-5866`). +- **(b) cannot be done blind here.** Every redesign the proposal names is informed by the bridges: pooled-sex r6 has a bridge roughly equal to the mean of the two known ones. The proposal concedes this in §7.5. +- **Required fix:** + - Adopt (c). Publish the per-cell table with its model/source decomposition on every gate-1 run, and set the draft block's status to report-only. + - Record the pause and this ruling in the forks ledger. + - Any future gate needs a new registration id, rules fixed before any recomputation, and a gate-1-orthogonal bite (see finding 4). + +### 2. SERIOUS: The bite requirement could not be met by design, so the pause was foreseeable + +- **The arithmetic.** For roughly normal `e`, the formula gives `mean|e| + 4 sd|e| ≈ (0.798 + 4×0.603)σ = 3.21σ`. + - With `σ = 0.0246`, `t = 0.079`. Artifact check for r6.men: 0.01982 + 4×0.01469 = 0.0786. + - Giving 10% of persons a donor's early years (bd1) cuts r6 by about 0.1 × 0.668 ≈ 0.067. That is less than `t`. + - Reaching a 90% fail rate would need about `t + 1.28σ_bite ≤ 0.067`, which means `σ ≲ 0.016`. The PSID cannot deliver that. +- **The bite and eligibility rules disagree.** Eligibility promises 80% power at a shortfall of about 0.10 from the PSID (`t + 0.84σ`). The bite demanded 90% power at 0.067. The drafting session had seen EPUF subsampled to PSID scale (§10), which gives σ, so this was knowable before the build. +- **Required fix:** In the forks ledger and §7.4, describe the pause as an internal inconsistency in the registration, not a data surprise. Any future registration must check that the bite dose sits above the cell's own 90% detection point before the floor build. + +### 3. SERIOUS: The bite fail shares do not measure the gate's power against a broken generator + +- **No shared noise.** `bite_demonstrations` (`scripts/build_epuf_gate_floors.py:755-822`) perturbs the realised PSID support and scores it on the 20 fixed gate holdouts. The term the floor says dominates (78% of variance for men, 73% for women) is therefore absent from the bites. +- **Anchored to where the 20 holdouts happen to sit.** The real-holdout estimate for women is −0.0448 against `B = −0.0323`, a gap of −0.0125. For men it is −0.0438 against −0.0428. This is why women fail 0.30 against men's 0.16 even though women get the smaller dose (0.064 against 0.067). + - For a generator, those holdout realisations do not carry over: its window values are generated. +- **The shifts are not stored.** The artifact keeps only fail counts, not the per-bite shifts. +- **Required fix:** + - Store per-seed bite estimates and each bite's mean shift `δ̂`. + - Report the power under the gate's own noise model, `Φ((δ̂ − (distance to edge))/σ)`. For bd1 on men that is about `Φ((0.067 − 0.079)/0.0246) ≈ 0.31`. + - Express any bite requirement in those terms. + +### 4. SERIOUS: What the gated surface adds beyond gate 1 is not demonstrated + +- **Gate 1 already polices persistence.** It sets tolerances of 0.05, 0.06 and 0.07 on log-earnings autocorrelation at lags of 2, 4 and 10 years (`gates.yaml:372-374`). The two gated cells are sex-level 6-year rank correlations whose lower edge is 0.079 below the PSID. +- **The by-sex split adds no catch.** bd2 and bd2c fail at 0.00 (artifact lines 6636-6651). Yet §3 sells the by-sex cells as "where this gate tests something gate 1 does not". +- **The bd2 design limits that conclusion.** Donors are matched on pooled-sex 2004 deciles, which preserves most of the rank correlation by construction. It tests pooling of a decile-conditional law, nothing finer. +- **No bite is scored on gate 1.** So no evidence shows a generator that passes gate 1 and fails `gate_epuf`. +- **Required fix:** Before any future lock, show a perturbation that passes gate 1's battery but fails `gate_epuf`. Otherwise `covers` must say the gated cells add no demonstrated bite beyond gate 1. + +### 5. SERIOUS (record honesty): The draft block names the wrong rules-first commit + +- **The error.** `docs/design/gate_epuf_block_draft.yaml:189-190` says "rules committed before the floor build (commit 970a9db721bf)". + - The renderer fills this from `revision_pins.head_sha` (`scripts/render_gate_epuf_block_draft.py:227-229`). + - 970a9db7 is the AIME fix made *after* the first floor build. The rules-first commit is `eec910d6` (proposal §10). +- **Required fix:** Have the renderer cite the rules commit and the build commit separately. Bind both in `tests/test_gate_epuf_block_draft.py`. + +### 6. SERIOUS: The blindness chronology cannot be audited from the PR + +- **The first build is not in the repository.** The proposal points to `epuf-20261001/first-floor-build/` and gives only a truncated hash (`369bf5ec…7e378`). Nothing in the repository references either. +- **No build time.** The artifact records no build timestamp, only `elapsed_seconds`. +- **The key claim is unverifiable.** "Window cells, floors, partition and bites identical" across the two builds cannot be checked. +- **Required fix:** + - Commit the first build as frozen lineage (as gate_m6 kept v1 and v2), with its full SHA-256. + - Add a test that its window-cell, partition and bite blocks equal v1's. + - Add a UTC build timestamp to future artifacts. + +### 7. SERIOUS (ceremony): The scoring path is not pinned + +- **The gap.** `DERIVATION_CORE` (`scripts/build_epuf_gate_floors.py:109-115`) and the pin test (`tests/test_gate_epuf_block_draft.py:78-89`) cover five files. Neither covers `harness/epuf_run.py`, which the draft block names as the scoring path (`scoring: populace_dynamics.harness.epuf_run.score_candidate`), nor the renderer. The scoring code could drift after lock without tripping a test. +- **Required fix:** Pin `epuf_run.py`'s SHA-256 in the draft block and add a binding test. The artifact is exclusive-create, so a separate pin is cleaner than a rebuild. + +### 8. MINOR: The floor bounds the shared noise rather than pricing it for this generator + +- **Calibrated to an oracle.** The half-split term is the right size for a generator that draws from the true law (Var = σ²/N). The simulation (`tests/harness/test_epuf_gate.py:294-340`) uses such an oracle, and it conditions on one of the two scored variables. +- **Likely conservative for candidate 11.** That generator copies donor ranks from training data drawn from 80% of the same sample (`run_gate1_candidate10.py:495-562`), so it partly tracks the realised sample. The shared residual is then smaller. + - Result: the OC is conservative, which is safe, but power is lost, and that feeds the pause. +- **The other term roughly offsets.** The averaging term's `m(H) − m(T)` has variance 6.25σ²/N per split. A candidate's holdout deviation is 4σ²/N plus its own draw noise. +- **The artifact matches the variance accounting.** Predicted shared share = 1/(1 + 6.25/20) = 0.76; observed 0.73-0.78. +- **Required fix:** Change "prices" to "bounds (exact for an oracle law)" in §4 and §11.5. + +### 9. MINOR: k = 4 is called "the house formula", but house precedent picks k by OC + +- **Precedent.** gate_m4 chooses k against the OC (`gates.yaml:3248-3266`); gate_m6 uses k = 3. +- **Over-conservative for one decision.** For a single 20-seed decision, k = 4 gives a per-cell false-fail rate of about 7e-4, far stricter than the 0.90 OC floor. This is the lever that made the bite unreachable. +- **Required fix:** Correct the wording. Changing k now would be a fork; any future registration should declare an OC rule for k before the floor build. + +### 10. MINOR: The reproduction clause is weak for seeds 5-19 + +- **The gap.** `gate1_rank_knn_v5.json` stores only pairs C2ST for seeds 5-19 (`scripts/run_gate1_candidate11.py:61-62`). "Reproduces exactly" therefore checks one scalar per seed. +- **Required fix:** Commit SHA-256 digests of the generated panels at registration and compare them. + +### 11. MINOR: The birth-year rule shifts cohort bands + +- **The bias.** `period = wave − 1` while age is measured at the wave (`data/family.py:796-800, 843`). So `period − age` gives b−1 or b, about half a year below EPUF's YOB. +- **House precedence is not followed.** The repository uses the marriage-history birth year first (`estimates/career.py:650-656`). +- **Within-band age mix differs.** The age-59 ceiling combined with the anchor ≥ 2006 rule thins the oldest c0 years. +- **Effect.** Both end up in the bridge, which is legitimate, but the bands are systematically shifted. +- **Required fix:** Adopt the house precedence or document the gap. Report the support's within-band birth-year distribution beside EPUF's. + +### 12. MINOR: The minimum-events rule for sex-level cells sums band events + +- **The issue.** `epuf_cells.py:330-334` sums events across bands. A band mean is only as precise as its weakest band. +- **House rule.** It is per cell, on the weaker half of the worst seed (`gates.yaml:3232-3234`). +- **Effect.** Moot for r6 (hundreds of pairs). It could admit sparse share cells. +- **Required fix:** Use the minimum over bands. + +### 13. MINOR: Bite doses are mislabelled + +- **bd3 moves more than labelled.** It ranks with `searchsorted(side="right")` (`build_epuf_gate_floors.py:720-723`), so every at-cap value gets rank 1.0. + - Men's at-cap share is 17.8%, so "top 8%" becomes "all at-cap values plus anything above 0.92". + - It is also pooled across sex and band. +- **bd1 is slightly under-dosed.** Donors are drawn with replacement and can include the person themselves (`rng.choice(index)`, line 671). +- **Required fix:** Correct the labels, or rank ties at their lower midrank. + +### 14. MINOR: Some §7 claims are not in the artifact or state a mechanism without evidence + +- **"Roughly 0.07" is not stored.** The shift is consistent with theory (0.1 × 0.668), but §7 says all its numbers come from the artifact. +- **Mechanisms stated as explanations:** + - "a more attached group" for the q_atmax bridge; + - "EPUF counts noncovered spells and years before arrival as zeros" for the zero-years bridge. +- **Mismatched comparison.** "Comparable to gate 1's 0.06-0.07" compares an 80% power point (0.10) with tolerances, on a different statistic, under a per-seed 4-of-5 rule. The like-for-like figure is `t = 0.079`. +- **Overstated certification.** "A pass certifies a distance below the cap" is too strong: a candidate at the cap still passes 20% of the time. +- **Required fix:** Hedge these statements and store the bite shifts. + +### 15. MINOR: The scope of "nothing generates a career" is overstated + +- **The issue.** The forward earnings law generates earnings for 2015 onward (`engine/forward_earnings.py:1-7`). `build_career` appends them as PROJECTED (`estimates/career.py:1032-1047`). +- **Required fix:** Say "nothing generates earnings for years before 1998 / a historical career". + +### 16. MINOR: The tranche R mask applies two of the assembler's rules, not all of them + +- **Not emulated:** + - the coverage ≥ 0.80 exclusion and the domain exclusions (`career.py:1580-1598`); + - the one-neighbour fallback (`career.py:972-975`), which is moot on EPUF. +- **Within the cohorts used, the 1968 start is right:** `max(1968, birth year + 22)` equals 1968 for everyone born 1930-1944. +- **Required fix:** Call it "two of the assembler's rules" and name the exclusions it does not apply. + +### 17. MINOR: Housekeeping + +- **Seed reuse contradicts the docstring.** `half_split_seed(b) = b` reuses gate seeds 0-19 (`epuf_gate.py:121-131`). On the same RNG stream, half A contains gate seed b's holdout. This is harmless, but it contradicts the "never reuses a gate seed" rationale. +- **Non-finite values are not stripped everywhere.** `_finite` wraps only the floor and bite blocks. `json.dumps` allows NaN by default (`artifacts.py:23`), so a NaN in tranche R would write invalid JSON. The current artifact has no NaN or Infinity. + +--- + +## Checked and found sound + +- **Split function.** `holdout_mask` matches `split_panel_by_person` (`harness/panel.py:207-209`). The builder asserts it on seeds 0-19, and the block test checks holdout sizes. +- **Calendar years.** Period is the income year, so capping at the year's wage base by period is correct. +- **Support and conditioning.** + - The anchor is the last in-filter period (`run_gate1_candidate2.py:276-285`). + - The chain keeps only that anchor at its real value (`run_gate1_candidate10.py:277-279, 384-569`). With anchor ≥ 2006, every scored window value is generated. + - The support comes from the real panel only (`epuf_run.py:56`). +- **Measurement.** + - The operator preserves whether a value is positive and whether it is at the cap. + - Wage bases for 1998-2004 are not multiples of $1,000, so rounding cannot land on the cap. + - EPUF tops out exactly at the wage base (`tests/data/test_epuf.py:157`). + - Weighted midranks are correct (a constant offset is irrelevant), and the unit-weight case is tested against scipy. +- **Gate algebra.** + - `[m(A) − m(B)]/2` has the variance of the full-sample estimate. + - The interval, eligibility rule, faithful OC and partition are recomputed by the binding test. + - My hand checks of r6.men and r6.women agree with the artifact: tolerances 0.079 and 0.078, OCs 0.99935 and 0.99925, minimum detectable gap 0.1425 for men. + - The bridge cannot widen acceptance beyond the cap, so the gate cannot become vacuous. + - The ladder is mechanical and was fixed before the build. +- **Tranche R AIME.** It uses 35 years, indexes to age 60, and ranks every year after 1950 through age 61. This is consistent with `ss.statutory_aime` for the 1930-1944 cohorts. +- **§7 counts match the artifact.** Support counts (22,300 → 5,769), the bite fail shares and the training-copy estimates (−0.044 for men, −0.045 for women) all agree. \ No newline at end of file diff --git a/runs/epuf_gate_floors_v1_first_build.json b/runs/epuf_gate_floors_v1_first_build.json new file mode 100644 index 00000000..d020dba6 --- /dev/null +++ b/runs/epuf_gate_floors_v1_first_build.json @@ -0,0 +1,7325 @@ +{ + "schema_version": "epuf_gate_floors.v1", + "run": "epuf_gate_floors_v1", + "status": "DRAFT_NOT_OPERATIVE", + "purpose": "Pre-lock floors, bridges, partition and operating characteristic of the proposed EPUF covered-earnings gate (docs/amendments/gate_epuf_registration_proposal.md). No candidate was generated or scored to build it.", + "ceremony": { + "step": "pre-lock floor", + "draft_block": "docs/design/gate_epuf_block_draft.yaml", + "gates_yaml_untouched": true + }, + "candidate_blind": { + "generated_candidates": 0, + "psid_read_through": [ + "populace_dynamics.data.family.family_earnings_panel", + "populace_dynamics.data.deaths.read_death_records" + ] + }, + "design": { + "window_years": [ + 1998, + 2000, + 2002, + 2004 + ], + "cohort_bands": { + "c0": [ + 1947, + 1955 + ], + "c1": [ + 1956, + 1964 + ], + "c2": [ + 1965, + 1973 + ] + }, + "gate_seeds": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "holdout_fraction": 0.2, + "floor": { + "n_replicates": 100, + "half_split_seed": "b", + "holdout_split_seed": "1000 + 20 * b + j", + "replicate": "e_b = [m(A_b) - m(B_b)] / 2 + pooled(m(H_bj)) - pooled(m(T_bj)), j = 0..19" + }, + "k": 4.0, + "tolerance": "round(mean|e_b| + k * sd|e_b| (ddof=1), 3)", + "interval": "[min(0, bridge) - t, max(0, bridge) + t]", + "eligibility": "abs(bridge) + t + 0.8416 * sigma <= cap", + "caps": { + "log_ratio": 0.4054651081081644, + "abs_gap": 0.15 + }, + "min_events": 20, + "epuf_noise_share_max": 0.1, + "oc_pause_below": 0.9, + "support": { + "universe": "gate 1's filtered PSID family panel: age 25-59, reference years 1998-2022, positive weight", + "rules": [ + "a row at each of 1998, 2000, 2002 and 2004", + "last in-filter period 2006 or later", + "sex coded male or female (ER32000)", + "birth year floor(median(period - age) + 0.5) in 1947-1973" + ], + "weight": "the person's 2004-row weight", + "epuf": "every EPUF person with sex 1 or 2 born 1947-1973, weight 1" + } + }, + "inputs": { + "epuf_sha256": { + "EPUF2006_DEMOGRAPHIC.csv": "195db459ca7b7c810162cb6e432371e8787eba8331787d2ba1eace1a0da2ccb0", + "EPUF2006_ANNUAL.csv": "a47315b56214df66fb9f9abcb2caa60779c8b3d091ded199323672c27e3ea105" + }, + "disclosure_constants_sha256": "ba1f39f238278243de19b8a9d194abedffeabd855f5b97779b685d852f62a881", + "psid_panel": { + "n_universe_persons": 22300, + "n_present_all_four_years": 6323, + "n_and_anchor_2006_or_later": 5775, + "n_and_sex_coded": 5775, + "n_support_persons": 5769, + "by_sex_and_band": { + "men.c0": 898, + "men.c1": 926, + "men.c2": 679, + "women.c0": 1059, + "women.c1": 1269, + "women.c2": 938 + }, + "reference": "runs/noise_floor_psid_family_9822.json" + }, + "gate1_run": "runs/gate1_rank_knn_v5.json" + }, + "epuf_support": { + "n_persons": 1311282, + "n_sex_unspecified_dropped": 3054, + "by_sex_and_band": { + "men.c0": 217559, + "men.c1": 244637, + "men.c2": 214306, + "women.c0": 204942, + "women.c1": 228276, + "women.c2": 201562 + } + }, + "holdout_ids": { + "0": { + "n_persons": 4427, + "n_support_persons": 1122, + "sha256_sorted_person_ids": "4cb1de0fb3e0ac3fce77701d869d6ae4fa9021b0166ca9b131315f3ad3357374" + }, + "1": { + "n_persons": 4495, + "n_support_persons": 1123, + "sha256_sorted_person_ids": "03010683999147a0aaeea472616e199599110605f90835ec892582f65bee9834" + }, + "2": { + "n_persons": 4477, + "n_support_persons": 1156, + "sha256_sorted_person_ids": "b3991d08922cf61bd14cb6ad1338c5f466bbb9f982a2485d080614f3fb52d3bb" + }, + "3": { + "n_persons": 4464, + "n_support_persons": 1145, + "sha256_sorted_person_ids": "a6354930f9c93095b22a67240aca70f5cd178debde11c9901710919954605f01" + }, + "4": { + "n_persons": 4530, + "n_support_persons": 1216, + "sha256_sorted_person_ids": "ba890a7017580d411bdbf320ee8cfc7faa5c1b261ffa99718aef63685f0bafe0" + }, + "5": { + "n_persons": 4514, + "n_support_persons": 1199, + "sha256_sorted_person_ids": "ea7c6074fff5592249c44000982c4c348d192263a316f676d47331500ed4c5f1" + }, + "6": { + "n_persons": 4476, + "n_support_persons": 1185, + "sha256_sorted_person_ids": "0a419703d9d010a1fab433122940f99b14df9068b816f16fe7c79659b3073895" + }, + "7": { + "n_persons": 4415, + "n_support_persons": 1135, + "sha256_sorted_person_ids": "819edeab9b1bd0ef0e1ee61264fc078792b106a59850f544a7c23f909d01886d" + }, + "8": { + "n_persons": 4336, + "n_support_persons": 1135, + "sha256_sorted_person_ids": "6f5a5df17b9a2d5f6dd29ee7eb3b9ce9a268e781cc63748ab1da54a7870736c9" + }, + "9": { + "n_persons": 4570, + "n_support_persons": 1150, + "sha256_sorted_person_ids": "5c50d7ff89ba8e4dd62f07a26c0545504d2a735038f5c1402183fa9e2496eeaf" + }, + "10": { + "n_persons": 4472, + "n_support_persons": 1168, + "sha256_sorted_person_ids": "9802ae0db85b3f4b65a424142e1835a572c63b7c051b2bf696a140602aee60fa" + }, + "11": { + "n_persons": 4517, + "n_support_persons": 1172, + "sha256_sorted_person_ids": "8c0fb2d1be76e8b061065b56541a6480b29a3c4f6a973caaa59b3c5d409f6863" + }, + "12": { + "n_persons": 4371, + "n_support_persons": 1074, + "sha256_sorted_person_ids": "ecde12f32dcc3396d5dc06c892f7780923689b5497ee5f76409795798355fd9b" + }, + "13": { + "n_persons": 4500, + "n_support_persons": 1176, + "sha256_sorted_person_ids": "3e5cf7ea85e667d2d3fbc2db59644fe3dc0bde40f724465c4773ebbb5d49e7dc" + }, + "14": { + "n_persons": 4522, + "n_support_persons": 1203, + "sha256_sorted_person_ids": "ac1c6fe33ba8589207fa97dec38a7aef0619f02526cdcab6d6f27bfb6fec21aa" + }, + "15": { + "n_persons": 4431, + "n_support_persons": 1197, + "sha256_sorted_person_ids": "e1ee767d29f165d31bf311573d74e383682fd74673fafbe30af94386d7310dc0" + }, + "16": { + "n_persons": 4449, + "n_support_persons": 1091, + "sha256_sorted_person_ids": "a03afcf9dbcdfacdc904700ca6a4af87662a367b8be1e3d517615ba93b7bc108" + }, + "17": { + "n_persons": 4500, + "n_support_persons": 1219, + "sha256_sorted_person_ids": "952dca2e5073733757a5b4e221165e0ef653829a1aab446b431e023abe338425" + }, + "18": { + "n_persons": 4484, + "n_support_persons": 1161, + "sha256_sorted_person_ids": "0b916d24ac009af2f7627d9c17a090356b4be32534aedb62495474a52407d0df" + }, + "19": { + "n_persons": 4442, + "n_support_persons": 1114, + "sha256_sorted_person_ids": "b523492d09cc174b732365471e5d7f43898666c45e70bb362f4f0a257f6ac7f5" + } + }, + "cells": { + "r6.men.c0": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7370421835844408, + "epuf_sampling_sd": 0.0018305516902764774, + "psid_value": 0.6672906355952744, + "psid_n": 761, + "bridge_psid_minus_epuf": -0.0697515479891665, + "min_events": 117, + "floor": { + "replicates": [ + -0.021057863545390687, + 0.005396951744537859, + -0.022140410128426824, + 0.025021545388600075, + 0.08090669852605714, + 0.05185027865511649, + 0.016794308434623928, + -0.10011827388689826, + -0.024237969517333424, + -0.013245233208305951, + -0.04216234141941877, + 0.010716703700710761, + 0.0006821034331753739, + -0.0008204335464723211, + 0.011027202618145215, + 0.0053241259492661785, + -0.019671686265050614, + -0.019331781853036745, + -0.04742270569341556, + 0.03397612606842643, + -0.011605842253357979, + -0.04885139883534573, + -0.04916743681449015, + -0.013474994749749392, + 0.040763563650294654, + 0.03567329519440554, + -0.03316450288499512, + -0.07985433330656666, + 0.0006265838940183177, + -0.003987738693373211, + 0.05290865061354899, + -0.004554467118761507, + 0.018015630812510064, + -0.021894293171350276, + 0.011863273084325832, + 0.01740196798047622, + 0.029875797972318374, + -0.01951656760773801, + -0.005593398659512583, + -0.014945415799800188, + 0.03927087480527963, + -0.03142262465626888, + 0.07861098001423272, + -0.12246342620200945, + -0.087649243277725, + -0.040477640372615864, + 0.06769334395409582, + 0.10905652523773424, + -0.0745428129563484, + -0.014444356631236221, + 0.001428319951245427, + 0.04077191644635836, + 0.03126801311893557, + -0.00582044137729959, + -0.04444123730715843, + -0.016177171436451143, + 0.00018819190183044787, + 0.02721703000343173, + -0.04368975633898614, + 0.004681596715681913, + -0.006304469830752668, + -0.0405106857812782, + 0.008806625317474281, + -0.06309129364433164, + -0.10621244899640575, + -0.04551930831053469, + 0.0645692946861004, + 0.009522525304856755, + -0.058785493066160766, + -0.0061032307925567575, + 0.05892139382187411, + -0.029212646938726994, + -0.05367027567368576, + -0.026882717053679672, + -0.0006696469747782263, + 0.07605402317137755, + 0.004180502089620841, + -0.08641595573349009, + -0.04166965308123255, + -0.011463380582869276, + -0.0770682986643067, + 0.0006048175205705109, + 0.04427714704983621, + 0.007990478634442633, + -0.015854755774779294, + -0.035144739897731925, + 0.01474565439819836, + 0.03937408778116824, + -0.04431453238230115, + 0.06143695254986736, + -0.0013879727248156115, + 0.00540336989636786, + -0.017501200590685828, + -0.009153705439037929, + -0.004518229782560945, + -0.07530319514502642, + 0.05915339320332369, + 0.05671152801268187, + -0.07748287213549782, + -0.0159521519989152 + ], + "mean_abs": 0.03408904053818175, + "sd_abs": 0.02875212805809537, + "realized_sigma": 0.04450259210432828, + "shared_noise_variance_share": 0.7182212591062277, + "tolerance": 0.149 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.219, + "upper": 0.149, + "minimum_detectable_gap_80": 0.2562058744532035, + "faithful_pass_probability": 0.9996008668738419, + "real_gate_holdouts": { + "estimate": 0.6743897728658892, + "gap_from_epuf": -0.06265241071855165, + "lower": -0.219, + "upper": 0.149, + "pass": true + } + }, + "r6.men.c1": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7517419621933827, + "epuf_sampling_sd": 0.0016814240619831553, + "psid_value": 0.7364055754959135, + "psid_n": 800, + "bridge_psid_minus_epuf": -0.015336386697469284, + "min_events": 120, + "floor": { + "replicates": [ + 0.01195576149536709, + -0.011219621670494784, + 0.013234877643894472, + -0.027217841496278983, + -0.003270938433287851, + -0.025532376989664318, + -0.021209633500452685, + 4.866123392899269e-06, + -0.06641866832389959, + 0.046116105545360886, + -0.0579049771738554, + -0.02487693371448424, + 0.04017544128320011, + 0.0007210050851538252, + -0.019895475130828455, + -0.04944754580043331, + -0.025344122978150696, + 0.004528678415250342, + 0.038497607130094924, + 0.012431885808830756, + 0.008602925993228927, + -0.03365723315457164, + 0.017149924312509057, + -0.002539862527080994, + 0.028305713310952885, + 0.08355329648234372, + -0.008868715681024097, + 0.027506876417028925, + 0.026171000423383106, + 0.08892044677715683, + -0.03778826771514182, + -0.0192152366799197, + -0.03423153659661682, + 0.0015768350387953545, + 0.03170184284576949, + -0.012485798989317232, + 0.007977856688259288, + 0.00887184107297917, + -0.013010500724199625, + -0.012568059579313506, + 0.003067329251639439, + 0.02437243533903255, + -0.054139043749243776, + -0.021362647557728542, + -0.031546458863387916, + -0.000572605775903845, + -0.006015345846570153, + -0.04674480399546532, + -0.007234298370190573, + -0.029806262446545106, + -0.028733019802124338, + -0.057941806353586756, + -0.03753264844793469, + -0.02693768054803275, + 0.03223527774839707, + 0.02137571785987763, + -0.05595723930827712, + 0.010734066350931493, + 0.008314704662883254, + 0.013260694685304164, + -0.006212162467210791, + 0.012944519198155147, + 0.010228999360785196, + -0.0414946055712182, + -0.0029705689817093317, + 0.04935760839837444, + 0.0011230328622329755, + 0.013105726364229353, + -0.06180819739705529, + -0.054209626673627664, + -0.015736164361947358, + -0.027062052547180415, + 0.01862721346634394, + 0.04097384531849618, + -0.001515614908966234, + -0.003800415764501297, + -0.022586709984411257, + -0.05532237365879483, + 0.027229610357893064, + -0.03204242165865284, + -0.013733170228488134, + -0.0012810727862572202, + -0.005637151434103815, + 0.02462089300216458, + 0.03054194604687238, + -0.04198390653207967, + 0.0012113801113280975, + -0.12193822326899306, + 0.03003353407680076, + -0.002641623797151882, + -0.021776385662239217, + -0.041076389479891395, + -0.0037397504996202757, + -0.03190534867499417, + -0.015554643086684417, + -0.017996525269547592, + 0.04768481575268052, + 0.007315752432949851, + 0.0629534774511597, + 0.018138169032649698 + ], + "mean_abs": 0.025627078496434662, + "sd_abs": 0.02158187008847976, + "realized_sigma": 0.03343451057834227, + "shared_noise_variance_share": 0.7892871921677226, + "tolerance": 0.112 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.128, + "upper": 0.112, + "minimum_detectable_gap_80": 0.15547558073432036, + "faithful_pass_probability": 0.9995538255975308, + "real_gate_holdouts": { + "estimate": 0.744942897785964, + "gap_from_epuf": -0.006799064407418731, + "lower": -0.128, + "upper": 0.112, + "pass": true + } + }, + "r6.men.c2": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.6438111652856673, + "epuf_sampling_sd": 0.001932701247990694, + "psid_value": 0.6004466040215929, + "psid_n": 621, + "bridge_psid_minus_epuf": -0.0433645612640744, + "min_events": 89, + "floor": { + "replicates": [ + 0.036239059227876735, + 0.034111370819834785, + -0.08977016650873579, + -0.008259532803103764, + -0.00466836934238779, + -0.025146463006230968, + 0.05499408162714925, + 0.06048267995408246, + -0.014208796631361376, + 0.01276510979394746, + 0.015068547796980747, + 0.095570841731905, + -0.056598926991726695, + 0.002837093143295555, + 0.013255518924018606, + -0.02233066193331562, + -0.03320428541939008, + 0.037669039173345464, + 0.020774095214502186, + -0.03246495895229701, + 0.04532059808539535, + -0.0035119836008826733, + -0.021597915964290726, + -0.06625979760158307, + 0.02422827275550332, + 0.05465560760929555, + 0.00890568498152755, + -0.0562207037577927, + -0.05664518567861154, + -0.0392369457254097, + -0.019066768905181997, + 0.007990876515124645, + 0.05089061325906452, + 0.04764605740031935, + 0.018470320023949105, + 0.051886962805775705, + 0.030091708941708872, + -0.04768938247107951, + 0.07673530525687727, + 0.05035123291656046, + -0.05978428136630454, + 0.014326140198183401, + -0.023756513538007562, + 0.04285909485313305, + -0.02392159887062112, + 0.08087933645467305, + 0.02803009304482501, + -0.0682510465936193, + -0.06020646929398149, + 0.004650137811546162, + 0.0713863070470594, + 0.08333227547169286, + 0.04172475028681577, + -0.07332963876011006, + 0.05181307342737085, + 0.020857373381929167, + 0.047476597837703804, + -0.017097969043722128, + -0.02284468436086534, + 0.04785735353991061, + 0.005222992433157492, + 0.0076408461420038876, + 0.018336288248974708, + -0.07086864288317096, + -0.07927866147554496, + -0.008383593022862235, + 0.015125390931530425, + -0.040071161516133325, + 0.05530196920616459, + -0.06073984434006224, + 0.03742459374201501, + 0.03715604166316866, + -0.05821394700748683, + -0.08218718837945233, + 0.06621899064745462, + 0.01770837560018751, + 0.03764790047638211, + -0.0035120723224087436, + -0.0546703685729214, + -0.04570613192480588, + 0.00871183781807, + -0.07346189804618686, + -0.013004575269209118, + -0.0280514297315827, + -0.12489948891489511, + 0.03349757398347969, + 0.09844685435869516, + -0.07479178668749353, + -0.044726412759420076, + -0.024811457798850578, + -0.014873680613234186, + -0.024482919871826936, + -0.015532411330050566, + 0.10747568845382549, + -0.04824694939455232, + -0.06002314869398678, + 0.0003721070815784766, + 0.06998653666592325, + 0.006544858189350411, + 0.03475565693887267 + ], + "mean_abs": 0.040403185315704665, + "sd_abs": 0.026781145783177748, + "realized_sigma": 0.04839912039924274, + "shared_noise_variance_share": 0.8781733988756965, + "tolerance": 0.148 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.192, + "upper": 0.148, + "minimum_detectable_gap_80": 0.23209828867832907, + "faithful_pass_probability": 0.9988949665049346, + "real_gate_holdouts": { + "estimate": 0.5818069602089632, + "gap_from_epuf": -0.06200420507670412, + "lower": -0.192, + "upper": 0.148, + "pass": true + } + }, + "r6.women.c0": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7177630429235712, + "epuf_sampling_sd": 0.0022793864174730115, + "psid_value": 0.6688335948077175, + "psid_n": 776, + "bridge_psid_minus_epuf": -0.048929448115853647, + "min_events": 121, + "floor": { + "replicates": [ + -0.025598767704403558, + 0.004324162885140037, + 0.015930166333267437, + -0.04689155487268737, + 0.016349694572241225, + 0.013566054117711224, + 0.013916401849683846, + -0.03050062593762276, + 0.00035086260248595735, + -0.03294753373468634, + -0.024423132963451055, + 0.05651446786833941, + -0.03796257194534797, + 0.036952136458281826, + -0.0822593653945386, + 0.005380637163796442, + 0.027039772218785507, + 0.04455534614791207, + -0.04955407808154705, + -0.001985010121798192, + -0.02821880407030114, + -0.0534250673524036, + 0.09632953643255576, + -0.050481519189487845, + 0.05435559156263153, + -0.004505804039738659, + -0.09388807084999717, + -0.040218172424239695, + 0.021610981967773557, + -0.0098136120107859, + -0.04628450754022406, + 0.0790928504638162, + -0.012333765099855398, + -0.028131000224770997, + 0.027525917603127503, + 0.022308237305243284, + -0.008727912204573529, + 0.016000440762479806, + -0.011290276939371291, + 0.03238917036683148, + -0.011464843410475933, + 0.07007307784834221, + 0.015445562328478268, + 0.02248302681565334, + -0.02630872373327131, + -0.05726664856778213, + -0.03039581892244586, + -0.010191692451961276, + 0.01345092789121316, + -0.005162743564838257, + -0.04432682917886277, + -0.0075007888279635115, + 0.11667661513072419, + -0.018601848146532374, + -0.058256204692082314, + 0.06877016972193134, + 0.0055004948239142926, + -0.006817002759317792, + -0.0163545480764844, + -0.03000091176470021, + -0.005563171906729614, + -0.08655215469157668, + 0.0402478690379684, + -0.00799682310190758, + 0.01956056653480065, + 0.024879672972170863, + -0.04231567748016968, + -0.07650372502440894, + -0.10009040866763597, + 0.06894130394636722, + -0.013055758457699573, + 0.03355833201159403, + 0.0704209405588247, + 0.0348435581144092, + 0.00869282324536541, + 0.04233360542821557, + -0.010119631620083336, + 0.06251601763203357, + -0.02300352466210115, + 0.06250296747944567, + -0.0674714146862056, + -0.04565143371726238, + -0.07946352756665304, + -0.029073202533154263, + 0.06978103146319636, + 0.07745803691123998, + -0.05758915225402983, + 0.00022739060758714125, + 0.006276030704074231, + -0.011122810089990165, + 0.018738982718483344, + -0.03480815367153306, + -0.02507582416385562, + -0.0038431344632028352, + -0.014980156004955336, + -0.07475173659921247, + 0.05283933654107281, + -0.049099382021192184, + -0.07227347790148447, + 0.07343063591402094 + ], + "mean_abs": 0.036366354431468254, + "sd_abs": 0.027040503363193486, + "realized_sigma": 0.045237027627251326, + "shared_noise_variance_share": 0.7252454351731714, + "tolerance": 0.145 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.194, + "upper": 0.145, + "minimum_detectable_gap_80": 0.2320018911106729, + "faithful_pass_probability": 0.9993200715125318, + "real_gate_holdouts": { + "estimate": 0.6318574755692126, + "gap_from_epuf": -0.08590556735435861, + "lower": -0.194, + "upper": 0.145, + "pass": true + } + }, + "r6.women.c1": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7026652344743403, + "epuf_sampling_sd": 0.0018466001551114115, + "psid_value": 0.7199216271832825, + "psid_n": 930, + "bridge_psid_minus_epuf": 0.017256392708942192, + "min_events": 148, + "floor": { + "replicates": [ + -0.012495614463988947, + -0.013268068329840732, + -0.021808945134435043, + 0.003459282966340682, + 0.006409564365645548, + -0.07298552329704089, + 0.02417423466997215, + -0.01889284423278048, + 0.027533196177212893, + -0.0034336834239842573, + -0.027157623948940834, + -0.015756779219479933, + -0.027465064136925788, + 0.006907323852385905, + 0.02199339232517039, + 0.044070360203807946, + 0.02193625900074303, + -0.021578968036096324, + -0.05485911329726334, + 0.0011586796476533712, + 0.014758310060015822, + -0.010831620390670205, + 0.05166698764171962, + 0.030670015409929474, + -0.053617830001822964, + -0.01116246693614853, + 0.015472616587935806, + -0.003267730635749533, + -0.006346332961541856, + 0.06186761450810885, + -0.001056615592264054, + 0.02906942845932281, + -0.010882821746472038, + 0.011274874901586629, + 0.012411046767446643, + -0.030098203828534342, + 0.051457037206824985, + -0.04832158311192475, + -0.0157439220395173, + 0.027597391691839335, + -0.0034325318070640987, + -0.011774914645492685, + 0.04260751540184449, + -0.0170598065994369, + 0.013404062752792545, + 0.037928515683807784, + 0.005659796262513228, + -0.06803342671320767, + 0.025543993780553997, + -0.0399563960143538, + 0.041448555382403496, + -0.0026376792297608254, + -0.04158609763361154, + -0.018777351867392156, + -0.02459364629036037, + 0.023641516602900203, + -0.021669129774723572, + -0.016262254655373454, + 0.010814826922454945, + -0.001003443103226087, + 0.000553583981614092, + -0.016374993750317923, + 0.007440738512325962, + 0.0031818058567170127, + -0.029631380625303405, + -0.028022676422357673, + -0.010484466189926822, + 0.029059541326916183, + -0.023940203579545016, + 0.001651380058835139, + 0.0699112847385665, + 0.03924891878514536, + 0.027602377465709038, + 0.011794247271936176, + 0.01602259414920204, + 0.015324081214608765, + 0.01726883298032661, + 0.00504448225595211, + 0.006828705569294491, + 0.010615859748085876, + 0.006424998054513853, + -0.03820186271626452, + -0.011260340237157718, + -0.0018808850775204333, + 0.005554176884328466, + -0.0004051667131188541, + 0.036607465595282884, + 0.027634093849734087, + -0.01148993392384301, + 0.03895075016638072, + 0.023036857873763805, + -0.02019312016615349, + 0.025840412723840356, + -0.0437301078600999, + -0.0036572195507122984, + -0.028146452105467457, + -0.06094789705088938, + 0.018414661472333727, + 0.004231638376235858, + 0.0038229391219454234 + ], + "mean_abs": 0.021931875663346298, + "sd_abs": 0.01724455244480441, + "realized_sigma": 0.027846148984085314, + "shared_noise_variance_share": 0.8079859780730623, + "tolerance": 0.091 + }, + "eligibility": "eligible", + "gated": false, + "report_reason": "cohort_rung_not_adopted", + "lower": -0.091, + "upper": 0.109, + "minimum_detectable_gap_80": 0.13169230296718323, + "faithful_pass_probability": 0.999456689357935, + "real_gate_holdouts": { + "estimate": 0.7252632586986001, + "gap_from_epuf": 0.022598024224259827, + "lower": -0.091, + "upper": 0.109, + "pass": true + } + }, + "r6.women.c2": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.5958794147877823, + "epuf_sampling_sd": 0.002163351705962211, + "psid_value": 0.5305971313131903, + "psid_n": 670, + "bridge_psid_minus_epuf": -0.06528228347459197, + "min_events": 101, + "floor": { + "replicates": [ + 0.10490601974383912, + -0.049314288499141073, + 0.010352014054280378, + -0.02597200810672534, + 0.02535370431684794, + 0.0518698373173235, + -0.10891350465849209, + 0.02067772516017874, + 0.036937875571853435, + 0.012375571789912138, + -0.019213584150096497, + -0.03251905106552003, + -0.01643157039886306, + 0.045749892898595435, + -0.05584954987391616, + -0.010132174448693437, + -0.006662614236828179, + -0.07329157361277813, + 0.03005766464998985, + -0.0037253920687714825, + 0.005006982000467952, + -0.01441776025392244, + 0.06100494148868377, + 0.01754342970816647, + 0.03898963344399747, + 0.061674154511149715, + -0.03217681791249055, + 0.03726431677067138, + -0.045830284128855925, + -0.04642262704767397, + 0.06909903392705449, + 0.033972166318559954, + 0.023524363611518967, + 0.030653790703022182, + -0.021705593164337234, + -0.019307561897643044, + -0.011227202295264915, + 0.05522162257604907, + -0.060533357834957086, + 0.011373680276743653, + -0.06516009109286902, + 0.04105277224293569, + -0.10290286580759447, + -0.06912593657376015, + 0.06321067096874095, + -0.09064528247206052, + -0.01673805651358007, + -0.017219137846226668, + 0.10990674903634495, + -0.016121176431398043, + -0.06479457589433071, + 0.024037657823169856, + -0.04845097121496644, + -0.05519287514862481, + 0.040812534024120634, + -0.059754319013949564, + -0.121164462599408, + 0.0012978415220585848, + 0.00802563129991446, + -0.01922462762898164, + -0.05263406449646835, + -0.06251037557024633, + -0.07331340624286814, + 0.03794024039579397, + -0.11215742799143702, + -0.0067290957054826905, + 0.02740531725248463, + -0.00903057397278767, + 0.005245922803151282, + 0.019096821334580683, + 0.015744092971736734, + -0.07384853213925968, + -0.07052719974009367, + -0.009115618567828193, + -0.049747291755972006, + 0.020780008606603062, + -0.009556800742561933, + 0.026213548790071817, + -0.07655278831239481, + -0.004018932726478575, + -0.07790052349302415, + 0.02761517637180172, + -0.020174757303220103, + -0.04990407996147492, + 0.06941339569768579, + 0.08025414086147978, + 0.056456478071275656, + 0.08307038931185856, + 0.07117740272772527, + 0.07794453100910506, + -0.05488289300067717, + -0.023898610904488304, + -0.08338064643796675, + 0.014818399014677242, + -0.007755773869001975, + 0.04881010880360803, + -0.0027498883874668145, + 0.07403016339205201, + 0.1289350573969411, + 0.05175030553163096 + ], + "mean_abs": 0.043391839533143746, + "sd_abs": 0.03060602988505856, + "realized_sigma": 0.05301144699724714, + "shared_noise_variance_share": 0.7584175456816651, + "tolerance": 0.166 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.232, + "upper": 0.166, + "minimum_detectable_gap_80": 0.27589784288990027, + "faithful_pass_probability": 0.9991629717379075, + "real_gate_holdouts": { + "estimate": 0.5248843871065718, + "gap_from_epuf": -0.07099502768121047, + "lower": -0.232, + "upper": 0.166, + "pass": true + } + }, + "zint.men.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.04612282019850528, + "epuf_sampling_sd": 0.014194897912778011, + "psid_value": 0.06374851572258607, + "psid_n": 761, + "bridge_psid_minus_epuf": 0.32363805830954506, + "min_events": 3, + "floor": { + "replicates": [ + -0.04655022311978052, + 0.15597766650080813, + 0.00878782017470936, + 0.2973885867304944, + 0.0035311813756737642, + 0.01621474114216115, + -0.41523657285641646, + -0.26060284375268905, + -0.06383197800957463, + -0.03394239742429561, + 0.466462997347203, + -0.04198290552652284, + -0.16904002791963646, + 0.12055732001787445, + -0.1602677810282298, + -0.03536330493517004, + 0.1367899766676084, + -0.029020646429642527, + -0.09666022931039753, + -0.003956650792959815, + -0.09221359998259637, + 0.1262261422623514, + 0.020919946963622982, + 0.17440405510751877, + 0.025553538231047, + -0.03493824111281629, + 0.17246362342858346, + -0.08259346276357404, + -0.18391773203979267, + 0.12421970520935122, + 0.08524741138498726, + -0.10806630715170851, + -0.16161588018957862, + 0.19082877808034926, + 0.29015279823634943, + 0.2874455224566492, + 0.16620602003264295, + 0.11037924741166694, + -0.1823534073523545, + 0.10087755382988561, + -0.18003585563913238, + -0.26480749539471393, + 0.27699252548319797, + -0.5050706075467057, + 0.40769368722964905, + -0.0573469130575448, + 0.17257819422642018, + -0.04776624174600275, + 0.12600856715560416, + 0.06882720240560203, + -0.021331389006895574, + 0.2318748900999319, + 0.17614285185276302, + 0.015719900230762862, + -0.10217717994297026, + -0.056061320788513, + 0.05202099364154078, + -0.0019270638298052312, + -0.461518243999711, + 0.24096766462623642, + 0.06323143463241432, + -0.45506414176261667, + 0.11715499996759271, + 0.04646432288698521, + 0.01916200414764946, + -0.21296992363884515, + 0.15861898376404482, + 0.005575320480244894, + -0.18503097441948513, + -0.08016962762229207, + -0.006998062912959568, + 0.07633347432294868, + -0.3949745081971232, + 0.10853057471565597, + 0.10852936641189714, + -0.13496707511650485, + 0.3421461728477171, + 0.15828275681009107, + -0.05919981328812596, + -0.07303438078028623, + -0.14314513226425363, + 0.06578406056619479, + 0.026473122724732345, + 0.08812854593896713, + 0.1261384560420602, + 0.141898826971822, + 0.04714434896700026, + 0.07442385669994178, + 0.03349800351339294, + -0.011939143744578828, + -0.11164180570974302, + -0.04213653513544213, + 0.2563818716736419, + -0.20521444620736173, + -0.3106305826125304, + -0.16473054701833534, + 0.06737737803681343, + 0.1743928723268655, + -0.028634930508075085, + 0.283955512836068 + ], + "mean_abs": 0.13959765510416275, + "sd_abs": 0.11754835741728505, + "realized_sigma": 0.18211794386816352, + "shared_noise_variance_share": 0.8052600092673866, + "tolerance": 0.61 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.61, + "upper": 0.934, + "minimum_detectable_gap_80": 1.0869123868836317, + "faithful_pass_probability": 0.9995979266730952, + "real_gate_holdouts": { + "estimate": -2.7819891329688065, + "gap_from_epuf": 0.2944583033383519, + "lower": -0.61, + "upper": 0.934, + "pass": true + } + }, + "zint.men.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.04939929809793205, + "epuf_sampling_sd": 0.009072210108223067, + "psid_value": 0.04302662854033297, + "psid_n": 800, + "bridge_psid_minus_epuf": -0.13811702314318808, + "min_events": 0, + "floor": { + "replicates": [ + -0.014328335055329378, + 0.09415714450228374, + 0.2414400187041459, + -0.23731707952033343, + -0.15615064451259997, + 0.3554436910456942, + 0.060918726485909014, + 0.11140018331568236, + 0.6677258723505699, + -0.3397582570602129, + -0.1214833164593625, + 0.04101819921134919, + -0.011276367869076154, + 0.1703464394908929, + 0.18273203280384265, + -0.1446267840752271, + 0.6804741571213866, + 0.13836492622884022, + 0.33395300834871633, + -0.5269205049976775, + 0.3767293022957232, + -0.30126797246759107, + 0.050482741486243876, + -0.3965517708081636, + 0.0063508668526415235, + -0.028861623906210276, + 0.3776464581044714, + -0.19396725395736825, + 0.2380839151997689, + 0.14796188804410693, + 0.274058786128516, + -0.050389709129245785, + 0.022916741064188173, + 0.37835233903150023, + 0.4509194739258231, + 0.28896466949624955, + 0.1781529989847126, + 0.10859799553454219, + 0.34674587483341934, + -0.059866966040254876, + -0.02253693957903158, + 0.3709092632999742, + -0.17302567008190595, + 0.1766068329613768, + 0.08019802288814937, + 0.17404957726141457, + 0.03039982992204604, + 0.17067747681459755, + 0.20162663379958534, + -0.2964312380904979, + -0.07268342933589711, + 0.4899361728062721, + 0.4214669869803016, + -0.10526303649709545, + -0.5244669295476705, + -0.1632279723047232, + -0.11801329270639349, + -0.03715614454738847, + -0.016013285409479883, + -0.5891457641657767, + -0.1723694647515588, + 0.13366308650811098, + -0.15226053228244285, + -0.008048706950201323, + -0.4368128900564252, + -0.0813794550675766, + 0.7197215938694841, + 0.25660162388825314, + 0.01578529967924358, + -0.25083813357746854, + -0.02922618213474837, + -0.05724732157956969, + -0.48429774942642734, + -0.07269592344999665, + 0.19591346068109328, + -0.2005852695704844, + -0.07206215321474674, + -0.026139012954925045, + -0.7941836435037055, + 0.19990703610219995, + -0.406692894195283, + -0.3121721374615063, + 0.2788883774906643, + -0.020409666879324995, + 0.2542045528804906, + 0.34617898890778, + -0.3045010455137751, + 0.3480892260341508, + -0.06783864107571858, + -0.07346901916863624, + 0.3324677447097244, + 0.02670920003222621, + -0.32342082140828143, + 0.11413764143435712, + -0.010162211423442091, + -0.0015658962422773204, + 0.1978324917559251, + 0.23694374518195072, + 0.3035840360253086, + -0.711064514636897 + ], + "mean_abs": 0.22170610927155834, + "sd_abs": 0.18296520108117634, + "realized_sigma": 0.28687122729012177, + "shared_noise_variance_share": 0.7910531798488605, + "tolerance": 0.954 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -1.093, + "upper": 0.954, + "minimum_detectable_gap_80": 1.3335539393316762, + "faithful_pass_probability": 0.9994932672059756, + "real_gate_holdouts": { + "estimate": -2.888252963039785, + "gap_from_epuf": 0.11956610039330329, + "lower": -1.093, + "upper": 0.954, + "pass": true + } + }, + "zint.men.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.05776751410682007, + "epuf_sampling_sd": 0.011481765143101334, + "psid_value": 0.04049494629719925, + "psid_n": 621, + "bridge_psid_minus_epuf": -0.35524939445916504, + "min_events": 0, + "floor": { + "replicates": [ + -0.4325132560574507, + 0.026435327397104746, + -0.09777216071751793, + 0.5676537831821507, + 0.13202966902985058, + -0.14187878346013605, + -0.2317921254254678, + -0.2885197965116282, + -0.14464689577383494, + -0.06997094017855399, + -0.3958852944550475, + 0.10923729330491971, + 0.3006550611333496, + 0.008907499320431667, + -0.2925846897974327, + -0.12373305088954756, + 0.014798475397111543, + -0.08811186147620487, + 0.12404772138833575, + -0.008383071695250655, + -0.015781441446637068, + 0.28377083510695233, + 0.34173624208352527, + 0.00670425210084824, + 0.21444763972561387, + 0.14863061377867348, + -0.1574485311431526, + -0.13124432701499944, + 0.1699951233861443, + 0.19162896249128147, + -0.15372372321197103, + -0.3917211052673488, + 0.17871979966512974, + -0.1643774892241996, + 0.009293547778314926, + -0.35714813760191055, + 0.0664524714949093, + -0.2563486090632283, + -0.24833350691463818, + 0.06065537717121172, + -0.15037860158905247, + -0.2204363783228105, + 0.26202566954463613, + 0.153192398905579, + 0.06637423752944382, + -0.2389761875111922, + 0.10016745130806637, + 0.5024789859472436, + 0.37912013044014214, + 0.01882748709995319, + -0.15220088841614055, + -0.24474398067426772, + 0.08393898120934629, + -0.11140877909727154, + -0.41168784840785344, + 0.18293173400502583, + 0.1294290167123926, + 0.3638209187666883, + 0.3369118842522607, + -0.36526823620863236, + -0.5526939034866287, + 0.3051494831950945, + 0.13813039161486773, + 0.274245362393956, + -0.10849468913806692, + 0.1503188775969566, + 0.06591443609678338, + -0.4639056069874741, + -0.07498069864732204, + 0.5840297586604746, + 0.14811250327184555, + -0.18347272531889725, + 0.28867943243205585, + -0.3651393976351487, + 0.02406261718624525, + -0.1707460900693094, + -0.060816434570763356, + 0.1847603352385061, + 0.27119075633197753, + -0.12786385530903566, + -0.05511163549857856, + -0.5095175008483253, + 0.04175633587846539, + 0.4849738723027388, + -0.26080508878078357, + -0.040584366888632095, + 0.51417864164003, + 0.49484712935411657, + 0.42761555808422425, + -0.008834539927055296, + 0.12268260452136404, + -0.23878982837755336, + 0.25589828574777007, + 0.25609384751024455, + 0.36604851300741625, + -0.00024704655081353444, + -0.10348457714473125, + 0.2022112726150449, + 0.03721354037718805, + -0.13333784768508372 + ], + "mean_abs": 0.20718977676131586, + "sd_abs": 0.14936403797743847, + "realized_sigma": 0.25497867220008874, + "shared_noise_variance_share": 0.84965212730423, + "tolerance": 0.805 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -1.161, + "upper": 0.805, + "minimum_detectable_gap_80": 1.3748448590909876, + "faithful_pass_probability": 0.9992086679522362, + "real_gate_holdouts": { + "estimate": -3.1854622085996853, + "gap_from_epuf": -0.33413350761798366, + "lower": -1.161, + "upper": 0.805, + "pass": true + } + }, + "zint.women.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.04953213817227809, + "epuf_sampling_sd": 0.013716525747986593, + "psid_value": 0.05188914732730771, + "psid_n": 776, + "bridge_psid_minus_epuf": 0.046487946027435445, + "min_events": 2, + "floor": { + "replicates": [ + -0.3122493831099178, + 0.09447402264576166, + 0.1572391779104818, + 0.32617470999187903, + -0.0820116506563553, + 0.11065392760922488, + -0.11579305314754706, + 0.39666083249205886, + -0.20801964677025775, + 0.26574360171447164, + -0.10394399988758929, + -0.14384959842774814, + -0.07642990698162855, + -0.13047907043188256, + 0.09411624576798827, + 0.32665312083507314, + 0.32712939095500904, + 0.007605535339593628, + 0.23876800570897472, + 0.2473437442283346, + 0.02420292358894205, + 0.052637628400742376, + 0.08133446557079593, + 0.08672437150861434, + 0.216300876127677, + -0.08813940374077012, + 0.2502878536518356, + -0.1125087223597594, + -0.23109413110884214, + 0.28701953527672575, + 0.1470707201685164, + 0.11809361777456218, + -0.16938093455289138, + -0.27731575418707743, + -0.003868805540703235, + -0.32366842442039334, + -0.39239089196769994, + -0.13786317068209164, + 0.2981864480370031, + -0.16673174924531975, + -0.028526418118344665, + 0.15084939499438077, + 0.05388167187048776, + -0.010701858046224366, + 0.24399014717225764, + -0.05049027368781167, + -0.2636642627302619, + -0.005031540485799457, + -0.39640623684038134, + 0.08163529544967929, + -0.13893977205704933, + 0.1394823926275186, + -0.4283741792800795, + 0.2291359729344129, + -0.14431936378427168, + -0.27035636690831577, + -0.31800926260437823, + -0.02628237250582388, + -0.13431862843760944, + 0.03087153394609765, + -0.21092347592188943, + 0.2677783642080187, + 0.13092152826657233, + 0.32448098332626896, + 0.27069702939233964, + -0.35873282157015196, + 0.08284375305297753, + -0.2208280987441409, + -0.02230080461567341, + -0.06688980327138472, + 0.11773701592910246, + 0.001482078838410894, + -0.10058768273910834, + -0.13437238903373605, + -0.13416781508739284, + 0.16562015150877807, + 0.23605343684831315, + -0.030250951107833934, + 0.22265232605126206, + -0.3277051121869856, + 0.10699562068825297, + 0.1806722068849873, + 0.2624773822561681, + 0.39455543927332637, + -0.115645922330601, + -0.10865303840323493, + -0.299374589669019, + -0.09930583091439282, + -0.17859487666285445, + -0.07388191520412124, + 0.025368921196273764, + -0.10687709583269589, + 0.149170979602969, + 0.04265256104391413, + 0.029874449540316927, + -0.23418300841287443, + -0.023926633995295044, + 0.06495056076142691, + 0.21042093412367602, + 0.0166064361689362 + ], + "mean_abs": 0.16526640021669603, + "sd_abs": 0.11053028345032793, + "realized_sigma": 0.19851387146645164, + "shared_noise_variance_share": 0.807120715910488, + "tolerance": 0.607 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.607, + "upper": 0.654, + "minimum_detectable_gap_80": 0.8205614354123654, + "faithful_pass_probability": 0.998396860296134, + "real_gate_holdouts": { + "estimate": -2.8552258175416814, + "gap_from_epuf": 0.1499077465356904, + "lower": -0.607, + "upper": 0.654, + "pass": true + } + }, + "zint.women.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.06229546347068492, + "epuf_sampling_sd": 0.009719862568026, + "psid_value": 0.07214555729600632, + "psid_n": 930, + "bridge_psid_minus_epuf": 0.14679710172798321, + "min_events": 4, + "floor": { + "replicates": [ + 0.13580325599168264, + 0.39415687369818353, + -0.0989286858415388, + 0.029921154426276075, + 0.15748393138947825, + -0.19602522351188978, + 0.06306565209790027, + -0.20884067697725306, + 0.05190547708264659, + 0.028326792679646662, + 0.03711573583526695, + -0.2512632814133682, + 0.02173669408569312, + -0.043278975337938785, + 0.007450711862019954, + -0.36063658764859086, + -0.08264916570299374, + -0.21939813190081314, + 0.0025806797302696527, + 0.1101275042058254, + 0.422589803263546, + 0.2607012035701639, + 0.2082016820968473, + -0.20942685333656752, + 0.0584000339906412, + 0.026073401102441718, + 0.0186346340839596, + -0.12278917918020094, + 0.0656858061204757, + 0.15274806343783243, + 0.09945903856340221, + 0.007636807271456991, + -0.13551137624427323, + -0.41022982435962696, + 0.0676318398723903, + -0.26244492642949635, + 0.013981740448352209, + -0.03719255389455367, + 0.14744089253591497, + 0.1604979585928148, + -0.12253245189927076, + -0.027598427389479596, + -0.01972884252814988, + 0.06857917581932171, + 0.0009047314723011901, + 0.26568230952705196, + 0.44198745757360114, + -0.14472233824230707, + -0.20442826419955962, + 0.2161045455787367, + 0.0766605569362373, + 0.050064694778060304, + 0.05680630039443191, + 0.14360040182550082, + -0.011265559268922365, + 0.10702382023140267, + 0.03936901437422802, + 0.1790990315801484, + -0.21536231005277573, + -0.32192952206484327, + -0.27704516517378064, + 0.07689623678253188, + -0.16100988855753018, + 0.14722927926072016, + 0.14411502790426822, + -0.042179685552598656, + -0.20080577037257608, + 0.4894768503911797, + 0.053259699669789384, + 0.13653244481573124, + 0.3524813979627144, + 0.2864938675965314, + 0.25345010169864346, + 0.05649213383067653, + -0.04441936805709634, + -0.1347206046587459, + 0.12393483282157858, + 0.14385900148187636, + 0.16011518157243265, + -0.11783264648256053, + 0.24226037707510706, + -0.3867534256676528, + -0.0849279949688364, + 0.049391287905437675, + 0.12346704276894349, + 0.12267410053795147, + 0.22023561232815458, + 0.1371341728578519, + -0.33227507262198297, + 0.06880897042303191, + 0.18397513969738966, + 0.04186181826614188, + 0.3308803598063821, + 0.11648809785199243, + 0.3278703545405717, + 0.029435734884602383, + -0.07555085079201973, + -0.41573888671122305, + 0.03266962070398316, + -0.1320320435895339 + ], + "mean_abs": 0.14958202714192917, + "sd_abs": 0.11753035374075863, + "realized_sigma": 0.18986846250447284, + "shared_noise_variance_share": 0.8397382082305642, + "tolerance": 0.62 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.62, + "upper": 0.767, + "minimum_detectable_gap_80": 0.9265944313575902, + "faithful_pass_probability": 0.999428657297769, + "real_gate_holdouts": { + "estimate": -2.6403871772898224, + "gap_from_epuf": 0.13547949603522236, + "lower": -0.62, + "upper": 0.767, + "pass": true + } + }, + "zint.women.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.08531100121766358, + "epuf_sampling_sd": 0.00981867541735719, + "psid_value": 0.0856936146279939, + "psid_n": 670, + "bridge_psid_minus_epuf": 0.004474897322680249, + "min_events": 3, + "floor": { + "replicates": [ + 0.06736233932160385, + -0.09061111766108576, + -0.05708120248201287, + 0.31669957625997425, + -0.08481582222579087, + -0.3160979097620302, + -0.038139374475324894, + 0.45985426174457067, + 0.03275657953012345, + -0.10774173013387123, + -0.19947574583066086, + -0.2861896591632431, + 0.21926313768117978, + -0.29328137461826054, + -0.28347478839181695, + 0.2646442087493528, + -0.1849301294312078, + -0.035396014353386684, + -0.09301272150407103, + -0.2195741937976794, + 0.056137921339340036, + 0.23937790583876262, + -0.14047119957304144, + 0.1859094413205853, + 0.27814604770307594, + -0.2986044825278864, + -0.056298496290390077, + 0.0017348824076806046, + 0.01017325534182989, + -0.06519068552896412, + 0.12203962167772109, + -0.16867211426084494, + -0.09394969963916688, + -0.23235102852426315, + 0.014954765798022018, + -0.14980694642133408, + 0.07565430481993407, + -0.10583798376130127, + 0.0989627766414658, + -0.29408491034122064, + 0.31665908118800323, + -0.007628087365198821, + 0.11898252469886406, + -0.0014352572540923259, + -0.2238664913710311, + 0.013956321486558343, + -0.04607866112209247, + -0.016185258027588967, + 0.11880600222063253, + 0.4007964422916157, + 0.13480793784392708, + 0.1880884894873296, + 0.1763014437322452, + 0.010053355198704983, + 0.12657822289057963, + -0.00024929508753879226, + -0.08554985741532506, + 0.15932918174110688, + 0.14364098769006062, + -0.08625853761406255, + 0.3328567749988025, + -0.07685835594713897, + 0.1362504996042364, + 0.22538754509112402, + 0.14134591880377378, + -0.07013953170660336, + -0.0045472627781959485, + 0.1460966900016203, + -0.07107514288286021, + 0.14745056553135027, + 0.2842568529549727, + 0.12253170183169759, + -0.11639069010250291, + 0.022738474077931725, + -0.003762448351361636, + 0.30479875950122026, + 0.07595901533400906, + 0.17473245694471085, + -0.009342038720254742, + 0.1635305462076153, + -0.05039934727519202, + 0.08134622982764461, + -0.1350346629426511, + -0.07311787884583731, + 0.2343391978633722, + -0.049099727696587214, + 0.1560439174239967, + 0.060376151324134986, + -0.27493003361898194, + 0.13045731459230625, + 0.07479415652960553, + 0.13236700353442155, + 0.1299223868718804, + 0.07654102425812925, + 0.23578093836427816, + -0.05574941851599413, + 0.012561101504733108, + -0.2417966409990835, + -0.13972032715031113, + -0.08485420853962822 + ], + "mean_abs": 0.13773294731651387, + "sd_abs": 0.10102474482569057, + "realized_sigma": 0.1705118877173041, + "shared_noise_variance_share": 0.8817502195582486, + "tolerance": 0.542 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.542, + "upper": 0.547, + "minimum_detectable_gap_80": 0.689981322602164, + "faithful_pass_probability": 0.9985925146505304, + "real_gate_holdouts": { + "estimate": -2.5301252781431414, + "gap_from_epuf": -0.0686734162413587, + "lower": -0.542, + "upper": 0.547, + "pass": true + } + }, + "d_anyzero.men.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.11174854735725806, + "epuf_sampling_sd": 0.007585313405558821, + "psid_value": 0.1134530894274814, + "psid_n": 799, + "bridge_psid_minus_epuf": 0.015138208107779327, + "min_events": 6, + "floor": { + "replicates": [ + -0.029260482752089034, + 0.13679940340352026, + 0.07705469085609784, + 0.03211843882554355, + 0.11486040798780706, + 0.12420331702839671, + -0.08472805696846142, + -0.017394716184427228, + 0.0513594287044119, + -0.07504824985709901, + 0.19470947082332035, + -0.017944257008175812, + -0.21212089047182103, + 0.14702773781452927, + -0.17263692314850942, + -0.058712522327699634, + 0.0948790734418099, + 0.000532453737849492, + -0.031637608479723855, + -0.08939389571787304, + -0.06303428197962746, + -0.03728791532102149, + 0.04991068288536882, + 0.15069911000644165, + 0.12875256584678807, + -0.02473594454620276, + 0.19137029363422775, + -0.1528167978379995, + -0.07101858935300953, + 0.05629640705349126, + 0.12665256829205207, + 0.02358951318768643, + -0.05116900147583481, + 0.005505775066714902, + 0.12152181937565709, + 0.12711814155260237, + 0.26134389943113423, + 0.2170629476904764, + -0.10755208999778598, + 0.08068822465977199, + -0.21743725376711165, + -0.4399993674953777, + 0.04966999278685402, + -0.38166438229874133, + 0.30253369163087784, + -0.14427931495436797, + 0.03382643904039284, + 0.17900625650349777, + -0.013263084423460025, + 0.11790077407303423, + -0.05711693333891632, + 0.23853782155829606, + 0.15503863826971154, + 0.07563099096699721, + 0.05716433293239098, + -0.0486419462268628, + -0.034845869234483295, + 0.03365655790440192, + -0.3310643471290158, + 0.22456728939646387, + 0.005632567952937428, + -0.11722496217237355, + 0.1514682746524818, + 0.18236053787325668, + -0.03313990167434788, + -0.13196447996922345, + -0.0354829512581043, + -0.0021651216942417673, + -0.03131002491104273, + -0.1243996501242397, + 0.008701661765123436, + -0.035794560727537617, + -0.2567737928687226, + 0.05999567870739897, + -0.014907482579986198, + -0.13447364324993272, + 0.03990929648699337, + 0.09374039569837755, + -0.16982539402228713, + -0.03604398511312845, + -0.06564932417713254, + 0.12024773983821091, + 0.11484309234561607, + 0.13013974449159083, + 0.08335522719666155, + -0.04127547915423446, + -0.033001403185783484, + 0.1984283533846234, + 0.09655320165224479, + -0.09412400890822048, + 0.029532335387060016, + -0.0580681280747144, + 0.3350060546151137, + -0.08278230773256245, + -0.05394757262015415, + -0.06495305287470621, + -0.13658136463223158, + 0.04261656171874795, + 0.15323644991315633, + -0.008899524722040697 + ], + "mean_abs": 0.10554949168790861, + "sd_abs": 0.08678853275361863, + "realized_sigma": 0.13637309895623315, + "shared_noise_variance_share": 0.7711407154923847, + "tolerance": 0.453 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.453, + "upper": 0.469, + "minimum_detectable_gap_80": 0.5829127038774854, + "faithful_pass_probability": 0.9992640616721213, + "real_gate_holdouts": { + "estimate": -2.1833041606992407, + "gap_from_epuf": 0.008199883913902806, + "lower": -0.453, + "upper": 0.469, + "pass": true + } + }, + "d_anyzero.men.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.1207520381057067, + "epuf_sampling_sd": 0.006516360998945018, + "psid_value": 0.1033160760107626, + "psid_n": 851, + "bridge_psid_minus_epuf": -0.15594618259593584, + "min_events": 7, + "floor": { + "replicates": [ + -0.3630472583763116, + 0.19875842577037606, + 0.03170176319690565, + -0.11008741749484008, + -0.040831275236310915, + -0.1492970981525985, + 0.2487602011171084, + 0.0548190984038075, + 0.504613989296346, + -0.29036442856700684, + 0.12885659585999187, + 0.07920212098254531, + -0.11069698496954228, + 0.018464859632182362, + 0.057798115425166774, + 0.11544044319366309, + 0.3100863906717619, + 0.038777620248873435, + 0.035486425245268016, + -0.11553323125600024, + 0.09047335804870227, + -0.15428477893440218, + 0.07053320989938472, + -0.1953139337664307, + -0.19461440344492442, + -0.009868440456330507, + -0.16963387023806842, + -0.1691046432814325, + 0.04853228630172479, + -0.03734370703512857, + 0.07760702602297265, + -0.04227023870274471, + -0.014655952218312729, + 0.4978105685982672, + 0.10759775442952213, + 0.2529414420731815, + 0.2569452965473855, + 0.1299994167384504, + -0.03704549784539801, + 0.17707381400322353, + -0.042430891021173256, + 0.12472791327462796, + 0.048853783328549394, + 0.09984769875219435, + 0.1239416711595398, + 0.18858478182750416, + 0.013108035081344394, + 0.1403039637631449, + 0.2408835347645646, + -0.1986816096299413, + -0.19956070906354717, + 0.17588563768551224, + 0.12777289441025608, + 0.04077494867544651, + -0.049750508916838854, + -0.16494241410318722, + -0.002379588857293724, + -0.017090638749129416, + -0.02709859607152665, + -0.212632436261184, + -0.2493189374521685, + -0.02162083766400902, + -0.01940893795773513, + -0.06288835520517844, + -0.1683055707345973, + 0.04887154723211351, + 0.3330629429760108, + -0.07519107534041791, + 0.052860685016435704, + -0.26020925392984307, + -0.17901474704340403, + -0.16413324072734414, + -0.09605009276201604, + -0.027051899038974536, + 0.23932190457881664, + 0.08598106532712668, + -0.09289102458354304, + -0.1874196773065091, + -0.1752121297029121, + -0.000948377443837245, + 0.00672859634187839, + 0.07973412648654521, + 0.055098641542078886, + -0.09315755218131261, + -0.10630130371360114, + 0.08117995687104007, + 0.20456419513547486, + 0.08784162642222038, + -0.04892541288154706, + -0.18397514314107055, + 0.3420062418751213, + -0.08483964998855065, + -0.4549379284924244, + 0.03155136447989082, + -0.05503701193409327, + 0.11011555987625088, + -0.04604424101609128, + 0.325685506209928, + 0.11472891247327799, + -0.26336798801745376 + ], + "mean_abs": 0.13291108898181944, + "sd_abs": 0.10762123927675528, + "realized_sigma": 0.1706805946977075, + "shared_noise_variance_share": 0.6564372184049466, + "tolerance": 0.563 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.719, + "upper": 0.563, + "minimum_detectable_gap_80": 0.862594595252379, + "faithful_pass_probability": 0.9995019900470593, + "real_gate_holdouts": { + "estimate": -2.160749939477582, + "gap_from_epuf": -0.046733831607891574, + "lower": -0.719, + "upper": 0.563, + "pass": true + } + }, + "d_anyzero.men.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.1530368274404898, + "epuf_sampling_sd": 0.005238972057206756, + "psid_value": 0.07515067155904992, + "psid_n": 650, + "bridge_psid_minus_epuf": -0.7111835422465012, + "min_events": 4, + "floor": { + "replicates": [ + -0.21141905137494454, + 0.026862770302403582, + -0.05400073395660665, + 0.41140416378920697, + 0.3701310151330095, + -0.21455557388624902, + -0.0901352660316348, + 0.10984983778473478, + -0.2201616288722681, + 0.03619345681469355, + -0.32295476997015893, + 0.015064433855552117, + 0.1410406414366696, + -0.054405886400692216, + 0.03725048226692218, + 0.03648770814289226, + 0.022131153840547757, + 0.004178563206376662, + 0.03660097188969602, + 0.06177030314361631, + 0.054928029370135745, + 0.31688921834394246, + 0.3419336038388969, + -0.07319635931448065, + 0.2713898242305153, + 0.1130854435999058, + 0.0679476366741325, + -0.044813573311728305, + 0.34036753402030273, + 0.14750954725116872, + -0.27110246049391806, + -0.30411675873626565, + 0.3723100371053074, + -0.04525448701682966, + 0.10778246319526841, + 0.06418390134547591, + 0.07465914096871318, + -0.169110957079871, + -0.2576303553114989, + 0.09253753909046969, + -0.08920441204866458, + -0.3444572154665353, + 0.2513462787914371, + 0.07636903519485139, + 0.049067996252233126, + -0.03803106822641, + -0.029119077430062257, + 0.2819687934049129, + 0.03652228820260772, + 0.06474132975426605, + -0.14990632800195858, + -0.27482314333165925, + -0.0005052178219340231, + -0.03880409094010395, + -0.24448794602911206, + 0.09265556542403619, + 0.08753983644687002, + 0.2832970506279602, + 0.10926451044923713, + -0.079466373532731, + -0.3254034510364232, + 0.27641198594914784, + 0.060762560852406944, + 0.01466470625932459, + -0.18625497626877796, + 0.23143277417054842, + -0.04793938602231562, + -0.22785174400275543, + -0.07682021180509357, + 0.27853862536410134, + -0.06868193135767453, + -0.20773634488178372, + 0.24818792040273951, + -0.07411901320526271, + -0.024435813770844694, + 0.012768420804408098, + 0.08716032656419492, + -0.11322664688495765, + 0.11556483406781437, + -0.029280700397253057, + -0.16115352962413199, + -0.007504161772715401, + 0.011542571229546716, + 0.28258312068018054, + -0.018822747941898532, + -0.1439425933119396, + 0.06832318934126391, + 0.06746002696414077, + 0.2818057395593796, + 0.03425873728890516, + 0.15968068828639548, + 0.0693740231562967, + 0.030835182513816006, + -0.012622762034519397, + 0.14755715924707946, + 0.05755756258623279, + -0.03820157029896509, + -0.07071479610971343, + -0.023606905579299786, + -0.11783500204166786 + ], + "mean_abs": 0.13141549283411202, + "sd_abs": 0.10933328178693909, + "realized_sigma": 0.17059970866936366, + "shared_noise_variance_share": 0.8197671429192506, + "tolerance": 0.569 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -1.281, + "upper": 0.569, + "minimum_detectable_gap_80": 1.4237638795039906, + "faithful_pass_probability": 0.9995812267827784, + "real_gate_holdouts": { + "estimate": -2.5016111633847213, + "gap_from_epuf": -0.6245344790563103, + "lower": -1.281, + "upper": 0.569, + "pass": true + } + }, + "d_anyzero.women.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.14444050852127366, + "epuf_sampling_sd": 0.006938591086387653, + "psid_value": 0.10727608634965125, + "psid_n": 834, + "bridge_psid_minus_epuf": -0.2974619594432444, + "min_events": 7, + "floor": { + "replicates": [ + -0.020123356335037368, + -0.01306206117043951, + 0.1476619583568648, + 0.32802853294551226, + -0.06942273184275294, + -0.016621415502744874, + -0.12859055891887428, + 0.2996108457127994, + -0.15427353721910775, + 0.1698602153071409, + 0.03581159402781653, + -0.015289136575569406, + 0.028898553839364904, + 0.14427138564433384, + 0.00844411191680039, + 0.11215558812069104, + 0.09212677485978271, + 0.013582679202676085, + 0.21642994598254428, + -0.06020739472129688, + 0.10665936916464358, + -0.06131836218811593, + -0.03250458523861077, + 0.010725813506375914, + 0.08804574512555052, + -0.1219694686395345, + 0.07230995734777368, + -0.07595855519959427, + -0.12021675852169023, + 0.19235602259767548, + 0.018847765685482187, + 0.05233217736242324, + -0.09752481067538343, + -0.12711552858086694, + -0.01893515003429802, + -0.24990516224361947, + -0.18045058191407648, + -0.026738845832260605, + 0.08481544855639078, + -0.015655199762610206, + 0.042489892055552314, + 0.12396583611282908, + 0.008144610151723963, + -0.016306969279003436, + 0.10577342232905407, + 0.03954827005018835, + -0.1878400285722115, + 0.01572957057658031, + -0.24347867997790162, + 0.02364491747119235, + -0.11799101013170654, + 0.09465513285383387, + -0.09085246352403531, + 0.14223689091489367, + -0.09902861127954043, + -0.13791491165357805, + -0.24077654617287436, + -0.1330508018099592, + 0.07921521531973852, + -0.04261953679209918, + -0.2113706547021459, + 0.14977596038270646, + 0.055346995171236424, + 0.2014020750041623, + 0.2324179694492412, + -0.2119000014897503, + 0.10834379971614028, + -0.2854811774579602, + -0.055115143763993846, + -0.12520282254489246, + 0.0021130973792089502, + -0.18148053473223635, + -0.0006191476675723173, + -0.22021964107148673, + -0.09899826889176144, + 0.013717556515621787, + 0.0626442995833063, + 0.0252761339922023, + 0.11078332407804825, + -0.0630040466231887, + 0.06645291686753407, + -0.036999678754178866, + 0.1768333294632014, + 0.18077674569112756, + -0.14034949537085661, + -0.02170450848411054, + -0.16705088821853797, + -0.10621253354219995, + 0.07505214718031494, + -0.24150334994121803, + -0.12180668700133057, + -0.12384254805168515, + 0.1982352949822379, + 0.10985910883137273, + -0.08530133795021588, + -0.05796832010324082, + 0.13737721998662566, + 0.02099284460104034, + 0.30097448330282384, + 0.10433007286889762 + ], + "mean_abs": 0.10702957164817235, + "sd_abs": 0.07827503305548618, + "realized_sigma": 0.13236706614196123, + "shared_noise_variance_share": 0.7790638644577595, + "tolerance": 0.42 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.718, + "upper": 0.42, + "minimum_detectable_gap_80": 0.8288648929340693, + "faithful_pass_probability": 0.9992560876085015, + "real_gate_holdouts": { + "estimate": -2.186808462523323, + "gap_from_epuf": -0.25192090058446737, + "lower": -0.718, + "upper": 0.42, + "pass": true + } + }, + "d_anyzero.women.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.18121376454974378, + "epuf_sampling_sd": 0.005907556785781356, + "psid_value": 0.15932157915084325, + "psid_n": 1021, + "bridge_psid_minus_epuf": -0.12875268394030193, + "min_events": 15, + "floor": { + "replicates": [ + 0.1322823309654655, + 0.16785611248860266, + -0.013820184984114414, + 0.03624483616738172, + 0.04825469509435931, + 0.02081210605191841, + 0.010676882140787103, + -0.0023636982116762573, + -0.060013208049847444, + 0.009636663990038818, + 0.0034192069186129714, + 0.007291552139760293, + 0.010849169803740066, + 0.13383595862989828, + 0.03927608819891626, + -0.16605902413055362, + 0.10902282183531387, + 0.01078575137391291, + 0.07196113431358808, + 0.13227503105820204, + 0.23009859056847481, + 0.055623557925539746, + 0.21842694518483807, + -0.09317265446137502, + 0.027753524760368187, + 0.16235209039276743, + -0.008230191315222513, + -0.05771094278553712, + -0.09465019298252719, + 0.13099334248023764, + 0.07641880567827652, + -0.11052226588270142, + 0.021757362998970242, + -0.15499201994379297, + -0.006368758180960721, + -0.12533016738581515, + 0.07712311509670433, + -0.05014891337378946, + 0.16547081479407277, + 0.027285837326386786, + -0.06374566175521479, + -0.04270451114854723, + 0.14136150605826125, + -0.01040524849632618, + 0.07003031279531957, + 0.039209372027868006, + 0.16389130500041527, + -0.06810615694622435, + -0.05591537484579412, + 0.07245269944111077, + 0.07287952087629246, + 0.13730040383350117, + -0.04170826299142072, + -0.06854937100303349, + -0.07248932337348468, + 0.09746634264897391, + -0.03019530335922349, + 0.05490187406490854, + -0.11032712605559503, + -0.14003932713962086, + -0.191419986287087, + -0.026178587089460525, + -0.08408289434465732, + 0.16893207692625323, + -0.011009952426729197, + -0.03263469221267046, + -0.15534194256306433, + 0.15478733989621973, + 0.09678519620970272, + 0.08084901632301955, + 0.06379574263512333, + 0.1251663683475185, + 0.09981565935585901, + 0.15124941467162045, + 0.013112522624175171, + -0.097163118538373, + 0.08462225346147134, + -0.16000489728673395, + 0.27714013657963166, + -0.005112632885726498, + 0.02447329367860862, + -0.11917764405552178, + -0.006636103632803758, + 0.01933693292672445, + 0.0476437503755911, + 0.022933321971606357, + 0.014402393318956874, + 0.012496542117265586, + -0.02823215501745191, + -0.009419840643037802, + 0.20960923052905267, + 0.0360278180109882, + 0.08884055853876471, + -0.027790132323703864, + 0.2074291942490698, + 0.038333150001632066, + 0.0067701619554140224, + -0.28517291807527634, + 0.03557898843693896, + -0.15442538546053175 + ], + "mean_abs": 0.08108779499910222, + "sd_abs": 0.06586539015226778, + "realized_sigma": 0.10425976031781281, + "shared_noise_variance_share": 0.8332751932740721, + "tolerance": 0.345 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.474, + "upper": 0.345, + "minimum_detectable_gap_80": 0.5614999120309959, + "faithful_pass_probability": 0.9995331122412535, + "real_gate_holdouts": { + "estimate": -1.808562059297702, + "gap_from_epuf": -0.10048413433818548, + "lower": -0.474, + "upper": 0.345, + "pass": true + } + }, + "d_anyzero.women.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.21506408205915595, + "epuf_sampling_sd": 0.005405600768118903, + "psid_value": 0.18668260282743956, + "psid_n": 754, + "bridge_psid_minus_epuf": -0.1415261760999349, + "min_events": 13, + "floor": { + "replicates": [ + -0.07792183798813335, + -0.03940744410876984, + -0.04343657794878342, + 0.14693024600374438, + -0.05305620284289936, + -0.04328324092496927, + 0.01705563985672154, + 0.2199548569898826, + 0.03373791200225784, + -0.045153429787722854, + -0.09204997827458306, + -0.16829826711349005, + 0.10867213019949873, + -0.2013481790529269, + -0.029186680766952744, + 0.2617894665765649, + -0.021837562857652704, + 0.036602665712578863, + 0.029124444871476696, + -0.10273247308602296, + 0.002664196196948354, + 0.14912153989713262, + -0.050901366767989176, + 0.07964249081273156, + 0.08981134331149543, + -0.059310857980187426, + -0.08297587959485275, + 0.12150567734275242, + 0.039106878866450256, + -0.06502026100721714, + 0.006817961773541326, + -0.036873128287411516, + -0.049291540904339515, + -0.20047436009077468, + 0.06702429555861289, + -0.016511568280761835, + 0.048412825547791805, + -0.05672082046496629, + 0.19996098222363945, + -0.2187243962228168, + -0.057606782510344345, + 0.039032328209208766, + -0.08540571440807765, + 0.03934135801911132, + -0.1757226604968235, + -0.10378699656423473, + -0.03142256980935787, + -0.09121027399792947, + 0.11946037469102544, + 0.20950965799053411, + 0.0700009789734436, + 0.12488444885660366, + 0.14731427641383976, + 0.04152962686714279, + 0.01394488834477925, + 0.05830416657343995, + -0.11994803383253638, + -0.0001367409958056287, + 0.028156351236734323, + 0.03784723338546947, + 0.1819480068054118, + 0.11278807157211668, + 0.08961195200726169, + -0.017067530194204372, + 0.04308279278753224, + 0.07262798713545005, + 0.09565277823827267, + 0.19124304070329656, + -0.23961164314356553, + 0.10430759277625579, + 0.07456283499910576, + 0.07375105187042796, + 0.019919837555936404, + -0.01477969695660053, + 0.041933018041058534, + 0.21885325246453802, + -0.046855336485522314, + 0.05356484808124007, + 0.0011562204574586676, + -0.002040648435235992, + 0.04030097495784024, + 0.04097180841313652, + -0.011713220110509903, + 0.01303818492521569, + 0.16324270217796089, + 0.0264459710423528, + -0.17055742799012585, + 0.11653608044854868, + -0.08985325800336441, + 0.08980054118350522, + 0.19376605905833322, + 0.07675212190082825, + -0.0686484098816249, + 0.033559542065267345, + 0.07488255026172386, + -0.021781258460202957, + 0.008231106599279503, + -0.12796659509847297, + 0.15973730196234792, + -0.03198465403908757 + ], + "mean_abs": 0.08262144979564708, + "sd_abs": 0.06402161859293053, + "realized_sigma": 0.10432681312644755, + "shared_noise_variance_share": 0.7491023487968095, + "tolerance": 0.339 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.481, + "upper": 0.339, + "minimum_detectable_gap_80": 0.5683298372581467, + "faithful_pass_probability": 0.9994288778480935, + "real_gate_holdouts": { + "estimate": -1.6851184774499817, + "gap_from_epuf": -0.14829923827471303, + "lower": -0.481, + "upper": 0.339, + "pass": true + } + }, + "q_atmax.men.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.15384588473191108, + "epuf_sampling_sd": 0.005687323396499473, + "psid_value": 0.22561493263149526, + "psid_n": 3219, + "bridge_psid_minus_epuf": 0.38287835533939907, + "min_events": 76, + "floor": { + "replicates": [ + 0.006268685924624817, + -0.06896157523881219, + -0.10736535434214345, + 0.009809698333810402, + 0.021413338562194406, + 0.06790947318243346, + -0.07983344782546675, + -0.027532304530521357, + 0.02760053337609336, + -0.0514393446196485, + 0.0719505769082811, + -0.04121058188815041, + -0.11704566781748127, + -0.08721754537211557, + -0.05048162440363735, + 0.08269285775315183, + 0.06507796191611226, + 0.09955747917297675, + -0.02880405748015591, + -0.061770402170215566, + 0.009798995421709034, + -0.02913558626663526, + -0.005306509864348885, + 0.045349053163840636, + 0.015873904996704602, + -0.05032111183866317, + -0.07260515730103267, + 0.03406762329277613, + -0.06594104446621807, + 0.05343256122032136, + -0.042029934707843664, + 0.1799505976702117, + -0.03815374511172265, + -0.11969250201631465, + -0.09660977202977439, + -0.003346920904507944, + -0.011746728185735189, + -0.12321117698678286, + -0.08720033595971421, + -0.10459949434018478, + -0.0845386794828098, + -0.08516967906407436, + 0.014754349692642776, + 0.08385497822013599, + -0.002928533950293244, + 0.01322929854039634, + -0.02292125024718983, + 0.012159815137235519, + 0.07732732724329183, + 0.016750723788165223, + -0.04801041608027945, + -0.20623864678802528, + 0.08296337412535193, + -0.048546391364383545, + -0.045197065125143654, + 0.1472851931689595, + 0.011018295050580162, + -0.011764679117148513, + 0.07934367153176003, + -0.010892772217998559, + 0.09088637401617294, + -0.0966682567558611, + 0.0426477525380794, + -0.08882224550986417, + -0.03172439513420455, + 0.047438640569666846, + 0.17632818683030382, + 0.023241245788923948, + -0.06135038447035168, + 0.0002076527781937898, + 0.02478098341365831, + -0.013961397266538222, + 0.13169922512580734, + -0.10209687137056689, + 0.008917280725322163, + 0.03421656171441412, + -0.04889091610871299, + -0.041806641048157234, + -0.06957059302666535, + -0.008506119703374004, + 0.015346606752661196, + 0.1136912041391992, + -0.12531139417489523, + -0.06048714094073426, + 0.01722875461217177, + -0.03998221750138231, + -0.012843583462227914, + 0.10469144781803641, + 0.05989198595879608, + -0.09728379351999439, + -0.03438940306391125, + 0.068085539184645, + -0.08029637796343203, + 0.07231944767347342, + -0.03850095836419232, + -0.07189132042339652, + -0.024567563796850433, + 0.11136414615486878, + -0.15072484340041603, + -0.11114914440961032 + ], + "mean_abs": 0.06021019003708668, + "sd_abs": 0.0435041867060745, + "realized_sigma": 0.07415493983983475, + "shared_noise_variance_share": 0.6511498444615121, + "tolerance": 0.234 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.234, + "upper": 0.617, + "minimum_detectable_gap_80": 0.679288727282926, + "faithful_pass_probability": 0.9992035275388971, + "real_gate_holdouts": { + "estimate": -1.503582209399558, + "gap_from_epuf": 0.36822171674614146, + "lower": -0.234, + "upper": 0.617, + "pass": true + } + }, + "q_atmax.men.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.12650910252315553, + "epuf_sampling_sd": 0.005533914747447267, + "psid_value": 0.19550268988820213, + "psid_n": 3402, + "bridge_psid_minus_epuf": 0.4352598760661004, + "min_events": 47, + "floor": { + "replicates": [ + -0.04013813878469119, + 0.02318613881884457, + -0.01302304647539898, + 0.07815243151769868, + 0.16435318475841731, + 0.06565373160080912, + -0.03208124686865721, + 0.06343039186616228, + -0.07536899573647127, + 0.009234866476144798, + -0.08924780363962104, + -0.11376830072939637, + -0.028630205491736338, + -0.06434220535118906, + 0.17555432949606176, + -0.013042895399761334, + -0.08125868363348587, + 0.02269483527410643, + -0.04731398903855022, + 0.05298895494803768, + -0.0742309355143852, + -0.08217965493039325, + 0.05484853226792108, + -0.041171018799089465, + 0.13154517575932667, + -0.07667301608609378, + -0.08230824786598678, + 0.05943633697891304, + 0.23366721920875322, + 0.092238616286062, + 0.03552862364941445, + -0.03098618377999518, + 0.07341933142693824, + -0.15788086856808792, + 0.1004205830666054, + -0.09680764281082821, + -0.027920637302293994, + -0.15876560405430817, + 0.037497075051844186, + -0.05198846122396583, + 0.049693431624255546, + 0.15926334173508427, + -0.01760871313926904, + -0.08018455309596362, + 0.019836250698934577, + -0.040415147338026536, + -0.023065175687228545, + -0.07149537869189537, + -0.06400376808967168, + 0.1583687960304916, + 0.014711037438157049, + 0.17423750240940172, + 0.07306900079249634, + 0.0840625346329974, + 0.05408809184939811, + -0.16065181009851004, + -0.08125769036009334, + 0.1612023285161448, + 0.09231026384044838, + 0.031102902989232906, + 0.013376277631312994, + 0.03025455444331504, + 0.19019350535084634, + 0.15757380041616642, + -0.08794543645450092, + -0.004814256123014227, + 0.02793457446632519, + 0.02745232967854938, + 0.17885721718850411, + 0.07956811246915174, + 0.03330981119073362, + -0.22769807491701732, + -0.07118273627683602, + 0.0289207203734535, + 0.16210178255183683, + 0.11321193083221504, + 0.008751699820555348, + -0.014336965101112487, + -0.07893750811884492, + -0.05714925348317956, + -0.07492072894073187, + 0.20205956543731163, + 0.019331357960828632, + 0.040874220056381416, + 0.10852307016538709, + 0.01773185725806692, + 0.023147777363521582, + 0.05242270789507286, + 0.09075489704321549, + -0.04989201688744449, + -0.03543858419878121, + 0.07429075476898062, + -0.012240288808053612, + -0.05516022100462714, + -0.06291604047820498, + 0.04723261030139969, + 0.0800658911997939, + -0.013336537929512948, + 0.002841063016242318, + -0.051995874501780226 + ], + "mean_abs": 0.07272352471696958, + "sd_abs": 0.054036462010903924, + "realized_sigma": 0.09044031668260008, + "shared_noise_variance_share": 0.7433058094147004, + "tolerance": 0.289 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.289, + "upper": 0.725, + "minimum_detectable_gap_80": 0.8003763669572352, + "faithful_pass_probability": 0.9993215394855008, + "real_gate_holdouts": { + "estimate": -1.5846878827692255, + "gap_from_epuf": 0.4827531339293092, + "lower": -0.289, + "upper": 0.725, + "pass": true + } + }, + "q_atmax.men.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.06812218003195328, + "epuf_sampling_sd": 0.008853612442503234, + "psid_value": 0.11162778379786058, + "psid_n": 2583, + "bridge_psid_minus_epuf": 0.49386711962403407, + "min_events": 11, + "floor": { + "replicates": [ + 0.09720674185722644, + -0.06694919856473058, + -0.0751324876865822, + 0.003259287628533558, + 0.05269804804247169, + 0.15749176937389153, + -0.17257518938530492, + 0.20554003383986963, + -0.14198229130598872, + -0.10282837216921292, + 0.08691086569062767, + 0.021092367672142398, + -0.06987862637968023, + -0.01998439539405461, + 0.05620795571241266, + -0.002115768545050578, + -0.2332713110743625, + -0.11619719264568706, + -0.05994414185292629, + -0.281423939451219, + 0.02004173777401097, + 0.022839041023165807, + -0.11389617157252285, + -0.05616524809427914, + 0.22955865813676524, + 0.1919266323391331, + -0.29449382820178416, + -0.1727771486524008, + -0.14417007116571456, + -0.04480130330044996, + 0.10689745523753347, + -0.041124295491419494, + 0.19232210072076272, + 0.019056426930049275, + 0.09510507437562277, + 0.17897221237150673, + 0.1933298535741763, + -0.05846907410329716, + 0.02999241579079337, + -0.13135391670061636, + -0.06394927666678707, + -0.09169105591412219, + -0.03152770142220729, + -0.01235972192206014, + 0.04292504684986165, + -0.043364350962640685, + 0.08215050154637793, + -0.002639596207686834, + -0.031884647845350944, + -0.0941459812123906, + -0.02951271539882705, + 0.18974105429436894, + -0.04453024476617773, + -0.009925147481549823, + -0.00030393611139989396, + 0.14241798234569658, + 0.3032198986649437, + -0.12090040162684712, + -0.10198666533204936, + -0.19400560807974965, + 0.02792953569577561, + 0.17398878828712339, + -0.0873347551679664, + -0.16521546421171807, + 0.15879528452474156, + -0.12884096066173734, + 0.1016672232325122, + -0.03536934248717438, + 0.22881961947349483, + -0.0557587504084911, + 0.18566001109099872, + 0.03676485444191968, + -0.13118025456028026, + 0.02259871537134872, + 0.029411781719150598, + 0.020001962503907178, + 0.09312352133481405, + 0.29447086823856605, + -0.05109355712787522, + 0.08509014857085306, + 0.0013147096679604342, + 0.012760393211193266, + -0.23376039281333127, + -0.011737749797011032, + -0.08335751580251682, + -0.017511835538311926, + 0.09718876615643302, + 0.09568890629498816, + 0.01215807415636605, + 0.1005279503687928, + 0.1866906339548322, + -0.09008763290476085, + -0.003527358685923687, + 0.056764455209855846, + 0.08152105972819279, + -0.09426593671544503, + 0.04602472318580375, + -0.1862074557581006, + 0.09667422232657441, + -0.06541330916318877 + ], + "mean_abs": 0.09679462665029108, + "sd_abs": 0.07538092293565783, + "realized_sigma": 0.12245268660006814, + "shared_noise_variance_share": 0.8053774807879254, + "tolerance": 0.398 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.398, + "upper": 0.892, + "minimum_detectable_gap_80": 0.9949259007747009, + "faithful_pass_probability": 0.9994256477510173, + "real_gate_holdouts": { + "estimate": -2.291135781796967, + "gap_from_epuf": 0.39531663908489234, + "lower": -0.398, + "upper": 0.892, + "pass": true + } + }, + "q_atmax.women.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.042625292841566825, + "epuf_sampling_sd": 0.0106813680069294, + "psid_value": 0.050342939872192335, + "psid_n": 3457, + "bridge_psid_minus_epuf": 0.16641058256012942, + "min_events": 4, + "floor": { + "replicates": [ + -0.24697741336864754, + 0.07840244916805661, + -0.05051952119093217, + 0.3336897977383302, + 0.01629802275268144, + 0.39991987136860296, + 0.10023937171785025, + -0.1662610989742701, + 0.11004613744479164, + 0.2279930391915883, + -0.02348072514037236, + 0.20076389847303444, + -0.36445311675351477, + 0.14230822817734512, + -0.148561599367117, + 0.04168695085310348, + -0.29435663277462165, + 0.032437520223510985, + 0.0954442729552496, + 0.24293608875447203, + 0.02435807487220143, + 0.20758988456581262, + 0.08946481283818275, + -0.05002974648923142, + 0.0035219465816311857, + 0.14517715161064704, + -0.08708113282368513, + 0.2520526603928954, + 0.15625920847864183, + 0.1914053751460063, + -0.05246212247915438, + -0.1194138519298733, + 0.20977465523046268, + -0.11132399361063827, + -0.16341926649983396, + -0.12050217967950605, + 0.14245898185219152, + -0.13712221301413874, + 0.193398157739892, + -0.09636685298622227, + -0.23456019888853907, + 0.1456817942293791, + -0.011384915050290934, + 0.38062387405535425, + -0.14651837071218243, + -0.2852669840767861, + -0.2797150239631785, + -0.23433934507725684, + -0.25202105983224365, + -0.17097724217701993, + 0.07292826052193879, + -0.22469317682557333, + 0.28018542153802883, + -0.0880734858888852, + 0.1353825899798915, + -0.2645796173661803, + 0.07383650580043599, + -0.24963730510186055, + 0.31450668803996296, + 0.11804316115845404, + 0.048058791894396435, + 0.15955612980580347, + 0.021690585045167632, + 0.18866532235889855, + 0.23120711503051994, + -0.035698477750898405, + -0.0037050289090336808, + 0.20651014686664126, + -0.014271904325657392, + -0.08411700206020423, + 0.06998430900671071, + -0.12469859244790427, + -0.04568538870201522, + 0.09634311187977973, + 0.15673035321387707, + 0.3066637472754292, + 0.31080007927645137, + -0.0030346531783256303, + 0.11189725701081499, + 0.16101854267262095, + -0.0710199497712034, + 0.104539186097109, + -0.007483922893344097, + 0.05608103555522015, + 0.15011498363719622, + -0.2590680124082967, + -0.27153376643937577, + -0.2345907447752269, + -0.06187230871318472, + 0.1314101420293765, + -0.06992698346963033, + 0.014887670187174074, + -0.12764546140662691, + -0.1646387254854338, + 0.20287472270679174, + -0.18967957728675233, + 0.05908013621003749, + -0.1328629825851224, + -0.11757993056897087, + -0.018626202363764444 + ], + "mean_abs": 0.14658766028793369, + "sd_abs": 0.0958910782206569, + "realized_sigma": 0.1749030875719111, + "shared_noise_variance_share": 0.9012734854997293, + "tolerance": 0.53 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.53, + "upper": 0.697, + "minimum_detectable_gap_80": 0.8436127348781127, + "faithful_pass_probability": 0.9987575921522331, + "real_gate_holdouts": { + "estimate": -3.0714377092740093, + "gap_from_epuf": 0.08386976394466039, + "lower": -0.53, + "upper": 0.697, + "pass": true + } + }, + "q_atmax.women.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.039300565125599984, + "epuf_sampling_sd": 0.009414582319136047, + "psid_value": 0.03892013301304321, + "psid_n": 4193, + "bridge_psid_minus_epuf": -0.009727223644806493, + "min_events": 4, + "floor": { + "replicates": [ + -0.5102752364735845, + -0.31016449839892846, + 0.19362111652266112, + -0.09435974655845669, + 0.24763541023352276, + -0.5335033430979987, + 0.12793013592400304, + -0.2913470315108686, + 0.16096648928414137, + -0.1480908365064324, + -0.15922996482339125, + 0.3561974704372113, + 0.04681767946440929, + -0.11043923043093451, + -0.4107328576477447, + 0.1303182657757973, + -0.17290711941359027, + 0.011336334122923564, + 0.19684371830232728, + 0.09688897446393363, + 0.04889199546739542, + 0.16321871951441924, + 0.02492867285079492, + -0.3618710741555653, + 0.09633711255991484, + 0.0850234589659391, + 0.015932456867683076, + -0.016487166199486314, + 0.006877924885762221, + -0.29493630499609313, + 0.2191816877606365, + 0.14021444974850605, + 0.15892520311204117, + -0.20038773075851402, + 0.05116237355961184, + 0.04468987289026183, + 0.3577781597309073, + -0.0003893564539905192, + -0.27547439350246417, + -0.030643309783154438, + -0.08965536030281318, + -0.10654517961665144, + 0.06353127287796956, + 0.17509348992315776, + -0.11323338210334044, + 0.11440058831622157, + 0.325335461183317, + 0.07270735245818538, + -0.0718248475975023, + -0.13854913228529453, + 0.0886327951579986, + 0.22883357285625938, + -0.2688324278799057, + -0.010548035260904198, + 0.1107827486759203, + 0.25335596474807454, + 0.11804559572809348, + -0.08823237039179421, + 0.1803702531853264, + -0.24016756986893162, + 0.12341555224950307, + -0.12472408698953052, + -0.13232957624472452, + 0.07960369113643018, + 0.016687429916489194, + 0.542500619742101, + 0.1976181366017873, + 0.22374049884639424, + -0.07877632479196683, + 0.5757580688678512, + 0.3828739535733474, + 0.4972872013031344, + 0.18593609044187565, + 0.1979230169285573, + -0.029530806763148343, + -0.14388282537820496, + 0.13856378711975736, + -0.10719319338716149, + -0.10545029649044335, + 0.22129985653351625, + -0.0636914864319198, + -0.09873937469096972, + 0.07306073994877194, + -0.33117714636401696, + -0.007444029590011558, + -0.39274608394678157, + 0.014732053109613119, + -0.028654671400161424, + -0.14999442594660461, + 0.18563982071125817, + 0.018868034921167842, + 0.014370648460311886, + -0.08110042494358094, + 0.24378510538693243, + -0.20822466227100866, + 0.21095674947692178, + 0.04628527779702951, + 0.13412832793128926, + -0.3101943324298324, + -0.7153797522583007 + ], + "mean_abs": 0.17195902444896075, + "sd_abs": 0.1419525410166041, + "realized_sigma": 0.2225284807648186, + "shared_noise_variance_share": 0.7468244272493322, + "tolerance": 0.74 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.75, + "upper": 0.74, + "minimum_detectable_gap_80": 0.9370119181311997, + "faithful_pass_probability": 0.9991834749723999, + "real_gate_holdouts": { + "estimate": -3.1970814987997955, + "gap_from_epuf": 0.0394348816242549, + "lower": -0.75, + "upper": 0.74, + "pass": true + } + }, + "q_atmax.women.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.025319243779007263, + "epuf_sampling_sd": 0.012871210974672668, + "psid_value": 0.027666318315116692, + "psid_n": 3099, + "bridge_psid_minus_epuf": 0.08865099774727714, + "min_events": 0, + "floor": { + "replicates": [ + 0.08166504591439261, + 0.01624933396642625, + -0.34284130842490046, + 0.7407080002105417, + 0.19875752722605555, + 0.20391204137799934, + -0.2430689316230965, + -0.0694133492209228, + 0.1800655127183508, + 0.1395151005813453, + -0.18453178907940182, + -0.5417905439327557, + 0.008846078809492175, + -0.38111138676691936, + 0.09352511695140664, + -0.4881707985526844, + -0.018722210232279934, + 0.07414433254210495, + 0.34290516937620974, + -0.0921789951107368, + 0.08167726249573803, + -0.05029377279518821, + -0.26948437106873846, + 0.4126512511850995, + 0.2060779977583196, + -0.11158494011500975, + -0.07847322066077189, + -0.13165154667954715, + -0.2530376564416785, + 0.16223644748598987, + 0.33563427602344675, + -0.29530360994964555, + 0.24430754010813693, + 0.10650328861463332, + -0.5290007814328344, + 0.03793913224626322, + -0.489331351562025, + -0.1439793197771777, + -0.10136255047666065, + -0.29706367864029004, + -0.13606327674793572, + -0.34691850593719575, + -0.09607525966776231, + 0.3644038001279759, + 0.26530544117288013, + -0.4296779254444911, + -0.13467708314134597, + -0.2996304773379488, + 0.03627787276409267, + -0.11804583569885985, + -0.05366862435799469, + 0.27218661069090033, + -0.040054994303141855, + -0.2765850868114159, + 0.12455697379572706, + 0.2779234673378048, + 0.28746499281819893, + 0.16395689520188417, + 0.004095727739597876, + 0.081043581629896, + -0.04249224569078103, + -0.2653920489920114, + 0.169461380526033, + 0.05906073729993566, + -0.03654041560287746, + 0.1353190989715498, + 0.18773163147387972, + 0.01733139394359351, + -0.16331737362529752, + -0.1932125854919855, + 0.2391030416287656, + -0.21234788382686087, + -0.3693728107442098, + 0.4220036737339399, + 0.018136041200808473, + 0.2234114519019863, + 0.07996282220244155, + -0.13188990659209732, + -0.2010300267986187, + 0.010921242475511184, + 0.18370510784057914, + -0.09042680481588095, + -0.12963554656327614, + 0.2986441009621481, + 0.13161071391471335, + 0.13681295946006888, + 0.15715708823046892, + 0.13512338444592342, + 0.22091681736835977, + -0.22290122277325009, + 0.1831429804550544, + 0.004639538215635897, + 0.034337866272266204, + 0.1477625150072872, + 0.059887517538184776, + 0.06800237772685302, + 0.015467582832888738, + 0.19163838847936798, + 0.3571474188661772, + 0.2173814738540567 + ], + "mean_abs": 0.18752708219207892, + "sd_abs": 0.1391503147494659, + "realized_sigma": 0.23309995398841543, + "shared_noise_variance_share": 0.8124685997245343, + "tolerance": 0.744 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.744, + "upper": 0.833, + "minimum_detectable_gap_80": 1.0288328685687969, + "faithful_pass_probability": 0.9991195408535404, + "real_gate_holdouts": { + "estimate": -3.6555248535496436, + "gap_from_epuf": 0.020665695150428487, + "lower": -0.744, + "upper": 0.833, + "pass": true + } + }, + "mpers.men.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.7825482702139276, + "epuf_sampling_sd": 0.003686401622664722, + "psid_value": 0.7501136516287285, + "psid_n": 155, + "bridge_psid_minus_epuf": -0.04233087713109862, + "min_events": 1, + "floor": { + "replicates": [ + 0.02366844521696393, + -0.04729073036875929, + 0.00020006975318637155, + 0.07210972372592535, + 0.04759705127104431, + -0.037717844076595536, + -0.036197761536218384, + -0.07678730524197695, + -0.02289237809451289, + 0.014206070896703255, + -0.09263366656103542, + 0.013751400476771147, + 0.045372704654683196, + -0.16472922401709622, + 0.028290773897475877, + 0.032672235220362555, + 0.05619046632360908, + -0.06337356901487366, + 0.0897476750021106, + 0.0290531910575981, + -0.013849619021810394, + -0.01926091207139599, + -0.047380657938624116, + -0.042827025781182165, + -0.06297485756640599, + -0.021507807514758337, + 0.06627676853893602, + -0.08377717489751996, + 0.029367561487031138, + 0.09254203590283779, + 0.041638684369397536, + -0.09290754921240428, + 0.05048507235783875, + 0.016717738759345152, + 0.04529236714649182, + 0.06453189393350198, + 0.15362989004106958, + -0.023861712656494755, + 0.0044237965173125615, + -0.0025727793639886143, + 0.026921821060059387, + 0.00440961455135061, + 0.13495718071117638, + 0.00790165518279437, + -0.048935514606838926, + -0.06308153551107917, + -0.002914109348047894, + 0.04771617176566191, + -0.024634063509057086, + 0.09163176752384503, + 0.011677009358410984, + 0.00015435282766726455, + 0.0018507431742127434, + -0.06328730950168784, + -0.014321440859930507, + -0.013492079101245336, + -0.05187183302351829, + 0.024188581295744, + 0.033439158937681054, + -0.01531545598424744, + 0.08226413571214611, + -0.09482537669150712, + -0.04636649134718021, + -0.07245332985292172, + -0.08027574058580379, + -0.05749978347955678, + 0.08177918710599787, + 0.0445820423529498, + 0.04972798972338599, + -0.044662576183377045, + 0.034420219538837366, + -0.08166012079302276, + 0.046556068923004845, + 0.0007608238467774198, + -0.019906377261165037, + 0.14265527906141826, + 0.02483202836327253, + -0.08779447423926859, + -0.019701209833739214, + -0.022116070721169445, + -0.11673914707308697, + 0.12299623225820619, + 0.06499810469341238, + -0.037322674566365996, + 0.028810033108506675, + -0.07532290409352449, + 0.11157843258482272, + -0.14292366106217974, + -0.04133669649783819, + 0.08804975280797017, + -0.0027813479390983997, + 0.04144661049012699, + -0.0558321451699343, + 0.027277033926300792, + -0.07982309270990529, + -0.08622063808966987, + 0.05139433673415905, + 0.022634333783161653, + -0.0070141560977058925, + -0.006296299038986292 + ], + "mean_abs": 0.0499864654766157, + "sd_abs": 0.03718480373002108, + "realized_sigma": 0.06218946263637177, + "shared_noise_variance_share": 0.7634506044898333, + "tolerance": 0.199 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.242, + "upper": 0.199, + "minimum_detectable_gap_80": 0.2936708493903585, + "faithful_pass_probability": 0.9992857388994426, + "real_gate_holdouts": { + "estimate": -0.28178872786078496, + "gap_from_epuf": -0.03658905656472905, + "lower": -0.242, + "upper": 0.199, + "pass": true + } + }, + "mpers.men.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.6662268006129747, + "epuf_sampling_sd": 0.004684632307432884, + "psid_value": 0.6599305131181035, + "psid_n": 136, + "bridge_psid_minus_epuf": -0.00949560770680724, + "min_events": 0, + "floor": { + "replicates": [ + 0.020253565942949164, + -0.014823423923427587, + 0.00533681559340396, + 0.05749498441989517, + 0.12574320810138195, + -0.04863380326159175, + -0.10871539104728212, + 0.05862400387063613, + -0.14946772460290864, + 0.018962098902648467, + -0.18083434072944046, + 0.05359270830107049, + 0.002078359517724726, + -0.011985658795294979, + 0.13497186886114523, + 0.009638313366686663, + -0.1037753712392015, + -0.03592331849086097, + 0.16477058040669593, + 0.001229763901411829, + -0.08188654999492859, + 0.1353706711811816, + 0.15250279399365355, + 0.06593798587205954, + -0.01452927927508238, + 0.07770309313951954, + 0.03145055348331774, + -1.1903201559387844e-05, + 0.02521291456464031, + -0.05292026155159693, + 0.04152261153137696, + 0.049944192543470545, + 0.0975935464824732, + -0.03123971858884636, + 0.0755403517561869, + 0.035460039462859916, + 0.0077928169323561725, + 0.01660315609452595, + 0.10192197311107618, + 0.1150581122673548, + 0.03483375557946353, + 0.1779285555354051, + -0.12244186316238054, + 0.0022561106332339154, + -0.1067954826208643, + -0.07919717589511968, + -0.029399937718480512, + 0.04611660216017102, + -0.03567738543937801, + 0.010763288272410687, + -0.07933919783137727, + -0.06396245697108582, + 0.037476710035576205, + -0.15520108135276856, + 0.13030643923160046, + -0.0019890787504318885, + -0.052065115902687475, + 0.12453169555165955, + -0.020471955844751893, + 0.08446742791201264, + -0.015608291818566322, + 0.06398790552649097, + -0.05530853620765269, + -0.03835895173541912, + 0.002892880549403981, + 0.04870147850023379, + -0.012922841399911122, + -0.05723355040739864, + 0.05478550641353758, + 0.016072132794438365, + 0.11702543871181625, + -0.021846606355395565, + -0.030869778650605834, + -0.02233940666583628, + 0.10614265615284438, + 0.017791742840970598, + -0.018250450152391906, + 0.038555075598661004, + 0.006280932692734692, + -0.10904096025523335, + -0.11644087075847653, + 0.07009812108030278, + 0.0749433808331258, + 0.0458820486458435, + 0.08997668681372603, + -0.07048102822734112, + -0.04623571701403245, + -0.023430850869819303, + 0.09177002729575373, + -0.045319543937190676, + -0.10407022047615122, + 0.05930786497372659, + -0.01998943135302031, + -0.11251677686936659, + -0.08131842949984502, + -0.11916247792760959, + 0.03919487783438089, + -0.18137529430920388, + -0.07751380847417885, + 0.026801532145960677 + ], + "mean_abs": 0.0626212325747318, + "sd_abs": 0.04707824062117016, + "realized_sigma": 0.07820240342702775, + "shared_noise_variance_share": 0.6009172983358492, + "tolerance": 0.251 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.261, + "upper": 0.251, + "minimum_detectable_gap_80": 0.326312410947429, + "faithful_pass_probability": 0.9989175986284126, + "real_gate_holdouts": { + "estimate": -0.39933093324817287, + "gap_from_epuf": 0.006794191703734742, + "lower": -0.261, + "upper": 0.251, + "pass": true + } + }, + "mpers.men.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.33371769653394834, + "epuf_sampling_sd": 0.014181248352802643, + "psid_value": 0.4279673072793644, + "psid_n": 70, + "bridge_psid_minus_epuf": 0.24875139218435527, + "min_events": 0, + "floor": { + "replicates": [ + 0.05056517893595791, + 0.10013725324718525, + 0.05650582609171406, + -0.39913928391921477, + 0.0643538605598234, + -0.0618714884055917, + 0.07455457401465537, + 0.0166827773160399, + 0.021294361935660755, + -0.19778388680197434, + -0.055868017603994014, + 0.10759594257335064, + -0.10633347525291381, + 0.15626987081922544, + -0.06931606322011757, + -0.016032034034211884, + -0.3060609135548298, + -0.20601163993128235, + 0.3324035252750533, + -0.045636067943886915, + 2.8848652273094633e-05, + 0.019702656002753782, + -0.19816747907905202, + 0.03344106179719614, + 0.13824512158859387, + 0.01927146205476149, + -0.17283040209314016, + -0.1556852564256035, + -0.2076623976869722, + -0.19008212359671683, + 0.0053326187658043755, + 0.006300123065727803, + 0.21792947972604315, + -0.019645566655051627, + -0.02201215466326284, + -0.1084806058303151, + 0.34216380355432324, + -0.07008753400209433, + 0.34001168819414596, + 0.15786069034455374, + -0.22099893296384376, + 0.12129486319726746, + -0.2035929830433768, + 0.29256464222395784, + -0.02188662647689632, + 0.07739877475651386, + 0.1511723202156125, + 0.1098561980617685, + -0.007329039853004926, + 0.1822418305814445, + -0.08662919604217151, + -0.048145811887065404, + 0.022217741862406104, + -0.30250222827404855, + 0.20316890543284755, + 0.21923487821555626, + 0.2844607997890592, + 0.009076920977804603, + -0.06089625904595225, + -0.06707802595276191, + -0.5364600856730649, + -0.06096566236286416, + 0.06722095561317604, + 0.17252751313793435, + -0.07460271627413417, + -0.19901819705719326, + 0.1023230431273559, + -0.13045882312939222, + -0.014829887082567272, + -0.43814889490576947, + 0.16633940361021238, + -0.04358368694073672, + -0.14073193171895337, + 0.030318926027152804, + 0.30740316310942256, + 0.012447267419427921, + 0.05944701040962491, + 0.11698348821356591, + -0.35762688467307313, + -0.05873565052865648, + -0.013736030201093818, + -0.028947574030545875, + 0.0015275852600315498, + -0.3429547536966415, + -0.2963763925908002, + -0.28224460319156164, + 0.22382128943513557, + 0.16681224705868752, + -0.17921556940404215, + -0.08289938563931054, + 0.2561383364002395, + -0.037984222715950144, + 0.13328837771656, + -0.017632539423700855, + 0.048497799374474126, + -0.1107506591296975, + -0.14639755494374396, + 0.35607839293191873, + 0.15549501649803155, + -0.13110387908754717 + ], + "mean_abs": 0.1366317949381242, + "sd_abs": 0.11478306965038826, + "realized_sigma": 0.17807764861317057, + "shared_noise_variance_share": 0.7458895636431065, + "tolerance": 0.596 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.596, + "upper": 0.845, + "minimum_detectable_gap_80": 0.9946253224819358, + "faithful_pass_probability": 0.9995923338005119, + "real_gate_holdouts": { + "estimate": -0.8934940703027577, + "gap_from_epuf": 0.20396579306070806, + "lower": -0.596, + "upper": 0.845, + "pass": true + } + }, + "mpers.women.c0": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.6293929712460063, + "epuf_sampling_sd": 0.011046973203030577, + "psid_value": 0.7217471079262044, + "psid_n": 38, + "bridge_psid_minus_epuf": 0.13691899432519222, + "min_events": 0, + "floor": { + "replicates": [ + -0.14151666071075933, + 0.029569239126633895, + 0.15348510880068883, + 0.09914618793149624, + -0.16517751114170454, + 0.1695369939821576, + -0.04618313336836985, + -0.03555924257491508, + 0.028941397234955923, + 0.11188403224695659, + -0.0367820437143368, + 0.0006843820816516688, + 0.08626204971327595, + 0.22589367667987545, + -0.01829323785788403, + 0.07396098512903651, + -0.0665289815913287, + -0.2121706933190832, + 0.15231132810311598, + -0.07118809075413982, + 0.11505540946288761, + 0.14918920809545855, + 0.03249114283209334, + -0.1526456075807696, + 0.02485830248089621, + 0.0885580985378982, + -0.0258983627111804, + 0.19472537496534975, + -0.16178846826070017, + -0.06705038572312816, + -0.10212102594271005, + 0.033184348496232696, + 0.30397749128982243, + -0.04232419820252961, + -0.08948754830362435, + 0.05620891937052322, + -0.003556332473639068, + -0.14227541261696303, + -0.13705907009871546, + 0.016940448903943833, + 0.055337378619030986, + -0.08072129158749669, + -0.07329551083772767, + 0.1263233041765977, + -0.09441749829629553, + -0.23591683761217846, + -0.030032307160317573, + -0.16731047211423872, + -0.06889132687606231, + -0.016478708987741564, + 0.1156440749848516, + -0.16051874748262915, + -0.05642604666376638, + -0.01019916445649674, + 0.16347179124825084, + 0.005508518633712156, + 0.15741709825564157, + -0.033874875771541774, + 0.09392003099728571, + -0.07328371421076418, + 0.13314252498194262, + 0.054194424906284094, + 0.11680559836143967, + 0.11509784958432223, + -0.026398264692355733, + -0.11279526686786427, + -0.10045442570922919, + 0.16499715807492446, + -0.2830731844884389, + -0.37354789453115983, + -0.058434444410880915, + -0.26816731242295117, + 0.13135716042521026, + 0.05458453034816255, + 0.11446069312162094, + 0.011483686090387357, + -0.12237165704944653, + 0.21343337771120835, + -0.050617218999446906, + -0.08639448231784799, + -0.06093114520234014, + -0.11191409600589357, + -0.2635492794089256, + -0.15312765818379115, + -0.12794758705271483, + -0.09697886232817332, + -0.06363843132966508, + -0.035196045112727836, + -0.06886051387099648, + 0.1930459271779255, + -0.07501721355480656, + -0.12034059032453714, + 0.08479074863984029, + -0.206671898003019, + -0.01013962730454529, + -0.19992523467877432, + 0.1024601262125203, + -0.06129832564934344, + -0.24359554348896295, + 0.09696599043807973 + ], + "mean_abs": 0.10651664830446764, + "sd_abs": 0.07391735574872596, + "realized_sigma": 0.1294408517126356, + "shared_noise_variance_share": 0.6549111381255552, + "tolerance": 0.402 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.402, + "upper": 0.539, + "minimum_detectable_gap_80": 0.6478591636183093, + "faithful_pass_probability": 0.9990370758788346, + "real_gate_holdouts": { + "estimate": -0.3251898583203061, + "gap_from_epuf": 0.13780960348185867, + "lower": -0.402, + "upper": 0.539, + "pass": true + } + }, + "mpers.women.c1": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.5392099056603774, + "epuf_sampling_sd": 0.012279417447860763, + "psid_value": 0.604826438632865, + "psid_n": 31, + "bridge_psid_minus_epuf": 0.11483660811939811, + "min_events": 0, + "floor": { + "replicates": [ + -0.7757517542092003, + -0.04371033872563998, + 0.006484845261138655, + 0.01004956389097425, + 0.26905313234245154, + -0.15397597722882816, + -0.17413695333797283, + -0.1975416447138753, + 0.5448173424210032, + -0.20013891048502688, + -0.0070129028309945385, + -0.2847451696120023, + -0.21155644761441902, + 0.17252748713512508, + 0.05461188919998519, + -0.2726559236324943, + -0.12048179928196937, + 0.41019630542182905, + 0.1402028206392107, + -0.11936353509218062, + -0.15604609286558735, + 0.19094115628502872, + 0.08347743573632493, + -0.33033302880306376, + -0.19823955771554647, + -0.39970344634456184, + -0.17887303412860564, + 0.267803882831321, + -0.06175534492849932, + 0.1252949410507285, + 0.06398245952189952, + -0.229080979581298, + -0.07149447208602919, + -0.1194508560336045, + 0.27234825384386124, + -0.08440553538665274, + 0.27207658792952955, + 0.07200989959524506, + 0.010582081378734759, + -0.23462656626740558, + -0.02634477654238973, + -0.380155876844039, + 0.2151865600572441, + 0.10280646211807073, + -0.1826866677411226, + 0.06286782839584718, + -0.050287196575101695, + 0.3800294934691151, + 0.17574832213382707, + 0.022168990365739716, + -0.26157648223716556, + 0.16172960602131994, + 0.06603635236065611, + -0.1885944467486351, + -0.015404954125387477, + -0.1132004682506337, + 0.3783931543601788, + -0.3377640633857202, + -0.2628995248397417, + 0.06214652777667684, + -0.12638045666905795, + 0.13933466754592344, + -0.0509580883373455, + -0.13169317708168532, + -0.30139894417831264, + 0.14760496986563568, + -0.04469607899335068, + -0.019751113889573457, + 0.16622339701895014, + -0.04755351759216003, + 0.15485487350766347, + 0.1864346532474565, + -0.1286708268710394, + 0.0904856401639004, + 0.19682863007749324, + 0.2601079150402822, + -0.22810120808943285, + -0.17427817605485257, + -0.13038677633771897, + -0.013376634220786943, + -0.029462415013100984, + -0.13824899833069107, + -0.16696088019538805, + -0.2192590732284345, + 0.06538197837035636, + -0.19690696592694554, + 0.10789184006684349, + -0.14647347544817949, + 0.021536215170427864, + -0.14245984548059623, + -0.032798183595845326, + 0.02071549642392334, + 0.03526451925887489, + -0.22137530250453238, + 0.10702687911680978, + 0.4321614332908081, + 0.12242244412980682, + 0.20998393376735697, + 0.08420314840380652, + -0.005885561495131225 + ], + "mean_abs": 0.1628310644373894, + "sd_abs": 0.12671027351555664, + "realized_sigma": 0.20593419829172754, + "shared_noise_variance_share": 0.8437671648805732, + "tolerance": 0.67 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.67, + "upper": 0.785, + "minimum_detectable_gap_80": 0.9581552021205311, + "faithful_pass_probability": 0.9993623849776376, + "real_gate_holdouts": { + "estimate": -0.5505793013167559, + "gap_from_epuf": 0.06707104720417201, + "lower": -0.67, + "upper": 0.785, + "pass": true + } + }, + "mpers.women.c2": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.264336542486396, + "epuf_sampling_sd": 0.02862049424031705, + "psid_value": 0.22110258180986492, + "psid_n": 24, + "bridge_psid_minus_epuf": -0.17859630853783282, + "min_events": 0, + "floor": { + "replicates": [ + -0.8209305197648629, + 0.3852810623558961, + null, + null, + -0.2169001632372567, + 0.5805317915535866, + -0.6646614586899067, + 0.12882743941176533, + 0.03841560865285498, + 0.9820424963005379, + 0.15570301016941224, + -0.697179283272433, + 0.23631025857673693, + -1.159092707813549, + -0.11941478289078322, + -0.6074170146389863, + 0.6669444446563726, + 0.5695878723602353, + 0.1582153977395876, + -0.5265044581979729, + 0.2238496402486545, + 0.21273981279051968, + 0.12641360573606952, + 0.3076902912048698, + 0.7514106310882548, + -1.602559861610047, + -1.0252882356851567, + -0.5957408629174854, + -0.35787434431302456, + 1.2173221674836476, + null, + 0.1157554550281179, + null, + -0.3752462976062064, + null, + 0.07870348502878044, + 0.08312364971210295, + null, + 0.17348546999681058, + -0.9798745923874248, + 0.02495700898583164, + 0.22824911612969456, + 0.6291907730840782, + -0.5354157430331361, + null, + null, + null, + -0.09638480461139676, + 0.20536827767187849, + 0.11356325353638541, + -0.35327901911163695, + 0.5501699180232433, + 0.015474873054100446, + -0.2908009574150062, + -0.2523596044414903, + null, + -0.4103099667624358, + 0.007067633027929454, + -0.13420834854359154, + -0.1099536056621494, + -0.3202155264290566, + 0.24111604303143408, + 0.5778832931953334, + -0.048804843797585096, + 0.5626693288217296, + -0.8945915138681562, + null, + -0.3865613025761089, + null, + -0.491230576060684, + 0.07708895922186132, + null, + 0.4598088262677642, + 0.30140666589561305, + -0.46333730304086773, + -0.5224149246796168, + -0.2073262073742893, + -0.13804455716081354, + -0.29071029355679523, + 0.02709908203030509, + null, + 0.4935718457401631, + -0.6763771378164388, + -0.6978503127726994, + 0.2504180613710951, + 0.7054034200801091, + -0.4117837183851891, + 0.1948494765621952, + -0.3061650462019492, + -0.21632649045964936, + 0.1950856520204728, + 0.038125579815583954, + 0.6290036872388993, + 0.3308111869424537, + -0.9535578586626708, + 0.19588451626019499, + 0.037402589037917044, + 0.3298289268692397, + -0.28528777208584144, + -0.17039292936190376 + ], + "mean_abs": null, + "sd_abs": null, + "realized_sigma": null, + "shared_noise_variance_share": null, + "tolerance": null + }, + "eligibility": "undefined_on_some_split", + "gated": false, + "report_reason": "undefined_on_some_split" + }, + "r6.men": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.7108651036878303, + "epuf_sampling_sd": 0.0011090717968760824, + "psid_value": 0.6680476050375935, + "psid_n": 2182, + "bridge_psid_minus_epuf": -0.04281749865023676, + "min_events": 368, + "floor": { + "replicates": [ + 0.00904565239261762, + 0.009429566964626046, + -0.032891899664422575, + -0.0034852763035942425, + 0.02432246358346024, + 0.00039047955307341953, + 0.0168595855204402, + -0.013210242603140854, + -0.03495514482419826, + 0.01521199404366741, + -0.028332923598764326, + 0.027136870572710525, + -0.005247127425117071, + 0.0009125548939920569, + 0.001462415470445011, + -0.022151360594827474, + -0.02607336488753026, + 0.007621978578519706, + 0.003949665550393888, + 0.0046476843083201325, + 0.014105893941755543, + -0.028673538530266773, + -0.017871809488757273, + -0.027424884959471152, + 0.03109918323891675, + 0.057960733095348216, + -0.011042511194830573, + -0.036189386882443386, + -0.009949200453736817, + 0.015231920786124675, + -0.0013154620022582386, + -0.005259609094518725, + 0.01155823582498594, + 0.009109533089254773, + 0.020678478651348087, + 0.018934377265644897, + 0.02264845453409542, + -0.019444703001946062, + 0.019377135291054726, + 0.007612585845815589, + -0.005815359103128359, + 0.002425316960315671, + 0.00023847424232714687, + -0.03365565963553513, + -0.04770576700391144, + 0.013276363435384686, + 0.029902697050783522, + -0.0019797751171167777, + -0.0473278602068401, + -0.013200160422078444, + 0.014693869065393494, + 0.02205412852148808, + 0.011820038319272308, + -0.03536258689514732, + 0.013202371289536663, + 0.008685306601785014, + -0.0027641498562477884, + 0.006951042436880384, + -0.019406578678989317, + 0.021933214980298932, + -0.0024312132882687854, + -0.006641773480372981, + 0.012457304309077877, + -0.05848484736624049, + -0.06282055981788681, + -0.0015150976450074571, + 0.026939239493287748, + -0.005814303282348998, + -0.021763907085683876, + -0.04035090060208252, + 0.026869941067313996, + -0.0063728859409129535, + -0.03108566973827609, + -0.02269868670487868, + 0.021344576254570036, + 0.029987327669021346, + 0.0064138975271971765, + -0.04841680057156439, + -0.023036803765420055, + -0.029737311388775833, + -0.027363210358241852, + -0.02471271777062467, + 0.008545140115507499, + 0.001519980635007967, + -0.03673743288093406, + -0.0145436908154441, + 0.0381346296227405, + -0.05245197405843932, + -0.019669137021640082, + 0.011327956984621745, + -0.012679346333429709, + -0.020051979818450194, + -0.012257787473452186, + 0.022138878113264426, + -0.02277327408793245, + -0.05110762303618693, + 0.03573677201252767, + 0.0446712723705186, + -0.0026615121649960494, + 0.012313891324202408 + ], + "mean_abs": 0.01981807862325246, + "sd_abs": 0.01469434082238032, + "realized_sigma": 0.024627640081819575, + "shared_noise_variance_share": 0.7755618412060957, + "tolerance": 0.079 + }, + "eligibility": "eligible", + "gated": true, + "lower": -0.122, + "upper": 0.079, + "minimum_detectable_gap_80": 0.1425446434758875, + "faithful_pass_probability": 0.9993478271525766, + "real_gate_holdouts": { + "estimate": 0.6670465436202722, + "gap_from_epuf": -0.04381856006755813, + "lower": -0.122, + "upper": 0.079, + "pass": true + } + }, + "r6.women": { + "metric": "abs_gap", + "cap": 0.15, + "epuf_value": 0.672102564061898, + "epuf_sampling_sd": 0.0011744622407952785, + "psid_value": 0.6397841177680634, + "psid_n": 2376, + "bridge_psid_minus_epuf": -0.03231844629383451, + "min_events": 407, + "floor": { + "replicates": [ + 0.02227054585848226, + -0.019419397981280506, + 0.001491078417704239, + -0.02313476000435749, + 0.016037654418244895, + -0.0025165439540020262, + -0.023607622712945198, + -0.009571915003408205, + 0.021607311450517364, + -0.008001881789586274, + -0.023598113687496147, + 0.002746212527779679, + -0.027286402160379086, + 0.029869784403087907, + -0.038705174314428215, + 0.013106274306303678, + 0.014104472327566897, + -0.016771731833654158, + -0.024785175576273577, + -0.0015172408476386567, + -0.002817837336605733, + -0.02622481599899862, + 0.06966715518765298, + -0.0007560246904642631, + 0.013242465001602088, + 0.015335294511754305, + -0.036864090724850584, + -0.002073862096439061, + -0.010188545040874575, + 0.0018771251498829744, + 0.007252636931522005, + 0.047378148413899424, + 0.00010259225506392688, + 0.004599221793279262, + 0.006077123735412138, + -0.009032509473644645, + 0.010500640902328773, + 0.007633493408867986, + -0.029189185604615253, + 0.0237867474451382, + -0.026685822103469647, + 0.03311697848192824, + -0.014949929359090453, + -0.021234238785847792, + 0.01676866999608756, + -0.03666113845201158, + -0.013824693057837456, + -0.031814752337131824, + 0.04963389023603737, + -0.020413438670196793, + -0.022557616563596672, + 0.004633063255148562, + 0.008879848760715292, + -0.030857358387516465, + -0.01401243898610749, + 0.010885789103627364, + -0.045777699183405796, + -0.007260471964211146, + 0.0008286367152950946, + -0.01674299416563596, + -0.019214550807194475, + -0.05514584133738032, + -0.008541599564191482, + 0.011041741050201115, + -0.04074274736064659, + -0.0032906997185565556, + -0.00846494213920379, + -0.018824919223426717, + -0.03959489648134351, + 0.029896501779927753, + 0.02419987308420124, + -0.0003470937808399688, + 0.009165372761480162, + 0.012507395606172311, + -0.008343958120468065, + 0.026145898416475633, + -0.0008025331274396641, + 0.03125801622601937, + -0.030909202468400454, + 0.023033298167017713, + -0.04631564670823857, + -0.018746040020575228, + -0.03696620836901032, + -0.026952722524049677, + 0.04824953468173698, + 0.0524356703532004, + 0.011824930470842931, + 0.03697729125639326, + 0.021987833169318793, + 0.03525749036183207, + -0.004369017469476544, + -0.02629996158072484, + -0.027538685959327402, + -0.010918281102875238, + -0.008797716474889805, + -0.018029359967023872, + -0.003619482965761145, + 0.014448480947730935, + 0.02029773929056422, + 0.04300129352253257 + ], + "mean_abs": 0.02006792746259624, + "sd_abs": 0.014592944093846679, + "realized_sigma": 0.02476986454942573, + "shared_noise_variance_share": 0.731808077498613, + "tolerance": 0.078 + }, + "eligibility": "eligible", + "gated": true, + "lower": -0.111, + "upper": 0.078, + "minimum_detectable_gap_80": 0.1311652902513562, + "faithful_pass_probability": 0.9992504698081728, + "real_gate_holdouts": { + "estimate": 0.6273350404581282, + "gap_from_epuf": -0.04476752360376979, + "lower": -0.111, + "upper": 0.078, + "pass": true + } + }, + "zint.men": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.051096544134419136, + "epuf_sampling_sd": 0.006633082948146222, + "psid_value": 0.049090030186706095, + "psid_n": 2182, + "bridge_psid_minus_epuf": -0.040060902463718406, + "min_events": 9, + "floor": { + "replicates": [ + -0.1401135608506665, + 0.10477379091127492, + 0.05137887584032286, + 0.20218646819539732, + -0.0062143897855735375, + 0.07206415282904399, + -0.21901929597349246, + -0.14967547574753737, + 0.11572859802185764, + -0.12155130349148169, + 0.058424322504289306, + 0.023741561989700566, + 0.010556055826274502, + 0.10782706628240235, + -0.09158784321993951, + -0.09114147197655931, + 0.2616340901720373, + 0.001210460672375513, + 0.08583665383066541, + -0.13771601555757096, + 0.061050121507771005, + 0.04781422866928686, + 0.11561871796611367, + -0.026213490498400827, + 0.07133203046324454, + 0.017210998394236565, + 0.13986043349299426, + -0.12664698250690742, + 0.037782189211846395, + 0.1494812565770285, + 0.06982160011215544, + -0.1649966528578941, + -0.012644565980883815, + 0.1480282255041192, + 0.2629664386901951, + 0.11345964136831621, + 0.14182164366568362, + 0.011222364113876448, + -0.04848537709386669, + 0.0460561633266654, + -0.11785104434413518, + -0.05123840571074778, + 0.13809106638165192, + -0.11468952723781056, + 0.20839513195677672, + -0.02865636461877563, + 0.11202858414729255, + 0.1694492982180802, + 0.21800705570015433, + -0.05049238837268555, + -0.07070341782021283, + 0.18056634902138846, + 0.22769752045864267, + -0.05204327731898806, + -0.2911584475940763, + -0.0173162997262597, + 0.024891968356806737, + 0.08877833268624413, + -0.09944807794965582, + -0.15556295420717214, + -0.13584357821182147, + -0.061349687247900686, + 0.04799709597237456, + 0.10011204745158553, + -0.1402627076447045, + -0.07293180459785442, + 0.2820984100004189, + -0.054305655123289664, + -0.09378255250522094, + 0.03575903765999433, + 0.03000039838373758, + -0.03196231507756675, + -0.23360151576093635, + -0.07169141197745632, + 0.11336152126289822, + -0.1634533272666252, + 0.11056179034635916, + 0.11159834093399335, + -0.13458384731412765, + -0.009442250964407872, + -0.19020012579734624, + -0.19605468713273777, + 0.10338151468408063, + 0.16196799012033614, + 0.060379472140769996, + 0.15427133030051987, + 0.059124178875652245, + 0.26792069695253695, + 0.10855344252764354, + -0.02346771855735552, + 0.08790408555451035, + -0.07483073601946688, + 0.08783253286456594, + 0.022928415424576798, + -0.0317416089438205, + -0.07171949393922361, + 0.055174365901295985, + 0.20372391905168996, + 0.0877326612602658, + -0.10706247664572888 + ], + "mean_abs": 0.10472630835904902, + "sd_abs": 0.06908154308488097, + "realized_sigma": 0.12526825879508746, + "shared_noise_variance_share": 0.7678354184999309, + "tolerance": 0.381 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.422, + "upper": 0.381, + "minimum_detectable_gap_80": 0.526489328958371, + "faithful_pass_probability": 0.9984639414144828, + "real_gate_holdouts": { + "estimate": -2.9377920785775298, + "gap_from_epuf": 0.036246334945345904, + "lower": -0.422, + "upper": 0.381, + "pass": true + } + }, + "zint.women": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.06571286762020886, + "epuf_sampling_sd": 0.006096057676295448, + "psid_value": 0.06990943975043597, + "psid_n": 2376, + "bridge_psid_minus_epuf": 0.06190592612052814, + "min_events": 18, + "floor": { + "replicates": [ + 0.000493108261421682, + 0.12552534805002002, + -0.020017171189385063, + 0.2137127567734607, + 0.004076921119741783, + -0.1670766728536719, + -0.022121514383216967, + 0.20378038080399818, + -0.018280284892326915, + 0.029972402634023565, + -0.09326130757375983, + -0.23444506517835073, + 0.07655898427030916, + -0.16469820904950327, + -0.08825274469670452, + 0.0730424654419759, + -0.02147068053969914, + -0.08725130447191698, + 0.022156521690507525, + 0.00829746166570744, + 0.171996741000761, + 0.20100432907605015, + 0.037460216769147126, + 0.026405902426941852, + 0.18606517473167372, + -0.1294071176952929, + 0.043594512827394016, + -0.06923136587434486, + -0.02764311101445549, + 0.09768290056536855, + 0.12445783205144667, + -0.03854194916184972, + -0.12647833792633434, + -0.3008658215710187, + 0.028882977583045255, + -0.22787383254397708, + -0.05949878619450111, + -0.0889106595271425, + 0.16539725093476676, + -0.10246421798318228, + 0.07800339922263144, + 0.026082815066698295, + 0.05562493154323023, + 0.022202849335754005, + -0.028429597716961075, + 0.08381615822314692, + 0.06441825657507794, + -0.054133135075801864, + -0.1166337463942353, + 0.2503236771741437, + 0.048046752606772936, + 0.12866453701842695, + -0.00545060644359574, + 0.11025452437322536, + 0.015367538820078241, + -0.027898488930152343, + -0.09646959769205377, + 0.11931117032744365, + -0.04579154458059609, + -0.13552164115499488, + -0.005461046670309333, + 0.06112241681988495, + 0.033801101145052526, + 0.22091655592153359, + 0.17473370073432526, + -0.12702333522273546, + -0.04588906099436252, + 0.16038495952288612, + -0.015481186934894975, + 0.09277728255694417, + 0.26561480536761284, + 0.14732862363034105, + 0.01173657598543576, + -0.0029201316844742475, + -0.04816039850266529, + 0.11635332660636544, + 0.1365199497442462, + 0.11378469746547037, + 0.10733280285331981, + -0.05016750755918564, + 0.0900516918211891, + -0.05061633640995855, + -0.017387789239716067, + 0.08651775654511873, + 0.10961788895399116, + -0.004089830250778581, + 0.06910392182409453, + 0.05195838731188829, + -0.2696518362416591, + 0.05970194465164802, + 0.09968910893282223, + 0.043520116545386234, + 0.20240355250181774, + 0.08250065780388671, + 0.21430927770782238, + -0.07026296226183537, + -0.02482001321393712, + -0.22225563998796782, + 0.010723175381815775, + -0.07462648605688083 + ], + "mean_abs": 0.09232117150839675, + "sd_abs": 0.07205852410579953, + "realized_sigma": 0.116891852992524, + "shared_noise_variance_share": 0.7837000411229423, + "tolerance": 0.381 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.381, + "upper": 0.443, + "minimum_detectable_gap_80": 0.54128459163072, + "faithful_pass_probability": 0.9993677658267089, + "real_gate_holdouts": { + "estimate": -2.6663061727814648, + "gap_from_epuf": 0.05615434569816369, + "lower": -0.381, + "upper": 0.443, + "pass": true + } + }, + "d_anyzero.men": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.12851247096781818, + "epuf_sampling_sd": 0.003778766947095098, + "psid_value": 0.09730661233243132, + "psid_n": 2300, + "bridge_psid_minus_epuf": -0.27815900488091083, + "min_events": 27, + "floor": { + "replicates": [ + -0.1903283184860194, + 0.13154144772960175, + 0.027172876835814153, + 0.07399663453554606, + 0.12344653164434494, + -0.0566699789110674, + 0.031170948296275647, + 0.04131130969578112, + 0.1347107694041425, + -0.11927017906917681, + 0.041323384438143096, + 0.025103171634741406, + -0.08493002971864239, + 0.05132140456841405, + -0.035587122322730425, + 0.028247620918516736, + 0.15290024120119527, + 0.015060373239285996, + 0.010053448879121518, + -0.0589827602590145, + 0.02289942935363687, + 0.013796524082233086, + 0.131110642093899, + -0.027682311952528904, + 0.05226392066087859, + 0.01582268713787638, + 0.03265465295798342, + -0.1303140518382413, + 0.07745214525078081, + 0.04676833378110401, + 0.00845586272365595, + -0.08279658599606066, + 0.06964140841532518, + 0.15909181739697198, + 0.11431624823211184, + 0.15545456703387317, + 0.20915048208181664, + 0.08786322049871309, + -0.11881871471958472, + 0.11815534086231794, + -0.11775645508903931, + -0.20739235395151034, + 0.10111498016851517, + -0.08983850457859055, + 0.1703356111251042, + 0.003149380068073082, + 0.010531823561399145, + 0.191080408457184, + 0.08893854628716213, + -0.006768654895150217, + -0.1288964674431985, + 0.08626954843260326, + 0.10622564168400461, + 0.03477581956734688, + -0.05661827453301571, + -0.05143487074618469, + 0.008692410650589233, + 0.0803218720457175, + -0.10545660861205497, + -0.0063822800347819175, + -0.16455277032281335, + 0.018859505029153567, + 0.06772626274968907, + 0.05238548632470841, + -0.11868333385134755, + 0.024712769598246087, + 0.092016803551761, + -0.08407225958007225, + -0.012399028923249178, + -0.0689727123294197, + -0.07655912223483385, + -0.1238948822738204, + -0.0687040937825989, + -0.004533970148011601, + 0.0721526608928671, + -0.017223261073371576, + 0.0049042927000042535, + -0.05819289736822353, + -0.09767502290530028, + -0.021867136418182165, + -0.06389964578276053, + 0.07274554374558595, + 0.06766515420466868, + 0.09081999224397186, + -0.00797364793384192, + -0.023425301350769256, + 0.07746505702521866, + 0.12592138788545926, + 0.09263743770847066, + -0.09014919919303943, + 0.17340591014962725, + -0.03465957383314944, + -0.022512819969987108, + -0.020836312410097646, + -0.0005322335163189251, + 0.029583938805666454, + -0.07824567105139746, + 0.11985293756741222, + 0.09332628916633823, + -0.12577759932035826 + ], + "mean_abs": 0.07421141935710207, + "sd_abs": 0.05211059838795353, + "realized_sigma": 0.09053007280844716, + "shared_noise_variance_share": 0.7204441525270843, + "tolerance": 0.283 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.562, + "upper": 0.283, + "minimum_detectable_gap_80": 0.6373510364334019, + "faithful_pass_probability": 0.9991416739993388, + "real_gate_holdouts": { + "estimate": -2.270246471934001, + "gap_from_epuf": -0.21851714291127466, + "lower": -0.562, + "upper": 0.283, + "pass": true + } + }, + "d_anyzero.women": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.1802394517100578, + "epuf_sampling_sd": 0.0031130699318153107, + "psid_value": 0.151093422775978, + "psid_n": 2609, + "bridge_psid_minus_epuf": -0.17638791473670734, + "min_events": 50, + "floor": { + "replicates": [ + 0.010153680097430784, + 0.0395633667127987, + 0.011553761121870787, + 0.14919244916441665, + -0.019898369470837896, + -0.014221332058080849, + -0.01968883583391179, + 0.15960575740005334, + -0.04252088152498923, + 0.026352190289331556, + -0.027995835393252788, + -0.06928748315709121, + 0.05617571766346585, + -0.0011915448620580804, + 0.003960392539886559, + 0.07747570022842665, + 0.051345930695844255, + 0.022319525310938393, + 0.08838634618092334, + -0.009469142300011724, + 0.10663016168996564, + 0.06616203368475482, + 0.051084183343682144, + 0.00264612164192235, + 0.06765209328250488, + 0.00341423824196585, + -0.01964262310548537, + 0.011874159913166205, + -0.043746251599051655, + 0.06452274151670001, + 0.036440374864393554, + -0.04134541721696494, + -0.03544419400657772, + -0.16659498284207408, + 0.021027345452591772, + -0.10756042396295085, + 0.00480142103424408, + -0.047140549194956916, + 0.16095492118366916, + -0.08335543581585825, + -0.03586164346578091, + 0.030635382761802332, + 0.017055429812710132, + 0.009604825495418301, + -0.021787644315861, + -0.019349988706166887, + 0.000964847145249581, + -0.05755065356097766, + -0.02735119201429448, + 0.11596718640775172, + 0.02728920505256438, + 0.1221859549715778, + 0.02595406870941741, + 0.028054017718809776, + -0.04194501363725711, + 0.026128823975225313, + -0.11542339836540128, + -0.011041994161186675, + -0.008163858700102056, + -0.04218023773586432, + -0.04074782775404373, + 0.07272403627938429, + 0.02092456095864359, + 0.09967549256117503, + 0.06808890407451773, + -0.029733534512762505, + 0.01158973134363872, + 0.06603444240279577, + -0.07597643237085949, + 0.04285532951529669, + 0.05366066465349939, + 0.03197023859639214, + 0.042999546923346954, + -0.0046783863755930355, + 0.0002789225763577541, + 0.05803561953688252, + 0.02658799155729763, + -0.026995784619142316, + 0.12257136273641767, + -0.01745977147394584, + 0.0410065707188928, + -0.033115159332053556, + 0.03492007121496188, + 0.0561086405370832, + 0.0508641542608157, + 0.013883731797356358, + -0.10414568484233244, + 0.02862446080920744, + -0.029238604390723122, + -0.022525483117415424, + 0.1255518937619975, + 0.016096421287819518, + 0.049834364765736106, + 0.030752417730713244, + 0.08316789869812857, + -0.008286874626800556, + 0.03901363646641465, + -0.14552178350010436, + 0.1499560196494364, + -0.0415789012115948 + ], + "mean_abs": 0.048446746358540994, + "sd_abs": 0.04092549486362834, + "realized_sigma": 0.06328692124968117, + "shared_noise_variance_share": 0.7715972613879603, + "tolerance": 0.212 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.389, + "upper": 0.212, + "minimum_detectable_gap_80": 0.4416515314678959, + "faithful_pass_probability": 0.9996095740293334, + "real_gate_holdouts": { + "estimate": -1.8716978845011494, + "gap_from_epuf": -0.15822885963913902, + "lower": -0.389, + "upper": 0.212, + "pass": true + } + }, + "q_atmax.men": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.11615905576233994, + "epuf_sampling_sd": 0.003100890006720793, + "psid_value": 0.17758180210585264, + "psid_n": 9204, + "bridge_psid_minus_epuf": 0.42447093741219777, + "min_events": 194, + "floor": { + "replicates": [ + 0.00843412274658717, + -0.03409200844396043, + -0.06577799315247546, + 0.033736627984672696, + 0.08057643434131645, + 0.08566294943381036, + -0.08154429470589009, + 0.05484388925103112, + -0.04543469460523175, + -0.03968069223271964, + 0.01627764560336664, + -0.05447794551379648, + -0.07446276793100892, + -0.06458483539317117, + 0.05488163417334657, + 0.029930238906929696, + -0.04988735741013994, + 0.026212166540517168, + -0.042112468709185835, + -0.0643332224917571, + -0.018829168047991063, + -0.03755413315246414, + -0.005641675764285203, + -0.00657668352727625, + 0.10290018286371716, + -0.008480890531639917, + -0.12200276997949977, + 0.0003235058290328441, + 0.026599418503463368, + 0.047069658783500556, + 0.0184972864190317, + 0.05637788507810737, + 0.05086279943366023, + -0.10367597783870541, + 0.016374367755696118, + -0.00018068351026057083, + 0.02559828125037955, + -0.12268184149291572, + -0.016577427555732993, + -0.09072301731655041, + -0.03078749195704311, + 0.00405111417495696, + -0.006340160420119645, + 0.004628323681505009, + 0.015028435065550627, + -0.018200968993455136, + -0.0007424787693890433, + -0.021380880099199473, + 0.002839749032820582, + 0.045815633719508475, + -0.020475838067010588, + 0.018121176320791466, + 0.05261229177605653, + 0.008065483961059994, + 0.0011692604619131242, + 0.0337615176964986, + 0.03590647009289105, + 0.029527118937377916, + 0.04665986446719084, + -0.032888018349156334, + 0.04988060606050426, + 0.007437347478792655, + 0.06948542312768768, + -0.014271552366700524, + -0.012327207631441128, + -0.0068954015778288635, + 0.10609551020096541, + 0.012485184254563353, + 0.08622360935022955, + 0.01830581187853275, + 0.061343107301697564, + -0.07926627623930049, + 0.002328910585863153, + -0.02759465077293788, + 0.06872471808442193, + 0.06062455386616983, + 0.0022164100216987004, + 0.03782362332483513, + -0.0689488635794937, + -0.0070878083635019795, + -0.019543253559266338, + 0.12447640105594082, + -0.09349077069652678, + -0.012901476892027364, + 0.029898266660784434, + -0.013835872391487536, + 0.023648999749985022, + 0.08362349906467037, + 0.061372718099296675, + -0.037889303580592504, + 0.011409445929664308, + 0.03734495567714213, + -0.03893367997892805, + 0.022626697660628192, + -0.02172649855071629, + -0.032592924097176734, + 0.0290765213086418, + 0.004017684186844006, + -0.04252381741050171, + -0.07903416733364765 + ], + "mean_abs": 0.03932807450199955, + "sd_abs": 0.031150968231388805, + "realized_sigma": 0.050073710043997056, + "shared_noise_variance_share": 0.7445235648728242, + "tolerance": 0.164 + }, + "eligibility": "bridge_exceeds_budget", + "gated": false, + "report_reason": "bridge_exceeds_budget", + "lower": -0.164, + "upper": 0.589, + "minimum_detectable_gap_80": 0.630614035028999, + "faithful_pass_probability": 0.9994914210835905, + "real_gate_holdouts": { + "estimate": -1.736333139873955, + "gap_from_epuf": 0.4164617168324696, + "lower": -0.164, + "upper": 0.589, + "pass": true + } + }, + "q_atmax.women": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.03574836724872469, + "epuf_sampling_sd": 0.00606052300187229, + "psid_value": 0.03897646373345075, + "psid_n": 10749, + "bridge_psid_minus_epuf": 0.08645337320704849, + "min_events": 27, + "floor": { + "replicates": [ + -0.24536006387987963, + -0.05952103981729295, + -0.03584511677245761, + 0.2594326322227296, + 0.13556650213510113, + 0.04604574276444917, + 0.02920239182759321, + -0.18311204220003163, + 0.14344689128193688, + 0.07803925154543867, + -0.10347987334448039, + 0.079644460543294, + -0.13553419268935385, + -0.06520938665589249, + -0.17399143490316948, + -0.047018487506690354, + -0.1844194978770599, + 0.03528537013947908, + 0.186935537924386, + 0.11544378659404808, + 0.04825990587601803, + 0.13154065697276263, + -0.016370337622008346, + -0.0460885569812397, + 0.08211326917471862, + 0.06480250988483527, + -0.04890672470991486, + 0.07489988113073398, + 0.011304272293922724, + 0.02529729883430054, + 0.12706349710018294, + -0.07277139905055052, + 0.20084562159880748, + -0.08824489661735702, + -0.17060065503681576, + -0.02322890185593174, + 0.07120806947083569, + -0.09083477658831751, + -0.032168501180461107, + -0.1138413890555039, + -0.15919293913844967, + -0.04038144182317449, + -0.005725460360337831, + 0.30604399467540855, + -0.03955548643956086, + -0.18334783799508925, + -0.043424504656244256, + -0.14264852704810904, + -0.12275107559471965, + -0.14639869478236878, + 0.05029177862319312, + 0.038775202475481496, + 0.024716622863362403, + -0.10342291514110702, + 0.12542988888340711, + 0.03549905429548672, + 0.1386350136704324, + -0.09338352008459361, + 0.1960431767409918, + -0.003695577286179086, + 0.05241300835707374, + -0.03352230867011552, + 0.006240440009228632, + 0.12436291491855611, + 0.09928743077921731, + 0.18991921733926653, + 0.10851257819563709, + 0.16939713662506928, + -0.06765473914205655, + 0.10544316153605271, + 0.2125975787737051, + 0.046950427330808564, + -0.04400950636287804, + 0.20401936896491835, + 0.06307802169299825, + 0.13682196236844102, + 0.1970692705720345, + -0.06736634004041786, + -0.03294719636326282, + 0.14754830781665018, + -0.009412127931885728, + -0.010419836985326114, + -0.006804575099132348, + -0.011646342710175617, + 0.09343361021693353, + -0.2050578370614029, + -0.06551638428758966, + -0.07537921496788091, + -0.02375570323909071, + 0.06912598987012375, + 0.020934913762387097, + 0.013161488163240254, + -0.07248692305697535, + 0.04631803546470348, + 0.03284959971181123, + 0.013724844803094882, + 0.04550961973033085, + 0.03488915833308259, + -0.06278691343983489, + -0.16835157710243465 + ], + "mean_abs": 0.09073013148033506, + "sd_abs": 0.0667141292305903, + "realized_sigma": 0.11241985610667196, + "shared_noise_variance_share": 0.7996190598281817, + "tolerance": 0.358 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.358, + "upper": 0.445, + "minimum_detectable_gap_80": 0.5390683111816352, + "faithful_pass_probability": 0.9992485362502166, + "real_gate_holdouts": { + "estimate": -3.2782390275913, + "gap_from_epuf": 0.05301165465813318, + "lower": -0.358, + "upper": 0.445, + "pass": true + } + }, + "mpers.men": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.5941642557869502, + "epuf_sampling_sd": 0.003462551711276296, + "psid_value": 0.6126704906753987, + "psid_n": 361, + "bridge_psid_minus_epuf": 0.03067144977867836, + "min_events": 10, + "floor": { + "replicates": [ + 0.02879396747458124, + -0.0008566422105176497, + 0.017076113628010786, + -0.0413131124883879, + 0.07976192112935224, + -0.0469874668640573, + -0.03615161036455747, + -0.006037868371096489, + -0.05762638558573141, + -0.03234493891707896, + -0.11525362772772965, + 0.04967649460145074, + -0.0046270963391473185, + -0.03401029015541973, + 0.044054250299758846, + 0.013176364820456893, + -0.08352481597315092, + -0.0863320320870255, + 0.17299500932479675, + 0.0017662606726903674, + -0.03453081189922669, + 0.04557363008060045, + -0.008217822412518033, + 0.013964867502223838, + -0.0003198872219154214, + 0.023854916439931262, + -0.0011138360922329782, + -0.06959479407454952, + -0.024463823840489507, + -0.024946916246465417, + 0.03358926864754169, + -0.01819065602761258, + 0.1080102389769246, + -0.006904664587984, + 0.04079875310966838, + 0.013277394081180033, + 0.14242379454686602, + -0.019689282736208513, + 0.11933601915723532, + 0.07789582730651137, + -0.026208708429585087, + 0.094175772396597, + -0.03563604950298624, + 0.07315273716243018, + -0.06270924265096234, + -0.03555131890318289, + 0.022466371332323543, + 0.061712820731880974, + -0.024372881058274287, + 0.08486655990228098, + -0.04366116337236958, + -0.03347046466810455, + 0.019614738262779402, + -0.15135794360850333, + 0.0882909553747489, + 0.04468722336158096, + 0.02265092027385096, + 0.05691411637962382, + -0.007276157037690217, + 0.008938108027363723, + -0.09409870646040358, + -0.02910288125058036, + -0.022225545628160676, + -0.0021699501533988252, + -0.04900378130126762, + -0.048227882677898876, + 0.052454976738579295, + -0.0316355906715961, + 0.037382520606727476, + -0.10921122255104715, + 0.09423133943382991, + -0.050824598765864676, + -0.02468052836512369, + -0.0002617450081405237, + 0.10050765367893277, + 0.06731717099428175, + 0.017347953070107974, + 0.0038501565359807255, + -0.0884415709745327, + -0.06173386511123474, + -0.091789785082669, + 0.06840851791839644, + 0.05459091616219425, + -0.07652445137037064, + -0.02241609130082417, + -0.11963937875423078, + 0.08002596852704297, + -0.029574223508213177, + -0.022856888760272726, + 0.0009154414142555911, + 0.019715109120236995, + 0.02956183486551653, + 0.0012306550716595088, + -0.03311902836924924, + -0.050467272385588346, + -0.10345056763012661, + 0.0029517660307466775, + 0.03024878880408438, + 0.005381027903544028, + -0.023311905916100717 + ], + "mean_abs": 0.046276669853330156, + "sd_abs": 0.037379483774143, + "realized_sigma": 0.059369889016767756, + "shared_noise_variance_share": 0.6199731556353196, + "tolerance": 0.196 + }, + "eligibility": "below_20_events", + "gated": false, + "report_reason": "below_20_events", + "lower": -0.196, + "upper": 0.227, + "minimum_detectable_gap_80": 0.2766384090100575, + "faithful_pass_probability": 0.9994609962051798, + "real_gate_holdouts": { + "estimate": -0.4918811315240385, + "gap_from_epuf": 0.028718341427559746, + "lower": -0.196, + "upper": 0.227, + "pass": true + } + }, + "mpers.women": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 0.4776464731309266, + "epuf_sampling_sd": 0.009017425791556429, + "psid_value": 0.5158920427896447, + "psid_n": 93, + "bridge_psid_minus_epuf": 0.07702666129718683, + "min_events": 0, + "floor": { + "replicates": [ + -0.41641599508056126, + 0.05581763343685381, + null, + 0.20177245310946001, + -0.002548071006900021, + 0.11146069434748912, + -0.1470071360631614, + -0.07299874782747545, + 0.22179957791335342, + 0.08050654630943188, + 0.00397892757118129, + -0.19109471080744367, + -0.0011514548702455385, + 0.050153305064907394, + 0.003052003455925878, + -0.13385065434347293, + 0.006231359397923908, + 0.1174910421040245, + 0.14834294311721347, + -0.15016091332105347, + 0.026160099481563948, + 0.17784716054567007, + 0.06679838168127339, + -0.15264103581406158, + 0.031162555789993163, + -0.29328014569566474, + -0.18716205928983815, + 0.10602902077582882, + -0.14563706660956477, + 0.15102554284884018, + 0.12404841709791953, + -0.050929711142149, + null, + -0.12244152064492297, + null, + 0.006533900509753665, + 0.11721417845521492, + null, + -0.03286414204329824, + -0.1887687821331681, + 0.02041636174214534, + -0.14432851455537216, + 0.13669431570608803, + 0.013155314315940525, + 0.004743812979697226, + null, + null, + 0.060704470836045354, + 0.06693194473772601, + 0.018009551772512067, + -0.09448204743222088, + 0.06081841992997, + 0.0031644098877188775, + -0.10724726512323846, + 0.03835828323418905, + 0.08527790657906908, + 0.1548039083519368, + -0.14095076991992528, + -0.0769471379423809, + -0.023345275287936673, + -0.03186102189788331, + 0.1154286682764652, + 0.11287733798433286, + -0.0038801296261344875, + -0.04544480775381238, + -0.1277091128765127, + 0.06686571277298226, + 0.029883706748795758, + null, + -0.26176908302277746, + 0.04346538288039947, + null, + 0.07498737861416394, + 0.10158839590464758, + 0.0778052677916834, + 0.037890515859538065, + -0.1732908798934919, + 0.014483002261755862, + -0.11461186632963655, + -0.03637636856783727, + null, + -0.03376279189770853, + -0.2509313095262008, + -0.2561120115438578, + 0.0034986956149389292, + -0.016146310698077926, + -0.03399056352118329, + -0.04489831379968501, + -0.06561667844273772, + 0.006294781419113604, + -0.021941542067019648, + -0.04013325961770203, + 0.14027375518989593, + -0.130005765399145, + -0.08707818261784617, + 0.10116748118812191, + 0.10141448968396927, + 0.09472836169699572, + -0.11173623894029786, + 0.023919888915225118 + ], + "mean_abs": null, + "sd_abs": null, + "realized_sigma": null, + "shared_noise_variance_share": null, + "tolerance": null + }, + "eligibility": "undefined_on_some_split", + "gated": false, + "report_reason": "undefined_on_some_split" + }, + "q_sexratio": { + "metric": "log_ratio", + "cap": 0.4054651081081644, + "epuf_value": 3.249352759362286, + "epuf_sampling_sd": 0.007332280696240959, + "psid_value": 4.556129137837785, + "psid_n": 19953, + "bridge_psid_minus_epuf": 0.3380175642051493, + "min_events": 27, + "floor": { + "replicates": [ + 0.2693178760318813, + 0.07053226687575886, + 0.03605384483177099, + -0.1932290840286648, + -0.024929348227733628, + 0.1029779771368855, + -0.07309370555363692, + 0.2728196186445446, + -0.16360288796786893, + -0.06956266392141652, + 0.1436036634971385, + -0.09290127756317945, + 0.100999676083244, + 0.02796828200582102, + 0.29211821473727817, + 0.12288557763621721, + 0.16605770879153126, + 0.04031034219928675, + -0.20291496120878916, + -0.16117676836916972, + -0.042140323518769285, + -0.13938791876143708, + 0.0480330442044552, + 0.09858991048974786, + 0.06303090965456326, + -0.03911015052158673, + -0.044836144216222173, + -0.03958160239375352, + 0.044509588521762566, + 0.07787558615876566, + -0.08237328474271755, + 0.2017232858460829, + -0.07786933130088092, + 0.029467632996889148, + 0.23320037087501855, + 0.0922455280981489, + -0.011776142845465243, + 0.0029337674969807104, + 0.049707237063367216, + 0.051746765315515364, + 0.16031353592151, + 0.12076327674993603, + 0.05908751874215068, + -0.2713732530726469, + 0.09080225873285064, + 0.18765451835175595, + 0.07839629677831972, + 0.16186719810291517, + 0.18353772601373552, + 0.2405024026905569, + -0.02007344763668384, + 0.025750220547614333, + 0.059021880649625325, + 0.1361874234924776, + -0.10953239476761145, + 0.04392381495844466, + -0.0789948571362794, + 0.13930478518475187, + -0.0933643023349704, + 0.017896110443148983, + 0.01536993195609837, + 0.08089373620053353, + 0.10720548727618984, + -0.0890263747974237, + -0.06423048976274925, + -0.12392828405861445, + 0.05101658549688215, + -0.1259237755853927, + 0.19165846064126224, + -0.052471392679218964, + -0.12020204642220456, + -0.08514020732095018, + 0.13313868292950326, + -0.19658427715682258, + 0.03576544492959888, + -0.01808502916120569, + -0.17251434092392826, + 0.15940656217023141, + 0.019665971955032502, + -0.09172816307076792, + 0.020144580764050568, + 0.16385952210510046, + -0.0334140830209636, + 0.039905868012965695, + -0.025535184408501665, + 0.22729988172914362, + 0.1174736594031125, + 0.18872477649049257, + 0.117518007130886, + -0.0852385560136788, + 0.015478726052087444, + 0.06430547403165654, + 0.1098393869781108, + 0.014338906019941033, + 0.006614759659199776, + -0.014680147768798446, + 0.020251681137752886, + 0.009929782670549891, + 0.05733086397408704, + 0.1455046845475273 + ], + "mean_abs": 0.0978688526905515, + "sd_abs": 0.07030058245806704, + "realized_sigma": 0.12029572935881357, + "shared_noise_variance_share": 0.7113262842612574, + "tolerance": 0.379 + }, + "eligibility": "noise_exceeds_cap", + "gated": false, + "report_reason": "noise_exceeds_cap", + "lower": -0.379, + "upper": 0.718, + "minimum_detectable_gap_80": 0.8182610043416674, + "faithful_pass_probability": 0.9992077236128104, + "real_gate_holdouts": { + "estimate": 1.598397320948634, + "gap_from_epuf": 0.4199414954056251, + "lower": -0.379, + "upper": 0.718, + "pass": true + } + } + }, + "gate_partition": { + "status": "lockable_pending_referee_round", + "gated": [ + "r6.men", + "r6.women" + ], + "n_gated": 2, + "report_only": { + "r6.men.c0": "noise_exceeds_cap", + "r6.men.c1": "bridge_exceeds_budget", + "r6.men.c2": "noise_exceeds_cap", + "r6.women.c0": "noise_exceeds_cap", + "r6.women.c1": "cohort_rung_not_adopted", + "r6.women.c2": "noise_exceeds_cap", + "zint.men": "below_20_events", + "d_anyzero.men": "bridge_exceeds_budget", + "zint.women": "below_20_events", + "d_anyzero.women": "bridge_exceeds_budget", + "q_atmax.men": "bridge_exceeds_budget", + "q_atmax.women": "noise_exceeds_cap", + "mpers.men": "below_20_events", + "mpers.women": "undefined_on_some_split", + "q_sexratio": "noise_exceeds_cap", + "zint.men.c0": "below_20_events", + "zint.men.c1": "below_20_events", + "zint.men.c2": "below_20_events", + "zint.women.c0": "below_20_events", + "zint.women.c1": "below_20_events", + "zint.women.c2": "below_20_events", + "d_anyzero.men.c0": "below_20_events", + "d_anyzero.men.c1": "below_20_events", + "d_anyzero.men.c2": "below_20_events", + "d_anyzero.women.c0": "below_20_events", + "d_anyzero.women.c1": "below_20_events", + "d_anyzero.women.c2": "below_20_events", + "q_atmax.men.c0": "bridge_exceeds_budget", + "q_atmax.men.c1": "bridge_exceeds_budget", + "q_atmax.men.c2": "below_20_events", + "q_atmax.women.c0": "below_20_events", + "q_atmax.women.c1": "below_20_events", + "q_atmax.women.c2": "below_20_events", + "mpers.men.c0": "below_20_events", + "mpers.men.c1": "below_20_events", + "mpers.men.c2": "below_20_events", + "mpers.women.c0": "below_20_events", + "mpers.women.c1": "below_20_events", + "mpers.women.c2": "undefined_on_some_split" + }, + "n_report_only": 39 + }, + "registered": { + "r6.men": { + "epuf_value": 0.7108651036878303, + "psid_value": 0.6680476050375935, + "lower": -0.122, + "upper": 0.079 + }, + "r6.women": { + "epuf_value": 0.672102564061898, + "psid_value": 0.6397841177680634, + "lower": -0.111, + "upper": 0.078 + } + }, + "faithful_candidate_oc": { + "method": "per cell, the normal probability that bridge + noise falls inside the interval at the cell's realised sigma; analytic_product multiplies the gated cells; empirical_joint is the share of floor replicates in which every gated cell's bridge + e_b is inside", + "analytic_product": 0.9985987857839889, + "empirical_joint": 1.0, + "n_replicates": 100, + "pause_below": 0.9, + "pause": false + }, + "training_copy": { + "cells": { + "r6.men": { + "estimate": 0.6670465436202722, + "gap_from_epuf": -0.04381856006755813, + "lower": -0.122, + "upper": 0.079, + "pass": true, + "source_term_psid_minus_epuf": -0.04281749865023676, + "model_term_candidate_minus_psid": -0.0010010614173213694 + }, + "r6.women": { + "estimate": 0.6273350404581282, + "gap_from_epuf": -0.04476752360376979, + "lower": -0.111, + "upper": 0.078, + "pass": true, + "source_term_psid_minus_epuf": -0.03231844629383451, + "model_term_candidate_minus_psid": -0.012449077309935275 + } + }, + "n_gated": 2, + "n_pass": 2, + "pass": true + }, + "real_gate_seed_values": { + "0": { + "r6.men.c0": 0.7584076993820408, + "zint.men.c0": 0.058028039231156604, + "d_anyzero.men.c0": 0.10593136896875945, + "q_atmax.men.c0": 0.26667734142374017, + "mpers.men.c0": 0.8346978791445984, + "r6.men.c1": 0.7374905575477457, + "zint.men.c1": 0.07943290393080892, + "d_anyzero.men.c1": 0.08777476985650152, + "q_atmax.men.c1": 0.19869221652210475, + "mpers.men.c1": 0.8634920909289296, + "r6.men.c2": 0.7239705724068728, + "zint.men.c2": 0.015153415098541588, + "d_anyzero.men.c2": 0.04673717101893403, + "q_atmax.men.c2": 0.1316067917424688, + "mpers.men.c2": 0.44126765025343956, + "r6.men": 0.7399562764455531, + "zint.men": 0.050871452753502376, + "d_anyzero.men": 0.080147769948065, + "q_atmax.men": 0.19899211656277124, + "mpers.men": 0.7131525401089891, + "r6.women.c0": 0.5631930684974464, + "zint.women.c0": 0.05688061623748897, + "d_anyzero.women.c0": 0.11444347305940275, + "q_atmax.women.c0": 0.05065486862851886, + "mpers.women.c0": 0.6298451480601881, + "r6.women.c1": 0.7303241715845974, + "zint.women.c1": 0.06538502817384795, + "d_anyzero.women.c1": 0.14989122225845763, + "q_atmax.women.c1": 0.03328883497131927, + "mpers.women.c1": 0.15892176925494164, + "r6.women.c2": 0.642481414155306, + "zint.women.c2": 0.08619416576092499, + "d_anyzero.women.c2": 0.16959232806950833, + "q_atmax.women.c2": 0.03781695983257177, + "mpers.women.c2": 0.0, + "r6.women": 0.6453328847457832, + "zint.women": 0.06948660339075396, + "d_anyzero.women": 0.1446423411291229, + "q_atmax.women": 0.0405868878108033, + "mpers.women": 0.2629223057717099, + "q_sexratio": 4.902867090730817 + }, + "1": { + "r6.men.c0": 0.744723856065266, + "zint.men.c0": 0.09121820745384153, + "d_anyzero.men.c0": 0.1553432957807589, + "q_atmax.men.c0": 0.1891448282208163, + "mpers.men.c0": 0.6522563749510658, + "r6.men.c1": 0.703995382816119, + "zint.men.c1": 0.07298655859460879, + "d_anyzero.men.c1": 0.17049463700364548, + "q_atmax.men.c1": 0.22002904693628397, + "mpers.men.c1": 0.6355200558181616, + "r6.men.c2": 0.6450408126671987, + "zint.men.c2": 0.06414884156330447, + "d_anyzero.men.c2": 0.11027622008253585, + "q_atmax.men.c2": 0.09764195463137662, + "mpers.men.c2": 0.4735753455408396, + "r6.men": 0.6979200171828612, + "zint.men": 0.07611786920391826, + "d_anyzero.men": 0.14537138428898008, + "q_atmax.men": 0.16893860992949228, + "mpers.men": 0.5871172587700223, + "r6.women.c0": 0.785872551705493, + "zint.women.c0": 0.018248884015976193, + "d_anyzero.women.c0": 0.05202574114171492, + "q_atmax.women.c0": 0.026794562949800357, + "mpers.women.c0": 0.6886371898138405, + "r6.women.c1": 0.7087249426947722, + "zint.women.c1": 0.07283592205402131, + "d_anyzero.women.c1": 0.18226294490600656, + "q_atmax.women.c1": 0.023951762938473124, + "mpers.women.c1": 0.57430104490257, + "r6.women.c2": 0.43271262862588994, + "zint.women.c2": 0.07894717070238709, + "d_anyzero.women.c2": 0.14904408005937964, + "q_atmax.women.c2": 0.01512258789899191, + "mpers.women.c2": 0.0, + "r6.women": 0.6424367076753851, + "zint.women": 0.05667732559079486, + "d_anyzero.women": 0.12777758870236702, + "q_atmax.women": 0.021956304595755132, + "mpers.women": 0.4209794115721368, + "q_sexratio": 7.694309813963576 + }, + "2": { + "r6.men.c0": 0.6679140241615406, + "zint.men.c0": 0.09438955839930924, + "d_anyzero.men.c0": 0.14976747118620196, + "q_atmax.men.c0": 0.2204513932616166, + "mpers.men.c0": 0.8109160122089235, + "r6.men.c1": 0.754550548149083, + "zint.men.c1": 0.04205401474533761, + "d_anyzero.men.c1": 0.1070692958144441, + "q_atmax.men.c1": 0.19613612113980114, + "mpers.men.c1": 0.7828155390842664, + "r6.men.c2": 0.44945348119669404, + "zint.men.c2": 0.07108945161988178, + "d_anyzero.men.c2": 0.08394246232068486, + "q_atmax.men.c2": 0.11224766466894875, + "mpers.men.c2": 0.4043722304283604, + "r6.men": 0.6239726845024393, + "zint.men": 0.06917767492150954, + "d_anyzero.men": 0.11359307644044364, + "q_atmax.men": 0.1762783930234555, + "mpers.men": 0.6660345939071833, + "r6.women.c0": 0.6474282875986841, + "zint.women.c0": 0.05874682773830413, + "d_anyzero.women.c0": 0.10818756721840204, + "q_atmax.women.c0": 0.04525561100901698, + "mpers.women.c0": 0.7945184235556843, + "r6.women.c1": 0.7740355039110793, + "zint.women.c1": 0.07519599119054629, + "d_anyzero.women.c1": 0.1714514029642944, + "q_atmax.women.c1": 0.043545184115731175, + "mpers.women.c1": 0.7406425529799678, + "r6.women.c2": 0.4192594514967901, + "zint.women.c2": 0.09445461031077512, + "d_anyzero.women.c2": 0.1978842431324377, + "q_atmax.women.c2": 0.01879142794313749, + "mpers.women.c2": 0.0, + "r6.women": 0.6135744143355178, + "zint.women": 0.07613247641320851, + "d_anyzero.women": 0.15917440443837805, + "q_atmax.women": 0.03586407435596189, + "mpers.women": 0.5117203255118841, + "q_sexratio": 4.91518033544763 + }, + "3": { + "r6.men.c0": 0.7163311399032256, + "zint.men.c0": 0.06327941139811413, + "d_anyzero.men.c0": 0.10327368536418081, + "q_atmax.men.c0": 0.1935377157671773, + "mpers.men.c0": 0.8292630096929658, + "r6.men.c1": 0.8233604342177068, + "zint.men.c1": 0.06221630471564382, + "d_anyzero.men.c1": 0.14753949658270527, + "q_atmax.men.c1": 0.20833346855359353, + "mpers.men.c1": 0.5569468547641852, + "r6.men.c2": 0.5249274157042227, + "zint.men.c2": 0.08821127069996498, + "d_anyzero.men.c2": 0.13838202889256143, + "q_atmax.men.c2": 0.09934634013712725, + "mpers.men.c2": 0.10723148337371909, + "r6.men": 0.6882063299417185, + "zint.men": 0.07123566227124098, + "d_anyzero.men": 0.12973173694648252, + "q_atmax.men": 0.16707250815263272, + "mpers.men": 0.49781378261029, + "r6.women.c0": 0.5144302970646379, + "zint.women.c0": 0.07899144835075336, + "d_anyzero.women.c0": 0.14745325491073166, + "q_atmax.women.c0": 0.06175187189659646, + "mpers.women.c0": 0.7546827794561933, + "r6.women.c1": 0.7850050967801495, + "zint.women.c1": 0.05690518517768177, + "d_anyzero.women.c1": 0.1391476877616161, + "q_atmax.women.c1": 0.04930650318892865, + "mpers.women.c1": 0.5649993588142789, + "r6.women.c2": 0.5050872210463359, + "zint.women.c2": 0.054580210667106346, + "d_anyzero.women.c2": 0.15202069576888344, + "q_atmax.women.c2": 0.04833841048323521, + "mpers.women.c2": 0.32200709445731795, + "r6.women": 0.6015075382970411, + "zint.women": 0.06349228139851382, + "d_anyzero.women": 0.14620721281374374, + "q_atmax.women": 0.053132261856253436, + "mpers.women": 0.5472297442425967, + "q_sexratio": 3.144464442425558 + }, + "4": { + "r6.men.c0": 0.7416173076638203, + "zint.men.c0": 0.03780162811991782, + "d_anyzero.men.c0": 0.08403885374597622, + "q_atmax.men.c0": 0.23697494312202236, + "mpers.men.c0": 0.8568933087726661, + "r6.men.c1": 0.7028362496860576, + "zint.men.c1": 0.05764141589961347, + "d_anyzero.men.c1": 0.14116789743039165, + "q_atmax.men.c1": 0.23042387244301427, + "mpers.men.c1": 0.6457915780821084, + "r6.men.c2": 0.5214693295060072, + "zint.men.c2": 0.05685214605461556, + "d_anyzero.men.c2": 0.10080762105238622, + "q_atmax.men.c2": 0.10193080414602468, + "mpers.men.c2": 0.555278673031273, + "r6.men": 0.6553076289519617, + "zint.men": 0.05076506335804895, + "d_anyzero.men": 0.10867145740958468, + "q_atmax.men": 0.18977653990368712, + "mpers.men": 0.6859878532953491, + "r6.women.c0": 0.5412496850461953, + "zint.women.c0": 0.06930093143197602, + "d_anyzero.women.c0": 0.13079158749760453, + "q_atmax.women.c0": 0.027278971333667173, + "mpers.women.c0": 0.35648157133707276, + "r6.women.c1": 0.6439844123629458, + "zint.women.c1": 0.07544796066674522, + "d_anyzero.women.c1": 0.15670461145733044, + "q_atmax.women.c1": 0.028412495972593377, + "mpers.women.c1": 0.8093840909942193, + "r6.women.c2": 0.5848876309322432, + "zint.women.c2": 0.063658068327262, + "d_anyzero.women.c2": 0.18034351638464044, + "q_atmax.women.c2": 0.030228338079266916, + "mpers.women.c2": 0.0, + "r6.women": 0.5900405761137947, + "zint.women": 0.06946898680866108, + "d_anyzero.women": 0.15594657177985846, + "q_atmax.women": 0.028639935128509156, + "mpers.women": 0.38862188744376397, + "q_sexratio": 6.626290843612183 + }, + "5": { + "r6.men.c0": 0.7669028833331876, + "zint.men.c0": 0.06980728595229388, + "d_anyzero.men.c0": 0.1407913325110129, + "q_atmax.men.c0": 0.2028051548573487, + "mpers.men.c0": 0.7338146501675348, + "r6.men.c1": 0.7929489704174362, + "zint.men.c1": 0.047190453228405024, + "d_anyzero.men.c1": 0.07890986295092642, + "q_atmax.men.c1": 0.22362944259445297, + "mpers.men.c1": 0.541125346886553, + "r6.men.c2": 0.5906484087416669, + "zint.men.c2": 0.02640029551140005, + "d_anyzero.men.c2": 0.07606533198331607, + "q_atmax.men.c2": 0.13803625473696493, + "mpers.men.c2": 0.5079408983927098, + "r6.men": 0.7168334208307635, + "zint.men": 0.047799344897366314, + "d_anyzero.men": 0.0985888424817518, + "q_atmax.men": 0.18815695072958885, + "mpers.men": 0.5942936318155992, + "r6.women.c0": 0.7002795584793922, + "zint.women.c0": 0.06971873410183542, + "d_anyzero.women.c0": 0.12070103248369732, + "q_atmax.women.c0": 0.07596844563597259, + "mpers.women.c0": 0.7992132406747113, + "r6.women.c1": 0.5906669997727583, + "zint.women.c1": 0.07014584828231196, + "d_anyzero.women.c1": 0.19253138120719193, + "q_atmax.women.c1": 0.04016412770811913, + "mpers.women.c1": 0.7675157306190983, + "r6.women.c2": 0.6303705538408385, + "zint.women.c2": 0.06808722713831637, + "d_anyzero.women.c2": 0.19158532100360967, + "q_atmax.women.c2": 0.030652374924849506, + "mpers.women.c2": 0.1332072936793191, + "r6.women": 0.6404390373643296, + "zint.women": 0.06931726984082126, + "d_anyzero.women": 0.16827257823149966, + "q_atmax.women": 0.048928316089647074, + "mpers.women": 0.5666454216577096, + "q_sexratio": 3.8455635870412 + }, + "6": { + "r6.men.c0": 0.6486319729820161, + "zint.men.c0": 0.021645544769739646, + "d_anyzero.men.c0": 0.06830981247118394, + "q_atmax.men.c0": 0.25333065555643514, + "mpers.men.c0": 0.7358156451228237, + "r6.men.c1": 0.8102925240514764, + "zint.men.c1": 0.04592275107101376, + "d_anyzero.men.c1": 0.1193575374977073, + "q_atmax.men.c1": 0.21351351000414026, + "mpers.men.c1": 0.6843724242914213, + "r6.men.c2": 0.5464656756571502, + "zint.men.c2": 0.012060640123319673, + "d_anyzero.men.c2": 0.0809718470743396, + "q_atmax.men.c2": 0.08526674508758346, + "mpers.men.c2": 0.46550568245812574, + "r6.men": 0.668463390896881, + "zint.men": 0.02654297865469103, + "d_anyzero.men": 0.08954639901441026, + "q_atmax.men": 0.18403697021605295, + "mpers.men": 0.628564583957457, + "r6.women.c0": 0.8125041768859935, + "zint.women.c0": 0.049120030577171354, + "d_anyzero.women.c0": 0.10786690578256594, + "q_atmax.women.c0": 0.03311336407158906, + "mpers.women.c0": 0.7556543174334707, + "r6.women.c1": 0.7785316927707905, + "zint.women.c1": 0.08768941964891724, + "d_anyzero.women.c1": 0.1641014667850972, + "q_atmax.women.c1": 0.039930857880997185, + "mpers.women.c1": 0.3049272312817815, + "r6.women.c2": 0.3966074993236662, + "zint.women.c2": 0.08483200655657751, + "d_anyzero.women.c2": 0.24459881146616103, + "q_atmax.women.c2": 0.02539768749599886, + "mpers.women.c2": 0.0, + "r6.women": 0.66254778966015, + "zint.women": 0.07388048559422204, + "d_anyzero.women": 0.17218906134460807, + "q_atmax.women": 0.032813969816195034, + "mpers.women": 0.35352718290508406, + "q_sexratio": 5.608494529827452 + }, + "7": { + "r6.men.c0": 0.5625395107662263, + "zint.men.c0": 0.06554799794661191, + "d_anyzero.men.c0": 0.13804730630231574, + "q_atmax.men.c0": 0.20204260465654744, + "mpers.men.c0": 0.7086708685810197, + "r6.men.c1": 0.8095105516917578, + "zint.men.c1": 0.09399769799695346, + "d_anyzero.men.c1": 0.1420449905842445, + "q_atmax.men.c1": 0.24641158711515423, + "mpers.men.c1": 0.8222825037416116, + "r6.men.c2": 0.6127225937921047, + "zint.men.c2": 0.04771989547710749, + "d_anyzero.men.c2": 0.10790829703302843, + "q_atmax.men.c2": 0.10732150422918245, + "mpers.men.c2": 0.34698002536461636, + "r6.men": 0.6615908854166963, + "zint.men": 0.06908853047355762, + "d_anyzero.men": 0.12933353130652955, + "q_atmax.men": 0.18525856533362803, + "mpers.men": 0.6259777992290826, + "r6.women.c0": 0.610186965463988, + "zint.women.c0": 0.05858863770019305, + "d_anyzero.women.c0": 0.10777650375399359, + "q_atmax.women.c0": 0.04966993481198279, + "mpers.women.c0": 0.5976203183373623, + "r6.women.c1": 0.7289783188863721, + "zint.women.c1": 0.04042867847481688, + "d_anyzero.women.c1": 0.16810094519718768, + "q_atmax.women.c1": 0.03403935240239404, + "mpers.women.c1": 0.8206916449449828, + "r6.women.c2": 0.3788428511790168, + "zint.women.c2": 0.12282262391288508, + "d_anyzero.women.c2": 0.25187962066941555, + "q_atmax.women.c2": 0.006788896128220392, + "mpers.women.c2": 0.0, + "r6.women": 0.5726693785097923, + "zint.women": 0.073946646695965, + "d_anyzero.women": 0.17591902320686562, + "q_atmax.women": 0.030166061114199075, + "mpers.women": 0.47277065442744837, + "q_sexratio": 6.14129118920426 + }, + "8": { + "r6.men.c0": 0.6730113301687092, + "zint.men.c0": 0.04709522381622225, + "d_anyzero.men.c0": 0.11006049156936433, + "q_atmax.men.c0": 0.2418454771068807, + "mpers.men.c0": 0.7394832252553442, + "r6.men.c1": 0.7194819430709375, + "zint.men.c1": 0.09819601473789781, + "d_anyzero.men.c1": 0.19641025561390119, + "q_atmax.men.c1": 0.1446471715131597, + "mpers.men.c1": 0.5157314356237278, + "r6.men.c2": 0.6243955071706151, + "zint.men.c2": 0.04107992091264552, + "d_anyzero.men.c2": 0.051768540281067046, + "q_atmax.men.c2": 0.06026646157614255, + "mpers.men.c2": 0.40134499436825016, + "r6.men": 0.6722962601367538, + "zint.men": 0.062123719822255195, + "d_anyzero.men": 0.11941309582144417, + "q_atmax.men": 0.14891970339872765, + "mpers.men": 0.5521865517491074, + "r6.women.c0": 0.652630514116165, + "zint.women.c0": 0.0329916505683257, + "d_anyzero.women.c0": 0.07697361123040979, + "q_atmax.women.c0": 0.06884957260682532, + "mpers.women.c0": 0.8119113717147083, + "r6.women.c1": 0.8182480192134666, + "zint.women.c1": 0.05940053937827732, + "d_anyzero.women.c1": 0.16579218372944732, + "q_atmax.women.c1": 0.05968582044148681, + "mpers.women.c1": 0.788949873481915, + "r6.women.c2": 0.45788149969727443, + "zint.women.c2": 0.09533113221462042, + "d_anyzero.women.c2": 0.16420369854024852, + "q_atmax.women.c2": 0.015690543795473338, + "mpers.women.c2": 0.0, + "r6.women": 0.6429200110089687, + "zint.women": 0.06257444072040781, + "d_anyzero.women": 0.13565649783336856, + "q_atmax.women": 0.04807531228126182, + "mpers.women": 0.5336204150655411, + "q_sexratio": 3.097633615513126 + }, + "9": { + "r6.men.c0": 0.6448903649867037, + "zint.men.c0": 0.02049471591628514, + "d_anyzero.men.c0": 0.04578579856541182, + "q_atmax.men.c0": 0.2204323402213543, + "mpers.men.c0": 0.858611158750354, + "r6.men.c1": 0.805832766960875, + "zint.men.c1": 0.021916049124656774, + "d_anyzero.men.c1": 0.06121968031492753, + "q_atmax.men.c1": 0.19687708502753642, + "mpers.men.c1": 0.6668842116712895, + "r6.men.c2": 0.5866955955018507, + "zint.men.c2": 0.015993148896185194, + "d_anyzero.men.c2": 0.07075131455506822, + "q_atmax.men.c2": 0.08488842450580514, + "mpers.men.c2": 0.540049016728694, + "r6.men": 0.6791395758164764, + "zint.men": 0.019467971312375706, + "d_anyzero.men": 0.05925226447846919, + "q_atmax.men": 0.16739928325156528, + "mpers.men": 0.6885147957167792, + "r6.women.c0": 0.6231365428923387, + "zint.women.c0": 0.09135131403627726, + "d_anyzero.women.c0": 0.14870163324123675, + "q_atmax.women.c0": 0.06963184192748588, + "mpers.women.c0": 1.0, + "r6.women.c1": 0.7400497512986712, + "zint.women.c1": 0.09022496028628058, + "d_anyzero.women.c1": 0.1482670206879975, + "q_atmax.women.c1": 0.0485578600981394, + "mpers.women.c1": 0.6331853456054863, + "r6.women.c2": 0.6130711454135491, + "zint.women.c2": 0.10209855710619765, + "d_anyzero.women.c2": 0.2276906289922285, + "q_atmax.women.c2": 0.04516332003017142, + "mpers.women.c2": 0.4130208220248822, + "r6.women": 0.6587524798681864, + "zint.women": 0.09455827714291849, + "d_anyzero.women": 0.17488642764048756, + "q_atmax.women": 0.054451007351932236, + "mpers.women": 0.6820687225434562, + "q_sexratio": 3.0743101256073455 + }, + "10": { + "r6.men.c0": 0.6212427133674956, + "zint.men.c0": 0.07808806984784009, + "d_anyzero.men.c0": 0.11480864423850146, + "q_atmax.men.c0": 0.23699816948065236, + "mpers.men.c0": 0.6067807717512818, + "r6.men.c1": 0.6313616298392534, + "zint.men.c1": 0.05158922344045858, + "d_anyzero.men.c1": 0.14881186229704804, + "q_atmax.men.c1": 0.18134346685763886, + "mpers.men.c1": 0.5943382014298688, + "r6.men.c2": 0.5019702716744544, + "zint.men.c2": 0.029925733785611582, + "d_anyzero.men.c2": 0.06191678328386254, + "q_atmax.men.c2": 0.0934812053093778, + "mpers.men.c2": 0.382955689638204, + "r6.men": 0.5848582049604012, + "zint.men": 0.05320100902463675, + "d_anyzero.men": 0.10851242993980399, + "q_atmax.men": 0.17060761388255632, + "mpers.men": 0.5280248876064515, + "r6.women.c0": 0.47223864783191505, + "zint.women.c0": 0.05273075519188642, + "d_anyzero.women.c0": 0.1515183703221506, + "q_atmax.women.c0": 0.0258522617538916, + "mpers.women.c0": 0.5424415312921911, + "r6.women.c1": 0.6735684861345123, + "zint.women.c1": 0.08461218663352783, + "d_anyzero.women.c1": 0.1305658156395188, + "q_atmax.women.c1": 0.03216838866222512, + "mpers.women.c1": 0.7777019251399481, + "r6.women.c2": 0.45950821978648687, + "zint.women.c2": 0.0788368133294165, + "d_anyzero.women.c2": 0.1235060734018649, + "q_atmax.women.c2": 0.02581151359609841, + "mpers.women.c2": 0.5688400125234815, + "r6.women": 0.535105117917638, + "zint.women": 0.07205991838494359, + "d_anyzero.women": 0.1351967531211781, + "q_atmax.women": 0.027944054670738377, + "mpers.women": 0.6296611563185402, + "q_sexratio": 6.105327802024669 + }, + "11": { + "r6.men.c0": 0.6825358003294848, + "zint.men.c0": 0.05487004699899977, + "d_anyzero.men.c0": 0.08865147535038403, + "q_atmax.men.c0": 0.2399939487612004, + "mpers.men.c0": 0.8394081967056027, + "r6.men.c1": 0.7073629572853287, + "zint.men.c1": 0.06700353881551921, + "d_anyzero.men.c1": 0.11529181840795324, + "q_atmax.men.c1": 0.1781691322912252, + "mpers.men.c1": 0.6891900356217028, + "r6.men.c2": 0.6541773616478727, + "zint.men.c2": 0.031019319389782012, + "d_anyzero.men.c2": 0.06382445617516937, + "q_atmax.men.c2": 0.10331564576181448, + "mpers.men.c2": 0.6418588930494687, + "r6.men": 0.6813587064208955, + "zint.men": 0.050964301734766994, + "d_anyzero.men": 0.08925591664450222, + "q_atmax.men": 0.17382624227141338, + "mpers.men": 0.7234857084589247, + "r6.women.c0": 0.6305839231786088, + "zint.women.c0": 0.032183300812038275, + "d_anyzero.women.c0": 0.05926883002865709, + "q_atmax.women.c0": 0.04005141524307904, + "mpers.women.c0": 0.865193610173173, + "r6.women.c1": 0.7936135490637775, + "zint.women.c1": 0.07983011465230039, + "d_anyzero.women.c1": 0.17163196727244776, + "q_atmax.women.c1": 0.05125664572030125, + "mpers.women.c1": 0.45423751956222624, + "r6.women.c2": 0.414881022105308, + "zint.women.c2": 0.05109719509180044, + "d_anyzero.women.c2": 0.18035050691519092, + "q_atmax.women.c2": 0.024718444003158868, + "mpers.women.c2": 0.12026200060497476, + "r6.women": 0.6130261647825647, + "zint.women": 0.05437020351871303, + "d_anyzero.women": 0.13708376807209857, + "q_atmax.women": 0.038675501655513055, + "mpers.women": 0.479897710113458, + "q_sexratio": 4.4944793171579995 + }, + "12": { + "r6.men.c0": 0.6916577286112705, + "zint.men.c0": 0.03984308888550937, + "d_anyzero.men.c0": 0.07962559434349108, + "q_atmax.men.c0": 0.2515463888129417, + "mpers.men.c0": 0.75495312331371, + "r6.men.c1": 0.7436476473836336, + "zint.men.c1": 0.0710255339585582, + "d_anyzero.men.c1": 0.11793390452471553, + "q_atmax.men.c1": 0.21227895770084812, + "mpers.men.c1": 0.6236590243554032, + "r6.men.c2": 0.4820746880729034, + "zint.men.c2": 0.07431089989268741, + "d_anyzero.men.c2": 0.09705591782250371, + "q_atmax.men.c2": 0.122672135725799, + "mpers.men.c2": 0.28680450191353973, + "r6.men": 0.6391266880226025, + "zint.men": 0.06172650757891832, + "d_anyzero.men": 0.09820513889690345, + "q_atmax.men": 0.19549916074652962, + "mpers.men": 0.5551388831942177, + "r6.women.c0": 0.5572000975849147, + "zint.women.c0": 0.037766236505514875, + "d_anyzero.women.c0": 0.0958492492822864, + "q_atmax.women.c0": 0.018370651684227926, + "mpers.women.c0": 0.29711963976087574, + "r6.women.c1": 0.7369700656262805, + "zint.women.c1": 0.015837189794271175, + "d_anyzero.women.c1": 0.10293398935569978, + "q_atmax.women.c1": 0.050081206847850536, + "mpers.women.c1": 1.0, + "r6.women.c2": 0.6076446338510757, + "zint.women.c2": 0.10718920476456646, + "d_anyzero.women.c2": 0.2693387363371659, + "q_atmax.women.c2": 0.02328764493500522, + "mpers.women.c2": 0.0, + "r6.women": 0.6339382656874236, + "zint.women": 0.053597543688117505, + "d_anyzero.women": 0.15604065832505068, + "q_atmax.women": 0.030579834489027898, + "mpers.women": 0.43237321325362527, + "q_sexratio": 6.39307452159936 + }, + "13": { + "r6.men.c0": 0.6581108598194192, + "zint.men.c0": 0.07692565250127277, + "d_anyzero.men.c0": 0.14664809457480624, + "q_atmax.men.c0": 0.16453872869960856, + "mpers.men.c0": 0.5460685753250463, + "r6.men.c1": 0.7775891406815194, + "zint.men.c1": 0.019856529619383764, + "d_anyzero.men.c1": 0.05994589597711119, + "q_atmax.men.c1": 0.19484223725979732, + "mpers.men.c1": 0.6244713987710908, + "r6.men.c2": 0.5060900832465616, + "zint.men.c2": 0.05794802087603595, + "d_anyzero.men.c2": 0.08484226598172187, + "q_atmax.men.c2": 0.1117941209005673, + "mpers.men.c2": 0.39683168087940796, + "r6.men": 0.6472633612491667, + "zint.men": 0.05157673433223083, + "d_anyzero.men": 0.09714541884454643, + "q_atmax.men": 0.15705836228665773, + "mpers.men": 0.5224572183251817, + "r6.women.c0": 0.6241630423622132, + "zint.women.c0": 0.041317712078056436, + "d_anyzero.women.c0": 0.12439708311939152, + "q_atmax.women.c0": 0.05999375710119314, + "mpers.women.c0": 1.0, + "r6.women.c1": 0.6578245068353336, + "zint.women.c1": 0.08071844071715903, + "d_anyzero.women.c1": 0.17353891875606897, + "q_atmax.women.c1": 0.016417872567856668, + "mpers.women.c1": 0.0, + "r6.women.c2": 0.5886680186109523, + "zint.women.c2": 0.03835220136203151, + "d_anyzero.women.c2": 0.15384215537678286, + "q_atmax.women.c2": 0.023962808883504643, + "mpers.women.c2": 0.0, + "r6.women": 0.6235518559361664, + "zint.women": 0.05346278471908233, + "d_anyzero.women": 0.15059271908408112, + "q_atmax.women": 0.03345814618418482, + "mpers.women": 0.3333333333333333, + "q_sexratio": 4.694174071153318 + }, + "14": { + "r6.men.c0": 0.6327145188389686, + "zint.men.c0": 0.06555028912281312, + "d_anyzero.men.c0": 0.0886218994432345, + "q_atmax.men.c0": 0.2101868657878025, + "mpers.men.c0": 0.7485959252603547, + "r6.men.c1": 0.6389266752172174, + "zint.men.c1": 0.06385233902675334, + "d_anyzero.men.c1": 0.08038538056106763, + "q_atmax.men.c1": 0.20873381667819174, + "mpers.men.c1": 0.6695928182302756, + "r6.men.c2": 0.5549493977998854, + "zint.men.c2": 0.022505080399822127, + "d_anyzero.men.c2": 0.08680589734928035, + "q_atmax.men.c2": 0.084711179601421, + "mpers.men.c2": 0.23459320631706324, + "r6.men": 0.6088635306186905, + "zint.men": 0.050635902849796195, + "d_anyzero.men": 0.08527105911786081, + "q_atmax.men": 0.16787728735580507, + "mpers.men": 0.5509273166025644, + "r6.women.c0": 0.6153085982697875, + "zint.women.c0": 0.08984003425456578, + "d_anyzero.women.c0": 0.16097015813188345, + "q_atmax.women.c0": 0.05163267934360909, + "mpers.women.c0": 0.9612659607598879, + "r6.women.c1": 0.7832999957185174, + "zint.women.c1": 0.10410857158250816, + "d_anyzero.women.c1": 0.20643031068892484, + "q_atmax.women.c1": 0.04670403566621052, + "mpers.women.c1": 0.5125177462427999, + "r6.women.c2": 0.5107491816195047, + "zint.women.c2": 0.09505176859526909, + "d_anyzero.women.c2": 0.16072839656057442, + "q_atmax.women.c2": 0.01186736064485531, + "mpers.women.c2": 0.0, + "r6.women": 0.6364525918692698, + "zint.women": 0.09633345814411436, + "d_anyzero.women": 0.17604295512712756, + "q_atmax.women": 0.03673469188489164, + "mpers.women": 0.4912612356675626, + "q_sexratio": 4.569993070361104 + }, + "15": { + "r6.men.c0": 0.6742388712492521, + "zint.men.c0": 0.05347854901222566, + "d_anyzero.men.c0": 0.09762971151635937, + "q_atmax.men.c0": 0.25073598981687617, + "mpers.men.c0": 0.7857243191301211, + "r6.men.c1": 0.6582082527645828, + "zint.men.c1": 0.05064758830741425, + "d_anyzero.men.c1": 0.1170890430662094, + "q_atmax.men.c1": 0.2219151991109193, + "mpers.men.c1": 0.6826244838390615, + "r6.men.c2": 0.6728465807643471, + "zint.men.c2": 0.07366190683748658, + "d_anyzero.men.c2": 0.1068956423661012, + "q_atmax.men.c2": 0.09628640165677076, + "mpers.men.c2": 0.6447121050287521, + "r6.men": 0.6684312349260607, + "zint.men": 0.05926268138570883, + "d_anyzero.men": 0.10720479898289, + "q_atmax.men": 0.1896458635281887, + "mpers.men": 0.7043536359993116, + "r6.women.c0": 0.7144195879825712, + "zint.women.c0": 0.0737293108879775, + "d_anyzero.women.c0": 0.12105628101259172, + "q_atmax.women.c0": 0.036637777073597166, + "mpers.women.c0": 0.7500178954903365, + "r6.women.c1": 0.7460872038437824, + "zint.women.c1": 0.046873113582672106, + "d_anyzero.women.c1": 0.12287590553901545, + "q_atmax.women.c1": 0.053516047614433446, + "mpers.women.c1": 0.43152431396555857, + "r6.women.c2": 0.5828701378889998, + "zint.women.c2": 0.08908028135283526, + "d_anyzero.women.c2": 0.2347698443523592, + "q_atmax.women.c2": 0.03265324060848657, + "mpers.women.c2": 0.12749765651980857, + "r6.women": 0.681125643238451, + "zint.women": 0.06989423527449495, + "d_anyzero.women": 0.15956734363465544, + "q_atmax.women": 0.04093568843217239, + "mpers.women": 0.4363466219919012, + "q_sexratio": 4.6327757219087395 + }, + "16": { + "r6.men.c0": 0.6582683632944424, + "zint.men.c0": 0.07777196982225687, + "d_anyzero.men.c0": 0.1465279201228039, + "q_atmax.men.c0": 0.19763356842239319, + "mpers.men.c0": 0.7601567348180978, + "r6.men.c1": 0.7106979262774492, + "zint.men.c1": 0.0676072807170083, + "d_anyzero.men.c1": 0.14311368235678526, + "q_atmax.men.c1": 0.16034892682786567, + "mpers.men.c1": 0.6027916331456155, + "r6.men.c2": 0.6439219283662241, + "zint.men.c2": 0.0014629366316946057, + "d_anyzero.men.c2": 0.04043805175582596, + "q_atmax.men.c2": 0.09704969325216406, + "mpers.men.c2": 0.42244690698275766, + "r6.men": 0.6709627393127052, + "zint.men": 0.04894739572365326, + "d_anyzero.men": 0.11002655141180502, + "q_atmax.men": 0.1516773961674743, + "mpers.men": 0.5951317583154903, + "r6.women.c0": 0.7445505869965238, + "zint.women.c0": 0.0573464936003138, + "d_anyzero.women.c0": 0.10661626231302851, + "q_atmax.women.c0": 0.02420847999674458, + "mpers.women.c0": 0.5063164591475052, + "r6.women.c1": 0.7135221112431321, + "zint.women.c1": 0.081478432067636, + "d_anyzero.women.c1": 0.21609897250637203, + "q_atmax.women.c1": 0.041011366819136155, + "mpers.women.c1": 0.5466054823879153, + "r6.women.c2": 0.5196639887197123, + "zint.women.c2": 0.09865460814569284, + "d_anyzero.women.c2": 0.2005682924573052, + "q_atmax.women.c2": 0.018930532604971365, + "mpers.women.c2": 0.0, + "r6.women": 0.6592455623197894, + "zint.women": 0.07915984460454754, + "d_anyzero.women": 0.1744278424255686, + "q_atmax.women": 0.028050126473617366, + "mpers.women": 0.35097398051180684, + "q_sexratio": 5.407369421672125 + }, + "17": { + "r6.men.c0": 0.73208567974812, + "zint.men.c0": 0.082676445910168, + "d_anyzero.men.c0": 0.1639072692326339, + "q_atmax.men.c0": 0.21687645342074507, + "mpers.men.c0": 0.7525529771190848, + "r6.men.c1": 0.8502423514668278, + "zint.men.c1": 0.050469866906478075, + "d_anyzero.men.c1": 0.09255726593371882, + "q_atmax.men.c1": 0.22353897752357105, + "mpers.men.c1": 0.7425082234215821, + "r6.men.c2": 0.6864788414925715, + "zint.men.c2": 0.01913607929281029, + "d_anyzero.men.c2": 0.07054461328812055, + "q_atmax.men.c2": 0.08381734315529517, + "mpers.men.c2": 0.24421861584584853, + "r6.men": 0.7562689575691731, + "zint.men": 0.05076079736981879, + "d_anyzero.men": 0.10900304948482442, + "q_atmax.men": 0.1747442580332038, + "mpers.men": 0.5797599387955051, + "r6.women.c0": 0.7128471194328649, + "zint.women.c0": 0.031503816002706034, + "d_anyzero.women.c0": 0.08962542911595411, + "q_atmax.women.c0": 0.055597947096161934, + "mpers.women.c0": 0.6566308846585892, + "r6.women.c1": 0.6987498339374705, + "zint.women.c1": 0.05996523551304486, + "d_anyzero.women.c1": 0.16596626607253534, + "q_atmax.women.c1": 0.04540036958781714, + "mpers.women.c1": 0.9638795935981104, + "r6.women.c2": 0.5236494562513436, + "zint.women.c2": 0.10009008194410664, + "d_anyzero.women.c2": 0.193682706488078, + "q_atmax.women.c2": 0.03281875556159681, + "mpers.women.c2": 0.29495369907579905, + "r6.women": 0.6450821365405597, + "zint.women": 0.06385304448661917, + "d_anyzero.women": 0.14975813389218914, + "q_atmax.women": 0.044605690748525294, + "mpers.women": 0.6384880591108328, + "q_sexratio": 3.917532832713301 + }, + "18": { + "r6.men.c0": 0.5691579475871474, + "zint.men.c0": 0.0785839662351384, + "d_anyzero.men.c0": 0.11895109315793893, + "q_atmax.men.c0": 0.2273308012241293, + "mpers.men.c0": 0.8396658644946317, + "r6.men.c1": 0.7688230156580048, + "zint.men.c1": 0.04550761978873843, + "d_anyzero.men.c1": 0.13123573055008528, + "q_atmax.men.c1": 0.23231421207314676, + "mpers.men.c1": 0.6880706572884498, + "r6.men.c2": 0.5885998379492251, + "zint.men.c2": 0.0483378435309026, + "d_anyzero.men.c2": 0.07834808790773808, + "q_atmax.men.c2": 0.118053400281775, + "mpers.men.c2": 0.40747891503465844, + "r6.men": 0.6421936003981258, + "zint.men": 0.0574764765182598, + "d_anyzero.men": 0.10951163720525409, + "q_atmax.men": 0.19256613785968368, + "mpers.men": 0.64507181227258, + "r6.women.c0": 0.5480682711012463, + "zint.women.c0": 0.06744439953040111, + "d_anyzero.women.c0": 0.11096201591052199, + "q_atmax.women.c0": 0.06618735172834742, + "mpers.women.c0": 0.7296447256813866, + "r6.women.c1": 0.7265000762568846, + "zint.women.c1": 0.0999419833577436, + "d_anyzero.women.c1": 0.17004259267226463, + "q_atmax.women.c1": 0.05048715644812472, + "mpers.women.c1": 0.5241195909348664, + "r6.women.c2": 0.6472661216546016, + "zint.women.c2": 0.05838210352440299, + "d_anyzero.women.c2": 0.15089433456780396, + "q_atmax.women.c2": 0.022549146195994, + "mpers.women.c2": 0.0, + "r6.women": 0.6406114896709109, + "zint.women": 0.0752561621375159, + "d_anyzero.women": 0.14396631438353022, + "q_atmax.women": 0.04640788479082205, + "mpers.women": 0.4179214388720844, + "q_sexratio": 4.1494271658286594 + }, + "19": { + "r6.men.c0": 0.6428128850594452, + "zint.men.c0": 0.06120885242010446, + "d_anyzero.men.c0": 0.10665167440804141, + "q_atmax.men.c0": 0.22356245361182364, + "mpers.men.c0": 0.6943325470949332, + "r6.men.c1": 0.7516984305362697, + "zint.men.c1": 0.004354138806255288, + "d_anyzero.men.c1": 0.0464203246537008, + "q_atmax.men.c1": 0.20805696859142525, + "mpers.men.c1": 0.7831651821943473, + "r6.men.c2": 0.5192408208208362, + "zint.men.c2": 0.030165650190164137, + "d_anyzero.men.c2": 0.08077450502682551, + "q_atmax.men.c2": 0.09329613973394263, + "mpers.men.c2": 0.2790214156890242, + "r6.men": 0.637917378805517, + "zint.men": 0.031909547138841296, + "d_anyzero.men": 0.07794883469618924, + "q_atmax.men": 0.1749718539790638, + "mpers.men": 0.5855063816594349, + "r6.women.c0": 0.5668579888932699, + "zint.women.c0": 0.08305537586289401, + "d_anyzero.women.c0": 0.11030512461813208, + "q_atmax.women.c0": 0.03958788782863117, + "mpers.women.c0": 0.9506087093265538, + "r6.women.c1": 0.67658043603671, + "zint.women.c1": 0.07964810759571017, + "d_anyzero.women.c1": 0.1794570149404264, + "q_atmax.women.c1": 0.0297009561015539, + "mpers.women.c1": 0.15820877301409267, + "r6.women.c2": 0.5815850659325437, + "zint.women.c2": 0.025240796729521398, + "d_anyzero.women.c2": 0.11192525493718304, + "q_atmax.women.c2": 0.026368557271189592, + "mpers.women.c2": 0.0, + "r6.women": 0.6083411636208412, + "zint.women": 0.06264809339604187, + "d_anyzero.women": 0.13389579816524716, + "q_atmax.women": 0.03188580040045822, + "mpers.women": 0.36960582744688214, + "q_sexratio": 5.487453718632365 + } + }, + "bite_demonstrations": { + "bd1_persistence_loss_0.10": { + "fail_share": 0.44, + "cell_fail_share": { + "r6.men": 0.16, + "r6.women": 0.3 + }, + "n_perturbation_seeds": 50 + }, + "bd1_persistence_loss_0.05": { + "fail_share": 0.0, + "cell_fail_share": { + "r6.men": 0.0, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "bd2_sex_blind_donors": { + "fail_share": 0.0, + "cell_fail_share": { + "r6.men": 0.0, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "bd2c_same_sex_donors_control": { + "fail_share": 0.0, + "cell_fail_share": { + "r6.men": 0.0, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "bd3_top_tail_compression": { + "fail_share": 0.42, + "cell_fail_share": { + "r6.men": 0.42, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "bd4_participation_loss": { + "fail_share": 0.0, + "cell_fail_share": { + "r6.men": 0.0, + "r6.women": 0.0 + }, + "n_perturbation_seeds": 50 + }, + "requirements": { + "persistence": { + "bite": "bd1_persistence_loss_0.10", + "required_fail_share": 0.9, + "fail_share": 0.44, + "met": false + } + }, + "pause": true + }, + "ceremony_pause": true, + "tranche_r_epuf_reference": { + "note": "EPUF only. Report-only career tranche: the original four career statistics on true EPUF careers and on EPUF careers masked as the career assembler builds a PSID career (nothing before 1968; odd years from 1997 filled with the neighbour mean). The PSID side is computed once, after lock.", + "ages": [ + 22, + 61 + ], + "cells": { + "men.1930-1934": { + "epuf": { + "n_persons": 70660, + "zero_years": { + "mean": 13.868864987262949, + "p25": 2.0, + "p50": 8.0, + "p75": 25.0, + "p90": 39.0, + "share_10_or_more": 0.4651429380130201, + "share_all_40": 0.09602320973676762 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5782172197177455, + "n_pairs": 33809 + }, + "1994_2004": { + "spearman": 0.37918442395825036, + "n_pairs": 8984 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.46740013934045516, + "n_positive_person_years": 516720 + }, + "35-44": { + "share_at_max": 0.5189188334094634, + "n_positive_person_years": 505713 + }, + "45-54": { + "share_at_max": 0.28168440578661025, + "n_positive_person_years": 442055 + }, + "55-61": { + "share_at_max": 0.1655239045066384, + "n_positive_person_years": 256688 + } + }, + "aime_35yr_through_age_61": { + "p25": 403.0, + "p50": 1517.0, + "p75": 2451.0, + "p90": 2972.0999999999985, + "mean": 1496.0396971412397, + "share_zero": 0.10065100481177469 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 70660, + "zero_years": { + "mean": 23.7083215397679, + "p25": 15.0, + "p50": 20.0, + "p75": 34.0, + "p90": 40.0, + "share_10_or_more": 1.0, + "share_all_40": 0.15887347863005943 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5782172197177455, + "n_pairs": 33809 + }, + "1994_2004": { + "spearman": 0.37918442395825036, + "n_pairs": 8984 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.4707683475265525, + "n_positive_person_years": 10451 + }, + "35-44": { + "share_at_max": 0.5126409578800659, + "n_positive_person_years": 441976 + }, + "45-54": { + "share_at_max": 0.28168440578661025, + "n_positive_person_years": 442055 + }, + "55-61": { + "share_at_max": 0.1655239045066384, + "n_positive_person_years": 256688 + } + }, + "aime_35yr_through_age_61": { + "p25": 135.0, + "p50": 1000.0, + "p75": 1855.0, + "p90": 2401.0, + "mean": 1088.664265496745, + "share_zero": 0.1635578828191339 + } + } + }, + "men.1935-1939": { + "epuf": { + "n_persons": 71924, + "zero_years": { + "mean": 13.015516378399422, + "p25": 1.0, + "p50": 7.0, + "p75": 24.0, + "p90": 38.0, + "share_10_or_more": 0.4465825037539625, + "share_all_40": 0.0827540181302486 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.6448152280677847, + "n_pairs": 40517 + }, + "1994_2004": { + "spearman": 0.3430385542877868, + "n_pairs": 17307 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.4741670046615514, + "n_positive_person_years": 539949 + }, + "35-44": { + "share_at_max": 0.39699374332366855, + "n_positive_person_years": 511134 + }, + "45-54": { + "share_at_max": 0.2093870070750956, + "n_positive_person_years": 457803 + }, + "55-61": { + "share_at_max": 0.15327290962993553, + "n_positive_person_years": 271196 + } + }, + "aime_35yr_through_age_61": { + "p25": 548.0, + "p50": 1933.0, + "p75": 3180.0, + "p90": 3971.0, + "mean": 1965.8954451921472, + "share_zero": 0.08568767031866971 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 71924, + "zero_years": { + "mean": 19.67613035982426, + "p25": 10.0, + "p50": 15.0, + "p75": 30.0, + "p90": 40.0, + "share_10_or_more": 0.7852455369556754, + "share_all_40": 0.1204187753740059 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.6448152280677847, + "n_pairs": 40517 + }, + "1994_2004": { + "spearman": 0.3430385542877868, + "n_pairs": 17307 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.5093021332892343, + "n_positive_person_years": 217692 + }, + "35-44": { + "share_at_max": 0.39699374332366855, + "n_positive_person_years": 511134 + }, + "45-54": { + "share_at_max": 0.2093870070750956, + "n_positive_person_years": 457803 + }, + "55-61": { + "share_at_max": 0.12759454106016827, + "n_positive_person_years": 275145 + } + }, + "aime_35yr_through_age_61": { + "p25": 316.0, + "p50": 1547.5, + "p75": 2769.0, + "p90": 3629.0, + "mean": 1675.2360130137367, + "share_zero": 0.12386685946276625 + } + } + }, + "men.1940-1944": { + "epuf": { + "n_persons": 85938, + "zero_years": { + "mean": 12.859526635481394, + "p25": 1.0, + "p50": 7.0, + "p75": 24.0, + "p90": 38.0, + "share_10_or_more": 0.44158579440992346, + "share_all_40": 0.07283157625264726 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.646264405803841, + "n_pairs": 52149 + }, + "1994_2004": { + "spearman": 0.459118180816953, + "n_pairs": 35060 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.3897923679428147, + "n_positive_person_years": 644361 + }, + "35-44": { + "share_at_max": 0.26213208490341994, + "n_positive_person_years": 602143 + }, + "45-54": { + "share_at_max": 0.1982687936937196, + "n_positive_person_years": 556144 + }, + "55-61": { + "share_at_max": 0.15505817227620747, + "n_positive_person_years": 333836 + } + }, + "aime_35yr_through_age_61": { + "p25": 685.0, + "p50": 2419.0, + "p75": 4104.75, + "p90": 5266.0, + "mean": 2520.755649421676, + "share_zero": 0.07592683097116526 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 85938, + "zero_years": { + "mean": 15.666305941492704, + "p25": 5.0, + "p50": 10.0, + "p75": 26.0, + "p90": 39.0, + "share_10_or_more": 0.5098210337685308, + "share_all_40": 0.08992529498010193 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.646264405803841, + "n_pairs": 52149 + }, + "1994_2004": { + "spearman": 0.459118180816953, + "n_pairs": 35060 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.3969524096533309, + "n_positive_person_years": 570746 + }, + "35-44": { + "share_at_max": 0.26213208490341994, + "n_positive_person_years": 602143 + }, + "45-54": { + "share_at_max": 0.190118713204826, + "n_positive_person_years": 557478 + }, + "55-61": { + "share_at_max": 0.07738474076932603, + "n_positive_person_years": 347239 + } + }, + "aime_35yr_through_age_61": { + "p25": 560.0, + "p50": 2240.0, + "p75": 3962.0, + "p90": 5171.0, + "mean": 2401.2820870860387, + "share_zero": 0.09306709488235705 + } + } + }, + "women.1930-1934": { + "epuf": { + "n_persons": 68306, + "zero_years": { + "mean": 23.23403507744561, + "p25": 13.0, + "p50": 24.0, + "p75": 36.0, + "p90": 40.0, + "share_10_or_more": 0.816370450619272, + "share_all_40": 0.13789418206306914 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5505398027062716, + "n_pairs": 22989 + }, + "1994_2004": { + "spearman": 0.3718776181481541, + "n_pairs": 5942 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.07021585702373481, + "n_positive_person_years": 232654 + }, + "35-44": { + "share_at_max": 0.05917046049448984, + "n_positive_person_years": 301806 + }, + "45-54": { + "share_at_max": 0.021851518254839785, + "n_positive_person_years": 324188 + }, + "55-61": { + "share_at_max": 0.017649151107392805, + "n_positive_person_years": 199613 + } + }, + "aime_35yr_through_age_61": { + "p25": 38.0, + "p50": 306.5, + "p75": 847.0, + "p90": 1489.0, + "mean": 548.0144496823119, + "share_zero": 0.14960618393698943 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 68306, + "zero_years": { + "mean": 28.30464380874301, + "p25": 19.0, + "p50": 29.0, + "p75": 39.0, + "p90": 40.0, + "share_10_or_more": 1.0, + "share_all_40": 0.2301115568178491 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5505398027062716, + "n_pairs": 22989 + }, + "1994_2004": { + "spearman": 0.3718776181481541, + "n_pairs": 5942 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.03690652818991098, + "n_positive_person_years": 5392 + }, + "35-44": { + "share_at_max": 0.05844550747209552, + "n_positive_person_years": 269670 + }, + "45-54": { + "share_at_max": 0.021851518254839785, + "n_positive_person_years": 324188 + }, + "55-61": { + "share_at_max": 0.017649151107392805, + "n_positive_person_years": 199613 + } + }, + "aime_35yr_through_age_61": { + "p25": 1.0, + "p50": 182.0, + "p75": 673.0, + "p90": 1215.0, + "mean": 421.53147600503615, + "share_zero": 0.24476619916259187 + } + } + }, + "women.1935-1939": { + "epuf": { + "n_persons": 70451, + "zero_years": { + "mean": 21.490127890306738, + "p25": 10.0, + "p50": 21.0, + "p75": 34.0, + "p90": 40.0, + "share_10_or_more": 0.7701381101758669, + "share_all_40": 0.12092092376261515 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5678069951825434, + "n_pairs": 28608 + }, + "1994_2004": { + "spearman": 0.3491876980176582, + "n_pairs": 13174 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.06899211360541456, + "n_positive_person_years": 270973 + }, + "35-44": { + "share_at_max": 0.036601977764639054, + "n_positive_person_years": 345036 + }, + "45-54": { + "share_at_max": 0.0201991641353756, + "n_positive_person_years": 371352 + }, + "55-61": { + "share_at_max": 0.022266569103527794, + "n_positive_person_years": 225495 + } + }, + "aime_35yr_through_age_61": { + "p25": 74.0, + "p50": 470.0, + "p75": 1208.0, + "p90": 2057.0, + "mean": 781.0067848575605, + "share_zero": 0.12979233793700587 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 70451, + "zero_years": { + "mean": 24.921420561808915, + "p25": 15.0, + "p50": 24.0, + "p75": 37.0, + "p90": 40.0, + "share_10_or_more": 0.926629856212119, + "share_all_40": 0.1701324324707953 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.5678069951825434, + "n_pairs": 28608 + }, + "1994_2004": { + "spearman": 0.3491876980176582, + "n_pairs": 13174 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.06106601080114203, + "n_positive_person_years": 116284 + }, + "35-44": { + "share_at_max": 0.036601977764639054, + "n_positive_person_years": 345036 + }, + "45-54": { + "share_at_max": 0.0201991641353756, + "n_positive_person_years": 371352 + }, + "55-61": { + "share_at_max": 0.018220695121260816, + "n_positive_person_years": 229629 + } + }, + "aime_35yr_through_age_61": { + "p25": 26.0, + "p50": 367.0, + "p75": 1064.0, + "p90": 1857.0, + "mean": 678.7997473421243, + "share_zero": 0.18045166143844657 + } + } + }, + "women.1940-1944": { + "epuf": { + "n_persons": 82476, + "zero_years": { + "mean": 19.21534749502886, + "p25": 8.0, + "p50": 17.0, + "p75": 31.0, + "p90": 39.0, + "share_10_or_more": 0.7021072796934866, + "share_all_40": 0.09477908724962414 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.546182245657991, + "n_pairs": 36701 + }, + "1994_2004": { + "spearman": 0.49476689183611483, + "n_pairs": 28822 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.052185278891862794, + "n_positive_person_years": 368763 + }, + "35-44": { + "share_at_max": 0.023083785263827306, + "n_positive_person_years": 452872 + }, + "45-54": { + "share_at_max": 0.028517795651471264, + "n_positive_person_years": 482646 + }, + "55-61": { + "share_at_max": 0.02789890602071119, + "n_positive_person_years": 287574 + } + }, + "aime_35yr_through_age_61": { + "p25": 160.0, + "p50": 773.0, + "p75": 1776.0, + "p90": 2916.0, + "mean": 1152.5662738251128, + "share_zero": 0.10115670013094719 + } + }, + "epuf_masked_as_career_assembler": { + "n_persons": 82476, + "zero_years": { + "mean": 20.884584606430963, + "p25": 10.0, + "p50": 19.0, + "p75": 32.0, + "p90": 40.0, + "share_10_or_more": 0.7622823609292401, + "share_all_40": 0.11740385081720743 + }, + "rank_persistence_10yr": { + "1980_1990": { + "spearman": 0.546182245657991, + "n_pairs": 36701 + }, + "1994_2004": { + "spearman": 0.49476689183611483, + "n_pairs": 28822 + } + }, + "at_max_by_age": { + "25-34": { + "share_at_max": 0.05248869878734264, + "n_positive_person_years": 328947 + }, + "35-44": { + "share_at_max": 0.023083785263827306, + "n_positive_person_years": 452872 + }, + "45-54": { + "share_at_max": 0.026930145160957278, + "n_positive_person_years": 484290 + }, + "55-61": { + "share_at_max": 0.013535773352026223, + "n_positive_person_years": 301719 + } + }, + "aime_35yr_through_age_61": { + "p25": 114.0, + "p50": 698.0, + "p75": 1687.0, + "p90": 2806.0, + "mean": 1088.7474295552645, + "share_zero": 0.12386633687375721 + } + } + } + } + }, + "concept_deltas": [ + { + "delta": "deaths, departures and arrivals", + "direction": "EPUF records none of them, so an EPUF year without earnings may follow death or precede arrival", + "handling": "every statistic conditions on covered earnings at one or both ends of its span; what remains is in the bridge" + }, + { + "delta": "noncovered employment", + "direction": "PSID labor income counts it; EPUF shows no earnings (6.4 percent of 2006 workers were noncovered, Compson 2011 Table 3)", + "handling": "in the bridge; the repository's crosswalk is unbuilt" + }, + { + "delta": "frame", + "direction": "the PSID panel is heads and spouses of responding families who stay through 2006; EPUF is every Social Security number issued before 2007", + "handling": "in the bridge; cells are within sex and cohort band" + }, + { + "delta": "reporting", + "direction": "PSID earnings are survey reports and EPUF's are employer and tax filings; whether that lowers the PSID's rank persistence is measured by the r6 bridge, not assumed", + "handling": "in the bridge" + }, + { + "delta": "birth year", + "direction": "the PSID birth year is derived from age at interview and can sit one year below EPUF's year of birth", + "handling": "nine-year cohort bands; in the bridge" + }, + { + "delta": "posting", + "direction": "EPUF 2005-2006 are short from late posting and 1998-2004 drift down slightly against the Supplement (Compson 2012)", + "handling": "the window ends in 2004; the drift is in the bridge" + }, + { + "delta": "disclosure", + "direction": "EPUF values are bottom-coded, banded and rounded", + "handling": "the same operator is applied to PSID-side earnings" + } + ], + "revision_pins": { + "head_sha": "eec910d61a7e0afe21995957740e03d64acdffdc", + "origin_master_sha": "75cd35245f1a0c12e7a23b048a7d126c74ad8ecb", + "derivation_core_sha256": { + "src/populace_dynamics/data/epuf.py": "b101210f7aec5e52fe21d83cd8037af2abc591ec4649c4320fac4367c1b2fd4d", + "src/populace_dynamics/harness/epuf_operator.py": "dc46c3fdc7743aedbe6ced575f6c7878e5b28443f52c7e13575c2e481de27b74", + "src/populace_dynamics/harness/epuf_cells.py": "b76a9dc338898284bb9558099c0264573eda547baa8b301fc9700a8905245c06", + "src/populace_dynamics/harness/epuf_gate.py": "03b4ba1df0eaf91bebc2367f239a8e6be3b2041d0f345c54c64ea8222db3a550", + "scripts/build_epuf_gate_floors.py": "448937d4ad251bec90f76b6135fe7108251a11fc05a6ef7bb042ca0c97ea21a2" + } + }, + "elapsed_seconds": 420.6 +} diff --git a/runs/epuf_gate_supplement_v1.json b/runs/epuf_gate_supplement_v1.json new file mode 100644 index 00000000..afa03a20 --- /dev/null +++ b/runs/epuf_gate_supplement_v1.json @@ -0,0 +1,965 @@ +{ + "schema_version": "epuf_gate_supplement.v1", + "run": "epuf_gate_supplement_v1", + "status": "REFEREE_ROUND_1_SUPPLEMENT", + "built_utc": "2026-10-02T20:55:52+00:00", + "floor_run": "runs/epuf_gate_floors_v1.json", + "floor_run_sha256": "33e75b96199ce748f0b9aaab0d77d1925405eede93d5e883fa329fde4d87e686", + "candidate_blind": { + "generated_candidates": 0 + }, + "bites": { + "bd1_persistence_loss_0.10": { + "fail_share_reproduced": 0.44, + "cells": { + "r6.men": { + "estimates_over_perturbation_seeds": [ + 0.5923556074312948, + 0.6071611919614812, + 0.5978617597445781, + 0.5724344887598866, + 0.5859877560615201, + 0.5957944062985611, + 0.6221279877980355, + 0.5891590292019118, + 0.6064882268784677, + 0.5899522401622763, + 0.6337736211254855, + 0.6010346988292776, + 0.5979863687191552, + 0.6177892746304151, + 0.6054430373960562, + 0.6058541450329126, + 0.5927044190255868, + 0.6150047065822098, + 0.6020637313386004, + 0.5916791734385692, + 0.5729800579056249, + 0.5990150471903852, + 0.58525598069942, + 0.5730482389387, + 0.59862281408879, + 0.5660125579190576, + 0.606212007107718, + 0.6057682138244861, + 0.6078010062357987, + 0.6104225653811912, + 0.5972859691048475, + 0.5815293447360345, + 0.5947014039241244, + 0.6105461001028126, + 0.6351780849657661, + 0.590984895524415, + 0.6160121858064789, + 0.6141147385811372, + 0.6046119623788956, + 0.6033859432590736, + 0.6096324345762685, + 0.617666644192961, + 0.6181532694059244, + 0.5884579589676284, + 0.6037229911021301, + 0.598170234098739, + 0.601205069728621, + 0.5975696649244217, + 0.5889452238952735, + 0.60546050631192 + ], + "real_gate_holdout_estimate": 0.6670465436202722, + "mean_shift": -0.06654396391437367, + "power_under_gate_noise_model": 0.3039109309521529 + }, + "r6.women": { + "estimates_over_perturbation_seeds": [ + 0.5672768886528738, + 0.5525156821580056, + 0.5722464712840242, + 0.5690293193383877, + 0.5811276249742666, + 0.5513156669764558, + 0.570512730161193, + 0.5552526068609532, + 0.5546284694876523, + 0.5800798902080182, + 0.5855614507796476, + 0.571220427536961, + 0.5640047327469548, + 0.5425043010596535, + 0.5692971323429362, + 0.5495346653181574, + 0.5707267161582226, + 0.5559382377285156, + 0.5728224738563782, + 0.5457454388662194, + 0.5795534888352817, + 0.5604932655945547, + 0.5923394875778772, + 0.6038920558139306, + 0.5510026931596977, + 0.5485206007108029, + 0.5647658226174728, + 0.5569226201674455, + 0.6020892439767127, + 0.5825484695215449, + 0.5787151645588856, + 0.587388713838193, + 0.5480651532709707, + 0.5664159512378253, + 0.5597631375761125, + 0.587011368780401, + 0.5819263230590885, + 0.5933802133837037, + 0.5876301246953135, + 0.5897171897472379, + 0.5669757485959178, + 0.5717028756779544, + 0.5765742969015433, + 0.5783093882223461, + 0.5787883858344222, + 0.5611918283266737, + 0.5927056935962701, + 0.5416550288220051, + 0.5899776638985268, + 0.5677236795515136 + ], + "real_gate_holdout_estimate": 0.6273350404581282, + "mean_shift": -0.05675330837721404, + "power_under_gate_noise_model": 0.18800303864617685 + } + } + }, + "bd1_persistence_loss_0.05": { + "fail_share_reproduced": 0.0, + "cells": { + "r6.men": { + "estimates_over_perturbation_seeds": [ + 0.6409750582088398, + 0.6474110504142504, + 0.6174054367792089, + 0.6247042082694905, + 0.6377803680205764, + 0.6191871349907039, + 0.6347984480979372, + 0.6362535893367012, + 0.6431209133987446, + 0.6399981983637179, + 0.6404495013993383, + 0.6284355499212884, + 0.615234054238924, + 0.6292740465932023, + 0.6365568192954434, + 0.6310784671820853, + 0.6365043607519216, + 0.6304201452004319, + 0.6366376291487114, + 0.6410151193136292, + 0.6312526167163951, + 0.6194858532904569, + 0.6437394763799247, + 0.6420634176704947, + 0.6223371394354594, + 0.6417570185495974, + 0.6271206592534122, + 0.629596165440204, + 0.645426475775039, + 0.6296201042310459, + 0.6344966426551988, + 0.642645950820744, + 0.6261857335148884, + 0.6177966087304092, + 0.6238510245525499, + 0.6409240108705532, + 0.6326445083739769, + 0.6367796151440489, + 0.6198285631235921, + 0.6394655889641212, + 0.6410628656180953, + 0.6415570608427397, + 0.6334318256184138, + 0.6377318418009892, + 0.6410170147775001, + 0.6375116179642668, + 0.6224712157233483, + 0.6342347521436908, + 0.6462446440679368, + 0.6352689790193089 + ], + "real_gate_holdout_estimate": 0.6670465436202722, + "mean_shift": -0.0333507618204012, + "power_under_gate_noise_model": 0.03137294478904317 + }, + "r6.women": { + "estimates_over_perturbation_seeds": [ + 0.5893378514028863, + 0.6058477516927409, + 0.5995152610595739, + 0.5946216398697298, + 0.595467742853605, + 0.5983843101987303, + 0.6003760676419267, + 0.5899081608305784, + 0.6024173419223324, + 0.5876876143206695, + 0.5972027723299896, + 0.6002470488016955, + 0.5991896071341655, + 0.6049400537583285, + 0.5996825210810371, + 0.6019534941323477, + 0.6052948543679659, + 0.6020200687301219, + 0.6033835086034096, + 0.6000593572048605, + 0.5820261854617766, + 0.5949543745859723, + 0.5898938001252603, + 0.6043652443631577, + 0.60344850623347, + 0.5980971314439019, + 0.5900090123591097, + 0.598051163032738, + 0.5875936935211727, + 0.5918612924491464, + 0.5995247777687709, + 0.5998463887884306, + 0.5984063815307475, + 0.6008539872718184, + 0.5913771229328634, + 0.5882192080632919, + 0.6146368840640243, + 0.6046275295975513, + 0.5941719096659768, + 0.5948355482344667, + 0.6000351965612885, + 0.5871664579508504, + 0.5914500017010246, + 0.6021855919417225, + 0.5877015338731928, + 0.6026654373250748, + 0.5961512177490491, + 0.6062396538671267, + 0.5959490917503085, + 0.6028032400597286 + ], + "real_gate_holdout_estimate": 0.6273350404581282, + "mean_shift": -0.02980134861393391, + "power_under_gate_noise_model": 0.024226495163577902 + } + } + }, + "bd2_sex_blind_donors": { + "fail_share_reproduced": 0.0, + "cells": { + "r6.men": { + "estimates_over_perturbation_seeds": [ + 0.7153950861353064, + 0.7370653330927845, + 0.7035650507778921, + 0.7144474151657335, + 0.7304769759262658, + 0.7530170061516803, + 0.7321445509364631, + 0.7098622922594803, + 0.7177726352580469, + 0.7372403879685606, + 0.742469589652152, + 0.7409452090188042, + 0.7095520186315777, + 0.6999010463044041, + 0.683712567796268, + 0.7112163486932499, + 0.7362858237053254, + 0.705185041484422, + 0.7452320751955938, + 0.7324858819379839, + 0.7240962294437366, + 0.7128881952366184, + 0.7549801573464814, + 0.7414648913691136, + 0.7298072785490497, + 0.7214771131752182, + 0.7493222899169527, + 0.707413332105844, + 0.7229774758990458, + 0.7192330856746771, + 0.6963031744092893, + 0.7091025325470135, + 0.7036336420328437, + 0.716509556578629, + 0.6912224996103169, + 0.7270500335758749, + 0.7464517355162836, + 0.7200901708659241, + 0.7207503221022613, + 0.7321933163143234, + 0.7263011980168408, + 0.7356217839545882, + 0.7048895801315306, + 0.7486673663894499, + 0.7250778787246253, + 0.7018815927749377, + 0.7516520134755222, + 0.730806970909791, + 0.7141326678289547, + 0.7115351682831353 + ], + "real_gate_holdout_estimate": 0.6670465436202722, + "mean_shift": 0.05606356815674518, + "power_under_gate_noise_model": 0.0037934393148943593 + }, + "r6.women": { + "estimates_over_perturbation_seeds": [ + 0.6255966828636164, + 0.6275555920574895, + 0.6281399533026925, + 0.6260039645952258, + 0.6105412185000044, + 0.5978595699145013, + 0.6275121903494605, + 0.6306911522736799, + 0.625859730988398, + 0.5997551124441413, + 0.6273563494477012, + 0.6132521980967177, + 0.6083122283553981, + 0.6148110115752243, + 0.6345409323905672, + 0.588868269651943, + 0.6320576157375684, + 0.6254160145132974, + 0.6135454461727925, + 0.6007444427358448, + 0.6563650321994557, + 0.6387767221390684, + 0.6404941159022517, + 0.6493457703717841, + 0.6095323274691222, + 0.6108119773478011, + 0.6616144996151829, + 0.6060321227830445, + 0.6097820743983396, + 0.6187277009171724, + 0.6425537823001654, + 0.6137145846642138, + 0.6065313061342027, + 0.6112195332161333, + 0.6393385326250282, + 0.6538782208281109, + 0.5988440936404312, + 0.5946414027674801, + 0.6325940067101765, + 0.5910466310990574, + 0.6183157562227156, + 0.6629488539583346, + 0.6018892253484041, + 0.6329467426917842, + 0.6094296968928011, + 0.6116295276678021, + 0.6154309676169256, + 0.6017014210545862, + 0.6613682631796018, + 0.6143377963037767 + ], + "real_gate_holdout_estimate": 0.6273350404581282, + "mean_shift": -0.0058497931775038925, + "power_under_gate_noise_model": 0.0016406415135619072 + } + } + }, + "bd2c_same_sex_donors_control": { + "fail_share_reproduced": 0.0, + "cells": { + "r6.men": { + "estimates_over_perturbation_seeds": [ + 0.6761335387704364, + 0.6823434522549541, + 0.674667757978237, + 0.6865065200671548, + 0.6794903684046517, + 0.6936011183837327, + 0.6562476986801798, + 0.6975758324632426, + 0.7024167575973106, + 0.6748361994360426, + 0.6849533552386975, + 0.6708323828068654, + 0.6286105986368329, + 0.6834442373516043, + 0.6507811508029542, + 0.6495391867363967, + 0.7060976589217143, + 0.6648131277113685, + 0.7077723744274611, + 0.6951752258367396, + 0.6870330986474561, + 0.666232004335718, + 0.6844594444012121, + 0.6531447446242681, + 0.6892888199055398, + 0.6610545725657526, + 0.6636342176426794, + 0.677735019786468, + 0.6700466775171937, + 0.6688038351912888, + 0.7097355421495779, + 0.6433199833213952, + 0.6638696455950001, + 0.6462842908192431, + 0.6332304265424927, + 0.6929677386691883, + 0.6835012196214301, + 0.6746618487743892, + 0.667277045867075, + 0.6745264949719494, + 0.6445881004674809, + 0.6825288796233381, + 0.6783959441972309, + 0.6845650284709408, + 0.6681682871161599, + 0.6539114794484223, + 0.6760777072234152, + 0.6581801166268575, + 0.695135221925521, + 0.700536780221383 + ], + "real_gate_holdout_estimate": 0.6670465436202722, + "mean_shift": 0.007328111555260808, + "power_under_gate_noise_model": 0.0002234208996335321 + }, + "r6.women": { + "estimates_over_perturbation_seeds": [ + 0.6416662493362032, + 0.623976823528731, + 0.6304156318590677, + 0.6239654120053894, + 0.6304607769690309, + 0.6667476036891037, + 0.6500472516668002, + 0.6299337104446504, + 0.6757891285643998, + 0.6769716231345546, + 0.6555691280782053, + 0.6692761036264944, + 0.6074921564207167, + 0.6388113186105824, + 0.6308906579032595, + 0.6113326051347121, + 0.6338397582331823, + 0.6451681093599267, + 0.6461835491118108, + 0.6604115338881542, + 0.6564380318652958, + 0.6639722965426451, + 0.6235061783115834, + 0.653248879878228, + 0.6716044225852134, + 0.6239560730741309, + 0.6157895438395329, + 0.6294288278834641, + 0.6039566972900559, + 0.6503767558417166, + 0.6271756039318566, + 0.6273170472151424, + 0.6389001952620804, + 0.6219797449566665, + 0.6635323354727409, + 0.6664689434261482, + 0.6060672928267848, + 0.5969663769248927, + 0.6160601331977598, + 0.6298981291707675, + 0.6460919001267953, + 0.6424159075942499, + 0.6375532409016837, + 0.6201095854176167, + 0.6335422832646428, + 0.636442822998477, + 0.6240312712120062, + 0.6208508549837559, + 0.6599469937285436, + 0.6185605883553231 + ], + "real_gate_holdout_estimate": 0.6273350404581282, + "mean_shift": 0.010167721334767288, + "power_under_gate_noise_model": 0.00019361590779055072 + } + } + }, + "bd3_top_tail_compression": { + "fail_share_reproduced": 0.42, + "cells": { + "r6.men": { + "estimates_over_perturbation_seeds": [ + 0.5798220029987741, + 0.5846062677294976, + 0.5960441062580587, + 0.592301968549996, + 0.5962883463958693, + 0.5934349304389787, + 0.5805627676041607, + 0.599415900074699, + 0.6082005064159525, + 0.576896954928045, + 0.5993404889133045, + 0.5856515207620114, + 0.5808549465730601, + 0.582159276971016, + 0.5977526798348524, + 0.5858187549510461, + 0.588481165220995, + 0.593199836421247, + 0.5816187339463432, + 0.5961880579677423, + 0.5872134040154153, + 0.5862823740946692, + 0.5949719147038374, + 0.5917618181290782, + 0.5995282125350574, + 0.5959868267436695, + 0.5860744455525585, + 0.5911686545446765, + 0.5945304723917568, + 0.5924642106406525, + 0.5981002184957689, + 0.6079924623171472, + 0.5914422683764399, + 0.5990499018455276, + 0.5960148746064251, + 0.5865320894528399, + 0.5874234134355608, + 0.5778416219184482, + 0.5998236360776552, + 0.5911492065346597, + 0.5914968492002735, + 0.5772158511638948, + 0.6103309783585508, + 0.5944455675110977, + 0.5867752026185494, + 0.5974710542602479, + 0.5947404719967178, + 0.584856496255865, + 0.5800627608684998, + 0.5828807326977913 + ], + "real_gate_holdout_estimate": 0.6670465436202722, + "mean_shift": -0.07596119953429248, + "power_under_gate_noise_model": 0.44796665721804707 + }, + "r6.women": { + "estimates_over_perturbation_seeds": [ + 0.6199468374976621, + 0.6186131534625089, + 0.6240417497513674, + 0.625117640388975, + 0.6192208842365626, + 0.6218779356149076, + 0.6259628844196214, + 0.6287008491466276, + 0.6229463227366054, + 0.6238997961049644, + 0.6199734024002126, + 0.6220236024488845, + 0.6202493832776335, + 0.6270659695720333, + 0.6201813738227636, + 0.621585870338773, + 0.6221590814042371, + 0.622497468277916, + 0.6174103131912325, + 0.6231321427082539, + 0.6205630175949021, + 0.6200090882435889, + 0.6257524923910419, + 0.6191516114999477, + 0.6206890659190105, + 0.6259476691099463, + 0.6252593893354802, + 0.6204985525314201, + 0.6208978640958024, + 0.6284665235221458, + 0.6252694823266617, + 0.6217965194267202, + 0.6242665658865489, + 0.62157967733388, + 0.6235629740103195, + 0.625095295249259, + 0.6204040242114544, + 0.620873109559793, + 0.6264490161205438, + 0.6228960042758768, + 0.6209760298492116, + 0.6197632207514895, + 0.6209927644099572, + 0.6189768326875759, + 0.619602110887437, + 0.6249376872185505, + 0.6270239955113669, + 0.6216915033899156, + 0.6243195128371027, + 0.6219216259993829 + ], + "real_gate_holdout_estimate": 0.6273350404581282, + "mean_shift": -0.0048102427183666085, + "power_under_gate_noise_model": 0.0014321067535039594 + } + } + }, + "bd4_participation_loss": { + "fail_share_reproduced": 0.0, + "cells": { + "r6.men": { + "estimates_over_perturbation_seeds": [ + 0.6620013767950192, + 0.6704456660582487, + 0.6684666827143908, + 0.6709681382265866, + 0.6659600535612956, + 0.6662748169189815, + 0.6681154045969351, + 0.6719452955909533, + 0.677362496758312, + 0.667022701657474, + 0.6680309326775706, + 0.6777456690002519, + 0.6656216058215625, + 0.6638327403508775, + 0.6658342258635395, + 0.6695467962999542, + 0.6721991983190925, + 0.659676656450425, + 0.6682680253176845, + 0.6696996949044792, + 0.6632854526398495, + 0.667734841718427, + 0.6801250297611072, + 0.6647741490134169, + 0.6665324979703295, + 0.6659641858747433, + 0.6621450917401062, + 0.6632912060219094, + 0.6649207673457398, + 0.6658883738584944, + 0.6703522521014662, + 0.6698733974208289, + 0.668726643260144, + 0.6649324514651596, + 0.6708622767042317, + 0.6636199731073636, + 0.6684862613761912, + 0.6728902567779388, + 0.667145529157907, + 0.6665612922214225, + 0.6665366671803681, + 0.6659824780438451, + 0.6616027146549299, + 0.6672796675552283, + 0.6672902963741667, + 0.6775822331555802, + 0.6694067729758396, + 0.6690556316830161, + 0.6646654115163818, + 0.6656944568461471 + ], + "real_gate_holdout_estimate": 0.6670465436202722, + "mean_shift": 0.0007979851278460126, + "power_under_gate_noise_model": 0.0005823797606719133 + }, + "r6.women": { + "estimates_over_perturbation_seeds": [ + 0.6220638782386041, + 0.6250342612599513, + 0.6321173973006279, + 0.6251557035870132, + 0.6332095031763649, + 0.6258352041707519, + 0.6308474820557787, + 0.6344953095624237, + 0.6305660083850215, + 0.6268020921974279, + 0.6250046992945462, + 0.6285650241178421, + 0.6235012081086688, + 0.6276096687370536, + 0.624177628832131, + 0.6188210527350243, + 0.6237239717444607, + 0.624988822776033, + 0.6305926803474363, + 0.6273022066646086, + 0.6224571482238876, + 0.6243519239085569, + 0.6285938659899117, + 0.6321207423573043, + 0.6248231905113933, + 0.6261058228291413, + 0.6246609412572002, + 0.6274227698012017, + 0.629897855877032, + 0.6264048958603077, + 0.625281933356596, + 0.6282137987830849, + 0.6289702351314833, + 0.6246629735535064, + 0.6324862902880063, + 0.6274490863774081, + 0.6249125757867608, + 0.6227952062640644, + 0.6221657636182293, + 0.6251107729724195, + 0.6175516198513791, + 0.6298563420279066, + 0.6264978703183096, + 0.6301126742811206, + 0.6229011634044149, + 0.6280770948420803, + 0.6322696760283177, + 0.6273947268317961, + 0.6322024818973843, + 0.6254301130745673 + ], + "real_gate_holdout_estimate": 0.6273350404581282, + "mean_shift": -0.0005031332861973326, + "power_under_gate_noise_model": 0.0008030587192465796 + } + } + }, + "detection_points": { + "r6.men": { + "distance_from_psid_to_lower_edge": 0.07918250134976323, + "realized_sigma": 0.024627640081819575, + "shortfall_failing_80_percent": 0.09990912324262259, + "shortfall_failing_90_percent": 0.1107452848786232 + }, + "r6.women": { + "distance_from_psid_to_lower_edge": 0.07868155370616549, + "realized_sigma": 0.02476986454942573, + "shortfall_failing_80_percent": 0.09952787171096218, + "shortfall_failing_90_percent": 0.11042661211270952 + } + } + }, + "birth_year_mix": { + "men.c0": { + "birth_years": [ + 1947, + 1948, + 1949, + 1950, + 1951, + 1952, + 1953, + 1954, + 1955 + ], + "psid_support_weighted_share": [ + 0.11712789799218337, + 0.10721668173541399, + 0.10310416687768334, + 0.10091619807409358, + 0.1060761196372529, + 0.11039328062758937, + 0.1237442227945775, + 0.1203869320136418, + 0.11103450024756416 + ], + "epuf_share": [ + 0.10774548513276858, + 0.10438547704300902, + 0.10570925588001416, + 0.10557595870545461, + 0.10994718674014865, + 0.11251660469114125, + 0.11400125942847687, + 0.11862988890369969, + 0.12148888347528716 + ], + "psid_mean_birth_year": 1951.065894354244, + "epuf_mean_birth_year": 1951.1212314820348 + }, + "men.c1": { + "birth_years": [ + 1956, + 1957, + 1958, + 1959, + 1960, + 1961, + 1962, + 1963, + 1964 + ], + "psid_support_weighted_share": [ + 0.11050546306111324, + 0.11718909548517067, + 0.11311945115841066, + 0.12602510965891073, + 0.12075013703296184, + 0.10264883807489189, + 0.0970746913735447, + 0.12266150792914061, + 0.09002570622585566 + ], + "epuf_share": [ + 0.10956233112734377, + 0.11278343014343702, + 0.1121416629536824, + 0.11132821282144566, + 0.11241962581293917, + 0.11165522794998303, + 0.11133638819965909, + 0.11009373071121703, + 0.10867939028029285 + ], + "psid_mean_birth_year": 1959.8790324188374, + "epuf_mean_birth_year": 1959.9871156039353 + }, + "men.c2": { + "birth_years": [ + 1965, + 1966, + 1967, + 1968, + 1969, + 1970, + 1971, + 1972, + 1973 + ], + "psid_support_weighted_share": [ + 0.11287135042723423, + 0.12919152088185798, + 0.11896376580823616, + 0.10956730403133158, + 0.1546859543857886, + 0.09303209958691612, + 0.10316120173228663, + 0.0821845946930787, + 0.09634220845326998 + ], + "epuf_share": [ + 0.11769619142721156, + 0.11281532014969249, + 0.11087883680344927, + 0.11167209504166939, + 0.1127453267757319, + 0.11654363386932703, + 0.11192407118792755, + 0.10545201720903755, + 0.10027250753595326 + ], + "psid_mean_birth_year": 1968.7447223209415, + "epuf_mean_birth_year": 1968.9151773632098 + }, + "women.c0": { + "birth_years": [ + 1947, + 1948, + 1949, + 1950, + 1951, + 1952, + 1953, + 1954, + 1955 + ], + "psid_support_weighted_share": [ + 0.0946920547727903, + 0.11511304032551242, + 0.10344816171667051, + 0.10637718411820407, + 0.1181124210553918, + 0.10753478631935529, + 0.10509314462589263, + 0.114599826947071, + 0.13502938011911197 + ], + "epuf_share": [ + 0.10725473548613754, + 0.10441978706170527, + 0.10600560158483864, + 0.10551765865464376, + 0.10960662040967688, + 0.1124854836978267, + 0.11469098574230759, + 0.11868235891130173, + 0.12133676845156191 + ], + "psid_mean_birth_year": 1951.1642572292697, + "epuf_mean_birth_year": 1951.1234544407687 + }, + "women.c1": { + "birth_years": [ + 1956, + 1957, + 1958, + 1959, + 1960, + 1961, + 1962, + 1963, + 1964 + ], + "psid_support_weighted_share": [ + 0.09457775902068434, + 0.10155665558093137, + 0.13204889984029605, + 0.11289767541484805, + 0.10323087271040733, + 0.13096706982205916, + 0.12706245599226856, + 0.10594014924100936, + 0.09171846237749579 + ], + "epuf_share": [ + 0.10865794038795143, + 0.11211428271040319, + 0.11191277225814365, + 0.1120003854982565, + 0.11267062678511977, + 0.1117112618058841, + 0.11207923741435806, + 0.11036639857015192, + 0.10848709456973138 + ], + "psid_mean_birth_year": 1960.0098098011188, + "epuf_mean_birth_year": 1959.9941167709264 + }, + "women.c2": { + "birth_years": [ + 1965, + 1966, + 1967, + 1968, + 1969, + 1970, + 1971, + 1972, + 1973 + ], + "psid_support_weighted_share": [ + 0.13857824343625616, + 0.11107368468897696, + 0.09816752120657735, + 0.11275713581469775, + 0.1381592068838578, + 0.14231142451250936, + 0.10533674298287174, + 0.08743792758201299, + 0.06617811289223988 + ], + "epuf_share": [ + 0.11770075708714936, + 0.11288338079598337, + 0.11038787072960181, + 0.11028368442464354, + 0.11398974012958792, + 0.11659935900616188, + 0.11172244768359116, + 0.1042954525158512, + 0.10213730762742977 + ], + "psid_mean_birth_year": 1968.6833849387533, + "epuf_mean_birth_year": 1968.9209672458103 + } + } +} diff --git a/runs/epuf_gate_supplement_v1.json.env.json b/runs/epuf_gate_supplement_v1.json.env.json new file mode 100644 index 00000000..cef6af18 --- /dev/null +++ b/runs/epuf_gate_supplement_v1.json.env.json @@ -0,0 +1,19 @@ +{ + "environment": { + "python": "3.14.7", + "numpy": "2.5.3", + "pandas": "3.0.6", + "sklearn": "1.9.1", + "scipy": "1.18.1", + "platform": "macOS-26.6.2-arm64-arm-64bit-Mach-O", + "fitting_stack": { + "populace_fit": "absent", + "populace_frame": "absent" + } + }, + "contract": { + "blob_sha": "b0c39af1e13a705f90b85d3e6b9a91e1d3c5485c", + "head_sha": "246eab025107d70deb5efe1209089c0cd37d438a", + "path": "gates.yaml" + } +} diff --git a/scripts/build_epuf_gate_supplement.py b/scripts/build_epuf_gate_supplement.py new file mode 100644 index 00000000..973779e8 --- /dev/null +++ b/scripts/build_epuf_gate_supplement.py @@ -0,0 +1,231 @@ +"""Supplement to the EPUF gate's floor artifact, for the referee round. + +Round 1 of the referee review (``reviews/gate_epuf_round1_referee_20261002.md``) +asked for three things the floor artifact does not store: + +1. **Bite shifts.** Each bite demonstration's per-seed estimates on the 20 + gate holdouts and its mean shift from the unperturbed real holdouts, for + every cell the registered rules selected, and the bite's power under the + gate's own noise model: the probability that a candidate centred at the + PSID's position moved by that shift falls outside the cell's interval, + with the cell's realised sigma. The fail shares in the floor artifact + perturb the realised sample and score it on fixed holdouts, so they omit + the noise the 20 seeds share. +2. **Birth years.** The support's birth-year distribution within each sex and + cohort band beside EPUF's, because the PSID birth year (derived from age + at interview) sits about half a year below EPUF's year of birth. +3. **A build timestamp** (UTC). + +The bite perturbations, splits, support and cells are imported unchanged +from ``scripts/build_epuf_gate_floors.py``; the script asserts that it +reproduces the floor artifact's fail shares exactly, so the shifts belong to +the same computation. It reads the real PSID only through the existing +loaders the floor builder uses, and generates no candidate. + +Usage:: + + uv run python scripts/build_epuf_gate_supplement.py +""" + +from __future__ import annotations + +import datetime as dt +import hashlib +import importlib.util +import json +import sys +from pathlib import Path + +import numpy as np +from scipy.stats import norm + +from populace_dynamics.artifacts import write_new +from populace_dynamics.data import epuf +from populace_dynamics.harness import epuf_gate as gate +from populace_dynamics.harness.epuf_cells import ( + COHORT_BANDS, + SEXES, + WindowArrays, +) + +ROOT = Path(__file__).resolve().parents[1] +FLOORS = ROOT / "runs" / "epuf_gate_floors_v1.json" +ARTIFACT = ROOT / "runs" / "epuf_gate_supplement_v1.json" +SCHEMA_VERSION = "epuf_gate_supplement.v1" + + +def _builder(): + name = "build_epuf_gate_floors" + if name in sys.modules: + return sys.modules[name] + spec = importlib.util.spec_from_file_location( + name, ROOT / "scripts" / f"{name}.py" + ) + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + spec.loader.exec_module(module) + return module + + +def power_against_shift( + shift: float, bridge: float, sigma: float, lower: float, upper: float +) -> float: + """Probability that a candidate at the PSID's position plus ``shift`` + falls outside ``[lower, upper]``, under the cell's normal noise.""" + centre = bridge + shift + return float( + norm.cdf((lower - centre) / sigma) + norm.sf((upper - centre) / sigma) + ) + + +def bite_shifts(builder, frame, universe, floors) -> dict[str, object]: + """Per-seed estimates and shifts of every bite, on the selected cells.""" + registered = floors["registered"] + cells = floors["cells"] + position = np.searchsorted(universe, frame["person_id"].to_numpy()) + masks = { + seed: builder.holdout_mask( + universe, seed=seed, fraction=gate.HOLDOUT_FRACTION + )[position] + for seed in gate.GATE_SEEDS + } + wage_bases = builder.wage_bases() + real = WindowArrays(frame, wage_bases=wage_bases) + real_values = { + seed: builder._values(real.cells(mask)) for seed, mask in masks.items() + } + real_estimate = { + cell_id: gate.pooled_estimate( + cell_id, [real_values[s][cell_id] for s in gate.GATE_SEEDS] + ) + for cell_id in registered + } + perturbations = { + f"bd1_persistence_loss_{share:.2f}": ( + lambda f, r, share=share: builder.perturb_persistence(f, r, share) + ) + for share in builder.BD1_SHARES + } + perturbations["bd2_sex_blind_donors"] = ( + lambda f, r: builder.perturb_sex_blind(f, r, same_sex=False) + ) + perturbations["bd2c_same_sex_donors_control"] = ( + lambda f, r: builder.perturb_sex_blind(f, r, same_sex=True) + ) + perturbations["bd3_top_tail_compression"] = builder.perturb_top_tail + perturbations["bd4_participation_loss"] = builder.perturb_participation + + out: dict[str, object] = {} + for index, (name, perturb) in enumerate(perturbations.items()): + per_cell = {cell_id: [] for cell_id in registered} + fails = 0 + for seed in builder.BITE_SEEDS: + rng = np.random.default_rng([builder.BITE_SEED_BASE, index, seed]) + arrays = WindowArrays(perturb(frame, rng), wage_bases=wage_bases) + per_seed = { + s: builder._values(arrays.cells(mask)) + for s, mask in masks.items() + } + scored = gate.score_run(per_seed, registered) + fails += not scored["pass"] + for cell_id in registered: + per_cell[cell_id].append(scored["cells"][cell_id]["estimate"]) + fail_share = fails / len(builder.BITE_SEEDS) + recorded = floors["bite_demonstrations"][name]["fail_share"] + if fail_share != recorded: + raise AssertionError( + f"{name}: fail share {fail_share} is not the floor " + f"artifact's {recorded}; not the same computation" + ) + rows = {} + for cell_id, estimates in per_cell.items(): + cell = cells[cell_id] + shift = float(np.mean(estimates) - real_estimate[cell_id]) + rows[cell_id] = { + "estimates_over_perturbation_seeds": estimates, + "real_gate_holdout_estimate": real_estimate[cell_id], + "mean_shift": shift, + "power_under_gate_noise_model": power_against_shift( + shift, + cell["bridge_psid_minus_epuf"], + cell["floor"]["realized_sigma"], + cell["lower"], + cell["upper"], + ), + } + out[name] = {"fail_share_reproduced": fail_share, "cells": rows} + detection = {} + for cell_id in registered: + cell = cells[cell_id] + sigma = cell["floor"]["realized_sigma"] + distance = cell["bridge_psid_minus_epuf"] - cell["lower"] + detection[cell_id] = { + "distance_from_psid_to_lower_edge": distance, + "realized_sigma": sigma, + "shortfall_failing_80_percent": distance + 0.8416 * sigma, + "shortfall_failing_90_percent": distance + 1.2816 * sigma, + } + out["detection_points"] = detection + return out + + +def birth_years(frame, demographic) -> dict[str, object]: + """Within-band birth-year shares: PSID support (weighted) and EPUF.""" + out = {} + labels = {1: "men", 2: "women"} + for sex in SEXES: + code = next(k for k, v in labels.items() if v == sex) + for band, (low, high) in COHORT_BANDS.items(): + years = list(range(low, high + 1)) + psid = frame[ + (frame["sex"] == sex) & frame["birth_year"].between(low, high) + ] + psid_share = ( + psid.groupby("birth_year")["weight"].sum().reindex(years) + ).fillna(0.0) + psid_share = psid_share / psid_share.sum() + epuf_band = demographic[ + (demographic["sex"] == code) + & demographic["birth_year"].between(low, high) + ] + epuf_share = ( + epuf_band.groupby("birth_year").size().reindex(years) + ).fillna(0) + epuf_share = epuf_share / epuf_share.sum() + out[f"{sex}.{band}"] = { + "birth_years": years, + "psid_support_weighted_share": [float(v) for v in psid_share], + "epuf_share": [float(v) for v in epuf_share], + "psid_mean_birth_year": float( + np.average(years, weights=psid_share) + ), + "epuf_mean_birth_year": float( + np.average(years, weights=epuf_share) + ), + } + return out + + +def main() -> None: + started = dt.datetime.now(dt.timezone.utc) + builder = _builder() + floors = json.loads(FLOORS.read_text(encoding="utf-8")) + frame, universe, _ = builder.psid_support() + demographic = epuf.read_demographic() + payload = { + "schema_version": SCHEMA_VERSION, + "run": "epuf_gate_supplement_v1", + "status": "REFEREE_ROUND_1_SUPPLEMENT", + "built_utc": started.isoformat(timespec="seconds"), + "floor_run": "runs/epuf_gate_floors_v1.json", + "floor_run_sha256": hashlib.sha256(FLOORS.read_bytes()).hexdigest(), + "candidate_blind": {"generated_candidates": 0}, + "bites": bite_shifts(builder, frame, universe, floors), + "birth_year_mix": birth_years(frame, demographic), + } + write_new(ARTIFACT, payload, sidecar=True) + print(f"wrote {ARTIFACT.relative_to(ROOT)}") + + +if __name__ == "__main__": + main() diff --git a/scripts/render_gate_epuf_block_draft.py b/scripts/render_gate_epuf_block_draft.py index 90e7623b..8a6d7542 100644 --- a/scripts/render_gate_epuf_block_draft.py +++ b/scripts/render_gate_epuf_block_draft.py @@ -1,10 +1,13 @@ -"""Render the proposed ``gates.gate_epuf`` block from its floor artifact. +"""Render the registered ``gates.gate_epuf`` block from its floor artifact. -The block is the entry the lock flip will copy into ``gates.yaml``. It -is carried as ``docs/design/gate_epuf_block_draft.yaml`` with -``locked: false`` until then (the pattern gate_m6 used), because a byte -change to ``gates.yaml`` moves pins that only a ratified flip may move. -Every number in it comes from ``runs/epuf_gate_floors_v1.json``; +The block is the gate's registration record. It is carried as +``docs/design/gate_epuf_block_draft.yaml`` with ``locked: false`` and is +not in ``gates.yaml`` (the pattern gate_m6 used for its drafts), because a +byte change to ``gates.yaml`` moves pins that only a ratified flip may +move. Round 1 of the referee review ruled that the gate does not lock as +registered (``ROUND_1`` below), so the block records the mechanical +partition the registered rules produced beside the ruling, and gates +nothing. Every number comes from ``runs/epuf_gate_floors_v1.json``; ``tests/test_gate_epuf_block_draft.py`` requires the committed block to equal this script's output. @@ -23,21 +26,51 @@ ROOT = Path(__file__).resolve().parents[1] ARTIFACT = ROOT / "runs" / "epuf_gate_floors_v1.json" +FIRST_BUILD = ROOT / "runs" / "epuf_gate_floors_v1_first_build.json" +SUPPLEMENT = ROOT / "runs" / "epuf_gate_supplement_v1.json" BLOCK = ROOT / "docs" / "design" / "gate_epuf_block_draft.yaml" PROPOSAL = "docs/amendments/gate_epuf_registration_proposal.md" +SCORING_PATH = "src/populace_dynamics/harness/epuf_run.py" + +#: The commit holding the registered rules, pushed before any real-PSID +#: value in EPUF units existed (2026-10-02 13:37 UTC, PR #509). +RULES_COMMIT = "eec910d61a7e0afe21995957740e03d64acdffdc" + +#: Round 1 of the adversarial referee review and the ruling taken on it. +ROUND_1 = { + "report": "reviews/gate_epuf_round1_referee_20261002.md", + "reviewer": ( + "independent Opus 5.5 lane (subfleet job " + "20261002-095515-epuf-gate-r1b), reviewing head ce8d5000" + ), + "verdict": "AMEND: do not lock as registered", + "ruling": ( + "Not locked. The registered persistence bite could not be met by " + "design: the tolerance is about 3.2 realised sigmas (0.079) while " + "giving 10 percent of persons a donor's early years shifts the " + "1998-2004 rank correlation by about 0.07, so the pause was an " + "internal inconsistency of the registration, not a data surprise. " + "The two cells the rules selected add no demonstrated catch beyond " + "gate 1, and with the bridge signs public the registered " + "candidate's verdict is largely predictable. Relaxing the bite " + "requirement after seeing the result (option (a)) is rejected; the " + "cells publish report-only with every gate-1 run. A gate with bite " + "needs a fresh registration (proposal section 12)." + ), +} HEADER = """\ -# gate_epuf block draft (registration proposal; lock flip PENDING). +# gate_epuf registration record (unlocked; not in gates.yaml). # -# The `gates.gate_epuf` block exactly as the lock flip will add it under the -# top-level `gates:` key of gates.yaml, after gate_m6, with `locked: true`. -# Until then it lives here with `locked: false` and edits no gates.yaml byte: -# any change to gates.yaml moves runs/legacy_manifest_v1.json's pin and three -# others, which only a ratified flip may move. +# Round 1 of the referee review ruled that the gate does not lock as +# registered: as designed it cannot fail the generator for anything gate 1 +# does not already catch. The block records the registered rules, the +# partition they produced, and the ruling. It gates nothing; every cell +# publishes report-only with each gate-1 run. It edits no gates.yaml byte. # # Rendered by scripts/render_gate_epuf_block_draft.py from # runs/epuf_gate_floors_v1.json; tests/test_gate_epuf_block_draft.py requires -# this file to equal a fresh render. Proposal and rationale: +# this file to equal a fresh render. Proposal, results and ruling: # docs/amendments/gate_epuf_registration_proposal.md. """ @@ -50,79 +83,63 @@ def _round(value, places=6): return None if value is None else round(float(value), places) -STATISTIC_TEXT = { - "r6": "rank persistence of capped earnings from 1998 to 2004", - "zint": "zero years inside the window among persons positive at both ends", - "d_anyzero": "zero years before 2004 among persons positive in 2004", - "q_atmax": "the share of positive person-years at the taxable maximum", - "mpers": "persistence at the taxable maximum from 1998 to 2004", - "q_sexratio": "men's over women's share at the taxable maximum", -} - - -def covers(gated: list[str]) -> str: - """The scored surface in words: exactly the gated cells.""" - if not gated: - return ( - "Nothing is gated: every cell is report-only " - "(report_only_bridge_dominated)." - ) - parts = [] - for cell_id in gated: - stat, *rest = cell_id.split(".") - where = " ".join(rest) if rest else "both sexes" - parts.append(f"{STATISTIC_TEXT[stat]} ({where}; {cell_id})") - return ( - "Tranche G: a candidate generator's earnings on gate 1's held-out " - "persons at the even reference years 1998, 2000, 2002 and 2004, in " - "EPUF's capped and disclosed units, scored on the mean of the 20 " - "registered seeds against EPUF with an allowance for the PSID's own " - "measured distance from EPUF. Gated cells, and nothing else: " - + "; ".join(parts) - + ". Every other cell is report-only." - ) +def _interval(cell: dict) -> dict: + return { + "metric": cell["metric"], + "cap": _round(cell["cap"]), + "epuf_value": _round(cell["epuf_value"]), + "psid_value": _round(cell["psid_value"]), + "bridge_psid_minus_epuf": _round(cell["bridge_psid_minus_epuf"]), + "tolerance": cell["floor"]["tolerance"], + "realized_sigma": _round(cell["floor"]["realized_sigma"]), + "lower": cell["lower"], + "upper": cell["upper"], + "faithful_pass_probability": _round(cell["faithful_pass_probability"]), + } -def render_block(artifact: dict, artifact_sha256: str) -> dict: +def render_block( + artifact: dict, artifact_sha256: str, hashes: dict[str, str] +) -> dict: partition = artifact["gate_partition"] cells = artifact["cells"] - gated = partition["gated"] + selected = partition["gated"] design = artifact["design"] oc = artifact["faithful_candidate_oc"] - if not gated: - status = "report_only_bridge_dominated" - elif artifact["ceremony_pause"]: - status = "paused_pending_referee_round" - else: - status = "draft_pending_referee_round" bites = artifact["bite_demonstrations"] - gated_cells = {} - for cell_id in gated: - cell = cells[cell_id] - gated_cells[cell_id] = { - "metric": cell["metric"], - "cap": _round(cell["cap"]), - "epuf_value": _round(cell["epuf_value"]), - "psid_value": _round(cell["psid_value"]), - "bridge_psid_minus_epuf": _round(cell["bridge_psid_minus_epuf"]), - "tolerance": cell["floor"]["tolerance"], - "realized_sigma": _round(cell["floor"]["realized_sigma"]), - "lower": cell["lower"], - "upper": cell["upper"], - "faithful_pass_probability": _round( - cell["faithful_pass_probability"] - ), - } + report_only = { + cell_id: "not_locked_referee_round_1" for cell_id in selected + } + report_only.update(partition["report_only"]) return { "gates": { "gate_epuf": { "id": "epuf_covered_earnings", - "status": status, + "status": "unlocked_report_only", "locked": False, "kind": "external_anchor", "proposal": PROPOSAL, + "rules_commit": RULES_COMMIT, + "floor_build_commit": artifact["revision_pins"]["head_sha"], "floor_run": "runs/epuf_gate_floors_v1.json", "floor_run_sha256": artifact_sha256, + "first_floor_build": { + "path": "runs/epuf_gate_floors_v1_first_build.json", + "sha256": hashes["first_build"], + "note": ( + "the build before the report-only career-AIME fix " + "(proposal section 10); its window cells, floors, " + "partition and bites equal the floor run's" + ), + }, + "supplement": { + "path": "runs/epuf_gate_supplement_v1.json", + "sha256": hashes["supplement"], + }, + "scoring_path": { + "module": SCORING_PATH, + "sha256": hashes["scoring_path"], + }, "external_anchor": { "source": ( "SSA 2006 Earnings Public-Use File (EPUF), " @@ -134,17 +151,20 @@ def render_block(artifact: dict, artifact_sha256: str) -> dict: "disclosure_constants_sha256" ], }, - "covers": covers(gated), + "covers": ( + "Nothing is gated. Every cell is published report-only " + "with each gate-1 candidate run: the candidate's 20-seed " + "estimate, its distance from EPUF, and that distance " + "split into the candidate's distance from the PSID and " + "the PSID's distance from EPUF." + ), "not_certified": [ + "anything: the gate is unlocked and gates no cell", "careers, years without earnings by age 62, and the " "35-year AIME (tranche R, report-only)", "any year before 1998, and 2006", - "ages outside the support's window range (about 25-57)", - "the forward earnings law certified by gate_m6", "that the PSID agrees with EPUF (the bridge is published " "per cell)", - "earnings levels by age, which the generator takes from " - "PSID marginals", ], "validation_only": ( "No candidate may use EPUF in fitting, tuning or " @@ -165,13 +185,8 @@ def render_block(artifact: dict, artifact_sha256: str) -> dict: "scoring": ( "populace_dynamics.harness.epuf_run.score_candidate" ), - "reproduction": ( - "a verdict attaches to a registered candidate only if " - "the run reproduces that candidate's committed gate-1 " - "artifact exactly" - ), }, - "scoring": { + "registered_scoring": { "estimator": ( "mean over the 20 gate seeds of the per-seed value, " "then log for shares, identity for rank correlations" @@ -186,17 +201,15 @@ def render_block(artifact: dict, artifact_sha256: str) -> dict: for key, value in design["caps"].items() }, "min_events": design["min_events"], - "pass_rule": ( - "the gate passes iff every gated cell's 20-seed " - "estimate lies inside its interval" - ), }, - "gated_cells": gated_cells, - "report_only": dict(partition["report_only"]), - "faithful_candidate_oc": { + "gated_cells": {}, + "selected_by_registered_rules": { + cell_id: _interval(cells[cell_id]) for cell_id in selected + }, + "report_only": report_only, + "faithful_candidate_oc_of_selected_cells": { "analytic_product": _round(oc["analytic_product"]), "empirical_joint": _round(oc["empirical_joint"]), - "pause_below": oc["pause_below"], }, "bite_requirements": { family: { @@ -208,28 +221,34 @@ def render_block(artifact: dict, artifact_sha256: str) -> dict: for family, row in bites["requirements"].items() }, "ceremony_pause": artifact["ceremony_pause"], + "referee_round_1": ROUND_1, "lock_ceremony": { - "exists": True, - "stage": "proposal", - "next": [ - "adversarial referee round", - "fixes", - "verification round", - "ratify by merge of the flip PR", - "registration of the first run on issue #42", - ], + "exists": False, + "stage": "closed without lock (referee round 1)", + "required_for_any_future_lock": ( + "a fresh registration with a new id, its rules " + "fixed before anything is recomputed (proposal " + "section 12)" + ), }, "history": [ { "id": "2026-10-02-epuf-registration-proposal", "proposed": "2026-10-02", "content": ( - "Registration proposed with the rules committed " - "before the floor build (commit " - f"{artifact['revision_pins']['head_sha'][:12]}); " - "floors in runs/epuf_gate_floors_v1.json." + "Rules committed and pushed before the floor " + f"build (commit {RULES_COMMIT[:12]}); floors " + "built at commit " + f"{artifact['revision_pins']['head_sha'][:12]}." ), - } + }, + { + "id": "2026-10-02-epuf-referee-round-1", + "content": ( + "Referee round 1: AMEND. Ruling: not locked; " + "report-only (referee_round_1)." + ), + }, ], } } @@ -238,7 +257,12 @@ def render_block(artifact: dict, artifact_sha256: str) -> dict: def render() -> str: artifact = json.loads(ARTIFACT.read_text(encoding="utf-8")) - block = render_block(artifact, _sha256(ARTIFACT)) + hashes = { + "first_build": _sha256(FIRST_BUILD), + "supplement": _sha256(SUPPLEMENT), + "scoring_path": _sha256(ROOT / SCORING_PATH), + } + block = render_block(artifact, _sha256(ARTIFACT), hashes) return HEADER + yaml.safe_dump( block, sort_keys=False, width=79, allow_unicode=True ) diff --git a/tests/README-tiers.md b/tests/README-tiers.md index 56b2bbb8..7d049a79 100644 --- a/tests/README-tiers.md +++ b/tests/README-tiers.md @@ -40,8 +40,8 @@ pytest --collect-only -q -m oracle_policyengine | tail -1 | Tier | Tests at HEAD | |---|---:| | `unit` | 5,800 | -| `artifact` | 3,353 | +| `artifact` | 3,357 | | `integration_psid` | 1,341 | | `reproduction_legacy` | 520 | | `oracle_policyengine` | 215 | -| **Total** | **11,229** | +| **Total** | **11,233** | diff --git a/tests/test_gate_epuf_block_draft.py b/tests/test_gate_epuf_block_draft.py index 6aed6e36..7d4c9555 100644 --- a/tests/test_gate_epuf_block_draft.py +++ b/tests/test_gate_epuf_block_draft.py @@ -17,12 +17,15 @@ import pytest import yaml +from scipy.stats import norm from populace_dynamics.harness import epuf_gate as gate from populace_dynamics.harness.epuf_cells import cell_ids, transform ROOT = Path(__file__).resolve().parents[1] ARTIFACT = ROOT / "runs" / "epuf_gate_floors_v1.json" +FIRST_BUILD = ROOT / "runs" / "epuf_gate_floors_v1_first_build.json" +SUPPLEMENT = ROOT / "runs" / "epuf_gate_supplement_v1.json" BLOCK = ROOT / "docs" / "design" / "gate_epuf_block_draft.yaml" GATES = ROOT / "gates.yaml" @@ -58,21 +61,119 @@ def test_block_is_the_render_of_the_committed_artifact(): ) -def test_block_is_unlocked_and_gates_yaml_is_untouched(): +def test_block_is_unlocked_gates_nothing_and_gates_yaml_is_untouched(): block = _block() - assert block["locked"] is False artifact = _artifact() - if not artifact["gate_partition"]["gated"]: - assert block["status"] == "report_only_bridge_dominated" - elif artifact["ceremony_pause"]: - assert block["status"] == "paused_pending_referee_round" - else: - assert block["status"] == "draft_pending_referee_round" - assert block["ceremony_pause"] == artifact["ceremony_pause"] + assert block["locked"] is False + assert block["status"] == "unlocked_report_only" + assert block["gated_cells"] == {} + assert block["lock_ceremony"]["exists"] is False + assert block["ceremony_pause"] == artifact["ceremony_pause"] is True + assert block["referee_round_1"]["verdict"].startswith("AMEND") + assert (ROOT / block["referee_round_1"]["report"]).is_file() gates = yaml.safe_load(GATES.read_text(encoding="utf-8"))["gates"] assert "gate_epuf" not in gates assert "gate_epuf" not in GATES.read_text(encoding="utf-8") - assert _artifact()["ceremony"]["gates_yaml_untouched"] is True + assert artifact["ceremony"]["gates_yaml_untouched"] is True + + +def test_block_names_the_rules_commit_and_the_build_commit_separately(): + block = _block() + artifact = _artifact() + assert block["floor_build_commit"] == ( + artifact["revision_pins"]["head_sha"] + ) + assert block["rules_commit"] == ( + "eec910d61a7e0afe21995957740e03d64acdffdc" + ) + assert block["rules_commit"] != block["floor_build_commit"] + first = json.loads(FIRST_BUILD.read_text(encoding="utf-8")) + assert first["revision_pins"]["head_sha"] == block["rules_commit"] + + +def test_scoring_path_is_pinned(): + block = _block() + module = block["scoring_path"]["module"] + assert module == "src/populace_dynamics/harness/epuf_run.py" + observed = hashlib.sha256((ROOT / module).read_bytes()).hexdigest() + assert observed == block["scoring_path"]["sha256"] + + +def test_first_build_is_frozen_lineage_with_equal_window_results(): + first_bytes = FIRST_BUILD.read_bytes() + assert hashlib.sha256(first_bytes).hexdigest() == ( + "369bf5ec4e62c0eaa2f70702a9173188c87e84a5544bb4470826781c1847e378" + ) + assert _block()["first_floor_build"]["sha256"] == ( + hashlib.sha256(first_bytes).hexdigest() + ) + first = json.loads(first_bytes) + rebuilt = _artifact() + for key in ( + "cells", + "gate_partition", + "registered", + "faithful_candidate_oc", + "training_copy", + "real_gate_seed_values", + "bite_demonstrations", + "holdout_ids", + "epuf_support", + "ceremony_pause", + "design", + ): + assert first[key] == rebuilt[key], key + # Only the report-only career tranche differs (the AIME fix). + assert ( + first["tranche_r_epuf_reference"] + != rebuilt["tranche_r_epuf_reference"] + ) + + +def test_supplement_belongs_to_the_floor_run_and_matches_its_bites(): + supplement = json.loads(SUPPLEMENT.read_text(encoding="utf-8")) + artifact = _artifact() + assert supplement["floor_run_sha256"] == ( + hashlib.sha256(ARTIFACT.read_bytes()).hexdigest() + ) + assert _block()["supplement"]["sha256"] == ( + hashlib.sha256(SUPPLEMENT.read_bytes()).hexdigest() + ) + assert supplement["candidate_blind"]["generated_candidates"] == 0 + bites = supplement["bites"] + for name, row in artifact["bite_demonstrations"].items(): + if name in ("requirements", "pause"): + continue + assert bites[name]["fail_share_reproduced"] == row["fail_share"] + for cell_id, cell in bites[name]["cells"].items(): + estimates = cell["estimates_over_perturbation_seeds"] + assert len(estimates) == 50 + assert cell["mean_shift"] == pytest.approx( + sum(estimates) / len(estimates) + - cell["real_gate_holdout_estimate"] + ) + floor = artifact["cells"][cell_id] + centre = floor["bridge_psid_minus_epuf"] + cell["mean_shift"] + sigma = floor["floor"]["realized_sigma"] + expected = norm.cdf((floor["lower"] - centre) / sigma) + norm.sf( + (floor["upper"] - centre) / sigma + ) + assert cell["power_under_gate_noise_model"] == pytest.approx( + expected + ) + for cell_id, point in bites["detection_points"].items(): + floor = artifact["cells"][cell_id] + sigma = floor["floor"]["realized_sigma"] + distance = floor["bridge_psid_minus_epuf"] - floor["lower"] + assert point["shortfall_failing_90_percent"] == pytest.approx( + distance + 1.2816 * sigma + ) + # The registered 10 percent persistence bite sits below the 90 + # percent detection point: the pause was foreseeable. + shift = bites["bd1_persistence_loss_0.10"]["cells"][cell_id][ + "mean_shift" + ] + assert -shift < point["shortfall_failing_90_percent"] def test_derivation_files_are_the_ones_the_floor_was_built_with(): @@ -138,9 +239,15 @@ def test_block_carries_the_artifact_partition_and_numbers(): artifact = _artifact() block = _block() partition = artifact["gate_partition"] - assert list(block["gated_cells"]) == partition["gated"] - assert block["report_only"] == partition["report_only"] - for cell_id, row in block["gated_cells"].items(): + selected = block["selected_by_registered_rules"] + assert list(selected) == partition["gated"] + expected_report = { + cell_id: "not_locked_referee_round_1" for cell_id in partition["gated"] + } + expected_report.update(partition["report_only"]) + assert block["report_only"] == expected_report + assert set(block["report_only"]) == set(cell_ids()) + for cell_id, row in selected.items(): cell = artifact["cells"][cell_id] assert row["lower"] == cell["lower"] assert row["upper"] == cell["upper"] diff --git a/tests/tier_counts.json b/tests/tier_counts.json index 528c5e1a..019fd592 100644 --- a/tests/tier_counts.json +++ b/tests/tier_counts.json @@ -2,7 +2,7 @@ "schema_version": 1, "counts": { "unit": 5800, - "artifact": 3353, + "artifact": 3357, "integration_psid": 1341, "reproduction_legacy": 520, "oracle_policyengine": 215 From 93848324885b5209a33fd059597bdb740bb98c0c Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 17:28:02 -0400 Subject: [PATCH 6/9] EPUF gate, verification round 2: a report path with no verdict; wording The round-2 verifier (reviews/gate_epuf_round2_verification_20261002.md, merge after listed fixes, no blockers) found that the record claimed a report-only path the code did not provide: the scoring function split the gap for the two persistence cells only and still returned a pass field. - harness/epuf_run.py: report_candidate replaces score_candidate. It reports every window cell (estimate, distance from EPUF, and that distance split into model and source terms) and returns no pass or fail. No run script calls it yet, and the record now says so. - The proposal, block and paper say the gate "has not been shown to catch anything gate 1 does not already catch" where they said it "cannot fail" the generator for it; no perturbation was ever scored on gate 1. - Section 7: sex-level figures are labelled as means over the three cohort bands; two bridges corrected in the third decimal (+0.424, +0.086); one cohort cell (r6.women.c1) is eligible and reported; the both-sexes donor bite lands slightly past EPUF, not short of it. - The birth-year comparison is described as a comparison of labels, not a measure of the shift. - Tests pin the reporting path and supplement by literal SHA-256 and recompute the 80 percent detection points, the per-cell bite fail shares and the birth-year mix. - The paper sentence follows the verifier's wording. No derivation file changed (git diff ce8d5000 HEAD on the five is empty). Co-Authored-By: Claude Opus 5.5 --- .../gate_epuf_registration_proposal.md | 157 +++++++++++------- docs/design/gate_epuf_block_draft.yaml | 43 +++-- paper/paper.qmd | 2 +- .../gate_epuf_round2_verification_20261002.md | 106 ++++++++++++ scripts/render_gate_epuf_block_draft.py | 66 +++++--- src/populace_dynamics/harness/epuf_run.py | 81 ++++++--- tests/README-tiers.md | 6 +- tests/test_epuf_gate_floor_builder.py | 63 +++++-- tests/test_gate_epuf_block_draft.py | 75 ++++++++- tests/tier_counts.json | 4 +- 10 files changed, 462 insertions(+), 141 deletions(-) create mode 100644 reviews/gate_epuf_round2_verification_20261002.md diff --git a/docs/amendments/gate_epuf_registration_proposal.md b/docs/amendments/gate_epuf_registration_proposal.md index 9b51ecd7..70676651 100644 --- a/docs/amendments/gate_epuf_registration_proposal.md +++ b/docs/amendments/gate_epuf_registration_proposal.md @@ -7,8 +7,9 @@ Earnings Public-Use File (EPUF). Tranche R, the career statistics, is report-only. - **Ceremony stage**: CLOSED WITHOUT LOCK after referee round 1 - (`reviews/gate_epuf_round1_referee_20261002.md`). **The gate gates nothing.** - Every cell publishes report-only with each gate-1 candidate run. This + (`reviews/gate_epuf_round1_referee_20261002.md`), verified in round 2 + (`reviews/gate_epuf_round2_verification_20261002.md`). **The gate gates + nothing.** A run reports every cell without a pass or fail. This registration edits no `gates.yaml` cell and no committed `runs/*.json`; its record is `docs/design/gate_epuf_block_draft.yaml` (`locked: false`, `status: unlocked_report_only`). @@ -27,33 +28,40 @@ A gate here is a pass-or-fail test whose rules and thresholds are fixed and published before the model is scored against it. This registration set out to make SSA's public earnings file such a test for -the model's generated earnings. **As registered, it cannot fail the generator -for anything gate 1 does not already catch, so it does not lock.** +the model's generated earnings. **As registered, it has not been shown to +catch anything gate 1 does not already catch, and it could not meet its own +check on its bite, so it does not lock.** - The generator's earnings overlap EPUF in four years, 1998-2004. On that overlap only two cells had the power the rules demand: how persistent earnings ranks are from 1998 to 2004, for men and for women. -- Those two cells fail a generator only when its persistence falls about - 0.10 below the PSID's (four times in five), or about 0.11 below (nine times - in ten). The registered check on the gate's own bite asked for more: that - it catch a smaller shortfall, about 0.07, nine times in ten. The rules - could not deliver that, and the floor build showed it. That was a flaw in - the registration, foreseeable from numbers available before the build, not - a surprise in the data. -- A generator that ignores sex moved men's persistence toward EPUF's, which - the cells accept. They add no demonstrated catch beyond gate 1. +- Those two cells fail a generator whose persistence falls about 0.10 below + the PSID's four times in five, and one about 0.11 below nine times in ten. + The interval also ends 0.08 above EPUF, so one that overshoots EPUF by + more than that fails more often than not. The + registered check on the gate's own bite asked for more: that it catch a + smaller shortfall, 0.07 for men and 0.06 for women, nine times in ten. The + rules could not deliver that. That was a flaw in the registration, not a + surprise in the data: a check of the dose against the cells' detection + point before the build would have shown it. +- A perturbation that draws each person's early years from donors of both + sexes raised men's persistence to about EPUF's level, which the cells + accept. No perturbation was shown to pass gate 1 and fail these cells. - With the PSID's distance from EPUF now public, the registered candidate's verdict on these cells could largely be predicted. The independent referee ruled against loosening the check to fit the result, and this registration takes that ruling (section 7.5). What EPUF does add is -measurement. On the generator's support the PSID's earnings ranks persist -less than SSA's records (0.668 against 0.711 for men). PSID men are at the -taxable maximum more often (17.8 against 11.6 percent of positive -person-years). Fewer PSID people have a zero year before covered work in 2004. -Every gate-1 run will publish these comparisons, and where the candidate sits -between the PSID and EPUF. Section 12 says what a gate with real bite would -need. +measurement. The figures below are means over the three birth-cohort bands, +on the generator's support. The PSID's earnings ranks persist less than +SSA's records (0.668 against 0.711 for men; in five of the six sex-by-cohort +cells). PSID men are at the taxable maximum more often (17.8 against 11.6 +percent of positive person-years). Fewer PSID men have a zero year before +covered work in 2004 (9.7 against 12.8 percent). A run that regenerates a +gate-1 candidate reports these comparisons for every cell, and where the +candidate sits between the PSID and EPUF +(`populace_dynamics.harness.epuf_run.report_candidate`); no run script calls +that path yet. Section 12 says what a gate with real bite would need. ## 1. Summary @@ -98,7 +106,7 @@ power cap. Cells that could not meet that are published with the reason. The four career statistics the request named are years without earnings by age 62, rank persistence ten years apart, the share at the taxable maximum by age, and the AIME under the 35-year rule. None can be scored on generated -histories, because nothing generates earnings for a career. They are registered +histories, because nothing generates a career's earnings before 1998. They are registered as tranche R, report-only, with their EPUF reference values in the floor artifact. @@ -136,9 +144,11 @@ to mirror, so each statistic carries its own conditioning (section 3). The PSID birth year is derived from age at interview, which is measured in the wave after the income year, so it can sit a year below EPUF's year of birth. The repository's career products take a marriage-history birth year -first (`estimates/career.py:650-656`); this registration does not. Within -each band the support's weighted mean birth year sits within 0.25 years of -EPUF's (`runs/epuf_gate_supplement_v1.json`, `birth_year_mix`). +first (`estimates/career.py:650-656`); this registration does not. The +supplement stores each band's birth-year mix on both sides +(`runs/epuf_gate_supplement_v1.json`, `birth_year_mix`). Their means agree +within 0.25 years, but that compares the two sides' own labels after each +was selected on its label, so it does not measure the shift. **Units.** PSID-side and candidate-side earnings pass through EPUF's measurement operator (`populace_dynamics.harness.epuf_operator.epuf_measure`): @@ -209,8 +219,8 @@ generator's mean differs from the real value by the realised sample's own deviation from its conditional law, which is the same on every seed. The term bounds that noise, and the bound is exact for a generator that draws from the true law. A generator that copies donors from the same sample, as -candidate 11 does, has less of it, so for such a generator the floor is -conservative. The second term stands for the noise that averages down: who +candidate 11 does, likely has less of it, in which case the floor is +conservative for it. The second term stands for the noise that averages down: who falls in each holdout, each seed's draws and each seed's fit. **Tolerance.** `t = round(mean|e_b| + 4 * sd|e_b|, 3)`, with sd taken with @@ -303,8 +313,9 @@ bite's mean shift and its power under the gate's own noise model. The numbers in this section come from `runs/epuf_gate_floors_v1.json` and `runs/epuf_gate_supplement_v1.json`. `tests/test_gate_epuf_block_draft.py` -recomputes every tolerance, interval, partition, pass probability, bite shift -and power figure from what those files store. +recomputes every tolerance, interval, partition, pass probability, detection +point, bite shift and power figure from what those files store. Each +sex-level figure is the unweighted mean of its three birth-cohort bands. ### 7.1 Support @@ -334,8 +345,8 @@ metric scale (log ratio for shares, difference for correlations). | `zint.women` | 0.066 | 0.070 | +0.062 | 0.381 | below 20 events | | `d_anyzero.men` | 0.128 | 0.097 | -0.278 | 0.283 | bridge exceeds budget | | `d_anyzero.women` | 0.180 | 0.151 | -0.176 | 0.212 | bridge exceeds budget | -| `q_atmax.men` | 0.116 | 0.178 | +0.425 | 0.164 | bridge exceeds budget | -| `q_atmax.women` | 0.036 | 0.039 | +0.087 | 0.358 | noise exceeds cap | +| `q_atmax.men` | 0.116 | 0.178 | +0.424 | 0.164 | bridge exceeds budget | +| `q_atmax.women` | 0.036 | 0.039 | +0.086 | 0.358 | noise exceeds cap | | `mpers.men` | 0.594 | 0.613 | +0.031 | 0.196 | below 20 events | | `mpers.women` | 0.478 | 0.516 | +0.077 | — | undefined on some split | | `q_sexratio` | 3.25 | 4.56 | +0.338 | 0.379 | noise exceeds cap | @@ -344,7 +355,9 @@ What the table says, and what it does not: - **Rank persistence.** On the support, PSID earnings ranks persist less from 1998 to 2004 than EPUF's do: 0.668 against 0.711 for men, 0.640 - against 0.672 for women. The bridge measures the gap. It does not say how + against 0.672 for women. That holds in five of the six sex-by-cohort + cells; for women born 1956-1964 the PSID's is 0.017 higher. The bridge + measures the gap. It does not say how much of it comes from reporting, from who the PSID samples, or from noncovered work. - **The taxable maximum.** Among positive person-years, 17.8 percent of the @@ -359,8 +372,9 @@ What the table says, and what it does not: zero there and not in the PSID; how much of the gap that accounts for is not measured here. - **Power.** Interior zero years and persistence at the maximum are too rare - at the PSID's size for the 20-event rule. No cohort-band cell is powered - within the caps. + at the PSID's size for the 20-event rule. One cohort-band cell is eligible + (`r6.women.c1`); the ladder gates cohort cells only when all six are, so it + is reported. ### 7.3 The cells the rules selected, and their operating characteristic @@ -397,19 +411,22 @@ The requirement could not have been met. Under the gate's own noise model the two cells fail a shortfall from the PSID of 0.100 (men) and 0.100 (women) four times in five, and of 0.111 and 0.110 nine times in ten (`detection_points` in the supplement). `bd1` at 10 percent shifts the -correlation by about 0.07, inside both points, so a 90 percent requirement on -it was out of reach whatever the data showed. The eligibility rule promised -80 percent power at the first point; the bite asked for 90 percent at a smaller -shortfall. EPUF subsampled to PSID scale, which the design panel had before -the build, gave sigma near this size. So the pause comes from an internal -inconsistency of the registration that could have been seen in advance, not +correlation by 0.067 for men and 0.057 for women, inside both points. The +eligibility rule promised 80 percent power at the first point; the bite asked +for 90 percent at a smaller shortfall. The registration never checked the +dose against the cells' detection point. Doing so on EPUF subsampled to PSID +scale, before the build, would have shown the requirement was out of reach. +So the pause comes from an internal inconsistency of the registration, not from something the data revealed. Two more readings, both from the supplement: -- Sex-blind donors (`bd2`) raise men's persistence by 0.056, toward EPUF's - value, where the interval accepts it. The cells by sex catch no sex-blind - generator here. +- Donors drawn from both sexes (`bd2`) raise men's persistence by 0.056, to + about EPUF's level and 0.012 past it, where the interval accepts it. `bd2` + is a perturbation of real data, not a generator. Its donors are matched on + 2004 deciles, and the same-sex control (`bd2c`) moves the cells by 0.01 or + less, so the matching itself keeps the rank correlation. Within that limit, + the cells by sex showed no catch for pooling the sexes. - No perturbation was shown to pass gate 1's battery and fail these cells. Their catch beyond gate 1 is not demonstrated. @@ -427,13 +444,18 @@ persists more than the PSID at two and four years in gate 1, which here moves it toward EPUF, inside the interval. The referee also ruled that (b) cannot be done blind, because every redesign it names is informed by the bridges. -**Ruling: the gate does not lock.** Every cell publishes report-only with -each gate-1 candidate run: the candidate's 20-seed estimate, its distance -from EPUF, and that distance split into the candidate's distance from the -PSID and the PSID's distance from EPUF -(`populace_dynamics.harness.epuf_run.score_candidate`). The drafting -session had recommended (a); it withdraws that recommendation. A gate with -bite needs a fresh registration (section 12). +**Ruling: the gate does not lock.** A run reports every cell without a pass +or fail: the candidate's 20-seed estimate, its distance from EPUF, and that +distance split into the candidate's distance from the PSID and the PSID's +distance from EPUF (`populace_dynamics.harness.epuf_run.report_candidate`). +No run script calls that path yet; a run that regenerates a gate-1 +candidate's 20 panels hands them to it. The drafting session had recommended +(a); it withdraws that recommendation. A gate with bite needs a fresh +registration (section 12). + +Round 2 (`reviews/gate_epuf_round2_verification_20261002.md`) verified this +record and asked for the fixes now applied: a reporting path that covers +every cell and returns no pass or fail, and corrected wording. ### 7.6 Tranche R on EPUF alone @@ -474,8 +496,9 @@ The floor artifact holds their EPUF values twice: on EPUF as published, and on EPUF rewritten by two of the career assembler's rules. Under those rules nothing counts before `max(1968, birth year + 22)`, and each odd year from 1997 is filled with the mean of its neighbours. The mask does not apply the -assembler's exclusions of low-coverage and incomplete-domain persons -(`estimates/career.py:1581-1598`). For the cohorts used, `max(1968, birth year +assembler's exclusions (incomplete domain, eligibility before 1979, empty +span, inconsistent chronology and low coverage; +`estimates/career.py:1581-1598`). For the cohorts used, `max(1968, birth year + 22)` is 1968 for everyone. The difference is exact and involves no PSID. A run adds the PSID career product's values beside the masked EPUF values. Survival to the PSID's observation years has no EPUF counterpart and is named @@ -487,10 +510,11 @@ and its distance from EPUF is the bridge itself. ## 9. What is published, and what is not certified -Every gate-1 candidate run publishes each cell's 20-seed estimate, its -distance from EPUF, and the split of that distance into the candidate's -distance from the PSID and the PSID's distance from EPUF. Tranche R publishes -the career statistics beside the masked EPUF values. +A run that regenerates a gate-1 candidate reports each cell's 20-seed +estimate, its distance from EPUF, and the split of that distance into the +candidate's distance from the PSID and the PSID's distance from EPUF +(`report_candidate`, which returns no pass or fail). Tranche R reports the +career statistics beside the masked EPUF values. No run has been made. Nothing is certified. In particular: @@ -538,6 +562,14 @@ under this gate's measurement. **Before any run.** No candidate has been generated. Tranche R's PSID side has not been computed. +**Strings this record supersedes.** The floor artifacts and the files they +bind to cannot be edited without breaking that binding, so a few of their +strings predate the ruling. `gate_partition.status` in the floor artifact +reads `lockable_pending_referee_round`, and its tranche R note says "computed +once, after lock". The docstring of `epuf_gate.tolerance` calls the formula +"the house formula". The block and this document supersede them: nothing is +pending a lock, and `k = 4` is not house precedent (section 4). + ## 11. Considered and rejected 1. **EPUF-centred tolerance with no bridge.** A faithful candidate's pass @@ -574,11 +606,11 @@ has not been computed. ## 12. What a gate with bite would need This surface cannot be rescued by retuning. The PSID's size sets the noise: -on about 2,500 people per sex, the 1998-2004 rank correlation has a realised -sigma of 0.025. Even with `k` chosen so a faithful generator passes 95 percent -of the time, a tolerance near two sigmas would leave a 90 percent detection -point near 0.08 below the PSID. And every redesign of these cells is now -informed by their bridges. +on 2,182 pairs of men and 2,376 of women with earnings in both years, the +1998-2004 rank correlation has a realised sigma of 0.025. Even with `k` chosen +so a faithful generator passes 95 percent of the time, a tolerance near two +sigmas would leave a 90 percent detection point near 0.08 below the PSID. And +every redesign of these cells is now informed by their bridges. A fresh EPUF gate, under a new registration id, would need all of these before its floor is built: @@ -598,7 +630,8 @@ before its floor is built: 5. **The smaller house details** found in round 1: events counted on the weakest band of a sex-level cell; panel digests for every scored seed; the repository's birth-year precedence; a build timestamp in the artifact; - floor half-split seeds that do not reuse gate seeds. + floor half-split seeds that do not reuse gate seeds; non-finite values + stripped from every block of the artifact, not only the floor and bites. ## 13. Ceremony checklist @@ -607,4 +640,4 @@ before its floor is built: - [x] Fixes: the supplement, the frozen first build, separate rules and build commits in the block, a pinned scoring path, corrected wording - [x] Ruling: closed without lock; every cell report-only -- [ ] Verification of this record by an independent reviewer (PR #509) +- [x] Verification round 2 (verdict: merge after listed fixes, applied) diff --git a/docs/design/gate_epuf_block_draft.yaml b/docs/design/gate_epuf_block_draft.yaml index 049f77da..fda633b8 100644 --- a/docs/design/gate_epuf_block_draft.yaml +++ b/docs/design/gate_epuf_block_draft.yaml @@ -1,10 +1,12 @@ # gate_epuf registration record (unlocked; not in gates.yaml). # # Round 1 of the referee review ruled that the gate does not lock as -# registered: as designed it cannot fail the generator for anything gate 1 -# does not already catch. The block records the registered rules, the -# partition they produced, and the ruling. It gates nothing; every cell -# publishes report-only with each gate-1 run. It edits no gates.yaml byte. +# registered: it has not been shown to catch anything gate 1 does not +# already catch, and its own bite requirement was out of reach. The block +# records the registered rules, the partition they produced, and the ruling. +# It gates nothing; a run reports every cell without a pass or fail +# (populace_dynamics.harness.epuf_run.report_candidate). It edits no +# gates.yaml byte. # # Rendered by scripts/render_gate_epuf_block_draft.py from # runs/epuf_gate_floors_v1.json; tests/test_gate_epuf_block_draft.py requires @@ -29,9 +31,9 @@ gates: supplement: path: runs/epuf_gate_supplement_v1.json sha256: 1570f80e5b42c0890871a818e29f09bdf55fdafe26ba4a2aaa7cade4280ea676 - scoring_path: + reporting_path: module: src/populace_dynamics/harness/epuf_run.py - sha256: f1a3055a36f225b59adf2240e1398b18724f06364706d692faf4445b380de995 + sha256: 243be0f7a7d17fed689b924af513f9d2645daf436dca25b5234b552b5f9df023 external_anchor: source: SSA 2006 Earnings Public-Use File (EPUF), https://www.ssa.gov/policy/docs/microdata/epuf/ provenance: data/external/epuf_2006/provenance.md @@ -39,10 +41,10 @@ gates: EPUF2006_DEMOGRAPHIC.csv: 195db459ca7b7c810162cb6e432371e8787eba8331787d2ba1eace1a0da2ccb0 EPUF2006_ANNUAL.csv: a47315b56214df66fb9f9abcb2caa60779c8b3d091ded199323672c27e3ea105 disclosure_constants_sha256: ba1f39f238278243de19b8a9d194abedffeabd855f5b97779b685d852f62a881 - covers: 'Nothing is gated. Every cell is published report-only with each gate-1 - candidate run: the candidate''s 20-seed estimate, its distance from EPUF, and - that distance split into the candidate''s distance from the PSID and the PSID''s - distance from EPUF.' + covers: 'Nothing is gated. A run reports every cell without a pass or fail: the + candidate''s 20-seed estimate, its distance from EPUF, and that distance split + into the candidate''s distance from the PSID and the PSID''s distance from + EPUF. No run script calls the reporting path yet.' not_certified: - 'anything: the gate is unlocked and gates no cell' - careers, years without earnings by age 62, and the 35-year AIME (tranche R, @@ -86,7 +88,7 @@ gates: - birth year floor(median(period - age) + 0.5) in 1947-1973 weight: the person's 2004-row weight epuf: every EPUF person with sex 1 or 2 born 1947-1973, weight 1 - scoring: populace_dynamics.harness.epuf_run.score_candidate + reporting: populace_dynamics.harness.epuf_run.report_candidate registered_scoring: estimator: mean over the 20 gate seeds of the per-seed value, then log for shares, identity for rank correlations @@ -189,12 +191,21 @@ gates: the tolerance is about 3.2 realised sigmas (0.079) while giving 10 percent of persons a donor''s early years shifts the 1998-2004 rank correlation by about 0.07, so the pause was an internal inconsistency of the registration, - not a data surprise. The two cells the rules selected add no demonstrated + not a data surprise. The two cells the rules selected have no demonstrated catch beyond gate 1, and with the bridge signs public the registered candidate''s verdict is largely predictable. Relaxing the bite requirement after seeing - the result (option (a)) is rejected; the cells publish report-only with every - gate-1 run. A gate with bite needs a fresh registration (proposal section - 12).' + the result (option (a)) is rejected; every cell is reported without a pass + or fail. A gate with bite needs a fresh registration (proposal section 12).' + verification_round_2: + report: reviews/gate_epuf_round2_verification_20261002.md + reviewer: independent Opus 5.5 lane (subfleet job 20261002-170235-epuf-gate-r2), + reviewing head d606ddea + verdict: MERGE AFTER LISTED FIXES (no blockers) + fixes: A report-only path that covers every cell and returns no pass or fail + (report_candidate) replaced the two-cell scoring path; the proposal, block + and paper say 'not shown to catch' where they said 'cannot fail'; section + 7 figures are labelled as means over the three cohort bands and corrected + in the third decimal. lock_ceremony: exists: false stage: closed without lock (referee round 1) @@ -207,3 +218,5 @@ gates: floors built at commit 970a9db721bf. - id: 2026-10-02-epuf-referee-round-1 content: 'Referee round 1: AMEND. Ruling: not locked; report-only (referee_round_1).' + - id: 2026-10-02-epuf-verification-round-2 + content: 'Verification round 2: merge after listed fixes, applied (verification_round_2).' diff --git a/paper/paper.qmd b/paper/paper.qmd index e3a3ad64..31dabd5e 100644 --- a/paper/paper.qmd +++ b/paper/paper.qmd @@ -363,7 +363,7 @@ The model addresses these limits in two ways, and we plan a third. None removes **Gates scored on the PSID.** The gates that score the model against the PSID set most of their tolerances from the discrepancy between two disjoint halves of the real PSID panel (@sec-scoring). A smaller panel produces a wider floor and a looser tolerance. Gates 2, 2b, 2c, m4 and m6 demote to report-only any cell whose weaker half holds fewer than 20 events or whose tolerance would exceed a cap, ln(1.5) for most cells and 0.15 for gate m6's earnings correlations (`gates.yaml`). These rules price the PSID's sampling noise. They cannot detect a bias that both halves share, because both halves come from the same selected and attrited panel: such a gate tests whether the model reproduces the PSID, and leaves open how far the PSID departs from the population. Gate m6 scores only the people the PSID observed in each later wave, treats the PSID's record of deaths above age 85 as confounded by attrition, and certifies nothing about mortality drift (`gates.yaml`, gate_m6). -**A planned check against administrative earnings records.** We plan to set the earnings careers the model reads from the PSID, and those it generates, against the Social Security Administration's 2006 Earnings Public-Use File. The file holds annual earnings records for 1951 through 2006 from a 1 percent random sample of all Social Security numbers issued before 2007, 4,384,254 people in all [@ssa2011epuf; @ssa2011epufdict].^[SSA's article introducing the file gives 4,348,254 in three places and 4,384,254 in another; its own count of the underlying sample less the records it removed yields 4,384,254 [@compson2011epuf].] Its records come from the earnings posted to workers' Social Security records, so they do not depend on anyone continuing to answer a survey. They hold only earnings up to each year's taxable maximum from jobs Social Security covers, with wages and self-employment combined, and the file records each person's birth year and sex and nothing about marriage, children, disability or death [@compson2011epuf]. The file follows each person across years, so it can test change over time as well as single years. Moffitt and Zhang report that the PSID's earnings data have never been matched to government administrative records [@moffitt2020estimating]. The comparison would run by birth year and sex and cover the share of years with no covered earnings, the share of low-earnings years, movement into and out of covered work, and how persistent a worker's position stays over time. Selective attrition and weak low-end reporting would distort these statistics, and the PSID's own halves cannot reveal the distortion. The comparison has to put the model's earnings on the file's terms, capped at each year's taxable maximum and limited to covered work. It also has to put the two populations on common terms. The file records no deaths, so a run of years without earnings can mean retirement, disability or death [@compson2011epuf], and its sample of Social Security numbers includes the post-1968 immigrants the PSID largely leaves out. The file's own low end is coarse: SSA replaces every amount under $100 with that year's average and rounds amounts from $100 to $1,000 at random to a base of $25 [@ssa2011epufdict; @compson2011epuf]. We registered the rules for one part of this comparison before computing any of it, as we do every gate (`docs/amendments/gate_epuf_registration_proposal.md`). That part covers the generated earnings, which overlap the file only in the even years from 1998 to 2004. On that overlap the PSID is too small for the comparison to pass or fail the generator on anything gate 1 does not already test, so we report it and do not gate it. We have not yet scored the model's earnings against the file, and we have not run the comparison of careers. +**A planned check against administrative earnings records.** We plan to set the earnings careers the model reads from the PSID, and those it generates, against the Social Security Administration's 2006 Earnings Public-Use File. The file holds annual earnings records for 1951 through 2006 from a 1 percent random sample of all Social Security numbers issued before 2007, 4,384,254 people in all [@ssa2011epuf; @ssa2011epufdict].^[SSA's article introducing the file gives 4,348,254 in three places and 4,384,254 in another; its own count of the underlying sample less the records it removed yields 4,384,254 [@compson2011epuf].] Its records come from the earnings posted to workers' Social Security records, so they do not depend on anyone continuing to answer a survey. They hold only earnings up to each year's taxable maximum from jobs Social Security covers, with wages and self-employment combined, and the file records each person's birth year and sex and nothing about marriage, children, disability or death [@compson2011epuf]. The file follows each person across years, so it can test change over time as well as single years. Moffitt and Zhang report that the PSID's earnings data have never been matched to government administrative records [@moffitt2020estimating]. The comparison would run by birth year and sex and cover the share of years with no covered earnings, the share of low-earnings years, movement into and out of covered work, and how persistent a worker's position stays over time. Selective attrition and weak low-end reporting would distort these statistics, and the PSID's own halves cannot reveal the distortion. The comparison has to put the model's earnings on the file's terms, capped at each year's taxable maximum and limited to covered work. It also has to put the two populations on common terms. The file records no deaths, so a run of years without earnings can mean retirement, disability or death [@compson2011epuf], and its sample of Social Security numbers includes the post-1968 immigrants the PSID largely leaves out. The file's own low end is coarse: SSA replaces every amount under $100 with that year's average and rounds amounts from $100 to $1,000 at random to a base of $25 [@ssa2011epufdict; @compson2011epuf]. We registered the rules for one part of this comparison before computing any PSID value on the file's terms, as we do every gate (`docs/amendments/gate_epuf_registration_proposal.md`). That part covers the generated earnings, which overlap the file only in the even years from 1998 to 2004. On that overlap only two cells had enough power, and we found nothing they would catch that gate 1 does not, so we report the comparison without a pass or fail. We have not yet scored the model's earnings against the file, and we have not run the comparison of careers. | Limit | What it does to the model | What the model does today | What remains open | |---|---|---|---| diff --git a/reviews/gate_epuf_round2_verification_20261002.md b/reviews/gate_epuf_round2_verification_20261002.md new file mode 100644 index 00000000..2714eb56 --- /dev/null +++ b/reviews/gate_epuf_round2_verification_20261002.md @@ -0,0 +1,106 @@ + + +**Verdict: MERGE AFTER LISTED FIXES.** No blockers. One serious finding and several small ones. The fixes are wording changes in the proposal, the paper, the PR body and possibly one docstring. No rule, threshold or artifact needs to change. + +The record is honest where it matters. The gate does not lock, `gated_cells: {}` is tested, option (a) is withdrawn, and both the pause and the ruling are in the forks ledger. The status of every committed number is below. The serious problem is that the proposal and the block describe a reporting path that the code does not provide. The small ones are mostly overstated or imprecise sentences, three of them in the plain-words outcome and one in the public paper. + +## Round-1 findings 1-17 + +| # | Finding | Status | Evidence | +|---|---|---|---| +| 1 | Option (a) is a self-serving fork; adopt (c) | **PARTLY RESOLVED** | (a) is rejected and withdrawn (`proposal.md:416-436`, `:571-572`). Status is `unlocked_report_only` and `gated_cells: {}` (`block.yaml:16-17,107`). Fork 2 is in the ledger (`proposal.md:528`) and a new id is required (`:583`). **But** the referee's fix "publish the per-cell table with its model/source decomposition on every gate-1 run" is not implemented. See new finding S1. | +| 2 | Bite requirement unreachable by design | RESOLVED | §7.4 calls it an internal inconsistency (`proposal.md:396-406`). The block ruling says the same (`block.yaml:188-191`). §12.2 asks future registrations to check the dose. The test asserts the bite sits below the 90% point (`test_gate_epuf_block_draft.py:171-176`). Fork 2's ledger row does not repeat the wording, which is minor. | +| 3 | Bite fail shares do not measure power | RESOLVED | The supplement stores per-seed estimates, shifts and power `Φ` under the gate's noise model. The formula is two-sided and correct (`build_epuf_gate_supplement.py:70-78`). I recomputed all of it (see below). | +| 4 | No catch beyond gate 1 demonstrated | RESOLVED in §7.4 (`:413-414`) and §12.3 | **But it is overstated in the headline.** See new finding M1. | +| 5 | Wrong rules commit | RESOLVED | `rules_commit: eec910d6…` and `floor_build_commit: 970a9db7…` (`block.yaml:20-21`). Test at `test_gate_epuf_block_draft.py:80-91`, including first-build `head_sha == rules_commit`. | +| 6 | Chronology not auditable | RESOLVED; timestamp DEFERRED-AND-DISCLOSED | The first build is committed with its full SHA-256 and an equality test (`test:102-130`). The full hash `369bf5ec…1847e378` matches the truncated form round 1 saw at `ce8d5000`, which is good evidence. The supplement has `built_utc`. A builder timestamp is listed for future work (§12.5). | +| 7 | Scoring path not pinned | RESOLVED, weakly bound | `scoring_path.sha256` is in the block (`block.yaml:32-34`), with a test at `test:94-99`. The expected hash comes from a fresh render, so re-running the renderer silently re-pins it. See M6. | +| 8 | "Prices" should be "bounds" | RESOLVED | §4 (`:209-213`) and §11.5. One sentence is still unhedged: "A generator that copies donors… has less of it" (`:211-213`). Round 1 said "likely"; that word should come back (M5). | +| 9 | k = 4 is not "the house formula" | RESOLVED in the doc (`:217-220`) | The docstring at `epuf_gate.py:179` still says "the house formula". That file is pinned as derivation core, so it cannot be edited without breaking the artifact binding. This is acceptable, but the proposal should say so. | +| 10 | Reproduction is weak for seeds 5-19 | DEFERRED-AND-DISCLOSED | `proposal.md:277-279`, §12.5. | +| 11 | Birth-year rule shifts the bands | PARTLY RESOLVED | Disclosed (`:136-141`) and listed in §12.5. The supplement adds the within-band mix. **But** the "within 0.25 years" comparison (I checked it: largest gap 0.238, women c2) compares birth-year *labels* after each side was selected on its own label. It cannot show the half-year shift is harmless. See M4. | +| 12 | Minimum events summed over bands | DEFERRED-AND-DISCLOSED | `:246-247`, §12.5. | +| 13 | Bite doses mislabelled | RESOLVED | The §6 table describes what the code does (`:289-293`), matching `build_epuf_gate_floors.py:671,721`. | +| 14 | §7 claims not in artifacts; unsupported mechanisms | PARTLY RESOLVED | The 0.07 shift is now stored. The q_atmax and zero-year mechanisms are hedged (`:350-360`). The "0.06-0.07" comparison and "certifies" are gone. **New unsupported claim:** "EPUF subsampled to PSID scale… gave sigma near this size" (`:403-405`). No artifact or doc in the repo records that subsample (grep finds nothing besides these sentences). See M3. | +| 15 | "Nothing generates a career" overstated | PARTLY RESOLVED | §1 is fixed (`:77-81`). `:100-101` still says "nothing generates earnings for a career". `build_career` appends PROJECTED forward-law years from 2015 (`career.py:25,1043-1046`). Suggested wording: "nothing generates a career's earnings before 1998". | +| 16 | Tranche R mask applies only some rules | RESOLVED | "two of the career assembler's rules" and the exclusions not applied are named (`:474-478`). The pre-1979, empty-span and chronology exclusions and the one-neighbour fallback are not named, but `career.py:1581-1598` is cited. | +| 17 | Seed reuse; NaN in JSON | Seed reuse DEFERRED-AND-DISCLOSED (§12.5); NaN NOT RESOLVED, not disclosed | Harmless: neither committed artifact contains NaN. Add one line to §12.5. | + +## New findings + +**S1 — SERIOUS: the claimed report-only publication path does not exist in code.** +- **What the documents say.** "Every cell publishes report-only with each gate-1 candidate run: the candidate's 20-seed estimate, its distance from EPUF, and that distance split…" with `score_candidate` named as the path (`proposal.md:53-55`, `:430-434`, `:490-493`; `block.yaml:42-45`). +- **What the code does.** + - `score_candidate` → `gate.score_run(per_seed, registered)` computes the estimate, the gap and the decomposition only for cells in `registered`, which is the floor artifact's two r6 cells (`epuf_gate.py:351-367`). The other 39 cells get only raw per-seed values (`epuf_run.py:112-114`). + - It still returns `"pass"`, `"n_gated": 2`, `"n_pass"` — a pass/fail verdict on the two cells. That contradicts "no pass or fail, on any cell" (§9) and creates a risk that someone cites "passes gate_epuf". + - Its docstring still reads "the post-lock run… to a verdict" (`epuf_run.py:3-6`). + - No gate-1 run script calls it: the only caller is `tests/test_epuf_gate_floor_builder.py:355`. +- **Fix.** Either: + - **(a, wording only):** say these comparisons *will* be published once a run script calls the scoring path. Say `score_candidate` today decomposes only `r6.men`/`r6.women`, and that its `pass` field is not a verdict. Or: + - **(b, code):** add a report-only wrapper that computes estimate, gap and decomposition for every cell from the artifact's `cells` block and returns no `pass`. Then re-pin `epuf_run.py` and re-render. This is safe because `epuf_run.py` is not derivation core. + +**M1 — MINOR (headline accuracy): "cannot fail" overstates "not demonstrated".** +- The outcome says "**As registered, it cannot fail the generator for anything gate 1 does not already catch**" (`proposal.md:30-31`). The block header comment (`block.yaml:4-5`), the PR body and the paper say the same. +- The evidence (§7.4 `:413-414`) supports only "no perturbation was shown to pass gate 1 and fail these cells". No bite was ever scored on gate 1. +- **Fix:** "it has not been shown to catch anything gate 1 does not already catch". + +**M2 — MINOR: errors in §7 and the outcome against the artifacts.** +- **Double-rounded bridges.** The `q_atmax.men` bridge is 0.42447, which rounds to **+0.424**, not +0.425. The `q_atmax.women` bridge is 0.08645, which rounds to **+0.086**, not +0.087 (`floors_v1.json:5012,5145`). +- **False claim about cohort cells.** "No cohort-band cell is powered within the caps" (`:362-363`) is wrong. `r6.women.c1` is `eligible` and was reported only as `cohort_rung_not_adopted` (`floors_v1.json:880-882`). +- **The bd2 men's shift overshoots EPUF.** It is +0.056 from 0.667, which lands at about 0.723, roughly 0.012 *past* EPUF's 0.711. "Toward EPUF's value" (`:43`, `:410-411`) should say it moves to about EPUF's level and slightly past it. bd2 is also a perturbation, not "a generator that ignores sex" (`:43`). +- **"About 0.07" is the men's figure only.** The bd1 shift is 0.067 for men and 0.057 for women (`:399-400`); state both. +- **"Only when" ignores the upper edge.** "Fail a generator only when its persistence falls about 0.10 below the PSID's" (`:36-37`) leaves out failure past the upper edge, which is 0.079 above EPUF and about 0.12 above the PSID. +- **"About 2,500 people per sex" (§12) fits men only.** The support has 2,503 men and 3,266 women; the r6 pairs are 2,182 and 2,376. + +**M3 — MINOR: unsupported claim.** "EPUF subsampled to PSID scale… gave sigma near this size" (`:403-405`). Either commit the subsample result or rephrase as "would have given". + +**M4 — MINOR: the birth-year comparison is mislabelled as reassurance** (`:139-141`). Say that it compares labels and does not measure the shift. + +**M5 — MINOR: band means are presented as raw figures.** +- 0.668/0.711, 17.8/11.6% and 9.7/12.8% are unweighted means of three cohort-band values, not pooled statistics. Check: (0.2256+0.1955+0.1116)/3 = 0.1776. +- The "PSID persists less" result holds in 5 of 6 bands; women c1 goes the other way (+0.017). +- Add "averaged over the three birth-cohort bands" in the outcome, §7.2 and the PR table. Hedge the §4 "has less of it" sentence as round 1 asked. + +**M6 — MINOR: test binding.** +- `test_scoring_path_is_pinned` and the supplement hash check compare against a fresh render. Hard-code both literals, as is already done for the first build. +- The supplement test recomputes the 90% detection point but not the 80% one, the distance, or `birth_year_mix`. That falls short of §7's claim that it recomputes "every… power figure" (`:305-307`). +- The supplement asserts only the overall fail share, not `cell_fail_share` (`build_epuf_gate_supplement.py:134-139`). + +**M7 — MINOR: the paper is not quite accurate** (`paper.qmd:366`). +- "We registered the rules… before computing any of it" is not true: per §10, EPUF-only values of every cell and EPUF subsamples had been computed. Say "before computing any PSID value on the file's terms". +- "The PSID is too small for the comparison to pass or fail the generator on anything gate 1 does not already test" has the same overstatement as M1. It also leaves out that some cells dropped because the PSID's own gap from EPUF was too large (`bridge_exceeds_budget`). +- Suggested sentence: "On that overlap only two cells had enough power, and we found nothing they would catch that gate 1 does not, so we report the comparison without a pass or fail." + +**M8 — MINOR: stale "pending lock" wording in immutable or pinned files.** +- `floors_v1.json:5661` has `gate_partition.status: "lockable_pending_referee_round"`. +- The tranche R note says "computed once, after lock" (`:6680`). +- There is also the `epuf_run.py` docstring. +- The artifacts are exclusive-create, so add one sentence to §10 saying the block supersedes these strings. + +## Checked and sound + +- **§7 numbers.** Every number in §7.1, §7.2 (except M2), §7.3, §7.4 and §7.6 matches the two artifacts. Hand checks: + - Tolerances 0.0786 → 0.079 and 0.0784 → 0.078. + - Outward-rounded intervals: −0.1218 → −0.122 and −0.1103 → −0.111. + - Faithful pass probability 0.99935 and 0.99925, product 0.9986. + - 80% points 0.0999 and 0.0995; 90% points 0.1107 and 0.1104. + - Powers: bd1 0.304/0.188, bd1 at 5% 0.031/0.024, bd2 men 0.0038 (upper edge), bd3 men 0.448. +- **§7.6 tranche R table.** All 18 values match; the drops of 10% and 36% (35.5%) are right. +- **§12 arithmetic.** 2σ + 1.2816σ ≈ 0.082. Even a one-sided 95% tolerance (1.645σ) gives 0.073, still above the 0.067 dose. "Cannot be rescued by retuning" holds. +- **Block.** `unlocked_report_only`, `locked: false`, `gated_cells: {}`, `lock_ceremony.exists: false`. Rules and build commits are named separately; the first build, supplement and scoring path are hashed. The selected cells sit under `selected_by_registered_rules` with reason `not_locked_referee_round_1`. Nothing in the block reads as a pending lock. +- **Supplement builder.** It imports the pinned builder by path and reuses its perturbations in the same order, seeds, masks and `score_run`. It asserts the floor's fail shares, and its real-holdout estimate equals the floor's to every digit (0.6670465436202722). The frame is one row per person, so the birth-year weighting is right. +- **Birth-evidence reducer.** The five EPUF modules are excluded with a comment and an exact-tuple test, and a reachability assertion (`test_birth_evidence_artifact.py:464-475`) follows the pattern of the bridge and graph exclusions. Grep finds no import of any EPUF module outside the EPUF files. +- **Code references.** `career.py:650-656` (birth-year precedence), `:1580-1598` (exclusions), `PROJECTED_START_YEAR = 2015`, and the sex-pooled `(bin, period)` marginals at `run_gate1_candidate10.py:557-562` all support the proposal's statements. +- **Terminology.** "Gate" is defined in plain words where a reader first meets it (`:26-27`). "Benchmark" appears in no EPUF document of this PR except the verbatim referee report. + +## What I could not check + +This session had no shell, so I ran no tests and no git commands. + +- **Rules unchanged since `eec910d6`.** I could not diff §§2-6 against the rules-first commit. Indirect evidence: the test asserts the first build (at `eec910d6`) has the same `design` block as the rebuild. Every §2-6 edit I can see is a wording correction or disclosure round 1 asked for, but I cannot rule out other changes. +- **Derivation-core diff.** I could not run `git diff ce8d5000 d606ddea` on the derivation-core files or compute any SHA-256. The binding rests on `test_derivation_files_are_the_ones_the_floor_was_built_with`, which I did not run. +- **Commit chronology.** I could not verify the 13:37 UTC push time or commit 52e10128's precedent directly. +- **PR body.** I read it only through a summarising fetch, so the PR body notes (missing support qualifier on the table, "cannot fail", "144 new tests") are approximate. +- **PSID data.** I read no PSID microdata. \ No newline at end of file diff --git a/scripts/render_gate_epuf_block_draft.py b/scripts/render_gate_epuf_block_draft.py index 8a6d7542..d5ef9445 100644 --- a/scripts/render_gate_epuf_block_draft.py +++ b/scripts/render_gate_epuf_block_draft.py @@ -30,7 +30,7 @@ SUPPLEMENT = ROOT / "runs" / "epuf_gate_supplement_v1.json" BLOCK = ROOT / "docs" / "design" / "gate_epuf_block_draft.yaml" PROPOSAL = "docs/amendments/gate_epuf_registration_proposal.md" -SCORING_PATH = "src/populace_dynamics/harness/epuf_run.py" +REPORTING_PATH = "src/populace_dynamics/harness/epuf_run.py" #: The commit holding the registered rules, pushed before any real-PSID #: value in EPUF units existed (2026-10-02 13:37 UTC, PR #509). @@ -50,23 +50,42 @@ "giving 10 percent of persons a donor's early years shifts the " "1998-2004 rank correlation by about 0.07, so the pause was an " "internal inconsistency of the registration, not a data surprise. " - "The two cells the rules selected add no demonstrated catch beyond " + "The two cells the rules selected have no demonstrated catch beyond " "gate 1, and with the bridge signs public the registered " "candidate's verdict is largely predictable. Relaxing the bite " - "requirement after seeing the result (option (a)) is rejected; the " - "cells publish report-only with every gate-1 run. A gate with bite " + "requirement after seeing the result (option (a)) is rejected; " + "every cell is reported without a pass or fail. A gate with bite " "needs a fresh registration (proposal section 12)." ), } +#: Round 2 verified the record after the round-1 fixes. +ROUND_2 = { + "report": "reviews/gate_epuf_round2_verification_20261002.md", + "reviewer": ( + "independent Opus 5.5 lane (subfleet job " + "20261002-170235-epuf-gate-r2), reviewing head d606ddea" + ), + "verdict": "MERGE AFTER LISTED FIXES (no blockers)", + "fixes": ( + "A report-only path that covers every cell and returns no pass or " + "fail (report_candidate) replaced the two-cell scoring path; the " + "proposal, block and paper say 'not shown to catch' where they " + "said 'cannot fail'; section 7 figures are labelled as means over " + "the three cohort bands and corrected in the third decimal." + ), +} + HEADER = """\ # gate_epuf registration record (unlocked; not in gates.yaml). # # Round 1 of the referee review ruled that the gate does not lock as -# registered: as designed it cannot fail the generator for anything gate 1 -# does not already catch. The block records the registered rules, the -# partition they produced, and the ruling. It gates nothing; every cell -# publishes report-only with each gate-1 run. It edits no gates.yaml byte. +# registered: it has not been shown to catch anything gate 1 does not +# already catch, and its own bite requirement was out of reach. The block +# records the registered rules, the partition they produced, and the ruling. +# It gates nothing; a run reports every cell without a pass or fail +# (populace_dynamics.harness.epuf_run.report_candidate). It edits no +# gates.yaml byte. # # Rendered by scripts/render_gate_epuf_block_draft.py from # runs/epuf_gate_floors_v1.json; tests/test_gate_epuf_block_draft.py requires @@ -136,9 +155,9 @@ def render_block( "path": "runs/epuf_gate_supplement_v1.json", "sha256": hashes["supplement"], }, - "scoring_path": { - "module": SCORING_PATH, - "sha256": hashes["scoring_path"], + "reporting_path": { + "module": REPORTING_PATH, + "sha256": hashes["reporting_path"], }, "external_anchor": { "source": ( @@ -152,11 +171,12 @@ def render_block( ], }, "covers": ( - "Nothing is gated. Every cell is published report-only " - "with each gate-1 candidate run: the candidate's 20-seed " - "estimate, its distance from EPUF, and that distance " - "split into the candidate's distance from the PSID and " - "the PSID's distance from EPUF." + "Nothing is gated. A run reports every cell without a " + "pass or fail: the candidate's 20-seed estimate, its " + "distance from EPUF, and that distance split into the " + "candidate's distance from the PSID and the PSID's " + "distance from EPUF. No run script calls the reporting " + "path yet." ), "not_certified": [ "anything: the gate is unlocked and gates no cell", @@ -182,8 +202,8 @@ def render_block( ), "gate_seeds": design["gate_seeds"], "support": design["support"], - "scoring": ( - "populace_dynamics.harness.epuf_run.score_candidate" + "reporting": ( + "populace_dynamics.harness.epuf_run.report_candidate" ), }, "registered_scoring": { @@ -222,6 +242,7 @@ def render_block( }, "ceremony_pause": artifact["ceremony_pause"], "referee_round_1": ROUND_1, + "verification_round_2": ROUND_2, "lock_ceremony": { "exists": False, "stage": "closed without lock (referee round 1)", @@ -249,6 +270,13 @@ def render_block( "report-only (referee_round_1)." ), }, + { + "id": "2026-10-02-epuf-verification-round-2", + "content": ( + "Verification round 2: merge after listed " + "fixes, applied (verification_round_2)." + ), + }, ], } } @@ -260,7 +288,7 @@ def render() -> str: hashes = { "first_build": _sha256(FIRST_BUILD), "supplement": _sha256(SUPPLEMENT), - "scoring_path": _sha256(ROOT / SCORING_PATH), + "reporting_path": _sha256(ROOT / REPORTING_PATH), } block = render_block(artifact, _sha256(ARTIFACT), hashes) return HEADER + yaml.safe_dump( diff --git a/src/populace_dynamics/harness/epuf_run.py b/src/populace_dynamics/harness/epuf_run.py index 8a7a19f6..9845a697 100644 --- a/src/populace_dynamics/harness/epuf_run.py +++ b/src/populace_dynamics/harness/epuf_run.py @@ -1,17 +1,23 @@ -"""From a candidate's generated panels to the EPUF gate's verdict. +"""From a candidate's generated panels to the EPUF comparison report. -The post-lock run generates a candidate panel for each of the gate's 20 -registered holdouts and hands them here. This module is the whole path -from those panels to a verdict, fixed and tested before lock, so the -run script adds only the generator call and the reproduction check. +``gate_epuf`` is registered and unlocked: referee round 1 ruled that it +gates nothing (``docs/amendments/gate_epuf_registration_proposal.md``). +What a run publishes is therefore a report, not a verdict. For every +window cell, :func:`report_candidate` gives the candidate's 20-seed +estimate, its distance from EPUF, and that distance split into the +candidate's distance from the PSID and the PSID's distance from EPUF. It +returns no pass or fail. A candidate panel is gate 1's candidate-panel shape: the holdout's persons on their observed periods, with generated ``earnings`` (``person_id``, ``period``, ``earnings``; other columns are ignored). -The gate's support is fixed by the real panel alone (who is present in -every window year, whose last period is 2006 or later, sex, birth -year, the 2004 weight), so it is read from the support frame the floor -builder computed, never from the candidate. +The support is fixed by the real panel alone (who is present in every +window year, whose last period is 2006 or later, sex, birth year, the +2004 weight), so it is read from the support frame the floor builder +computed, never from the candidate. + +No run script calls this module yet. A run that regenerates a gate-1 +candidate's 20 panels hands them here. """ from __future__ import annotations @@ -25,6 +31,7 @@ from populace_dynamics.harness.epuf_cells import ( WINDOW_YEARS, WindowArrays, + transform, window_frame, ) from populace_dynamics.harness.epuf_operator import ( @@ -32,7 +39,7 @@ epuf_measure, ) -__all__ = ["candidate_window_cells", "score_candidate"] +__all__ = ["candidate_window_cells", "report_candidate"] def _wage_bases() -> dict[int, float]: @@ -47,7 +54,7 @@ def candidate_window_cells( ) -> dict[str, float]: """One seed's window cells from its generated candidate panel. - ``support`` is the gate's support frame (``person_id``, ``sex``, + ``support`` is the support frame (``person_id``, ``sex``, ``birth_year``, ``weight``). The seed's scored persons are the support persons the candidate panel holds; each must have a generated row at every window year, because a support person is @@ -92,24 +99,56 @@ def candidate_window_cells( return {cell_id: cell.value for cell_id, cell in cells.items()} -def score_candidate( +def _on_scale(cell_id: str, value: float | None) -> float: + return float("nan") if value is None else transform(cell_id, value) + + +def report_candidate( candidates: Mapping[int, pd.DataFrame], support: pd.DataFrame, - registered: Mapping[str, Mapping[str, float]], + cells: Mapping[str, Mapping[str, object]], ) -> dict[str, object]: - """Score the 20 generated panels against the registered intervals. + """Report every window cell of a candidate's 20 generated panels. ``candidates`` maps each gate seed to its candidate panel and - ``registered`` is the floor artifact's ``registered`` block. Returns - :func:`populace_dynamics.harness.epuf_gate.score_run`'s result with - every cell's 20 per-seed values attached (gated or not). + ``cells`` is the floor artifact's ``cells`` block, which holds each + cell's EPUF and PSID values. For every cell the report gives, on the + cell's metric scale (log for shares, identity for rank correlations): + + - ``estimate``: the transform of the mean of the 20 per-seed values; + - ``gap_from_epuf``: the estimate less EPUF's value; + - ``source_term_psid_minus_epuf``: the PSID's distance from EPUF; + - ``model_term_candidate_minus_psid``: the rest of the gap. + + A value that is undefined (a cell with no events on some seed, or no + PSID value) is NaN. The report carries no pass or fail: the gate is + unlocked and gates no cell. """ + if set(candidates) != set(gate.GATE_SEEDS): + raise ValueError( + f"a run reports exactly seeds {gate.GATE_SEEDS[0]}-" + f"{gate.GATE_SEEDS[-1]}; got {sorted(candidates)}" + ) per_seed = { int(seed): candidate_window_cells(panel, support) for seed, panel in candidates.items() } - scored = gate.score_run(per_seed, registered) - scored["per_seed_values"] = { - str(seed): values for seed, values in sorted(per_seed.items()) + report = {} + for cell_id, registered in cells.items(): + values = [per_seed[seed][cell_id] for seed in gate.GATE_SEEDS] + estimate = gate.pooled_estimate(cell_id, values) + epuf = _on_scale(cell_id, registered["epuf_value"]) + source = _on_scale(cell_id, registered["psid_value"]) - epuf + gap = estimate - epuf + report[cell_id] = { + "estimate": estimate, + "gap_from_epuf": gap, + "source_term_psid_minus_epuf": source, + "model_term_candidate_minus_psid": gap - source, + "per_seed_values": values, + } + return { + "status": "report_only", + "n_cells": len(report), + "cells": report, } - return scored diff --git a/tests/README-tiers.md b/tests/README-tiers.md index 7d049a79..fa24ea06 100644 --- a/tests/README-tiers.md +++ b/tests/README-tiers.md @@ -39,9 +39,9 @@ pytest --collect-only -q -m oracle_policyengine | tail -1 | Tier | Tests at HEAD | |---|---:| -| `unit` | 5,800 | -| `artifact` | 3,357 | +| `unit` | 5,802 | +| `artifact` | 3,359 | | `integration_psid` | 1,341 | | `reproduction_legacy` | 520 | | `oracle_policyengine` | 215 | -| **Total** | **11,233** | +| **Total** | **11,237** | diff --git a/tests/test_epuf_gate_floor_builder.py b/tests/test_epuf_gate_floor_builder.py index e4231c27..e6302d8f 100644 --- a/tests/test_epuf_gate_floor_builder.py +++ b/tests/test_epuf_gate_floor_builder.py @@ -331,7 +331,7 @@ def test_bite_demonstrations_report_every_perturbation(built): ) -# --- from candidate panels to a verdict ---------------------------------- +# --- from candidate panels to a report ----------------------------------- def _holdout_panels(panel, universe): @@ -349,34 +349,71 @@ def _holdout_panels(panel, universe): } -def test_a_candidate_equal_to_the_real_panel_scores_as_the_training_copy( +def test_a_candidate_equal_to_the_real_panel_reports_the_real_values( support, built ): - from populace_dynamics.harness.epuf_run import score_candidate + from populace_dynamics.harness.epuf_run import report_candidate panel, _, frame, universe, _ = support _, _, _, out = built - scored = score_candidate( - _holdout_panels(panel, universe), frame, out["registered"] + report = report_candidate( + _holdout_panels(panel, universe), frame, out["cells"] ) - expected = out["training_copy"] - assert scored["pass"] == expected["pass"] - for cell_id, cell in expected["cells"].items(): - assert scored["cells"][cell_id]["gap_from_epuf"] == pytest.approx( + # A report, not a verdict: every cell, and no pass or fail anywhere. + assert report["status"] == "report_only" + assert sorted(report["cells"]) == sorted(cell_ids()) + assert "pass" not in report + assert all("pass" not in cell for cell in report["cells"].values()) + for cell_id, cell in out["training_copy"]["cells"].items(): + assert report["cells"][cell_id]["gap_from_epuf"] == pytest.approx( cell["gap_from_epuf"], abs=1e-12 ) - assert sorted(scored["per_seed_values"]) == sorted( - str(seed) for seed in gate.GATE_SEEDS - ) for seed, values in out["real_gate_seed_values"].items(): for cell_id, value in values.items(): - got = scored["per_seed_values"][seed][cell_id] + got = report["cells"][cell_id]["per_seed_values"][int(seed)] if value is None: assert np.isnan(got) else: assert got == pytest.approx(value, abs=1e-12) +def test_report_splits_each_gap_into_model_and_source_terms(support, built): + from populace_dynamics.harness.epuf_run import report_candidate + + panel, _, frame, universe, _ = support + _, _, _, out = built + report = report_candidate( + _holdout_panels(panel, universe), frame, out["cells"] + ) + checked = 0 + for cell_id, cell in report["cells"].items(): + floor = out["cells"][cell_id] + if floor["psid_value"] is None or np.isnan(cell["gap_from_epuf"]): + continue + assert cell["source_term_psid_minus_epuf"] == pytest.approx( + floor["bridge_psid_minus_epuf"], abs=1e-12 + ) + assert cell["gap_from_epuf"] == pytest.approx( + cell["source_term_psid_minus_epuf"] + + cell["model_term_candidate_minus_psid"], + abs=1e-12, + ) + assert len(cell["per_seed_values"]) == len(gate.GATE_SEEDS) + checked += 1 + assert checked >= 10 + + +def test_report_requires_exactly_the_gate_seeds(support, built): + from populace_dynamics.harness.epuf_run import report_candidate + + panel, _, frame, universe, _ = support + _, _, _, out = built + panels = _holdout_panels(panel, universe) + del panels[19] + with pytest.raises(ValueError, match="seeds 0-19"): + report_candidate(panels, frame, out["cells"]) + + def test_a_candidate_missing_a_window_row_is_refused(support): from populace_dynamics.harness.epuf_run import candidate_window_cells diff --git a/tests/test_gate_epuf_block_draft.py b/tests/test_gate_epuf_block_draft.py index 7d4c9555..9627cc6b 100644 --- a/tests/test_gate_epuf_block_draft.py +++ b/tests/test_gate_epuf_block_draft.py @@ -91,12 +91,19 @@ def test_block_names_the_rules_commit_and_the_build_commit_separately(): assert first["revision_pins"]["head_sha"] == block["rules_commit"] -def test_scoring_path_is_pinned(): +def test_reporting_path_is_pinned(): block = _block() - module = block["scoring_path"]["module"] + module = block["reporting_path"]["module"] assert module == "src/populace_dynamics/harness/epuf_run.py" observed = hashlib.sha256((ROOT / module).read_bytes()).hexdigest() - assert observed == block["scoring_path"]["sha256"] + # A literal, so that re-rendering the block cannot silently re-pin it. + assert observed == ( + "243be0f7a7d17fed689b924af513f9d2645daf436dca25b5234b552b5f9df023" + ) + assert block["reporting_path"]["sha256"] == observed + assert block["candidate_protocol"]["reporting"].endswith( + "epuf_run.report_candidate" + ) def test_first_build_is_frozen_lineage_with_equal_window_results(): @@ -136,9 +143,11 @@ def test_supplement_belongs_to_the_floor_run_and_matches_its_bites(): assert supplement["floor_run_sha256"] == ( hashlib.sha256(ARTIFACT.read_bytes()).hexdigest() ) - assert _block()["supplement"]["sha256"] == ( - hashlib.sha256(SUPPLEMENT.read_bytes()).hexdigest() + supplement_sha256 = hashlib.sha256(SUPPLEMENT.read_bytes()).hexdigest() + assert supplement_sha256 == ( + "1570f80e5b42c0890871a818e29f09bdf55fdafe26ba4a2aaa7cade4280ea676" ) + assert _block()["supplement"]["sha256"] == supplement_sha256 assert supplement["candidate_blind"]["generated_candidates"] == 0 bites = supplement["bites"] for name, row in artifact["bite_demonstrations"].items(): @@ -148,6 +157,20 @@ def test_supplement_belongs_to_the_floor_run_and_matches_its_bites(): for cell_id, cell in bites[name]["cells"].items(): estimates = cell["estimates_over_perturbation_seeds"] assert len(estimates) == 50 + # The stored estimates reproduce the floor's per-cell fail share. + registered = artifact["registered"][cell_id] + epuf_value = transform(cell_id, registered["epuf_value"]) + outside = [ + not ( + registered["lower"] + <= estimate - epuf_value + <= registered["upper"] + ) + for estimate in estimates + ] + assert sum(outside) / len(outside) == ( + row["cell_fail_share"][cell_id] + ) assert cell["mean_shift"] == pytest.approx( sum(estimates) / len(estimates) - cell["real_gate_holdout_estimate"] @@ -165,6 +188,13 @@ def test_supplement_belongs_to_the_floor_run_and_matches_its_bites(): floor = artifact["cells"][cell_id] sigma = floor["floor"]["realized_sigma"] distance = floor["bridge_psid_minus_epuf"] - floor["lower"] + assert point["distance_from_psid_to_lower_edge"] == pytest.approx( + distance + ) + assert point["realized_sigma"] == pytest.approx(sigma) + assert point["shortfall_failing_80_percent"] == pytest.approx( + distance + 0.8416 * sigma + ) assert point["shortfall_failing_90_percent"] == pytest.approx( distance + 1.2816 * sigma ) @@ -299,3 +329,38 @@ def test_gate_holdouts_are_gate_ones(): assert sorted(holdouts, key=int) == [str(s) for s in gate.GATE_SEEDS] for row in gate1["per_seed"]: assert holdouts[str(row["seed"])]["n_persons"] == row["n_persons"] + + +def test_supplement_birth_year_mix_is_a_distribution_within_each_band(): + supplement = json.loads(SUPPLEMENT.read_text(encoding="utf-8")) + mix = supplement["birth_year_mix"] + assert sorted(mix) == sorted( + f"{sex}.{band}" + for sex in ("men", "women") + for band in ("c0", "c1", "c2") + ) + for row in mix.values(): + years = row["birth_years"] + assert years == list(range(years[0], years[0] + 9)) + for side in ("psid_support_weighted_share", "epuf_share"): + assert len(row[side]) == 9 + assert sum(row[side]) == pytest.approx(1.0) + for side, mean in ( + ("psid_support_weighted_share", "psid_mean_birth_year"), + ("epuf_share", "epuf_mean_birth_year"), + ): + assert row[mean] == pytest.approx( + sum(y * w for y, w in zip(years, row[side], strict=True)) + ) + assert abs( + row["psid_mean_birth_year"] - row["epuf_mean_birth_year"] + ) < (0.25) + + +def test_block_records_both_review_rounds(): + block = _block() + for key in ("referee_round_1", "verification_round_2"): + assert (ROOT / block[key]["report"]).is_file() + assert ( + "MERGE AFTER LISTED FIXES" in block["verification_round_2"]["verdict"] + ) diff --git a/tests/tier_counts.json b/tests/tier_counts.json index 019fd592..eb530d6e 100644 --- a/tests/tier_counts.json +++ b/tests/tier_counts.json @@ -1,8 +1,8 @@ { "schema_version": 1, "counts": { - "unit": 5800, - "artifact": 3357, + "unit": 5802, + "artifact": 3359, "integration_psid": 1341, "reproduction_legacy": 520, "oracle_policyengine": 215 From 95291e7543ca956d57c79953134227356212790c Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 17:35:38 -0400 Subject: [PATCH 7/9] EPUF gate: apply the approving re-review's five minor points The re-review of the round-2 fixes (reviews/gate_epuf_round3_rereview_ 20261002.md) approved head 93848324 and listed five minor points. - The paper and the proposal's outcome say only two cells "met the rules for gating". A third cell had the power but the ladder did not select it, so "had enough power" contradicted section 7.2. - report_candidate is now tested against the committed artifact, where the bridges are not zero: the source term equals the stored bridge, the model term is the rest, and undefined values propagate. - The supplement tests assert their cell sets and band years, so none can pass on an empty loop. - Section 10 lists the round-2 commit; the checklist says "reporting path"; the block's ruling gives the bite shift for both sexes. Co-Authored-By: Claude Opus 5.5 --- .../gate_epuf_registration_proposal.md | 25 ++-- docs/design/gate_epuf_block_draft.yaml | 18 ++- paper/paper.qmd | 2 +- reviews/gate_epuf_round3_rereview_20261002.md | 131 ++++++++++++++++++ scripts/render_gate_epuf_block_draft.py | 14 +- tests/README-tiers.md | 4 +- tests/test_gate_epuf_block_draft.py | 96 ++++++++++++- tests/tier_counts.json | 2 +- 8 files changed, 267 insertions(+), 25 deletions(-) create mode 100644 reviews/gate_epuf_round3_rereview_20261002.md diff --git a/docs/amendments/gate_epuf_registration_proposal.md b/docs/amendments/gate_epuf_registration_proposal.md index 70676651..2b2373e7 100644 --- a/docs/amendments/gate_epuf_registration_proposal.md +++ b/docs/amendments/gate_epuf_registration_proposal.md @@ -33,8 +33,8 @@ catch anything gate 1 does not already catch, and it could not meet its own check on its bite, so it does not lock.** - The generator's earnings overlap EPUF in four years, 1998-2004. On that - overlap only two cells had the power the rules demand: how persistent - earnings ranks are from 1998 to 2004, for men and for women. + overlap only two cells met the rules for gating: how persistent earnings + ranks are from 1998 to 2004, for men and for women. - Those two cells fail a generator whose persistence falls about 0.10 below the PSID's four times in five, and one about 0.11 below nine times in ten. The interval also ends 0.08 above EPUF, so one that overshoots EPUF by @@ -424,8 +424,8 @@ Two more readings, both from the supplement: - Donors drawn from both sexes (`bd2`) raise men's persistence by 0.056, to about EPUF's level and 0.012 past it, where the interval accepts it. `bd2` is a perturbation of real data, not a generator. Its donors are matched on - 2004 deciles, and the same-sex control (`bd2c`) moves the cells by 0.01 or - less, so the matching itself keeps the rank correlation. Within that limit, + 2004 deciles, and the same-sex control (`bd2c`) moves the cells by about + 0.01, so the matching itself keeps the rank correlation. Within that limit, the cells by sex showed no catch for pooling the sexes. - No perturbation was shown to pass gate 1's battery and fail these cells. Their catch beyond gate 1 is not demonstrated. @@ -513,8 +513,9 @@ and its distance from EPUF is the bridge itself. A run that regenerates a gate-1 candidate reports each cell's 20-seed estimate, its distance from EPUF, and the split of that distance into the candidate's distance from the PSID and the PSID's distance from EPUF -(`report_candidate`, which returns no pass or fail). Tranche R reports the -career statistics beside the masked EPUF values. No run has been made. +(`report_candidate`, which returns no pass or fail). Tranche R would report +the career statistics beside the masked EPUF values; no code computes its +PSID side yet. No run has been made. Nothing is certified. In particular: @@ -541,8 +542,11 @@ Nothing is certified. In particular: 3. `ce8d5000` added the rebuilt artifact, the draft block and section 7. Neither artifact records its build time. The supplement records its own (2026-10-02 20:55 UTC). -4. The round-1 commit adds the referee report, the supplement, the frozen - first build, the ruling and these corrections. +4. The round-1 commit (`d606ddea`) adds the referee report, the supplement, + the frozen first build, the ruling and the round-1 corrections. +5. The round-2 commit (`93848324`) adds `report_candidate`, the round-2 + report and its corrections. A last commit applies the five minor points of + the re-review that approved it. **Forks ledger.** @@ -567,7 +571,7 @@ bind to cannot be edited without breaking that binding, so a few of their strings predate the ruling. `gate_partition.status` in the floor artifact reads `lockable_pending_referee_round`, and its tranche R note says "computed once, after lock". The docstring of `epuf_gate.tolerance` calls the formula -"the house formula". The block and this document supersede them: nothing is +"the house floor formula". The block and this document supersede them: nothing is pending a lock, and `k = 4` is not house precedent (section 4). ## 11. Considered and rejected @@ -638,6 +642,7 @@ before its floor is built: - [x] Proposal: this document, the floor artifact, the draft block - [x] Adversarial referee round 1 (verdict AMEND) - [x] Fixes: the supplement, the frozen first build, separate rules and build - commits in the block, a pinned scoring path, corrected wording + commits in the block, a pinned reporting path, corrected wording - [x] Ruling: closed without lock; every cell report-only - [x] Verification round 2 (verdict: merge after listed fixes, applied) +- [x] Re-review of the round-2 fixes (verdict: approve) diff --git a/docs/design/gate_epuf_block_draft.yaml b/docs/design/gate_epuf_block_draft.yaml index fda633b8..2d07ae30 100644 --- a/docs/design/gate_epuf_block_draft.yaml +++ b/docs/design/gate_epuf_block_draft.yaml @@ -190,12 +190,13 @@ gates: ruling: 'Not locked. The registered persistence bite could not be met by design: the tolerance is about 3.2 realised sigmas (0.079) while giving 10 percent of persons a donor''s early years shifts the 1998-2004 rank correlation by - about 0.07, so the pause was an internal inconsistency of the registration, - not a data surprise. The two cells the rules selected have no demonstrated - catch beyond gate 1, and with the bridge signs public the registered candidate''s - verdict is largely predictable. Relaxing the bite requirement after seeing - the result (option (a)) is rejected; every cell is reported without a pass - or fail. A gate with bite needs a fresh registration (proposal section 12).' + 0.067 for men and 0.057 for women, so the pause was an internal inconsistency + of the registration, not a data surprise. The two cells the rules selected + have no demonstrated catch beyond gate 1, and with the bridge signs public + the registered candidate''s verdict is largely predictable. Relaxing the + bite requirement after seeing the result (option (a)) is rejected; every + cell is reported without a pass or fail. A gate with bite needs a fresh registration + (proposal section 12).' verification_round_2: report: reviews/gate_epuf_round2_verification_20261002.md reviewer: independent Opus 5.5 lane (subfleet job 20261002-170235-epuf-gate-r2), @@ -206,6 +207,11 @@ gates: and paper say 'not shown to catch' where they said 'cannot fail'; section 7 figures are labelled as means over the three cohort bands and corrected in the third decimal. + rereview_round_3: + report: reviews/gate_epuf_round3_rereview_20261002.md + reviewer: independent Opus 5.5 lane (subfleet job 20261002-172832-epuf-gate-r3), + reviewing head 93848324 + verdict: APPROVE (five minor points, applied) lock_ceremony: exists: false stage: closed without lock (referee round 1) diff --git a/paper/paper.qmd b/paper/paper.qmd index 31dabd5e..df55ac9d 100644 --- a/paper/paper.qmd +++ b/paper/paper.qmd @@ -363,7 +363,7 @@ The model addresses these limits in two ways, and we plan a third. None removes **Gates scored on the PSID.** The gates that score the model against the PSID set most of their tolerances from the discrepancy between two disjoint halves of the real PSID panel (@sec-scoring). A smaller panel produces a wider floor and a looser tolerance. Gates 2, 2b, 2c, m4 and m6 demote to report-only any cell whose weaker half holds fewer than 20 events or whose tolerance would exceed a cap, ln(1.5) for most cells and 0.15 for gate m6's earnings correlations (`gates.yaml`). These rules price the PSID's sampling noise. They cannot detect a bias that both halves share, because both halves come from the same selected and attrited panel: such a gate tests whether the model reproduces the PSID, and leaves open how far the PSID departs from the population. Gate m6 scores only the people the PSID observed in each later wave, treats the PSID's record of deaths above age 85 as confounded by attrition, and certifies nothing about mortality drift (`gates.yaml`, gate_m6). -**A planned check against administrative earnings records.** We plan to set the earnings careers the model reads from the PSID, and those it generates, against the Social Security Administration's 2006 Earnings Public-Use File. The file holds annual earnings records for 1951 through 2006 from a 1 percent random sample of all Social Security numbers issued before 2007, 4,384,254 people in all [@ssa2011epuf; @ssa2011epufdict].^[SSA's article introducing the file gives 4,348,254 in three places and 4,384,254 in another; its own count of the underlying sample less the records it removed yields 4,384,254 [@compson2011epuf].] Its records come from the earnings posted to workers' Social Security records, so they do not depend on anyone continuing to answer a survey. They hold only earnings up to each year's taxable maximum from jobs Social Security covers, with wages and self-employment combined, and the file records each person's birth year and sex and nothing about marriage, children, disability or death [@compson2011epuf]. The file follows each person across years, so it can test change over time as well as single years. Moffitt and Zhang report that the PSID's earnings data have never been matched to government administrative records [@moffitt2020estimating]. The comparison would run by birth year and sex and cover the share of years with no covered earnings, the share of low-earnings years, movement into and out of covered work, and how persistent a worker's position stays over time. Selective attrition and weak low-end reporting would distort these statistics, and the PSID's own halves cannot reveal the distortion. The comparison has to put the model's earnings on the file's terms, capped at each year's taxable maximum and limited to covered work. It also has to put the two populations on common terms. The file records no deaths, so a run of years without earnings can mean retirement, disability or death [@compson2011epuf], and its sample of Social Security numbers includes the post-1968 immigrants the PSID largely leaves out. The file's own low end is coarse: SSA replaces every amount under $100 with that year's average and rounds amounts from $100 to $1,000 at random to a base of $25 [@ssa2011epufdict; @compson2011epuf]. We registered the rules for one part of this comparison before computing any PSID value on the file's terms, as we do every gate (`docs/amendments/gate_epuf_registration_proposal.md`). That part covers the generated earnings, which overlap the file only in the even years from 1998 to 2004. On that overlap only two cells had enough power, and we found nothing they would catch that gate 1 does not, so we report the comparison without a pass or fail. We have not yet scored the model's earnings against the file, and we have not run the comparison of careers. +**A planned check against administrative earnings records.** We plan to set the earnings careers the model reads from the PSID, and those it generates, against the Social Security Administration's 2006 Earnings Public-Use File. The file holds annual earnings records for 1951 through 2006 from a 1 percent random sample of all Social Security numbers issued before 2007, 4,384,254 people in all [@ssa2011epuf; @ssa2011epufdict].^[SSA's article introducing the file gives 4,348,254 in three places and 4,384,254 in another; its own count of the underlying sample less the records it removed yields 4,384,254 [@compson2011epuf].] Its records come from the earnings posted to workers' Social Security records, so they do not depend on anyone continuing to answer a survey. They hold only earnings up to each year's taxable maximum from jobs Social Security covers, with wages and self-employment combined, and the file records each person's birth year and sex and nothing about marriage, children, disability or death [@compson2011epuf]. The file follows each person across years, so it can test change over time as well as single years. Moffitt and Zhang report that the PSID's earnings data have never been matched to government administrative records [@moffitt2020estimating]. The comparison would run by birth year and sex and cover the share of years with no covered earnings, the share of low-earnings years, movement into and out of covered work, and how persistent a worker's position stays over time. Selective attrition and weak low-end reporting would distort these statistics, and the PSID's own halves cannot reveal the distortion. The comparison has to put the model's earnings on the file's terms, capped at each year's taxable maximum and limited to covered work. It also has to put the two populations on common terms. The file records no deaths, so a run of years without earnings can mean retirement, disability or death [@compson2011epuf], and its sample of Social Security numbers includes the post-1968 immigrants the PSID largely leaves out. The file's own low end is coarse: SSA replaces every amount under $100 with that year's average and rounds amounts from $100 to $1,000 at random to a base of $25 [@ssa2011epufdict; @compson2011epuf]. We registered the rules for one part of this comparison before computing any PSID value on the file's terms, as we do every gate (`docs/amendments/gate_epuf_registration_proposal.md`). That part covers the generated earnings, which overlap the file only in the even years from 1998 to 2004. On that overlap only two cells met the rules for gating, and we found nothing they would catch that gate 1 does not, so we report the comparison without a pass or fail. We have not yet scored the model's earnings against the file, and we have not run the comparison of careers. | Limit | What it does to the model | What the model does today | What remains open | |---|---|---|---| diff --git a/reviews/gate_epuf_round3_rereview_20261002.md b/reviews/gate_epuf_round3_rereview_20261002.md new file mode 100644 index 00000000..1fbc7327 --- /dev/null +++ b/reviews/gate_epuf_round3_rereview_20261002.md @@ -0,0 +1,131 @@ + + +**APPROVE** + +# Re-review of PR #509 (gate_epuf registration) at head `93848324` + +Head `93848324` is an accurate record of a registration that does not lock, and it is safe to merge to `master`. S1 is fixed in code: `report_candidate` reports all 41 window cells and returns no pass or fail. Its arithmetic matches the pinned algebra. M1–M8 and the round-1 residue are resolved. The fixes introduced no blockers and no serious problems. Five minor points are listed below. One is a sentence in the public paper that now disagrees with §7.2, so I'd fix that one before merge, but it doesn't block. + +## What was checked + +- **Diffs.** I read the round-2 fix delta and the proposal diff since `eec910d6`. The derivation-core diff since `ce8d5000` is empty, as stated. +- **Hashes.** The hash list in `.diag/hashes-and-tests.txt` matches all of these: + - the block (`gate_epuf_block_draft.yaml:25,28,33,36`); + - the literals in `tests/test_gate_epuf_block_draft.py:100-102,147-149,111-113`; + - the artifact's `revision_pins.derivation_core_sha256` (`runs/epuf_gate_floors_v1.json:7316-7322`). +- **Tests.** The drafting session reports 152 targeted tests passing. I did not run them. + +## S1, M1–M8 + +| Item | Status | Evidence | +|---|---|---| +| **S1**: a reporting path that covers every cell and gives no verdict | **RESOLVED** | See the S1 details below. | +| **M1**: "cannot fail" | **RESOLVED** | No "cannot fail" claim is left in any EPUF document; the phrase survives only inside the record of round 2's fix (`block.yaml:206`) and in the review files. The new wording is "has not been shown to catch… and it could not meet its own check on its bite" (`proposal.md:31-33`, `block.yaml:4-5`), plus "No perturbation was shown to pass gate 1 and fail these cells" (`proposal.md:49,430-431`). | +| **M2**: §7 and the outcome against the artifacts | **RESOLVED** (small residue in the block) | See the M2 details below. | +| **M3**: the subsample sentence | **RESOLVED** | It is now stated as a counterfactual (`proposal.md:416-418`), and the algebra supports it. The distance from the PSID to the lower edge is `max(0,B)+t`, which is at least `t` whatever the bridge. So the 90% detection point is at least about `t + 1.28σ`, roughly 4.5σ. Sigma alone was enough to show that a 0.067 dose could not be caught nine times in ten. | +| **M4**: the birth-year sentence | **RESOLVED** | `proposal.md:148-151` now says the comparison "compares the two sides' own labels… so it does not measure the shift". | +| **M5**: band means shown as raw figures | **RESOLVED** in the proposal | The labels are at `proposal.md:55-58` and `:317-318`. This matches the code: `epuf_cells.py:29-31` defines a sex-level cell as the unweighted mean of its three bands. The §4 sentence is hedged ("likely has less of it", `:222`). For the PR-body table, see "What I could not check". | +| **M6**: test binding | **RESOLVED** | See the M6 details below. Minor gaps remain (new finding 3). | +| **M7**: the paper | **RESOLVED**, with new finding 1 | `paper.qmd:366` now says "before computing any PSID value on the file's terms", which matches the chronology (`proposal.md:530-533`). It adopts round 2's suggested sentence. But "only two cells had enough power" now contradicts §7.2 (finding 1). | +| **M8**: superseded strings | **RESOLVED** (one small misquote) | `proposal.md:565-571` names both strings, which exist at `floors_v1.json:5661` and `:6680`. The docstring is quoted as "the house formula" but actually reads "the house floor formula" (`epuf_gate.py:179`; also "house tolerance" at `:38`). | + +**S1 details** + +- **What the code does.** `epuf_run.py::report_candidate` loops over every cell in the floor artifact's `cells` block. That is all 41 window cells (`test_gate_epuf_block_draft.py:225`). It returns only `status`, `n_cells` and `cells`. +- **Arithmetic.** + - The estimate is `gate.pooled_estimate`: the mean of the 20 seeds, then `transform`, and NaN if any seed is not finite (`epuf_gate.py:134-143`). + - The gap and the source term match `score_cell` and `score_run` term for term (`epuf_gate.py:320-321,360-366`). + - I checked a nonzero case by hand. For `q_atmax.men`, ln(0.177582/0.116159) = 0.42447, which equals `bridge_psid_minus_epuf` (`floors_v1.json:5008-5012`). +- **Undefined values.** A missing (None) PSID or EPUF value becomes NaN through `_on_scale`. `transform` gives NaN for a share ≤ 0. NaN then carries through the gap and both terms. +- **Seeds.** Anything other than seeds 0–19 is refused, and that is tested. +- **Docstring.** The verdict wording is gone, and it says "No run script calls this module yet". +- **Tests.** "No pass" is asserted on the report and on every cell (`test_epuf_gate_floor_builder.py`, in the round-2 diff). The synthetic tests are weak, though (new finding 2). +- **Documents.** They say exactly what the code does, including that nothing calls it yet: + - proposal: `:12`, `:60-64`, `:447-454`, `:513-517`; + - block: `covers` (`:44-47`), `candidate_protocol.reporting` (`:91`), header (`:7-8`); + - the paper does not name the path and makes no claim about it. + +**M2 details** + +- **Bridges.** +0.424 and +0.086 (`proposal.md:348-349`) match `floors_v1.json:5012`. +- **Cohort cell.** `r6.women.c1` is now said to be eligible but not adopted (`:374-377`). The block agrees (`block.yaml:140`). +- **bd2.** Men's persistence goes 0.6670 + 0.0561 = 0.7231, which is 0.012 past EPUF's 0.7109 (`:424-425`, supplement `:307`). bd2 is now called a perturbation, not a generator. Its description at `:47-48` matches `build_epuf_gate_floors.py:681-688`. +- **bd1.** The shift is −0.0665 for men and −0.0568 for women (supplement `:69,126`), shown as 0.067/0.057 (`:414`) and 0.07/0.06 (`:43`). +- **Upper edge.** It is 0.079/0.078 (`floors_v1.json:5715,5721`), described as "ends 0.08 above EPUF" (`:40-41`). +- **Pair counts.** 2,182 and 2,376 (`:609`) equal `psid_n` at `floors_v1.json:4215,4347`. +- **Five of six cells.** The bridges of the six `r6` cohort cells (`floors_v1.json:237…902`) are negative in five; women c1 is +0.0173 (`:769`), as stated at `:358-359`. +- **Residue.** The block's ruling text still says "about 0.07", which is the men's figure only (`block.yaml:193`). + +**M6 details** + +- Literal hashes are now asserted (`test_gate_epuf_block_draft.py:100-102,147-149`), and they equal the hash list. +- The 80% and 90% detection points, the distance and sigma are recomputed (`:191-200`). +- The per-cell fail share is recomputed from the 50 stored estimates (`:161-173`). +- A test of the birth-year mix was added (`:334-357`). + +## Round-1 residue + +| # | Status | Evidence | +|---|---|---| +| 1 | **RESOLVED** | The table published per cell is implemented (S1). Status is `unlocked_report_only` and `gated_cells: {}` (`block.yaml:18,109`). | +| 8 | **RESOLVED** | "likely has less of it" (`proposal.md:222`). | +| 9 | **RESOLVED** | Superseded in §10 (`:569-571`); it misquotes the docstring slightly (see M8). | +| 11 | **RESOLVED** | Same as M4 (`:148-151`). | +| 14 | **RESOLVED** | Same as M3 (`:416-418`). | +| 15 | **RESOLVED** | "nothing generates a career's earnings before 1998" (`:109`). | +| 16 | **RESOLVED** | All five exclusions are named (`:498-501`) and match `career.py:1580-1598`. | +| 17 | **RESOLVED** | NaN is disclosed as future work in §12.5 (`:633-634`). | + +## Rules unchanged, nothing locked + +- **§§2–6 since `eec910d6`.** Every change is wording, a disclosure, or a description brought into line with code that was already pinned (the §6 bd1/bd3 rows). No threshold, cap, `k`, seed rule or ladder rule changed. The first-build equality test (`test_gate_epuf_block_draft.py:119-132`) also requires the build at `eec910d6` to have the same `design`, partition and bites as the rebuild. +- **The added §2 sentence.** "EPUF enters nothing upstream of the model" (`:164`) tightens the validation-only rule. It does not loosen anything. +- **Nothing locks.** + - `gates.yaml` has no EPUF match, and the test asserts this (`:74-77`). + - The block has `locked: false` (`:19`), `gated_cells: {}` (`:109`) and `lock_ceremony.exists: false` (`:210`). + - The two selected cells are listed under `report_only` as `not_locked_referee_round_1`. + +## New findings + +1. **MINOR: "only two cells had enough power" contradicts §7.2.** + - `paper.qmd:366` says "only two cells had enough power", and `proposal.md:36` says "only two cells had the power the rules demand". + - The M2 fix made §7.2 say that `r6.women.c1` is *eligible*: it passed the power and cap rules and was not adopted only because of the ladder (`proposal.md:374-377`, `block.yaml:140`). The paper is public. + - **Fix:** in both places, say "only two cells were selected under the rules" (or "met the rules for gating"). +2. **MINOR: the synthetic tests of `report_candidate` cannot catch errors in the source or model term.** + - The `built` fixture uses the support's own values as the EPUF reference, so every bridge is zero (`test_epuf_gate_floor_builder.py:163-165`). + - That makes the check `source == bridge` a check of 0 == 0. It would pass even with the sign reversed or on the wrong scale. + - `gap == source + model` is true by construction. + - The comparison with `training_copy` covers only the synthetic build's gated cells, and nothing asserts that set is non-empty. + - The code is right (checked by hand above), but no test proves it. + - **Fix:** add a unit test that monkeypatches `candidate_window_cells` to return fixed per-seed values and passes in the committed artifact's `cells` block. Assert, for every defined cell: + - `source_term_psid_minus_epuf == bridge_psid_minus_epuf` (the bridges are nonzero there); + - `estimate == gate.pooled_estimate(...)`; + - a NaN seed gives a NaN estimate, and a missing `psid_value` gives NaN terms. + + Then re-pin nothing, since the test file is not pinned. +3. **MINOR: three supplement checks could pass vacuously.** + - `test_supplement_belongs_to_the_floor_run_and_matches_its_bites` loops over `bites[name]["cells"]` and `bites["detection_points"]` without asserting they are non-empty (`test_gate_epuf_block_draft.py:157,187`). + - The birth-year test does not tie `years[0]` to the band's first year (`:344`). + - **Fix:** + - `assert set(bites[name]["cells"]) == set(artifact["registered"])`; + - `assert set(bites["detection_points"]) == {"r6.men", "r6.women"}`; + - `assert years[0] == COHORT_BANDS[band][0]`. +4. **MINOR: the record of commits stops at round 1.** + - §10 "Order of commits" ends at item 4 (`proposal.md:544-545`) and does not list `93848324`. Round 2 appears only in §7.5 and the block. + - The §13 checklist still says "a pinned scoring path" (`:641`). + - **Fix:** add "5. The round-2 commit adds `report_candidate`, the round-2 report and these corrections", and change "scoring path" to "reporting path". +5. **MINOR: three small wording points.** + - The block's round-1 ruling says "about 0.07"; it should say "0.067 for men, 0.057 for women" (`render_gate_epuf_block_draft.py`, then re-render). + - §10 should quote "the house floor formula" exactly. + - §7.4 says bd2c "moves the cells by 0.01 or less", but women's figure is +0.0102 (supplement `:483`). "About 0.01" would be exact. + - Optional: §9's "Tranche R reports the career statistics" (`:516-517`) is in the present tense, but no code computes tranche R's PSID side. "Would report" is more accurate; §10 `:562-563` already says it has not been computed. + +## What I could not check + +- **Tests.** I had no shell, so I ran no tests, no git commands and no hashing. The hashes and the 152-pass result are taken from `.diag/hashes-and-tests.txt`; I only compared them for consistency. +- **Synthetic `training_copy`.** I could not confirm that the synthetic build's `training_copy` holds any cells (finding 2). +- **PR body.** I read it only through a summarising fetch. It shows "not shown to catch", `report_candidate` and "No run script calls it yet". I could not confirm that its PSID/EPUF table carries the "means over the three birth-cohort bands" label. +- **Push time.** I could not check the 13:37 UTC push time directly. The branch log shows `eec910d6` at 09:36 −04:00, before the build commits. +- **PSID data.** I read no PSID microdata. \ No newline at end of file diff --git a/scripts/render_gate_epuf_block_draft.py b/scripts/render_gate_epuf_block_draft.py index d5ef9445..925a11fe 100644 --- a/scripts/render_gate_epuf_block_draft.py +++ b/scripts/render_gate_epuf_block_draft.py @@ -48,7 +48,8 @@ "Not locked. The registered persistence bite could not be met by " "design: the tolerance is about 3.2 realised sigmas (0.079) while " "giving 10 percent of persons a donor's early years shifts the " - "1998-2004 rank correlation by about 0.07, so the pause was an " + "1998-2004 rank correlation by 0.067 for men and 0.057 for women, " + "so the pause was an " "internal inconsistency of the registration, not a data surprise. " "The two cells the rules selected have no demonstrated catch beyond " "gate 1, and with the bridge signs public the registered " @@ -76,6 +77,16 @@ ), } +#: Round 3 re-reviewed the round-2 fixes. +ROUND_3 = { + "report": "reviews/gate_epuf_round3_rereview_20261002.md", + "reviewer": ( + "independent Opus 5.5 lane (subfleet job " + "20261002-172832-epuf-gate-r3), reviewing head 93848324" + ), + "verdict": "APPROVE (five minor points, applied)", +} + HEADER = """\ # gate_epuf registration record (unlocked; not in gates.yaml). # @@ -243,6 +254,7 @@ def render_block( "ceremony_pause": artifact["ceremony_pause"], "referee_round_1": ROUND_1, "verification_round_2": ROUND_2, + "rereview_round_3": ROUND_3, "lock_ceremony": { "exists": False, "stage": "closed without lock (referee round 1)", diff --git a/tests/README-tiers.md b/tests/README-tiers.md index fa24ea06..e28a4e93 100644 --- a/tests/README-tiers.md +++ b/tests/README-tiers.md @@ -40,8 +40,8 @@ pytest --collect-only -q -m oracle_policyengine | tail -1 | Tier | Tests at HEAD | |---|---:| | `unit` | 5,802 | -| `artifact` | 3,359 | +| `artifact` | 3,361 | | `integration_psid` | 1,341 | | `reproduction_legacy` | 520 | | `oracle_policyengine` | 215 | -| **Total** | **11,237** | +| **Total** | **11,239** | diff --git a/tests/test_gate_epuf_block_draft.py b/tests/test_gate_epuf_block_draft.py index 9627cc6b..52535dc4 100644 --- a/tests/test_gate_epuf_block_draft.py +++ b/tests/test_gate_epuf_block_draft.py @@ -20,7 +20,11 @@ from scipy.stats import norm from populace_dynamics.harness import epuf_gate as gate -from populace_dynamics.harness.epuf_cells import cell_ids, transform +from populace_dynamics.harness.epuf_cells import ( + COHORT_BANDS, + cell_ids, + transform, +) ROOT = Path(__file__).resolve().parents[1] ARTIFACT = ROOT / "runs" / "epuf_gate_floors_v1.json" @@ -154,6 +158,7 @@ def test_supplement_belongs_to_the_floor_run_and_matches_its_bites(): if name in ("requirements", "pause"): continue assert bites[name]["fail_share_reproduced"] == row["fail_share"] + assert set(bites[name]["cells"]) == set(artifact["registered"]) for cell_id, cell in bites[name]["cells"].items(): estimates = cell["estimates_over_perturbation_seeds"] assert len(estimates) == 50 @@ -184,6 +189,7 @@ def test_supplement_belongs_to_the_floor_run_and_matches_its_bites(): assert cell["power_under_gate_noise_model"] == pytest.approx( expected ) + assert set(bites["detection_points"]) == {"r6.men", "r6.women"} for cell_id, point in bites["detection_points"].items(): floor = artifact["cells"][cell_id] sigma = floor["floor"]["realized_sigma"] @@ -339,9 +345,10 @@ def test_supplement_birth_year_mix_is_a_distribution_within_each_band(): for sex in ("men", "women") for band in ("c0", "c1", "c2") ) - for row in mix.values(): + for key, row in mix.items(): years = row["birth_years"] - assert years == list(range(years[0], years[0] + 9)) + low, high = COHORT_BANDS[key.split(".")[1]] + assert years == list(range(low, high + 1)) for side in ("psid_support_weighted_share", "epuf_share"): assert len(row[side]) == 9 assert sum(row[side]) == pytest.approx(1.0) @@ -359,8 +366,89 @@ def test_supplement_birth_year_mix_is_a_distribution_within_each_band(): def test_block_records_both_review_rounds(): block = _block() - for key in ("referee_round_1", "verification_round_2"): + for key in ("referee_round_1", "verification_round_2", "rereview_round_3"): assert (ROOT / block[key]["report"]).is_file() + assert block["rereview_round_3"]["verdict"].startswith("APPROVE") assert ( "MERGE AFTER LISTED FIXES" in block["verification_round_2"]["verdict"] ) + + +def _fixed_per_seed_values(cells): + """Invented per-seed cell values near each cell's PSID value.""" + values = {} + for seed in gate.GATE_SEEDS: + tilt = 1.0 + 0.004 * (seed - 9.5) + values[seed] = { + cell_id: ( + 0.5 if cell["psid_value"] is None else cell["psid_value"] + ) + * tilt + for cell_id, cell in cells.items() + } + return values + + +def test_report_candidate_terms_against_the_committed_bridges(monkeypatch): + from populace_dynamics.harness import epuf_run + + cells = _artifact()["cells"] + values = _fixed_per_seed_values(cells) + monkeypatch.setattr( + epuf_run, + "candidate_window_cells", + lambda panel, support: values[panel], + ) + candidates = {seed: seed for seed in gate.GATE_SEEDS} + report = epuf_run.report_candidate(candidates, None, cells) + assert report["status"] == "report_only" + assert "pass" not in report + assert sorted(report["cells"]) == sorted(cell_ids()) + nonzero_bridges = 0 + for cell_id, row in report["cells"].items(): + assert "pass" not in row + per_seed = [values[seed][cell_id] for seed in gate.GATE_SEEDS] + assert row["per_seed_values"] == per_seed + estimate = gate.pooled_estimate(cell_id, per_seed) + assert row["estimate"] == pytest.approx(estimate) + cell = cells[cell_id] + epuf_value = transform(cell_id, cell["epuf_value"]) + assert row["gap_from_epuf"] == pytest.approx(estimate - epuf_value) + if cell["psid_value"] is None: + assert math.isnan(row["source_term_psid_minus_epuf"]) + assert math.isnan(row["model_term_candidate_minus_psid"]) + continue + bridge = cell["bridge_psid_minus_epuf"] + assert row["source_term_psid_minus_epuf"] == pytest.approx(bridge) + assert row["model_term_candidate_minus_psid"] == pytest.approx( + estimate - transform(cell_id, cell["psid_value"]) + ) + nonzero_bridges += abs(bridge) > 0.01 + # The committed bridges are not zero, so the terms' signs are tested. + assert nonzero_bridges >= 25 + + +def test_report_candidate_propagates_undefined_values(monkeypatch): + from populace_dynamics.harness import epuf_run + + cells = { + cell_id: dict(cell) for cell_id, cell in _artifact()["cells"].items() + } + cells["r6.women"]["psid_value"] = None + values = _fixed_per_seed_values(cells) + values[7]["r6.men"] = float("nan") + monkeypatch.setattr( + epuf_run, + "candidate_window_cells", + lambda panel, support: values[panel], + ) + report = epuf_run.report_candidate( + {seed: seed for seed in gate.GATE_SEEDS}, None, cells + )["cells"] + # A seed with an undefined value makes the cell's estimate undefined. + assert math.isnan(report["r6.men"]["estimate"]) + assert math.isnan(report["r6.men"]["gap_from_epuf"]) + # A cell with no PSID value keeps its gap but has no split. + assert not math.isnan(report["r6.women"]["gap_from_epuf"]) + assert math.isnan(report["r6.women"]["source_term_psid_minus_epuf"]) + assert math.isnan(report["r6.women"]["model_term_candidate_minus_psid"]) diff --git a/tests/tier_counts.json b/tests/tier_counts.json index eb530d6e..7cbced40 100644 --- a/tests/tier_counts.json +++ b/tests/tier_counts.json @@ -2,7 +2,7 @@ "schema_version": 1, "counts": { "unit": 5802, - "artifact": 3359, + "artifact": 3361, "integration_psid": 1341, "reproduction_legacy": 520, "oracle_policyengine": 215 From 56938042733dad8746d307ef5a83ba0561217e9b Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 3 Oct 2026 22:08:45 -0400 Subject: [PATCH 8/9] EPUF gate: record the confirmation review and apply its three optional points - reviews/gate_epuf_round4_confirmation_20261002.md commits round 4 (job 20261002-173551-epuf-gate-r4, head 95291e75) verbatim; the block records it as confirmation_round_4. - Rounds 3 and 4 keep the reviewer's verdict apart from the fixes. - The committed-bridges test checks each estimate against the seeds' mean computed without pooled_estimate. The invented seed values are now skewed: with the old symmetric tilt, a median passed. A median and a mean of logs each fail the test now. - One proposal line rewrapped; section 10 names 95291e75. Co-Authored-By: Claude Opus 5.5 --- .../gate_epuf_registration_proposal.md | 8 +-- docs/design/gate_epuf_block_draft.yaml | 12 ++++- .../gate_epuf_round4_confirmation_20261002.md | 52 +++++++++++++++++++ scripts/render_gate_epuf_block_draft.py | 21 +++++++- tests/test_gate_epuf_block_draft.py | 22 ++++++-- 5 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 reviews/gate_epuf_round4_confirmation_20261002.md diff --git a/docs/amendments/gate_epuf_registration_proposal.md b/docs/amendments/gate_epuf_registration_proposal.md index 2b2373e7..0b853340 100644 --- a/docs/amendments/gate_epuf_registration_proposal.md +++ b/docs/amendments/gate_epuf_registration_proposal.md @@ -545,8 +545,10 @@ Nothing is certified. In particular: 4. The round-1 commit (`d606ddea`) adds the referee report, the supplement, the frozen first build, the ruling and the round-1 corrections. 5. The round-2 commit (`93848324`) adds `report_candidate`, the round-2 - report and its corrections. A last commit applies the five minor points of + report and its corrections. `95291e75` applies the five minor points of the re-review that approved it. +6. A confirmation review of `95291e75` approved it with three optional + points. The commit that records that review applies them. **Forks ledger.** @@ -571,8 +573,8 @@ bind to cannot be edited without breaking that binding, so a few of their strings predate the ruling. `gate_partition.status` in the floor artifact reads `lockable_pending_referee_round`, and its tranche R note says "computed once, after lock". The docstring of `epuf_gate.tolerance` calls the formula -"the house floor formula". The block and this document supersede them: nothing is -pending a lock, and `k = 4` is not house precedent (section 4). +"the house floor formula". The block and this document supersede them: +nothing is pending a lock, and `k = 4` is not house precedent (section 4). ## 11. Considered and rejected diff --git a/docs/design/gate_epuf_block_draft.yaml b/docs/design/gate_epuf_block_draft.yaml index 2d07ae30..b4da36cc 100644 --- a/docs/design/gate_epuf_block_draft.yaml +++ b/docs/design/gate_epuf_block_draft.yaml @@ -211,7 +211,17 @@ gates: report: reviews/gate_epuf_round3_rereview_20261002.md reviewer: independent Opus 5.5 lane (subfleet job 20261002-172832-epuf-gate-r3), reviewing head 93848324 - verdict: APPROVE (five minor points, applied) + verdict: APPROVE (five minor points) + fixes: applied in 95291e75 + confirmation_round_4: + report: reviews/gate_epuf_round4_confirmation_20261002.md + reviewer: independent Opus 5.5 lane (subfleet job 20261002-173551-epuf-gate-r4), + reviewing head 95291e75 + verdict: APPROVE (three optional points) + fixes: The committed-bridges test checks each estimate against the mean of + its seeds, computed without pooled_estimate, on seed values skewed so that + a median or a mean of logs fails; rounds 3 and 4 record the verdict and the + fixes apart; one proposal line is rewrapped. lock_ceremony: exists: false stage: closed without lock (referee round 1) diff --git a/reviews/gate_epuf_round4_confirmation_20261002.md b/reviews/gate_epuf_round4_confirmation_20261002.md new file mode 100644 index 00000000..6f4ea963 --- /dev/null +++ b/reviews/gate_epuf_round4_confirmation_20261002.md @@ -0,0 +1,52 @@ + + +**APPROVE** + +All five of round 3's points are fixed at `95291e75`. The delta adds no false claim and nothing that reads as a lock or a certification. `gates.yaml` still has no EPUF entry, and the block still has `locked: false` and `gated_cells: {}`. I had no shell, so this rests on reading the files; I didn't run the tests. + +| # | Round-3 point | Status | Evidence | +|---|---|---|---| +| 1 | "only two cells had enough power" in the paper and the proposal's outcome | **RESOLVED** | Both now say "only two cells met the rules for gating" (`paper/paper.qmd:366`, `proposal.md:36`), the wording round 3 suggested. The sentence is now true and matches §7.2–7.3. §7.2 says `r6.women.c1` is eligible but not gated, because the ladder gates cohort cells only when all six are eligible (`proposal.md:374-377`). §7.3 says "The ladder fell back to sex-level persistence and selected two cells" (`:381`). The rest of the paper sentence ("we found nothing they would catch that gate 1 does not… without a pass or fail") matches §7.4 (`:430-431`). No "enough power" or "had the power" is left in the paper, proposal, block or renderer. | +| 2 | `report_candidate` tests: source and model terms on nonzero bridges, and the NaN paths | **RESOLVED** | See the notes below the table. | +| 3 | Supplement tests could pass vacuously | **RESOLVED** | See the notes below the table. | +| 4 | §10 commit record and the checklist wording | **RESOLVED** | Item 4 now names `d606ddea`. A new item 5 names `93848324` (`report_candidate`, the round-2 report and its corrections) and mentions the final commit. The checklist says "a pinned reporting path" and adds the re-review line. "Scoring path" survives only in the block's round-2 record (`block.yaml:206`, renderer `:73`), where it correctly describes what was replaced. | +| 5 | Four wording fixes | **RESOLVED** | • Block ruling (rendered from the script, `block.yaml:190-199`): "0.067 for men and 0.057 for women". This matches §7.4 and the supplement's −0.0665/−0.0568.
• §10 quotes "the house floor formula", the docstring's exact text (`epuf_gate.py:179`).
• §7.4 says bd2c moves the cells "about 0.01", matching the table's +0.007/+0.010 (`proposal.md:402`).
• §9 says tranche R "would report… no code computes its PSID side yet". `career_cells` is called only on EPUF data (`build_epuf_gate_floors.py:295-296`), so this is accurate. | + +**Point 2 in detail.** The new tests cannot pass vacuously: + +- **Real bridges, not the synthetic fixture.** `test_report_candidate_terms_against_the_committed_bridges` feeds the committed artifact's `cells` into `report_candidate`. `candidate_window_cells` is stubbed out (monkeypatched); `report_candidate` calls it through the module, so the stub takes effect. +- **Nonzero bridges.** I counted the artifact's 41 bridges: 38 have |b| > 0.01, against the test's floor of 25. Only three are below 0.01 (0.0045, −0.0097, −0.0095). +- **Source term.** The test compares the code's `psid − epuf` on the cell's scale with the stored `bridge_psid_minus_epuf`. A flipped sign or a wrong scale would now fail. +- **Model term.** It is checked as `estimate − transform(psid)`, which is computed separately from the code's `gap − source`. +- **Coverage.** The test asserts that the report's cell ids equal `cell_ids()`, so all 41 cells are checked. It also asserts that neither the report nor any cell carries a `pass` key. +- **Defined values only.** `pytest.approx` never treats NaN as equal to NaN, so the test cannot pass by producing NaN. +- **NaN paths.** `test_report_candidate_propagates_undefined_values` sets one seed of `r6.men` to NaN, which makes its estimate and gap NaN. It sets `r6.women`'s `psid_value` to None, which leaves the gap defined but makes both split terms NaN (via `_on_scale`, `epuf_run.py:102-103`). + +**Point 3 in detail.** + +- `set(bites[name]["cells"]) == set(artifact["registered"])` is added (`test:161`). It can't hold for empty sets: the detection-point loop indexes `bites["bd1_persistence_loss_0.10"]["cells"]["r6.men"]` and `["r6.women"]` (`:209`), which would fail if those cells were missing. +- `set(bites["detection_points"]) == {"r6.men", "r6.women"}` is a literal (`:192`). +- The band years are now tied to `COHORT_BANDS` (`:350-351`), which defines c0 = 1947–1955, c1 = 1956–1964 and c2 = 1965–1973. + +**New findings.** Nothing blocks merge. Three optional nits: + +- **The pooled estimate is checked against itself.** Test 1 compares `estimate` with `gate.pooled_estimate`, the same function the code calls, so an error in that function would go unnoticed. Fix (optional): also assert `row["estimate"] == pytest.approx(transform(cell_id, statistics.fmean(per_seed)))`. +- **The round-3 verdict mixes in the drafting session's claim.** The block records `verdict: APPROVE (five minor points, applied)` (`block.yaml` `rereview_round_3`), but "applied" is the drafting session's claim, not the reviewer's verdict. Round 2's record uses the same pattern. Fix (optional): `verdict: APPROVE (five minor points)` and `fixes: applied in 95291e75`. +- **One long line.** `proposal.md:574` ("the house floor formula" line) now runs past the wrap width. + +**Lock and certification check.** + +- `gates.yaml` has 0 EPUF matches. +- The block has `status: unlocked_report_only` (`:18`), `locked: false` (`:19`), `gated_cells: {}` (`:109`) and `lock_ceremony.exists: false` (`:216`). +- The header says it "gates nothing" and "edits no gates.yaml byte". +- The diff adds no wording about passing, locking or certifying. The phrase "met the rules for gating" sits beside "report the comparison without a pass or fail". + +**What I could not check:** + +- **Tests.** I ran no tests. So I couldn't confirm that the two new tests pass, that the tier count of +2 (3,359 → 3,361) is right, or that the block equals a fresh render. +- **Git.** I ran no git commands. I took the delta from `.diag/round3-fix-delta.diff`, and the claim that the derivation-core diff since `ce8d5000` is empty from the drafting session. +- **Hashes.** I computed none. The supplement and artifact hash literals are unchanged in the diff. +- **PR body.** I didn't read it. +- **PSID data.** I read no PSID microdata. \ No newline at end of file diff --git a/scripts/render_gate_epuf_block_draft.py b/scripts/render_gate_epuf_block_draft.py index 925a11fe..ea542e0f 100644 --- a/scripts/render_gate_epuf_block_draft.py +++ b/scripts/render_gate_epuf_block_draft.py @@ -84,7 +84,25 @@ "independent Opus 5.5 lane (subfleet job " "20261002-172832-epuf-gate-r3), reviewing head 93848324" ), - "verdict": "APPROVE (five minor points, applied)", + "verdict": "APPROVE (five minor points)", + "fixes": "applied in 95291e75", +} + +#: Round 4 confirmed the final head. +ROUND_4 = { + "report": "reviews/gate_epuf_round4_confirmation_20261002.md", + "reviewer": ( + "independent Opus 5.5 lane (subfleet job " + "20261002-173551-epuf-gate-r4), reviewing head 95291e75" + ), + "verdict": "APPROVE (three optional points)", + "fixes": ( + "The committed-bridges test checks each estimate against the mean " + "of its seeds, computed without pooled_estimate, on seed values " + "skewed so that a median or a mean of logs fails; rounds 3 and 4 " + "record the verdict and the fixes apart; one proposal line is " + "rewrapped." + ), } HEADER = """\ @@ -255,6 +273,7 @@ def render_block( "referee_round_1": ROUND_1, "verification_round_2": ROUND_2, "rereview_round_3": ROUND_3, + "confirmation_round_4": ROUND_4, "lock_ceremony": { "exists": False, "stage": "closed without lock (referee round 1)", diff --git a/tests/test_gate_epuf_block_draft.py b/tests/test_gate_epuf_block_draft.py index 52535dc4..10167000 100644 --- a/tests/test_gate_epuf_block_draft.py +++ b/tests/test_gate_epuf_block_draft.py @@ -13,6 +13,7 @@ import hashlib import json import math +import statistics from pathlib import Path import pytest @@ -364,11 +365,19 @@ def test_supplement_birth_year_mix_is_a_distribution_within_each_band(): ) < (0.25) -def test_block_records_both_review_rounds(): +def test_block_records_every_review_round(): block = _block() - for key in ("referee_round_1", "verification_round_2", "rereview_round_3"): + rounds = ( + "referee_round_1", + "verification_round_2", + "rereview_round_3", + "confirmation_round_4", + ) + for key in rounds: assert (ROOT / block[key]["report"]).is_file() - assert block["rereview_round_3"]["verdict"].startswith("APPROVE") + for key in ("rereview_round_3", "confirmation_round_4"): + assert block[key]["verdict"].startswith("APPROVE") + assert "applied" not in block[key]["verdict"] assert ( "MERGE AFTER LISTED FIXES" in block["verification_round_2"]["verdict"] ) @@ -378,7 +387,8 @@ def _fixed_per_seed_values(cells): """Invented per-seed cell values near each cell's PSID value.""" values = {} for seed in gate.GATE_SEEDS: - tilt = 1.0 + 0.004 * (seed - 9.5) + # Skewed, so the seeds' mean differs from their median. + tilt = 1.0 + 0.004 * (seed - 9.5) + 0.0002 * (seed - 9.5) ** 2 values[seed] = { cell_id: ( 0.5 if cell["psid_value"] is None else cell["psid_value"] @@ -411,6 +421,10 @@ def test_report_candidate_terms_against_the_committed_bridges(monkeypatch): assert row["per_seed_values"] == per_seed estimate = gate.pooled_estimate(cell_id, per_seed) assert row["estimate"] == pytest.approx(estimate) + # Computed without pooled_estimate: average the seeds, then transform. + assert estimate == pytest.approx( + transform(cell_id, statistics.fmean(per_seed)) + ) cell = cells[cell_id] epuf_value = transform(cell_id, cell["epuf_value"]) assert row["gap_from_epuf"] == pytest.approx(estimate - epuf_value) From 65daf03b198a49116b439f90daba79cf3d348008 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 3 Oct 2026 22:40:02 -0400 Subject: [PATCH 9/9] EPUF gate: complete the block's history through round 4 The history list stopped at round 2, and its round-2 line mixed the verdict with the fixes. It now has one entry per review round, each keeping the verdict apart from the commit that applied the fixes, and the rounds test checks every round appears in the history. Co-Authored-By: Claude Opus 5.5 --- docs/design/gate_epuf_block_draft.yaml | 8 +++++++- scripts/render_gate_epuf_block_draft.py | 17 ++++++++++++++++- tests/test_gate_epuf_block_draft.py | 3 +++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/design/gate_epuf_block_draft.yaml b/docs/design/gate_epuf_block_draft.yaml index b4da36cc..58ca4def 100644 --- a/docs/design/gate_epuf_block_draft.yaml +++ b/docs/design/gate_epuf_block_draft.yaml @@ -235,4 +235,10 @@ gates: - id: 2026-10-02-epuf-referee-round-1 content: 'Referee round 1: AMEND. Ruling: not locked; report-only (referee_round_1).' - id: 2026-10-02-epuf-verification-round-2 - content: 'Verification round 2: merge after listed fixes, applied (verification_round_2).' + content: 'Verification round 2: merge after listed fixes (verification_round_2); + fixes applied in 93848324.' + - id: 2026-10-02-epuf-rereview-round-3 + content: 'Re-review round 3: approve, five minor points (rereview_round_3); + fixes applied in 95291e75.' + - id: 2026-10-02-epuf-confirmation-round-4 + content: 'Confirmation round 4: approve, three optional points (confirmation_round_4).' diff --git a/scripts/render_gate_epuf_block_draft.py b/scripts/render_gate_epuf_block_draft.py index ea542e0f..e5a03bc0 100644 --- a/scripts/render_gate_epuf_block_draft.py +++ b/scripts/render_gate_epuf_block_draft.py @@ -305,7 +305,22 @@ def render_block( "id": "2026-10-02-epuf-verification-round-2", "content": ( "Verification round 2: merge after listed " - "fixes, applied (verification_round_2)." + "fixes (verification_round_2); fixes applied " + "in 93848324." + ), + }, + { + "id": "2026-10-02-epuf-rereview-round-3", + "content": ( + "Re-review round 3: approve, five minor points " + "(rereview_round_3); fixes applied in 95291e75." + ), + }, + { + "id": "2026-10-02-epuf-confirmation-round-4", + "content": ( + "Confirmation round 4: approve, three optional " + "points (confirmation_round_4)." ), }, ], diff --git a/tests/test_gate_epuf_block_draft.py b/tests/test_gate_epuf_block_draft.py index 10167000..f85c5310 100644 --- a/tests/test_gate_epuf_block_draft.py +++ b/tests/test_gate_epuf_block_draft.py @@ -378,6 +378,9 @@ def test_block_records_every_review_round(): for key in ("rereview_round_3", "confirmation_round_4"): assert block[key]["verdict"].startswith("APPROVE") assert "applied" not in block[key]["verdict"] + history = " ".join(entry["content"] for entry in block["history"]) + for key in rounds: + assert f"({key})" in history assert ( "MERGE AFTER LISTED FIXES" in block["verification_round_2"]["verdict"] )