fix: hotplug-driven inventory and phantom device-card suppression#346
Conversation
Greptile SummaryThis PR replaces the pure 2 s polling inventory watcher with a hotplug-driven design (using
Confidence Score: 5/5Safe to merge; all three subsystems (hotplug watcher, first-sighting confirmation, phantom-card suppression) are guarded by dedicated unit tests and the changes degrade gracefully when hotplug is unavailable. The hotplug stream initialisation is correctly placed inside rt.block_on(), fixing the thread-kill risk raised in the previous thread. The plan_reapply logic handles every edge case (offline during followup, wake + first sighting, replug under a new route) with matching test assertions. Receiver-absent filtering and wire-PID dedup in append_offline_known are symmetric in their lowercasing and correctly interact with the existing key-based dedup. No new unsafe code, no new IPC surface, no migrations. No files require special attention; inventory.rs has the most surface area (new async select loop) but the fallback-to-polling path and stream-end detection are both tested or exercised by the existing WatchState tests. Important Files Changed
Reviews (5): Last reviewed commit: "Merge branch 'master' into fix/device-li..." | Re-trigger Greptile |
Only one `futures-lite` (2.6.1) remains in the tree, so cargo canonicalizes the `openlogi-agent-core` dependency reference to the unqualified name. The qualified form landed via AprilNEA#346's merge and every `cargo` run rewrites it, dirtying the tree; commit the canonical form so `--locked` builds are stable.
… the whole receiver (#251) Wrap each Bolt slot's HID++ feature walk in a 1 s BOLT_SLOT_PROBE timeout, mirroring the existing UNIFYING_SLOT_PROBE guard. Without it, one online device that stops answering its feature reads burns the whole receiver's PROBE_BUDGET, so probe_one times out and the receiver yields nothing — every paired device drops to "No devices" even though its pairing-register identity read fine. A timed-out slot now falls back to its cached / identity data while the rest of the receiver still enumerates. Further hardens the #218 scenario beyond the short-transient recovery from #222/#237. Also canonicalizes a stale futures-lite lockfile entry left by #346's merge so cargo no longer rewrites Cargo.lock on every run.
Context
Stale device cards pile up when the same models are used at two locations (work + home G513 / MX Master 3S), and a just-plugged keyboard waits seconds for its configured lighting. Root causes: persisted
known_identitiesresurrect unreachable devices as placeholders with model-key dedup defeated by the flaky extended-model byte (0b034vs2b034, #271/#280), and the inventory watcher is a pure 2 s poll — the "async-hid has no listener API" rationale predates async-hid 0.5'swatch().Demo
cargo test --workspacepasses; clippy/fmt clean.Changes
hotplug.rs,transport.rs(openlogi-hid)watchers/inventory.rsorchestrator.rsstate/devices.rsNotes