Census ACS 5-year SLD source packages: Utah pilot at summary levels 610/620 (microcosm#625) - #146
Open
MaxGhenis wants to merge 2 commits into
Open
Census ACS 5-year SLD source packages: Utah pilot at summary levels 610/620 (microcosm#625)#146MaxGhenis wants to merge 2 commits into
MaxGhenis wants to merge 2 commits into
Conversation
…ls 610/620 (populace#625) Six witnessed packages for the state-legislative-district target surface: S0101 age bands, B19001 household income brackets (+ total households), and B19013 median household income, each per chamber, generated deterministically from canonical api.census.gov per-state responses by ledger/sources/census_acs_sld.py (regeneration is a pinned test). SLD geography levels were already in the core vocabulary; the compact rectangular record-set shape (row-level district geography overrides, measure-level band constraints) follows the oep_state_level precedent. The 2020-2024 5-year window, the 2024 district-boundary vintage, and the per-state fetch constraint (the API rejects state wildcards for SLD hierarchies) are declared in the packages. B19013 facts aggregate as median — the populace consumer treats them as validation-only by doctrine. publish-raw to R2 is the one pending step (needs ledger-raw credentials); manifests carry no storage.r2 block until the upload actually happens. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ce pins
Sol cross-family review verdicts on the pilot commit: ledger-source-fidelity
FAIL (bounds not evidenced by source rows; no column-identity guards),
ledger-boundary pass-with-notes. All fidelity findings addressed:
- S0101 and B19001 switch to unpivoted per-district record sets so every
constrained fact's own source rows evidence its bounds: S0101 reuses the
CD-family age parser (publisher band labels on rows); B19001 gets a
sibling parser emitting bracket labels plus explicit
household_income_{lower,upper}_bound numeric keys (the suite's
row-constraint gate validates them). B19013 stays compact (no
constraints).
- Measure-level expected_column_header guards on every package (the cell
store materializes the unpivoted header at row 1, so a column edit now
fails selector resolution — the reviewed column-swap probe dies).
- Data rows start at cell row 2 (header row 1) — the CD package's
numbering, now explained rather than inferred.
- Negative-sentinel rejection broadened to any negative value.
- Manifests record fetched_at (the artifacts.py acquisition convention).
- New pins: witness bytes hash-match manifests; the agent-acceptance gate
runs in CI for all three shapes and must be clean except the recorded
missing_raw_r2_link (publish-raw needs ledger-raw credentials; the pin
tightens to empty once it runs).
Rebased across the Chronicle rename (code identity ledger->chronicle;
frozen machine surfaces unchanged).
Co-Authored-By: Claude Fable 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
Six witnessed Census ACS 2020-2024 5-year source packages at state-legislative-district summary levels 610 (upper) / 620 (lower) — the Utah pilot of the SLD target surface for PolicyEngine/microcosm#625 (the per-district layer over the ACS local artifact):
census/acs_s0101_sldu_ut_2024(age bands)census/acs_s0101_sldl_ut_2024census/acs_b19001_sldu_ut_2024(income brackets + total households)census/acs_b19001_sldl_ut_2024census/acs_b19013_sldu_ut_2024(median household income, aggregationmedian)census/acs_b19013_sldl_ut_20243,744 facts. The SLD geography levels were already in the core vocabulary; no core-schema change. Two commits: the pilot, then the review fix batch (see verdicts below).
Shapes. The constrained tables use the CD-family unpivoted per-district record sets so every fact's own source rows evidence its bounds: S0101 reuses the existing age parser (publisher band labels on rows); B19001 gets a sibling parser (
census_acs_b19001_income_json_rows) emitting bracket labels plus explicithousehold_income_{lower,upper}_boundnumeric keys, which the suite's row-constraint gate validates fact by fact. The unconstrained B19013 keeps the compact rectangular shape. Every measure carries anexpected_column_headerguard (the cell store materializes the unpivoted header at row 1), so a column edit fails selector resolution. All YAML is generated deterministically from the witnessed bytes bychronicle/sources/census_acs_sld.py; regeneration, witness-sha integrity, and the agent-acceptance gate are pinned tests.Witnessing notes (reviewed honestly)
in=state:*for SLD hierarchies; witnesses are per-state canonical queries (comma-listed FIPS works for the national generalization, National generalization of the ACS SLD packages (all states, ~6.8k districts) #138).api.census.govnow hard-requires a key. Recordedsource_urls are the canonical keyless queries; the fetch appends a key at request time only; the recorded sha256 is of the canonical body. No key material anywhere in the diff (grep-verified). Manifests recordfetched_at.publish-rawto R2 is the one pending owner step (needsledger-rawcredentials): manifests honestly carry nostorage.r2block until the upload happens, and the CI acceptance pin is exactly "clean exceptmissing_raw_r2_link" — it tightens to empty once publish-raw runs.geography_vintage: 2024_state_legislative_districtsmatches the 2024 SLD BEFs the microcosm membership layer pins.aggregation: median; the microcosm consumer treats them as validation-only by doctrine.Ledger Governance
ledger-source-ingestorvalidate-packagevalid for all six, exact counts pinned in testspublish-raw(see notes); the acceptance gate is otherwise clean and pinned in CIledger-source-fidelity: fail on the pilot commit — constrained bounds not evidenced by source rows; no column-identity guards; R2 links absent. All addressed in the fix commit (evidence-bearing shapes, header guards, CI acceptance pin); the numeric review also confirmed every one of the 3,744 committed cell mappings exact.ledger-target-profile: n/a (no target profiles touched)ledger-contract: n/a (no schema change; alias entries + two parser-dispatch clauses)ledger-boundary: pass-with-notes — nothing crosses the facts-only boundary; the notes (R2 durability, authenticated cold refetch, acquisition timestamp) are operational, withfetched_atnow recorded and R2 the documented owner step.Tests
Regeneration determinism for all six packages + manifests; witness-sha integrity; canonical-keyless URL properties; district-count pins; refusals (unsorted/duplicate districts, any negative sentinel, wrong-chamber GEO_IDs); exact validation counts; fact spot values with constraint bounds and median typing; the agent-acceptance pin; bundle skipped-source pins. Full suite green; ruff clean.
Rebased across the Chronicle rename (
ledger→chroniclecode identity; frozen machine surfaces untouched). Part of PolicyEngine/microcosm#625; national generalization tracked in #138.🤖 Generated with Claude Code