diff --git a/src-tauri/src/controller.rs b/src-tauri/src/controller.rs
index b496f1d..d8e9408 100644
--- a/src-tauri/src/controller.rs
+++ b/src-tauri/src/controller.rs
@@ -646,10 +646,36 @@ async fn run(
};
match cmd {
Cmd::Connect { pod, address } => {
+ // The rule `Cmd::Seen` has always enforced, applied
+ // here too: with the `−` pod up there is nothing for a
+ // `+` link to add and one specific thing for it to
+ // break — connected as a pair, the `−` pod stops
+ // reporting its own paddle (§2.3.1).
+ //
+ // Only the scan-driven path was guarded, so an explicit
+ // request walked straight past it. Housekeeping then
+ // closed the redundant link a second or so later, which
+ // reads as the app handling it and is not the same
+ // thing at all: on the tablet, 2026-08-27 15:55:39, the
+ // pair was joined for 1.4 s and the `−` pod did not
+ // report a press again for the rest of the session.
+ //
+ // `auto` is still armed below, so the fallback stands:
+ // the moment the `−` pod goes away, the `+` pod is
+ // taken on its next advertisement.
+ let minus_up = !minus.idle();
let slot = slot_mut(&mut minus, &mut plus, pod);
// Asking for it by hand re-arms auto-connect, whatever
// came before.
slot.auto = true;
+ if pod == PodId::Plus && minus_up {
+ tracing::info!(
+ "controller: refusing a + pod link while the − pod is up — \
+ it relays the pair, and joining both stops it reporting \
+ its own paddle"
+ );
+ continue;
+ }
// A second click while a search is running means
// "connect", which is what is already happening.
if slot.connecting() {
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 1d4dc3c..b94d860 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "BikeControl",
- "version": "0.2.4",
+ "version": "0.2.5",
"identifier": "paris.tourolle.bikecontrol",
"build": {
"frontendDist": "../ui/dist",
@@ -43,7 +43,7 @@
],
"category": "Utility",
"android": {
- "versionCode": 1204
+ "versionCode": 1205
},
"shortDescription": "Indoor cycling trainer control",
"longDescription": "Control a smart trainer over BLE, ride gradient profiles and synthetic waveforms, and record the result."
diff --git a/ui/src/components/ClickPanel.svelte b/ui/src/components/ClickPanel.svelte
index c939335..d97e2ed 100644
--- a/ui/src/components/ClickPanel.svelte
+++ b/ui/src/components/ClickPanel.svelte
@@ -158,10 +158,15 @@
{:else if pod.state === 'searching'}
+ {:else if dormant}
+
+ Held in reserve
{:else}
-
+
{/if}
@@ -353,6 +358,12 @@
font-size: 0.82rem;
}
+ .held {
+ align-self: center;
+ font-size: 0.8rem;
+ color: var(--ink-faint);
+ }
+
.note {
flex: 1 1 100%;
margin: 0;