The reveal turned your own cards face down, and four more from review

Fixkamo-internal
Shipped
September 8, 2026 at 6:17 PM UTC
Author
Kamo
Commit
b2d9bf0

An adversarial review of the choreography commit, verified against the code. Six defects, two of which only a browser could have shown. YOUR OWN CARDS. The showdown reveal built its order from every seat with a shown hand — which includes YOURS, because the server sends showdownRank for everybody who showed, viewer-independent. So a showdown began by turning the reader's own cards face down and giving them back a second later: the felt taking away the one thing on the table you are always entitled to see. showdownOrder now excludes the reader, and there is a test that says so. AND IT DID IT A FRAME LATE. The reveal gate lived in an effect, and an effect lands one paint after the commit that carries the cards. The frame that completes a hand is also the first frame carrying everybody's hole cards, so every showdown painted all hands face up and then turned them all down. The gate is computed during render now, from a ref keyed on the hand; the state entries that remain are alarm clocks whose only job is to be a state CHANGE at the moment a card is due — see the note in the file, and **************** A FOLDED HAND SHOWED BLANK WHITE FRONTS. `filter` is a grouping property: any value but `none` forces the used value of `transform-style` to `flat`, which collapses the 3D context the card is built from and takes `backface-visibility` with it. The dim was on the element holding the two faces, so a face-down card showed its front through its back. Moved to the wrapper. Every test passed either way; a browser did not. THE MUCK SNAPPED BACK. The fold-away fills `forwards`, so the cards hold their pushed-away position — and the flag expiring 100ms later put them back on the felt at full opacity. A folded hand stays out of the way until the next deal now, which is what "decision made, this player is out of this hand" looks like. PLAYER_ELIMINATED COULD NEVER FIRE. It watched for a stack going from positive to zero, and a player who moves all in has their seat's stack written to zero the moment they act — several frames before the hand ends. By the time the hand settles the previous frame already showed them at zero. It watches the STATUS now, which is the transition that actually happens. A SHORT ALL-IN MADE EVERY LATER RAISE A RE-RAISE. The exception meant to catch it read `earlier.amount > 0`, and an all-in's recorded amount is its street total, which is always positive. It also walked the street backwards, so it reached the all-in before it knew what bet the all-in was answering. Forwards now, against the engine's own rule: an all-in re-opens the betting only if it raises by at least the big blind. A REFUSED ACTION LEFT ITS ECHO. You click FOLD, the server says the table has moved on, and FOLD stayed on your seat for another second and a half — the felt contradicting the only authority there is. The echo is cancelled when the action is refused. AND THE FELT CAN NO LONGER GO BACKWARDS. Four unordered writers put frames into a window — the socket, the refresh on focus, the refresh on reconnect, and the read that follows an action — and a slow read landing after the socket message it raced rolled the table back. The worst version is a finished hand arriving again after the linger dropped it, which replays every action in it as news. `supersedes` is now the one place that says which of two frames is later. A finished hand also gets one last read when the linger expires: a table where somebody busted publishes nothing afterwards, because there are no longer two players to deal to, so HAND_ENDED can be the last frame a window ever receives. `presented` is cleared per hand, as its own comment always claimed. Its ids are hand-scoped, so keeping them was keeping keys that can never match again — and the ids that are NOT hand-scoped were being swallowed for ever the second time they happened. HoldemFelt.tsx and Seat.tsx are deliberately not in this commit: they currently also carry a concurrent session's chip layer, which imports files that are not yet tracked. Their half of this — holding the winning-card highlight and the pot back until the winner is named — follows once that lands.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing