Periphery 3.7.4 audit of both schemes (macOS + iOS, intersected so
platform-specific code is never touched), with test targets indexed and
the share extension built. 277 dead declarations removed or demoted:
dead forwarding wrappers (ChatViewModel+Nostr/+PrivateChat), removed-
feature remnants (autocomplete command suggestions, back-swipe tuning,
MediaSendError, GeohashParticipantTracker), unused Tor dormancy
bindings, assign-only properties, unused parameters (renamed to _), and
redundant public accessibility. 13 orphaned localization keys deleted
across all 29 locales (old pre-#1392 location-notes UI, app_info
warnings).
Two real tests were flagged as unused because they never ran: Swift
Testing methods missing @Test (NostrProtocolTests.
testAckRoundTripNIP44V2_Delivered, NotificationStreamAssemblerTests.
testAssemblesCompressedLargeFrame). Re-armed both; they pass.
Deliberately kept, now recorded in .periphery.baseline.json: iOS-only
code invisible to the CI macOS scan, C FFI signatures, keep-alive
NWPathMonitor reference, InboundEventKey.eventID (dedup semantics),
wifiBulk capability bit (reserved for Wi-Fi bulk work, used by
BitFoundation package tests), and the String secureClear cluster
(exercised by package tests).
New: .periphery.yml config and an advisory Dead Code CI job (mirrors
the SwiftLint precedent from #1361) that fails on findings not in the
committed baseline.
Verified: full macOS app suite, BitFoundation (119) and BitLogger (13)
package tests green; periphery scan --strict exits clean.
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Originate v2 source routes and wire fragmentIdFilter targeted resync
Part A — source-route origination policy:
- Gate route application (BLESourceRouteOriginationPolicy): only packets we
author, directed at a single peer, with TTL headroom, whose recipient is
not directly connected. Relays no longer attach routes to (and re-sign)
packets they merely forward.
- Version-gate paths: MeshTopologyTracker records the highest protocol
version observed per peer; BFS routes require every intermediate hop and
the recipient to be v2-observed, capped at 4 intermediate hops.
- Degrade on failure: BLESourceRouteFailureCache marks a routed send that
sees no inbound traffic from the recipient within 10s as failed and floods
for 60s before retrying routes.
Part B — REQUEST_SYNC fragmentIdFilter (TLV 0x06):
- Requester: BLEFragmentAssemblyBuffer reports stalled broadcast
reassemblies (no new fragment for 5s, retried at most every 10s); the
maintenance pass sends a types=fragment REQUEST_SYNC naming the stalled
8-byte fragment stream IDs to each connected peer.
- Responder: GossipSyncManager restricts the fragment diff to exactly the
named streams, bypassing the since-cursor while the GCS filter still
excludes pieces the requester holds; RSR/TTL-0/rate-limit semantics
unchanged and REQUEST_SYNC stays link-local.
- Bounds: at most 60 IDs per request (60*17-1 = 1019 bytes <= the 1024-byte
decoder cap); oversized 0x06 values are ignored, not fatal.
Docs: SOURCE_ROUTING.md gains the iOS origination policy (§8);
REQUEST_SYNC_MANAGER.md documents 0x05/0x06 as implemented.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Fix stall-clock refresh on duplicates and overflow suppression in fragment resync
Two fixes to stalledBroadcastFragmentIDs bookkeeping in
BLEFragmentAssemblyBuffer:
- Duplicate fragments no longer reset the stall clock. Fragment packets
bypass the packet deduplicator, so relayed duplicates of an
already-held index arriving every few seconds kept lastFragmentAt
fresh and suppressed the targeted REQUEST_SYNC indefinitely. Now
lastFragmentAt only updates when the index is new (actual progress).
- Only the streams that will actually be encoded on the wire are
rate-limited. Previously every stalled candidate got
lastResyncRequestAt set, but encodeFragmentIdFilter serializes at most
RequestSyncPacket.maxFragmentIdFilterCount (60) IDs, so overflow
streams were suppressed for retryAfter without ever being requested.
Selection now caps at that shared constant, oldest stall first, so
overflow stays eligible and rotates fairly on the next pass.
Tests: duplicates arriving periodically still trigger the stall report;
70 stalled streams yield the 60 oldest on the first pass and the
remaining 10 on the next.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
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>