diff --git a/app/bin/diet_guard_desktop.dart b/app/bin/diet_guard_desktop.dart index d4a2f61..90b71d8 100644 --- a/app/bin/diet_guard_desktop.dart +++ b/app/bin/diet_guard_desktop.dart @@ -103,7 +103,6 @@ Future _provisionSyncAccount(String home, int port) async { '--headless=new', '--disable-gpu', '--user-data-dir=${_profileDir(home)}', - '--virtual-time-budget=45000', // Surface the page's own log() output, so a failure inside the app // is visible in the terminal that started the provisioning run. '--enable-logging=stderr', diff --git a/app/lib/services/background_sync_service.dart b/app/lib/services/background_sync_service.dart index 10abd11..29b1dae 100644 --- a/app/lib/services/background_sync_service.dart +++ b/app/lib/services/background_sync_service.dart @@ -5,6 +5,7 @@ /// reconnect and uploads the log without the app being reopened. library; +import 'dart:developer'; import 'package:diet_guard_app/services/app_settings_service.dart'; import 'package:diet_guard_app/services/budget_history_service.dart'; import 'package:diet_guard_app/services/firebase_backend.dart'; @@ -41,16 +42,38 @@ Future backgroundSyncPush({http.Client? httpClient}) async { final SyncSettings settings; try { settings = await SyncSettings.load(); - } on Exception { - return false; // couldn't read config in-isolate; let WorkManager retry + } on Exception catch (error, stackTrace) { + log( + 'diet_guard background sync: cannot read config in-isolate', + level: 900, + error: error, + stackTrace: stackTrace, + ); + return false; // let WorkManager retry + } + // Either backend counts. `isConfigured` means "has a GitHub token", so + // gating on it alone silently skips every background push on a device + // connected only to Firebase. + if (!settings.isConfigured && await openFirebase() == null) { + log( + 'diet_guard background sync: no backend configured; nothing to push', + level: 900, + ); + return true; // nothing to push; don't retry } - if (!settings.isConfigured) return true; // nothing to push; don't retry final client = createGitHubClient(settings, httpClient: httpClient); try { await runSync(await syncBackend(client)); return true; - } on Exception { - return false; // offline / transient GitHub error -> retry with backoff + } on Exception catch (error, stackTrace) { + // Never silent: this is the only signal that a background push failed. + log( + 'diet_guard background sync failed', + level: 1000, + error: error, + stackTrace: stackTrace, + ); + return false; // offline / transient error -> retry with backoff } finally { client.close(); } diff --git a/app/lib/services/firebase_backend.dart b/app/lib/services/firebase_backend.dart index 8b86649..327b011 100644 --- a/app/lib/services/firebase_backend.dart +++ b/app/lib/services/firebase_backend.dart @@ -12,6 +12,7 @@ /// half. On Android there is no such file. library; +import 'dart:developer'; import 'package:crdt_sync/crdt_sync.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -59,9 +60,16 @@ Future loadAccount() async { final provisioned = await accountFromWrapper(Uri.base); if (provisioned != null) await saveAccount(provisioned); return provisioned; - } on Object { - // No secret service available: behave as "not configured" rather than - // crashing the settings screen. + } on Object catch (error, stackTrace) { + // Still "not configured" rather than crashing the settings screen -- but + // never silent: this hid *why* provisioning failed, which is + // indistinguishable from "no account set" until you say so. + log( + 'loadAccount failed; treating this device as not configured', + level: 1000, + error: error, + stackTrace: stackTrace, + ); return null; } }