Repository navigation
Conversation
The API now holds level Plutonium rewards (level_milestone) until the account is trusted, marking them `held: "trust"` on /users/@me's rewards. The rewards panel shows a held reward with "Trusted accounts only" in place of its Claim button, and a note under the list saying how the account becomes trusted (CrazyGames gets a variant without purchases). - Claim all is offered only for claimable rewards, and after it the panel keeps the rewards the server left held (`held` on the claim-all response) instead of clearing the list. - A single claim answered 403 with `held` marks that reward held rather than showing the claim-failed alert. - The login rewards popup counts only claimable rewards, so held ones alone don't reopen it every boot. - Every new field is optional and reads a malformed value as absent, so older and newer APIs both parse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (8)
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 5 remain after this review. WalkthroughThe change adds hold fields to reward schemas and recognizes held responses from reward claims. The rewards panel retains and displays held rewards. Boot interrupt counting and rewards modal visibility now use claimable rewards. ChangesHeld Reward Handling
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix Sequence Diagram(s)sequenceDiagram
participant RewardsPanel
participant claimReward
participant AccountRefresh
RewardsPanel->>claimReward: Submit reward claim
claimReward-->>RewardsPanel: Return held result
RewardsPanel->>AccountRefresh: Refresh account data
AccountRefresh-->>RewardsPanel: Return refreshed rewards and currency
RewardsPanel->>RewardsPanel: Emit updated reward list
Suggested reviewers: Merge Risk: ⚪ Minimal · up to No actionable merge-blocking issue is established for the current change. The held-reward behavior is ready for normal merge checks. Pre-merge checks |
|
Coordinated review — #5879Reviewed against the backend half (infra #933) and But the explanatory copy is wrong in a way that lands on exactly the players who will read it. [high] The held-reward note omits the linked-identity gate, so it is false for the players who see itWhere: The real rules in
So both halves of the note are false for a guest — playing more public games won't lift it, and neither will a purchase. Failure scenario, and the popup is the live path: a guest reaches level 25, the backend issues the On CrazyGames it's sharper: with no purchase route, signing in is the only way for that player to become trusted — and the note doesn't mention signing in at all. Suggested fix: add signed-out variants and branch on them, exactly as the existing trust copy already does. [medium] Even for a linked account, "after you play more public games" understates itBoth floors in the games branch are hard: 14 days of account age AND 25 Public games (ranked and unranked; Singleplayer and Private excluded). The note mentions neither. It also omits the instant pass a free player can actually hit (≥ 200 lifetime Caps, roughly two 10-player wins) and says nothing about a cheat ban overriding everything. A day-1 player grinds 40 public games, is told "play more public games", and stays held for a fortnight with no explanation. Suggested fix: name the floors — "…after your account is 14 days old and you've played 25 public games, or right away with any purchase". The vaguer phrasing is pre-existing in the ranked strings, but a reward the player is waiting to be paid is where it reads as a broken promise. [medium] An unknown
|
|
infra #933 merged ( The backend half is on The six findings in my review above are still unanswered. Both bots read this PR
The high and the fail-open medium are the two I would not ship without. The rest are fine as Separately: this PR has no milestone, so the required |
- RewardSchema.held is any non-empty string: a hold kind this client
doesn't know reads as held, never as claimable. The note switches on
"trust", with a separate path for other holds.
- claimReward passes the 403's hold on as named ({ held }) instead of a
bare "held", and the panel uses it rather than assuming "trust".
- A held 403 re-reads /users/@me and emits the whole fresh list (the
hold is per account), still marking the refused reward held.
- Claim-all's held list is parsed per row, so one bad row drops only
itself.
- The login rewards popup opens, and stays open, only while a reward can
be claimed.
- isRewardClaimable() in ApiSchemas is the one claimability predicate
(Main, RewardsPanel, RewardsModal); rewardCount's doc says claimable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A held value that isn't a non-empty string (a number, an object, "") now reads as an unknown hold rather than as claimable; only absent or null is claimable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DRAFT copy, pending design approval. - Trust needs a linked identity: without one an account is never trusted, whatever it plays or buys. RewardsPanel takes a signedIn flag (responseHasLinkedIdentity(userMe) || a CrazyGames sign-in, as for trustRequiredDialog) from AccountModal, RewardsModal and Main's boot popup, and a signed-out viewer is told to sign in first. - Name the floors: 14 days old and 25 public games (TRUST_MIN_ACCOUNT_AGE_DAYS / TRUST_MIN_GAMES), or any purchase off CrazyGames. - A hold with no copy of its own gets a neutral note, reward_held_other_info, and no "Trusted accounts only" label. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks — the code findings are pushed (cf487e2, ad9bbcf, plus a
The [high] and the [medium] on the copy are built (the panel gets a signed-in flag from the same 🤖 Addressed by Claude Code |
Re-reviewed
|
|
|
The copy is in (2c3006e), signed off by the designer: the note now depends on whether the account has a linked identity (the same 🤖 Addressed by Claude Code |
|
Thanks for checking the predicate itself. Agreed on the low. Since three of the five sites are outside this PR ( 🤖 Addressed by Claude Code |
🤖 Claude Code ReviewVerdict: No issues found. Findings: 0 high, 0 medium, 0 low. Checked for bugs and CLAUDE.md compliance: i18n keys and 🤖 Generated with Claude Code |
What this is
Level Plutonium is now kept until a player's account is trusted (openfrontio/infra#933). This makes the game show that properly instead of offering a Claim button that would fail.
infra#933 must not deploy before this lands.
What changed
responseHasLinkedIdentity, or a CrazyGames sign-in).heldvalue the client doesn't recognise, or one that is malformed, still counts as held. Only an absentheldis claimable. One rule,isRewardClaimable(), decides it everywhere.held, the whole list is re-read (the hold is per account), with no "claim failed" alert.The end-of-game XP panel doesn't list rewards from
/users/@me/xp/:gameId, so it needed no change.Screenshots
All three use sample data: the rewards are injected into the local dev client; no account or API is involved.
Signed in, a held reward next to claimable ones (sample data):
Not signed in, the same rewards (sample data):
Phone width, 390px, signed in (sample data):
Testing
heldpresent, absent, null, unknown and malformed; claim-allheldwith good and bad rows.RewardsPanelandRewardsModaltests: label and note per variant (signed in or not, CrazyGames or not, other holds); Claim all hidden when only held rewards remain; claim-all keeps the held ones; a held 403 re-reads the list without the failure alert; the popup closes when nothing claimable is left.Apitests: a 403 without a usableheldfails generically.npm run typecheckandnpm run lintpass. The client test suite passes (3,991 tests).🤖 Generated with Claude Code