feat(dialog): batch table deltas — append/update/remove without resending rows#152
Merged
Conversation
…ding rows
Large tables (10k+ rows) cost ~25 ms per full-state refresh (~1 MB JSON
round-trip); a live feed appending one row per event had no cheaper option
than resending the whole array. Add batch deltas (JSON-level, backward
compatible; no C ABI change):
- WidgetData::appendTableRows / updateTableCells / removeTableRows write a
per-widget table_delta {seq, append, update_cells, remove_rows}. seq is
plugin-owned; hosts apply a delta only when its seq differs from the last
applied (restart-safe, no wraparound edge), as update_cells -> remove_rows
-> append, all indexes addressing the pre-delta table. Ops of one refresh
share one seq — a differing seq starts a fresh delta, so stale ops can
never be relabeled. rows in the same refresh wins and consumes the delta.
- WidgetDataView::tableDelta() decodes strictly (a malformed op rejects the
whole delta — partial application would consume the seq while diverging
from the plugin's model) and normalizes remove_rows to descending unique;
tableDeltaSeq() is the cheap staleness pre-check.
- dialog-plugin-guide.md gains a "Large tables" section: the
omit-unchanged-fields pattern (every widget-data field is optional), the
efficiency ladder, and the delta contract. SDK-side only: hosts apply
table_delta from the companion PlotJuggler change onward; older hosts
ignore the key (harmless no-op).
Rides the 0.18.0 release together with the QDateTimeEdit event PR (#150);
CHANGELOG entries merge under one heading on whichever lands second.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 18, 2026
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.
Summary
A 10,000×6 table costs ~25 ms and ~1 MB of JSON per full-state refresh (measured; grows ~linearly), so live feeds (streaming fault lists, status boards) had no efficient way to change one row. This adds batch table deltas to the dialog protocol — JSON-level, backward compatible,
PJ_DIALOG_PROTOCOL_VERSIONunchanged:WidgetData::appendTableRows / updateTableCells / removeTableRows→ per-widgettable_delta{seq, append, update_cells, remove_rows}(+TableCellUpdate).UINT64_MAX"must increase" dead-end; a full-state rebuild carrying an old delta is harmless on all three delivery paths (key-diffing, byte-identical drop, diffing disabled). Ops of one refresh share one seq —tableDeltaEntrydiscards prior ops on a differing seq, so stale ops can never be relabeled (tested).rowsin the same refresh wins and consumes the delta.remove_rowsarrives normalized (descending, duplicate-free) so hosts can apply in vector order with no index-shift hazard.tableDeltaSeq()lets hosts check staleness before paying for the full decode.dialog-plugin-guide.mdgains a "Large tables" section: every widget-data field is optional (omit-unchanged is the primary pattern), the efficiency ladder, and the delta contract. Marked SDK-side only: hosts applytable_deltafrom the companion PlotJuggler change onward (queued next); older hosts ignore the key by design.Versioning
Rides 0.18.0 together with #150 (QDateTimeEdit events) — no version-file changes here to avoid a bump collision; CHANGELOG entries merge under the one
[0.18.0]heading on whichever PR lands second. Header-only additions, abidiff additions-only.Review trail (pipeline: codex → simplify → PR)
tableDeltaSeq(); altitude findings → unsourced-precision numbers softened, SDK-only status made explicit.Test plan
Round-trip + absent/malformed/normalization tests in
widget_data_test.cpp/widget_data_view_test.cpp; full SDK suite 49/49; pre-commit clean.🤖 Generated with Claude Code