Repository navigation
Give Connecticut blocks their CBSA through 2022 planning regions - #1072
Merged
Merged
Conversation
The OMB 2023 delineations list Connecticut by its nine planning regions (09110-09190), while 2020 blocks carry the eight old counties (09001-09015), so assemble_us_block_ladder's county-prefix lookup left every CT block at cbsa_code 0. Map each CT block to its planning region through its town (2020 BAF MCD layer + Census ct_cou_to_cousub_crosswalk) and look the CBSA up by that county-equivalent. The join now refuses a delineated county-equivalent in a built state that no populated block reaches, and a state only partly remapped. The builder records cbsa_delineated_states and, after loading the artifact back, refuses one that leaves any such state without a CBSA. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Address review findings on the Connecticut CBSA fix: - Keep county-equivalents as int64 and apply the CT remap with searchsorted, instead of holding one Python string per national block (~330 MB of peak memory on the national build). - Correct the comments on 'County subdivisions not defined' rows: only Fairfield's is split between two planning regions, and no populated 2020 block carries the code. - Say what the builder's load-back coverage check is for: it cannot fail on a ladder the join just accepted, and exists for ladders built elsewhere or before the join refused unreached county-equivalents. - Refuse a CT build without the BAF MCD layer by naming the file. - Test main() offline on a synthetic cache: CT blocks get planning-region CBSAs, a build without CT never reads the crosswalk, and a CT build without the MCD layer stops before writing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mutation analysis of the CBSA join (46 mutants, one per plausible regression) left seven alive; add the tests that kill them: - a remap naming only unpopulated CT blocks still claims the state - the coverage check covers every recorded state, ignores recorded states absent from the ladder, and refuses malformed entries - a crosswalk with no town rows, and an MCD layer with a repeated block or another header, are refused The eighth survivor was equivalent: csv already joins a quoted cell's lines without their terminators, and the header normalizer splits at the parenthesis either way, so _csv_lines now only strips the byte-order mark. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Every Connecticut block in the US block ladder had
cbsa_code == 0.assemble_us_block_ladderlooked each block's CBSA up by its 2020 county prefix (09001–09015). The OMB 2023 delineation file (list1_2023.xlsx) lists Connecticut by its nine 2022 planning regions instead (county-equivalents 09110–09190), so no CT block matched. Both local ladders carry the defect: the Route A input (7ba39b95…) and the PUMA-carrying rebuild for #1047 (9f2dc986…). Connecticut was the only state with an all-zero CBSA.This PR maps each CT block to its planning region through its town, then looks the CBSA up by that county-equivalent:
BlockAssign_ST09_CT_MCD.txt, already inside the BAF zip the builder downloads) gives block → 2020 county + town. 2020 blocks nest in towns.ct_cou_to_cousub_crosswalk.txtgives town → planning region. In that file every town keeps its county-subdivision FIPS, and the new file is downloaded, cached and sha-recorded like every other source.The CBSA layer's vintage string stays
omb_2023_delineations, because the delineation vintage did not change.Changes
packages/microcosm-build/src/microcosm/build/us_runtime/block_ladder_sources.py(not byte-hashed):parse_baf_county_subdivision_fileparses the MCD layer. It refuses a row whoseCOUNTYFPdisagrees with the block geoid.parse_ct_planning_region_crosswalkhandles the file's layout: the quoted two-line header cells, BOM, trailing glossary, and the redundant old/new geoid columns, which are cross-checked. It skips the "County subdivisions not defined" rows (00000, coastal water). Fairfield County's is listed under two planning regions, so the code names no single region, and no populated 2020 block carries it.ct_planning_region_by_blockrefuses a CT block with no town, or a town the crosswalk lacks.assemble_us_block_ladder(..., cbsa_county_by_block=...)looks each block up by its delineation county-equivalent. That is its 2020 county unless the override map names another. County-equivalents stay int64 and the remap is applied withsearchsorted, so the join no longer holds a Python string per national block.cbsa_delineated_statesandus_block_ladder_cbsa_coverage_failures(ladder)are the loader-level check over a loadedUsBlockLadder. On a ladder this join just accepted the check cannot fail. Its job is ladders built elsewhere or before the join refused unreached county-equivalents: on the Route A artifact it reports exactly state 09.tools/build_us_block_ladder_artifact.py:cbsa_delineated_statesin the metadata.load_us_block_ladderself-check.geography_ladder.py(the loader and gate) and every other_DIRECT_KERNEL_MODULESentry are untouched.Invariants
Each of these holds for every input and is enforced by a test:
assemble_us_block_ladderraises if and only if some delineated county-equivalent in a built state is reached by no populated block. A partial remap is refused separately, by invariant 5. The pre-fix CT join now fails loudly instead of emitting zeros. Rows outside the built states (Puerto Rico, or CT in a smoke build of other states) are ignored. Tests: Hypothesistest_cbsa_join_invariants_hold_for_generated_ladders, plustest_assemble_refuses_ct_blocks_keyed_by_2020_countyandtest_assemble_ignores_delineation_rows_outside_the_built_states.cbsa_code[i] == delineation.get(county_equivalent(block_i), 0). Tested by the same Hypothesis test.cbsa_codeis independent of the CBSA inputs, so the delineation and the override map change nothing else. Tested by the Hypothesis test, and checked on the real national rebuild below.cbsa_delineated_states, passesus_block_ladder_cbsa_coverage_failures. Tested by the Hypothesis test.cbsa_county_by_blockentry must have one for every populated block, and every entry is a 5-digit county-equivalent in the block's own state. Tests:test_assemble_refuses_a_state_only_partly_remappedandtest_assemble_refuses_malformed_county_equivalents.09+ new county. Tested by Hypothesistest_ct_crosswalk_round_trips_generated_towns.cbsa_delineated_stateswhose blocks all havecbsa_code == 0is a failure. Artifacts built before that record fall back to every state present, because OMB 2023 delineates territory in all 50 states and DC (computed fromlist1_2023.xlsx: 52 states including PR). Tests:test_cbsa_coverage_check_flags_the_legacy_connecticut_ladderandtest_cbsa_coverage_check_follows_the_recorded_states.Differentials.
6840b990…both times).test_builder_output_matches_the_pre_fix_join_outside_connecticutruns the tool end to end and checks that the join outside CT equals the plain 2020-county lookup.Mutation analysis. I ran 44 mutants, one per plausible regression: ignoring the remap, dropping the whole-state or reachability rule, looking up by 2020 prefix, coverage over the wrong states, crosswalk and MCD validation removed, a wrong
return_inverseorder, and so on. Each was monkeypatched in-process againsttest_us_block_ladder_sources.pyandtest_us_block_ladder_tool.py. All 44 are killed. Two of them had to be re-pointed at lines the vectorized rewrite changed (E3, F6), and the adapted versions are also killed. The first pass left 7 alive, and the tests above were added for them. An 8th survivor was equivalent (a newline re-append csv never needed) and its code was deleted.Verification: national rebuild
Rebuilt with
tools/build_us_block_ladder_artifact.pyat this branch's code (nice -n 10, cached sources) and compared with the Route A artifactus_block_ladder_2020.npz(7ba39b959068…). The new artifact is6840b990acdf….block_geoid,population,congressional_district_geoid,sldu,sldl,place_fipscbsa_coderows changedcbsa_code == 0metadata_jsoncbsa_delineated_states(all 51), the crosswalk source file and sha, and the cbsa layer's source text; vintage unchangedCT CBSA population shares (2020 P.L. 94-171 block populations, CT total 3,605,944):
All of CT is inside a CBSA under the 2023 delineation.
PUMA-carrying variant. I applied this fix to #1047's head
4324432e5; the conflicts were additive, and a patch is kept locally. I rebuilt with #1047's builder and compared the result withus_block_ladder_2020_puma.npz(9f2dc986bec7…). The new artifact isf84936637d49…. Every array,pumaincluded, is byte-identical exceptcbsa_code, which changed only on the 42,008 CT blocks. The coverage check and the differential give the same results as above. Thecbsa_codearrays of the two rebuilt artifacts are identical.Downstream effects
us_geography_ladder_gate(hashed, unchanged). Its CBSA check is the national nonempty weighted share against(0.75, 0.99). On ladder population the share moves from 0.9352 to 0.9461 (+1.09 pp, CT's population share), well inside the bounds. The docstring's "about 93% in a CBSA" anchor now reads low by about a point. The gate has no per-state CBSA check, which is why an all-zero CT passed it. Adding one would mean editing the hashed module.us_runtime/block_location.py(US household location v1: one census block per household, every geography derived #1047, not on main).state_unidentified_counties_cbsaview excludes blocks withcbsa <= 0. Before this fix, a CT household narrowed to a CBSA had no candidate block, and the draw refuses an empty candidate set. After it, CT households have candidates in their CBSA.cbsa_vintage_agreementbuilds its county → CBSA lookup from the first block of each 2020 county (np.unique(..., return_index=True)). That assumes a 2020 county sits in one CBSA, which stops holding for CT: 7 of its 8 counties now span 2–3 CBSAs (09001: 14860/47930; 09003: 25540/45860/47930; 09005: 14860/45860/47930; 09009: 35300/47930; 09011: 25540/35980/39480; 09013: 25540/39480; 09015: 35980/39480; only 09007 is single-CBSA). A CT source pair would then be compared with whichever CBSA the county's lowest block has. The fix belongs in US household location v1: one census block per household, every geography derived #1047: a pair should agree only when every ladder block in the county carries that CBSA.4324432e5, the conflicts are additive only, all 41 ladder-source tests pass, and the rebuilt PUMA ladder is described above.GTCO > 0, ASEC 2023, 2024 and 2025, 280 pairs each) with that first-block rule,cbsa_vintage_agreementfinds 20 disagreeing pairs against both the old and the rebuilt ladder, so narrowing stays off. The CT pairs move as follows: 09001 (CPS 14860) flips to agree. 09005 (CPS 0) flips to disagree, against its first block's 14860. 09009 (CPS 35300 vs 47930) and 09015 (CPS 49340, the 2013 Worcester delineation, vs 35980) disagree both before and after.cbsa_codeonce it adopts a rebuilt ladder.cbsa_codeis astrhousehold input with default"", defined only invariables/input/geography.py. I checked 1.764.6 and 2.2.1; no formula or parameter reads it, so no tax or benefit output moves. A rebuilt ladder changes CT households'cbsa_codefrom""to a planning-region CBSA. Block draws are population-weighted within the CD and do not depend on CBSA, so no other column changes.tools/build_us_puf_support_base.pyloads the ladder for the release path and does not run the new coverage check yet. US household location v1: one census block per household, every geography derived #1047 moves that load, so wiring it in waits until US household location v1: one census block per household, every geography derived #1047 lands._buildf-runtimeis untouched, and adopting the rebuilt ladder there is a separate call. An in-flight checkpointed release should not pull this branch mid-run: the builder'sbuilder_code_identitydigests every package source, so its resume would refuse the changed run config.Tests
test_us_block_ladder_sources.py: 47 passed (34 new, including 2 Hypothesis property tests).test_us_block_ladder_tool.py(new): 4 passed. It runsmain()offline on a synthetic cache: CT gets planning-region CBSAs, a build without CT never reads the crosswalk, a CT build without the MCD layer stops before writing, and the join outside CT is unchanged.test_us_geography_ladder.py: 21 passed.test_us_spine_blindness.py -k "classification or source_spine or import_graph": 9 passed.ruff check/ruff format --check: clean;tools/ci_test_plan.py verify: ok.Review
Four independent Opus 5.5 reviewers (source formats, invariants, downstream effects, conformance) each had every finding put to an adversarial verifier. Confirmed and fixed:
'09'in an error message.An independent Opus 5.5 merge-gate review approved the change. Its own differential re-parsed the raw sources without the PR's parsers and found 0 mismatches on all 42,008 CT blocks and outside CT; the body corrections it asked for are applied.
Confirmed and deferred: the coverage check cannot fail inside the builder, and the release consumer doesn't call it yet (see Downstream). Refuted: "a refused ladder is left at
--out" predates this change.No byte-hashed module is in the diff, which touches 5 files.
source_inventory_sha256for_DIRECT_KERNEL_MODULESand_QRF_KERNEL_MODULESis4734e4eb…and9c4ba3bf…on this branch, as on main.axiom: n/a: data infrastructure (geography ladder builder), no policy rules.
🤖 Generated with Claude Code