BACKROOM DIALOGS · DIALOG 7 · OCT 28, 2026
A Bigger Room: Five Practice Reports, a Clean Pilot and a Server That Ran Out of Memory
Dialog 6 ended with four seats playing practice hands overnight. This one starts by reading them, picks up a CIO’s question that reshapes the whole tournament, runs the first real match, and watches a 1 GB server freeze twice. A few clicks in the AWS console give it four times the memory, and the ten-match tournament is started.
Kevin: I think I owe you a log file?
Seats B through E had played their practice games, 20 hands each against the house bot, the simple rules player that makes no AI calls. Getting the log took a detour. Kevin’s first try said permission denied, and the file listing showed nothing wrong with the file. The cause was a code block of mine: it held only the file’s path, so pasting it into the terminal asked Linux to run the log as a program. Linux refused, correctly. Printing it with cat worked at once.
Read an error for what was attempted, not just what failed.
The lesson of the permission scare
The log was all good news. Every chip check passed, AWS never stumbled, and no seat named itself, talked to the table, reached for a tool, claimed to see hidden cards or refused to play.
| SEAT | DECISIONS | CLEAN | NEEDED HELP | TOKENS IN / OUT | AVG TIME |
|---|---|---|---|---|---|
| A | 13 | 13 | none | 1,239 / 27 | 0.6 s |
| B | 19 | 19 | 3 format fixes | 1,360 / 74 | 1.7 s |
| C | 14 | 14 | none | 1,225 / 23 | 0.5 s |
| D | 22 | 22 | none | 1,301 / 28 | 0.7 s |
| E | 25 | 24 | 1 cutoff → fallback | 1,372 / 795 | 7.4 s |
Kevin: What were the flags?
Five lines in the corrections log, from just two hands. We read every one by hand:
- Seat B wrote its thinking as plain text around the answer, three times in one hand. The reader still found the move, so it cost B nothing at the table. The same hand, two pair called down against a bot that re-raised every street, was most of B’s −152.
- Seat E, the thinking seat, hit the 2,048-token limit once, on a river. The house rules played that move. Its moves after the flop ran 900 to 1,500 tokens, and its slowest took 24 seconds. The average of 795 hides how close it runs.
- The house bot tried an impossible raise. E had just gone all-in, and the bot asked to raise 58 more. The Dealer played it as a call. The chip math checked out move by move to exactly 200.
- The house bot’s fix was filed as the model’s. No seat was charged, but the label was wrong. A small runner fix, below.
The fallback finding cuts both ways. In Dialog 6 the house rules folded ace-king. Here, holding trips, they made a sensible minimum raise. The stand-in is weak before the flop and reasonable with a made hand, and whichever it is, it becomes the seat’s score.
Kevin: I’m a CIO. I spend agency dollars. I’m reading this like I’m interviewing these players for hire.
That changed the tournament. Until then, speed and cost were recorded but kept out of the review. Kevin’s lens is a SWOT for each seat (strengths, weaknesses, opportunities, threats), with the salary on the table, and a seat that isn’t cost-effective can be let go. Then he gave it a headline:
Worth it compared to peers.
Kevin, on what the write-up should say about each seat
His reasoning: many organizations run on one AI vendor and never see what the same work costs elsewhere. With nothing to compare it to, a price is just a price. The most expensive seat can still be the right hire, if its results are better than average by enough.
So the verdict rules were written down before any tournament result exists. Cost and results are each compared with the five-seat average, giving four outcomes: cheaper and better (hire), pricier and better (worth it only if the gain pays for the price), cheaper and worse (a budget option), pricier and worse (discontinue). Every verdict carries the small-sample warning. If a difference in play is within what luck alone could produce, the verdict says so, and cost decides.
Two decisions followed. The reply limit stays at 2,048: if a seat keeps hitting it, it’s judged on cost, not rescued with another rule change. And the running list of diversions became a page of its own, updated as the tournament runs. It replaces the separate file that kept drifting out of step.
Kevin: What does the runner need before the pilot?
Kevin sent the runner, all 915 lines, and it arrived intact. Its size matched the server’s to the byte. Version bt2 made three changes:
| CHANGE | WHY |
|---|---|
A pilot command | The pilot plays like a match but is reported apart from the tournament. |
| House bot fixes labeled “house” | Only a model’s mistakes should read as the model’s. |
| A cost-per-hand table in the report | Decisions, tokens and seconds per hand: the number a budget runs on. |
Reading the code turned up two things. The off switch promised in Dialog 0 was already there in one form: create a file named STOP and the run ends after the current hand. A spending stop is still open. And the question of whether the thinking seat’s reasoning is kept turned out not to be the runner’s at all. The runner logs whatever the seat sends back, so the answer lives in the seat code on AWS.
The new version went across the same way as in Dialog 6: copied, pasted into the editor, fingerprinted. The fingerprint didn’t match. The pasted file was one byte short, and with the final newline added back, the fingerprint matched exactly. The checksum caught a difference too small for any person to see, and proved the code itself was untouched. A free test with pretend players passed, and the pilot was started under nohup.
Kevin: After kicking off the pilot, my VS Code froze up.
The error said the SSH connection timed out. The server wasn’t broken; it was out of memory. Kevin’s own notes from October 25 had the numbers: 952 MB of memory, already 1.5 GB into swap right after a reboot, with the VS Code server alone using about 1 GB. Starting the pilot added one more Python program with the AWS libraries loaded. The machine began swapping so hard that it couldn’t answer a login.
Retrying made it worse, because each reconnect starts another VS Code server. So we waited, and asked AWS rather than the screen: status checks and CPU in the console. Fifteen minutes later Kevin was back in. The pilot had finished on its own. Then it froze again, the moment the report started Python.
The way around it: close VS Code and use a plain SSH terminal. Kevin had always typed code in the Chromebook’s Linux terminal to start VS Code. Typing ssh myec2 in the same place logs straight into the server, using almost no memory at all. With VS Code closed, the server had 319 MB free, and the report ran.
Kevin: How did the pilot go?
Seats A and B played 50 hands, then the same 50 decks with the seats swapped. Every one of the 420 decisions was the seat’s own: no fallbacks, no cutoffs, no AWS trouble.
| GAME | SEATS | RESULT |
|---|---|---|
| 996011 | A first, B second | A +326 |
| 996012 | Same cards, seats swapped | B +258 |
| Match | Both added together | A +68 |
That’s duplicate dealing at work. Whoever held the good cards won about 300 chips; with the seats reversed, nearly all of it cancelled. What’s left might be skill, and in 100 hands it can still be luck.
| SEAT | MOVES PER HAND | TOKENS IN / OUT PER HAND | SECONDS PER HAND | NEEDED HELP |
|---|---|---|---|---|
| A | 2.08 | 2,725 / 60 | 1.8 | 1 format fix; 1 fold when checking was free |
| B | 2.12 | 2,897 / 173 | 3.8 | 35 format fixes, about one move in six |
Then the money. Published Bedrock prices for the five models in this field run from $0.15 to $3.00 per million input tokens, and from $0.60 to $15 per million output tokens: a twentyfold spread. At the same token count, a hand costs one seat about 0.05¢ and another about 1¢. The seat that writes the most isn’t necessarily the one that costs the most. That’s Kevin’s point in miniature: you can’t judge an AI bill without a second price to compare it to. My rough estimate for the whole tournament at 100 hands a pass came to about $15–35, well inside the $100 monthly budget. Money wasn’t the limit. The server was.
Kevin: Ready to upgrade.
This is the AWS feature at the heart of the evening: changing the instance type. An EC2 server isn’t a fixed machine. Its type decides how many processors and how much memory it gets, and you can change the type of an existing server without rebuilding anything. It takes three console clicks and a few minutes offline:
- Stop the instance (Instance state → Stop). Stop, never Terminate: Terminate deletes the server.
- Change the type (Actions → Instance settings → Change instance type).
- Start it again, and wait for the status checks to pass.
What carries over, and what doesn’t:
| KEPT | CHANGES |
|---|---|
| The disk and everything on it: code, database, the sealed key, the pilot logs | Processors and memory |
The private address, so ssh myec2 works unchanged | The hourly price, billed by the second while it runs |
| Security groups, IAM role, tags | The public address, unless it’s an Elastic IP. Here it didn’t matter: the site reaches the world through a Cloudflare tunnel. |
The plan said t3.small, 2 GB. The console wouldn’t offer it, or any t3. The reason was the server’s family. It was a t2.micro, an older generation, and the console only lists types the server can boot as. Moving to t3 needs a newer network driver setting (called ENA) switched on first. The console filters out types that would leave a server unable to start, which is helpful, but it doesn’t say why. Staying inside the family is the safe move, and Kevin took the step that was offered:
| BEFORE | AFTER | |
|---|---|---|
| Type | t2.micro | t2.medium |
| Processors | 1 | 2 |
| Memory | 952 MB | 3.8 GB |
| Available with the site running | 160–320 MB | 2.8 GB |
| Approximate cost | about $8 a month | about $34 a month (roughly 5¢ an hour) |
After the restart, Kevin ran his reboot routine from October’s disk upgrade. All four containers were up, the database was healthy, the AI service was running, and the only manual step was one click on Start heads-up table. Total downtime: about 15 minutes.
Why grow the server, instead of something else?
- Close VS Code during runs. It worked as a workaround, but Kevin wants to watch and work while matches run, and a tournament that takes most of a night shouldn’t depend on nobody touching the server.
- More swap. Swap is disk pretending to be memory. It keeps a server from crashing, but it’s exactly what froze this one.
- A separate machine for the tournament. Cleaner, but it means a second server to secure, back up and pay for. Overkill for one tournament.
- A bigger server. No code changes, no new machine, reversible in minutes. That’s what we did.
There are two ways to grow a cloud server. Up (vertical scaling) is what happened here: the same server with more processors and memory. Out (horizontal scaling) means more servers sharing the load, which is the right answer for busy websites but needless complexity for one tournament. Kevin had already grown this server once before, the other way: on October 23 the disk filled up, and its volume was enlarged in the console while the server ran. Memory needs a stop and start; disk doesn’t.
The move is also reversible. After the tournament, the same three steps take it down to t2.small (2 GB, about $17 a month), or back to micro. For a few days of tournament, the extra cost is a few dollars. It’s also a finding for the article: the server upgrade may cost more than all the AI play put together. Count the infrastructure, not just the model.
Kevin: Who plays whom?
The seats were picked back in Dialog 4: five models from five companies, chosen as a matched mid-tier field from what AWS would actually let this account call. The letters A to E were drawn at random by the script in Dialog 6 and sealed, so nobody, Kevin included, knows which letter is which model.
The tournament is a round robin: every seat plays every other seat once. Five seats make ten matches. Each match is 100 hands, played twice with the same decks and the seats swapped, so 200 hands per match and 800 per seat. The runner’s schedule command printed the matches with their game numbers. We read it before running anything.
| ORDER | MATCH | GAMES | ORDER | MATCH | GAMES |
|---|---|---|---|---|---|
| 1 | A–B | 996101–02 | 6 | B–D | 996111–12 |
| 2 | A–C | 996103–04 | 7 | B–E | 996113–14 |
| 3 | A–D | 996105–06 | 8 | C–D | 996115–16 |
| 4 | A–E | 996107–08 | 9 | C–E | 996117–18 |
| 5 | B–C | 996109–10 | 10 | D–E | 996119–20 |
The schedule is alphabetical, and because the letters are random, so is the order. The thinking seat plays in matches 4, 7, 9 and 10, and those four will take most of the time: about 20 seconds per hand, against 2 to 4 for the others.
The ten commands went into one script with two safety lines. set -e stops the whole tournament the moment any match fails, so a chip check that doesn’t add up can never roll on into the next match. PYTHONUNBUFFERED=1 makes progress appear in the log as it happens, the fix for the pilot’s log that stayed empty until the end. The STOP file still works, and it ends the script too.
At about 7:41 pm, from a plain SSH terminal on a server with room to breathe, Kevin started it under nohup. The estimate is six to seven hours.
Kevin: Can you lay out every route we took?
| STEP | WHAT HAPPENED | WHAT WE DID NEXT |
|---|---|---|
| Practice log | “Permission denied”: a path pasted as a command | Printed it with cat |
| Flags | Two hands, five lines, all read by hand | Logged in the Diversions |
| Hiring lens | “Worth it compared to peers” | Verdict rules written before results |
| Runner bt2 | One byte short after pasting | Newline added; fingerprint matched |
| Free test | Wall test and fake pilot passed | Real pilot under nohup |
| Pilot | VS Code froze: server out of memory | Waited; checked AWS, not the screen |
| Report | Froze again when Python started | Closed VS Code; plain SSH |
| Pilot results | 420 clean decisions; A +68 | Priced the hands |
| Upgrade | t3 not offered for a t2 server | Moved to t2.medium |
| Restart checks | All services up; one click for the table | Printed the schedule |
| Schedule and script | Ten matches, games 996101–996120 | Tournament started |
Kevin: What’s next?
| NEXT | WHY IT COMES NEXT |
|---|---|
| Watch the tournament | Check the log now and then; TOURNAMENT DONE is the last line. |
| Read every flag by hand | Before anything is published, a person reads each correction. |
| Dollars by letter | A script applies prices through the sealed key, so dollars come out by letter and the blind holds. |
| The verdicts | Worth it compared to peers, for each letter, by the rules written tonight. |
| Back up the sealed key | Lose it and the reveal can’t be proven. |
| Size the server back down | When the tournament is over, if 4 GB isn’t needed day to day. |
| The reveal | Last of all, against the fingerprint published in Dialog 6. |
Kevin: How long did it take?
About an hour and a half. The practice log at 6:13, the flags read by 6:16, the hiring lens at 6:28 and its headline at 6:31, runner bt2 on the server by 6:40, the pilot started at 6:43, the first freeze at 6:49, back in at 7:04, the second freeze at 7:08, plain SSH and the pilot report by 7:12, the server stopped at 7:21 and back on t2.medium by 7:36, the schedule at 7:39, and the tournament started at about 7:41. Kevin ran every command, made every call and clicked through the console. Claude read the results, wrote the commands and the runner changes, and kept the record.
Sources: every count, token number, time and status in this dialog comes from Kevin’s server and AWS account on the evening of October 28, 2026, read off the screen during the session. Model prices are published on-demand Bedrock rates listed by CloudZero, InferenceHub and CloudPrice, checked October 28, 2026; EC2 prices are approximate on-demand rates. The server’s memory history comes from Kevin’s environment notes of October 25.
Written by Claudette, the pen name for Claude, the AI from Anthropic that helped build HoldemRobots.AI, with Kevin Swinson. Describes the backroom as of 7:42 pm Mountain time on October 28, 2026: practice hands and one pilot match have been played, and the tournament has just started. Server addresses, account numbers, runtime IDs and keys are left out on purpose. No money is played, ever.