From 6287acd591fde7db99a6a219b32bd0731dfe6089 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Fri, 7 Aug 2026 16:17:28 -0400 Subject: [PATCH] fix(vegas): stop capping plugin width by default (#445) * fix(vegas): stop capping plugin width by default Vegas plugins read as "cut off early" or "starting in the middle". That was the per-plugin width budget, not the scroll engine: overflow_mode=rotate is designed to resume mid-content on each appearance, so the symptom was the feature working as specified. Measured over a 17-plugin fleet on a 512px panel, the cap was a bad trade. Only four plugins were ever wide enough to hit the 3.0 default -- leaderboard 11,518px, news 10,021px, odds-ticker 4,643px, hockey 1,508px. Weather is 650px and flights 512px; the cap never touched them or the other eleven. So it bought nothing on thirteen plugins while costing two visible faults on four: content entering mid-item (a news ticker started at column 6027 of its own strip), and a final rotation window of whatever happened to be left -- 348px of an 1,840px stocks ticker, seven seconds of panel time. Default max_plugin_width_ratio to 0 (uncapped), so every plugin contributes all of its content and is always entered at its beginning. The cap remains available, and vegas_max_width_screens still caps an individual plugin -- which is where the knob belongs, since a genuinely long ticker is a property of that plugin rather than of the fleet. Verified on a live 512px device: 327 budget crops in the preceding six hours, none after. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Udr6MfaFLUPhX5Fgo67Jf5 * test(vegas): cover the width cap still working when asked for Defaulting the cap off must not quietly remove it. Asserts that an explicit ratio is honoured and validates, alongside the existing check that omitting it means uncapped. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Udr6MfaFLUPhX5Fgo67Jf5 --------- Co-authored-by: Claude Opus 5 (1M context) --- config/config.template.json | 2 +- docs/CONFIG_REFERENCE.md | 2 +- src/vegas_mode/config.py | 22 ++++++++++++++----- test/test_vegas_density.py | 14 ++++++++++++ .../templates/v3/partials/display.html | 4 ++-- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/config/config.template.json b/config/config.template.json index 433039f7..9edbec18 100644 --- a/config/config.template.json +++ b/config/config.template.json @@ -149,7 +149,7 @@ "min_plugin_width": 8, "lead_in_width": 0, "plugins_per_cycle": 6, - "max_plugin_width_ratio": 3.0, + "max_plugin_width_ratio": 0.0, "overflow_mode": "rotate", "dynamic_duration_enabled": true, "min_cycle_duration": 60, diff --git a/docs/CONFIG_REFERENCE.md b/docs/CONFIG_REFERENCE.md index a7bd81df..ff623439 100644 --- a/docs/CONFIG_REFERENCE.md +++ b/docs/CONFIG_REFERENCE.md @@ -127,7 +127,7 @@ Read by `src/vegas_mode/config.py` (`VegasScrollConfig.from_config`). See | `min_plugin_width` | int, `8` | | `lead_in_width` | int, `0` | | `plugins_per_cycle` | int, `6` | -| `max_plugin_width_ratio` | float, `3.0` | +| `max_plugin_width_ratio` | float, `0.0` | | `overflow_mode` | string, `"rotate"` | | `dynamic_duration_enabled` | bool, `true` | | `min_cycle_duration` | int, `60` | diff --git a/src/vegas_mode/config.py b/src/vegas_mode/config.py index 14786481..551da4d8 100644 --- a/src/vegas_mode/config.py +++ b/src/vegas_mode/config.py @@ -104,10 +104,22 @@ class VegasModeConfig: overflow_mode: str = "rotate" # Cap on one plugin's share of a cycle, as a multiple of display width. - # A single ticker returning 7,000px would otherwise hold the panel for over - # two minutes. Overflow is deferred to later cycles rather than discarded. - # 0 disables the cap. - max_plugin_width_ratio: float = 3.0 + # 0 (the default) disables the cap, so every plugin contributes all of its + # content and is always entered at its beginning. + # + # Capping was the default until it proved to cost more than it bought. + # Measured over a 17-plugin fleet on a 512px panel, only four plugins were + # ever wide enough to hit a 3.0 cap; for those four it produced two visible + # faults. Content resumed mid-item on each appearance (a news ticker entered + # at column 6027 of its own strip), and the final window of a rotation was + # whatever happened to be left — 348px of a 1840px stocks ticker, seven + # seconds of panel time. Both read as the display being broken rather than + # as deferral working. + # + # A wide plugin does hold the panel for a long time uncapped: set the cap + # per plugin with vegas_max_width_screens where that matters, rather than + # globally where it mostly hurts plugins that were never the problem. + max_plugin_width_ratio: float = 0.0 # Plugin management plugin_order: List[str] = field(default_factory=list) @@ -159,7 +171,7 @@ class VegasModeConfig: lead_in_width=int(vegas_config.get('lead_in_width', 0)), plugins_per_cycle=int(vegas_config.get('plugins_per_cycle', 6)), max_plugin_width_ratio=float( - vegas_config.get('max_plugin_width_ratio', 3.0)), + vegas_config.get('max_plugin_width_ratio', 0.0)), overflow_mode=str(vegas_config.get('overflow_mode', 'rotate')), plugin_order=list(vegas_config.get('plugin_order', [])), excluded_plugins=set(vegas_config.get('excluded_plugins', [])), diff --git a/test/test_vegas_density.py b/test/test_vegas_density.py index f0c1fd72..4fc2db12 100644 --- a/test/test_vegas_density.py +++ b/test/test_vegas_density.py @@ -781,6 +781,20 @@ class TestNewConfigKeys: assert cfg.render_width_pct == 100 assert cfg.min_content_separation == 24 + def test_width_cap_is_off_by_default(self): + # Capping made wide plugins resume mid-content on every appearance and + # emit runt final windows; it is now opt-in per plugin instead. + assert VegasModeConfig().max_plugin_width_ratio == 0.0 + assert VegasModeConfig.from_config({}).max_plugin_width_ratio == 0.0 + + def test_width_cap_is_still_available_when_asked_for(self): + # Defaulting the cap off must not remove it: a user who sets a ratio + # still gets one, and 0 still means uncapped. + cfg = VegasModeConfig.from_config( + {'display': {'vegas_scroll': {'max_plugin_width_ratio': 3.0}}}) + assert cfg.max_plugin_width_ratio == 3.0 + assert cfg.validate() == [] + @pytest.mark.parametrize('overrides,bad_key', [ ({'render_width_pct': 5}, 'render_width_pct'), ({'render_width_pct': 101}, 'render_width_pct'), diff --git a/web_interface/templates/v3/partials/display.html b/web_interface/templates/v3/partials/display.html index 2fa31027..1e2c423a 100644 --- a/web_interface/templates/v3/partials/display.html +++ b/web_interface/templates/v3/partials/display.html @@ -556,11 +556,11 @@
- +