Fix password recovery reminder triggering - #6177
Open
j0ntz wants to merge 3 commits into
Open
Conversation
Contributor
Author
📸🪓 Test evidence
recovery reminder on funded account 🪓 HACK-FORCED: rate refresh trigger Captured by the agent's in-app test run (build-and-test). |
j0ntz
force-pushed
the
jon/pw-recovery-reminder-trigger
branch
from
August 28, 2026 01:30
a8e87e6 to
4f3fd7c
Compare
j0ntz
marked this pull request as ready for review
August 28, 2026 01:30
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Description
The password-recovery reminder is meant to fire once per balance milestone ($20 / $200 / $2,000 / $20,000 / $200,000) for accounts with no recovery key. It rarely did, for these reasons:
newTransactions.checkPasswordRecoveryhad exactly one dispatch site, inside thewallet.on('newTransactions')handler. It now also runs on each exchange-rate refresh, so funds that arrived while the app was closed are noticed.getExchangeRatereturns0for a rate it has not loaded, so a partly-loaded rate set undercounts the total and credits the wrong milestone. The thunk now bails out when any funded wallet or token lacks a USD rate, and picks the check back up on a later pass.!transactions[finalTxIndex].isSend, so a batch whose last element was a send skipped the check even when the batch contained receives. It now uses the already-computedreceivedTxs.Trigger paths, before and after
Before, every path to the check was gated on something that was often false:
sequenceDiagram autonumber participant Chain participant Wallet participant ACM as AccountCallbackManager participant Check as checkPasswordRecovery Chain-->>Wallet: deposit lands while the app is closed Note over Wallet,ACM: no listener attached, so no event Wallet-->>ACM: app reopens, wallet syncs ACM--xCheck: never dispatched, the only call site was newTransactions Chain-->>Wallet: deposit while the app is running Wallet->>ACM: newTransactions([receive, send]) ACM--xCheck: skipped, guard read transactions[last].isSend Chain-->>Wallet: deposit on a cold start Wallet->>ACM: newTransactions([receive]) ACM->>Check: dispatch Note over Check: rates not loaded yet, so the total is 0<br/>lt(0, "20") returns early, and nothing re-runs itAfter, the rate-refresh cycle gives the check a second, unconditional entry point, and the two broken guards are fixed:
sequenceDiagram autonumber participant Chain participant Wallet participant ACM as AccountCallbackManager participant Check as checkPasswordRecovery Chain-->>Wallet: deposit lands while the app is closed Wallet-->>ACM: app reopens, wallet syncs loop every rate refresh (30s) ACM->>Check: dispatch alt a funded wallet still has no USD rate Note over Check: defer to the next refresh else rates complete Check->>Check: mark every crossed level shown Check-->>ACM: show one reminder modal end end Chain-->>Wallet: deposit while the app is running Wallet->>ACM: newTransactions([receive, send]) ACM->>Check: dispatch, guard is now receivedTxs.length > 0The above also forces two supporting changes:
writePasswordRecoveryReminderstakes a level array so the marks are one read-modify-write, not a race.account.username == null) are skipped. They have no password to recover, and they already get the backup modal from the same handler.Also on this branch, because it blocks CI for every PR: commit
3923d60acon develop accidentally committed.husky/_as a symlink to an absolute local path, sohusky installfails withENOENT: mkdir '.husky/_'andnpm run prepareexits 1 anywhere that path does not exist. Travis errors on develop for that reason. The stray symlink is removed here;npm run preparethen succeeds and husky recreates the directory itself.Asana: https://app.asana.com/0/1215088146871429/1211152484915503
CHANGELOG
Does this branch warrant an entry to the CHANGELOG?
Dependencies
none
Requirements
If you have made any visual changes to the GUI. Make sure you have: