CloudBridge URL unification — single resolver for chat and submit
CloudBridge URL unification — single resolver for chat and submit
Status: Delivered CAS: CAS-2537 Delivered: 2026-05-12 PRs: #651 (B1 — shared resolver), #652 (B2 — wire both paths)
What’s new
Chat and submit now resolve the CloudBridge URL through a single async
cloudbridge_base_url() function. The previous two-code-path design —
chat reading from the AI_CLOUDBRIDGE_URL env var, submit reading from
iOS Keychain cloudbridge.worker_url — could silently diverge when the
device paired before a backend architecture change.
How it works
async fn cloudbridge_base_url() -> Result<String> { // 1. Env override (dev / CI) if let Ok(url) = std::env::var("AI_CLOUDBRIDGE_BASE_URL") { return Ok(url); } // 2. Keychain (written at pair time, canonical in prod) keychain::read("cloudbridge.worker_url")}Both start_stream (chat) and cloud_bridge_report_issue (submit)
call this resolver. The Keychain read is now authoritative in production;
the env var is the escape hatch for dev and CI runs that don’t pair.
The pair_with_pin command retains a hardcoded fallback (https://ai-bridge.casaconomy.com)
because it bootstraps the Keychain entry — it cannot read from it before
writing it.
What changed
src-tauri/src/services/ai/cloudbridge.rs— newcloudbridge_base_url()async fn;CloudBridgeService::new()is now async; the inlineworker_urlfield removed.src-tauri/src/services/ai/manager.rs—AIManager::new()is now async to await the base-URL resolution.src-tauri/src/commands/ai_commands.rs— inline Keychain read incloud_bridge_report_issueremoved; routes through shared resolver.src-tauri/src/main.rs— async init for the CloudBridge service path.
Why we built it
On 2026-05-12 the regent’s iPhone (0.2.2 build 15) could chat (AI bridge worked) but submit failed with “Mac bridge is offline”. The daemon was healthy — curl confirmed 200 from the public hostname. The failure was that the Keychain stored a stale URL from before the CAS-2196 architecture rewire. Chat ignored Keychain and used the env var; submit read Keychain and got the stale value.
Root cause: two independent URL sources of truth for the same daemon. This is the two-source-of-truth rule (Rule 5 in CAS-2550’s quality skills extension): if two functions resolve the same logical value, they must share an implementation.