From 5cfe6cad659e115582e361b94ba668b579373519 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 11 Jul 2026 12:44:11 -0400 Subject: [PATCH] Refresh merged-bundle count pins and make bundle drift loud in CI tests/test_arch_bundle.py::test_build_bundle_writes_merged_consumer_contract pinned the merged default bundle at 7,149 facts / 27 source packages -- the state of 2026-05-28 (5ec0956). Main then landed fifteen source-package PRs (#34-#48) before this branch forked at 5e851c5, and the test is not in the CI pytest whitelist, so the pins went stale silently: the bundle has built 10,268 facts / 39 packages (8 year-skipped) since the fork point. Diagnosis (2026-07-11): legitimate additive drift, not a regression. The bundle built at the fork point 5e851c5 and at branch tip 08d1001 produce byte-identical consumer_facts.jsonl (sha256 78ca9a51...), so no branch-side commit changed bundle behavior; every count delta decomposes exactly into the fifteen pre-fork package additions (bea +443, cbo +6, census_acs +468, census_population_projections +86, cms_medicaid +255, hhs_acf_liheap +1, irs_soi +1444, ssa +416 = +3,119), and every pre-existing per-table count is unchanged. - Refresh all hardcoded expectations to the current build; pin the eight year-2023-skipped packages by name (mirrors main's test_ledger_bundle style) and spot-check three post-fork package suites. - Run the file in CI as a standalone "Arch bundle drift" job. It is deliberately NOT added to the required "Arch checks" pytest whitelist: the merged build takes ~6 minutes and "Arch checks" gates the resolver's daily append PRs, which cannot touch bundle inputs. The test docstring records the same rationale. Lint the file via the ruff whitelist. - Drop the paths filter from the append-gate workflow: "Append gate" is a required status check, and with the filter a PR touching none of the gated paths (like this one) never receives the check and deadlocks on "Expected". The gate is cheap when the ledger diff is empty. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 30 +++++ .github/workflows/thesis-facts-append.yml | 23 +--- tests/test_arch_bundle.py | 152 +++++++++++++++++----- 3 files changed, 153 insertions(+), 52 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9647692..b32af30 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,7 @@ jobs: run: > uv run ruff check arch + tests/test_arch_bundle.py db/cli.py db/etl_snap.py db/etl_aca_enrollment.py @@ -136,3 +137,32 @@ jobs: assert ConditionalMAF is not None PY /tmp/arch-wheel-smoke/bin/arch --help >/dev/null + + # Exact-count pin on the merged consumer bundle (tests/test_arch_bundle.py). + # Deliberately a standalone job rather than part of the required "Arch + # checks" pytest whitelist: the merged build takes ~6 minutes, and "Arch + # checks" gates the Thesis resolver's daily append PRs, which cannot touch + # bundle inputs. This job keeps bundle drift loud on every push and PR + # without adding latency to the required append path. + arch-bundle-drift: + name: Arch bundle drift + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.14" + + - name: Install dependencies + run: uv sync --locked --all-extras + + - name: Pin merged bundle counts + run: uv run pytest tests/test_arch_bundle.py -q diff --git a/.github/workflows/thesis-facts-append.yml b/.github/workflows/thesis-facts-append.yml index cff2c1e..73c6cca 100644 --- a/.github/workflows/thesis-facts-append.yml +++ b/.github/workflows/thesis-facts-append.yml @@ -6,30 +6,21 @@ name: Thesis facts append gate # PR base, the witnessed release chain, per-row schema and binding requirements, # and explicit supersede semantics for corrections. Direct pushes get the same # full-file checks. +# +# No paths filter, on purpose: branch protection lists "Append gate" as a +# required status check, so it must report on every pull request into the +# branch. With a paths filter, a PR that touches none of the gated files +# (tests, CI config) never receives the check and deadlocks on "Expected". +# For such PRs the append-only diff is trivially clean and the gate stays +# cheap. on: pull_request: branches: - codex/thesis-ledger-facts - paths: - - "ledger/**" - - "releases/**" - - "scripts/check_thesis_facts_append.py" - - "scripts/canonical_json.py" - - "scripts/cut_release_manifest.py" - - "scripts/verify_release_chain.py" - - ".github/workflows/thesis-facts-append.yml" push: branches: - codex/thesis-ledger-facts - paths: - - "ledger/**" - - "releases/**" - - "scripts/check_thesis_facts_append.py" - - "scripts/canonical_json.py" - - "scripts/cut_release_manifest.py" - - "scripts/verify_release_chain.py" - - ".github/workflows/thesis-facts-append.yml" jobs: append-gate: diff --git a/tests/test_arch_bundle.py b/tests/test_arch_bundle.py index 436b9ce..f26a628 100644 --- a/tests/test_arch_bundle.py +++ b/tests/test_arch_bundle.py @@ -13,6 +13,26 @@ def _load_jsonl(path): def test_build_bundle_writes_merged_consumer_contract(tmp_path): + """Pin the merged default bundle to exact counts so drift is loud. + + Every count below is deliberately hardcoded: any change to bundle + inputs (``arch/``, ``packages/``, ``db/data/``) must update this test + in the same change. On this branch those inputs are frozen — the + thesis-facts branch takes ledger appends, not source-package work — + so a failure here is a tripwire, not routine drift. The counts were + regenerated 2026-07-11 from the fork-point package set (main PRs + #34-#48 landed before this branch forked and were never reflected + here because CI did not run this file). Regenerate by rebuilding: + ``uv run arch build-bundle --year 2023 --out `` and reading the + artifacts it writes. + + CI runs this file as the standalone "Arch bundle drift" job, and it + is deliberately NOT in the required "Arch checks" pytest whitelist: + the merged build takes ~6 minutes, and the required set gates the + Thesis resolver's daily append PRs, which cannot affect bundle + inputs. Keeping the slow pin visible-but-nonblocking protects append + merge latency; the omission from the whitelist is not an oversight. + """ output_dir = tmp_path / "bundle" report = build_bundle(output_dir, year=2023) @@ -29,62 +49,95 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): "aggregate_duplicate_key_count": 0, "entity_count": 6, "error_count": 0, - "fact_count": 7149, - "geography_count": 54, - "period_count": 7, + "fact_count": 10268, + "geography_count": 483, + "period_count": 9, "semantic_duplicate_key_count": 3, - "skipped_source_count": 0, - "source_count": 12, - "source_package_count": 27, + "skipped_source_count": 8, + "source_count": 16, + "source_package_count": 39, "warning_count": 1, } - assert len(rows) == 7149 + assert len(rows) == 10268 assert rows[0]["aggregate_fact_key"].startswith("arch.aggregate_fact.v2:") assert rows[0]["semantic_fact_key"].startswith("arch.semantic_fact.v2:") - assert source_packages["source_package_count"] == 27 - assert source_packages["skipped_source_count"] == 0 - assert not source_packages["skipped_sources"] - assert coverage["fact_count"] == 7149 + assert source_packages["source_package_count"] == 39 + assert source_packages["skipped_source_count"] == 8 + assert sorted(item["source"] for item in source_packages["skipped_sources"]) == [ + "census-acs-s0101-congressional-district-age-2024", + "census-acs-s0101-national-age-2024", + "census-acs-s0101-state-age-2024", + "census-acs-s2201-congressional-district-snap-2024", + "cms-aca-effectuated-enrollment-2022", + "cms-aca-oep-state-level", + "cms-aca-oep-state-level-2022", + "cms-aca-oep-state-level-2025", + ] + assert { + item["reason"] for item in source_packages["skipped_sources"] + } == {"source package is not available for requested year"} + assert coverage["fact_count"] == 10268 assert coverage["counts"]["by_source"] == { + "bea": 443, + "cbo": 6, + "census_acs": 468, "census_pep": 988, + "census_population_projections": 86, "census_stc": 46, - "cms_medicaid": 260, + "cms_medicaid": 515, "cms_medicare": 1, "cms_nhe": 1, "federal_reserve": 1, - "hhs_acf_liheap": 1, + "hhs_acf_liheap": 2, "hhs_acf_tanf": 110, - "irs_soi": 5467, + "irs_soi": 6911, "kff": 52, - "ssa": 6, + "ssa": 422, "usda_snap": 216, } assert coverage["counts"]["by_source_table"] == { + "bea:BEA NIPA annual data flat file": 27, + "bea:BEA Regional annual state personal income CSV ZIP": 416, + ( + "cbo:Revenue Projections, by Category, February 2026, sheet " + "3.Individual Income Tax Details" + ): 6, + ( + "census_acs:ACS 2023 1-year detailed table B01001 female age " + "bands by state" + ): 468, ( - "census_pep:Annual Estimates of the Resident Population by Single Year " - "of Age and Sex for the United States" + "census_pep:Annual Estimates of the Resident Population by " + "Single Year of Age and Sex for the United States" ): 19, ( - "census_pep:Annual State Resident Population Estimates by Single Year " - "of Age, Sex, Race, and Hispanic Origin" + "census_pep:Annual State Resident Population Estimates by " + "Single Year of Age, Sex, Race, and Hispanic Origin" ): 969, + ( + "census_population_projections:2023 National Population " + "Projections Main Series, middle series" + ): 86, "census_stc:FY2023 STC Flat File item T40 Individual Income Taxes": 46, ( - "cms_medicaid:State Medicaid and CHIP Applications, Eligibility " - "Determinations, and Enrollment Data" - ): 260, + "cms_medicaid:State Medicaid and CHIP Applications, " + "Eligibility Determinations, and Enrollment Data" + ): 515, "cms_medicare:2025 Medicare Trustees Report Table III.C3": 1, ( - "cms_nhe:National Health Expenditures by type of service and source " - "of funds, CY 1960-2024" + "cms_nhe:National Health Expenditures by type of service and " + "source of funds, CY 1960-2024" ): 1, "federal_reserve:Z.1 B.101 Households and nonprofit organizations": 1, + "hhs_acf_liheap:LIHEAP FY2023 National Profile (All States)": 1, "hhs_acf_liheap:LIHEAP FY2024 National Profile (All States)": 1, "hhs_acf_tanf:FY 2024 Federal TANF and State MOE Financial Data": 52, "hhs_acf_tanf:TANF Caseload Data 2024": 58, + "irs_soi:Congressional District Data 2022": 1440, "irs_soi:Historic Table 2": 605, "irs_soi:Historic Table 2 state AGI facts": 918, "irs_soi:Historic Table 2 state broad totals": 2703, + "irs_soi:Historic Table 2 state data, United States total": 4, "irs_soi:Historic Table 2 state EITC totals": 510, "irs_soi:Publication 1304 Table 1.1": 80, "irs_soi:Publication 1304 Table 1.2": 7, @@ -108,28 +161,37 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): "Age of Taxpayer" ): 2, "kff:Full Year Average Marketplace Effectuated Enrollment, 2017-2024": 52, - "ssa:SSA Annual Statistical Supplement 2025 extracted OASDI and SSI target rows": 6, - "usda_snap:SNAP Monthly State Participation and Benefit Summary FY69 to current": 216, + "ssa:SSA Annual Statistical Supplement 2025 Table 7.B1": 416, + ( + "ssa:SSA Annual Statistical Supplement 2025 extracted OASDI " + "and SSI target rows" + ): 6, + ( + "usda_snap:SNAP Monthly State Participation and Benefit " + "Summary FY69 to current" + ): 216, } assert coverage["counts"]["by_period"] == { - "calendar_year:2023": 2, - "calendar_year:2024": 1047, - "fiscal_year:2023": 46, + "calendar_year:2018": 1, + "calendar_year:2023": 997, + "calendar_year:2024": 1464, + "fiscal_year:2023": 47, "fiscal_year:2024": 327, "month:2024-12": 260, + "month:2025-12": 255, "tax_year:2022": 4968, - "tax_year:2023": 499, + "tax_year:2023": 1949, } - assert coverage["counts"]["by_geography"]["country:0100000US"] == 1384 - assert coverage["counts"]["by_geography"]["state:0400000US06"] == 113 - assert len(coverage["counts"]["by_geography"]) == 54 + assert coverage["counts"]["by_geography"]["country:0100000US"] == 1527 + assert coverage["counts"]["by_geography"]["state:0400000US06"] == 146 + assert len(coverage["counts"]["by_geography"]) == 483 assert coverage["counts"]["by_entity"] == { "family": 107, "government": 101, - "household": 55, + "household": 56, "institutional_sector": 1, - "person": 1418, - "tax_unit": 5467, + "person": 3086, + "tax_unit": 6917, } assert not coverage["duplicates"]["aggregate_fact_keys"] assert len(coverage["duplicates"]["semantic_fact_keys"]) == 3 @@ -213,6 +275,24 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): / "kff-marketplace-effectuated-enrollment" / "consumer_facts.jsonl" ).exists() + assert ( + output_dir + / "sources" + / "bea-nipa-personal-income-components" + / "consumer_facts.jsonl" + ).exists() + assert ( + output_dir + / "sources" + / "soi-congressional-district-2022" + / "consumer_facts.jsonl" + ).exists() + assert ( + output_dir + / "sources" + / "ssa-ssi-table-7b1-2024" + / "consumer_facts.jsonl" + ).exists() def test_build_bundle_cli_supports_explicit_sources(tmp_path, capsys):