perf(watch): re-sort on push + skip redundant idle redraws#55
Merged
Conversation
Two fixes for the "watch updates a beat late" / wasted-CPU behaviour. 1. Re-sort on push. A streaming `SingleAgent` transition updated the row in place but never re-sorted, so the ordering only refreshed on the 5 s `Full` fallback tick. With `sort = ["state", …]` — where the sort key is itself a pushed field — the state badge changed instantly while the row stayed put for up to 5 s. `apply_outcome` now calls `resort_rows_preserving_selection` after a push. The merge is surgical and `sort_by` is stable, so only the changed row moves (no "all rows jumped" jitter), and selection is pinned by pane_id so the cursor stays on the same agent. 2. Dirty-gated rendering. The run loop repainted unconditionally once per input-poll tick (~62 fps) even on a fully idle UI. It now repaints only when something changed (input, a refresh outcome, a preview recapture) or the 1 s idle cadence elapses — the cadence keeps the Activity column's second-granularity `relative_time` current without the constant full re-render. Adds a unit test asserting a pushed Error transition reorders a state-sorted list immediately. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Problem
muxa watchfelt like it updated "a beat late" (한 박자 늦게), especially withsort = ["state", "latest"].Root cause: a streaming
SingleAgenttransition updates the row in place but the loop never re-sorts on a push — ordering only refreshes on the 5 sFullfallback tick (STREAMING_FALLBACK_INTERVAL). When the sort key is a pushed field (state), the badge changed instantly but the row's position lagged up to 5 s.Separately, the run loop repainted unconditionally every input-poll tick (~62 fps) even on a fully idle UI — wasted CPU.
Changes
apply_outcomenow callsresort_rows_preserving_selection()after applying aSingleAgent. The merge is surgical andsort_byis stable, so only the changed row moves (no "all rows jumped" jitter); selection is pinned bypane_idso the cursor stays on the same agent. State-sorted views now reflect transitions immediately.relative_timecurrent without the constant full re-render.Notes / ruled out
Store::apply(no debounce), so a pushed state change reaches the stream in ms; the lag was entirely client-side sort staleness.Test
push_resorts_rows_so_a_state_change_moves_immediately.cargo fmt --all -- --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test -p muxa-cliall green (151 watch unit + 8 e2e).🤖 Generated with Claude Code