Skip to content

fix(vegas): restore live plugin-update refresh dropped by sync refactor#395

Merged
ChuckBuilds merged 1 commit into
mainfrom
fix/vegas-live-refresh
Jul 12, 2026
Merged

fix(vegas): restore live plugin-update refresh dropped by sync refactor#395
ChuckBuilds merged 1 commit into
mainfrom
fix/vegas-live-refresh

Conversation

@ChuckBuilds

@ChuckBuilds ChuckBuilds commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Summary

Investigating a user report that Vegas scroll mode doesn't update scores or
game status.

Root cause: PR #299
(Mar 28, "refresh scroll buffer on live score updates") added a mechanism so
a live score change reached the ticker within a few seconds instead of
waiting for a full scroll cycle:

  • _tick_plugin_updates_for_vegas() in display_controller.py diffed
    plugin_last_update timestamps to detect which plugins got fresh data on
    each tick, and called coordinator.mark_plugin_updated() for each.
  • render_pipeline.should_recompose() checked
    stream_manager.has_pending_updates_for_visible_segments() to trigger an
    immediate hot-swap.

PR #330 (May 14,
multi-display wireless sync) refactored both call sites while adding sync
support, and silently deleted this entire mechanism — not gated behind
the new sync-mode deferral it legitimately needed, but removed outright.

Result: VegasModeCoordinator.mark_plugin_updated() and
StreamManager.has_pending_updates_for_visible_segments() are both still
fully implemented and correct — just orphaned, called from nowhere, for the
past ~2.5 months. Vegas mode's only remaining freshness sources are a 5s
content cache TTL (fine, imperceptible) and a full recompose at cycle
boundaries, which depending on min_cycle_duration/max_cycle_duration can
be minutes away. So a live score genuinely can sit stale on screen far
longer than a "live" ticker should — matching the reported symptom exactly.

Fix

Test plan

  • Added test_display_controller_vegas_tick.py and
    test_vegas_render_pipeline_recompose.pyneither area had any prior
    test coverage
    , which is very likely why this regression went unnoticed
    for two and a half months.
  • Verified both new test files fail against the pre-fix code (swapped in
    the current main versions of both touched files) with exactly the
    expected errors — AttributeError for the deleted method, and the
    recompose assertion returning False instead of True — then pass
    against the fix.
  • Confirmed the sync-mode deferral this restoration must not break still
    holds: test_sync_active_defers_pending_updates_to_cycle_boundary.
  • Full related suite (test_vegas_plugin_adapter, test_vegas_config,
    test_display_controller_plugin_toggle,
    test_display_controller_optimizations, test_plugin_system): 108
    passed, 1 pre-existing failure unrelated to this change
    (test_circuit_breaker, stale mock signature — same one already
    documented in prior PRs' test plans).
  • Full CI plugin-safety suite (test_harness, test_visual_rendering,
    test_plugin_matrix): 52 passed, 2 pre-existing skips.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Vegas mode now responds more quickly when plugins receive fresh data.
    • Visible plugin updates are applied promptly in standalone Vegas mode instead of waiting for the next full cycle.
    • Update handling remains stable when Vegas coordination is unavailable or encounters an error.
  • Tests

    • Added regression coverage for plugin update notifications and live Vegas recomposition behavior.

Investigating a user report that Vegas scroll mode doesn't update scores
or game status. Root cause: PR #299 (Mar 28) added a mechanism so a live
score change reached the ticker within a few seconds instead of waiting
for a full scroll cycle -- _tick_plugin_updates_for_vegas() diffed
plugin_last_update timestamps to detect which plugins got fresh data and
called coordinator.mark_plugin_updated() for each, and should_recompose()
checked has_pending_updates_for_visible_segments() to trigger an immediate
hot-swap.

PR #330 (May 14, multi-display wireless sync) refactored both call sites
while adding sync support and silently deleted this entire mechanism --
not just gated it behind the new sync-mode deferral it legitimately
needed, but removed it outright. The result: VegasModeCoordinator.
mark_plugin_updated() and StreamManager.has_pending_updates_for_visible_
segments() have been fully implemented but never called from anywhere
since. Vegas mode's only remaining freshness sources are a 5s content
cache TTL (fine) and full recompose at cycle boundaries, which depending
on min/max_cycle_duration can be minutes away -- so live scores/status
can sit stale far longer than a user would expect from a "live" ticker.

Fix:
- Restored _tick_plugin_updates_for_vegas() in display_controller.py,
  wired as the Vegas coordinator's update callback in place of the plain
  _tick_plugin_updates(). Diffs plugin_last_update before/after the tick
  and calls vegas_coordinator.mark_plugin_updated(plugin_id) for each
  plugin that actually got new data (rather than returning the list, since
  the callback interface no longer consumes a return value).
- Restored the has_pending_updates_for_visible_segments() check in
  render_pipeline.should_recompose(), positioned after (not instead of)
  the sync-mode early return PR #330 added, so standalone installations
  regain immediate refresh while synced leader/follower pairs correctly
  keep deferring hot-swaps to cycle boundaries as PR #330 intended.

Test plan:
- Added test_display_controller_vegas_tick.py and
  test_vegas_render_pipeline_recompose.py -- neither area had any prior
  test coverage, which is very likely why this regression went unnoticed
  for ~2.5 months.
- Verified both new test files fail against the pre-fix code (swapped in
  the current main versions of both files) with exactly the expected
  errors -- AttributeError for the deleted method, and the recompose
  assertion returning False instead of True -- then pass against the fix.
- Confirmed the sync-mode deferral this restoration must not break still
  holds: test_sync_active_defers_pending_updates_to_cycle_boundary.
- Full related suite (test_vegas_plugin_adapter, test_vegas_config,
  test_display_controller_plugin_toggle, test_display_controller_
  optimizations, test_plugin_system): 108 passed, 1 pre-existing failure
  unrelated to this change (test_circuit_breaker, stale mock signature).
- Full CI plugin-safety suite (test_harness, test_visual_rendering,
  test_plugin_matrix): 52 passed, 2 pre-existing skips.
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Vegas plugin update ticks now notify the coordinator when plugin timestamps advance. Standalone rendering also recomposes when visible segments have pending updates, while synchronized rendering preserves cycle-based recomposition behavior. Regression tests cover both paths and their edge cases.

Changes

Vegas update flow

Layer / File(s) Summary
Plugin freshness notifications
src/display_controller.py, test/test_display_controller_vegas_tick.py
Vegas uses a freshness-aware plugin tick that notifies the coordinator only for plugins updated during the tick, while handling missing coordinators and notification exceptions.
Visible segment recomposition
src/vegas_mode/render_pipeline.py, test/test_vegas_render_pipeline_recompose.py
Standalone mode recomposes when visible segments have pending updates; synchronized mode continues deferring those updates until cycle completion, with regression coverage.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: restoring Vegas live plugin-update refresh behavior after the sync refactor.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/vegas-live-refresh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 5 complexity · 0 duplication

Metric Results
Complexity 5
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
src/display_controller.py (1)

834-868: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the return annotation and narrow the exception boundary.

The new method lacks a -> None return annotation, and except Exception can silently suppress unrelated programming errors from mark_plugin_updated(). Keep per-plugin isolation, but catch only documented recoverable exceptions, including the RuntimeError intentionally covered by the test.

As per coding guidelines, Python code must use type hints and catch specific exceptions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/display_controller.py` around lines 834 - 868, Add the -> None return
annotation to _tick_plugin_updates_for_vegas. Preserve per-plugin isolation
while replacing the broad Exception handler around
vc.mark_plugin_updated(plugin_id) with only the documented recoverable
exceptions, including RuntimeError covered by the test.

Source: Coding guidelines

test/test_display_controller_vegas_tick.py (2)

19-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Annotate the new test helper.

Add parameter and return annotations to _make_controller() so the dynamically constructed controller and timestamp mapping have an explicit contract.

As per coding guidelines, Python functions should use type hints for parameters and return values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/test_display_controller_vegas_tick.py` around lines 19 - 24, Update the
_make_controller test helper with explicit type annotations for
plugin_last_update, vegas_coordinator, and its returned DisplayController, using
the project’s existing timestamp and coordinator types where available. Preserve
the helper’s current construction and initialization behavior.

Source: Coding guidelines


27-76: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a regression test for callback wiring.

These tests call _tick_plugin_updates_for_vegas() directly, so Line 508 could regress back to _tick_plugin_updates while every test here still passes. Add a focused test with a fake coordinator asserting that set_update_callback() receives the Vegas-aware bound method.

The PR objective explicitly includes restoring the coordinator callback wiring.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/test_display_controller_vegas_tick.py` around lines 27 - 76, Add a
focused regression test for the controller’s coordinator callback wiring, using
a fake coordinator to capture set_update_callback and asserting it receives the
Vegas-aware bound method _tick_plugin_updates_for_vegas rather than
_tick_plugin_updates. Keep the test independent of direct invocation tests and
verify the callback is registered during controller setup.
test/test_vegas_render_pipeline_recompose.py (2)

25-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Annotate the new test helper.

Add parameter and return annotations to _make_pipeline() to make its test fixture contract explicit.

As per coding guidelines, Python functions should use type hints for parameters and return values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/test_vegas_render_pipeline_recompose.py` around lines 25 - 30, Update
the test helper _make_pipeline to add a type annotation for its optional
sync_manager parameter and an explicit return annotation describing the returned
pipeline and stream_manager tuple, preserving its existing behavior.

Source: Coding guidelines


25-30: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover the production-shaped standalone sync state.

All standalone cases use sync_manager=None, but production creates a standalone DisplaySyncManager. Add a test with an inactive/standalone manager (or equivalent fake) so a mistaken is not None check cannot suppress standalone recomposition while these tests remain green.

The supplied controller context creates a sync manager even for standalone deployments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/test_vegas_render_pipeline_recompose.py` around lines 25 - 30, Extend
_make_pipeline or add a focused test to construct the standalone pipeline with
an inactive DisplaySyncManager instead of sync_manager=None. Exercise the
standalone recomposition path and assert recomposition still occurs, ensuring
the implementation does not rely on a non-None manager to distinguish
synchronized deployments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/display_controller.py`:
- Around line 847-861: Update the plugin update flow around DisplayController’s
plugin_last_update snapshot and _tick_plugin_updates call to use a new locked
PluginManager helper that atomically snapshots prior timestamps, performs the
update, computes changed plugin IDs, and returns them. Ensure all reads,
mutations, and iteration of plugin_last_update occur under the same lock, then
use the helper’s returned IDs for the Vegas notification path.

---

Nitpick comments:
In `@src/display_controller.py`:
- Around line 834-868: Add the -> None return annotation to
_tick_plugin_updates_for_vegas. Preserve per-plugin isolation while replacing
the broad Exception handler around vc.mark_plugin_updated(plugin_id) with only
the documented recoverable exceptions, including RuntimeError covered by the
test.

In `@test/test_display_controller_vegas_tick.py`:
- Around line 19-24: Update the _make_controller test helper with explicit type
annotations for plugin_last_update, vegas_coordinator, and its returned
DisplayController, using the project’s existing timestamp and coordinator types
where available. Preserve the helper’s current construction and initialization
behavior.
- Around line 27-76: Add a focused regression test for the controller’s
coordinator callback wiring, using a fake coordinator to capture
set_update_callback and asserting it receives the Vegas-aware bound method
_tick_plugin_updates_for_vegas rather than _tick_plugin_updates. Keep the test
independent of direct invocation tests and verify the callback is registered
during controller setup.

In `@test/test_vegas_render_pipeline_recompose.py`:
- Around line 25-30: Update the test helper _make_pipeline to add a type
annotation for its optional sync_manager parameter and an explicit return
annotation describing the returned pipeline and stream_manager tuple, preserving
its existing behavior.
- Around line 25-30: Extend _make_pipeline or add a focused test to construct
the standalone pipeline with an inactive DisplaySyncManager instead of
sync_manager=None. Exercise the standalone recomposition path and assert
recomposition still occurs, ensuring the implementation does not rely on a
non-None manager to distinguish synchronized deployments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 11685edd-a606-4d1f-b292-94a14654b3be

📥 Commits

Reviewing files that changed from the base of the PR and between 05e7c43 and e4c7c8c.

📒 Files selected for processing (4)
  • src/display_controller.py
  • src/vegas_mode/render_pipeline.py
  • test/test_display_controller_vegas_tick.py
  • test/test_vegas_render_pipeline_recompose.py

Comment thread src/display_controller.py
@ChuckBuilds ChuckBuilds merged commit 6052a60 into main Jul 12, 2026
10 checks passed
@ChuckBuilds ChuckBuilds deleted the fix/vegas-live-refresh branch July 12, 2026 14:52
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