Root cause of the CI app-test hang was a pre-existing bleQueue<->collectionsQueue
lock inversion driven by the periodic maintenance timer (performMaintenance ->
drainAllPendingWrites takes collectionsQueue while another path holds it and
sync-waits on bleQueue via readLinkState). The timer is created unconditionally
in init, so it also ran in the unit-test process (initializeBluetoothManagers:
false), where it only churns BLE writes/notifications/announces that don't exist.
Recent timing changes made the latent deadlock surface reliably.
- Only start the maintenance timer when real CoreBluetooth managers were
initialized (maintenanceTimerEnabled). Production behavior is unchanged; the
unit-test process no longer runs the timer and cannot hit the inversion.
Also fix BLEServiceCoreTests.duplicatePacket_isDeduped, which sent an unsigned
public packet that the new signature requirement (security fix#2) correctly
drops. The test now signs the packet and preseeds the sender's signing key
(production sendMessage signs public broadcasts), exercising the dedup path
(security fix#7) end to end. _test_handlePacket gains an optional
signingPublicKey to seed the registry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
EOSE callbacks parked while Tor is bootstrapping now get a fallback
unblock at the standard 10s EOSE timeout (via the injected scheduler,
generation-guarded, single-fire) instead of waiting up to ~225s for
Tor-readiness retry exhaustion. The identity swap in
refreshPeerIdentity runs inside a messageQueue barrier with re-entrancy
guard, so a panic reset can no longer race in-flight packet builds
(deadlock analysis documented; both call paths verified off-queue).
Relay send-queue overflow drops now log a sampled warning.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Refactor BLE transport event handling
* Make image output paths unique
* Keep queued Nostr read receipts alive
* Refine BLE ingress fanout
* Rediscover BLE service after invalidation
* Extract BLE notification retry buffer
* Extract BLE inbound write buffer
* Extract BLE fragment assembly buffer
* Tidy secure log handling from device run
* Allow self-authored RSR ingress replies
* Harden read receipt queue test timing
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Expand protocol coverage with edge-case tests
* Stabilize read receipt transport test
* Stabilize BLE duplicate packet test
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Expand coverage for relay, identity, and location flows
* Fix macOS SwiftPM CI failures
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Add comprehensive test coverage for ChatViewModel and BLEService
This commit adds 14 new tests to improve the safety net for future
refactoring of ChatViewModel and BLEService:
New test files:
- ChatViewModelTorTests: Tor lifecycle notification handlers (8 tests)
- ChatViewModelDeliveryStatusTests: Delivery status state machine (6 tests)
- ChatViewModelRefactoringTests: Command routing and message handling (4 tests)
- BLEServiceCoreTests: Packet deduplication and stale broadcast filtering (2 tests)
- PublicMessagePipelineTests: Message ordering and deduplication (4 tests)
- MessageRouterTests: Transport selection and outbox behavior (4 tests)
- PrivateChatManagerTests: Chat selection and read receipts (2 tests)
- UnifiedPeerServiceTests: Fingerprint resolution and blocking (2 tests)
- RelayControllerTests: TTL, handshake, and fragment relay logic (4 tests)
Modified files:
- MockTransport: Added peer snapshot publishing on connect/disconnect
- TestHelpers: Added waitUntil polling helper for async tests
- MockIdentityManager: Extended for new test scenarios
Total: 454 tests across 64 suites (was 440)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix flaky test by using waitUntil instead of fixed sleep
Replace fixed 200ms sleep with waitUntil helper for more reliable
async assertion in routing tests. This prevents timing issues on CI.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>