app-startup-and-bootstraplisted
Install: claude install-skill zakariaf/CatchLaw
# App startup and bootstrap
`main()` has one job: install a crash net, read the little state the first frame needs, wire real dependencies into the tree, and hand off to `runApp` — fast, ordered, and unable to hide a failure. Everything expensive happens after the first frame or off the launch path entirely.
## Non-negotiable rules
1. **Error handlers go first, before anything that can throw.** A crash-log sink, `FlutterError.onError`, and `PlatformDispatcher.instance.onError` are installed immediately after `WidgetsFlutterBinding.ensureInitialized()`. The step most likely to throw is opening the DB; installing handlers after it inverts the whole point.
2. **Exactly two error handlers — no zone.** `FlutterError.onError` (build/layout/paint errors) and `PlatformDispatcher.instance.onError` (uncaught async errors) cover every path. **Never add `runZonedGuarded`.** The "you need all three" advice is crash-SDK advice (Sentry wraps its init in a zone); with no such SDK a zone buys nothing and costs a documented zone-mismatch footgun. Flutter's own fix for that warning is to remove zones.
3. **`PlatformDispatcher.onError` returns `true` unconditionally.** Returning `false` routes to the embedder fallback, where the process may exit or hang. Get debug-console visibility from `debugPrint` under `kDebugMode`, not from `return kReleaseMode`.
4. **Never let an error handler throw.** Wrap its body in a bare `try/catch (_)` and keep the comment explaining why the discarded error is del