Seiten · Health Debug
The Five Known Divergences (iOS vs Android parity)
Document: docs/plan/02-platform-divergences.md
Status: Planning only — no implementation. UI design is being finalized separately; all visual details below are subject to that work and are flagged PENDING DESIGN where relevant.
Reference: The legacy togo-based codebase at github.com/fadymondy/health-debug is reference only. Nothing in it is ported as-is; the new build is greenfield.
Purpose
The legacy Health Debug apps drifted apart: five features exist (or work) on one mobile platform but not the other. This document records those five known divergences exactly as observed, the legacy-era fix for each, and — more importantly — why the greenfield architecture eliminates this entire class of problem by design. In the new build, every divergence collapses into "implement the presentation layer for platform X against an API contract that already exists," and each one is closed by a specific execution phase (Phase 4 = native Apple suite, Phase 5 = native Android suite).
1. Divergence summary table
| # | Divergence | iOS (legacy) | Android (legacy) | Legacy-era fix | Phase that closes it (new build) |
|---|---|---|---|---|---|
| 1 | Meds & Cycle Tracking | Missing from iOS code | Working | Port logic to Swift native app via API | Phase 4 (native Apple suite) |
| 2 | Light/Dark Mode | Working | Code written but untested | Test and activate on Android devices | Phase 5 (native Android suite) |
| 3 | Notification Center | Working | Missing | Build notification infrastructure in Kotlin | Phase 5 (native Android suite) |
| 4 | AI Integration | Working (Apple Intelligence) | Missing | Integrate the API-key proxy system into Android | Phase 5 (native Android suite) |
| 5 | Widgets / Watch / Car | Working | Missing | Develop Android Wear, Android Auto, and widgets for parity | Phase 5 (native Android suite) |
Known caveats (both platforms, legacy state)
- Android: splash and onboarding screens compile but are untested on physical devices.
- iOS: profile and onboarding fixes are merged but pending QA.
Both caveats are carried into planning as QA debt markers only — in the greenfield build these screens are rebuilt anyway (PENDING DESIGN: their new layouts come from the separate Figma/design track).
2. Divergence details
2.1 Meds & Cycle Tracking — missing on iOS, working on Android
Legacy state. The medication and cycle-tracking features work on Android but are entirely missing from the iOS code. This is the only one of the five divergences where Android is ahead of iOS.
Legacy-era fix. Port the logic to the Swift native app via the API.
Why this matters most. This divergence touches three of the eight Protocol Engines:
| Engine | Rule (spec) |
|---|---|
| Medication Grace (Engine 5) | 60-minute flexible window to log medications |
| Cycle Engine / Fertility (Engine 6) | Requires 3 consecutive logged cycles before predicting; fails safe on irregularity |
| Contraceptive Security (Engine 7) | Differentiates daily pills, monthly injections, implants |
In the legacy world, "porting" these meant re-implementing state-machine behavior in Swift — exactly the kind of duplicated business logic that caused the drift in the first place.
Greenfield resolution. All three engines are backend state machines in the ToGO API (built in Phase 1). The iOS app never re-implements the 60-minute grace window, the 3-cycle prediction gate, or the contraceptive-type differentiation — it only renders engine state returned by the API and submits log events. Per the architectural rule, clients NEVER compute or hardcode protocol business logic locally.
Closed by: Phase 4 — the native Swift app (iOS, plus watchOS/macOS/CarPlay/Widgets surfaces) implements the meds/cycle screens against the already-live API. PENDING DESIGN: the meds and cycle-tracking screen layouts.
2.2 Light/Dark Mode — working on iOS, written-but-untested on Android
Legacy state. Theming works on iOS. The Android theming code was written but never tested; its actual behavior on devices is unknown.
Legacy-era fix. Test and activate the existing code on Android devices.
Greenfield resolution. The theme system is specified once — the strict color spec below — and Phase 2 builds the theme/i18n engine for the React web dashboard, establishing the canonical token set that every native client then mirrors:
| Token | Dark Mode | Light Mode |
|---|---|---|
| Background | #1A1A1A charcoal | #FFFFFF |
| Active timers | #00FF33 neon green glow | #20A060 saturated teal |
| Active buttons | #00CCFF cyan | #0070A0 deep cyan blue |
| Alerts | #FF3333 red | (not defined in spec — genuinely undefined; needs a design decision) |
| Effect style | Glowing effects | Flat colors |
Note: the light-mode alert color and the exact mapping of #20A060 / #0070A0 to individual components are not fully defined in the current spec — do not invent them; they resolve in the design track (PENDING DESIGN). The theme engine must also satisfy the i18n rules (full RTL support for Arabic, including mirrored progress bars and layout; ICU Message Format; no string concatenation), since theme and layout direction are rendered together.
Closed by: Phase 5 — the native Kotlin app implements light/dark theming from the shared token spec, with physical-device testing as an explicit exit criterion (directly addressing the legacy "compiles but untested" failure mode).
2.3 Notification Center — working on iOS, missing on Android
Legacy state. iOS has a working notification center; Android has none.
Legacy-era fix. Build the notification infrastructure in Kotlin.
Greenfield resolution. Smart alerts are a core platform feature ("smart alerts across all devices"). In the new architecture, what to notify and when is decided server-side by the Protocol Engines (e.g., Hydration cooldowns, the Caffeine Block's 90-minute post-wakeup rule, the 4-hour GERD pre-sleep window, the Medication Grace window). The Android client's job is delivery and presentation only. That reduces the Android gap from "re-invent an alerting brain in Kotlin" to "build the Kotlin delivery/rendering layer for alerts the API already emits."
The transport mechanism on Android (e.g., push service choice, local scheduling fallback) is not defined in the current spec and must be decided during Phase 1 API-contract design so both platforms consume the same alert contract. PENDING DESIGN: notification center UI, alert grouping, and in-app inbox presentation.
Closed by: Phase 5 — Kotlin notification infrastructure for Android, WearOS, Android Auto, and ChromeOS surfaces.
2.4 AI Integration — working on iOS (Apple Intelligence), missing on Android
Legacy state. iOS has working AI integration via Apple Intelligence; Android has none.
Legacy-era fix. Integrate the API-key proxy system into Android.
Greenfield resolution. The BYOK (Bring Your Own Key) design makes this divergence almost disappear:
- Supported providers: OpenAI, Anthropic, Google, Apple Intelligence.
- Keys are encrypted in the backend; all AI calls are proxied server-side; no API key ever reaches any client.
- The AI's sole job is behavioral pattern analysis. It is strictly prohibited from diagnosing, prescribing, or guessing drug categories, and its final output must always defer to "Consult your doctor." (Core Opinion 2 — non-negotiable.)
Because the proxy lives in the ToGO backend (Phase 1), the Android app does not "integrate AI" in any deep sense — it renders proxied AI responses and provides the key-enrollment UI, identical in contract to iOS. One open point: Apple Intelligence is an Apple-platform provider; whether it is selectable from Android via the server proxy, or Apple-only, is not defined in the current spec and needs a decision (see Open Questions).
Closed by: Phase 5 — wire the Android client to the server-side AI proxy endpoints and build the BYOK key-management UI. PENDING DESIGN: AI insight surfaces and key-enrollment screens.
2.5 Widgets / Watch / Car — working on iOS, missing on Android
Legacy state. iOS has widgets, watch, and car support; Android has none of the three.
Legacy-era fix. Develop Android Wear (WearOS), Android Auto, and Android widgets for parity.
Greenfield resolution. The target platform matrix is explicit in the spec:
| Surface | Apple (Phase 4) | Google (Phase 5) |
|---|---|---|
| Phone/tablet | iOS (Swift) | Android (Kotlin) |
| Desktop-class | macOS | ChromeOS |
| Watch | watchOS | WearOS |
| Car | CarPlay | Android Auto |
| Widgets | Widgets | Widgets |
All are native only — no hybrid. Two engine-specific notes:
- The Kinetic Pomodoro Engine (Engine 8) depends on wearables: the desk-timer break only registers if the wearable detects physical movement away from the screen. Without WearOS support, Android users cannot fully participate in this engine — making the watch surface a protocol-correctness requirement on Android, not a nice-to-have.
- IoT ingestion is per-ecosystem: Apple HealthKit on Phase 4 surfaces, Google Health Connect on Phase 5 surfaces; clients read on-device and push securely to ToGO.
Closed by: Phase 5 — WearOS, Android Auto, and Android widgets, each as a thin renderer of server state. PENDING DESIGN: widget layouts, watch complications/tiles, and car-safe UI.
3. Why the greenfield architecture resolves divergence by design
The five divergences share one root cause: in the legacy apps, business logic lived inside each client, so every feature had to be written twice (Swift and Kotlin) and drifted whenever one side lagged. The new architecture removes that failure mode structurally:
- Single Source of Truth. All eight Protocol Engines — Hydration, Caffeine Block, GERD Window, Trigger Families, Medication Grace, Cycle, Contraceptive Security, Kinetic Pomodoro — are backend state machines in the central ToGO REST API (Phase 1). All temporal and state logic lives there, once.
- Clients are presentation + sensor collection only. The architectural rule is absolute: clients never compute or hardcode protocol logic locally. An iOS screen and an Android screen for the same feature consume the same endpoint and render the same state.
- Parity becomes an API-contract problem, not a logic-porting problem. "Feature missing on platform X" can no longer mean "the 3-cycle prediction rule doesn't exist on X." It can only mean "platform X hasn't built the screen yet" — a bounded, testable rendering task with the contract already fixed.
- The core opinions are enforceable in one place. The categorical protocol (Safe vs Trigger-bearing, never quantitative) and the no-medical-certainty rule for AI are enforced server-side, so no client can accidentally diverge from them.
- Sequenced closure. Phase 1 (ToGO backend + PostgreSQL + auth) and Phase 2 (React dashboard + theme/i18n engine) establish the contract and the canonical theme tokens. Phase 4 then closes divergence #1 (iOS-missing meds/cycle) by building the Apple presentation layer; Phase 5 closes divergences #2–#5 (all Android-missing/untested) by building the Google presentation layer. Phases 3 (Chrome extension) and 6 (Electron) reuse the same contract, so no new divergence class is introduced.
A future-state note (context, not scope): doctor-prescribed "Medical Restrictions" will dynamically alter the Protocol Engines. Because engines are server-side, such changes propagate to every platform simultaneously — under the legacy client-side model, that feature would have multiplied the divergence problem instead.
4. Phase-mapping recap
| Divergence | Legacy gap side | Closing phase | Closure criterion (greenfield) |
|---|---|---|---|
| 1. Meds & Cycle Tracking | iOS | Phase 4 | Swift screens live against Engines 5/6/7 endpoints; zero client-side protocol logic |
| 2. Light/Dark Mode | Android (untested) | Phase 5 | Theme tokens from Phase 2 engine render correctly on physical Android devices, both modes, LTR + RTL |
| 3. Notification Center | Android | Phase 5 | Kotlin delivery layer consumes the server alert contract across Android surfaces |
| 4. AI Integration | Android | Phase 5 | Android renders server-proxied AI responses; BYOK key UI; no key on device |
| 5. Widgets / Watch / Car | Android | Phase 5 | WearOS + Android Auto + widgets shipped; Kinetic Pomodoro movement detection functional on WearOS |
5. Open questions
- Apple Intelligence on Android: since all AI calls are server-proxied, is Apple Intelligence selectable as a provider from Android clients, or is it Apple-platform-only? Not defined in the current spec.
- Light-mode alert color: the light-mode palette defines
#20A060and#0070A0but no alert red equivalent. Needs a design decision (PENDING DESIGN). - Android notification transport: push service vs. local scheduling fallback is unspecified; must be fixed in the Phase 1 alert API contract.
- Kinetic Pomodoro without a wearable: behavior for Android users with no WearOS device (does the break simply never register?) is implied but not explicitly specified.
- Legacy QA debt: whether the two caveats (untested Android splash/onboarding; iOS profile/onboarding pending QA) need any verification in the legacy apps at all, given both flows are rebuilt from the new designs (PENDING DESIGN).