Carry the geography ladder by default; gate releases on it#289
Merged
Conversation
The ladder shipped opt-in (#277): nothing stopped a base or release from being built without the geography spine, which is the silent-degradation family (#225 everyone-is-a-citizen, #34 NYC-zero) this repo legislates against. - tools/build_us_puf_support_base.py: omitting --block-ladder-artifact is now an error; diagnostic builds opt out explicitly with --without-block-ladder (recorded in the summary). - L0/refit release export: the geography spine (state_fips, congressional_district_geoid, and the seven ladder columns) joins the required release source columns (presence; value quality is the gate's job), and the us_geography_ladder gate runs on the selected support with its calibrated weights — a release whose spine is inconsistent or whose NYC mass collapsed fails by default. --allow-geography-ladder-gate-failures is the diagnostic escape hatch; the gate result is recorded in the export summary either way. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Jul 2, 2026
The reviewer found two sibling scorer tools this branch broke: score_us_fiscal_targets.py and score_us_state_files.py imported the retired _load_ledger_facts and compiled without contract flags, so both crashed at import and would then have raised PeriodContractError on any real feed. They now load through the pinned artifact loader and expose --age-targets / --allow-unaged-dollar-targets mirroring the release builder, defaulting to the incumbent un-aged-waived surface so existing releases score against the surface they were calibrated to. Also from review: publisher-projection-backed dollar targets are never re-aged (aging_factor_source=source_projection_level, mirroring the period-contract exemption — re-projecting a published projection would silently compound models); ledger_assertion metadata is recorded only when the fact asserts it, matching the loader's no-stamp rule; the CBO and SOI series indexers fail loudly on conflicting facts for the same (series, year) instead of last-write-wins; and one misindented test kwarg. Branch rebased onto current main (#289 et al.). The review harness behind the PR's measured-implications section is checked in as tools/diff_us_target_surface_aging.py so reviewers can reproduce it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Jul 3, 2026
* Consume pinned Ledger artifacts and enforce the period contract Loads Ledger consumer artifacts (manifest.json + consumer_facts.jsonl) with hash verification and optional build-config pins, and records the artifact identity in both build and release manifests, so a release's target values are reproducible from a named Ledger artifact (#160, #271). Bare consumer-facts files still load, content-addressed by their own hash. The period contract (PolicyEngine/ledger#71) is now enforced at compile time: an ageable observation dollar level whose fact period differs from the build period raises PeriodContractError instead of silently calibrating at the wrong period — the populace#212 failure mode. Builds either age the value under the named cbo_growth_factor_aging model (now the release-tool default, with --no-age-targets to disable), or pass an explicit allow_unaged_dollar_targets waiver that stamps period_contract_waiver metadata on every affected target. Aged targets carry alignment_model_id/alignment_model_version alongside the existing factor lineage, publisher projections consumed at their published level are exempt by assertion, and CBO rows typed as observations are refused as growth factors. Consumer rows' assertion and fact period now flow into ledger_* target metadata and reference selectors. Refs #116, #160, #212, #271; PolicyEngine/ledger#71, PolicyEngine/ledger#73. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Adapt existing target-compile tests to the period contract Existing tests compile 2024/2025 surfaces from TY2022/23 fixture facts un-aged — exactly the state the contract now refuses silently. Each compile call declares the explicit allow_unaged_dollar_targets waiver so the tested behavior is unchanged and the waived state is visible, and the release-builder test stubs the artifact loader instead of the retired bare-JSONL helper. A new compile-level test asserts the unwaived path raises. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Do not stamp default assertions onto legacy fact rows The artifact loader validated row assertions by writing the observation default onto rows that omit the field. Measured against a real bundle feed, that broke aging: pre-#73 CBO projection rows arrive unlabeled, the stamp typed them as observations, and the growth-factor filter then refused them — zero targets aged. Rows now pass through exactly as published; an assertion is validated when present and never fabricated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Chain observed SOI growth into aging factors (model v1.1.0) Measured against a real three-year Ledger bundle feed, v1.0.0 aged only the 28 national TY2023 dollar targets: the CBO February 2026 projection detail starts at TY2023, so all 1,480 TY2022 state rows had no denominator and fell to period-contract waivers — an incoherent joint surface (national anchors at 2024 levels, states at 2022). cbo_growth_factor_aging v1.1.0 bridges years the projection detail does not cover with the same series' national SOI actuals: factor = soi(pivot)/soi(source) x cbo(build)/cbo(pivot), observed growth for observed years and projected growth only where nothing is observed. Chain sources are an explicit map (AGI via Table 1.1, wages and net capital gain via Table 1.4); everything else keeps the AGI default, now also chainable. Chained factors record both bridge facts in their lineage. On the same feed the full surface now ages: 1,480 targets, zero waivers, aged-dollar total $184.0T -> $202.7T (+10.2%); the TY2022 US AGI row lands at $16.56T against $16.62T from the TY2023 national path — independent vintages converging on the same build-year level. Refs #116, #212; PolicyEngine/ledger#71. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix independent review findings The reviewer found two sibling scorer tools this branch broke: score_us_fiscal_targets.py and score_us_state_files.py imported the retired _load_ledger_facts and compiled without contract flags, so both crashed at import and would then have raised PeriodContractError on any real feed. They now load through the pinned artifact loader and expose --age-targets / --allow-unaged-dollar-targets mirroring the release builder, defaulting to the incumbent un-aged-waived surface so existing releases score against the surface they were calibrated to. Also from review: publisher-projection-backed dollar targets are never re-aged (aging_factor_source=source_projection_level, mirroring the period-contract exemption — re-projecting a published projection would silently compound models); ledger_assertion metadata is recorded only when the fact asserts it, matching the loader's no-stamp rule; the CBO and SOI series indexers fail loudly on conflicting facts for the same (series, year) instead of last-write-wins; and one misindented test kwarg. Branch rebased onto current main (#289 et al.). The review harness behind the PR's measured-implications section is checked in as tools/diff_us_target_surface_aging.py so reviewers can reproduce it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Retire the bare Ledger facts loader everywhere The re-review found a third importer of the removed _load_ledger_facts: audit_us_ctc_line19_proxies.py failed at import. An exhaustive sweep then found build_us_puf_support_base.py carrying its own private copy of the same bare loader. Both now load through the pinned artifact loader, so no unverified feed path remains anywhere in tools/. Also covers the SOI-chain conflict guard with its own regression test (the CBO guard already had one). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- 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.
Follow-up to #277 (populace #275). The ladder shipped opt-in: nothing stopped a base or a release from being built without the geography spine — the silent-degradation family (#225's everyone-is-a-citizen, #34's NYC-zero) with a new face. Carrying the ladder is now the default at both enforcement points:
tools/build_us_puf_support_base.py): omitting--block-ladder-artifactis an error; diagnostic builds opt out explicitly with--without-block-ladder, and the opt-out is recorded in the build summary.l0_refit_export): the geography spine (state_fips,congressional_district_geoid, and the seven ladder columns) joinsUS_RELEASE_REQUIRED_HOUSEHOLD_SOURCE_COLUMNS(presence-checked; value quality is the gate's job), and theus_geography_laddergate runs on the selected support with its calibrated weights — a release whose spine is inconsistent or whose NYC mass collapsed fails by default.--allow-geography-ladder-gate-failuresis the diagnostic escape hatch, mirroring--allow-input-mass-drift, and the gate result lands in the export summary either way.Operational note: reconstructions of ladder-less bases (anything built before #277) now require the explicit escape hatches — that is the point. The national ladder artifact builds in minutes from cached sources via
tools/build_us_block_ladder_artifact.py(18MB NPZ; validated at 5,769,942 blocks / population exactly 331,449,281 / 436 CDs / 3,143 counties).🤖 Generated with Claude Code