From 3595427567223ad46e7c189857f401a32cfb9315 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 24 Oct 2026 11:49:29 -0400 Subject: [PATCH 1/4] U2: commit the pre-registration evidence record (hashes only, cleared by value-free scan) Adds docs/design/u2_preregistration_evidence.json, a byte-for-byte copy of the record the section 20 step-4 pass wrote under d1724 at 1e739d32. Its SHA-256 equals loader.PREREGISTRATION_EVIDENCE_SHA256 (7bc5c3c26ff014271061a8228068c6e71103430ec299048462570476a510b845). Co-Authored-By: Claude Opus 5.5 --- docs/design/u2_preregistration_evidence.json | 148 +++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 docs/design/u2_preregistration_evidence.json diff --git a/docs/design/u2_preregistration_evidence.json b/docs/design/u2_preregistration_evidence.json new file mode 100644 index 00000000..8ee0dfa9 --- /dev/null +++ b/docs/design/u2_preregistration_evidence.json @@ -0,0 +1,148 @@ +{ + "cited_sources_sha256": { + "PSID/documentation/capture1/cross_sec_weights_13.pdf": "77c084c40210484b5d33f484fe5ce1049406b98b19d2f365b796aed0627e0070", + "PSID/documentation/capture1/cross_sec_weights_15.pdf": "c872cdc9d26db324bc6a580af47fa1c465547f8ff25a0e7f686242846c4f4f02", + "PSID/documentation/capture1/cross_sec_weights_17.pdf": "b35b5d9c99e74983c84d519383ba2b586c5db33f6b666d16370c54dbdb7a5438", + "PSID/documentation/capture1/cross_sec_weights_19.pdf": "6ef4795c5af79828aacb6f549bef58c9deffbf67f87651050bc03db4e991fc84", + "PSID/documentation/capture1/cross_sec_weights_21.pdf": "b7b128e71233f60998fa265e3cc08e6c1f4990c26d977f5d5ca9c59c3a012d4c", + "PSID/documentation/capture1/q2013.pdf": "5f966b9268ed428acd9454263296b31006220c69b33b6b36b8f6364436332c0d", + "PSID/documentation/capture1/q2015.pdf": "f3a4613bc8c1017f7cb40b30db4034d5f9a9234aad8022679ecd5c399f42e4e8", + "PSID/documentation/capture1/q2017.pdf": "733a9be8591080e09179857e672808d8cbf9b9ff351b2adf2c9e8200d893d9dc", + "PSID/documentation/capture1/q2019.pdf": "e848a2a8ea5bb7cfb14f87f98410a33b4ca7de85c51916acb7c8a49503c92835", + "PSID/documentation/capture1/q2021.pdf": "6c639ec32bfdd2176b5823d31815e31ac0db732a46ed05f22aa6a892cc1c31fb", + "PSID/documentation/capture1/q2023.pdf": "adc9975e1d7e901eb7192e6c6498f53be0eda62e0393ef1b06de0c85c511cad8", + "PSID/family/2013/FAM2013ER.sps": "526595b50a2087adc635da3c1288a396aa7179b075c11506f10338ab6348a0b5", + "PSID/family/2013/FAM2013ER_codebook.pdf": "40cc2de6af801b94b93518f7252e24c7c95098e713fc97f9ead1af74c4ce25d6", + "PSID/family/2015/FAM2015ER.sps": "6500c8e88a2353e7a6c5322a898f3879662228fdefa329e0901eb254fc9e3fff", + "PSID/family/2015/FAM2015ER_codebook.pdf": "7dcb71f823e309a286b904531410243d58cde48b8f50079401856de9ac762238", + "PSID/family/2017/FAM2017ER.sps": "24abae319022d4e3da9bce8052455dfee6b00b7b9c642004eddcfa06cb8d59e5", + "PSID/family/2017/FAM2017ER_codebook.pdf": "19bfba9f7a3fecc82a18711466e2b2a5f00b49c9d3db0f9f8587795fad2bf8c1", + "PSID/family/2019/FAM2019ER.sps": "c9f8ba8698779aeaf239c0eea4b1f98d32975b1c77767acfd35601fcb883a5b0", + "PSID/family/2019/fam2019er_codebook.pdf": "ce637e37e0f5e306dd7f10455e85069b56c9b13d5c138d3eb4b9c8d6a8452406", + "PSID/family/2021/FAM2021ER.sps": "50526906dafd86271074ba15fd426ab7030c2b62f29acf3d819b577fdc9442e2", + "PSID/family/2021/FAM2021ER_codebook.pdf": "e3b88ef394952fa05b9b98eb7f05bf9a99896840515942562aa37399e1bcd462", + "PSID/family/2021/FAM2021ER_formats.sps": "863f151a4cab1282060aa3bfe4f6648bbbc1822e6f739bcfd502ff13b40a952c", + "PSID/family/2023/FAM2023ER.sps": "915755685965a41743e96e42abbbfdddd7eab1df33234e462b0813b25d4df169", + "PSID/family/2023/FAM2023ER_codebook.pdf": "85a4078ebb79146d023df3d9d4e2d2ef6017eced849656ca39f4b740cb5a5688", + "PSID/family/2023/FAM2023ER_formats.sps": "89e4f2be4bea66fe83e0f11682bdcfab2590c01310bd697833846377d64a59f2", + "PSID/ind2023er/IND2023ER.sps": "92d32d0efd65d50e984e971c681f6e9231b720973444cdc8f20f397039c9a462", + "PSID/ind2023er/IND2023ER_codebook.pdf": "4878100887dce1a7b7831af272a9f19b01ec33dcea091a5c7352625ecd464308", + "PSID/ind2023er/IND2023ER_formats.sps": "b42b3560fb3116af0cc6bf0740824cbc24b0ff94d7a1fd4891e40c7a12f93dc4", + "PSID/mh85_23/MH85_23.sps": "6f4a194b74c2dc7b95f2a163aeab19244384099ac0966dbe735157a60c1953ad", + "PSID/mh85_23/MH85_23_Codebook.pdf": "d7b7d0f4b7b6a2653a45f38665482f9447fdcd59ccc7a678b3c4d23546273034", + "PSID/mh85_23/MH85_23_formats.sps": "f7db069e55329eb1e2272dd4163244dfa7a05e323726144c0854b70f14c1186d", + "tests/data/track_u2/psid_sources/cross_sec_weights_17.pdf": "b35b5d9c99e74983c84d519383ba2b586c5db33f6b666d16370c54dbdb7a5438", + "tests/data/track_u2/psid_sources/cross_sec_weights_23.pdf": "58411f56001e6089226ce5fc9ebcd132e85f9e917571d3fe54dcdc5139e63983" + }, + "frame_environment": { + "future_infer_string": true, + "pandas_version": "3.0.6" + }, + "input_frames_sha256": "d37d0379e56884fec4d0d883a1b655e6b66f53f03fe4c1c229dff087b2cb5de4", + "psid_files_bundle_sha256": "0dec885e58d97e2cd6e7e95cba6b6b5019e77306718a7b57eda2233e453ae374", + "psid_files_sha256": { + "family/1968/FAM1968.sps": "a2adbebfb2af38cafb2669e2aebef489f24e9e1d0c1b5e8cd2b23287dcadaaa5", + "family/1968/FAM1968.txt": "9fb3f8b872e139f23afc158cc205440af385a1e619a5cc9a95f83fa61b85bb78", + "family/1969/FAM1969.sps": "94a07c16e393cae68538d715d6a722a3c0de6e02dc8c9e56c5e658725db622c2", + "family/1969/FAM1969.txt": "f564d78850ce6a5e262389df9dc20fae52a3e63f5ae6b141bba787dd04c72fdd", + "family/1970/FAM1970.sps": "0212c4fd983a19b9c1cdd71feb4d92beed9d3906f807b485ef209ebd9f6d75f0", + "family/1970/FAM1970.txt": "8d28224213dc9d2dd31e1ac70ee9775ff257350926c0f595782de95f5ad4d84c", + "family/1971/FAM1971.sps": "8a6ccfc9ba6110dabe8147b528c2e0b2ada2d701889ea9bb03aa6c9bf0d479ae", + "family/1971/FAM1971.txt": "97360718a1f76e910ff2f2941dc0c65d6022016a570d53435b8ede97cef0b73c", + "family/1972/FAM1972.sps": "04b8594dda71404ff2e27734ff20ba8c7f9b982d2a4c834e61d59958000a5b9e", + "family/1972/FAM1972.txt": "5b1148272096ea8b50351ae4a98c1792be666b9ab140b344ee72434abd867055", + "family/1973/FAM1973.sps": "10f4b5e346529c6f5f4705842dfaa25186d514725fac6cc3a6b50dfabe3c33c4", + "family/1973/FAM1973.txt": "ae656b7f4b689f82259bec0e392e425df61eb8ab446b1bcb4187e25de568d011", + "family/1974/FAM1974.sps": "e043119eca809a3a32cbd086b5a17db114da72305446cb54ffa6e134e5ca0082", + "family/1974/FAM1974.txt": "579d98750c34753bfd3ee16149bb1124dd8cbd531b97c65a41e9fe0ae7e7f6cf", + "family/1975/FAM1975.sps": "a120da243300e5684f946f98acc25414f62579ec8c9c675267bbcce48c88f6e3", + "family/1975/FAM1975.txt": "26f6c07de11b9cbfc1ca0ff2942851b73f9e2f89df1abd0b77f2cda5fc097776", + "family/1976/FAM1976.sps": "f1884fe637284802ee2c4d0d147ed5f42a048e5f9d30a9c8c05bc53142d61771", + "family/1976/FAM1976.txt": "b35387e2b04bb9515f5edc1a31cc4b55a5bf018f9aa102ead4d7399e5d8b0824", + "family/1977/FAM1977.sps": "2367ae4b09af04ae0b69ef4cd65a1b47303f7526e24a16483ff1edd21fabbe53", + "family/1977/FAM1977.txt": "6314e1ae1784a6d5267ec863c96432c11a8b22a45a09170d7c7322ff0faaa1d8", + "family/1978/FAM1978.sps": "2a0eaa0fab5a17dc02a3c344b65599d3169d0a95bab1a2d6b9129454c4886239", + "family/1978/FAM1978.txt": "39764f180bf8431e7947027ef656c7910e832c01facfb86c8534735bdf42e12d", + "family/1979/FAM1979.sps": "3c1041d482cde534562f251f7cf6a9a7369980fdf5e4b691fa7413c5fa7e58ed", + "family/1979/FAM1979.txt": "6666f099d276fe353180b0e1d3881e06be70f656bda87d4f05a04ef7ed80e529", + "family/1980/FAM1980.sps": "acba02dc6d341d2cc4a8cd0a8b1365edf9f1d2c90dba32b4ddc83667b6750d67", + "family/1980/FAM1980.txt": "a1e28e6e689cbe990ae0cf9d4bbc268c75c5a30a21e0ff7297a970f69ac8a054", + "family/1981/FAM1981.sps": "a914dd7d130fca11745d2f099f5181d3e347d4a1206706a4524982f1bc5d4509", + "family/1981/FAM1981.txt": "b38c3093711aaa9e74875a610d874f155be6ed4b3a2bf67badc740a7373a149e", + "family/1982/FAM1982.sps": "e99097b4fad8dbd1fc99740ee6632db2cfb678dd3dbd7142f62f50bb4b1ff05a", + "family/1982/FAM1982.txt": "dc3510d641a9b878528977bdaa1173c46e9cb89db2e0003575213db80cc6476b", + "family/1983/FAM1983.sps": "685e7c076eb68a79a5a7c5e4f6a6bbe94fa7769ba5c5883775978b7b2ece0f3e", + "family/1983/FAM1983.txt": "acf81d4911373984974e02fce4707bb4779c72f00e30d01fbc7c16d6cc68a140", + "family/1984/FAM1984.sps": "ad90da0506c5c556ef8b527e1d6c75a057b30bd05ba5e09588df514053630368", + "family/1984/FAM1984.txt": "bc92bb4d845241db96864b038476a6524ae5f43311db708972dd8bd8084bb9ef", + "family/1985/FAM1985.sps": "07b156f52c91dbcc66944b983f601553d9ddb94bb343248434d55e3d01eb7c2f", + "family/1985/FAM1985.txt": "db0daa1860e69fce5c66567a5d64b0bd07be3d31e0c70046bc7e474d22119f51", + "family/1986/FAM1986.sps": "a8d57b14f4efc36170cc2577174ab336b026a01e61f0639f8e3b8d1f82d930da", + "family/1986/FAM1986.txt": "f78ba17a5e50df3860b65e957777ad778bd0a49308b1ab684ad7ca9893a8d3c8", + "family/1987/FAM1987.sps": "3f1816e8bd169ba55ddb2c42cc5488d00adb8913f17687d7885cec8fe5f812bd", + "family/1987/FAM1987.txt": "b0512acd98ef280878271840229af34401f30702e01d8d646191f049e4bdcba0", + "family/1988/FAM1988.sps": "a2971802f1e81107e27cf7c426986f387db8bed9481026a4cf876bcd9bad6f69", + "family/1988/FAM1988.txt": "e30bd0ead4bba2238108a51eb2e24eee935a4a38e0d4257efdd1cff1bd23389c", + "family/1989/FAM1989.sps": "bf034bb3e45dc8ff5ec6a25c34d81f7888e922686e66362f2fa57bfd7c452058", + "family/1989/FAM1989.txt": "524d0627d471a66dcfa73ace35389e8117d426d56d6c7804df742e91ab7be728", + "family/1990/FAM1990.sps": "8eb30ab1a766c3b60e0e84aab24f197992c2cd0947c33acfb6d34684fc28fe67", + "family/1990/FAM1990.txt": "318fc47527ec48f8ebc8bc7114649a5a85b978e591a964fd46a8735935c0dc95", + "family/1991/FAM1991.sps": "dec4e504682dc08014a82307e3dd78d2833cc0f16ae8a3eaee1693f2fdf11e32", + "family/1991/FAM1991.txt": "01e39177b72be26da8eeb62d193ac0c5e47265a530a8a484dc271687e45fd3cb", + "family/1992/FAM1992.sps": "0c512da1ad8bc7ffb764b07376edf5200a5a166287ca4c4070a4b371010c9bb5", + "family/1992/FAM1992.txt": "d392f84b96b5f76bff8cccc0dde3defa8fc02a1646d3fcf607e0f5e91d3698b7", + "family/1993/FAM1993.sps": "acf13fda9d02d5a2cfdcf4a180a3bffbb4dcd2a64770b6312d0933cf7b111a08", + "family/1993/FAM1993.txt": "76ac2c830d9912cba11c3187a6c1c47612142894592f955ac1f03aabb8e3153e", + "family/1994/FAM1994ER.sps": "c5ae483c602e0cb1ce5cb280c4704d9ee49bd09ba5fd2ff1747c571abd693c43", + "family/1994/FAM1994ER.txt": "326dfb30ed4a7193c9aa41527c646ec9e58e44165175f70db32b31d7ee94eae3", + "family/1995/FAM1995ER.sps": "5487bb3e0f782124d0b872ab43d09ee424c15b801868605121e3719483dce3a1", + "family/1995/FAM1995ER.txt": "c24d9982413259fce6bf386ff84195b5deb77ebb0e834705cdffe8987cb6a0db", + "family/1996/FAM1996ER.sps": "9aa5ad480b2f80b300af58d457c15e5f8c2c027dcb1a78ed1aecc9821c665067", + "family/1996/FAM1996ER.txt": "8b607a5f0f3aeaa706c5036c0240e46c684d083c66da31a38b2c835e3adfdbb3", + "family/1997/FAM1997ER.sps": "a40333ad1795c7f19d194797137e340732b093d4a4c0108589dd1512b66f4b99", + "family/1997/FAM1997ER.txt": "1fb8b8bee3fdd1a2e8f6637b6c3e434019d8dca5eacb94478e0419d5fbcfc8e9", + "family/1999/FAM1999ER.sps": "7afad10e0da6969cd434a588f7d336923451d7a2fa8a71959c6edf376b023a9b", + "family/1999/FAM1999ER.txt": "92d7bef0eb5794cccb9137a4fe177dadfb2ba92709628b5cbc4004f8e7d786a0", + "family/2001/FAM2001ER.sps": "c6dc0e81131ece42ebeb70a67ee58082b939049815bd359724e745780d0afc12", + "family/2001/FAM2001ER.txt": "cc55d16f2fd44bcc89c1ab812e21f3f4f7bc26b15645b3170e590f55d1320ca5", + "family/2003/FAM2003ER.sps": "09f96449a9410a2478c0c24c042b5510ea0a75e7c97d83102a60d1faab747ac3", + "family/2003/FAM2003ER.txt": "f06914b61c017d34c471343d9667d2c19ad5d59f78890ee26ff613d465555ef1", + "family/2005/FAM2005ER.sps": "9a3440f8c3ba8af3ab2a40bde19b3a7382e20b82b0d91bd7b4ccf5e36ee7ec0d", + "family/2005/FAM2005ER.txt": "29e9d9a3eb7cdf33df8831cc55f27ab6e230e8202b4cdd982da79b759c0a749f", + "family/2007/FAM2007ER.sps": "4c8bd5b1d7bdce8a9d596e191f2791004ceb3413bf0b88c68cadccd33277977d", + "family/2007/FAM2007ER.txt": "f811e277303fe90a42edef602ad1a92405e8df0c9ee0dd36eff4ff531202ebbf", + "family/2009/FAM2009ER.sps": "4faa45e30b5a4719a3fa12f9d5d48568f644f315457ee3eed3e4ff8872459e4c", + "family/2009/FAM2009ER.txt": "59cf31106cf4c3d2e62903bd841b1689c9229e15674bdc5fd896453286b085f2", + "family/2011/FAM2011ER.sps": "6a994d8b65803a515eaa3bf62c74e278dd5943b8b578428ef4fd462d96cba45c", + "family/2011/FAM2011ER.txt": "3253586567a76a43d3e4a568dd5ca8af0f8a3c69db829d6a55bdf0942c60992f", + "family/2013/FAM2013ER.sps": "526595b50a2087adc635da3c1288a396aa7179b075c11506f10338ab6348a0b5", + "family/2013/FAM2013ER.txt": "0406aed042d660f51712d0f18a6e80f939717c0c2fc68b8d3a8d6dcbf48180e1", + "family/2015/FAM2015ER.sps": "6500c8e88a2353e7a6c5322a898f3879662228fdefa329e0901eb254fc9e3fff", + "family/2015/FAM2015ER.txt": "e4a64b275a9c6dbe8e7b562be7ed0906d4082b0c49cad79d764c69b8de318ec2", + "family/2017/FAM2017ER.sps": "24abae319022d4e3da9bce8052455dfee6b00b7b9c642004eddcfa06cb8d59e5", + "family/2017/FAM2017ER.txt": "c4220fe0569f3dbb8e110029a9d4d896c41635c50c86b7cb9edd0e7a5de82b0f", + "family/2019/FAM2019ER.sps": "c9f8ba8698779aeaf239c0eea4b1f98d32975b1c77767acfd35601fcb883a5b0", + "family/2019/FAM2019ER.txt": "80602015789c552cff3b75dfec6813204e918837f767f2e71744f51c07a9056d", + "family/2021/FAM2021ER.sps": "50526906dafd86271074ba15fd426ab7030c2b62f29acf3d819b577fdc9442e2", + "family/2021/FAM2021ER.txt": "c8a7a0589962bd3e6300e99595be16cb198ef48b3bb2b9b626743fe44cd185ae", + "family/2023/FAM2023ER.sps": "915755685965a41743e96e42abbbfdddd7eab1df33234e462b0813b25d4df169", + "family/2023/FAM2023ER.txt": "384c63924b6667ecebd7b3ca797bfae94fcea4c0de1708c46ab25659a16432b2", + "ind2023er/IND2023ER.sps": "92d32d0efd65d50e984e971c681f6e9231b720973444cdc8f20f397039c9a462", + "ind2023er/IND2023ER.txt": "d68554ac828a690491572f37323eba1d8488e8b0001ed2aa89df4d4ade26c869", + "mh85_23/MH85_23.sps": "6f4a194b74c2dc7b95f2a163aeab19244384099ac0966dbe735157a60c1953ad", + "mh85_23/MH85_23.txt": "05297c541ae3cc62abd834b0c8e06aa189df4712e56f3507bb64c15e05b38ff7" + }, + "registries_sha256": { + "design": "56181372d412811af6d06f5c0d8d1e071049f7fb73c34bd394aaff8f5e0c2fd6", + "income": "79b8f953eda2111389b762608cea1025fb45d96ceb0468169eaf9ed405b0d4eb", + "individual": "283c65c46ccfbc6b3a5b700ec7d0d1783e61c931352455b842828cc0186cedda", + "pension": "7cc17ff1f6f4a5896b86cafa5edc59028102d28bfcdfa42840d55b628074f3dd", + "roles": "f10c4a7dff38f74a29291fcec4a96c8c7b31d58561798a10c53094d6dcf393b7", + "support": "279515f5dab832155583829aec312078547a28d7152bcd07e90a2cf9bb863b8a", + "wealth": "c5c8fa1ddf283c07ac4dcac4490afb9754d336ef3618a159e028ce2b39f874a1", + "weights": "47c9f2d1b4b95f8259107d589aadc370b835dc807d45fa5268cf88abd72cc3be" + }, + "schema_version": "populace_dynamics.track_u2_preregistration_evidence.v2", + "specification": "boomers2004_1946_55_uniform_cut", + "target_id": "U2" +} From 2faf03565cb55ab56256317aebefab2a2ce82efd Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 24 Oct 2026 12:06:43 -0400 Subject: [PATCH 2/4] U2: test the committed evidence record as present; force absence by path The committed pre-registration evidence record is now the intended state. Every refusal branch stays tested, with absence forced through an explicit missing path; the record itself is never removed. - test_the_committed_evidence_record_is_absent_so_registration_refuses is replaced in place by test_the_committed_evidence_record_is_the_pinned_one. It checks that the file exists and that its SHA-256 equals both loader.PREREGISTRATION_EVIDENCE_SHA256 and the literal pin 7bc5c3c2...b845. It checks that read_preregistration_evidence() accepts the record and that an explicit missing path still refuses ("no pre-registration"). A copy one hex digit away, still well-formed, refuses as "not the committed record". - test_a_frozen_load_needs_the_committed_record and test_preflight_refuses_while_the_evidence_record_is_absent force the no-record case by patching loader.read_preregistration_evidence to read an explicit missing path. - scripts/track_u2_dry_run.py: registered_preflight_without_evidence now reads an explicit missing path in a fresh temporary directory, checked absent first. The output keys are unchanged. No test is added or removed, and the five tier counts are unchanged (18125/4261/1450/520/308). The loader, the registered runner and the specification are untouched. Co-Authored-By: Claude Opus 5.5 --- scripts/track_u2_dry_run.py | 16 +++++++-- tests/track_u2/test_u2_loader.py | 55 +++++++++++++++++++++++++------ tests/track_u2/test_u2_scripts.py | 18 +++++++--- 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/scripts/track_u2_dry_run.py b/scripts/track_u2_dry_run.py index 7ae97fa6..a4d959b2 100644 --- a/scripts/track_u2_dry_run.py +++ b/scripts/track_u2_dry_run.py @@ -73,6 +73,7 @@ import platform import subprocess import sys +import tempfile from pathlib import Path from typing import Any @@ -127,6 +128,17 @@ def _refusal(call: Any) -> dict[str, Any]: return {"refused": False} +def _refusal_without_evidence() -> dict[str, Any]: + """The registered preflight's read of the evidence record, forced + absent through an explicit missing path in a fresh temporary + directory: the committed record stays in place.""" + with tempfile.TemporaryDirectory() as directory: + missing = Path(directory) / "absent.json" + if missing.exists(): + raise RuntimeError(f"{missing} exists in a fresh directory") + return _refusal(lambda: loader.read_preregistration_evidence(missing)) + + def _invented_individual_raw( inputs: cohort.U2Inputs, registries: sources.RegistrySet ) -> pd.DataFrame: @@ -208,9 +220,7 @@ def _round_1_refusals( "undocumented_relationship_rule": _refusal( lambda: registry_roles.rule(2015, 99) ), - "registered_preflight_without_evidence": _refusal( - loader.read_preregistration_evidence - ), + "registered_preflight_without_evidence": _refusal_without_evidence(), "evidence_from_invented_inputs": _refusal( lambda: loader.preregistration_evidence(inputs) ), diff --git a/tests/track_u2/test_u2_loader.py b/tests/track_u2/test_u2_loader.py index d3c56ebf..fc6cefd3 100644 --- a/tests/track_u2/test_u2_loader.py +++ b/tests/track_u2/test_u2_loader.py @@ -23,8 +23,8 @@ invented frames; * for a frozen load, ``loader.read_preregistration_evidence`` returns the invented evidence record the load is given, standing in for the - committed record (none is committed yet; a frozen load refuses any - other record, ``test_a_frozen_load_needs_the_committed_record``). + committed record (a frozen load refuses any other record, + ``test_a_frozen_load_needs_the_committed_record``). An audit hook refuses any open under the PSID directory -- the default one and the one under the account's real home, which differ when HOME is @@ -1036,8 +1036,9 @@ def test_a_frozen_load_needs_the_committed_record( against the committed pre-registration record, so a fabricated record, however well-formed, cannot stand in for the authorization an unfrozen load needs. It refuses before any PSID path is resolved or any file - opened: while no record is committed, and when the committed one - differs.""" + opened: when no record can be read (forced here through an explicit + missing path; the committed record stays in place), and when the + committed one differs.""" import sys @@ -1056,7 +1057,14 @@ def spy(event, args): "_resolve_data_dir", lambda data_dir: resolved.append(data_dir) or original(data_dir), ) - assert not loader.PREREGISTRATION_EVIDENCE_PATH.exists() + read = loader.read_preregistration_evidence + missing = tmp_path / "no-record" / "absent.json" + assert not missing.exists() + monkeypatch.setattr( + loader, + "read_preregistration_evidence", + lambda *args, **kwargs: read(missing), + ) with pytest.raises( loader.U2FrozenIdentityMismatch, match="no pre-registration evidence" ): @@ -1206,13 +1214,40 @@ def test_an_absent_or_unpinned_evidence_record_refuses( loader.read_preregistration_evidence(path) -def test_the_committed_evidence_record_is_absent_so_registration_refuses(): - """At this commit the section 20 step-4 pass has not run: there is no - committed evidence record, so the registered run cannot bind one.""" +def test_the_committed_evidence_record_is_the_pinned_one(tmp_path): + """Section 20 step 5: the committed evidence record is the one the + step-4 pass wrote, byte for byte, and the reader accepts it. An + absent record and a copy one byte away from it still refuse.""" - assert not loader.PREREGISTRATION_EVIDENCE_PATH.exists() + path = loader.PREREGISTRATION_EVIDENCE_PATH + assert path.is_file() + raw = path.read_bytes() + assert ( + hashlib.sha256(raw).hexdigest() + == loader.PREREGISTRATION_EVIDENCE_SHA256 + == "7bc5c3c26ff014271061a8228068c6e71103430ec299048462570476a510b845" + ) + assert loader.read_preregistration_evidence() == ( + loader.check_preregistration_evidence(json.loads(raw)) + ) + absent = tmp_path / "absent.json" + assert not absent.exists() with pytest.raises(loader.U2LoaderRefusal, match="no pre-registration"): - loader.read_preregistration_evidence() + loader.read_preregistration_evidence(absent) + # One hex digit of the frame digest changes: the copy stays a + # well-formed record, so only the pin refuses it. + key = b'"input_frames_sha256"' + at = raw.index(b'"', raw.index(key) + len(key)) + 1 + altered = bytearray(raw) + altered[at] = ord("1") if raw[at] == ord("0") else ord("0") + assert sum(a != b for a, b in zip(raw, altered, strict=True)) == 1 + assert loader.check_preregistration_evidence(json.loads(bytes(altered))) + copy_path = tmp_path / "evidence.json" + copy_path.write_bytes(bytes(altered)) + with pytest.raises( + loader.U2FrozenIdentityMismatch, match="not the committed record" + ): + loader.read_preregistration_evidence(copy_path) def test_evidence_is_recorded_only_from_loader_sealed_inputs( diff --git a/tests/track_u2/test_u2_scripts.py b/tests/track_u2/test_u2_scripts.py index ff66f748..608261d5 100644 --- a/tests/track_u2/test_u2_scripts.py +++ b/tests/track_u2/test_u2_scripts.py @@ -989,14 +989,24 @@ def test_binding_covers_every_registered_identity(registered): ) != registered.binding_sha256("d" * 64, evidence) -def test_preflight_refuses_while_the_evidence_record_is_absent(registered): +def test_preflight_refuses_while_the_evidence_record_is_absent( + registered, tmp_path, monkeypatch +): """Section 14: execution rechecks the frozen identities, so without - the committed pre-registration evidence record (none exists at this - commit) the preflight refuses before comparing the binding.""" + the committed pre-registration evidence record (forced absent here + through an explicit missing path; the committed record stays in + place) the preflight refuses before comparing the binding.""" from populace_dynamics.uniform_cut_track_u2 import loader - assert not loader.PREREGISTRATION_EVIDENCE_PATH.exists() + read = loader.read_preregistration_evidence + missing = tmp_path / "absent.json" + assert not missing.exists() + monkeypatch.setattr( + loader, + "read_preregistration_evidence", + lambda *args, **kwargs: read(missing), + ) with pytest.raises(loader.U2LoaderRefusal, match="no pre-registration"): _preflight(registered, evidence=None) with pytest.raises(loader.U2LoaderRefusal, match="registries other"): From a0fd18ccdc4ab24a19721643d29507a388002d64 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 24 Oct 2026 12:09:28 -0400 Subject: [PATCH 3/4] U2: record the exact U1 differential at 2faf035 scripts/u2_u1_differential.py ran with the U1 base 9cee2423 and the candidate 2faf0356 as clean detached checkouts, one Python 3.14.7 interpreter (pandas 3.1.0, numpy 2.5.4), seed 20260924, and an empty PSID root. The result has all_equal true and all_checks_passed true, and refusal expectations are met on both sides. The contract-check digest equals the one in u2_m2_u1_differential_14d9576.json. Co-Authored-By: Claude Opus 5.5 --- .../design/u2_m2_u1_differential_2faf035.json | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 docs/design/u2_m2_u1_differential_2faf035.json diff --git a/docs/design/u2_m2_u1_differential_2faf035.json b/docs/design/u2_m2_u1_differential_2faf035.json new file mode 100644 index 00000000..f8a24f4c --- /dev/null +++ b/docs/design/u2_m2_u1_differential_2faf035.json @@ -0,0 +1,142 @@ +{ + "base": { + "path": "/Users/maxghenis/PolicyEngine/_clones/md-u2-diff-base-9cee2423", + "head": "9cee2423f048683e15838aa5fee330afd072f85f" + }, + "candidate": { + "path": "/Users/maxghenis/PolicyEngine/_clones/md-u2-diff-cand", + "head": "2faf03565cb55ab56256317aebefab2a2ce82efd" + }, + "python": "/Users/maxghenis/PolicyEngine/_clones/md-u2-evidence-copy-venv/bin/python", + "seed": 20260924, + "tolerance": "zero: byte equality", + "excluded_json_paths": [ + "/run/git_head", + "/run/date" + ], + "ratified_u1_block_sha256": "aed6e724053a44da76e4d08069930c88fe6c978a5ff58fce42beffd3a78785eb", + "dry_run": { + "result_json_equal": true, + "results_md_equal": true, + "result_json_sha256": { + "base": "f2a57684097d4ce04bd8f26291a1fbdd4dc45e37dfdcf3c3f9c9f4f8842c709c", + "candidate": "f2a57684097d4ce04bd8f26291a1fbdd4dc45e37dfdcf3c3f9c9f4f8842c709c" + }, + "results_md_sha256": { + "base": "3f518a236c62e65b64142e998b10e1d7acb2baa9c43d4ffb2c248e5bf3541dd6", + "candidate": "3f518a236c62e65b64142e998b10e1d7acb2baa9c43d4ffb2c248e5bf3541dd6" + }, + "first_json_difference": null, + "first_md_difference": null, + "run": { + "base": { + "date": "2026-10-24", + "invented_seed": 20260924, + "git_head": "9cee2423f048683e15838aa5fee330afd072f85f", + "git_clean": true, + "python": "3.14.7", + "command": "python scripts/track_u_dry_run.py --output-dir /var/folders/9l/_wztzgbx7mgc7l1r0416cy7m0000gn/T/u1-differential-gd2rm4q1/same-output --seed 20260924" + }, + "candidate": { + "date": "2026-10-24", + "invented_seed": 20260924, + "git_head": "2faf03565cb55ab56256317aebefab2a2ce82efd", + "git_clean": true, + "python": "3.14.7", + "command": "python scripts/track_u_dry_run.py --output-dir /var/folders/9l/_wztzgbx7mgc7l1r0416cy7m0000gn/T/u1-differential-gd2rm4q1/same-output --seed 20260924" + } + } + }, + "refusal_expectations": { + "base": { + "met": true, + "failures": {} + }, + "candidate": { + "met": true, + "failures": {} + } + }, + "loader_file_accesses_empty": true, + "contract_checks": { + "equal": true, + "sha256": { + "base": "49e47726948dc6faf4f39e0ae1ff60054e178b5feb4701cbb8b84400b6bdccd9", + "candidate": "49e47726948dc6faf4f39e0ae1ff60054e178b5feb4701cbb8b84400b6bdccd9" + }, + "first_difference": null, + "checked": [ + "actual_loader", + "age67.WAVES", + "input_frames_sha256", + "observation_plan", + "pending_decisions", + "refusal_parity", + "rows.MAX_RULINGS", + "runner.NAMED_DELTAS", + "uniform_cut_tabulation.COMPARATOR_COLUMN", + "uniform_cut_tabulation.REPORT_ROWS" + ], + "refusal_parity": { + "existing_artifact": { + "class": "ValueError", + "message": "/INVENTED/u1-refusal-parity/replication_boomers2004_uniform_cut_v1.json already exists: the registered run is one-shot", + "module": "builtins" + }, + "existing_sidecar": { + "class": "ValueError", + "message": "/INVENTED/u1-refusal-parity/replication_boomers2004_uniform_cut_v1.json already exists: the registered run is one-shot", + "module": "builtins" + }, + "invalid_provenance": { + "class": "TrackURunError", + "message": "data_provenance must be one of ('invented', 'registered_real')", + "module": "populace_dynamics.uniform_cut_track_u.runner" + }, + "invalid_registration_url": { + "class": "TrackURunError", + "message": "a registered run needs an issue #42 comment URL as its registration pointer (https://github.com/PolicyEngine/microcosm-dynamics/issues/42#issuecomment-)", + "module": "populace_dynamics.uniform_cut_track_u.runner" + }, + "invented_labeled_registered": { + "class": "TrackURunError", + "message": "a registered run reads the staged PSID through age67.load_age67_inputs; these inputs record 'invented'", + "module": "populace_dynamics.uniform_cut_track_u.runner" + }, + "invented_with_pointer": { + "class": "TrackURunError", + "message": "an invented run carries no registration pointer", + "module": "populace_dynamics.uniform_cut_track_u.runner" + }, + "u2_seed_under_u1": { + "class": "ValueError", + "message": "seed_wave_rule must be earliest_presence_wave", + "module": "builtins" + }, + "wrong_registered_headline": { + "class": "ValueError", + "message": "the registration names headline row U0, but the staged PSID gives U0-F under the fallback rule (WEALTH1 refused for waves [2005, 2007]): the staging changed after registration, so this is not the registered run", + "module": "builtins" + }, + "wrong_ssi_hash": { + "class": "TrackURunError", + "message": "a registered run needs the committed SSI capture; the SSI parameters record {'kind': 'policyengine_us_capture', 'sha256': '0000000000000000000000000000000000000000000000000000000000000000'}", + "module": "populace_dynamics.uniform_cut_track_u.runner" + }, + "wrong_threshold_hash": { + "class": "TrackURunError", + "message": "a registered run needs the committed, pinned Census threshold capture (adjusted_poverty.THRESHOLDS_SHA256 is 'dc21a78736f5085872cf56c9cf291258034c1293572b77455cba689a1ed0eec5'); the thresholds record {'kind': 'census_capture', 'sha256': '0000000000000000000000000000000000000000000000000000000000000000'}", + "module": "populace_dynamics.uniform_cut_track_u.runner" + } + }, + "loader_opened_under_fake_root": { + "base:supplements_refused": [], + "base:supplements_staged": [], + "candidate:supplements_refused": [], + "candidate:supplements_staged": [] + } + }, + "all_equal": true, + "dry_run_skipped": false, + "all_checks_passed": true +} From c9c0f4a20a1d37526acca7346851747e10e611eb Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 24 Oct 2026 12:17:00 -0400 Subject: [PATCH 4/4] U2: rerun the U1 differential at 2faf035 in the step-4 frame environment The pre-registration evidence record pins pandas 3.0.6 with future.infer_string True. scripts/u2_u1_differential.py was rerun in that environment, using the same clean checkouts as before: base 9cee2423 and candidate 2faf0356. The environment was Python 3.14.7, pandas 3.0.6 and numpy 2.5.4 (the step-4 pass's versions), with seed 20260924 and an empty PSID root. Results: - all_equal and all_checks_passed are true. - The expected refusals hold on both sides. - The contract-check digest is unchanged. The report gains an `environment` block after `python`, read from that interpreter after the run. With the block removed, the file is byte-identical to the harness's output. The pandas 3.1.0 run committed in a0fd18cc gave the same results. It differs only in the interpreter path, the temporary output directory named in run.command and the dry-run digests that include it. Co-Authored-By: Claude Opus 5.5 --- .../design/u2_m2_u1_differential_2faf035.json | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/design/u2_m2_u1_differential_2faf035.json b/docs/design/u2_m2_u1_differential_2faf035.json index f8a24f4c..15c34a7a 100644 --- a/docs/design/u2_m2_u1_differential_2faf035.json +++ b/docs/design/u2_m2_u1_differential_2faf035.json @@ -7,7 +7,16 @@ "path": "/Users/maxghenis/PolicyEngine/_clones/md-u2-diff-cand", "head": "2faf03565cb55ab56256317aebefab2a2ce82efd" }, - "python": "/Users/maxghenis/PolicyEngine/_clones/md-u2-evidence-copy-venv/bin/python", + "python": "/Users/maxghenis/PolicyEngine/_clones/md-u2-diff-venv-pandas306/bin/python", + "environment": { + "added_after_run": "read from the interpreter named in `python`, under the run's environment variables; scripts/u2_u1_differential.py does not write this block", + "python_version": "3.14.7", + "pandas_version": "3.0.6", + "numpy_version": "2.5.4", + "future_infer_string": true, + "install": "uv pip install -e \".[dev]\" \"pandas==3.0.6\" \"numpy==2.5.4\"", + "psid_root": "an empty directory (POPULACE_DYNAMICS_PSID_DIR and HOME)" + }, "seed": 20260924, "tolerance": "zero: byte equality", "excluded_json_paths": [ @@ -19,12 +28,12 @@ "result_json_equal": true, "results_md_equal": true, "result_json_sha256": { - "base": "f2a57684097d4ce04bd8f26291a1fbdd4dc45e37dfdcf3c3f9c9f4f8842c709c", - "candidate": "f2a57684097d4ce04bd8f26291a1fbdd4dc45e37dfdcf3c3f9c9f4f8842c709c" + "base": "9f4e4e7f1c466db7b375de6909ea85a2201a7d2361f101a35fc2514befffd35f", + "candidate": "9f4e4e7f1c466db7b375de6909ea85a2201a7d2361f101a35fc2514befffd35f" }, "results_md_sha256": { - "base": "3f518a236c62e65b64142e998b10e1d7acb2baa9c43d4ffb2c248e5bf3541dd6", - "candidate": "3f518a236c62e65b64142e998b10e1d7acb2baa9c43d4ffb2c248e5bf3541dd6" + "base": "5906f196f71c09e48163e12abcf36f70083ec5674874aaa440474ceddb03c0df", + "candidate": "5906f196f71c09e48163e12abcf36f70083ec5674874aaa440474ceddb03c0df" }, "first_json_difference": null, "first_md_difference": null, @@ -35,7 +44,7 @@ "git_head": "9cee2423f048683e15838aa5fee330afd072f85f", "git_clean": true, "python": "3.14.7", - "command": "python scripts/track_u_dry_run.py --output-dir /var/folders/9l/_wztzgbx7mgc7l1r0416cy7m0000gn/T/u1-differential-gd2rm4q1/same-output --seed 20260924" + "command": "python scripts/track_u_dry_run.py --output-dir /var/folders/9l/_wztzgbx7mgc7l1r0416cy7m0000gn/T/u1-differential-tjve5_7o/same-output --seed 20260924" }, "candidate": { "date": "2026-10-24", @@ -43,7 +52,7 @@ "git_head": "2faf03565cb55ab56256317aebefab2a2ce82efd", "git_clean": true, "python": "3.14.7", - "command": "python scripts/track_u_dry_run.py --output-dir /var/folders/9l/_wztzgbx7mgc7l1r0416cy7m0000gn/T/u1-differential-gd2rm4q1/same-output --seed 20260924" + "command": "python scripts/track_u_dry_run.py --output-dir /var/folders/9l/_wztzgbx7mgc7l1r0416cy7m0000gn/T/u1-differential-tjve5_7o/same-output --seed 20260924" } } },