service-boundary-and-nativelisted
Install: claude install-skill zakariaf/CatchLaw
# Service boundary and native
Every platform capability — reading "now", sharing, logging an event, fetching remote flags, calling a MethodChannel — crosses the app's layers as an **injected interface**. The interface names value types only; the concrete SDK lives in exactly one class; the composition root (`main`) wires one live impl; tests wire a deterministic fake. **Abstract exactly what cannot run in a test — nothing more.** This is the seam that keeps features pure, SDKs swappable, and the whole app testable headlessly.
Read the reference for the task at hand:
- `references/service-interface.md` — typed outcomes vs bool/throw, exhaustiveness, `@useResult`, hand-written env-fakes, the arrow-callback Future-drop hole, single write path.
- `references/native-channels.md` — MethodChannel placement, the cross-language contract ownership table, versioned-file-vs-`shared_preferences` traps, native-fast-path independence, the round-trip `integration_test`.
- `references/multi-flavor.md` — line-for-line composition roots, build flavors over runtime detection, per-flavor plugin pins, the banned-dependency CI graph gate.
Run `scripts/check-service-boundaries.sh` and `scripts/check-flavor-graph.sh` before a PR.
## Non-negotiable rules
1. **Every side effect is an injected interface, never a concrete SDK at the call site.** Features, Notifiers, and repositories depend on the *interface*; the app imports the real SDK in exactly one live-impl class. WHY: one seam to swap, one pla