Label IRS SOI N01000/A01000 as Form 1040 line 7 capital gain or loss - #304
Conversation
Historic Table 2 declared N01000/A01000 with Table 1.4's Schedule D taxable-net-gain concept (irs_soi.returns_with_taxable_net_capital_gains / irs_soi.taxable_net_capital_gains). Every IRS guide for Historic Table 2 (TY2020-TY2023) and for the TY2022 congressional-district, ZIP and county files defines them as "net capital gain (less loss)" from Form 1040 line 7: a Schedule D gain, a limited Schedule D loss, or capital gain distributions filed without Schedule D. For TY2022 the two counts are 30,465,850 and 12,915,122 returns, yet they shared one semantic fact key. Historic Table 2 and the congressional-district file now declare irs_soi.returns_with_form_1040_capital_gain_or_loss / irs_soi.form_1040_capital_gain_or_loss with the IRS labels. measure_id, values and lineage are unchanged; Table 1.4 keeps its concept. - docs/concept-migrations.md records the rename, as docs/architecture.md requires, and architecture.md links it. - tests/test_chronicle_soi_capital_gain_concepts.py requires every irs_soi package reading N01000/A01000 (any vintage) to carry the line 7 concept, keeps the Schedule D concept on Table 1.4 only, pins the consumer selector and values, and checks the concept against the registered publisher cells (N01000 = Table 1.4 distributions-only + Schedule D gain + Schedule D loss returns within 0.25%). - The default-bundle snapshot gains 104 semantic-duplicate keys (2,022 -> 2,126): Historic Table 2 and congressional-district state and US rows now share a concept, as 19 of the 31 IRS columns they share already do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The guard scan now yields every measure declaration, so a measure missing its concept fails the line 7 check instead of being skipped. - The Schedule D gain concept may live on any Table 1.4 vintage package (table_1_4*), still only on the net_capital_gains_* measures. - docs/concept-migrations.md: count shared columns per package (19 of 31 national, 24 of 36 state), say the HT2/Table 1.4 collision was latent in the default bundle, and point the shared measure_id and the 10 other HT2/CD concept mismatches at chronicle#307. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Independent review (Opus 5.5 via Subfleet, read-only lane; job ledger-source-fidelity: PASS This approval assumes CI passes, in particular the 2,126 pin. None of the findings blocks the merge. Answers to the seven questions1. Source fidelity: verified. The doc guides define both variables the way the PR says, in every vintage:
HT2 US cells, checked in the IRS CSVs (row 2,
TY2020–21 has no Table 1.4 cells:
Nothing but concept and label changed:
The new id and label describe line 7 accurately. The id names the form line but not the line number, so it survives line renumbering (line 6 in TY2019, for example). 2. Concept choice: sound.
3. Semantic duplicates: +104 is right.
4. Tests: the guard catches the TY2023 clone. The differential test is sound and does real work.
5. Consumer claim: verified by reading the code, with a scoping caveat (finding 2).
6. Boundary: PASS. The change touches only YAML vocabulary, docs and tests. No reconciliation, aging, imputation, target selection or PolicyEngine-computed value enters Chronicle. The tests only compare published cells. 7. Docs: accurate.
Findings
Not verified
|
From the second review of chronicle#304: - Count shared IRS variables by the header each measure reads, not only by source_column_id: before this change 26 of 38 (national) and 24 of 36 (state) carried one concept in Historic Table 2 and the congressional-district file, with the same 12 exceptions. The first commit's message said 19 of 31, counting source_column_id only. - Only the capital-gain rows stop sharing a semantic key with Table 1.4. - State what the guard enforces: measures that name N01000/A01000 in a source_column_id or expected_column_header guard. - Give Table 1.4's pre-TY2022 column numbers and say which year CI checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Second independent review (Opus 5.5 agent with a shell, read-only), of follow-up Recommendation: APPROVE. No blocking findings.
|
Resolves the default-bundle pins in tests/test_chronicle_bundle.py: main's counts after chronicle#302/#304 plus this PR's 1,020 facts and one package (fact_count 409,165; source_package_count 269), and both period-increment blocks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Historic Table 2 (HT2) labels IRS columns
N01000/A01000"Returns with taxable net capital gains" / "Taxable net capital gains". Their concept ids areirs_soi.returns_with_taxable_net_capital_gains/irs_soi.taxable_net_capital_gains, the ids Table 1.4 uses for columns 37/38 (Schedule D "Taxable net gain"). Those are different IRS counts: for TY2022 they are 30,465,850 and 12,915,122 returns. On main they still share onesemantic_fact_key.This PR gives
N01000/A01000the concept their IRS documentation defines, in every package that reads them:soi-historic-table-2,soi-historic-table-2-state-broad-2022N01000irs_soi.returns_with_taxable_net_capital_gainsirs_soi.returns_with_form_1040_capital_gain_or_lossA01000irs_soi.taxable_net_capital_gainsirs_soi.form_1040_capital_gain_or_losssoi-congressional-district-2022N01000irs_soi.returns_with_net_capital_gainsirs_soi.returns_with_form_1040_capital_gain_or_lossA01000irs_soi.net_capital_gainsirs_soi.form_1040_capital_gain_or_lossmeasure_id(net_capital_gains_returns/net_capital_gains_amount), values, columns, header guards and lineage are unchanged.What the IRS files define
All files are in
~/PolicyEngine/_reviews/cg-returns-control-20260925/irs/. Doc guides were converted withtextutil -convert txt; the line numbers refer to that text.Doc guides. Every guide gives the same two rows, "1040:7" (TY2020/21: "1040: 7"):
20incmdocguide.doc4925939d…21incmdocguide.docd7bf3d65…22incmdocguide.docd99db44b…23incmdocguide.doc94279069…22incddocguide.docx4e265d3c…22zpdoc.docx/ county TY202222incydocguide.docx8aedaa4d…/a6acb748…Form 1040 line 7. "Capital gain or (loss). Attach Schedule D if required. If not required, check here" is line 7 on the 2020–2023 Form 1040. The line holds one of three things:
Publisher cells. Table 1.4 splits those three groups into separate columns. HT2's count matches their sum, not the gain column:
N01000(STATE=US, AGI_STUB=0)20in55cmcsv.csvAI2)21in55cmcsv.csvAI2)22in55cmcsv.csvAK2)23in55cmcsv.csvAK2)20in14ar.xls–23in14ar.xls, sheetTBL14, row 9 "All returns, total".Why these ids.
irs_soi.*capital_asset_net_gain_less_lossfor yet another count. Naming the Form 1040 line identifies the population exactly.irs_soi.net_capital_gainsreads as a gain-only amount. IRC §1222(11) and the Pub 1304 Explanation of Terms (printed p. 331) both use "net capital gain" for a positive amount.Chronicle effects (measured)
Four affected packages, main vs this branch. Build:
build-bundle --year 2023oversoi-historic-table-2,soi-historic-table-2-state-broad-2022,soi-congressional-district-2022andsoi-table-1-4, 30,768 facts. Diffed row by row onsource_record_id:observed_measure.source_concept,observed_measure_key,aggregate_fact_key,semantic_fact_key,legacy_fact_key, the generatedlabel, andlayout.measure_label.layout.record_set_spec_hashchanges on all 30,188 rows of the three relabelled packages, because it hashes the whole record-set spec.Semantic duplicates.
22incddocguide.docx, section C) says its state totals "may not be comparable to State totals published elsewhere by SOI because of disclosure protection procedures or the exclusion of returns that did not match based on the ZIP code."test_line_7_and_schedule_d_gain_facts_are_different_semantic_factsnow pins apart.Recorded in
docs/concept-migrations.md, whichdocs/architecture.mdnow links, per its rule that "a deliberate rename requires a migration note and a regression test for the affected consumer selector".TY2023 Historic Table 2 (#295)
#295 (stacked on #291) adds
historic_table_2_2023andhistoric_table_2_state_broad_2023. Both are cloned line by line from the TY2022 YAML, so they carry the old label. Two tests keep either merge order from shipping it:source_column_id/expected_column_header=N01000/A01000), so it covers every vintage. A TY2023 package with the old concept fails it.test_packages_mirror_their_2022_twinsfails if the TY2022 twin is relabelled and TY2023 is not, and passes once both are.Simulation: #295's head
f55ae34with this commit cherry-picked:historic_table_2_2023:net_capital_gains_returns, and Add IRS SOI Historic Table 2 TY2023 national, state broad and state EITC facts #295's mirror test fails for the national and state-broad packages (3 failed; the EITC mirror passes).tests/test_chronicle_soi_ht2_2023.pyandtests/test_chronicle_soi_capital_gain_concepts.pypass in full, 29 passed.The TY2023 patch touches 8 lines in 2 files:
packages/irs_soi/historic_table_2_2023/source_package.yaml,net_capital_gains_returnsandnet_capital_gains_amount(label and concept each);packages/irs_soi/historic_table_2_state_broad_2023/source_package.yaml, the same.The generator
gen_ht2_2023.pycopies measure labels and concepts from the TY2022 twin, so re-running it on this tree produces the same 8 lines. The patch is posted on #295: #295 (comment)Consumers (Microcosm)
Microcosm does not select on this concept id.
main(5187fce25), #1036 (2c811ab1c), #1040 (011a63b1a) and #1053 (67a36f5bc), excluding*.jsonl. None of them names any of the six ids.(measure_id, filing_status, universe):_soi_capital_gains_control_key_from_fact,fiscal_targets.py:1611. A tie goes to the first row in the feed, but only between rows with an equal period:_prefer_candidate,:2603.ledger_measure_concept,ledger_source_conceptandledger_fact_label. The key fieldsledger_*_fact_key/ledger_observed_measure_keycome along too._fiscal_target_concept_budget_keyintools/build_us_fiscal_refresh_release.py. For congressional-district specs it groups loss weights by metadata, including the concept.Measured on the pinned feed (
consumer_facts_us_c5e5bf8.jsonl). I relabelled the 1,084 rows and recomputed their keys with Chronicle's algorithm, re-sorted byaggregate_fact_keyastools/build_us_chronicle_feed.pywrites it, and compiled the release registry (target period 2024, aged, packaged CD crosswalk, Medicaid substitution):main5187fce25a0698bc97ff9/d315c75804ef->a4764a201fd4/6863092aa5862c811ab1ce02123644d42/65e4dde11c83->966a52f02d64/903e3a40cbe3011a63b1a059dc56d78db/47dce807b412->591c162264a4/b146a1df2d18ledger_measure_concept,ledger_source_concept,ledger_fact_label,ledger_observed_measure_key,ledger_aggregate_fact_key/ledger_fact_key/ledger_legacy_fact_key/ledger_semantic_fact_key, andhierarchy_raw_value(float rounding only).~/PolicyEngine/_reviews/ht2-cg-concept-20260927/microcosm-consumer/scratch/final/.So, incremental to #292, a re-pin onto this change moves no Microcosm target value, only the
ledger_*concept, label and key metadata. (A re-pin from the pinnedc5e5bf8feed onto current Chronicle main does move the returns control, because #292 restamps the congressional-district rows to TY2022; that is #292's effect, handled by microcosm#1036, not this PR's.) The code-level reading was re-checked on microcosmmainfdee065e9: no concept id is named, and the chooser and budget key are unchanged.Chronicle governance
ledger-source-ingestor.docs/concept-migrations.mdand the one-line link indocs/architecture.mdsit outside that role'sallowed_paths; they are the migration notedocs/architecture.mdrequires for a concept rename.python -m chronicle.harness validate-package <id> --year {2022,2023}: valid for all four packages with 0 errors (605, 2,703, 26,880 and 580 source records).build-bundle --year 2023over the four packages: valid, 30,768 facts, 0 errors, 0 aggregate-duplicate keys. Lineage coverage is 1.0 and agent-acceptance errors are 0 for each package. The only acceptance warning is the standardconcept_alignment_validation_skipped.ruff check chronicle policyengine_chronicle db scripts testsis clean.uv run pytest -q, the full suite, plus the source DB and wheel builds) passes on0f6b73c, including the new module and the 2,126 default-bundle pin; it re-runs on the review-fix head. Locally the new module passes (all 6 on the Add IRS SOI Historic Table 2 TY2023 national, state broad and state EITC facts #295 simulation tree).ledger-source-fidelity: PASS. Independent Opus 5.5 review via Subfleet (read-only lane), which re-derived the doc-guide rows, the HT2 and Table 1.4 cells and the identity table, and diffed the YAML against main. Posted below.ledger-contract: no schema or consumer-contract change. Concept ids are package vocabulary;docs/concept-migrations.mdrecords the rename.ledger-boundary: PASS (same review): only vocabulary, docs and tests change; the tests compare published cells only.Invariants (
tests/test_chronicle_soi_capital_gain_concepts.py)irs_soimeasure that namesN01000/A01000in itssource_column_idorexpected_column_headerguard declares the line 7 concept and IRS label, with both header guards naming the variable. The rule holds for any vintage, and the known TY2022 packages must be among them.table_1_4, or a latertable_1_4*vintage) declareirs_soi.*taxable_net_capital_gains, and only onnet_capital_gains_*.irs_soi.returns_with_net_capital_gains/irs_soi.net_capital_gains.source_measure_idand the published values: HT2 30,465,850 / $1,251,675,034k; congressional district 29,845,710 / $1,157,234,600k; Table 1.4 12,915,122 / $1,269,785,083k.22in55cmcsv.csvand22in14ar.xls,N01000equals Table 1.4's distributions-only + Schedule D gain + Schedule D loss returns within 0.25%, and exceeds 2.3x the gain-only count.Not changed here
measure_idnet_capital_gains_*for two different measures, againstdocs/architecture.md's rule. Changing it would move Microcosm's selector (microcosm#1036 and #1040 tell them apart by record-set family), so it is tracked in chronicle#307 with the 10 other HT2/CD concept mismatches.N/A00900,N/A01700,N/A06500,N/A25870,N/A26270) still carry different concepts in HT2 and the congressional-district file.limited_state_local_taxes_*andpremium_tax_credit_*columns read the wrong IRS variables. Another session is fixing that separately; this PR leaves those blocks untouched.Review follow-ups (commit
7c83e89)table_1_4*vintage package.measure_idhas a tracking issue (chronicle#307), linked fromdocs/concept-migrations.md.7c83e89(Opus 5.5, with a shell) approved and mutation-tested the guards: removing a concept, putting the Schedule D concept on another Table 1.4 measure, and restoring a retired id each fail; a copiedtable_1_4_2024package passes. Its P3 wording points (shared-variable counts by IRS variable, "capital-gain rows", what the guard enforces) are fixed in the follow-up doc commit.🤖 Generated with Claude Code