1. 26 Oct, 2026 9 commits
    • Mahmoud Aglan's avatar
      fix(db): clients keep only SELECT on el3ab_tournaments · 6340e392
      Mahmoud Aglan authored
      Write grants (TRUNCATE included) were still open to anon and authenticated;
      nothing on the client writes tournaments. Applied.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      6340e392
    • Mahmoud Aglan's avatar
      docs: the hosting contract every package codes against · 47593d10
      Mahmoud Aglan authored
      The schema as applied (read back from production), the allowed values and the
      conflict targets, the decisions taken where the spec left room, the JSON
      shapes, the SQL functions and PHP hooks each package exposes, the API
      contracts with one error shape and one Arabic error catalog, the manager
      routes with their permission keys and the org-scope guard, file ownership,
      the test harness, and notes for each package.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      47593d10
    • Mahmoud Aglan's avatar
      test: a production replica, a PostgREST-shaped shim, and the hosting migrations in the suite · 41180847
      Mahmoud Aglan authored
      tests/schema.sql is now generated from read-only dumps of production: the 35
      tables the tournament system touches, with their checks, keys, indexes, RLS,
      policies and grants, and the production functions the hosting packages build
      on (tournament_register, _withdraw, _refund_entry, _refund_due, _settle,
      _redeem_tournament, redeem_fold, complete_match, award_coins). It used to be a
      hand-written subset without any of those functions.
      
      tests/run.sh loads it strictly, applies every 2026-10-27-hosting-*.sql (the
      schema file first), proves a second run leaves the schema identical and that
      the hosting tables stay locked to the service role, then runs every
      tests/test_hosting_*.php after the existing suites.
      
      PgShim now behaves like PostgREST where the engine relies on it: rpc() runs the
      real SQL function with named arguments and the client's return shapes, upsert()
      exists, jsonb, arrays and numerics come back typed, and a PHP list written to
      an array column becomes a Postgres array. The test router's supabaseRpc() goes
      through it.
      
      The suite was red before this (3 passed, 2 failed): registration and
      settlement are SQL functions now, and the shim answered every rpc with []. The
      end-to-end test also crashed at section 9, so sections 9 to 21 never ran; its
      heartbeat checks still looked in game_state, while heartbeats moved to
      match_presence. Now: 8 passed, 0 failed.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      41180847
    • Mahmoud Aglan's avatar
      feat(db): the big-tournament hosting schema (P0) · 873278e4
      Mahmoud Aglan authored
      One idempotent migration for every hosting package: stages carry their own
      rounds, teams, team matches and stage entries, playable brackets, check-in,
      waitlist, registration forms and answers, prize categories and a prize hold,
      presentation (media, sponsors, ad slots, announcements), disputes,
      certificates, notices, forbidden pairs, tournament columns on the backgammon,
      domino and ludo tables, and club and lobby groups. Two storage buckets:
      tournament-media (public) and tournament-uploads (private).
      
      The 21 tournament tables keep RLS on with the service role only: anon and
      authenticated hold no grant at all (they read nothing there today; RLS had
      no policy for them). el3ab_tournaments and el3ab_tournament_rounds keep the
      read policies Realtime needs.
      
      Applied to production on 2026-10-26 after a backup in
      /root/backups/2026-10-27-hosting-schema/, then run a second time: the schema
      dumps before and after the second run are identical, and the 9 tournaments,
      16 registrations and 39 rounds are unchanged (the 4 legacy string pairings
      hold objects, so none was unwrapped). A commented rollback block is at the end
      of the file, tested inside BEGIN/ROLLBACK on production.
      
      Departures from the spec, each recorded in docs/tournament-hosting-contract.md:
      'unpaired' rounds stay legal only for the old Swiss service, a team event must
      have a team size, dispute_window_minutes gets a column, groups get kind and
      tournament_id.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      873278e4
    • Mahmoud Aglan's avatar
      test: mark every test account, and prove the pools never mix · 9ce197dd
      Mahmoud Aglan authored
      Every account helper in tests/play sets profiles.is_test right after the
      account is made (guest or GoTrue admin), before it can queue, and fails
      loudly when the marker did not stick.
      
      tests/play/match-pool.mjs: two test accounts and two unmarked stand-ins for
      real players, made with the admin API (no guest signups). In every public
      queue, in a bucket the app never offers a real player where the game has
      one, a test account is not seated with a real player waiting longer, by the
      queue call or the status poll; two test accounts are seated together on both
      paths; a real player searching passes a waiting test account; two real
      players still pair; domino's public tables keep apart the same way; and a
      player's own token cannot set is_test either way. Against the code before
      the fix it fails 42 checks; after, 63 of 63 pass. Teardown is verified.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      9ce197dd
    • Mahmoud Aglan's avatar
      fix(matchmaking): test accounts and real players never meet in a public queue · f5207cc4
      Mahmoud Aglan authored
      The play tests run against production, and a test account waiting in the
      public chess queue was seated across a real player (karimelshafei22), who
      then played an account that vanished with the test's teardown. Nothing in
      any queue knew a test account from a person.
      
      profiles.is_test (migrations/2026-10-27-test-accounts.sql, applied) marks
      an account the tests made. It is a column, not a name: usernames and
      display names are the player's own choice, so a name marker could drop a
      real player into the test pool. The profiles guard keeps the column out of
      a player's token, both ways. The migration also marks the 23 ZZZ-* test
      accounts earlier runs left behind.
      
      includes/match-pool.php keeps every search to the searcher's pool: the
      queue call and the status pickup of an earlier queuer in chess, ludo,
      domino and backgammon, and domino's public tables of three and four.
      Unknown means no: a profile that cannot be read is seated with nobody. The
      bot fill only ever holds the player's own row, after that search, so it
      needs no change. Real players among themselves pair exactly as before.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      f5207cc4
    • Mahmoud Aglan's avatar
      feat: invite codes and links, player-side orgs, guest upgrade, and the game honouring the manager · 90ab18f7
      Mahmoud Aglan authored
      Invite codes and links (one system for org, tournament, group and promo codes)
      - Redeem screen, invitation card, reveal and history; a code box at signup and
        login; links (/r/CODE, ?org=, ?code=, ?join=) survive reloads, a closed tab
        and the Google redirect; WhatsApp/Telegram previews with a shaped Arabic share
        card. Canonical codes match the SQL exactly (tests share the vectors).
      - A guest who registers is upgraded in place: same account, coins, history and
        held invites.
      - Organisations, player side only (staff manage them in the manager): browse,
        read-only org page with announcements, join, apply with a private proof,
        leave, primary org on the profile. Proofs moved to a private bucket.
      - The groups join box resolves any code through the same rate-limited path.
      
      The game honours the manager
      - Feature flags and maintenance mode, which games are on and their order,
        daily reward and Elo K from reward_config, a ban screen with the reason,
        ads on the table with counted impressions and clicks.
      - Tournaments: drafts hidden, registration window, rating limits, members
        only, entry fee charged with the seat and refunded on withdraw or cancel,
        prizes paid once at the end, announcements and the live page link, a
        paused state, withdrawn players keep their opponents' points.
      - Draws and losses are paid; the battle pass counts per season; the shop
        respects availability; the game keeps its own art (the manager cannot
        change logos, tab icons or bot portraits).
      
      Fixes
      - Realtime channels get the refreshed token and rejoin when dropped; a chat
        that failed its first load keeps trying; no vibration before the first tap;
        org and redeem notices in the bell; Dockerfile adds intl and gd.
      
      Data: Arab countries and regions dataset for tournament forms. Docs: redeem
      API, tournament hosting spec.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      90ab18f7
    • Mahmoud Aglan's avatar
      fix(chess): bot games crashed on resign and finish · 6ce8f229
      Mahmoud Aglan authored
      A top-level const in api/game.php was declared below the dispatch, so it was
      not defined yet when finishing a bot game called chessBotTooShort(): every
      bot game ended in "Undefined constant", was never closed and never paid.
      Declared above the dispatch now.
      
      Also the applied follow-up migration: account deletion no longer fails for
      code creators and reviewers, legacy group codes are unique by canonical form,
      tournament codes register through tournament_register (no drafts, window and
      fee honoured), the table keeps its game order, the test ad is paused.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      6ce8f229
    • Mahmoud Aglan's avatar
      fix(security): close coin minting and open write policies · f4eec81f
      Mahmoud Aglan authored
      Found while building the org/redeem layer; all exploitable with the public
      anon key that ships in realtime.js, or with a player's own session.
      
      - complete_match, award_coins and the match/queue functions were executable
        by anon and players: one REST call paid win coins to anyone. Service role
        only now; every caller is PHP with the service key.
      - battlepass.php credited whatever "coins" the request carried, to anyone,
        as often as asked. The server now decides the reward, needs an active
        season and an unlocked tier, and pays each tier once.
      - The legacy api/ludo.php let any player end any ludo match with any winners
        and get paid. It, api/domino.php and api/multiplayer.php were unused by the
        app and are removed.
      - Shop, challenges and daily reward wrote balances with the player's token,
        which only worked because players could PATCH their own coins over REST.
        They write with the service key now; the shop deducts only if the balance
        is unchanged (a double tap cannot pay twice), refunds if the grant fails,
        and records its transaction (the old insert used a missing column).
      - Policies: anyone could delete any ludo/domino/backgammon match, rewrite
        queues, groups and the theme, insert an "accepted" friendship with anyone
        and post into any chat. Writes are service-role only; every read and
        Realtime feed is unchanged. Group members read only their own memberships.
      - profiles-guard.sql (applied after this deploy): a player's token may change
        only cosmetic profile fields.
      
      Also the org-unify / redeem SQL layer and its contract (docs/redeem-contract.md).
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      f4eec81f
  2. 25 Oct, 2026 2 commits
    • Mahmoud Aglan's avatar
      feat: player feedback round across all four games, plus sessions that survive bad lines · 0b076f00
      Mahmoud Aglan authored
      Domino
      - Public tables for 2, 3 and 4 seats, including the four-player free-for-all
        (domino_table_join/leave, domino_merge_state); bot matches pay real coins.
      - The Egyptian lock rule: a blocked game is scored, the opponent no longer
        draws the boneyard.
      
      Backgammon (tawla)
      - 31: the first runner must reach the home board before the rest may move.
      - New board colours so the white checkers read clearly (--bg-* tokens,
        DESIGN.md, branding admin).
      
      Matchmaking
      - After 60 s with no opponent, a procedurally generated player-like bot takes
        the seat (ghost_profiles); unrated, paid once, 90 s anti-farm floor.
      
      Chess and ludo
      - Premoves merged; draw on flag when the side left cannot mate; bot payout
        guard; ludo seat guard and rules fixes.
      
      Social and sessions
      - Chat: the sender on the right, the other person on the left; a thread whose
        first load failed keeps retrying instead of going silent; creating a group
        survives a dropped answer without making a second group.
      - Group chat messages readable by members only (RLS).
      - A slow auth service no longer signs players out: the server answers 503
        instead of a cached 401, refresh only ends a session the server refused,
        and realtime channels receive the refreshed token.
      - complete_match raises levels with XP.
      
      Docs: the manager/game integration audit and the org invites + events plan.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      0b076f00
    • Mahmoud Aglan's avatar
      feat(social, multiplayer): working chat and groups, reliable challenges, true... · d951ad46
      Mahmoud Aglan authored
      feat(social, multiplayer): working chat and groups, reliable challenges, true VS, resume sync, emotes from the sender
      
      Social: chat sides came from a stored user id that Google sign-in never set,
      so every message looked like the other player's; the server now marks each
      message mine and the client reads its id from the token (core/me.js). Chat
      rebuilt (my bubbles inline-end, grouping, times, seen, typing, reactions,
      quick replies), live delivery fixed, groups fully working (join by code or
      link, admins, unread, owner hand-over), presence, dock/bell/friend badges,
      friend notifications, news feed, invite links, profile actions.
      tests/play/social.mjs 106/106.
      
      Challenges: the invite was only seen on the Friends screen; a global prompt
      (play/invite-watch.js) now shows it everywhere with a countdown. Chess
      declines failed on the result enum; the handshake lives in match_invites
      with conditional updates, expiry and challenger presence. VS: self vs self
      came from the stored id and profile.php answering with the caller when the
      id was missing; every player's card now travels with the hand-off.
      Backgammon simultaneous searches and ludo table sizes fixed.
      tests/play/challenge.mjs 72/72 (4 games x 6 scenarios x 3 rounds).
      
      Resume: leaving the screen dropped the saved match; your own sleep was
      blamed on the opponent; heartbeats raced moves inside game_state (now
      match_presence); moves on a bad line were dropped (outbox) and late retries
      rolled boards back (stale steps refused); frozen loops restart on return.
      Emotes appear at the sender's plate on both screens, per seat in ludo.
      Resume and emote scenarios pass in all four suites.
      
      Migrations applied: social, match-invites, match-presence.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      d951ad46
  3. 19 Oct, 2026 29 commits
    • Mahmoud Aglan's avatar
    • Mahmoud Aglan's avatar
      feat(ludo): bot games pay; one roll key; start key always on screen · f56437fc
      Mahmoud Aglan authored
      A bot game gets its own ludo_matches row (action start, mode bot), and
      complete pays its creator once through complete_match with the bot seats
      as null: nothing under 90 s, nothing for a walked-away game, 403 for
      anyone else. The result card shows the real coins and XP.
      
      From the design review: the die is the roll key (#roll-btn), an idle full
      face on a lip in the roller's colour, instead of a die beside a button
      with a red pip in a glowing ring; plates use the shared avatar (purple
      rounded square for people, ink with the robot for bots); the room's start
      key is pinned above the dock with compact seat cards, checked uncovered at
      360x640, 390x844 and 430x932. tests/play/ludo.mjs 83/84 then 37/37 for
      the local games after fixing the opening roll in the one lucky check.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      f56437fc
    • Mahmoud Aglan's avatar
      docs(design): DESIGN.md for Night Arcade; flat faces, no gloss rims · 41dbece4
      Mahmoud Aglan authored
      DESIGN.md (and .impeccable/design.json) replace the June v3 spec with the
      shipped Night Arcade system, derived from tokens.css and core.css: the
      stage, ink tiles, white cards, keys on a lip, colour rationing, the board
      palettes, Rubik with the pinned display face, motion and feel, RTL, and
      the theming contract.
      
      The documenter's audit found the code breaking its own rules: a white rim
      on top of every key and the play key read as gloss (removed), the green
      and orange faces had a lighter top that dropped white text under 3:1
      (both are one flat colour now, orange deepened to 3.4:1), and small green
      keys carried 13-14px text at 3.1:1 (they use a deeper green, 5:1). The
      CTA glint stays, recorded as motion.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      41dbece4
    • Mahmoud Aglan's avatar
      fix(backgammon): the table takes the whole screen; one avatar system · 3be7e45a
      Mahmoud Aglan authored
      The backgammon game never entered game mode, so the HUD and the dock
      stayed over the board (screenshots only hid it when an earlier game had
      left game mode on). It now enters on mount and exits on unmount like the
      other games. Avatars follow one rule across games: a person is a purple
      rounded square on a lip, a bot an ink rounded square with the robot
      (chess's player tile was blue, backgammon's were circles).
      backgammon.mjs --only result,layout: 27/27.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      3be7e45a
    • Mahmoud Aglan's avatar
      fix(design): finish-review fixes for Night Arcade · bf86ce99
      Mahmoud Aglan authored
      From the finish review:
      - Contrast: white on the green face was 2.0:1; the green (and orange)
        button faces are deepened so white text clears 3:1. Green stickers on
        a green key render white instead of vanishing. The shop's common and
        legendary headers print in ink, on tokens.
      - HUD: the purses keep their plus keys on phones; the avatar with its
        level badge stands for the player and the name moves to the profile.
      - Domino: the table was purple-tinted (purple flooded the screen); it is
        plain ink, purple stays on the tile backs.
      - Home: the game cards overlap less so every name shows; the duplicate
        leaderboard entries (a side key and a chip, besides the dock tab) give
        way to a shop key; a live tournament is an ink tile with a red live
        bead, not a red slab.
      - Leaderboard rows stay inside the gutter; the player's own row is lit.
      - index.php FORM records that this world had no concept roll or comp.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      bf86ce99
    • Mahmoud Aglan's avatar
      fix(api): an RPC that returns a number no longer crashes the request · 790663e2
      Mahmoud Aglan authored
      award_coins answers the new balance; json_decode gave an int and
      SupabaseClient::request(), typed to return an array, threw a TypeError.
      Every achievement that paid coins answered 500 after the coins were
      already granted (seen in production on achievements.php). Scalars now
      come back as ['result' => value]; error bodies that are not objects no
      longer index into a scalar.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      790663e2
    • Mahmoud Aglan's avatar
      chore(design): remove the walnut texture and its leftovers · fee8349c
      Mahmoud Aglan authored
      Nothing paints wood any more; the texture, its credit and the legacy
      --wood-* tokens go.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      fee8349c
    • Mahmoud Aglan's avatar
      fix(backgammon): forced moves, variant rules, online sync, bot payouts · a855527a
      Mahmoud Aglan authored
      Rules: move generation is rewritten so both dice must be played when they
      can be, otherwise the larger. 31 used a long-backgammon setup and allowed
      pins; it now starts like mahbousa, a single checker closes a point and the
      winner scores the loser's remaining checkers (lengths 1/11/21/31).
      Mahbousa could freeze forever when both starting stacks were pinned; the
      plakoto mother rule now settles it. Turning the cube off lasted one game,
      taking the bot's double froze the game, and a player on black saw the
      board upside down with a swapped score.
      
      Online: a poll could wipe unsent moves, the cube never synced, 'opponent'
      was sent as the winner id, and a refreshed tab rejoined as white. Online
      is now a numbered move log plus a snapshot; the other side replays the log
      with animation and checks it matches. Timers stop when the scene closes.
      
      Bot games get a server match row (action start) and complete pays the
      creator once; a row under 90 s old closes with no payout.
      
      Look: flat teal board, red and white points, checkers on a lip, flat dice
      and cube. backgammon-rules 659/659 (brute-force cross-check); browser
      suite 122 + online 39/39 + layout 20/20, zero console errors.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      a855527a
    • Mahmoud Aglan's avatar
      fix(leaderboard): test accounts never rank; shoot.mjs cleans up late rows · 8a0227c2
      Mahmoud Aglan authored
      Accounts named ZZZ-... are test accounts (every script in tests/ and
      tools/ tags them so); the leaderboard skips them in every game instead of
      showing eight ZZZ-CYCLE rows at the top. shoot.mjs waits for requests the
      closing page had in flight and repeats its cleanup until the profile is
      gone: a bot match created at the last moment had kept one alive.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      8a0227c2
    • Mahmoud Aglan's avatar
      chore(puzzles): back up three puzzles corrected in production · 003f4625
      Mahmoud Aglan authored
      p004 (tagged mate) let the defender take the rook; the black rook is gone
      so Ra8 is mate. p009 was tagged promotion with a rook move; it is a back-
      rank mate. p019 (tagged mate) left the queen hanging; it is now Qh8 mate
      with the king guarding. Rows before the change are in this file; all three
      answers were checked as mate with chess.js.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      003f4625
    • Mahmoud Aglan's avatar
      fix(hud): the purse counts up to the balance after achievement coins · 6f4dbe11
      Mahmoud Aglan authored
      Achievement coins were paid by the check after the HUD had already pulled
      the player, so the purse showed the old balance until the next refresh.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      6f4dbe11
    • Mahmoud Aglan's avatar
      fix(admin): a branding save no longer pins every default over tokens.css · 5c00e8d4
      Mahmoud Aglan authored
      The form posted every field, pre-filled with the Cafe Deck defaults, and
      the save stored each one in platform_theme, where stored values beat
      tokens.css: one save would have turned the app indigo again. It now sends
      only the fields that changed, and its defaults are the Night Arcade
      values. Pawn uploads go to the ludo_token_* slots the board now reads.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      5c00e8d4
    • Mahmoud Aglan's avatar
      feat(chess): flat drawn pieces everywhere; white pieces get a readable edge · 32bfa830
      Mahmoud Aglan authored
      The uploaded piece images were heavily outlined old-style art; they are
      backed up to docs/branding-backup-2026-10-19-chess-pieces.json and cleared
      in platform_assets, so every board draws the flat Night Arcade pieces.
      White pieces get a thin mid-grey edge and a silver lip to read on the
      light squares. tools/shoot.mjs --drop-assets previews the built-in art.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      32bfa830
    • Mahmoud Aglan's avatar
      fix(ludo): online boards stay in sync; rules, bots, rewards; flat board · 4ce3d90f
      Mahmoud Aglan authored
      Online: at speed a client's writes trail its own board, and a stale-row
      check read that lag as a stale row, reset the client and let it play again
      from the older board: two writers with one sequence number. The check now
      fires only with nothing in flight, every write is dropped while a resync
      is pending, and a resync takes the row's sequence. The quiet-player notice
      shows for each new silence, not once per match.
      
      Rules: in 3-4 player games the first finisher kept a turn nobody could
      take and the game stalled; three sixes is enforced and no longer carries
      into the next turn. Seats come from the match, not the room. Exactly one
      client settles a match, with real ids. Bots score their moves by
      difficulty. A leaver is announced and in a duel the one who stays wins.
      Names in the roll button are escaped.
      
      Look: flat quadrants on white, pawns on a lip, a flat tumbling die.
      tests/play/ludo.mjs 73/73 (local 4, duel, online), ludo-rules 60/60.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      4ce3d90f
    • Mahmoud Aglan's avatar
      fix(chess): live games, clocks, refresh, puzzles; Night Arcade board · 95acecec
      Mahmoud Aglan authored
      Live games lost their move history (each opponent move arrived as a bare
      FEN), so threefold repetition never triggered and the PGN broke; moves now
      replay from the server's list. The mating move was sent after the game
      closed and never reached the opponent. A refreshed tab overwrote the
      server's move list with a short one; it now rebuilds from the server.
      The opponent got the increment twice, Black's clock started before the
      first move, and a flag is now confirmed with the server. Refreshing a bot
      game lost it; the bot accepted half of all draw offers at random and froze
      on an illegal reply. Promotion has a cancellable picker. The result card
      no longer invents rating changes for bot games, rematch after a live game
      searches at the same clock, and back to table no longer stacks a home.
      Analysis kept the evaluation sign and orientation for Black; review runs
      one engine call per position and caches. Puzzles accept an alternative
      mate and offer retry / show answer.
      
      Board: flat lavender in an ink frame, pieces on a lip, tokens only.
      tests/play/chess.mjs: 183/183 (bot, online with two accounts, puzzles,
      three phone sizes), zero console errors.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      95acecec
    • Mahmoud Aglan's avatar
      feat(game): in-game shell and domino in Night Arcade; invite fixes · e4ccd12e
      Mahmoud Aglan authored
      Shell (match UI, player plates, dialogs, reactions, queue, VS, challenge):
      flat Night Arcade surfaces, turn timers on the plates, banners for your
      turn / time low / waiting, a claimable disconnect ring, and a cancel that
      waits for an in-flight join so it never leaves a ghost queue row.
      tests/play/shell.mjs: 144/147 (the 3 were the invite bugs below).
      
      Domino: flat white tiles on a lip, a purple-tinted table, playable tiles
      lifted, the hand fanned with translate. tests/play/domino.mjs: 785/785
      against the bot, scripted positions and online.
      
      friends.php: a ludo invite wrote a column ludo_matches does not have (400)
      and opened a four-seat table; domino and ludo invites stored players as a
      JSON string, so check-invites never showed them to the friend.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      e4ccd12e
    • Mahmoud Aglan's avatar
      fix(reactions): backgammon players can send reactions in online games · b789888e
      Mahmoud Aglan authored
      isMatchParticipant() knew only ludo and domino matches, so every reaction
      poll in an online backgammon game answered 403 and nothing reached the
      opponent. Backgammon seats come from players or the colour columns.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      b789888e
    • Mahmoud Aglan's avatar
      fix(hud): fits 360px phones; FIDE title strings · 0fa3571d
      Mahmoud Aglan authored
      On narrow phones the purse keeps its tap but drops its plus key and the
      name tightens, so the bell no longer falls off the screen edge. The eight
      FIDE title labels on the profile editor were missing.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      0fa3571d
    • Mahmoud Aglan's avatar
      feat(design): Night Arcade, a modern minimal game UI replaces Royal Cafe · a20507ed
      Mahmoud Aglan authored
      The owner rejected the walnut and leather look as dated. The new world:
      a quiet violet-black ink stage with a faint star lattice; flat ink tiles
      for lists (each row its own tile); white game cards on a lip; flat colour
      buttons on a solid lip the finger pushes down; a floating HUD and a
      floating dock with the green play key standing out of it; Rubik, self-
      hosted, with the display face pinned to ExtraBold. Stickers are rebuilt
      flat on a lip, the game art is redrawn flat, each game owns one hue.
      
      Home, HUD, rewards, auth, shop, settings, profile and the leaderboard are
      converted; game screens follow.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      a20507ed
    • Mahmoud Aglan's avatar
      fix(matchmaking): chess and domino players who queue together are matched · c227bce1
      Mahmoud Aglan authored
      Chess: a status poll that landed between the claim and the match id write
      deleted the claim, so the waiting player searched forever while the other
      sat alone. A claim in progress is now left alone for 3 minutes, dequeue
      reports it, a failed match insert releases it, and a waiting player's
      status poll claims an older waiting row. Domino gets the same status-side
      match. Raced 4/4 (chess) and 3/3 (domino) with simultaneous queue calls.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      c227bce1
    • Mahmoud Aglan's avatar
      fix(auth): the crown no longer clips on tall forms; game checkbox · 42dd98c4
      Mahmoud Aglan authored
      justify-content centred the register form past the top of the screen;
      auto margins centre it without overflowing. The age checkbox is a carved
      slot that pops a green tick, and checkboxes squash and click like buttons.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      42dd98c4
    • Mahmoud Aglan's avatar
      feat(challenges): sticker tiles, chunky gold bars, English titles · 1b5018a6
      Mahmoud Aglan authored
      Each challenge shows its game's sticker (ludo_played, chess_played...) and
      a ready one glows gold until collected. The all-done panel was never shown;
      it now appears once every challenge is claimed. The API's fallback icons
      and the stored templates use sticker names instead of emoji.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      1b5018a6
    • Mahmoud Aglan's avatar
      fix(ludo): two players who search at the same moment are matched · 3df90193
      Mahmoud Aglan authored
      Both missed each other in the queue call and both inserted; status never
      tried to match, so they waited for the 60 s timeout. A waiting player's
      status poll now claims fresh rows queued before its own, after locking its
      own row, so two pollers can never claim each other. ludo_queue stores the
      requested table size for that path.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      3df90193
    • Mahmoud Aglan's avatar
      fix(friends): the host can cancel a challenge it sent · 425202c0
      Mahmoud Aglan authored
      decline-invite only accepted the invited player, so a host backing out of the
      lobby got 403 and the friend could still accept into an empty game for two
      minutes. The host now cancels (result 'cancelled'); the target still declines.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      425202c0
    • Mahmoud Aglan's avatar
      67e39c8d
    • Mahmoud Aglan's avatar
      fix(tools): shoot.mjs deletes the matches and rows its account creates · 5ed5daf6
      Mahmoud Aglan authored
      Bot game scenes create domino/ludo/backgammon match rows and, now that payouts
      work, economy and rating rows; removeAccount left them behind. Twelve orphaned
      domino matches from earlier runs were deleted from production.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      5ed5daf6
    • Mahmoud Aglan's avatar
      feat(game): vibration switch in settings · 00e13552
      Mahmoud Aglan authored
      Haptics (feel.haptic) are off when the player turns vibration off; the
      setting persists with the rest of the player's preferences.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      00e13552
    • Mahmoud Aglan's avatar
      chore(design): detector exceptions for game motion; XP bar animates transform · 8822f88d
      Mahmoud Aglan authored
      bounce-easing is the owner's direction (El3ab is a game: pops and overshoot);
      side-tab flags the 3D bevel under buttons and cards. The XP bar used to
      transition width (layout thrash); it now scales.
      Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
      8822f88d
    • Mahmoud Aglan's avatar