fix(status): distinguish runtime-loaded plugins from installed inventory#97479
Conversation
/status plugins merged disk-scan plugin records with the active runtime registry, so the detailed Loaded: list could include plugins that were installed/config-enabled but never loaded at runtime. Record the runtime- loaded plugin ids on the health snapshot, carry them through the merge, and make Loaded: reflect runtime-confirmed plugins; show installed/discovered plugins that are not active as a neutral "Installed (not active)" inventory line rather than an error. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Build runtimeLoadedPluginIds from all live runtime registry surfaces via collectLivePluginRegistries() (active plus any pinned channel / http-route / session-extension registry) and render Loaded: from that id set directly, so a plugin live only through a pinned surface still counts as loaded instead of being dropped or misreported as "Installed (not active)". Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
Codex review: needs maintainer review before merge. Reviewed June 28, 2026, 8:11 AM ET / 12:11 UTC. Summary PR surface: Source +58, Tests +158. Total +216 across 5 files. Reproducibility: yes. from source inspection: current main marks enabled installed inventory as Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Next step before merge
Security Review detailsBest possible solution: Land the status-only provenance fix after ordinary maintainer review, keeping Do we have a high-confidence way to reproduce the issue? Yes, from source inspection: current main marks enabled installed inventory as Is this the best way to solve the issue? Yes, this appears to be the best fix shape: it records runtime provenance at the status snapshot boundary and reuses the existing live-registry surface set instead of changing installed inventory semantics or eagerly loading plugins. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 08d15ec32db3. Label changesLabel justifications:
Evidence reviewedPR surface: Source +58, Tests +158. Total +216 across 5 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
…ory (openclaw#97479) * fix(status): distinguish runtime-loaded plugins from installed inventory /status plugins merged disk-scan plugin records with the active runtime registry, so the detailed Loaded: list could include plugins that were installed/config-enabled but never loaded at runtime. Record the runtime- loaded plugin ids on the health snapshot, carry them through the merge, and make Loaded: reflect runtime-confirmed plugins; show installed/discovered plugins that are not active as a neutral "Installed (not active)" inventory line rather than an error. Co-Authored-By: Claude Opus 4.8 <[email protected]> * fix(status): include pinned runtime registries in loaded ids Build runtimeLoadedPluginIds from all live runtime registry surfaces via collectLivePluginRegistries() (active plus any pinned channel / http-route / session-extension registry) and render Loaded: from that id set directly, so a plugin live only through a pinned surface still counts as loaded instead of being dropped or misreported as "Installed (not active)". Co-Authored-By: Claude Opus 4.8 <[email protected]> --------- Co-authored-by: Claude Opus 4.8 <[email protected]>
…ory (openclaw#97479) * fix(status): distinguish runtime-loaded plugins from installed inventory /status plugins merged disk-scan plugin records with the active runtime registry, so the detailed Loaded: list could include plugins that were installed/config-enabled but never loaded at runtime. Record the runtime- loaded plugin ids on the health snapshot, carry them through the merge, and make Loaded: reflect runtime-confirmed plugins; show installed/discovered plugins that are not active as a neutral "Installed (not active)" inventory line rather than an error. Co-Authored-By: Claude Opus 4.8 <[email protected]> * fix(status): include pinned runtime registries in loaded ids Build runtimeLoadedPluginIds from all live runtime registry surfaces via collectLivePluginRegistries() (active plus any pinned channel / http-route / session-extension registry) and render Loaded: from that id set directly, so a plugin live only through a pinned surface still counts as loaded instead of being dropped or misreported as "Installed (not active)". Co-Authored-By: Claude Opus 4.8 <[email protected]> --------- Co-authored-by: Claude Opus 4.8 <[email protected]>
…ory (openclaw#97479) * fix(status): distinguish runtime-loaded plugins from installed inventory /status plugins merged disk-scan plugin records with the active runtime registry, so the detailed Loaded: list could include plugins that were installed/config-enabled but never loaded at runtime. Record the runtime- loaded plugin ids on the health snapshot, carry them through the merge, and make Loaded: reflect runtime-confirmed plugins; show installed/discovered plugins that are not active as a neutral "Installed (not active)" inventory line rather than an error. Co-Authored-By: Claude Opus 4.8 <[email protected]> * fix(status): include pinned runtime registries in loaded ids Build runtimeLoadedPluginIds from all live runtime registry surfaces via collectLivePluginRegistries() (active plus any pinned channel / http-route / session-extension registry) and render Loaded: from that id set directly, so a plugin live only through a pinned surface still counts as loaded instead of being dropped or misreported as "Installed (not active)". Co-Authored-By: Claude Opus 4.8 <[email protected]> --------- Co-authored-by: Claude Opus 4.8 <[email protected]>
…ory (openclaw#97479) * fix(status): distinguish runtime-loaded plugins from installed inventory /status plugins merged disk-scan plugin records with the active runtime registry, so the detailed Loaded: list could include plugins that were installed/config-enabled but never loaded at runtime. Record the runtime- loaded plugin ids on the health snapshot, carry them through the merge, and make Loaded: reflect runtime-confirmed plugins; show installed/discovered plugins that are not active as a neutral "Installed (not active)" inventory line rather than an error. Co-Authored-By: Claude Opus 4.8 <[email protected]> * fix(status): include pinned runtime registries in loaded ids Build runtimeLoadedPluginIds from all live runtime registry surfaces via collectLivePluginRegistries() (active plus any pinned channel / http-route / session-extension registry) and render Loaded: from that id set directly, so a plugin live only through a pinned surface still counts as loaded instead of being dropped or misreported as "Installed (not active)". Co-Authored-By: Claude Opus 4.8 <[email protected]> --------- Co-authored-by: Claude Opus 4.8 <[email protected]> (cherry picked from commit 949b1af)
…ory (openclaw#97479) * fix(status): distinguish runtime-loaded plugins from installed inventory /status plugins merged disk-scan plugin records with the active runtime registry, so the detailed Loaded: list could include plugins that were installed/config-enabled but never loaded at runtime. Record the runtime- loaded plugin ids on the health snapshot, carry them through the merge, and make Loaded: reflect runtime-confirmed plugins; show installed/discovered plugins that are not active as a neutral "Installed (not active)" inventory line rather than an error. Co-Authored-By: Claude Opus 4.8 <[email protected]> * fix(status): include pinned runtime registries in loaded ids Build runtimeLoadedPluginIds from all live runtime registry surfaces via collectLivePluginRegistries() (active plus any pinned channel / http-route / session-extension registry) and render Loaded: from that id set directly, so a plugin live only through a pinned surface still counts as loaded instead of being dropped or misreported as "Installed (not active)". Co-Authored-By: Claude Opus 4.8 <[email protected]> --------- Co-authored-by: Claude Opus 4.8 <[email protected]>
What Problem This Solves
/status pluginscould list disk-discovered / config-enabled plugins underLoaded:even whenthey were not present in any live runtime registry surface. The detailed view merges an
installed/disk-scan plugin report with the runtime registry, and the disk scan marks every
config-enabled discoverable plugin "loaded" from configuration alone — before any runtime load. So
a plugin that is installed and enabled in config but not actually running showed up under
Loaded:, misleadingly answering the operator question "are the plugins I configured actuallyrunning?"
Why This Change Was Made
The gateway intentionally loads only the plugins its startup plan requires, so
installed-but-not-running is a normal healthy state, not an error. This records the plugin ids
confirmed loaded across all live runtime registry surfaces — active plus any pinned
channel / http-route / session-extension registry (via the canonical
collectLivePluginRegistries()set) — and renders
Loaded:from that set directly. A plugin live only through a pinned surfacestill counts as loaded. Installed/discovered plugins that are not active are shown as a separate,
neutral
Installed (not active)inventory line. When a snapshot carries no runtime provenance (thecompact path), rendering falls back to the previous behavior. Observer/status only: no
repair/retry/reload/install, no config write, no startup or doctor behavior change, and no new
diagnostics or errors for inactive inventory.
User Impact
openclawoperators reading/status pluginsnow get a truthful split:Loaded:means"running in a live runtime registry," and installed-but-not-active plugins are listed separately as
inventory instead of being counted as loaded. Errors, disabled plugins, dependency issues, channel
failures, diagnostics, compatibility notices, and the compact status line are unchanged.
Evidence
Actual OpenClaw runtime / terminal proof — no mocked disk-scan or channel-resolution I/O.
On the final PR HEAD (
ae8289d), in an isolatedOPENCLAW_STATE_DIR, one real bundled plugin(
diffs) was enabled and loaded through the production plugin loader (loadOpenClawPlugins, realon-disk scan + activation). The real
/status pluginshandler (buildStatusPluginsReply→collectInstalledPluginHealthSnapshot→formatDetailedPluginHealth) then produced:diffsis genuinely runtime-loaded;memory-coreis installed/discovered (found by the real diskscan) but not active in any live runtime registry. The compact line stays
🔌 Plugins: OK, and noErrors:/Diagnostics:are emitted for the inactive inventory. Nothing was mocked — the diskscan and channel resolution ran for real.
Supporting (deterministic, same production collection path). Before vs after this change for an
installed-but-not-running plugin, via
collectInstalledPluginHealthSnapshoton the final HEAD:Tests (
src/status/status-plugin-health.test.ts,src/status/status-plugin-health.runtime.test.ts,src/plugins/active-runtime-registry.test.ts): runtime-loaded vs installed-not-active separation,the field-absent fallback, the installed+runtime merge, per-surface pinned-registry divergence
(channel / http-route / session-extension), cross-surface dedup, and the runtime-loaded-but-absent-
from-records render case. 25 status + 6 active-runtime-registry tests pass; typecheck (tsgo core +
core-tests) clean.
AI-assisted.