From 4b9fc3c755b3cc2c0aefa2c6dc5dfd1bad41c9e6 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Mon, 5 Oct 2026 17:18:36 -0400 Subject: [PATCH] fix(display): a failed on-demand request drops the session it ended _set_on_demand_error ends any running session (_reset_on_demand_fields) but left its saved copy, display_on_demand_config, in the cache. A failed request that replaced a running session therefore made the next restart resume the session that had already ended. Clear the saved copy where every error path goes through, and drop the two restore-failed callers' own clears, which this now covers. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 7 +++++++ src/display_controller.py | 10 +++++++--- test/test_on_demand_disabled_plugin.py | 9 +++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f729e9e..01630b51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,13 @@ accepts both, but the store flags the old spelling as deprecated ## Unreleased +### Fixes + +- A failed on-demand request no longer comes back after a restart as the + session it ended. A failed request ends any running session, but the + saved copy of that session (`display_on_demand_config`) was left behind, + so the next restart of the display resumed it. + ## 3.8.2 The display hands freed memory back to the OS (#774), and sports consolidation diff --git a/src/display_controller.py b/src/display_controller.py index 44a70f84..4eea649c 100644 --- a/src/display_controller.py +++ b/src/display_controller.py @@ -668,7 +668,6 @@ class DisplayController: except Exception: # pylint: disable=broad-except cached_session = None if self.on_demand_active or cached_session: - self.cache_manager.clear_cache('display_on_demand_config') self._set_on_demand_error('restore-failed') # Its state machine no longer describes what runs; let the last # snapshot go stale (readers then say unknown) rather than keep @@ -1817,8 +1816,14 @@ class DisplayController: logger.error("Failed to publish on-demand state: %s", err, exc_info=True) def _set_on_demand_error(self, message: str) -> None: - """Set on-demand state to error and publish.""" + """Set on-demand state to error and publish. + + Ends any running session, so its saved copy goes too: a failed + request that replaced a session left display_on_demand_config + behind, and the next restart resumed the session that had ended. + """ self._reset_on_demand_fields() + self.cache_manager.clear_cache('display_on_demand_config') self.on_demand_status = 'error' self.on_demand_last_error = message self.on_demand_last_event = None @@ -2756,7 +2761,6 @@ class DisplayController: logger.error("On-demand session for plugin '%s' cannot resume after the " "restart: the plugin has no loaded display modes (did it " "fail to load?); ending it", plugin_id) - self.cache_manager.clear_cache('display_on_demand_config') self._set_on_demand_error('restore-failed') return diff --git a/test/test_on_demand_disabled_plugin.py b/test/test_on_demand_disabled_plugin.py index a7c52f80..b148a057 100644 --- a/test/test_on_demand_disabled_plugin.py +++ b/test/test_on_demand_disabled_plugin.py @@ -217,6 +217,15 @@ class TestReleasingThePlugin: assert controller.current_display_mode == 'clock' assert controller.force_change is True + def test_a_failed_request_that_ends_the_session_drops_its_saved_copy(self, controller): + """Otherwise the next restart resumes the session that just ended.""" + _start(controller, plugin_id='clock') + controller.cache_manager.clear_cache.reset_mock() + + _start(controller, plugin_id='uninstalled') + + controller.cache_manager.clear_cache.assert_called_once_with('display_on_demand_config') + def test_a_plugin_enabled_during_the_session_stays_loaded(self, controller): _start(controller) controller.test_config['preview-me'] = {'enabled': True}