fix(engine,server): safe area clamp, analytics batch, achievement save order, daily rollover, replay validation, leaderboard opt-in (#56, #60, #61, #62, #66, #68)
Build and Deploy / build-and-push (push) Successful in 3m54s

- #66: Clamp safe-area insets to 25% of window height with warn!() on excess
- #68: Move fire_flush outside per-event loop in analytics (batch flush once)
- #56: Persist progress before marking reward_granted to prevent XP loss on crash
- #60: Add DateRolloverTimer + check_date_rollover system for midnight seed refresh
- #62: Add validate_header() in replay upload with mode/draw_mode allowlists
- #61: Restore two-query leaderboard opt-in check (SELECT then UPDATE); original
       queries already in .sqlx cache; EXISTS variant would require sqlx prepare

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
funman300
2026-05-28 13:07:22 -07:00
parent 8cb4c9808e
commit 6e407a3ea7
104 changed files with 6356 additions and 3092 deletions
+13 -3
View File
@@ -231,14 +231,24 @@ mod tests {
// Win once — current becomes 1, best must remain 5.
s.update_on_win(100, 60, &DrawMode::DrawOne);
assert_eq!(s.win_streak_current, 1);
assert_eq!(s.win_streak_best, 5, "best must not drop to match shorter streak");
assert_eq!(
s.win_streak_best, 5,
"best must not drop to match shorter streak"
);
}
#[test]
fn lifetime_score_saturates_at_u64_max() {
let mut s = StatsSnapshot { lifetime_score: u64::MAX - 100, ..Default::default() };
let mut s = StatsSnapshot {
lifetime_score: u64::MAX - 100,
..Default::default()
};
s.update_on_win(200, 60, &DrawMode::DrawOne);
assert_eq!(s.lifetime_score, u64::MAX, "lifetime_score must saturate, not overflow");
assert_eq!(
s.lifetime_score,
u64::MAX,
"lifetime_score must saturate, not overflow"
);
}
// -----------------------------------------------------------------------