Recycle a pod link that goes mute, not only one born mute
A link can wedge *after* working. On the tablet, 2026-08-27: the − pod connected at 15:46:29, carried sixty presses, and at 15:47:19 stopped sending button frames altogether while still streaming battery every five seconds. The link was up, the pod was answering, and not one press arrived for the rest of the ride. The §7.1 detector could not see it. Its test was `buttons_this_link == 0` — a link that had ever carried a button was exempt, on the reasoning that a healthy pod proves itself once and should never be disturbed again. Exempt for life turned out to mean dead for the ride. So the clock runs from the last press rather than from the connect, and falls back to the connect for a link that never carried one. The cost of being wrong is unchanged and still real — a rider who genuinely has not shifted for NO_INPUT_AFTER loses shifting for the few seconds a reconnect takes — which is why the window stays longer than any climb's worth of steady pedalling. Automatic recovery is deliberately slow, because the supervisor cannot tell a wedged pod from a rider who is not shifting. The rider can, so the shifter tile's action while connected is now Reconnect: drop the link and take it again, immediately, instead of waiting out the window. Not the both-pods failure, which was the first suspicion and would have been the better story — connecting both is what stops the − pod reporting its own paddle. The log rules it out: one `pod connected`, for the − pod, and no redundant link ever closed. Every `plus` in it is the − pod relaying its twin's paddle over the mesh, which is the pair working as designed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
* strangers fold away into a collapsed list at the bottom.
|
||||
*/
|
||||
import { app } from '../lib/app.svelte';
|
||||
import { api } from '../lib/bridge';
|
||||
import { api, type Pod } from '../lib/bridge';
|
||||
import { connectionText, rssiBars } from '../lib/format';
|
||||
import type { DeviceInfo, DeviceKind } from '../lib/types';
|
||||
import ClickPanel from './ClickPanel.svelte';
|
||||
@@ -116,6 +116,12 @@
|
||||
* were a separate button the rider had failed to press would be a lie about
|
||||
* what the protocol does.
|
||||
*/
|
||||
/** Drop a pod's link and take it again — the fix for a wedged session. */
|
||||
async function reconnectPod(pod: Pod) {
|
||||
await api.disconnectController(pod);
|
||||
await api.connectController(pod);
|
||||
}
|
||||
|
||||
async function reacquire(id: string) {
|
||||
await api.disconnect(id);
|
||||
await api.connect(id);
|
||||
@@ -179,8 +185,13 @@
|
||||
.join(' · ')
|
||||
: 'Press a button to wake it — the keyboard works meanwhile',
|
||||
tone: live ? 'tone-ok' : 'tone-idle',
|
||||
// Connected, the useful action is *rebuild the link*. A Click can wedge
|
||||
// while looking perfectly healthy — battery arriving every five seconds,
|
||||
// every press ignored (§7.1) — and the supervisor's own recovery is
|
||||
// deliberately slow, because it cannot tell a wedged pod from a rider who
|
||||
// simply is not shifting. The rider can, instantly.
|
||||
action: live
|
||||
? null
|
||||
? { label: 'Reconnect', run: () => app.run(() => reconnectPod(live.pod)) }
|
||||
: { label: 'Find it', run: () => app.run(() => api.connectController()) },
|
||||
secondary: live
|
||||
? { label: 'Disconnect', run: () => app.run(() => api.disconnectController()) }
|
||||
|
||||
Reference in New Issue
Block a user