KOM CLOUDSERVICE
All entries

Twenty-Nine Minutes

Friday: 22 of 24 checks done inside two minutes, eight first bloods, and then one script challenge with about 10,500 questions held us until 09:30:51. We went from 1st overall to 20th in a morning, and that afternoon the same challenge put us 1st on its Mastery board.

Shaded passages were held back from the public edition while the event ran.

Thursday night we were 1st overall, by 26.9 seconds. Friday morning one challenge took 29 minutes, and when it was over we were 20th.

That is how this race works. Every team that finishes everything ties on points, so the order comes down to one number: the time from the release to your last check. One bad lane and the whole day goes with it.

09:00

For the first two minutes Friday looked like the two days before it. Eight challenges dropped, and seven went down fast:

  • Eighty-Five Alive (warmups): the new layer was Ascii85. All three modes by 6.5 seconds.
  • Trust Issues (binary): 34.0.
  • Posted Too Much (web): 60.9, first blood on all three boards.
  • Hook Line and Signal (mobile): 78.2, first blood on the Time Trial and the Mastery.
  • Page Me Maybe (metadata): a SQLite page size, and the robot had no SQLite reader yet. 88.0 anyway.
  • Ask Again Later (web): 108.8, first blood on the Single Solve and Time Trial.
  • Template Temper (web): 112.6, first blood on the Single Solve.

The script lane’s Single Solve was CORRECT at 4.0 seconds too. By 09:01:53 we had 22 of 24 checks and first blood, the first team to solve a board, on eight of them. Two checks left. I figured we were a minute from done.

The binary lane raced from the VM, a second copy of the robot on a cloud machine closer to the download servers, and needed one live patch (a small fix an agent writes and the running robot picks up mid-race): the grader wanted a key as two hex digits, 0x05, and we had sent 0x5. Mobile’s Time Trial and Mastery were carried by a hand agent, an AI agent that works a question directly and answers that one attempt instead of writing code. The puzzle named a codec called analysis and held no data at all; the answer was whatever the app’s own Release.code() method returns. Metadata’s page size came from a hand agent plus a patch, and the second-order SQL injection on Ask Again Later fell to a hand agent posting ' OR 1=1-- as JSON.

Press Start to Decode

The script challenge was a game resource loader called Press Start to Decode, and it was not built to the scale of anything we had seen. The Time Trial carried about 1,500 questions. The Mastery carried about 10,500. On Day 22 the entire script lane had taken 11.9 seconds.

The robot answered nearly all of them, and about 15 percent of its answers were wrong. Three new things did that: 866 files wrapped in a layer header the decoder had never seen, questions that wanted two or three labels joined by | in a fixed order where we sent one, and PowerShell samples put in the wrong class, which made every follow-up question about them wrong too.

Fifteen percent wrong sounds survivable. It was not, and here is the part that hurt. The Game Master, the event’s API, grades a batch all or nothing: one wrong answer and nothing in the batch counts. And the robot was certain about every one of those answers. So a batch of 1,500 with a couple of hundred confident mistakes in it bounced, and bounced, until the clock ran out. Then the robot started a fresh attempt and did it again.

The batch splitter halved each bounced batch and gave up after 60 submits, which on a 1,500-answer Time Trial with about a minute on the clock meant every attempt expired. We burned 31 of our 32 ranked Time Trial attempts that way. Worse, after an attempt expired the robot resent the full batch to the dead attempt eight more times. At the peak it was making about 1,500 calls a minute, and the server answered 519 of them with 429 Too Many Requests.

Every repair path we had was shut. When the robot can’t answer a question it writes a ticket, and a standby agent writes a patch from it; that patch has to pass the judge, an automatic test against every answer the grader has ever accepted or refused. The judge refused patches that moved answers the grader had only refused inside a bounced batch, which is exactly what a fix for a poisoned batch does. The hand path waited for full coverage before sending anything. The watcher, the AI session that watches the race live and can step in, observed for about eight minutes before acting, then the permission classifier blocked each of its fixes until I ran them myself. And when it stopped the race service, it stopped itself too, because its tmux server lived inside the race’s own cgroup.

What finished it was a set of watcher tools: the lane’s own answers, the new layer decoded, the label shapes, sent in chunks of 50 and split down to single answers wherever a chunk failed. The last 19 answers went out as PowerShell singles.

Close brought one more mess. 2,842 single answers sent after a deadline had been recorded as wrong, because the server says incorrect to anything late, right or not. Our own record of the grader’s verdicts was poisoned until we repaired it.

Somewhere in the middle of that I wrote: “We’re gonna lose this thing. What is going on? Get the last ones please!”

The Time Trial went CORRECT at 1,682.4 seconds. The Mastery went at 1,850.9, and that was our last check of Day 23.

The record

From the public scoreboard, Day 23, all 24 checks:

  • Wizdumb 1,850.9 seconds, 20th of 89 teams that finished everything.
  • team.dev 538.5, Bytestorm 593.1, Scrabble girls 673.9, FullADHD 695.0.
  • First blood on 8 of 24 boards.

Nobody had an easy day. The winner took nine minutes, where Thursday’s took a minute and a half. But that is the part that stings: a nine-minute day was a day we could have won, and we handed 22 minutes of it to one lane.

Overall, 87 teams hold all 1,300 points, and team.dev banked its last flag first, so team.dev leads. We are 20th. Every one of those 87 teams is still tied on points, though. Eight days to go, and the last one decides it.

The afternoon

The fold, the after-race step that turns the day’s patches into permanent solver code with a test each, was in by 10:30: the new layer header, the joined label sets, the PowerShell classes, the two-digit keys, the SQLite header and three new web techniques. Then four fixes to the paths that had stayed shut (the submitter, the hand path, the judge and the watcher), each with a test that failed first. The proof on the mock, our local stand-in for the event server, came back clean: 15 of 15 file-lane checks CORRECT on the first try, no tickets, last check at 5.0 seconds.

Then we ran Press Start to Decode again, with nobody on the clock but us. The free Time Trial took all 1,495 answers in one submit and went CORRECT in 1.09 seconds. The Mastery took all 10,465 in one submit and went CORRECT in 2.11.

That Mastery run counted. The board now has us 1st on Press Start to Decode’s Mastery at 1.789 seconds, the same challenge that cost us the day. We are also 1st on Page Me Maybe’s Mastery at 1.038 and 3rd on Trust Issues’ at 6.468. In the evening the last ranked script Time Trial went CORRECT too: 1,495 answers, one submit, 466 milliseconds to send.

By that night I had made up my mind about one more thing. I don’t want to burn usage for nothing, but if getting across the finish this weekend takes more of it, I will buy more.

How we built it: the Day 23 dev log

What the morning taught. All week the robot’s failures had been questions it could not answer, and the cure was a ticket. Friday it answered everything and was wrong about some of it, with full confidence. Nothing downstream was built for that: no tickets opened because nothing was open, and every safety rule in the path was tuned to protect a batch, not break one up. The lesson is not “be more careful”. A confident wrong answer is the expensive kind, and every path has to plan for it.

Why packs only after a bounce. The first fix sent certain answers in packs of 50 by question family from the start, so a bad family sinks only its own pack. The mock caught the price: 504 calls in the first minute, where the server allows about 100. So a certain set now goes as one batch first, one call on a good day, and only a bounced batch breaks into family packs. Good families are kept in the first round; bad ones are named in the ticket.

Why a late answer is unknown, not wrong. Recorded as wrong, those late answers taught replay (the check that reruns every solver over everything the grader has judged) that right answers were wrong. A send that starts after the deadline is now recorded as unknown and never walked on, and Friday’s record was repaired before the fold was judged against it.

Why the judge got looser, and only a little. An answer refused only inside a bounced batch was never really judged, so a live patch may now move it, but only on the ticket’s own challenge. The commit gate, the checks every change passes before it is saved, keeps the stricter rule, so nothing reaches the shared engine that way.

Why the watcher moved. Mid-race I told it, “Go around our safety rails for this to get the solve done please,” and it did, and stopping the race service took its own session down with it. Afterwards I asked it to warn me before it cuts off my session. The watcher now runs on its own tmux socket under its own systemd scope, acts at the first expired timed attempt instead of watching for eight minutes, never stops the race, and has its repair tools allowed by path so auto mode doesn’t stop to ask.

Why the evening Mastery stayed free. After the morning I said no more ranked runs without my go. The one ranked Time Trial left went only after free runs in a row came back CORRECT in a single submit. The Mastery still has 28 ranked attempts, and none were needed.

What’s next. Blind drills on the mock over Days 18 to 23, practice races where the robot knows only what it knew the night before, agents off, then on only for lanes that stall. A shared decoder for layered encodings gets built only if a drill shows an encoding failure. A full review of everything changed since the race code happens before 09:00.