Skip to content

fix(ble): retry a refused pairing scan in seconds, not minutes - #1109

Merged
cryptskii merged 2 commits into
mainfrom
cryptskii/eager-darwin-1668e4
Oct 3, 2026
Merged

cryptskii merged 2 commits into
mainfrom
cryptskii/eager-darwin-1668e4

Conversation

@cryptskii

Copy link
Copy Markdown
Collaborator

Summary

Bluetooth pairing after adding a contact could take a minute or two.

Cause: in the scanner role, start_ble_discovery counted the start as successful whenever advertising started, even when the scan itself was refused. Scans get refused by Android's 5-starts-per-30 s limit, or by BleCoordinator's 6 s gap between scans. The attempt then sat in WaitingForConnection waiting on a scan that never ran. Nothing retried until the 90 s stale window passed, plus up to 30 s more for the pairing loop to look again.

Fix (bluetooth/pairing_orchestrator.rs):

  • In the scanner role, a refused scan is now a failed start. After 7 s (past the 6 s scan gap), after_discovery_start → discovery_refused marks an attempt still waiting for its first connection as Failed and wakes the loop, so it starts again at once.
  • stale_after_secs: an attempt waiting for its first connection goes stale after 20 s. A handshake already under way keeps 90 s.
  • The pairing loop wakes every 10 s (was 30 s).
  • The retry logic is host-compiled and tested. Only the one-line call from the JNI spawn is Android-only.

Testing

  • pairing_orchestrator tests: 11 pass, 3 of them new
    • stale windows per state, and the loop's wake interval
    • a refused scan frees only an attempt still waiting (not one reading identity, and no session is created)
    • a started discovery leaves the attempt alone; a refused one frees it after the retry delay
  • clippy -D warnings (dsm_sdk --all-targets); real_code_guard.py; ci/no_clock_and_no_json.sh
  • Android-target compile: not available here (the local NDK has no sysroot). The Android-only change is the single call above.

Notes

  • android_ble_bridge::tests::pairing_smoke_* fail when run on their own ("Storage base directory not set"). They fail the same way on main, a different one each run, and pass in the full suite. Not touched here.
  • Code-map pins are repinned in a follow-up commit once the map and evidence run.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y4wDTToHmJfkYYJvMKXt3u


Generated by Claude Code

claude added 2 commits October 3, 2026 01:47
The scanner role counted a pairing start as begun whenever advertising
started, even when the scan itself was refused (Android's 5-per-30 s
limit, or the coordinator's 6 s gap between scans). The attempt then sat
in WaitingForConnection on a scan that never ran until the 90 s stale
window passed, plus up to 30 s for the loop to look again: up to two
minutes before a retry.

- A refused scan is now a failed start: after 7 s (past the scan gap) the
  attempt is marked failed and the loop woken, so it starts again at once.
- An attempt still waiting for its first connection goes stale after 20 s;
  a handshake under way keeps 90 s.
- The pairing loop looks again every 10 s instead of 30 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4wDTToHmJfkYYJvMKXt3u
Code-only moves. Map built at d39cf96; the evidence each pin names ran
at that tree: 36 dsm and 35 dsm_sdk tests, all passing.
make requirement-map-intent INTENT_BUILT=android,node: 635 PINNED,
0 failing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4wDTToHmJfkYYJvMKXt3u
@cryptskii
cryptskii merged commit e1b1339 into main Oct 3, 2026
27 checks passed
@cryptskii
cryptskii deleted the cryptskii/eager-darwin-1668e4 branch October 3, 2026 02:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants