fix(gui): keep the diagnostics report truthful across agent restarts#230
Conversation
- Read the agent status from the live AgentLink instead of a never- cleared copy: a report copied while the agent is down now says "not connected" instead of replaying the last snapshot, and AppState stops retaining a second AgentStatus alongside AgentLink::Ready. - Gate the diagnostics inventory snapshot on InventoryHealth::Ready — the same gate the device-list merge uses — so a report copied during the reconnect window keeps the receivers and transports the UI is still showing instead of an empty pre-enumeration list. - Surface enumeration health as an "Inventory:" line in the App section so zero-device reports are self-explaining.
Greptile SummaryThis PR fixes two staleness bugs in the Copy Diagnostics feature that surfaced after the agent-restart rework: agent status is now read from the live
Confidence Score: 5/5Safe to merge — the changes are narrowly scoped to diagnostic snapshot collection and do not touch device control, IPC command dispatch, or any UI render path. Both halves of the fix (live agent status read and gated inventory snapshot) follow the same consistency rule already used by refresh_inventories. The two updated state writes happen in the same update_global closure so device_list and last_inventory cannot diverge. Test coverage was extended to all four InventoryState / connectivity combinations. The removed last_status field had no other consumers, and agent_status() was already the correct source for all render-path reads. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant Poll as IPC Poll loop
participant State as AppState
participant Diag as diagnostics::collect()
participant Report as DiagnosticsReport
Note over Poll,State: Agent restart / reconnect window
Poll->>State: GuiUpdate::Unreachable
State->>State: set_agent_link(Unreachable)
Poll->>State: "GuiUpdate::Ready { inventory: Scanning }"
State->>State: "set_agent_link(Ready(status{Scanning}))"
Note right of State: ready=false → skip refresh_inventories, skip store_inventory_snapshot
Poll->>State: "GuiUpdate::Ready { inventory: Ready }"
State->>State: refresh_inventories() → device_list updated
State->>State: store_inventory_snapshot() → last_inventory updated
Note over Diag,Report: User copies diagnostics (at any point)
Diag->>State: agent_status() [live AgentLink]
State-->>Diag: "None (Unreachable) OR AgentStatus{inventory}"
Diag->>State: last_inventory() [gated snapshot]
State-->>Diag: last completed enumeration
Diag->>Report: "AppInfo{agent, inventory: None/Scanning/Ready/Unavailable}"
Diag->>Report: receivers + devices from gated snapshot
Reviews (1): Last reviewed commit: "fix(gui): keep the diagnostics report tr..." | Re-trigger Greptile |
Follow-up to #206. The Copy Diagnostics feature was written before the startup-states rework (#213/#215) landed, and the rebase kept its original snapshot plumbing. Two of those seams could make a report disagree with reality exactly when users are most likely to file one — right after an agent restart.
Changes
Read the agent status from the live
AgentLinkinstead of a never-cleared copy.AppState.last_statuswas retained on every poll and never invalidated, whileAgentLinkalready carries the fullAgentStatusand flips toUnreachableon disconnect. A report copied while the agent was down would claimAgent: v… (connected)from the stale copy — misleading for exactly the "agent is unresponsive" class of bug report. The adapter now readsAppState::agent_status()(backed byAgentLink), and the duplicate field is gone.Gate the inventory snapshot on
InventoryHealth::Ready. The device-list merge already ignores pre-enumeration snapshots (an agent restart serves an empty list for the 1.5–5 s enumeration window), but the diagnostics snapshot was stored unconditionally. A report copied in that window lost its Receivers section and all per-device enrichment (codename, wpid, model-ids, transports — Connection degraded tounknown) while the UI still showed everything, because the visible list is protected by the gate. The snapshot now shares it, so report and UI follow the same staleness rule.Surface enumeration health in the report. New
Inventory: ready / scanning (first enumeration in progress) / ⚠️ unavailable (enumeration failed — see agent log)line in the App section, so a zero-device report is self-explaining.Testing
app()fixture pinsInventory: ready, the unreachable-agent test pins the—placeholder, and a new test covers the scanning/unavailable wording (9 tests total).cargo test -p openlogi-core,cargo clippy -p openlogi-gui -p openlogi-core --all-targets(zero warnings), andcargo fmt --checkall pass locally; full-workspace clippy ran via the pre-push hook.