Polling Bug#502
Conversation
- Only poll for active account
…into beast/polling-bug
|
I have enough context. Here's my review: PR #502 Review: Polling Bug FixThe refactor is a solid direction — narrowing polling to the active account avoids the wasteful fan-out across every visited wallet, and the new Critical: Double-scheduled timer on
|
|
We already have remote notification. So this is intentional to not send notification for non active account.
This is nonsense. We don't skip. We don't do recon if there is nothing to recon. |
|
I've reviewed the new commits and the additional Bugbot/author comments. Here's my updated review: PR #502 — Re-review (after
|
|
I have the latest state. Let me provide the updated review. PR #502 — Third Review (after commits through
|
| Issue | Status | Notes |
|---|---|---|
Double-scheduled timer on activeId == null |
✅ Fixed | Defensive _pollingTimer?.cancel() inside _scheduleNextPoll(). Different approach than suggested but effective. |
Inverted onlyIfAlive in reconciliation |
✅ Fixed | Renamed parameter to isAccountInactive, logic flipped to accountId != activeId. Active account now always refreshed; inactive accounts only if provider already alive. |
_txSubscription leak in dispose() |
✅ Fixed | Subscription now closed + nulled in dispose(). |
Duplicate silentRefreshActiveAccount call in silent refresh path |
✅ Fixed | HistoryPollingManager.triggerSilentRefresh() no longer calls _reversibleMonitor.forceCheckAllMonitoredTransfers(). The monitor's forceCheck... still does a conditional refresh when pollers exist, but the double-tap in the common path is gone. |
| Debug print hygiene | Partial | One print → quantusDebugPrint in global poller; file still has mixed usage. |
Remaining open finding (from Bugbot on 487404ea)
Low severity: triggerManualRefresh uses silentRefresh() instead of loadingRefresh()
Current code in GlobalHistoryPollingService.triggerManualRefresh():
await refreshAccountsPagination(
_ref,
accountIds: [active.account.accountId],
action: (notifier) => notifier.silentRefresh(), // was loadingRefresh
);The method is documented as "Manually trigger a history refresh (useful for pull-to-refresh)". The previous behavior (and the old code the diff removes) used loadingRefresh() which shows loading indicators.
However, this method is not actually called from the real pull-to-refresh gestures:
- Home screen
_refreshdirectly callsloadingRefresh()on the filtered controller. - Activity screen
_refreshdirectly callssilentRefresh()on the notifier.
HistoryPollingManager.triggerManualRefresh() (which delegates to the global poller) even has a comment: // This is not called from anywhere!
So the user-visible behavior of pull-to-refresh is unchanged — the screens bypass these service methods entirely. The finding is a documentation/implementation mismatch on a low-traffic code path, not a regression in the shipping UX.
Recommendation on this one: Either:
- Update the implementation to call
loadingRefresh()(preserving old documented behavior for any future callers), or - Update the doc comment to clarify this is a "background-triggered manual refresh" that intentionally stays silent.
Either is fine; it's a low-priority cleanup.
Other nits still outstanding (unchanged from prior review)
refreshAccountsPaginationstill lacks a doc comment (the new helper at the heart of the scoping logic).- The
filtersparameter added toupdatePaginationFiltersForstill has no non-default callers — either migrate callers or drop the now-dead param. - The
activeAccountProviderlistener still silently skips the first assignment after launch (previousId == null). A one-line comment would help. - Mixed
print/quantusDebugPrintremains in the touched files.
Positives (reiterated)
- Active-account scoping is now consistently applied across polling, reconciliation, reversible monitoring, and event-driven refreshes.
- Timer safety, subscription hygiene, and duplicate refresh elimination are all solid fixes.
- The parameter rename (
isAccountInactive) makes the intent much clearer than the originalonlyIfAliveboolean. - Unit tests landed for the scoping helpers.
Overall assessment
This PR has meaningfully improved since the initial review. The three medium-severity Bugbot findings from the previous round are all resolved. The remaining open item is a low-severity documentation-vs-implementation nit on a method that isn't even wired to the actual pull-to-refresh UX.
Verdict: LGTM with optional low-priority cleanup. If the author addresses the triggerManualRefresh doc/impl mismatch (or just clarifies it), this is ready to merge. The core correctness and resource-leak issues that blocked earlier are gone.
PR: #502
n13
left a comment
There was a problem hiding this comment.
GTG!
the AI is kinda confused about the UX for refreshing, lets see how it looks later ;)
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 50d05ae. Configure here.
| } | ||
| } | ||
|
|
||
| return confirmedById.values.toList(); |
There was a problem hiding this comment.
Reconciliation creates providers that refresh intentionally skipped
Medium Severity
_loadConfirmedTransactions calls _ref.read(filteredPaginationControllerProviderFamily(params)) for every account ID (including external addresses from tx.from/tx.to), which creates providers that refreshAccountsPagination intentionally skipped via ref.exists(...). The refresh step avoids instantiating controllers for inactive/external accounts, but _loadConfirmedTransactions then instantiates them anyway by calling _ref.read(...). Adding a ref.exists(...) guard before reading would maintain consistency with the optimization.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 50d05ae. Configure here.
| _ref, | ||
| accountIds: [active.account.accountId], | ||
| action: (notifier) => notifier.loadingRefresh(), | ||
| ); |
There was a problem hiding this comment.
Manual refresh defaults to background-only filter scope
Low Severity
triggerManualRefresh calls refreshAccountsPagination without specifying the filters parameter, so it defaults to _backgroundPollFilters which is only [TransactionFilter.all]. A manual refresh conceptually covers all filter views (all, send, receive), matching what the old code did via updatePaginationFiltersFor iterating TransactionFilter.values. If this method is ever invoked for a user-initiated refresh, only the "all" tab updates.
Reviewed by Cursor Bugbot for commit 50d05ae. Configure here.


Summary
Fixed the bug of polling visited accounts even though not active.
Note
Medium Risk
Changes how often history, balances, and pending/reversible state refresh run; incorrect scoping could leave inactive-account pending txs stale, though reconciliation still includes senders/receivers.
Overview
Fixes background polling and refresh fan-out so work targets the active wallet account (and transaction parties where needed), not every account the user has opened.
A new
polling_refresh_scopemodule centralizes scoped balance invalidation, filtered pagination refresh, account-switch handling, and reconciliation account selection. Global history polling now silently refreshes only the active account; pending-tx reconciliation reads per-account filtered history and skips inactive accounts unless their pagination provider already exists. Reversible-transfer monitoring subscribes to the active account’s transaction list instead of wallet-wide history, and event-driven refreshes use deduplicated per-account targets instead of refreshing all accounts.Across the mobile app, raw
printcalls are replaced withquantusDebugPrintfor consistent debug logging. Unit tests cover refresh-target and reconciliation account scoping.Reviewed by Cursor Bugbot for commit 50d05ae. Bugbot is set up for automated code reviews on this repo. Configure here.