Repository navigation
fix(mobile): show a store timeout separately from a missing credit catalog - #8458
Conversation
The credit-pack loader caught every store rejection the same way, so a price lookup that missed the 15 s deadline showed the no-matching-products copy and filed as an error-level store failure. The loader now keeps the deadline module's distinction: a deadline maps to its own per-store timeout copy, a store that failed maps to the existing connection copy, and only a store answer that priced no pack keeps the catalog copy. A deadline reports under its own warning fingerprint (store-timeout) instead of store-error. The new copy is translated into every catalog. The store fetch also accepts an AbortSignal that the loader aborts once the call settles without an answer, so the Play NotPrepared reconnect does not ask a store that already missed the deadline a second time.
|
bot: Android proof from the branch build on the local dev stack (Play system image, throwaway local account).
|
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryThe three store outcomes are now distinguished correctly (deadline → timeout copy and warning fingerprint, failure → connection copy and error fingerprint, zero-match → catalog copy), the abort signal only short-circuits the Play reconnect path, and all 87 catalogs carry matching, store-correct copy; I found no runtime, security, or leak issue in the changed code. Assumptions: Files Reviewed (95 files)
Reviewed by deepseek-flash-latest · Input: 95.3K · Output: 21.8K · Cached: 2.3M Review guidance: REVIEW.md from base branch |


What changes
The credit-pack loader bounded the store price lookup with the shared 15 s store
deadline, but its catch was untyped: a deadline, a store failure and a catalog
that priced no pack all became one
StoreCreditProductsErrorbuilt from theno-matching-products copy. The card therefore told the reader the store had
returned no matching packs when the store had simply never answered, and the
report filed that expected, bounded outcome as an error.
isStoreDeadlineErroris exported from the deadline module, so a caller cankeep the deadline the module documents ("distinct from a store that answered
with a failure") apart from a store failure.
loadStoreCreditProductsnow picks the card body by outcome: a misseddeadline gets the new timeout copy, a store failure gets the existing
per-store connection copy, and only a store answer that priced no pack keeps
the catalog copy.
StoreCreditProductsErrorderives its telemetry from the caught cause: adeadline files as
warningundercredit-catalog-query/store-timeout/<storefront>instead of an error-levelstore-error.AbortSignal. The loader aborts it once the callsettles without an answer, and the IAP owner checks it before and after its
NotPreparedreconnect, so a store that already missed the deadline is notasked a second time.
credits.storeTimedOut/credits.storeTimedOutPlay, translatedinto every catalog, alongside the existing per-store no-match keys.
The screen needs no change: it renders the key the loader authors.
End-to-end evidence
Android emulator (
omp36play, Play system image) against the local dev stack onthis VM, signed in as a throwaway local account seeded in the dev database, on
the branch build served by Metro:
dev-only) to never answer, the credits screen shows the new state after the
15 s deadline: title
Google Play products unavailable, bodyGoogle Play didn't respond in time. Try again., a Try again action, and thefour backend pack amounts kept on screen as
Price unavailable.uiautomator dumpand OCR of the capture both read that copy. The loader,deadline module, screen and catalogs under test are the committed ones; only
the store boundary was stubbed.
client on the emulator fails the price lookup: the same card now reads
Could not connect to Google Play. Check your connection and try again.instead of claiming no matching packs. Same dump/OCR verification.
No matching credit packs were returned by Google Play.copy and is covered by the mounted screen suite (a store answerthat prices nothing), since the emulator cannot make Play answer with
unrelated listings.
Captures are attached in the evidence comment on this pull request.
Checks run
New tests cover: a deadline maps to the timeout key with the deadline as
causeand a warningstore-timeoutfingerprint; a store failure maps to theconnection key with the error
store-errorfingerprint; the loader aborts thesignal it gave up on; the IAP owner does not re-ask an aborted call, including
when the abort lands during the reconnect; and the screen renders the timeout
copy after the deadline instead of the catalog copy.
Proxy answers
The owner's proxy gave these answers in the owner's place.
Answer: New per-store keys credits.storeTimedOut/_Play
Confidence: 0.55 · Precedent: Keep similar elements consistent across surfaces: the existing connection copy is already per-store (couldNotConnectToAppStore/Play). Localize every string in the mobile app, so the translation pass is required, not a cost to avoid.
Answer: couldNotConnectToAppStore/Play
Confidence: 0.85 · Precedent: Fix the root cause and the class of the issue; a genuine failure should not claim a catalog mismatch.
Answer: Warning + store-timeout fingerprint
Confidence: 0.80 · Precedent: If you see a gap or an error, fix it. Make alerts informative and actionable.
Answer: Pass an AbortSignal and skip the retry
Confidence: 0.80 · Precedent: Fix the root cause and the class of the issue on every affected surface. The brief explicitly asks that callers avoid re-calling a store that missed the deadline.