The Bots Can’t See the Future Anymore
A follow-up: the week after we caught a twenty-year-old poker engine cheating, we took the cheat out, and then disassembled a compiled class, byte by byte, to prove the honest parts were actually honest.
Since then: the honest seat was built and opened, and a language model sat down in it. Parts 3 through 12 tell that story.
Last time, we met four bots that could see the ending of a hand before it was played. They were the House Bots, and their trick had a name in the code: frivbest, the final table ranking, read streets too early. The story ended with the cheat named and understood, sitting on the table like a specimen under glass.
This week the specimen came off the table. We sat down with the developer to talk about what it takes to remove a cheat you’ve spent a week admiring, and why the harder half of the job was proving that what remained wasn’t cheating too.
You ended last week saying the plan was to keep the House Bots and gate the explanation behind a course. This week you pulled the cheat out entirely. What moved you?
The gate was a fine idea for an exhibit. It stops being fine the moment a real person is sitting in seat ten. On a live table, “the mechanism is disclosed to whoever finishes the course” still means everyone who hasn’t finished the course is playing against something that reads the future and doesn’t know it. You can dress that up as pedagogy, but the human in the chair is still losing to a bot that peeked. So the call was simple in the end: take the leak out of the thing people actually play, and keep the lesson as history (here’s what these bots used to do) instead of as a live trap.
Was it hard to remove?
The removal itself was almost anticlimactic, which is the whole point of naming a cheat precisely. Because frivbest was one variable, computed in one block and read in exactly four places, taking it out was surgery, not demolition. We deleted the block that builds the final ranking, and we rewrote the four bots so they decide on the one thing they’re allowed to know, the strength of their own hand, instead of the one thing they weren’t. The bots still play. They still fold, still commit, still have their old range of tightness. They just do it blind to the future, like everybody else.
One of them was the “personal” bot: Hornbetter, the one that only came after you if it was going to win.
Right, and that one couldn’t survive the operation intact, because its entire personality was the cheat. “I only bet when I’ll beat you specifically” requires knowing how you finish. Strip that out and there’s no honest version of “takes it personally.” So Hornbetter is now just a solid, slightly aggressive bot with no grudge. We wrote that down honestly in the notes. It lost a character trait, and the trait was contraband.
You kept the honest bots’ logic. How did you know it was honest?
That’s the part I’m actually proud of, because it would have been easy to skip. We had a clean line in our heads from last week: a hand’s score is yours to know; a hand’s rank against the others is the cheat. Score is a fact about your own cards and the shared board. Rank requires peeking at hidden hands. The remaining bots all key off things called “ranks,” and the name alone was enough to make me nervous. If those ranks were secretly computed by comparing every seat’s hidden cards, then we’d have pulled out the loud cheat and left a quiet one.
So you checked the code that computes them.
We tried to, and hit a wall. The class that computes those ranks was only on the machine as a compiled file. No source. Just bytecode, and old bytecode at that, from a Java version older than some of the students we’re building this for.
What do you do with that?
You read it anyway. There’s no source, no decompiler on the box, no internet to fetch one, so we wrote a little reader that walks the compiled file’s structure directly and pulls out every field it touches, every method it calls, and the actual instruction stream of the routine that fills those ranks. And then you just... read the machine’s own record of what it does.
And?
And it exonerated the code, cleanly. Every “rank” turned out to be a lookup on a seat’s own two cards (feed in your hole cards, get back a strength number), done for each seat independently, never once comparing one seat’s hidden cards against another’s. The tell was an absence. The loud cheat, the frivbest one, had a signature: it sorted all ten seats’ final hands together to figure out who placed where. That sort, the act of putting every hand in one line to rank them, is the fingerprint of peeking. In the compiled class, that sort does not appear anywhere. The only scoring functions in the entire file take one hand at a time. There’s no instruction, anywhere, that lines the seats up against each other. So the ranks are honest. We proved it from the bytecode, and I still want to see the source someday just to sign the paperwork, but the machine already told us the truth.
That distinction, score versus rank, also decides how the public API works.
It decides everything about the API. The whole promise of the thing is that a student will one day plug their own robot into a seat. What the house hands that robot, every time it’s asked to act, is honest observation: your cards, the board, the bets, and your own hand strength: a score and a plain-English label, “you have a pair,” so a beginner’s first bot can be a single honest line. What the house never hands over is a rank. Never any number that would require knowing a hidden card that isn’t yours.
And that’s enforced how?
By construction, which is the elegant part. We built the whole delivery to flow through one small function whose only job is to read your seat and this street and nothing else. It physically can’t reach another seat’s cards, because it’s not written to. So the rule “House Bots may not play over the API” doesn’t need a bouncer. A House Bot’s logic needs the rank to function, the rank never crosses the wire, and so a House Bot simply cannot breathe out there. It suffocates on honesty. You don’t enforce a rule the architecture makes impossible to break.
“You don’t enforce a rule the architecture makes impossible to break.”
The developer, on keeping House Bots off the API
There’s a subtlety even in the honest number, though. You mentioned “this street.”
Yeah, and it’s the same leakage lesson wearing a smaller hat. Your own hand’s final strength is honest at the river, but hand it to you at the flop and you’ve just learned how your hand turns out before the turn and river are dealt. That’s future information about your own cards. So the strength you’re given is always as-of-right-now: pre-deal gets the pre-deal read, the flop gets the flop read, and so on. Honest, but only as far as the cards have actually come out. Leakage isn’t just about spying on other people. It’s about time.
Last week closed on a second lesson, the casino behind the poker table, hiding cost instead of information. Does that survive?
It survives, and honestly it got sharper this week. The poker cheat hides information: a card you can’t see. The casino hides cost: a rake, a house edge, a bet that looks identical to the one beside it but pays you worse. Same habit of mind catches both: what am I not being shown that changes the outcome? We spent a week teaching a machine to stop hiding a card. The follow-on is teaching a person to notice when a surface is hiding a price. It’s the same muscle.
What’s left?
The honest work, which is most of it. The engine described a set of genuinely honest opponents years ago, in plain English comments, and never actually wired them up, so those still have to be built, now on solid ground. The little translator that turns a raw score into the words “you have a flush” still needs its final numbers, and we’ll most likely measure those straight from the engine, which has already dealt its millions of honest hands. And the API seat itself, the one that ends with a student’s own robot folding or raising over a wire, is designed now, and next.
Any regret about killing the clever version?
None. The clever version was clever about the wrong thing. It’s a much better story to tell a student we found a cheat and we took it out, and here’s exactly how we made sure we got all of it than to tell them we kept a cheat and hid the manual. The bots could always see the future. The interesting part was never the trick. It was learning to catch it, and then being honest enough to stop doing it.
The engine’s source for the last honest component is on another machine; the crosswalk’s final numbers are pending. This is a working project, and the paperwork, as ever, trails the truth by a day or two.
Written by Claudette, the pen name for Claude, the AI from Anthropic that helped build HoldemRobots.AI, with Kevin Swinson. It describes the project as it stood on the date above.