A pod that was connected, reporting battery every five seconds, and sending no button frames at all cost most of an evening. The cause was not in the decode: it was that the previous run never let go of the link. `Actor::teardown` unsubscribed every notifying characteristic before disconnecting, each under its own two-second timeout. A Click carries five of them, so the exit path could spend ten seconds on optional work against a supervisor budget of three. The supervisor gave up first, the process exited, and `disconnect` was never reached — leaving BlueZ holding the pod with no application running. The next connect inherited that half-dead session, and a half-dead session streams battery and no buttons, which reads exactly like broken hardware. Measured directly: both apps stopped, `bluetoothctl devices Connected` still listing the pod. It also explains the connect failures that came with it — `le-connection-abort-by-local`, then `service discovery timed out` — and why the fault came and went, since it depended on whether the last exit happened to time out. Nothing is lost by dropping the unsubscribes. The link going down clears the peripheral's CCCDs anyway, so they were only ever politeness toward a connection about to be destroyed. The heart rate actor had the same shape with one characteristic instead of five; the trainer's safety writes stay, because SAF-2 is not optional. All three now say what a timed-out disconnect costs. The old message named the symptom and not the consequence, and the consequence lands on the *next* run — which is precisely why this hid for so long. Also logs which pod reported which button. A pod reporting a button that belongs to the other one is invisible downstream, because the input carries the button and never its source. Fixes both platforms at once: this is `crates/ble`, and Android is the worse case — a leaked link there survives the app being swiped away. Verified with four connect/disconnect cycles against the `−` pod: every button registers on its documented bit (D-pad 0-3, paddle 8), and BlueZ holds nothing afterwards. That satisfies TASK-0(d) and retires RISK-9. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>