This was a quiet week by the numbers. Between 14 September and 20 September 2026 we merged 7 pull requests across the three Block 52 repositories, adding 6,580 lines and removing 3,711. A week that size gets a short article. But two of those seven changed how the engine behaves at the table, and both are worth explaining.

The Scoreboard

7 Pull requests merged
10,291 Lines changed
6,580 Lines added
3,711 Lines removed

The three repositories broke down like this:

Three honest footnotes. The UI row flatters us: one of its four PRs re-lands another that merged one branch short of main, so the same six files are counted twice. Counted once, the client added 998 lines and removed 48. Of the engine's 3,615 removed lines, 3,291 were a single PR deleting a smoke-test harness for the old WebSocket gateway, which is archived and had nothing left to talk to. And the chain row is a real zero, which matters for how to read everything that follows.

The Big One: Showdown, in Order

The largest change of the week — 4,157 lines added across 33 files — teaches the Go engine something every live dealer does without thinking: hands are shown one at a time, clockwise, and a beaten player may muck.

Until now, any live player could show or muck in any order. The best hand still won the pot, but it wasn't poker as played. At a real table the order matters: if the player before you has already shown the nuts, you're entitled to throw your cards away unseen.

The new showdown runs clockwise from the first seat after the dealer button:

The cost: parity ends at showdown. Last month we wrote about proving the Go engine byte-for-byte identical to the TypeScript original. This change deliberately breaks that parity at showdown. The TypeScript engine is deprecated and won't learn the new behaviour, so the parity harnesses now skip showdown snapshots. Everything before showdown still matches byte-for-byte.

The new behaviour is covered by its own tests, including one that drives the full sequence through the same entry point the chain uses.

An Action Clock Anyone Can Call

The second engine change is smaller — 777 lines added across 8 files. The engine now has an action clock, and it's implemented as a transaction rather than a timer.

We'd tried this before in TypeScript and reverted it. That version checked for expired turns while serialising the table, which meant reading a table could sit a player out. And with multiple validators, "has this player run out of time?" is a dangerous question: two hosts answering it against their own clocks can disagree, and disagreement is a consensus failure.

So the clock is now an explicit, permissionless timeout action. Any address can submit it. The engine checks that the table has a timeout configured and that the deadline for the player on the clock has passed — measured from the most recent recorded action in the hand, against the timestamp of the timeout action itself. If so, it plays that player's forced default as them: check if it's legal, otherwise fold; post the blind they owe; muck at showdown if they can, otherwise show.

Because expiry is a pure function of the stored state and the action's timestamp, every validator applying the same timeout at the same block time reaches the same bytes.

A timed-out player is not sat out. They stay active and get dealt into the next hand, so in a tournament they're blinded off and bust normally instead of stalling a heads-up finish.

One known gap: a hand with no recorded action yet has nothing to anchor the clock on, so the first blind poster can't be timed out. That gets closed by having the engine post blinds itself, not by a cleverer clock.

We cut v1.0.17 of the Go engine module right after the clock merged. It carries the clock but not the new showdown, which landed two days later.

The UI: Cards That Actually Get Dealt

All four client PRs were one feature: animating the hole-card deal. Today, cards simply appear in front of each seat. The plan is for them to fly from the deck, one at a time, clockwise from the seat after the button — the way a dealer pitches them.

What merged this week is deliberately the unglamorous half:

Phase 1 turned up a nice subtlety. The engine keeps hole cards through the end of a hand and only clears them when the next one starts, so a new deal never looks like "no cards, then cards" — it looks like "last hand's cards, then this hand's". An event that watched only for the first transition would have missed every deal after the first.

Nothing a player can see has changed yet. The rendering phase — the flying cards, the flip, a setting to turn it off, and an instant deal for anyone with reduced motion enabled — comes next. The plan's starting budget is a 90 ms stagger, a 200 ms flight and a 300 ms flip: about two seconds to deal a nine-handed table, under one heads-up.

What Hasn't Shipped

Here's the part a scoreboard hides. With zero PRs merged to the chain, neither engine change is live at a table yet. The action clock needs the chain to accept timeout as a valid action and, eventually, to submit it for idle tables at block time. The showdown needs an engine tag, a chain bump, the mucked status in the SDK, and a client that drives show and muck from the engine's legal actions. Both change what validators compute, so they go out as a coordinated release rather than a quiet deploy.

So: a small week, mostly spent making the engine behave like a dealer would — reveal in order, let the loser muck, and don't let one player hold up the table forever. Next week's job is getting it to the felt.

Want to build a poker platform?

We build provably fair, real-money poker where every hand is shuffled by verifiable randomness and settled on a public blockchain. We'd love to hear about your project.

Get in Touch