walletSyncPassesRunProvider top-level property
SSOT for money copy that leans on a future SYNC PASS (#401 R5).
The core's durable money machinery — the §6.1 ReBroadcast arm that re-sends
an already-signed-but-unbroadcast transaction, the §6.3 reconcile that
re-queues a mid-signature row, the queue drain — is driven EXCLUSIVELY by
after_synced. No completed pass, no correction. So any string that promises
the wallet "will finish this on a later sync" is a claim about THIS provider,
and must be qualified when it reads false.
BOTH TERMS (#403 R5 — the #401 version read the DRIVE alone).
!= failed is the term that does the work the policy cannot: a start command
that FAILED means the loop never ran and after_synced never fires, WHILE the
policy still reads true. Copy keyed on the policy alone tells exactly that
user their payment completes on its own — the wait-forever this qualifier
exists to prevent.
walletSyncPolicyProvider is the host's own switch and a plain
Provider<bool> — it cannot lag and it has no in-flight command behind it.
BE PRECISE ABOUT WHAT IT BUYS, because the review that proposed this
conjunction credited it with more: today it is REDUNDANT with the drive's
disabledByHost, since build returns that synchronously the moment the
policy reads false, and every settle path is already policy-aware. It is
kept as defence in depth — the host's explicit "off" should be authoritative
for a money promise no matter what the drive is doing — not as a fix for a
reproduced bug. It does NOT close the background/resume flicker either: on the
flickering host the policy reads true, so the whole predicate rides on the
drive. What closes that is the drive itself now PRESERVING failed across a
background stop (see the settle in _command), which is where the bug was.
The two remaining drive states are deliberately not consulted:
- WalletSyncDrive.suspended — the app is backgrounded, so nothing that reads this is on screen, and a resume restarts the loop. Qualifying it would be a pause the user can only ever be told about after it ended.
- WalletSyncDrive.inactive — no session; every consumer here renders inside a live one.
TWO ROLES, one predicate (#405 sharpened the original "never a gate" claim, which this provider outgrew the moment a DESTRUCTIVE op was keyed on it):
- HONESTY QUALIFIER for money copy — the original role. A
falsehides and disables NOTHING: the affordances a committed payment needs stay available (the #400 R9 rule), the copy just stops promising a schedule it cannot keep. - READINESS PREDICATE for the two ops that can only COMPLETE through a
sync pass — the rescan (wipes the DB and rebuilds as sync scans) and the
swap deep scan (marks ranges a later pass covers). Offering those while
no pass will run is a destructive dead end, not a copy problem, so they
are genuinely DISABLED on
falseand the rescan is refused again at its commit point. This is not an exception to rule 1 — neither op is an affordance a committed payment needs; both are user-initiated recovery.
The line between the two: never remove a way to FINISH or RESCUE money that is already committed; do refuse to START something that provably cannot end.
CAUSE-AGNOSTIC AT EVERY CONSUMER (#405). The predicate deliberately does not
say WHICH term is false, and no consumer may re-derive it to word its copy:
"turn syncing on in settings" is the right instruction for disabledByHost
and the WRONG one for a failed start, and a family that words itself per
cause drifts back into exactly the #401 R5 bug the SSOT replaced. Consumers
state the CONDITION ("syncing isn't running"); the sync badge and the
start-failed notice — both always on the wallet surface — own the cause and
its remedy.
Implementation
final walletSyncPassesRunProvider = Provider<bool>((ref) {
return ref.watch(walletSyncPolicyProvider) &&
ref.watch(walletSyncControllerProvider) != WalletSyncDrive.failed;
});