Skip to content

fix(watch): apply Transition payload in place — stop full-list redraws#31

Merged
jiunbae merged 1 commit into
mainfrom
fix/watch-per-row-update
May 5, 2026
Merged

fix(watch): apply Transition payload in place — stop full-list redraws#31
jiunbae merged 1 commit into
mainfrom
fix/watch-per-row-update

Conversation

@jiunbae
Copy link
Copy Markdown
Member

@jiunbae jiunbae commented May 5, 2026

Summary

User reported: STATE / LAST PROMPT in `muxa watch` appear to update for every row on every tick even when only one agent had an event. Asked if we could skip updates for rows without their own transition.

Yes — v0.5.0's subscribe was only used as a wake signal: each Transition triggered a fresh `client.snapshot()` and `apply_outcome` replaced the entire agent list. The single row that changed got the correct new value, but every other row was also rewritten with "current values" — visually indistinguishable from constant churn.

Fix

  • `RefreshOutcome` becomes an enum:
    • `Full(FullRefresh)` — periodic 5 s sync + priming wake (full list replace, existing behavior).
    • `SingleAgent(Agent)` — push delivery, carries just the post-transition payload.
  • `refresh_task`'s subscribe arm ships `Transition.agent` directly via `SingleAgent`, no snapshot fetch.
  • `apply_outcome` matches on the variant. `apply_single_agent` finds the row by `(kind, session_id)` and replaces only that one; appends if unknown; no re-sort (sort runs on the next `Full` tick so the table doesn't "jump" on every push).

Push deliveries no longer pay the snapshot RPC + tmux pane re-fetch round-trip. Other rows keep their prior bytes.

Test plan

  • `cargo test --workspace` — 425 → 427 (+2 new)
  • `cargo clippy --workspace --all-targets -- -D warnings` — clean (one targeted `large_enum_variant` allow on the enum)
  • `cargo fmt --all -- --check` — clean
  • Live: open `muxa watch`, drive activity in one Claude pane, confirm only that row's columns visually change between ticks while other rows stay static.

🤖 Generated with Claude Code

User-reported: STATE / LAST PROMPT columns appear to "update for
every row" on every tick, even though only one agent had a real
transition. Asked: can we skip the update for rows that didn't have
an event?

Yes — the v0.5.0 subscribe stream was being treated as a wake
signal only. Every Transition triggered a fresh `client.snapshot()`
and `apply_outcome` replaced the whole agent list. Even when only
one row's data actually changed, every row was rewritten with
"current values" — visually indistinguishable from constant churn.

Restructure:

- `RefreshOutcome` becomes an enum:
    - `Full(FullRefresh)` — periodic fallback (5 s) and priming wake;
      replaces the whole list (existing behavior, isolated path).
    - `SingleAgent(Agent)` — push delivery; carries just the
      transitioned agent's post-transition payload.
- `refresh_task`'s subscribe arm ships `Transition.agent` directly
  via `SingleAgent` instead of falling through to `fetch().await`.
- `apply_outcome` matches on the variant. The new
  `apply_single_agent` finds the row by `(kind, session_id)` and
  replaces only that one; appends if unknown. No re-sort on push so
  the table doesn't visually "jump" — sort happens in the periodic
  Full tick.

Performance: push deliveries no longer pay the round-trip cost of a
snapshot RPC + tmux pane re-fetch. Only the matching row's bytes
change. The fallback Full tick still keeps everything else fresh.

Tests: 2 new — `single_agent_outcome_only_updates_matching_row` and
`single_agent_outcome_appends_unknown_row`. Existing tests that
constructed `RefreshOutcome` directly were updated to use
`RefreshOutcome::Full(FullRefresh { … })`. Workspace 425 → 427 pass.
clippy clean (with one targeted `large_enum_variant` allow on the
enum — boxing the Full variant would add an allocation per tick for
no real-world benefit). fmt clean.

No version bump.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jiunbae jiunbae merged commit bac6b15 into main May 5, 2026
6 checks passed
@jiunbae jiunbae deleted the fix/watch-per-row-update branch May 5, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant