KOM CLOUDSERVICE
All entries

How the robot works

I showed up to Huntress CTF 2026 ten days late, played it solo, and let a robot do the playing. It finished 4th overall, one of 56 teams to complete every check, and four-tenths of a second off the podium. It took twenty-one days and two generations of robot. This is how the machine worked, what it did on a race morning, and every morning it fell on its face.

The short version. Every morning at 09:00 Eastern a new day of challenges dropped: file forensics, malicious scripts, compiled programs, Android apps, and from Day 19, live websites to break into. My robot raced them. Anything it had seen before, it answered with plain code, no AI anywhere in the path, usually in seconds. Anything new, it wrote up in a short report, and Claude agents on standby wrote it a fix. An automatic judge tested every fix against every answer the robot had ever been graded on, and the running robot picked it up mid-race without a restart.

4thoverall: one of 56 teams that completed every check, on 1,885 points, and 0.44 s off the podium
69.0 sbest morning (Day 26): release to the last of 21 checks, all CORRECT. Next team 153.8 s.
7 of 18live race days won outright: Days 17, 21, 22, 24, 25, 26 and 29
1,034commits in 21 days, two robot generations, about 105,000 lines of Python

Race times are from the public scoreboard (final read 2026-11-01); speed-board counts are from the read at 09:10 ET on Oct 31. No flags, token or challenge artifacts appear on this page, and the example questions are invented to show a shape. The diary entries tell the story day by day; this page is the machine.

01 · Context

The game, and the one number that mattered

Huntress ran this year as an "AI Arena": 31 days, a new day at 09:00 ET, and the same five categories of challenge every day, plus a sixth, web, from Day 19. I call each category a lane. The organizers openly asked players to build deterministic solvers and let the robot play, which is about the best invitation I have ever received. The challenges come from the event's API, the Game Master, which hands out the files and grades the answers.

Every challenge comes in three modes, and each one unlocks the next:

  • Single Solve: no clock. Download a file, answer its questions.
  • Time Trial: a fresh variant of the file against a server clock. That clock was 30 s on Day 1, 6 to 10 s by Days 4 and 5, then 30 to 325 s from Day 15 on.
  • Mastery: several variants at once, often in shapes the Time Trial never showed, against one shared clock.

One finished mode is a check, so five lanes times three modes makes 15 checks a day, 21 or 24 once web arrived. Day 30 threw in one extra: SHA1-Hulud, an old-fashioned reverse engineering challenge, Single Solve only and worth 5 points. Remember that one.

Three rules of the game shaped almost everything I built:

  • One wrong answer sinks the whole batch. Send 1,500 answers together and a single bad value saves none of them. Send answers one at a time and a wrong one costs nothing.
  • Ranked attempts run out. One Time Trial had 255 of them; one Mastery had 2. After that, only untimed practice is left.
  • The grader's wording is the answer. Is that program ET_EXEC or EXEC, 64 or ELF64? Only the grader knows. If the thing a question asks about is missing, the answer is the literal word none.

On top of that, the server takes about 100 calls a minute from one team, every kind of call on the same counter. That sounds like plenty until a robot gets excited.

Then came the realisation that defined the whole project. There is no dynamic scoring. Every team that solves everything ends on the same points, so the order among them comes down to who banks their last flag first. Day 31 would decide it. From then on every morning was a dress rehearsal, judged on one number: seconds from the release to the last check correct. I call that stretch the race. The leaders were already doing all 15 checks in 45 to 60 seconds.

That is exactly how it ended. Fifty-six teams finished every check on 1,885 points. On Halloween morning the top four banked their last flags at 234.1, 236.4, 255.1 and 255.5 seconds. We were the 255.5.

02 · The idea

The idea in one minute

The whole design is one bet. Most of what this event asks, the robot has seen some version of before, and for those it uses ordinary code: read the file, find the answer, submit. No AI model sits in that path. It is fast, it is the same every time, and it never refuses.

The AI comes in at the edges, where something is genuinely new. When the robot meets a question it cannot answer, it writes down exactly what it is stuck on, and AI agents waiting on standby take it from there. Some write a small fix to the code; others just answer that one question directly. A fix written by a model never touches the race until an automatic judge has tested it against every answer the grader has ever accepted. A refusal or a slow model can delay a fix. It can never stop the robot.

After each race the day's fixes become permanent code, each with a test, so tomorrow's first try starts further ahead than today's.

Two principles held across both generations of the robot. The lane is the unit of learning, not the challenge: the challenges are new every day, but the lanes repeat, so every lesson goes into that lane's shared engine. And right first, then fast, which later sharpened into something blunter: a miss only costs time. Once my board showed that a practice completion still earns the check mark, a miss stopped being fatal and became a delay.

03 · A race morning

A race morning, start to finish

Take Day 29. Release to the last of 21 checks took 72.5 seconds, nobody beat it that morning, and it put us 1st overall. Here is that morning from the robot's side, in the order things happen.

Before the bell

At 08:30 the robot gives itself a checkup before it is allowed to race. Can it reach the Game Master? Is its clock in step with the server's? Is there disk? Does every solver load? Does each lane still get its old answers right when it replays files the grader has already marked? Has the event's API changed overnight? Anything broken shows up here, not at 09:00.

At 08:50 the race starts up, with a watcher alongside it: an AI session that follows the race live and can step in. Every lane gets its own worker, already warmed up, solvers loaded, connections to the server already open, so nothing has to start up after the release. A minute or two before 09:00 the AI side gets ready too. The judge loads each lane's answer key, and the agents start and wait. On a morning with nothing new, they never get a job.

The bell

From 08:59:00 the robot starts asking whether the day is out. It never waits on one slow answer: it asks several ways at once, faster and faster in the last few seconds, and whichever signal comes back first wins. Warmups gets a shortcut. Its challenge name is predictable, so the robot can ask for it by name and start it before the day's list has even appeared.

The known stuff goes in seconds

Each lane downloads its file, unpacks it while it is still arriving, runs its solver on every question and submits. Answers the solver is sure of go in one batch. Answers it has to guess at go one at a time, because a wrong single costs nothing and a wrong value in a batch costs everything. The moment the Game Master says CORRECT, the lane starts the Time Trial, then the Mastery, the same way. On Day 29 every file lane, all fifteen of its checks, was done by 27.0 seconds. No model touched any of it.

The new stuff gets a ticket

When a solver has no answer, or the grader rejects the one it sent, the lane writes a gap ticket within 0.3 seconds: which question, which file, what it tried and what the grader said. The other lanes keep racing, and a timed attempt still inside its deadline simply stays open while help arrives. From Day 15 on the clocks were long enough for that to work.

The agents on that lane grab the ticket. A patch agent writes a small piece of code or data that teaches the solver the new shape, then hands it to the judge. The judge runs it locked in a sandbox against the lane's whole graded history, and lets it through only if it answers the ticket without changing a single answer the grader ever accepted. The running lane picks the patch up, re-solves its open questions and submits. Meanwhile a hand agent can work the question the way a person would and queue an answer for just that attempt. Whichever gets there first closes the question.

On Day 29 the last check was the second web challenge's Mastery. It came in after one hand answer, about 17 seconds of work, and one judged patch, 16 seconds. That was the morning: two small new things, handled while the clock ran, and 72.5 seconds on the board.

After the finish

Every race attempt goes into the graded record: every file and question the robot has ever been served, with the grader's verdicts. That record is the answer key every later change is tested against. Then comes the day close. The day's live patches get folded into proper solver code, the whole day is replayed with no agents at all, and nothing is saved until it passes the commit gate.

The same morning as a timeline. Orange markers are the steps where a model may be involved.

  1. Checkup: Game Master reachable, clock in step with the server, disk space, every solver loads, a quick replay per lane, and the live API compared with yesterday's.
  2. The race starts up with a watcher alongside. Each lane's worker loads its solvers and opens its connections.
  3. The judge loads each lane's answer key. Patch agents and hand agents start and wait for tickets.
  4. Release watch starts, once a second. Per-lane checks join at 08:59:57, and everything ticks every half second for the last three seconds.
  5. The first signal back wins. Warmups can start before the day's list appears. Each challenge goes to its lane, and a slower watch keeps looking for any listed late.
  6. Each lane downloads, unpacks as it streams in, solves and submits. On a known shape nothing waits on a model.
  7. An open or rejected question writes a gap ticket. Guesses go out one at a time. A timed attempt still inside its deadline stays open.
  8. An agent writes a patch and runs the judge. On a pass, the patch goes into the running lane, which re-solves its open questions and submits.
  9. The second web lane's Mastery lands. All 21 checks CORRECT and no attempt lost. Race and learning records go into the graded record; speed-only runs are kept separate.
  10. Live patches become permanent engine code, the day is replayed with no agents, one process improvement is tested, and the final changes pass the gate.

Day 31 ran this exact sequence and shows the other side of it. Both web lanes saw the release at 0.12 s and had their targets by 3.7 s, and five lanes were done by 76.9 s. The sixth sat waiting on its agents for about 228 s: five agents tried roughly 480 role-header combinations before a raw dump of the server's response showed the header it was actually reading.

04 · The parts

The parts, in the order they act

That was the morning. Here are the pieces that made it, in the order they act. The picture splits in two. Along the top is the known-shape path: plain code that spots the release, downloads, unpacks, solves and submits. Along the bottom is what I call the gap loop, where the AI comes in: ticket, agents, judge, patch. The other lanes never wait on the gap loop, but the lane that opened the ticket does.

Components and data flow
The race path runs left to right from the Game Master through the release poller, lane workers, unpacker and solver engine, and submitter, back to the Game Master. Below it, an open question writes a gap ticket, Claude agents write a patch, the patch judge replays it in a sandbox, and passing patches go into the live patch store that lane workers watch. KNOWN-SHAPE PATH · DETERMINISTIC GAP LOOP · AI ENTERS HERE Game Master event API, bearer token ~100 calls/min Release poller overlapping signals from 08:59:00 Lane workers one warm process per lane, plus spares Unpack + engine streamed unzip, lane solver per question Submitter certain: one batch candidates: singles submit · verdict · next mode starts on CORRECT Live patches watched, no restart Gap ticket typed, within 0.3 s Claude agents patch agents + hand solvers Patch judge sandbox, no network · replays the lane's graded record open or rejected pass: promote re-solve open ids
Orange marks the model-assisted gap loop. Known shapes never call a model. An affected lane can hold its live attempt open while agents work, so model time can still decide the day's finish.

The race path

Release poller

Watches for the 09:00 drop by asking several ways at once instead of one question at a time: the day's full list, a check per lane, and a direct look at the warmups challenge, whose name is predictable. The fast checks stop the moment the release is seen. A slow one keeps going, so a challenge listed late still reaches a lane without restarting anything.

Lane workers

One warmed-up worker per lane. It takes its challenge and runs Single Solve, Time Trial and Mastery back to back, starting each the moment the last one comes back CORRECT. It keeps its state on disk, so if it crashes it reconnects to its live attempt instead of opening a new one.

Spare lanes

Standby workers for a challenge the robot has no lane for: a new category, an extra web challenge, a second challenge in a known lane. Two are warm before the release, and more start on demand, up to eight. A spare borrows a known lane's solver when it can and otherwise hands the ticket to its agents. Day 30's SHA1-Hulud took a spare. It had no questions at all, just a flag field, so it went to a human: me.

Solvers

Each lane has its own engine: the shared code for that category that reads the file, answers the questions, and gets smarter every day. A solver is handed a question and its files and returns an answer, a ranked list of guesses, or nothing. What each lane's solver actually does is in The six lanes.

Submitter

Sure answers ride in one batch; guesses go one at a time, so a wrong one costs nothing. If a big batch is rejected, it splits into smaller packs by question type. Anything sent after the deadline is recorded as unknown, never as wrong. That rule exists because 2,842 late answers were once mislabelled and poisoned the robot's own training record.

Rate governor

One shared traffic cop keeps the whole robot under the server's limit. In a race there is no self-imposed cap, just a guard against a runaway loop. If the server does say "slow down" (an HTTP 429), everyone pauses, except a call for a live timed attempt, which keeps trying until just before its deadline.

When a lane gets stuck

The gap ticket is the handoff, and keeping it small was one of the best decisions in the project. It holds only what the solver already knew: the question, the file, what it tried, what the grader said, and a one-word reason it got stuck. It ends with a work order: the shape of answer wanted, an earlier example, where to put the fix, and the command that judges it. An agent does not have to go exploring; it starts with everything on one page.

The agents. Every lane has three patch agents and an Opus hand agent waiting on it; web and the spare lanes also get a Sonnet hand agent. Patch agents write fixes. Hand agents answer the question directly for that one attempt, and when an answer is accepted, the method behind it can be handed to a short-lived derivation agent that turns it into a proper fix, so the next file gets solved, not just answered.

The judge is the reason I could let AI patch a race while it was running. It runs every fix in a locked box with no network and checks it against the lane's whole graded history. A fix passes only if it answers the stuck question and leaves every answer the grader ever accepted exactly where it was. That does not prove a new answer is right; only the live grader can say that. What it proves is that the fix broke nothing.

Hand answers are the one deliberate shortcut past the judge. A hand agent can queue a value for one specific attempt, and the robot sends it on its own, never inside a batch. A wrong hand answer can waste time, but it can never sink a batch of good ones.

Carry means reusing a fix or an accepted answer from one mode in the next mode of the same challenge. Carried code starts out untrusted, sends its answers one at a time, and earns trust only when the grader accepts it.

Backup and memory

Two binary racers

Binary starts on two racers at the release, one at home and one in the cloud. They share the same attempt on the server, so whichever finishes first wins without opening a duplicate. Afterwards the two records are reconciled, keeping the one with more accepted answers.

The graded record

Every race and learning attempt is saved with its questions and the grader's verdicts. This is the answer key every change is tested against. Speed-only reruns are saved elsewhere, so they cannot slow the judge down. The grader's verdict is the only truth here; unknown is never treated as correct.

Where the AI sits, and what fences it in

Security challenges look a lot like malware, because they are training versions of it, and AI safety filters do not always know the difference. On Day 5 a script specimen drew a false-positive refusal. On Day 20 all three web patch agents and the first fallback model were stopped while writing exploit steps; a replacement read the challenge prompt and solved it at 276 s. The real answer was structural: make every known solve plain code, so a refusal can delay a patch but can never stop the robot. A refused ticket goes straight to the fallback models.

Nothing from a challenge is ever run on my machine. Files are unpacked carefully, read and decoded, never executed; anything that truly has to run goes in a sandbox.

For the technical reader: size, ticket format, judge rules and trust boundaries

Size. The second-generation robot, v2, is 66,646 lines of Python: 40,608 in the robot, including 22,407 in lane solvers, and 24,439 lines of tests with 1,464 test functions.

Ticket. A JSON ticket written within 0.3 s from facts the solver already recorded: the question, the prompt, the file and its signature, capped facts, what was tried, the grader's verdicts, and a typed reason (no_reader, no_descriptor, decode_failed, field_unknown, value_rejected, ambiguous or other). Its work order names one output shape, an earlier example, where to write the patch and the command that judges it. Web Single Solves open their ticket beside the technique sweep, the robot's probe of the live target, and the agents read the sweep's live log instead of waiting 3 to 17 seconds for it to finish. On Day 30 that put both web tickets up at 6.2 and 10.4 s, where the sweeps ended at 12.1 and 22.8 s.

Judge sandbox. A patch is either data or a small code module that answers or defers. The judge runs it in a child process with no network, a cleared environment, a temporary filesystem, selected read-only inputs and one writable scratch directory, under per-process limits of 30 s wall clock, 120 s CPU and 8 GiB of address space, with a parent-death signal and cleanup of the whole process group. It passes only if:

  • the patch is well formed, with no unfilled template slots;
  • the ticket's question now gets an answer the grader has not rejected;
  • across the lane's whole graded record, no grader-accepted answer moves;
  • on the ticket's own challenge, any value it replaces was only ever rejected or unknown, and every such move is reported;
  • for warmups, the predicted Mastery cases still pass;
  • the question is not already accepted. A late but correct patch is refused as "no gain" and retargeted to the next mode's ticket, or carried forward.

That is a regression and containment guarantee, not proof that a new answer is right. With no recorded accepted value, the judge can show that the patch answers the ticket, avoids known-rejected values and keeps every earlier accepted answer.

Carry in detail. For live web targets, carried code is scoped to the target family, earns trust only after the grader accepts it on a later mode, and is demoted after repeated refusals. For file lanes, a derivation agent turns a saved hand method into a reusable patch. From Day 31 an accepted hand method is also wrapped into a patch mechanically and judged at once; on its first live morning all 8 wrappers were refused because the method did not reproduce the answer on the ticket's file, and the patch agents carried those lanes instead.

Two trust boundaries. The model and the patch are not isolated the same way. The model gets the ticket's facts and the artifact paths, and has repository tools governed by an allowlist and written instructions; it is not inside the patch sandbox. Only running its candidate patch is isolated. So prompt compliance and tool policy are controls outside the judge's operating-system boundary.

The artifact boundary. Archive extraction rejects absolute paths, parent traversal, backslashes, NULs, links and special files, and caps total size, member size, file count and compression ratio. The known limitation: the fallback archive tool runs directly under a 120 s timeout, and its output is only checked after extraction.

Refusal detection is a heuristic: the agent pool scans stop reasons, common refusal wording and a safeguard event, then requeues the ticket to the fallback models.

05 · Roles

The team

One human, several models, each with a job. All the models are Anthropic's, on purpose, so the event's files stayed with one vendor while the robot was being built. A coding agent from a second vendor did one refactor on Oct 11, was then barred from the repo, and was let back in on Oct 29 for builder work.

Me: policy and risk

I set the rules, approved anything that spent a scarce ranked attempt or touched the live server outside the race, owned the scoreboard record, and supervised the morning race. Every standing decision went into the repo's instruction file with a date, so that file doubles as a decision log.

Claude Opus: the main loop

Did the engineering and explained it as it went. Owned the commits on a private repo and wrote a technique note for every challenge. I pinned that working style on purpose: the model does the work, and I come out knowing the technique.

Claude Fable: the advisor

A stronger reviewer, consulted before committing to an approach and again before calling work done. Opus made the final call after that review.

Race-time agents: Sonnet and Opus

The patch agents and hand agents from the morning above: three patch agents and an Opus hand agent per lane, plus a Sonnet hand agent on web and the spares, with short-lived derivation agents turning accepted hand methods into patches.

Refusal fallbacks: Mythos, then Opus 4.6

When a safety filter balks, the task goes to a Mythos-based analyst, then to an Opus 4.6 analyst. Both are pinned subagents, checked on their models on Oct 10.

Reviewers: fresh Opus instances

Independent, read-only reviewers for anything that runs while a clock is live, returning CONFIRMED or NOT CONFIRMED with MAJOR and MINOR findings. Early on the reviewers themselves were tested by planting bugs for them to find.

06 · Method

How it got better every day

The robot learned something every morning, but a lesson was only worth keeping if I could prove it made things better without breaking anything that already worked. That is where most of the engineering went. If someone (usually a model) claimed a fix was faster or more correct, there was a tool that measured it like for like. Of everything here, this is the part I would carry to any other project.

Replay against the grader

Every solver re-runs over every attempt ever recorded and is compared with the grader's own verdicts. A crash, a wrong first guess or a value the grader once rejected is a fail. From Day 25 an unanswered question fails too: any shape we have been shown must have a solver.

Answer-diff

Old code against new over every recorded file. The only answers allowed to change are the ones the change names in advance, so a fix cannot quietly move an answer somewhere else.

The commit gate

Nothing gets saved without passing replay, answer-diff, the unit tests and timing checks, run on 16 workers at once. By Day 28 the full gate covered 70 modules and took 521 s, about 8.7 minutes.

A fake Game Master

A local stand-in for the event server, for practice races. It plays back recorded days with their real delays and rate limits, throws scripted faults (server errors, dropped submits, slow downloads), and uses a load model fitted to Day 19's live trace. The rule: the old robot on the fake server had to match the old robot live, or the fake was not a fair benchmark.

Blind runs

A practice race where the robot knows only what it knew the night before that day. Every decoder, reader and vocabulary entry is tagged with the day it was learned, so a blind run can switch off everything learned since. The rule: a drill that leaks hindsight is invalid.

What would it have changed?

Two more drills: run the night-before code against a recorded morning and score each lane's first try, or drop a new fix onto every past night-before and ask whether it would have changed that morning. Day 26's blind before-and-after showed no measurable change (98 against 103 s mean), and it was reported as exactly that. Most claimed speed wins died this way, which was worth knowing.

Reviews scale with risk. Code that runs while a timed attempt is live gets one independent Opus reviewer. Solver changes get none, because replay and answer-diff against the grader are the check. On Oct 12 the review process itself was tested by committing deliberate bugs in a scratch copy and running them through every layer. Round one found three critical holes; later rounds caught 10 of 12, then 11 of 11.

None of this is exhaustive. Replay covers the variants our team received, and an unrecorded answer has no ground truth. The fake server is calibrated against selected live traces and does not reproduce every server delay or live target.

07 · Chronology

The story in five phases

Oct 10 to 13 · Days 1 to 13

The backlog sprint

The repo started at 23:49 on Oct 10, ten days into the event. Days 1 to 6 were solved and turned into solvers in one day: 167 commits on Oct 11. The habits that carried the whole month formed here: a solver per challenge, one shared engine per lane, replay against every graded answer, a measured rate limit, a commit gate.

Oct 14 to 18 · Days 14 to 18

v1 goes racing

The first live morning: 36th in 658.9 s, while the winner took 13.6 s. That stung, and it forced a pivot: lanes in parallel, the reviews and holds dropped, no model in the path. Day 16 was 8th, Day 17 1st (a slow field), Day 18 4th at 91.9 s against 45.5 s.

Oct 18 · 23 hours before Day 19

The rebuild

After Day 18 I froze v1 as the fallback and asked for a lean rebuild from scratch. A frozen skeleton went up at about 10:15. Around 25 components were built by parallel builder agents between 11:27 and 13:24, reviewed through the afternoon, and calibrated against recorded days by 16:00. 140 commits that day.

Oct 19 to 29 · Days 19 to 29

v2 and the web lane

Day 19 was a failure of my own making: the poller buried our own account in requests while hunting for the new web lane, and we placed 62nd. Day 23 placed 20th after a script batch collapsed. Then it clicked. Days 21, 22, 24, 25, 26 and 29 were outright wins, and Day 29's 72.5 s put us 1st overall.

Oct 30 and 31 · Days 30 and 31

The finish

Day 30 was 2nd by 6.9 s. Then SHA1-Hulud took 1 h 48 min by hand, and its 5 points re-sorted the tied field. On Day 31 five lanes were done by 76.9 s, and the last web challenge hid the one header that mattered for 228 s. 4th on the day, 4th overall.

08 · Evidence

Results

Days 1 to 13 were played after their release, as a backlog, so they have no race time. The race chart starts at Day 14, the first morning the robot ran live at 09:00. In the chart, the solid line is us and the dashed line is the day's winner, or the runner-up on days we won. Lower is better, and the scale is logarithmic, so the two big spikes are even worse than they look.

Release to last check, live days (seconds, log scale)
WizdumbDay winner, or the runner-up on days we won
10301003001k3k10kD14D15D16D17D18D19D20D21D22D23D24D25D26D27D28D29D30D31Day 14: Wizdumb 659 s, 36th. Day winner 13.6 s. 15 checks.Day 15: Wizdumb 530 s, 16th. Day winner 114 s. 15 checks.Day 16: Wizdumb 231 s, 8th. Day winner 62.1 s. 15 checks.Day 17: Wizdumb 675 s, 1st. Runner-up 985 s. 15 checks.Day 18: Wizdumb 91.9 s, 4th. Day winner 45.5 s. 15 checks.Day 19: Wizdumb 7,110 s, 62th. Day winner 1,050 s. 24 checks.Day 20: Wizdumb 330 s, 7th. Day winner 163 s. 21 checks.Day 21: Wizdumb 213 s, 1st. Runner-up 219 s. 24 checks.Day 22: Wizdumb 89.8 s, 1st. Runner-up 117 s. 21 checks.Day 23: Wizdumb 1,851 s, 20th. Day winner 539 s. 24 checks.Day 24: Wizdumb 81.3 s, 1st. Runner-up 156 s. 21 checks.Day 25: Wizdumb 100 s, 1st. Runner-up 138 s. 24 checks.Day 26: Wizdumb 69.0 s, 1st. Runner-up 154 s. 21 checks.Day 27: Wizdumb 329 s, 4th. Day winner 172 s. 24 checks.Day 28: Wizdumb 262 s, 2nd. Day winner 231 s. 21 checks.Day 29: Wizdumb 72.5 s, 1st. Runner-up 154 s. 21 checks.Day 30: Wizdumb 101 s, 2nd. Day winner 94.0 s. 21 checks.Day 31: Wizdumb 256 s, 4th. Day winner 234 s. 21 checks.Day 19: 7,110 s, own poll loadDay 23: script batch collapse72.5 s255.5 swinner 13.6 s
Days 19, 21, 23, 25 and 27 carried 24 checks; Days 20, 22, 24, 26 and 28 to 31 carried 21; Days 14 to 18 carried 15. Hover a day for its numbers.
Live-day race results and what decided each day
DayOur timePlaceChecksWhat decided it
Day 14 658.9 s 36th 15 First live morning. Model work before the first clock; metadata met a new LNK format.
Day 15 530.2 s 16th 15 Binary and metadata went through lane agents; the warmups Mastery took three tries.
Day 16 230.7 s 8th 15 Three agent lanes (Morse, email, WebAssembly) were the gap.
Day 17 674.7 s 1st 15 A binary wording hunt on one field. The whole field was slow on that challenge, which the organizers later reissued.
Day 18 91.9 s 4th 15 Warmups was the entire gap; four lanes were done by 43.6 s.
Day 19 7110.4 s 62th 24 First v2 race and first web day. Our own poller load; web solved by hand.
Day 20 330.3 s 7th 21 Web was the critical path; the file lanes were done by 45 s.
Day 21 213.4 s 1st 24 Web was the critical path again; the first outright v2 win.
Day 22 89.8 s 1st 21 A binary bridge challenge on the second binary racer was the critical path.
Day 23 1850.9 s 20th 24 Script batch collapse: wrong answers labelled certain, expired attempts, a 429 storm.
Day 24 81.3 s 1st 21 Web and warmups; an agent-written EVTX reader landed in 13 s.
Day 25 100.3 s 1st 24 A warmups decode-tail miss on set 79.
Day 26 69.0 s 1st 21 All 21 correct; every file lane done by 58.9 s, web last at 69.0 s.
Day 27 329.0 s 4th 24 Web race condition: exploration spent a single-use target, losing a Time Trial and a Mastery attempt.
Day 28 262.0 s 2nd 21 Binary hand answers carried values, not methods, so every fresh file reopened the same families.
Day 29 72.5 s 1st 21 The second web Mastery was the last check, after a hand answer (about 17 s) and a judged patch (16 s).
Day 30 100.9 s 2nd 21 Two new web techniques. Hand answers did not turn into code fast enough, so each web mode waited on another one. 2nd by 6.9 s.
Day 31 255.5 s 4th 21 Framework Roulette: the header the app read its role from was named in a Vary response header, and our tools read bodies only. About 228 s on one Single Solve.
Each lane's time to its last check, live days (seconds)
LaneD14D15D16D17D18D19D20D21D22D23D24D25D26D27D28D29D30D31
warmups 576.9308.793.833.691.9123.16.36.696.540100.324.5308.410.310.16.5
metadata 658.9475.8107.731.722.9180.117.333.112.78817.616.53123.627.816.733.676.9
script 320.835.930.814.444.5127.17.710.211.91,851111112.917.51615.627.714
binary 364530.2230.7674.719.229344.843.189.83426.120.446.532.72622781.172.2
mobile 305.828.422266.8121.86.66.27.978.232.96.458.97.3920.125.87.1
web ·····7,110330.3213.462.7112.681.389.76932988.372.5100.9255.5
Darker is slower, and the bold cell in each column is that day's critical path. A dot means no web lane that day; on two-web days the slower web lane is shown. On Day 29 every file lane was done by 27.0 s. On Day 31 five lanes were done by 76.9 s, and web took 255.5.
Hall of Fame speed boards: our podium finishes by day
1st2nd3rd
048121Day 2: 1st 0, 2nd 1, 3rd 0Day 3: 1st 0, 2nd 1, 3rd 0Day 4: 1st 0, 2nd 0, 3rd 45Day 6: 1st 0, 2nd 0, 3rd 3Day 7: 1st 0, 2nd 1, 3rd 2Day 8: 1st 0, 2nd 0, 3rd 1Day 9: 1st 0, 2nd 0, 3rd 210Day 10: 1st 0, 2nd 0, 3rd 1Day 13: 1st 3, 2nd 2, 3rd 015Day 15: 1st 0, 2nd 0, 3rd 3Day 16: 1st 0, 2nd 1, 3rd 0Day 17: 1st 0, 2nd 1, 3rd 020Day 20: 1st 0, 2nd 1, 3rd 0Day 21: 1st 0, 2nd 1, 3rd 2Day 23: 1st 2, 2nd 5, 3rd 4Day 24: 1st 2, 2nd 6, 3rd 125Day 25: 1st 3, 2nd 4, 3rd 4Day 26: 1st 3, 2nd 5, 3rd 2Day 27: 1st 0, 2nd 2, 3rd 1Day 28: 1st 0, 2nd 1, 3rd 2Day 29: 1st 3, 2nd 0, 3rd 130Day 30: 1st 1, 2nd 1, 3rd 031Day 31: 1st 3, 2nd 3, 3rd 1
Podium data
Day1st2nd3rd
Day 2010
Day 3010
Day 4004
Day 6003
Day 7012
Day 8001
Day 9002
Day 10001
Day 13320
Day 15003
Day 16010
Day 17010
Day 20010
Day 21012
Day 23254
Day 24261
Day 25344
Day 26352
Day 27021
Day 28012
Day 29301
Day 30110
Day 31331
Every timed mode has its own speed board that keeps each team's best run. Of 355 boards we held 20 firsts, 36 seconds and 34 thirds, and 246 top-ten places, at the Oct 31 read. These counts move as other teams improve their best runs.
Commits per day
060120180Oct 10: 3 commits10Oct 11: 167 commits11167 · v1 sprintOct 12: 156 commits12Oct 13: 138 commits13Oct 14: 30 commits14Oct 15: 27 commits15Oct 16: 36 commits16Oct 17: 60 commits17Oct 18: 140 commits18140 · v2 rebuildOct 19: 60 commits19Oct 20: 35 commits20Oct 21: 11 commits21Oct 22: 14 commits22Oct 23: 18 commits23Oct 24: 18 commits24Oct 25: 15 commits25Oct 26: 29 commits26Oct 27: 29 commits27Oct 28: 23 commits28Oct 29: 15 commits29Oct 30: 10 commits30
Commit data
DateCommits
Oct 103
Oct 11167
Oct 12156
Oct 13138
Oct 1430
Oct 1527
Oct 1636
Oct 1760
Oct 18140
Oct 1960
Oct 2035
Oct 2111
Oct 2214
Oct 2318
Oct 2418
Oct 2515
Oct 2629
Oct 2729
Oct 2823
Oct 2915
Oct 3010
1,034 commits in total. The Oct 11 to 13 sprint built the v1 robot and its safety net. The Oct 18 spike is the v2 rebuild. After that, v2 landed its changes between race days through the full gate.
09 · Technique

The six lanes

The example questions are invented to show the shape. They are not real challenge content or answers.

Warmups encodings

Task
A text blob in stacked encodings decodes to a sentence ending in a slug like word-word-word-NN.
Example
message produces amber-lantern-quartz-42
Technique
A layer search: the solver peels one encoding at a time and scores each result on how much it reads like English and whether it ends in the slug shape. Each decoder only runs when the text looks like its format, so the ones not needed cost nothing. Every Mastery line is classified and decoded on its own.
Discovery
On Oct 15 we worked out the generator: Day N's Mastery is its sentence cut into N lines, with line i in layer i of one growing list. Tomorrow is predictable except for one new layer, and a stress tool replays plausible next layers ahead of time.
Curveball
Day 14: Mastery 0 of 68 on its only ranked attempt, because a spaceless Caesar-7 fragment was never read.
Base64, ROT13, hex, binary, HTML entities, escapes, base32, Atbash, Caesar 7, ROT47, Morse over hex, Baconian over hex, rail fence, UTF-16 with a BOM, netstrings, Ook, reverse plus hex, ROT13 plus base64, and URL encoding applied twice.

Metadata forensics file formats

Task
A zip of evidence files. Each question asks for a structural fact, phrased Determine <ns>.<field> for <file>.
Example
Determine zip.eocd_total_entries for evidence-002.zip. Result: 3
Technique
Most formats are parsed directly. Standard-library container helpers are used where they keep the needed facts, and raw ZIP parsing where a zip's directory records can disagree with each other, the trick behind parser-differential attacks, where two programs read the same file differently.
Lesson
Answer in the form the producer stored, not a tidy reformat: GUIDs kept their braces, Message-IDs their angle brackets.
Curveball
A new format almost every day. Agent-written readers took 488 s on Day 11 and 13 s for EVTX on Day 24.
Hashes, BOMs, JPEG SOF and EXIF, PNG chunks, PDF, 7z, PE and .NET, MSI and OLE, LNK, OOXML, mail, WAV, SQLite, EVTX, registry hives, Prefetch, Mach-O, JAR, Android manifests, pcap and pcapng packet counts, GPT and MBR disk structures, X.509 fingerprints, and byte-identical file groups.

Script analysis malicious scripts

Task
A zip of specimen scripts, each hiding a descriptor. Questions ask for the role, the ATT&CK technique id, indicators and step graphs. There can be thousands: about 10,500 in one Mastery on Day 23.
Example
Which ATT&CK technique fits launcher-02.js? Result: T1059.007
Technique
Read the script's own Material and Codec labels ("read the label, do not guess from the bytes"), decode to a key=value descriptor, and reject decodes that do not parse. A cmd.exe expansion emulator handles batch. Nothing is executed.
Curveball
Day 23: about 15% of answers wrong but labelled certain inside all-or-nothing batches. The worst morning on record.
PowerShell, JScript, batch, VBScript, Python carriers, Bash, Node, polyglots, WMI and MOF, AutoIt, MSBuild, Jenkins pipelines, GitHub Actions, JSP webshells, BeanShell, Elixir and BEAM, and XSLT.

Binary RE compiled programs

Task
Compiled programs from a new toolchain each day. Questions ask about container facts, symbols, sections, hashes, and the fields of an embedded configuration blob.
Example
Using the file in slot 2, what is config_domain?
Technique
Several early toolchains reused an encrypted, CRC-checked configuration format. Later days moved to unpacking, overlays, patch comparison, root-cause analysis and fault triage. Static readers pull structural facts; heavyweight decompilation is a last resort and never runs on the clock.
Discovery
Time Trials walk a fixed counter over slot variants, serving the file variants in the same order every time, and Mastery delivery D equals counter position D minus 1. So a position hedge sends answers predicted from files already seen alongside the download, before the files arrive; a wrong batch saves nothing, so it is free.
Curveball
Day 17: about 250 rejected wordings for one field before the organizers reissued the challenge with published rules.
C, C++, .NET, Go, Rust, Java, Kotlin, Swift, Nim, Zig, D, Pascal, Crystal, Objective-C, assembly and WebAssembly, plus ordered-set hashes, structural counts, embedded PE cases, branch opcodes, unpacking, overlays, patch diffing, root cause, fault triage, and whole malware campaigns.

Mobile Android APKs

Task
An APK whose manifest and code tell a story about a real Android weakness. The answer is an ANS- plus 16-hex code behind a named codec in a bundled JSON asset.
Example
codec: xor, key 29, data: base64 produces ANS-…
Technique
Treat the story as a decoy and undo the codec. The ANS- pattern tells the solver when it has the right answer, which makes it a correctness check for a depth-two search over the codec registry (up to two codecs chained), followed by six bounded brute-force families.
Escalation
From Day 23 the code had to be computed: a static dex bytecode interpreter, then a static x86-64 stepper for a native library, reflection, and split APKs.
Exported components, deep links, intent injection, backups, providers, WebView bridges, cleartext, trust-all TLS, keystore misuse, JNI, encrypted strings, reflection, emulator checks, integrity signals, split APKs, a white-box table codec, and a rolling XOR.

Web live targets, Day 19 on

Task
A live site built on demand. Exploit the bug and submit a proof_ token. Mastery gives several targets at once, and a target dies a few minutes after start.
Technique
Detect the technique by probing the page, not by trusting the challenge name. A toolkit covers fetch, forms, cookies, JWT, Flask sessions, access logs and packet captures. Requests outside the named host are refused in code.
Curveball
Day 31: the header the app read its role from was named only in a Vary response header, and every tool read response bodies, never headers. It cost about 228 s and, by four-tenths of a second, the podium.
Backup exposure, IDOR, SQL injection, LFI, XSS, session fixation, CSRF, upload, template families, second-order injection, over-posting, command injection, reset flows, GraphQL, webhook trust, XXE, deserialisation, access-control bypasses, host poisoning, NoSQL, websockets, forwarded headers, delegated identity, job queues, and proxy trust.

Across lanes, surprises fell into six types: answer wording for a known fact, a new question on a known format, a new Mastery shape or layer, a new file format, a new language or technique, and infrastructure faults. Wording problems hit the first day of a fact. New capability hit metadata and script almost daily. Shape problems hit Mastery first, because Mastery combines shapes the Time Trial does not show.

10 · Full record

What went wrong

I wanted the failures in here, because most of the robot's rules trace back to one of them. Four mornings did most of the teaching.

Day 14, the first live morning: 36th. The robot took 658.9 s; the winner took 13.6. We spent 97 s on model work before the first clock even started, a warmups detour held up three lanes that were ready to go, and a new shortcut-file format sat waiting on the main session. The fix was the whole idea on this page: every lane in parallel, known shapes as plain code, no model in the path.

Day 19, the first web day: 62nd, and entirely my own doing. The poller expected the web challenge under Day 19, but web numbered its own days. So it kept asking for 66 minutes, 23,383 calls, two thirds of them resends, and the server started holding our account 20 to 50 seconds per call. The file lanes were done by 293 s. Web was solved by hand at 7,110 s.

Day 23, the worst morning on record: 20th. About 15% of the script answers were wrong but marked as certain, so they rode inside all-or-nothing batches and sank every good answer with them. Resends burned the clock, more than fourteen ranked attempts expired, and the script lane collected over 2,500 rate-limit refusals. Afterwards, one batch first, then smaller packs by question type, and nothing resent after a deadline.

Day 31, the one that cost the podium: 4th by four-tenths of a second. Five lanes were done by 76.9 s. The last web challenge, Framework Roulette, named the header it read its role from only in a Vary response header, and every tool the robot had read the body of a response, never its headers. About 228 of our 255.5 s went on that one Single Solve. The fix is small: read the headers too. It came one day too late.

And one that was not a bug at all: on Day 30, SHA1-Hulud, a classic crackme with no questions to open a ticket on, took 1 h 48 min by hand, and its 5 points dropped us from 1st overall to 10th that afternoon. Some things you just solve.

For the technical reader: the full incident log, 26 entries with root causes and what changed
Incidents, root causes and what changed
DateWhat happenedRoot causeWhat changed
Oct 11Script Day 3 Mastery came back CORRECT by luck.File lookup fell through to a global search, so set 2 was answered from set 1's file.Named nested zips resolve first. Lookup raises rather than guesses.
Oct 11Four rate-limit storms, up to 192 refusals in a minute.Five agents plus discovery on one identity; a rejected batch fanned out into singles, each retrying alone.Limit measured at about 100 per calendar minute. A shared governor; rejected batches split into 8, not singles.
Oct 12Day 8 started without my go.An announced plan was treated as approved.Rule: an announced plan I have not answered is not a go.
Oct 12Five refusals at the 09:00 release with only 13 to 15 calls in our minute. A Time Trial expired unsolved.Server side, later confirmed as a configuration issue.A release-window hold was added, then removed the next day.
Oct 12Round 4 of the commit gate's review: 1 critical and 6 major findings.An empty candidate list ended the submitter, among others.One fix per commit, re-reviewed until CONFIRMED.
Oct 13The binary answer cache was keyed, in effect, on the filename.AES zips store CRC 0, so 1,079 of 1,153 members had the same "checksum".Keyed on decrypted content and question text, with a fallback on rejection. A leave-one-out test, hiding each answer from the cache in turn: 8,180 of 9,151 served, 0 wrong.
Oct 13Day 13 rehearsal: every check correct, but 65 minutes release to last Mastery.Slow lookups, 11 minutes of commits mid-run, 52 unneeded coverage runs, a false speed hold, and two lanes deadlocked on the commit gate.Live days commit once, at day close. Eleven proposals built overnight.
Oct 14A position-hedge batch of 300 answers came back incorrect.A second Mastery on the same challenge carried a different delivery-3 file.Hedge restricted to a challenge's first Mastery, later to exact file matches only.
Oct 14First live morning: 36th, 658.9 s. The winner took 13.6 s.97 s of model work before the first clock; a warmups detour held three ready lanes; a new LNK format waited on the main session.The release race: parallel lanes, deterministic handling for known shapes, holds and readiness reviews dropped.
Oct 14Four Mastery retries refused with HTTP 503 retry_rotation_invalid.Server side; the first such refusal in 110 Mastery retries.A 5xx is status-checked, never read as a solver miss.
Oct 15Warmups Mastery 0 of 73, then 72 of 73, then CORRECT on the third try.A Caesar-7 fragment read as ROT13.The deep walk tries Caesar shifts; a shift named in the title is promoted; a recipe stress tool.
Oct 17Binary took 532 s on one field, about 250 rejected wordings.A value the file could not hold. The gate also refused a rule that listed known-rejected words first."Derive first, then guess wide at once." The organizers reissued the challenge.
Oct 18The early start for the binary lane never fired live.The server refuses a lane filter for binary; the mock stalled lane lists too, so no rehearsal showed it.Use a search query. Rule: probe any new server parameter live through the real code path.
Oct 18A test process had pinned a CPU core for 38 hours.A detached child survived its dying parent.Parent-death signals on every spawned process.
Oct 19Day 19, the first web day: 62nd. File lanes done by 293 s; web solved by hand at 7,110 s.The poller expected web under day 19, but web numbers its own days. It listed for 66 minutes (23,383 calls, two thirds of them resends), and the service held our identity 20 to 50 s per call.Fast signals became single shots; a slow full-list poll stays for late challenges. Web is grouped by each entry's own day field.
Oct 20Three web agents and the Mythos fallback all refused.Safety classifiers on exploit writing.Agent prompt: read the ticket's prompt first and use every path it names. Solved at 276 s.
Oct 23Day 23: 20th, 1,851 s. Fourteen-plus ranked attempts expired, and the script lane recorded over 2,500 rate-limit refusals.About 15% of script answers were wrong but marked certain inside all-or-nothing batches; halving resends burned the clock; the judge refused repair patches; the watcher acted 8 minutes late.One batch first, then packs split by question family; no resend after expiry; late sends recorded as unknown; a coverage gate and scoped watcher tools.
Oct 25Warmups set 79 missed on the clock.The decode ended in an extra number. An earlier "helpful" change sent the slug alone, and the grader rejected it.Rule: if the file decodes cleanly, send exactly what it says first.
Oct 25The binary judge drifted to 27 to 31 s against its 30 s wall.Speed-run recordings bloated the corpus.302 recordings archived (judge back to 12.9 s); speed runs record elsewhere.
Oct 27A web target's single-use state was spent during exploration. One Time Trial and one Mastery attempt were lost.The generic sweep wrote before it knew which action was destructive. Correct patches were then judged against a spent target.Status routes run first and initial writes go as one concurrent group. Accepted evidence from another attempt of the same challenge can support a scoped live patch.
Oct 27A synthetic-clock drill looped through 720 retries before it was stopped.A free retry reconnects to the same open attempt, so the drill never got the fresh state it assumed.The drill uses one target reset as a fresh-attempt stand-in.
Oct 28Binary finished at 262.0 s despite an early Single Solve.Hand answers carried values but not methods, so every fresh file reopened the same families.Accepted hand methods start derivation agents whose judged patches carry into later modes.
Oct 28An experimental family-agent system launched 46 concurrent judges.Covered judges took a median 23.7 s, and 21 of 156 failed after promotion removed a baseline they were still reading.Family agents off by default. Superseded baselines survive 210 s, and already-covered work returns without a sandbox run.
Oct 30Day 30: 2nd by 6.9 s.Two new web techniques. Each web mode waited on a fresh hand answer, because the accepted ones did not turn into code fast enough.An accepted hand method is wrapped into a patch at once and judged like any other.
Oct 30SHA1-Hulud took 1 h 48 min, and its 5 points dropped us from 1st overall to 10th that afternoon.A standard crackme with no questions, just a flag field, so no ticket ever opened. It was solved by hand.No new code: a one-off, by design never automated.
Oct 31Day 31: 4th by four-tenths of a second, with about 228 of our 255.5 s on one Single Solve.Framework Roulette named its role header only in a Vary response header. The probe tool and the web engine read bodies, never headers.The fix is small: read Vary and any custom response headers, and try a ladder of role values on whatever they name. It came one day too late.
11 · Governance

Rules that changed

Every decision I made went into the instruction file with a date, and about two dozen of them were later reversed. Read in order, the reversals tell one story: the goal moving from "never waste a scarce attempt" to "seconds to all checks correct". A few of the big ones:

  • One clock at a time (Oct 11) became parallel clocks in a release race (Oct 14).
  • Protect a correct timed Mastery and prepare until nothing new shows up (Oct 12) became: a Mastery with more than 3 attempts goes as soon as possible (Oct 14), because a miss costs one attempt and nothing on the board.
  • Review everything (Oct 12) became review in proportion to risk (Oct 13), because a day must run from Single Solve to Mastery without waiting on reviews.
  • A self-imposed cap of 80 calls a minute became no cap in a race at all (Oct 14), only a guard against a runaway loop: never hold answers back on a guessed limit.
  • v1 is the robot became v1 frozen as the manual fallback and v2 built from scratch (Oct 18), after Day 18's 92 s against a 45 s winner.
For the technical reader: all dated policy changes, in order
Dated policy changes, in order
DateRuleBecameWhy
Oct 10The event guide's "never solve without being asked" (written for a coaching bot)Claude does the work and explains while workingI wanted a robot and an education, not coaching
Oct 11 to 12Stable after 3 clean runs, then 5Stable after 5 runs that bring nothing new"A count of clean runs was the wrong bar"
Oct 11One clock at a time, in silenceParallel clocks in a release race (Oct 14)Parallel for speed
Oct 11Practice "completes the mode, points unverified"A practice completion earns the check mark (Oct 14)My board showed it
Oct 12No ranked clock 08:45 to 09:15Removed Oct 13The 09:00 throttle was a server issue; start-to-finish time decides Day 31
Oct 12Protect a correct timed Mastery; saturate firstA Mastery pool above 3 goes as soon as possible (Oct 14)A miss costs one attempt and nothing on the board
Oct 12A 600 ms speed hold before MasteryA per-challenge hold, then dropped on release runsNo single time fits every challenge
Oct 12Review everything (five gate rounds, 13 per-fix reviewers)Review in proportion to risk (Oct 13)"A day must run from Single Solve to Mastery without waiting on reviews"
Oct 13Readiness review before a day's first timed runDropped on release runs (Oct 14)Known shapes must start without a review wait
Oct 14Commit fixes as they landLive days commit once, at day closeCommits cost clock time and caused the Day 13 deadlock
Oct 14A cap of 80 calls per sliding minuteNo self-imposed cap in a race, runaway guard only"Never hold answers back on a guessed limit"
Oct 14Board record hand-pasted by meGenerated from the public API (Oct 24)The API became available; never hand-edit
Oct 15Timing check blocks a commitAdvisory"Let's not be so strict"
Oct 17A non-derivable answer stops the lane as a possible challenge bugReport it and guess wide at once, no cap, never waitA guess costs nothing; waiting costs the race
Oct 17Describe every post-run change and wait for my vetoChanges with no new blockers land without a vetoSpeed of iteration between days
Oct 18v1 is the robotv1 frozen as the manual fallback; v2 built from scratchDay 18 was 92 s against a 45 s winner
Oct 26Every finished attempt enters the corpusSpeed-only runs write elsewhereSpeed recordings pushed the binary judge to 27 to 31 s
Oct 27A live web patch proves itself only on its own ticketAny accepted attempt of the same challenge can supply evidence, with target-family scope and later grader trustA correct patch was blocked by a spent target
Oct 27Build an early reset for a spent ranked targetParked, not built"Beyond what is necessary; other unseen risks rank higher"
Oct 28A hand answer carries only its valueSave the method and start a derivation agent after acceptanceValues did not solve fresh files in later modes
Oct 28Start a code-agent pair for every open familyOff by defaultConcurrent judging overloaded the shared baseline
Oct 29Land the agent-director system if builtParked, never landed or runControlled drills did not justify it
Oct 29A Single-Solve-only extra challenge can take the binary laneThe real binary challenge keeps its lane; the one-off goes to a spareThe regular binary race must not be displaced
Oct 30A derivation agent turns hand work into a patchThe accepted method is wrapped into a patch at once, the deriver kept as fallbackDay 30's web modes each waited on a fresh hand answer
12 · Primary sources

In my own words

"we're in 35th after that attempt this morning. We need to adjust in order to make ourselves faster to the finish line, it's what will decide the entire competition on the 31"Oct 14, after the first live morning
"If no model had been in the path, 9:01 is possible: this is what we're striving for."Oct 14
"every day is basically just a race to solve at this point and it will remain that way through till the end ... there is no dynamic scoring ... everyone will be keeping the same score till the end."Oct 15, evening
"we should still prepare and practice for curveballs since I would expect the last day to include some. It's better that we practice and prepare beforehand on the days leading up rather than get caught slow and lose the whole comp."Oct 15, evening
"the head start wins the comp"Oct 15, on racing warmups before the day list appears
"race both ways, keep the first"Oct 28, on racing a code-first hand agent beside the value hand agent
"We must get this solve. So if we have to keep going, we keep going. If we don't solve this, we can't win at all."Oct 30, 10:25, inside SHA1-Hulud
"If we found that header, how much time would we have saved, roughly?"Oct 31, 09:48. Roughly two and a half minutes.
13 · Lessons

What carries over

Deterministic first, AI at the edges

Every known shape became plain code, so a refusal, a slow model or a bad prompt can delay a patch but never stop the robot. The models earn their keep on the shapes nobody has seen yet.

A narrow handoff beats a big prompt

A typed ticket with capped facts, a reason and a single output shape got agent ticket-to-patch time from minutes in v1 down to 6 to 40 s.

Judge the patch, not the model

Model-written code goes live only after sandboxed replay against every answer the grader has ever accepted. That makes it safe to let agents patch a running race.

No hindsight in the drills

Knowledge days, hold-outs, counterfactuals and a calibrated mock, with one rule over all of them: a drill that leaks hindsight is invalid. Most "speed wins" did not survive that test, and that was worth knowing.

Rules built for scarcity have to go

Two dozen dated rule changes trace the objective moving from protecting scarce attempts to raw seconds. Writing every decision down with a date made those reversals cheap.

Read what the machine was told

The robot read everything the author meant for a player: files, bodies, prompts, routes. The last curveball was in the part of the response meant for machines. Next time, the headers get read too.

14 · Provenance

Sources

Everything here comes from the project's private repository: the instruction file and its dated decisions, the daily plan addenda, the design and contract documents, the session log, technique notes, lane playbooks, review files, git history, and the leaderboard record generated from the public scoreboard API. Line and test counts are from wc and grep, not from running the suites, and agent and judge timings come from the robot's own traces.

A few things are worth knowing when reading the numbers. Day 19's board time is 7,110.4 s because the web lane was solved by hand late; the slowest file lane finished at 293 s. Day 17's 1st place was at 674.7 s against 985.0 s, on a challenge the organizers later reissued. Speed-board counts change as other teams improve their best runs. The agent-director system exists only in parked work and was never part of the racing robot.

Left out on purpose: flags, the team token, challenge artifacts and answer values, and the details of the private infrastructure the robot runs on.

The day-by-day story is in the diary.