check method

Future<SwapAddressCheckReport?> check()

Run ONE deep scan. Returns the counts-only report, or null when nothing ran — a scan is already in flight (that run owns the outcome) or the session is gone. A typed refusal / fault PROPAGATES (the caller maps the copy); the latch resets and the coverage read re-pulls on EVERY exit so the sheet settles.

Implementation

Future<SwapAddressCheckReport?> check() async {
  if (state) return null; // single-flight: the running scan owns the outcome
  final session = ref.read(walletSessionProvider);
  if (session == null) return null;
  state = true;
  try {
    // Bound the widen FFI call (rel-MED2): a wedged bridge must degrade to a
    // reset latch + an honest "couldn't start", never a permanent "Checking…"
    // that ALSO pins the core aux mutex the widen serializes on. The widen is
    // a durable local aux write — a timeout after a slow commit self-corrects
    // on the coverage re-pull in the finally below. Same package-wide wedge
    // bound every other local FFI read carries.
    final report = await session.checkOlderSwapAddresses().timeout(
      walletFfiWedgeTimeout,
    );
    // A widen executed — arm the C1 progress cue (survives closing the sheet).
    _armProgress(session);
    return report;
  } on TimeoutException {
    // The FFI call exceeded the wedge bound, but the widen is a durable local
    // aux write that MAY have committed (rel-H1). Arm the cue anyway: the
    // banner only shows if the coverage re-pull below confirms a pending band,
    // so a genuinely-failed widen stays hidden — while a slow-but-committed
    // one keeps its "still surfacing" cue instead of a false "nothing changed".
    _armProgress(session);
    rethrow;
  } finally {
    // Guarded: the controller has no provider dependencies (session is
    // `ref.read`), so only a whole-scope teardown can unmount it mid-scan —
    // and an unmounted-ref throw in `finally` would REPLACE the scan's real
    // outcome. Re-pull the coverage read so the sheet's line advances.
    if (ref.mounted) {
      state = false;
      ref.invalidate(swapAddressCoverageReadProvider);
    }
  }
}