Summary
The dataflow cascade for a quick_command_args change (search / filter) runs _summary_sd to recompute summary stats for the new filtered frame. Even when the user re-types a search term they've used before — and summary_stats_cache already holds the exact entry for that filt-scope chain — _summary_sd still runs the full _get_summary_sd pipeline. On xorq backends that's ~300ms per state_change of pure waste. On polars/pandas it's smaller but still nonzero.
A prior version of _summary_sd did a cache lookup against summary_stats_cache keyed on the filt-scope chain hash, but it was removed (see history of buckaroo/dataflow/dataflow.py) because of a cascade-ordering issue: _summary_sd fires on processed_result change, which happens during self.cleaned = result — BEFORE the parent _operation_result reaches self.operations = result[3]. So self.operations still holds the prior state's filt chain at lookup time, and the cache returned the prior state's entry mislabelled as the new state's stats.
Reproduction
Run any buckaroo widget against a non-trivial dataset, do a state_change cycle that re-uses a previously-computed filter (e.g. type "abc", clear, type "abc" again). Observe via the buckaroo.dataflow.cache_timing log channel that _summary_sd compute=NNNms fires both times even though the cache entry from the first run is still present (visible as populate: filt HIT key=...).
Measured cost on the boston-restaurant xorq build: ~330ms _summary_sd compute on warm cache, contributing ~half of the ~700ms total state_change latency.
Scope
Widget AND server — buckaroo/dataflow/dataflow.py is shared between jupyter widgets and the server's ServerDataflow / XorqDataflow / PolarsServerDataflow.
Impact
- Search latency on warm caches is ~2× what it could be.
- The cache_timing log channel makes the wasted work obvious; users who turn on instrumentation will see the gap.
- The cascade-ordering issue that originally blocked the fix is itself a latent footgun (any future cache lookup on
self.operations during _summary_sd will hit the same trap).
Summary
The dataflow cascade for a
quick_command_argschange (search / filter) runs_summary_sdto recompute summary stats for the new filtered frame. Even when the user re-types a search term they've used before — andsummary_stats_cachealready holds the exact entry for that filt-scope chain —_summary_sdstill runs the full_get_summary_sdpipeline. On xorq backends that's ~300ms per state_change of pure waste. On polars/pandas it's smaller but still nonzero.A prior version of
_summary_sddid a cache lookup againstsummary_stats_cachekeyed on the filt-scope chain hash, but it was removed (see history ofbuckaroo/dataflow/dataflow.py) because of a cascade-ordering issue:_summary_sdfires onprocessed_resultchange, which happens duringself.cleaned = result— BEFORE the parent_operation_resultreachesself.operations = result[3]. Soself.operationsstill holds the prior state's filt chain at lookup time, and the cache returned the prior state's entry mislabelled as the new state's stats.Reproduction
Run any buckaroo widget against a non-trivial dataset, do a state_change cycle that re-uses a previously-computed filter (e.g. type "abc", clear, type "abc" again). Observe via the
buckaroo.dataflow.cache_timinglog channel that_summary_sd compute=NNNmsfires both times even though the cache entry from the first run is still present (visible aspopulate: filt HIT key=...).Measured cost on the boston-restaurant xorq build: ~330ms
_summary_sd computeon warm cache, contributing ~half of the ~700ms total state_change latency.Scope
Widget AND server —
buckaroo/dataflow/dataflow.pyis shared between jupyter widgets and the server'sServerDataflow/XorqDataflow/PolarsServerDataflow.Impact
self.operationsduring_summary_sdwill hit the same trap).