Conversation
Registers 23in55cmcsv.csv (TY2023, published 21 Aug 2026; sha256
d1f7c890...668f, verified by R2 readback in ledger-raw and chronicle-raw)
and adds soi-historic-table-2-state-agi-2023: for 50 states and DC, the
return count (N1) and AGI (A00100) of each of the ten AGI stubs.
Unlike the TY2022 package, stub 9 ($500k-$1M) and stub 10 ($1M+) are
separate facts, so every fact is one published cell. Labels are literal
TY2023 (no {year}), and both measures guard their column header because
the TY2023 file inserts two columns after DP.
Consumer context: PolicyEngine/microcosm#940 (state top-tail AGI mass).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured with chronicle build-bundle --year 2023: +1,020 facts (all irs_soi), +1 source package; semantic duplicates (467), warnings (76) and source tables (222) unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… its cell Review finding: the one-cell oracle read state and band from the record id, so a swapped bound pair or a wrong FIPS code outside Colorado would have passed. Each fact now also checks its own geography id (against an independent FIPS table), income_range filter, AGI bounds and source column. 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
Adds IRS SOI Historic Table 2 for tax year 2023 at state level: for the 50 states and DC, the number of returns (
N1) and adjusted gross income (A00100) in each of the ten AGI classes. The package emits 1,020 facts, and every one is a single published cell.The existing TY2022 package sums the $500,000-$1,000,000 and $1,000,000-or-more classes into one
500k_plusrow. In this package they are separate facts (500k_to_1m,1m_plus), so a consumer can see a state's returns and AGI at $1M+. For example, Colorado TY2023 has 15,610 returns with $47,266,883,000 of AGI at $1M+.Consumer context: PolicyEngine/microcosm#940. State totals match SOI while a state's income above $1M does not. Microcosm needs these rows to bind state top-tail targets. Facts are inert until Microcosm re-pins its feed.
What changes
db/data/irs_soi/historic_table_2/23in55cmcsv.csv: the publisher file from https://www.irs.gov/pub/irs-soi/23in55cmcsv.csv (Historic Table 2 page, updated 21 August 2026). It is 757,078 bytes with SHA-256d1f7c8901fcefb2c46f5dd14f22715b7c8513794ce7b9ea6a6a947f1c548668f.chronicle fetch-artifact --upload-r2, which added only the2023:entry to the shared manifest.ledger-rawat the recorded key and hash-verified. The same object is also inchronicle-rawat the same key, also read back and verified, matching how the TY2022 file is mirrored there.-diffin.gitattributes. The committed blob hashes to the publisher sha.packages/irs_soi/historic_table_2_state_agi_2023/source_package.yaml: one record set per state,irs_soi.ty2023.historic_table_2.state_agi.<st>.source_tableandrecord_set_spec_idare the same as TY2022, so the two vintages are one series.return_countandadjusted_gross_income. The AGI measure keeps the TY2022 concept alignment (IRC §62, exact,ledger-us).legal_vintage. There is no{year}, so building at any year yields the same TY2023 facts, and the package is already clean under the pending artifact-year restamp guard.N1,A00100), because the TY2023 file inserts two columns after column DP (N07262 ... A07265in place ofN07260, A07260). The columns this package reads (C, T) did not move.selected_rows, row numbers and guards, splits the summed top row into two single-cell rows, and uses literal-year labels. The same PyYAML dump settings reproduce the TY2022 file's body byte for byte; the header label maps are written as text, as in TY2022.soi-historic-table-2-state-agi-2023is registered inSOURCE_PACKAGE_ALIASES, in theirs_soi_filer_income_tax_creditsfamily (chronicle/targets/us_poverty.py), and indocs/pe-calibration-targets.md.The TY2022 package is unchanged. Its taxable-interest rows are what Microcosm binds today. An unpushed restamp-guard branch edits that file, so I did not touch it. This package has no taxable-interest measures, because a consumer that binds state interest needs the matching TY2023 national Historic Table 2 total, which is not packaged yet. Those measures should arrive together with that package.
Chronicle governance
ledger-source-ingestor.chronicle validate-package ... --year 2023: valid. It reports 51 record sets, 510 rows, 102 measures, 1,020 source records and 51 regions.chronicle build-bundle --year 2023 --source packages/irs_soi/historic_table_2_state_agi_2023: valid. It reports 1,020 facts, lineage coverage 1.0, 84,315 source cells, 594 source rows and 0 agent-acceptance errors.build-bundle --year 2023: valid. It has 351,913 facts (+1,020), 228 packages (+1), andirs_soi41,083 (+1,020). Semantic duplicate keys (467), warnings (76) and source tables (222) are unchanged, so no new fact shares a semantic key with an existing one.ledger-source-fidelity: PASS (independent Opus 5.5 review via subfleet, read-only). It re-read all 510 selectors, the row headers and state guards, the 51 identical measure blocks, the band constraints (51 of each), the CSV header columns and the Colorado and California cells. That reviewer had no shell, so the sha, the build and the full per-fact comparison come from my runs listed under the deterministic checks.ledger-contract: no schema or consumer-contract change.ledger-boundary: PASS (same review). The change is a pinned publisher artifact, a declarative one-cell-per-fact package and alias/coverage/doc entries. It contains no reconciliation, aging, imputation, activation or solver logic, and the TY2022 package is untouched.Review findings and responses
income_rangefilter, its AGI bounds and its source column.ledger-source-ingestor'sallowed_paths(db/data,.gitattributes, the alias maps and the docs row). Every package PR touches these; Add HMRC CGT Table 4 BADR and Investors’ Relief facts #288, Add HMRC CGT Tables 7–9 source packages #273 and Add TY2020 IRS SOI Table 1.4 facts (aging-chain bridge for TY2020 dollar targets) #113 did the same. Widening the role file belongs in a separate governance change.record_set_spec_idas TY2022 with a different band set. Kept on purpose. The spec id names the Historic Table 2 state AGI table, so TY2022 and TY2023 facts stay one series (source_series_key), and Add SOI state AGI taxable interest facts #62 changed these record sets' measures without a bump. A vintage's band set is what its package publishes. Consumers should select bands by their constraints, as Microcosm does.-diffdoes not stop line-ending conversion. This follows the file's existing convention for pinned CRLF artifacts. Notextattribute or autocrlf applies here (git check-attr), and every build re-verifies the sha, so a converted copy would fail loudly.legal_vintage: tax_year_{year}relabels at other build years. This predates the PR and the unpushed restamp-guard branch fixes it. This package is literal-year.Invariants (tested in
tests/test_chronicle_soi_state_agi_2023.py)value_scale, read with Python'scsvmodule rather than Chronicle's parser, and has exactly one source row.500k_to_1mmapped to500k_plus, the TY2023 ids of rows below $1M equal the TY2022 package's return-count and AGI ids. Consumers match vintages on these ids.Tests
tests/test_chronicle_soi_state_agi_2023.py(9 tests), plus the TY2023 counts intest_national_soi_source_package_aliases_validate_fixture_counts.tests/test_chronicle_bundle.pydefault-bundle pins re-measured with the build above.uv run pytest -q tests/test_chronicle_source_package.py tests/test_us_poverty_target_coverage.py tests/test_source_package_alias_drift.py tests/test_chronicle_pe_source_plan.py tests/test_chronicle_soi_state_agi_2023.py: 156 passed. The default-bundle test is covered by the fullbuild-bundle --year 2023run above, whose counts it pins; CI runs it.ruff check chronicle policyengine_chronicle db scripts testspasses.🤖 Generated with Claude Code