Repository navigation
perf(diff): skip summary stats for the compare grid's hidden columns - #312
Merged
Merged
Conversation
paddymul
force-pushed
the
feat/diff-parquet-view
branch
from
October 7, 2026 15:37
3f5c5f5 to
89095f7
Compare
…mns in Buckaroo's stats The compare grid is three to four times as wide as the entries it compares, and a third to a half of its columns are hidden: the before-value of each column, its equality sentinel, and membership. Buckaroo runs a batch aggregate and a histogram query for every one of them, and nothing reads a stat of any. These tests describe sending them as skip_stat_columns on the diff's /load_expr: - diff_skip_stat_columns(overrides) is exactly the hidden columns, sorted. A column that changed to an incomparable dtype (#68) keeps its before-value visible and is not in it, and neither is a key. - The diff route posts it as a list, over the file it hands Buckaroo, and changes no other field of the body. No visible column of the file is in it. - Over a real Buckaroo dataflow built from the posted body: no view draws a skipped column, every color_map rule reads the histogram of a column that keeps its stats, every view's display config is the same with and without the list, and the stat pipeline runs fewer queries with it on a cold stat cache while visible columns keep their histograms. All ten fail on this commit: the function does not exist and the body has no skip_stat_columns. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The diff's /load_expr now carries skip_stat_columns: the compare columns that the grid's overrides hide. Those are each column's before-value, its equality sentinel, membership, and the file's __row_order. Buckaroo ran a batch aggregate and a histogram query for every one of them, and nothing reads a stat of any: the key and equality colors read row values, the before-value tooltip reads a cell, and only the delta columns' min, max and histogram bins are read, by the display klasses and by color_map. Those are never hidden. diff_skip_stat_columns(overrides) reads the hidden set off the same overrides the grid is configured with, so the two cannot drift, and returns it sorted. A skipped column keeps its name, dtype and length. The display config is the same with and without the list, and no visible column is in it. Buckaroo honors the field in 0.15.9 and 0.15.10 alike. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
paddymul
force-pushed
the
feat/diff-skip-hidden-stats
branch
from
October 7, 2026 15:49
5dae01e to
4b73509
Compare
paddymul
marked this pull request as ready for review
October 7, 2026 16:29
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.
Stacked on #309. The base is
feat/diff-parquet-viewso the diff shows only this change; retarget tomainwhen #309 merges.Problem
Buckaroo runs a batch aggregate and one histogram query for every column of the grid it is handed. The compare grid is three to four times as wide as the entries it compares, and a third to a half of its columns are hidden: each column's before-value (
{col}), its equality sentinel ({col}_eq),membership, and the file's__row_order. Nothing reads a stat of any of them, but Buckaroo computes all of it. After #309 those queries run over a file and are cheap each, but there are still 56 of them on a 19-column pair and 138 on a 45-column pair. Under #304'sstats_delivery: "deferred"the first rows do not wait for them, and the grid's statistics do. They also occupy Buckaroo's single event loop while they run.plans/diff-performance-proposals.mdcalls this B1.Fix
The diff's
/load_exprbody gainsskip_stat_columns, the list of columns the grid's overrides hide.tallyman_companion.diff.diff_skip_stat_columns(overrides)returns the keys of the overrides whosemerge_ruleis"hidden", sorted. It reads the same dict the grid is configured with (view.column_config_overrides), so the hidden set and the skip set cannot drift apart. A column that changed to an incomparable dtype (diff stat path raises XorqTypeError when a shared-name column changed type across revisions (string→date) #68) keeps its before-value visible, side by side with the new one, so it is not in the list. Keys are never hidden._load_compare_viewinapp.pyadds the field to the body. Nothing else in the body changes.Why a hidden column's stats are never read:
color_categoricalreads the row value atval_column(the key color reads themembershipcell, the changed-value color reads the{col}_eqcell), and the simple tooltip reads the{col}cell. Both are cells, not stats. What the grid does read aremin,maxand the histogram bins of the delta columns (diff_extras/display/*.py, andcolor_mapreadshistogram_stats[val_column].histogram_bins), and the delta columns are never hidden.A skipped column keeps its name, dtype and length and gets no stat queries. Its
min,maxanddistinct_countare null, and it has nonull_count,mean,histogramor the rest. If a visible column were in the list it would lose its displayer (fare_amount_v2's 3-decimalfloatdisplayer drops toobj, checked by adding it to the list), which is why the function takes the hidden set and nothing else, and why a test checks it from the other side.Not in this PR: promoted diff entries (they load through the entry path, and their overrides are persisted and user-editable),
init_sdfrom the source entries' stats (B2), narrowing the compare to changed columns (B3), primary-key detection, splitting the route.What it saves
A throwaway project (
TALLYMAN_HOMEin a temp dir, nothing of mine read or written), synthetic data, 2,000,000 rows.tripsis 19 source columns (87 columns in the file, 36 skipped, 51 visible);parkingis 45 source columns (173 in the file, 90 skipped, 83 visible). The real route throughTestClient, a real Buckaroo 0.15.9 subprocess on a random port, a cold stat cache and a fresh Buckaroo process every open, the diff file already written. "Without" dropsskip_stat_columnsfrom the body before it is posted, which is #309's body. Six cold opens of each, in shuffled order, over three runs of the script./load_exprPOST withouttripsparkingThe whole route took 0.03 s longer than the POST in each case, since the file was already there. The ranges are the spread of the six opens. The machine was also running another job's tests during some of them.
Checks on the same runs, over the real WebSocket:
main,detailed_pct,detailed_absolute,summary) come back, and a page request for 300 rows returns without an error.tripsand 838 onparkingwere compared. All are identical excepthistogramcells (5 and 26). The same cells also differ between two runs that both have no skip, so that is run-to-run variation in those columns' histograms, not an effect of the list.The table above is buckaroo 0.15.9 with inline stats. After rebasing onto #309's rebased head, which is on
mainwith #304 (buckaroo 0.15.10,stats_delivery: "deferred"), I ran the same route and a WebSocket client that advertises?caps=stats_updateas the frontend does, on a fresh throwaway project of 2,000,000 rows by 20 columns, one run per pair. Without this PR (#309's rebased head) and with it:stats_updateafter connect, withoutSo on 0.15.10 the list does not move the first page. It brings the statistics in about twice as soon. A separate run on 0.15.10 (not repeated for this PR) found the list honored by the deferred second stage, by
/reload_expr, and by the cell-level stat cache (a full run after a skip run computes only the missing cells, a skip run after a full run computes none). It also measured the stretch where deferred stats occupy Buckaroo's single event loop: a second session's page request waited 7.8 s during a 45-column load without the list and 3.2 s with it.Relation to #304
#304 is on
mainand #309 is rebased onto it, so the body in_load_compare_viewnow carriesskip_stat_columns,data_idandstats_delivery: "deferred", and this branch is rebased onto #309 with no conflict. The skip list does not enter the cache identity: skipped columns send no queries, and the queries that remain are keyed bydata_idand the stat hash, sodata_iddoes not need to change.Verification
After the rebase onto #309's rebased head (
89095f7), local, macOS:uv run pytest: 1184 passed, 6 skipped, 1 failed. The failure istest_fouc.py::test_unknown_api_path_404s, which fails because this worktree has no builtpackages/app/dist, the same failure perf(diff): write the diff's join to a parquet file and hand Buckaroo a read of it #309 records; CI builds the app.uvx ruff check: clean.d7c6a09, checked out alone, fails the same 10 tests. One of them, the test that pins the other fields of the body, was amended in that commit for the rebase: the body now also carriesdata_idandstats_delivery.CI on the rebased head
4b73509(run 37647153416): ruff clean; fast suite 1189 passed, 2 skipped (vitest 15 passed); integration suite 7 passed, 1 skipped.Before the rebase, on #309's 0.15.9 base (TDD):
9b6f956(tests/test_diff_skip_stats.pyonly, 10 tests), run 37638467476: 10 failed, 1168 passed, 2 skipped. Three fail withImportError(nodiff_skip_stat_columns) and seven withKeyError: 'skip_stat_columns'or the body-fields assertion. Ruff passed.5dae01e, run 37641097890: ruff clean; fast suite 1178 passed, 2 skipped (vitest 15 passed); integration suite 7 passed, 1 skipped (the macOS-only Buckaroo crash test). Theperf reportworkflow does not run on a PR whose base is notmain.The tests: the list is exactly the hidden columns of a compare of two entries, sorted and without repeats, and excludes keys,
_v2, deltas and the before-value of a column whose dtype changed to an incomparable one; a key that changed dtype is never in it; the route posts it as a list for a worthy pair and a cheap pair, equal to the hidden columns of the posted overrides and disjoint from every visible column of the file; no other field of the body changed. Over a real Buckaroo dataflow built from the posted body: no view draws a skipped column and everycolor_maprule reads the histogram of a column that keeps its stats, every view's display config is identical with and without the list, and the stat pipeline runs fewer queries with it on a cold cache while visible columns keep their histograms and skipped ones keep their dtype and length. I checked that this guard bites by adding a delta column to the list: the route tests, the "no view draws a skipped column" test and the display-config test all failed.🤖 Generated with Claude Code