feat(desktop): route beta channel to dev backend#7224
Conversation
Beta channel of the production bundle now routes to the development backend (api.omiapi.com + the dev Cloud Run desktop-backend). The dev backend is configured to use prod Firebase (project_id=based-hardware, prod service account, FIREBASE_API_KEY=AIzaSyA88g...), so custom tokens it mints resolve to the same UID users have on prod — reads/writes hit prod Firestore. Same pattern mobile TestFlight uses for staging. This redoes PR #7014, which was reverted in April because dev backend was on the based-hardware-dev Firebase project at the time, so beta users landed in fresh empty Firebase accounts. The dev backend's SERVICE_ACCOUNT_JSON, FIREBASE_API_KEY, FIREBASE_PROJECT_ID, and FIREBASE_AUTH_DOMAIN have all since been moved onto prod Firebase — verified via `gcloud run services describe backend --project=based-hardware-dev`. The Rust desktop-backend in the dev GCP project has the matching FIREBASE_PROJECT_ID=based-hardware and the same FIREBASE_API_KEY as prod. Also adds an OMI_FORCE_DEV_BACKENDS env override so a named test bundle (com.omi.omi-*) can opt into dev backends without flipping its channel or bundle ID — useful for validating routing on a side-by-side build before shipping to actual beta users. Stable channel and non-prod bundles still default to prod backends or their configured OMI_PYTHON_API_URL / OMI_DESKTOP_API_URL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR re-enables beta-to-dev backend routing for the production macOS bundle (
Confidence Score: 4/5Safe to merge; the routing logic is correct, well-tested, and well-commented with the historical context needed for future maintainers. The routing logic is narrowly scoped and all test cases pass. The only rough edges are a log message that now misfires under the force-override path, and a small gap in isAffirmative test coverage — neither affects correctness of the routing decisions. desktop/Desktop/Sources/DesktopBackendEnvironment.swift — the applyReleaseChannelDefaults() log message should be updated to distinguish the force-override trigger path from the beta-channel path. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[shouldUseDevelopmentBackends called] --> B{OMI_FORCE_DEV_BACKENDS\nis affirmative?}
B -- Yes --> C[return true\nRoute to dev backends]
B -- No --> D{bundleIdentifier ==\ncom.omi.computer-macos?}
D -- No --> E[return false\nRoute to prod backends]
D -- Yes --> F{normalizedChannel ==\nbeta or staging?}
F -- No --> E
F -- Yes --> C
C --> G[applyReleaseChannelDefaults:\nsets OMI_PYTHON_API_URL to api.omiapi.com\nsets OMI_DESKTOP_API_URL to dev Cloud Run]
E --> H[pythonBaseURL to api.omi.me\nrustBackendURL to prod Cloud Run]
|
| func testForceOverrideEnablesDevelopmentBackendsForAnyBundle() { | ||
| XCTAssertTrue(DesktopBackendEnvironment.shouldUseDevelopmentBackends( | ||
| bundleIdentifier: "com.omi.desktop-dev", | ||
| updateChannel: "stable", | ||
| forceOverride: "1" | ||
| )) | ||
| XCTAssertTrue(DesktopBackendEnvironment.shouldUseDevelopmentBackends( | ||
| bundleIdentifier: "com.omi.omi-beta-dev-test", | ||
| updateChannel: "stable", | ||
| forceOverride: "true" | ||
| )) | ||
| XCTAssertFalse(DesktopBackendEnvironment.shouldUseDevelopmentBackends( | ||
| bundleIdentifier: "com.omi.computer-macos", | ||
| updateChannel: "stable", | ||
| forceOverride: "0" | ||
| )) | ||
| } |
There was a problem hiding this comment.
isAffirmative "yes" branch and non-affirmative values are untested
isAffirmative accepts "yes" in addition to "1" and "true", but testForceOverrideEnablesDevelopmentBackendsForAnyBundle never exercises it. Likewise, "false" and "no" are silently rejected by the function but are never asserted as false in the test. A future refactor that trims the accepted set or changes the rejection logic would have no test catching the regression.
Reverts #7224. The change was merged before being validated locally; we want to test the dev-backend routing on a named local bundle first (using the `OMI_FORCE_DEV_BACKENDS` override I added in that PR — except the env-var didn't actually reach the launched .app because `run.sh` loads URLs via a baked `Contents/Resources/.env`, not shell env). Reverting on `main`, validating locally, then redoing. The diagnostic PR #7227 stays — that's an unrelated workflow hardening that's useful regardless. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reapplies #7224 after the #7230 revert. Verified locally this time: - Named bundle (`com.omi.omi-beta-dev-test`) launched with shell-bundled dev URLs (`OMI_PYTHON_API_URL=https://api.omiapi.com/`, `OMI_DESKTOP_API_URL=https://desktop-backend-dt5lrfkkoa-uc.a.run.app/`). - Signed in with `kodjima33@gmail.com` — landed on **prod UID `viUv7GtdoHXbK1UBCDlPuTDuPgJ2`** (not a ghost dev UID). - Existing chat history and tasks loaded. - New requests go through dev backend: `POST https://api.omiapi.com/v2/desktop/messages`, `/v3/memories`, `/v1/action-items` — all succeeding, AgentSync pushing rows. - Confirms dev backend's `SERVICE_ACCOUNT_JSON`, `FIREBASE_API_KEY`, `FIREBASE_PROJECT_ID` are all on prod Firebase (`based-hardware`), so dev-issued custom tokens resolve to the same prod UID. This time the change ships through the existing #7227 diagnostic patch (already on main), so if Codemagic's universal-bundle step trips again we'll get a real error instead of a 0.6s opaque failure. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Summary
com.omi.computer-macos) now routes to the dev backend (api.omiapi.comPython + dev Cloud Run desktop-backend), matching mobile's TestFlight → staging pattern.OMI_FORCE_DEV_BACKENDS=1env override lets a named test bundle opt into dev backends without flipping its channel — handy for side-by-side validation.Why this won't repeat the PR #7014 outage
PR #7014 (April 2026) was reverted because the dev backend was wired to the
based-hardware-devFirebase project, so beta users signed in as fresh empty UIDs (e.g.caLCFj7…instead of prod'sviUv7Gtdo…). The dev backend infra has since been moved onto prod Firebase. Verified against the live deployments:So custom tokens minted by the dev backend resolve to the same UID the user has on prod, and reads/writes hit prod Firestore.
Test plan
swift test --filter APIClientRoutingTests(46/46 passing)auth_userIddefaults shows the prod UID (viUv7Gtdo…), not a fresh oneapi.omi.me🤖 Generated with Claude Code