Repository navigation
feat(margins): split margin-commodity columns by commodity purchased - #1144
Open
WesIngwersen wants to merge 4 commits into
Open
WesIngwersen wants to merge 4 commits into
WesIngwersen wants to merge 4 commits into
Conversation
…1140) Step 6 placed each buyer's margin across the margin commodities with that buyer's 2017 placement, so every commodity a buyer purchased got the same within-type split. commodity_placement fits each buyer's cells (RAS) to a commodity prior while holding each commodity's margin per type and each margin commodity's earnings from the buyer, so Use, Make and Import do not move. Give-back cells are fitted on their own sign. margins_table gates the earnings against the buyer split. Transport prior: joint_mode_fit (the 2017 mode x commodity fit), exposed as transport_commodity_prior. Wholesale and retail keep the buyer split until their product-line prior lands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1140) F03000's 2017 margin-commodity placement nets offsetting signs (pipeline is 117% of its transport margin), so every inventory build booked pipeline margin: 17% of automobiles' transport margin in v0.6 A_margin, and negative pipeline on grain draw-downs. derive_cornerstone_A_margin now reads the margins with exclude_inventories=True. Phi keeps F03000. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…duct lines (#1140) trade_commodity_prior gives each trade code's margin by purchased commodity: the code's published 2017 give-up over its Economic Census product-line sales, applied to its sales of each good. Kinds of business map to codes by the trade crosswalk and product lines to commodities by the #529 concordance, plus a local supplement for light trucks, nonprescription drugs, the retail medicines line and retail pet food. Anchored on 2017 only, and guarded: 2022 retail is on NAICS 2022 kinds of business the crosswalk does not cover, and 454000 nonstore is not observable on its own there. Suppressed cells that the PxI recovery split equally across withheld industries are re-split by each industry's observed sales in the same commodity family; equal shares had put grain on furniture and machinery wholesalers. margins_table now places all three families by commodity. On 2024 the per-buyer earnings gate holds within $1 for every margin commodity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1140) Same as 2025_usa_cornerstone_v0_6 except nowcast_mut_vintage, which points at the Steps 6-7 rebuild with the commodity-based margin split. Make, Use and Import match v0.5.0_a166975 (Use within $1), so only A_margin differs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bl-young
approved these changes
Oct 23, 2026
Member
There was a problem hiding this comment.
Looks good — approving with a few pre-merge / follow-on notes.
Must before merge
- Fix typecheck.
test_use_price_bridge.py(~402, 419–420): cast.loc[...]results tofloat(or usepytest.approx) before comparing to numeric literals. Format/lint/tests are otherwise green.
Follow-on
- Time-series MUTs: I've created #1146 from this PR (rebuild NowcastMUT 2017–2024 with the commodity-split Step 6 and retarget v1.0 year configs from #1145). Only
v0.6.0_5d40d42/v0_6_margin_splithas the fix today;a166975/011f41fstay buyer-split. Balanced SUT pin is out of scope there.
Merge posture
- Fine alongside #1138. No file overlap: #1138 registers
A_marginfor future snapshot cuts; this PR corrects the matrix content / interim sidecar CEDA already loads (…/a_margin/v0.6.0_5d40d42/…). Either merge order works.
Optional validation
- Running
2025_usa_cornerstone_v0_6_margin_splitthrough CEDA to confirm global EFs are unchanged is available if we want extra comfort, but not necessary for merge given Make/Use/Import parity and CEDA already consuming this sidecar.
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.
Closes #1140. Related: #1138, #836, #815, #615, https://github.com/cornerstone-data/ceda/issues/547
What changed? Why?
The nowcast Margins table splits each transaction's margin across the 24 margin-providing commodities (10 wholesale, 9 retail, 5 transport codes). That split was taken from each buyer's 2017 mix of margin services, so every commodity a buyer purchased got the same split. As a result,
A_margin(margin dollars paid to each margin commodity per dollar of a commodity's producer value) reflected who buys a commodity, not what the commodity is. In v0.6, automobiles (336111) put less wholesale margin on motor vehicle wholesale (423100) than on machinery, electrical or professional equipment wholesale.This PR splits each transaction's margin by the commodity purchased:
commodity_placement): within each buyer, a biproportional (RAS) fit holds two sets of totals: each commodity's Transportation, Wholesale and Retail margin (the five published Margins columns), and what each margin commodity earns from the buyer (its row of the Use table). The commodity prior decides the split inside those totals. Give-back (negative) cells are fitted on their own sign. A new Step 6 gate fails the build if any margin commodity's earnings from any buyer move by more than $1M.joint_mode_fit), now exposed astransport_commodity_prior.trade_commodity_prior): 2017 Economic Census product-line sales by kind of business, mapped to trade codes by the trade crosswalk and to BEA commodities by the Step 1C: Inventories FBS - integrate the change in inventories column #529 product concordance. Each trade code's margin is its published 2017 margin output over its sales of all product lines, applied to its sales of each good. Two corrections for this use only:336112), nonprescription drugs (325412), retail "medicines, vitamins, minerals, and supplements" (325412/325411) and retail pet food (311111). They stay out of the shared concordance because it also drives the inventories attribution.449,455-459) that the trade crosswalk does not cover, and nonstore retail (454000) is not observable on its own.F03000) is left out ofA_margin. Its 2017 placement nets offsetting signs (pipeline is 117% of its net transport margin), which put pipeline margin on automobile inventory builds. Phi (producer to purchaser price ratio) still includes it.2025_usa_cornerstone_v0_6_margin_split: v0.6 withnowcast_mut_vintage: v0.6.0_5d40d42.Impact
v0.6.0_5d40d42, built from the same balanced 2024 tables asv0.5.0_a166975) matchv0.5.0_a166975on Make and Import exactly and on Use within $0.98. Under the two configs, q is identical and A_dom differs by at most 1.6e-12.A_marginchanges in its split only. Total margin per dollar of each commodity (the column sums) is unchanged to 2e-16; 4,352 cells move. Selected columns, margin dollars per dollar of producer value:336111336111325412324110212100v0.5.0_a166975exactly in the five published columns. On margin-commodity rows, Producers' Value matches; Purchasers' Value (the buyer's direct purchase of the margin service, stored as Producers' Value minus margin routed onto it) moves by $14.1bn gross, $0 net, because Step 7 rescales each goods row with its own redefinition. Negative direct-purchase cells fall from 526 (-$8.65bn) to 434 (-$5.78bn).A_marginfor CEDA under this config:gs://cornerstone-default/snapshots/a_margin/v0.6.0_5d40d42/A_margin.parquet. The feat(snapshots): add A_margin as a snapshot object #1138 sidecar at.../a_margin/e10c75f5.../A_margin.parquetis untouched; @bl-young, feat(snapshots): add A_margin as a snapshot object #1138 can point at the new object.v0.6.0_5d40d42is otherwise the first v0.7 input; the v0.6 release and.SNAPSHOT_KEYare unchanged.Testing
commodity_placement(empty prior reproduces the buyer split; both totals held; a commodity lands on its own code; give-backs fitted on their own sign), the 2017 guard, and the suppression re-split.v0.5.0_a166975as above; identity Producers' Value - Purchasers' Value = routed margin exact on every margin-commodity row.blackandruff; the full test suite is left to CI.🤖 Generated with Claude Code