This release includes: Website can read the lottery rule parameters again; H5 dependency lockfile encoding canonicalized; Client slow-request alerts: endpoint names, Safari timing and probe timeouts attributed; Game Center now has Popular, New games and All games tabs; Development: every worktree runs its own backend on its own ports; Tighter Niu Niu opponent hand-detail row; and 35 more changes.
Website can read the lottery rule parameters again
Build fix, no gameplay change. The TOTO, Shuangseqiu, Happy 8 and Fucai 3D rule modules import the draw-log helper by relative path so the marketing site rules pages build again.
- Lottery rule modules use relative imports so the website builds again
H5 dependency lockfile encoding canonicalized
Build housekeeping, no gameplay change. One package checksum string in the H5 dependency lockfile now uses the repository's equivalent escaped encoding; dependency versions and checksums are unchanged.
- One H5 lockfile checksum string uses an equivalent escaped encoding; dependencies unchanged
Client slow-request alerts: endpoint names, Safari timing and probe timeouts attributed
Operations alerting fix, no gameplay change. About 40 endpoints (player stats, club avatar/name, Sic Bo and Baccarat room bets, Guandan events, tournaments, beans, email preferences and more) used to appear in slow-request alerts as an unrecognised endpoint; they are now grouped by their real route. iPhone Safari behind a proxy withholds Resource Timing phases; such samples are now labelled as withheld instead of posing as measured. Probe timeouts whose reply the server flushed within 100 ms but the client never received within 5 s are now logged as warnings instead of paging per sample; requests whose time sits only in the browser's own queue and in long tasks observed inside the response-callback window (page transitions, table mounts) are warnings too, and many clients at once still page once.
- Slow-request alerts group by the real endpoint instead of an unrecognised one
- Requests slow only on the player's network or phone browser log as warnings instead of paging
Game Center now has Popular, New games and All games tabs
The home hub opens on the Popular tab: yesterday's Top 3 by visitors (Texas Hold'em, Zha Jin Hua and Niu Niu while the ranking is unavailable or empty). Games launched in the past month gather under a New games tab (hidden when there is none; a dot marks a launch from the past week). All games lists every game by yesterday's visits with the tools last and a Cards / Board / Casual filter. The former six-card Games & tools block and its expand button are gone. Guests now see the notifications bell too, so feedback replies reach them. H5, Android and iOS share this hub.
- The hub shows yesterday's Top 3; switch to All games for the rest
- New games stay findable under New games for a month
- Guests get the notifications bell too
Development: every worktree runs its own backend on its own ports
Local development backends now share the runtime lock so several worktrees can each run a backend against the one local database; each live room is driven by exactly one backend, and worktree backends skip startup recovery and owner sweeps. The engineering blog posts are updated to match.
- new-session.sh allocates backend/dealer/Vite ports and writes the matching E2E target config
- Per-room OS file locks stop two local backends from driving the same room
Tighter Niu Niu opponent hand-detail row
The opponent seat's 'Bull N ⓘ' row no longer leaves empty space above and below it and lines up with plain rank labels; the 44px tap target is unchanged.
- Opponent hand-detail row sits tight under the cards
Lottery draws now play out ball by ball with draw numbers, live hit counts and recent-draw history
SSQ, Toto, Happy8 and Fucai3D save the result on tap, then reveal it ball by ball from a drawing machine (three digit drums for Fucai3D): matched numbers light up with a gold ring and a live hit counter, followed by the prize tier and payout. Each draw has a period number, the last 10 draws are one tap away, and hot numbers are flagged on the grid; quick pick flickers before settling; tap to skip, instant under reduced motion. Scratch cards count the prize up and pulse winning spots at settlement with a bigger celebration for large wins. Odds, payouts and rules are unchanged.
- Ball-by-ball draws with gold-ring hits and a live counter
- Draw numbers, last-10 history and hot-number badges
- Scratch settlement count-up and winning-spot pulse
Sic Bo dice roll animation and betting feel upgrade
The Sic Bo table now rolls real 3D dice: the cup drops, shakes and lifts, each die tumbles and lands in turn, and a Big/Small/Triple stamp lands on the felt. Chips in the rack look like real chips, stakes show as a chip stack, other players' wagers fly from their seats to the zone, the countdown wears a draining ring, the recent roll trail stays on the felt, and a one-tap Rebet repeats last round's wager.
- 3D dice tumble and land; the cup drops, shakes and lifts
- Big/Small/Triple result stamp and winning-zone burst
- Real chip tokens and stacks; other players' wagers fly in
- Countdown ring and on-felt roll trail
- One-tap Rebet of last round's wager
Niu Niu and Sangong opponents' cards match the hero's size
Opponents' cards on the Niu Niu and Sangong tables are no longer thumbnails: they use the hero's card size, fanned so every corner index stays visible, on the phone three-column seats and the desktop layout alike.
- Opponent cards share the hero card size
- Fanned so each card's corner index shows
Slow-request pages only when the server is at fault; QA regression stops re-downloading assets
When the browser has no matched Resource Timing entry it only has fetch boundaries; samples whose server span is within budget and whose client processing phases are normal now log as warnings like other network-only samples. The QA regression relay keeps cacheable static responses on disk across runs, so a build's voice packs, sounds and chunks leave the production host once instead of competing with players for its 2 Mbps egress.
- Slow requests dominated by fetch_headers / body_read with the server within budget log as warnings
- The QA relay caches static responses across runs per upstream Cache-Control
Verification-code requests reply immediately; sending runs in the background
Requesting an email verification code now replies as soon as the local checks pass and the challenge is stored, instead of waiting ~0.5–1 s for the mail provider; the mail is sent once, with a time bound, in the background. A failed send retires that challenge at once and raises the existing alert, so the user's next request is not blocked by the cooldown; a code still only verifies after the mail actually left.
- Code requests no longer include mail-provider time
- A failed background send retires the challenge so a retry is not throttled
Admin daily report registration-environment stat uses indexes
The daily report's registration-environment breakdown now reads only the day's registered accounts and their own events instead of recomputing every account and every telemetry event; registration events sharing one timestamp take the first by time. Admin-only; no player-facing change.
- Registration-environment stat drops from ~70 s to tens of milliseconds
Stop stale Guandan room reconnects
Check authoritative membership after disconnection, stop reconnecting after a confirmed lost seat, retain recovery on network failure, and ignore stale checks. The server no longer lets later moves in a room the player left clear their membership in a newer room.
- Stop reconnecting after confirmed seat loss while preserving network recovery
- A room the player left no longer overwrites their newer seat
Faster bot turns in Zhajinhua
Zhajinhua bots now think for about 0.35–0.75 s per action (half the previous delay) and pause less after looking; against five bots, waiting on bot turns drops from an estimated 6 s to 3 s per round (a little more when bots look). The action right after a compare keeps the old pace so the duel verdict stays readable; the 5 s between-hands gap and other games are unchanged.
- About half the waiting on bot turns
WebSocket latency alerts use server flush evidence for network-only slowness
Slow table probes and action acks now log as a user-network warning when the server's own same-trace evidence shows the reply was flushed within 100 ms; missing, pending or failed evidence still pages as before.
- User-network slowness no longer pages as a server fault
Unchanged sign-in probe no longer re-downloaded
GET /api/auth/me now carries a strong ETag; the client remembers the last reply in memory and revalidates with If-None-Match, so an unchanged profile answers 304 with no body (cookie refresh and no-store unchanged). Saves 4–30 KB (own avatar image included) on every re-probe while the app is still in memory (foreground, reconnect) on the shared 2 Mbps uplink; a cold start still downloads once. The opponent-avatar batch read already omits unchanged images via known avatar_tags; verified, no change needed.
- /api/auth/me answers 304 when unchanged
- Avatar batch read already reuses avatar_tags; verified
First load downloads only the active language's copy
Every first visit used to download the full bilingual UI copy (about 190 KB compressed). Copy is now bundled per language and a page fetches only the active one (a Chinese visit downloads about 109 KB compressed, roughly 44% less); switching loads the other language on demand. Strings, keys and switching behaviour are unchanged; first paint is faster on the capped server uplink.
- About 44% (zh) / 46% (en) fewer compressed bytes of UI copy on first load
- The other language's copy loads on demand when switching
Two male voice packs are about 75% and 50% smaller, cutting first-load traffic
The general male voice pack had been encoded at 128 kbps (1.5 MB) and the Niuniu male pack at 64 kbps, while every other pack is 32 kbps. At the server's 2 Mbps egress, one player's first load of the 1.5 MB pack takes an estimated 6 seconds, during which it competes with other players' downstream traffic. Both packs are now re-encoded with the same settings as the rest (mono, 24 kHz, 32 kbps), shrinking to 378 KB (about −75%) and 87 KB (about −50%); each file's decoded sample count matches the original, so the existing clip timetable is reused and callout content and timing are unchanged.
- General male pack 1.5 MB → 378 KB, Niuniu male pack 174 KB → 87 KB
- Decoded sample count matches the original; the existing clip timetable is reused
Retransmission figures in the ops notes corrected
Replaces the proxy namespace's 60-second total retransmission ratios (which included SYN-ACK retransmits for unfinished handshakes) with the established-connection lifetime ratio of retransmitted over sent TCP segments (6.3%, worst peers 10–16%). Documentation only; no runtime change.
- Documentation wording only
Thin connections no longer double their retransmission timer for the first 6 timeouts
At evening peak, connections in ESTABLISHED state at the sampling moment showed cumulative retransmitted TCP segments over cumulative sent TCP segments (`ss -tin` retrans total / segs_out, the denominator including pure ACKs) of 6.3%, and 10–16% on the worst peers (a lifetime retransmission count, not a direct loss rate, and not comparable with the namespace-wide 60-second ratios of 20.6–22.6% that night, which also counted SYN-ACK retransmits for unfinished handshakes, a suspected low-rate SYN flood). On established connections the kernel classifies as thin at a retransmission timeout (fewer than 4 segments in flight and past initial slow start; a per-connection property, not message size: qualifying table WebSocket and HTTP/2 connections may benefit, the tail of a bulk transfer may qualify too, a small reply on a busy connection may not), the first 6 timeouts use the estimated RTO instead of doubling it, at the cost of somewhat more retries under congestion (bounded). The effect on player stall times is not yet measured. Already set live; the next release persists it.
- No exponential backoff for the first retries of qualifying thin connections (effect to be measured)
One three-minute end-to-end check replaces unit tests
Every change is now verified by one end-to-end run that plays all 25 games against the real server, starting with the three most played, and must finish 100% green within three minutes. Unit and integration test code and its dead hooks were removed; game behaviour is unchanged.
- All games verified end to end on every change
Server egress now queued below the bandwidth cap
The server's public link is a fixed 2 Mbps and the provider drops packets above it. The host now queues below the cap with per-flow fairness. Measured as total retransmissions in the Caddy network namespace (not attributed to specific connections or players): for the same 876 KB sound download, retransmissions fell from 223 in a 12-second window to 30 in a 14-second window; small flows such as table messages are scheduled ahead of bulk files, which is not a guarantee for any single player, and bulk downloads themselves get slightly slower.
- Far fewer total server retransmissions during bulk downloads (namespace totals, not a per-player guarantee)
Poker table sound file about 9× smaller
The poker table's card and chip foley file changes from an 877 KB uncompressed WAV to a 95 KB MP3, keeping the original recordings and clip timing, which cuts the first table entry's download size and bandwidth use.
- Smaller download on first table entry
Feature usage and game popularity use daily rollups
The admin feature-usage report and the lobby's game popularity ranking now read daily rollups instead of scanning every visit, so they stay fast as traffic grows.
- Feature usage report completes at large scale
Tables no longer back up saves when the database is busy
When database writes slow down, Dou Dizhu, Zha Jin Hua, Niu Niu and similar tables merge consecutive ordinary state saves into one write; settlements and seat changes are still saved one by one, so moves and timed auto-plays are paused less often.
- Fewer table stalls when the database is busy
Hub popular games no longer stall
The daily popular ranking now refreshes in the background; while it updates, the hub immediately shows the previous ranking instead of waiting seconds.
Feedback alerts recognise HarmonyOS phones
Player-feedback alerts now label HarmonyOS phones as HarmonyOS instead of desktop/other.
- More accurate feedback platform labels
Admin report tests stay reliable at large data volumes
Admin report tests now check only their own fixture data, so they run reliably against a million-user database; player features are unchanged.
Isolated request-body waits no longer page
Isolated request-body waits on telemetry and avatar lookups, where measured server wake/poll time is not dominant, now log a warning; the fifth and later in one fixed 10-minute window page, and scheduling-dominated or unmeasured waits page immediately.
- Fewer isolated request-body-wait alerts
Scratch cards offer a refill when coins run short
When practice coins cannot cover the selected tickets, the purchase area now shows the refill button directly instead of hiding it in the menu.
- One-tap refill when short
Membership campaign stats no longer scan every account
Admin membership-campaign eligibility now reads an hourly account counter, so it stays instant with many accounts while returning the same numbers.
- Faster campaign statistics
Choose your club number when creating a club
Club numbers are still random by default; tick “Choose the club number” to pick any unused six-digit number.
- Pick your own club number
Admin insights: ratings and notification stats use live counters
Admin insights now keep play-rating and notification-campaign stats as they are written instead of rescanning all history; windows are whole days and campaigns show fixed labels without stored notification titles.
Admin business metrics read summary tables
Sign-ups, daily/weekly/monthly actives, retention and Pro members now come from write-time summary tables or primary-key lookups, so the admin business report no longer scans every user and event at large scale.
- Admin business report stays fast at scale
Admin growth insights count actions and errors by day
The admin growth insights sections for actions, failures, WeChat entry points and client errors are now counted by day as data is written, so they stay fast as data grows; windows align to whole days.
- Admin insights stay fast at large data volumes
Admin monetization report reads write-time counters
The monetization report no longer rescans raw telemetry and game records every minute; it reads counters the statistics writer keeps as data is written, so it stays at milliseconds as data grows.
- Admin monetization report stays fast at scale
Admin growth and retention reports read daily totals
The admin sign-up cohort, games and retention reports now read running daily totals, so they stay fast as the player base grows; windows count whole days.
- Admin reports stay fast at large scale
Admin reports identify test accounts faster
When admin reports exclude internal and test accounts, they now read a dedicated index of test traffic instead of checking every guest account; the counting rules are unchanged.
Creating a room right after leaving no longer says you are in another room
In room games such as Niuniu, Sangong and Dou Dizhu, creating or joining right after leaving now waits for the previous room to finish saving instead of wrongly saying you are in another room.
- Smoother create right after leaving
Admin activity counts accumulate as events arrive
The admin hourly, daily and 7-day active counts now accumulate as events are written, so the report reads a few summary rows and stays in milliseconds as users grow.
- Admin activity stays fast at large user counts
Admin reports compute only while someone is looking
Admin reports no longer recompute every minute in the background; they are computed only while staff have the page open, leaving the database to the games. The first open briefly waits while the report is computed.
- Games no longer compete with admin reports for the database