docs(nowcast): the 7 September rebuild — all eight years, and what the stack moved - #875
Conversation
Every table in the report was rebuilt from cleared artifacts on methods that changed in seven places since the 3 September run. Section 6a records what moved and why. Grand totals are preserved - the Use SUT differs from the previous build by 3 million USD at 2017 on 56.7 trillion, 0.007% at worst across the span - because every change this cycle is a redistribution rather than a level change. The interior moves 1.3% at 2017 rising to 7.3% at 2024, and that shape is the expected one: 2017 is anchored so only the trade re-splits and the aerospace conditioning reach it, while later years also carry the value-added reconciliation, whose gap against BEA's published series grows across the span. All eight years balance at T11 max |residual| 0.0 $M, 20 outer iterations, nothing skipped. Also records the two things this cycle exposed that were not visible before: that seven of eight years failed at first on a household gross-operating-surplus cell the reconciliation had never been exercised against, and that the Step 5 and Step 6 products carry no source lineage, so the artifact check cannot tell when their inputs move. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Step 6 produces the before-redefinitions tables; the after-redefinitions quartet was still built on the 2 September ones, and those are what the model build consumes. Ran the redefinitions across the span after its 2017 replay gate held, and recorded it alongside the rest of the rebuild. Also states the post-rebuild artifact-check position plainly: 386 flags remain, none of them on a product built in this cycle. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6d4547c to
1214c35
Compare
Carries the four new commits from main up the stack. No conflicts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The column read "Use SUT interior moved", which was wrong twice over: the figure covers the whole balanced table, value-added rows and final-demand columns included, and it is a gross sum of absolute cell differences, so it counts every relocated dollar twice. Renames the column, states the definition and both properties, and breaks the movement out by block. The split is the substantive part: the value-added share runs from 28% at 2017 to 45% at 2024, so at the far end of the span nearly half of what was labelled "interior" is the value-added reconciliation rather than the commodity-by-industry interior. The dollar figures and the block shares are unchanged measurements from the same comparison; only the description is new. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
In your description, this is listed under " Two things this rebuild exposed that are not fixed here". But this sounds like it was fixed? |
There was a problem hiding this comment.
Thank you this is a helpful summary! Looks like some good improvements across the board, but especially in trade. One comment on the description above. Also might be good to clarify where or which specific files were uploaded to GCS that correspond to this stack so we have a easily trackable record.
.gitattributes declined LFS on a measurement and named the condition for revisiting it: "if these figures start churning per-commit rather than per-milestone". That is what happened. The report's 30 comparison figures are re-rendered whenever the colour scheme or the tables underneath them move, which is 1.16 MB of incompressible blobs each time, and it ran twice in three days. All 42 committed PNGs become pointers. Nothing changes about their content or how the report references them. Two consequences worth stating rather than discovering. Working on this repo now needs git-lfs installed, which is the cost the original note was avoiding. And this does not shrink anything: blobs committed before this change stay in history as blobs, so the repo stops growing at this rate rather than getting smaller. Rewriting the history to convert those too would rewrite main and all ten open branches in the stack, and that is a separate decision. The nine committed .parquet fixtures are 3.1 MB, larger than the images, and are left as ordinary blobs: they are static reference artifacts rather than regenerated output, so they do not churn. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…threshold The report was dominated by a statistic with no grounding: the share of cells landing within 1% of the published value. The 1% was a choice, and the report read as though it were a property of the data. Two cells 0.9% and 1.1% apart were drawn as different colours and counted on opposite sides of a headline number. Cells both sides populate are now coloured on one continuous ramp, green at no difference through to red at 100% or more, and the figures carry a median and a value-weighted relative difference instead of an accuracy. The two are quoted together because they disagree in both directions and the gap is informative: the summary Use table at 2024 has a median cell 22.0% off but only 6.7% of its dollars misplaced, so the large cells are far better than the typical one, which no threshold count could show. Tolerance survives where a boundary is actually needed. check() has to answer pass or fail, so it keeps rtol/atol and the MATCH/PARTIAL split; what changed is that no colour and no reported statistic depends on it. The ramp is green to red as asked, but not on hue alone: that is the one gradient protanopes and deuteranopes cannot read. Lightness falls monotonically along it, L* 81/73/64/48/33, which carries the scale when the hues collapse - the two ends separate by dE 45.3 under simulated deuteranopia, almost all of it lightness. The anchors were searched rather than picked: the green end is squeezed between white (ABSENT) and the blue of EXTRA, which under tritanopia both sit near a light green, and the best available worst-pair separation is dE 26.0 against the floor of 25 that palette_separation already enforced. All 30 committed comparison figures re-rendered, and every caption and both summary tables rewritten from the measured values rather than carried over. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The rebuild exposed this and the PR described it as not fixed: the Step 5 to Step 7 products are written by bespoke savers rather than the FBS framework, so nothing populated primary_source_meta for them. The staleness check therefore had no way to see an input move, and answered "No stale cached artifacts" about balanced SUTs sitting on trade inputs that had been rebuilt hours earlier. A silent pass on something that cannot be checked reads as a clean bill of health, which is worse than no check at all. source_lineage() in utils/metadata takes the artifact names a saver read and returns their sidecars in the shape stale_artifacts._walk_sources already follows. Wired into both savers that know their inputs: save_mut() from MutTables.sources, and save_after_redef() from the before_inputs it already accepted and only recorded as bare filenames. A rebuilt Step 5 product now invalidates Step 6, and a rebuilt Step 6 invalidates Step 7. A name with no readable sidecar is recorded as a lineage_error rather than dropped, for the same reason: a source that quietly disappears from the record reads as "no inputs moved".⚠️ Step 5 itself is not covered. save_balance() cannot name its inputs - the seed comes from fit_interior, derive_initial_Y_pur, derive_initial_value_added and assemble_supply_seed, none of which report the artifacts they read, and each globs for its own newest file. Giving Step 5 real lineage means making those four report, which is a change across several modules rather than a saver edit. It keeps the builder surface from #867 in the meantime, so a change to the assembly module still flags it; what it cannot see is an upstream FBS rebuild. Not retroactive: products already on disk keep the sidecars they were written with, so the lineage appears on the next build. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Both addressed. You were right that the first item was fixed — it was under the wrong heading. That whole "not fixed here" section is gone: the household The second item is now fixed too, for Steps 6 and 7. On the GCS record: added as its own section with a table of the newest file per product and year, which reconciles to the 160 figure (80 parquet + 80 sidecars). Two commits cover the set — |
And the GHG FBS too? |
Carries the review fixes from #874 up the stack. No conflicts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Not yet will do that after merging |
Top of the stack. Records the 7 September rebuild in the progress report, and summarises everything below it.
Every table was rebuilt from cleared artifacts on the methods in this stack. All eight years balance at
T11max |residual| 0.0 $M, 20 outer iterations, nothing skipped; Step 6 produced the quartet for all eight; Step 7 applied the redefinitions across the span; 160 files uploaded to GCS.What changed in the stack
Trade — the 1:m splits were weighted on the wrong thing
T007. A supply weight answers who produced it; an export split needs who exported it, and those differ by a factor of eight inside aerospace (engines export 83% of output, guided missiles 11%). Graded on two benchmark holdouts,T007misplaced 13.7% and 20.9% of family export dollars against published exports' 3.2% and 4.7%.33641Xbefore splitting.3399had 88% of its excess on339910jewelry at 2.93×, and an unguarded re-split dragged five leaves from within 9% of published to 1.50×.Value added and gross output
336414/33641Asee-saw: it agrees with BEA on the pair's combined output to 0.03% and moves 5.1bn between the two members, with QCEW payroll opposed in both halves. Both are now held.Margins
Tooling
stale_artifactscould not see a method change: nothing upstream moves, the cache key does not move, and a rerun silently returns the previous parquet. It found 10 stale artifacts before, 290 after.Impact on the result, against the previous build
What this column measures: the gross cell-by-cell difference — the sum of |new − old| over all 406 × 421 = 170,926 cells of the balanced Use SUT — divided by the previous build's grand total for the same cells. Two consequences worth stating: it is gross, not net, so offsetting moves add rather than cancel (the controls hold, so net is near zero by construction); and it counts each relocated dollar twice, once where it leaves and once where it arrives, so 762,736 $M at 2017 is roughly 381bn of value actually changing position. It also covers the whole table — value-added rows and final-demand columns included, not just the commodity-by-industry interior — which is why those are broken out.
The three middle columns are shares of that year's gross movement. The value-added share nearly doubles across the span — 28% at 2017 to 45% at 2024, which is 2,766,328 $M of the 2024 total. At the far end of the span nearly half of this column is the value-added reconciliation rather than the commodity-by-industry interior.
The growth with distance from the benchmark is the expected shape, not drift: 2017 is anchored, so only the trade re-splits and the aerospace conditioning reach it. Later years additionally carry the value-added reconciliation, whose gap against BEA's published series grows across the span. A rebuild that moved 2024 as little as 2017 would mean the new methods were doing nothing.
Cell-level, on the Use SUT: 16,068 cells move by more than $1M at 2017, rising to 33,290 at 2024, out of 170,926. Counting any non-zero movement the figure is far wider — 46,959 cells at 2017.
Named outcomes, 2017 against published:
MATCHcells 109 → 123,EXTRA2 → 0, Pearson excluding specials 0.976 → 0.989336111/336112: 0.31× and 1.52× → 1.01× both,MATCH336414gross operating surplus: −2,957 → +311 $M at 2022, −3,693 → −22 at 2024Source lineage for the Step 5-7 products
The rebuild exposed that these products carry no source lineage. They are written by bespoke savers rather than the FBS framework, so nothing populated
primary_source_meta, and the artifact check could not tell when their inputs moved — it answered "No stale cached artifacts" about balanced SUTs sitting on trade inputs rebuilt hours earlier. A silent pass on something that cannot be checked reads as a clean bill of health.Fixed for Steps 6 and 7.
source_lineage()inutils/metadatatakes the artifact names a saver read and returns their sidecars in the shapestale_artifacts._walk_sourcesalready follows. It is wired into both savers that know their inputs —save_mut()fromMutTables.sources, andsave_after_redef()from thebefore_inputsit already accepted and had only recorded as bare filenames. A rebuilt Step 5 product now invalidates Step 6, and a rebuilt Step 6 invalidates Step 7. A name with no readable sidecar is recorded as alineage_errorrather than dropped, for the same reason a silent pass is worse than a noisy flag.save_balance()cannot name its inputs: the seed comes fromfit_interior,derive_initial_Y_pur,derive_initial_value_addedandassemble_supply_seed, none of which report the artifacts they read, and each globs for its own newest file. Giving Step 5 real lineage means making those four report — a change across several modules rather than a saver edit, and not one to land inside a docs PR. It keeps the builder surface from #867 in the meantime, so a change to the assembly module still flags it; what it cannot see is an upstream FBS rebuild.Not retroactive: products already on disk keep the sidecars they were written with, so the lineage appears on the next build.
Which files on GCS correspond to this stack
Newest per product and year,
gs://cornerstone-default/. 80 parquet + 80 sidecars = the 160 files reported above. Two commits cover the set:d2e2112for Step 5 and the before-redefinitions quartet,4276083for the after-redefinitions quartet — both in this stack.Step 5 — balanced SUT —
gs://cornerstone-default/flowsa/BalancedSUT/Balanced_Detail_Supplyv0.3.0_d2e2112Balanced_Detail_Use_SUTv0.3.0_d2e2112Steps 6-7 — MUT quartet —
gs://cornerstone-default/flowsa/NowcastMUT/Nowcast_Detail_Import_after_redefv0.3.0_4276083Nowcast_Detail_Make_after_redefv0.3.0_4276083Nowcast_Detail_Margins_after_redefv0.3.0_4276083Nowcast_Detail_Use_after_redefv0.3.0_4276083Nowcast_Detail_Import_before_redefv0.3.0_d2e2112Nowcast_Detail_Make_before_redefv0.3.0_d2e2112Nowcast_Detail_Margins_before_redefv0.3.0_d2e2112Nowcast_Detail_Use_before_redefv0.3.0_d2e2112The bucket holds 248 data blobs in these two prefixes in total; the rows above are the newest per product and year, which is what the detail loaders resolve.
The comparison figures no longer have a threshold in them
The report was dominated by a statistic with no grounding: the share of cells landing within 1% of the published value. The 1% was a choice, and the report read as though it were a property of the data — two cells 0.9% and 1.1% apart were drawn in different colours and counted on opposite sides of a headline number.
Cells both sides populate are now coloured on one continuous ramp, green at no difference through to red at 100% or more, and each figure carries a median and a value-weighted relative difference in place of "accuracy".
The pair earns its keep immediately. Summary Use at 2024 has a median cell 22.0% off but only 6.7% of its dollars misplaced — the large cells are far better than the typical one, which no threshold count could show. Its old headline was "7.5% accuracy", which reads as catastrophic and says nothing; its old picture was near-uniform amber. It now shows a green interior with identifiable hot rows and columns.
Tolerancesurvives where a boundary is genuinely needed —check()has to answer pass or fail, so it keepsrtol/atoland theMATCH/PARTIALsplit. Nothing in the report depends on it any more.L*81/73/64/48/33), so the two ends separate by dE 45.3 under simulated deuteranopia, almost entirely from lightness. The anchors were searched, not picked: the green end is squeezed between white (ABSENT) and the blue ofEXTRA, which under tritanopia both sit near a light green. Best achievable worst-pair separation is dE 26.0 against the floor of 25 thatpalette_separationalready enforced — it passes with less headroom than the old palette, and the binding pair is white-against-green, the same one that bound the old one.All 30 committed figures re-rendered; every caption and both summary tables rewritten from the measured values, so they now reflect the 7 September rebuild rather than the older numbers they had been carrying.
git-lfsinstalled.gitattributeshad declined LFS on a measurement and named the condition for revisiting it: "if these figures start churning per-commit rather than per-milestone." That happened — 1.16 MB of incompressible blobs per re-render, twice in three days. All 42 committed PNGs are now pointers.This does not shrink the repo: blobs committed before the change stay in history, so it stops growing at this rate rather than getting smaller. Converting the history too would rewrite
mainand all ten branches in this stack, and is deliberately not done here. The nine committed.parquetfixtures are 3.1 MB — larger than the images — and are left as ordinary blobs, since they are static reference artifacts rather than regenerated output.Verification
T11= 0.0 $M; Step 6 quartet for 8/8; Step 7 for 8/8 — 32 + 64 + 64 = 160 files uploaded to GCSstale_artifactsV00300 × 814000is 0.0 in every year through Step 6, with compensation carrying the whole 18.7 → 27.4 bnCensus_USATradeFBA regenerated and the trade totals verified identical, so its staleness flag is true but benignblack,ruffandmypyclean;--check-palettepasses at dE 26.0 against its floor of 25mainby merge, not rebase. Main added four commits (the MECS energy wiring, the GHG fix for the hardcoded 2018 vintage, the v0.3.2 snapshot bump) and none of them touches a file this stack changes, so all ten merges were clean with nothing to resolve. Rebase is the wrong tool here: the stack still carries the pre-squash nowcast history that main holds as the single squashed commit for Add nowcasted SUTs and MUTs 2017-2024 and associated CS models and analysis #854, sogit rebasereplays 180 commits main already has and conflicts on August history rather than on anything in the stack.🤖 Generated with Claude Code