The runtime status snapshot now agrees with the display heartbeat, and current-status is republished when the display wakes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage 2 of the web plugin catalog, after #688.
- The display publishes a plugin runtime snapshot (plugin_runtime.py) to
the shared cache: per plugin loaded, lifecycle state, a short redacted
error summary, the version it loaded and when, plus published_at /
stale_after / running. Written on change (throttled to 10 s; the
RUNNING/ENABLED flip of an ordinary update is not a change) and once a
minute otherwise; cleanup() publishes running: false.
- The web reads it back and restores loaded / state / error_info in
/api/v3/plugins/installed (plus loaded_version, loaded_at and
data.runtime). Only a live snapshot counts; stale, stopped or missing
answers null and says which.
- data/plugin_state.json is retired: every reader and writer moved to
config + disk (desired) or the snapshot (observed). Nothing in it was
non-derivable, so nothing is migrated and an existing file is left
unread. The web-side PluginStateManager (state_manager.py) is removed;
the display's plugin_state.PluginStateManager is the only state machine.
- StateReconciliation compares config + disk with the snapshot, reporting
enabled-but-not-loaded and older-version-loaded as no_action findings.
- Backups list installed manifests with enabled from config.json.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>