BLE connection/sync redundancy, derivation concurrency, platform-standards compliance - #44
Merged
Merged
Conversation
…-standards compliance BLE reliability (connection ladder + sync integrity): - Timeout discoverServices()/setNotifyValue() so a wedged BLE stack can't hang the connect chain forever and jam the whole reconnect ladder above it - FrameCorruptionDetector: CRC-failure-rate detector, independent of the existing timeout-based MarginalRadioDetector (catches a radio that responds promptly but wrong, not just one that stops responding) - Band-truth reconciliation: track expectedPacketCount mismatch streaks over time instead of only logging once - CounterRegressionDetector: explicit, observable band-reboot signal, seeded from the durable counter_hw cursor across reconnects - Periodic RTC re-verification on long-lived connections (previously only checked once at connect) - isCorruptFutureRtc: sanity-check GET_DATA_RANGE's range_newest before it can poison the session's plausibility window - Real per-chunk sync_ledger (ChunkFailureLedger) + wired sync_quarantine read/write — a token failing ACK repeatedly across reconnects is now tracked and quarantined instead of silently overwriting one shared row - Activated schemaHealth() (real PRAGMA integrity_check) at startup + on the foreground cadence — was fully implemented but never called - Removed dead, unwired, untested Whoop5EmptyOffloadTracker - HeadlessSyncGate skip-streak telemetry (per-owner + lifetime counters) - Cross-platform staleness escalation: local notification at 48h+ silence, quiet in-app tier at 12h, wired into both the headless and foreground cadence paths - Android OEM autostart deep links (Xiaomi/Huawei/Honor/Oppo/Vivo/OnePlus), gated behind ActivityManager.isBackgroundRestricted() (the one official documented signal) rather than firing on manufacturer-string match alone - iOS force-quit explainer tied to the staleness notification - Per-checkpoint diagnostic logging in commitSyncBatch (decoded/archive/ cursor phases) via a failure-safe optional callback, atomicity unchanged - Notification permission requests now respect platform docs: background/ headless code paths only check (never request) authorization, since an interactive prompt requires a foreground scene the OS won't grant one to from a background execution context Derivation engine concurrency (single-threaded backlog sweeps were the biggest contributor to "results aren't ready when the app opens"): - runWithConcurrency: bounded worker-pool primitive replacing three identical fully-sequential per-day for-loops (run/runDays/rescanRecent). A multi-day backlog used to process one day's isolate work fully before starting the next, leaving every core but one idle; days within a run are independent (frozen baseline snapshot, day_id-keyed writes) so this is genuinely safe to parallelize - Newest-first day ordering — a backlog sweep used to compute the oldest pending day first and today dead last, backwards from what the user actually wants on open - Per-day-local prepare-stats accumulator so concurrent days don't race on shared diagnostic counters (telemetry-only; never a correctness issue for the derived values themselves) All changes verified against official Android/Apple documentation (not community folklore) where platform behavior was load-bearing. 434 Dart tests green (62 new), zero new analyzer issues, Android debug APK and iOS debug build both verified.
…sets frameworks The Watch app's Info.plist carries a literal WKCompanionAppBundleIdentifier that must exactly match the phone app's bundle id. Every free-account resigner (Sideloadly, AltStore) mints its own unique per-user bundle id without patching that unrelated nested plist key, so the Watch companion fails install for every sideloaded user under every resigner. Drop it from the unsigned CI artifact only; source builds via Xcode/flutter run keep full Watch support with a consistent signing identity. Also adds a "Re-sign ad-hoc native-assets frameworks" build phase: Dart's native-assets pipeline copies compiled frameworks into the app bundle via Flutter's own script rather than Xcode's auto-signing Copy Files mechanism, so they can end up ad-hoc-signed instead of matching the app's real signing identity, which fails code-signing validation on-device. Runs after both Embed Frameworks and CP Embed Pods Frameworks, re-signs only frameworks actually detected as ad-hoc via codesign -dv, and is a verified no-op when code signing isn't active (confirmed in a local --no-codesign build log).
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
BLE reliability — closes gaps found in a full audit of the reconnect/sync ladder (connection timeouts, corruption detection, band-reboot signal, per-chunk sync ledger + quarantine, staleness escalation notification, activated
schemaHealth()) and verifies the implementation against official Android/Apple documentation rather than community folklore (notably: gated the OEM-autostart deep link behindActivityManager.isBackgroundRestricted(), and made notification-permission requests respect the platform rule that authorization must come from a foreground context, never a headless one).Derivation engine concurrency — the real fix for "results aren't ready when the app opens." Backlog sweeps (
run/runDays/rescanRecent) were fully sequential single-threaded for-loops that also computed the oldest pending day first and today last. Replaced with a bounded worker-pool (runWithConcurrency) that runs multiple independent days' isolate work genuinely in parallel across cores, plus newest-first ordering so today lands first.CI/Xcode (teammate's changes, included in this PR): strips the Watch companion from the unsigned sideload IPA (its
WKCompanionAppBundleIdentifiercan't survive a per-user resign under any sideloading tool), and adds a build phase to re-sign ad-hoc-signed native-assets frameworks — verified as a no-op under--no-codesignvia an actual build log.Test plan
flutter test --concurrency=1— 434/434 green (62 new tests)flutter analyze— 11 pre-existing issues only, zero newflutter build apk --debug— cleanflutter build ios --debug --no-codesign— clean, including after the Xcode project change (verified the new re-sign build phase correctly no-ops via verbose build log)