All Screeps posts

ScreepsAiSLP Build Log · Part 7 of 8

ScreepsAiSLP Build Log – Part 7: Passing the Test, Failing the Room

October 18, 20267 min read

Stuck at zero

At the end of Part 6 the agent was running back-to-back on M2, the extensions-and-roads milestone. On Monday night I finally pulled up the overview of the last twelve hours, and it was the same line over and over:

level 2, extensions built 0, extension sites 5, roads built 0, road sites 50

Every test since late afternoon had ended exactly like that. One run had worked for an hour and a half and didn't commit a single change of its own. The agent was busy, it was trying things, and not one number moved.

That's the moment I'd been half expecting since Part 6. The agent can only guess from what's in front of it, and what was in front of it was "0 extensions finished" and nothing else. Running the same 13-minute test again wasn't going to show it anything new.

One hint, written in a file

So I did what a human reviewer is for. I copied the builder code off the server and read it with Claude. The logic looked fine on paper, which usually means the problem only shows up when the game is actually running. The most likely suspect:

  • The extension sites were placed on the eight tiles right around the controller, exactly where creeps walk to upgrade it.
  • In Screeps you can't build an extension while a creep is standing on its tile. The build call returns an error instead.
  • The builder code only handled two kinds of errors and silently ignored every other one. Both builders always picked the same closest site, so they could stand there trying the same blocked tile forever, and never even get to the roads.

The fix for the code was the agent's job. My job was getting the hint to it. That's what the FEEDBACK.md idea from Part 6 was for, and it became one small change:

  • The file lives next to the standing task in a system folder. The agent can read it but can't change or delete it, and it never goes into the public repo.
  • The standing task got one new step: right after reading the last gate result, read FEEDBACK.md, and follow it before your own plan.

The hint itself was plain advice, the kind you'd give a junior developer: stop changing logic blindly, measure first with a short 1000-tick debug test that prints what each builder is doing, handle every error code, put extensions near the spawn, and put roads on the real paths instead of a grid. I stopped the stuck run, and the next one started with the hint.

M2 passes

Tuesday evening I checked in, and the gate had pushed. M2 had passed.

The commit list read almost like my hint, point by point:

What the hint saidWhat the agent committed
Handle the "creep on the site" errorBuilders handle it and skip blocked sites
Extensions not next to the controllerExtensions placed away from the controller
Don't keep trying the same blocked tileBuilders filter out occupied sites
Clean the backticks out of the M1 blog postRewrote the M1 post

That was the most satisfying part of the whole week. The feedback channel works: one plain-text file, read at the start of a run, and the agent acts on it.

I pulled the code on my main computer, built it and pasted it into the game on shard2. It runs without errors, and the controller is now close to level 3. I tagged it on GitHub as v0.2.

Then I read the details, and it was closer than it looked. The passing run had finished exactly 1 extension in 3,000 ticks, the bare minimum the test accepts. The very next run's gate failed with 0. So it passes, but only just. The real room was about to show me why.

Then I looked at the room

The test was green. The colony was growing. And the roads were terrible.

My room on shard2 running v0.2. Every small green ring is a planned road tile.

Every little green ring is a road construction site: a spot where the bot has decided a road should go. They're scattered over the whole room, along the edges, in empty corners, next to walls, far from anywhere a creep ever walks. The few roads actually finished are short stubs in the middle of nowhere.

The agent's own status.md said roads were placed "along paths from spawn to sources and controller", and extensions "near the spawn". So I read the code again:

  • Roads: every 100 ticks it tries 5 more spots, first on a fixed grid every 10 tiles across the room, then on random tiles. There's no limit and no stopping. And there's a hard cap of 100 construction sites per player, so sooner or later these useless sites would block the containers and extensions the bot actually needs.
  • Extensions: also a fixed grid, starting at hard-coded coordinates. The comment above it names where the spawn and controller sit in the test room. My real room looks nothing like the test room.
  • Builders: while fixing the blocked-site bug, the agent had quietly dropped the "extensions first" rule. Builders now go to the closest construction site of any kind. With dozens of road sites everywhere, the closest one is almost always a road, often on swamp (5 times the work), and the code doesn't even stop it from planning roads on natural walls (150 times the work). In my real room, not a single extension has been finished. Too many construction sites and no priority: that's why the bot barely scraped through the test, and why the room looks the way it does.
  • The description: status.md described the code the agent meant to write, not the code it wrote.

None of that broke the test, because the test never asked. My M2 test checked counts: at least 5 extensions placed, at least 1 finished, at least 5 road tiles placed, at least 1 finished. Fifty random road tiles pass "at least 5" just as well as a good road network. The agent did exactly what was measured, and nothing that wasn't. That's not the agent cheating. That's me writing a test that measured the wrong thing.

A new M3: build properly, then defend

The fix starts with the test, because the test is the only thing the gate enforces. I changed the roadmap: the next milestone is no longer containers. A base has to build properly and be able to defend itself first, so the new M3 is build priorities, layout and a tower. Containers move to M4; that test is already written and waiting.

A tower needs controller level 3, which a short test room never reaches on its own. So the M3 test sets the room to level 3 at the start and runs 4,000 ticks. Then it checks:

CheckWhy
A tower is finished and held at least 500 energyThe base can defend itself
At least 3 extensions finished, all 10 built or placedExtensions have to win over roads, not scrape by with 1
At most 10% of the build energy goes into roads while tower or extension sites existPriorities, measured from the game's own event log
Extensions and tower within 8 tiles of the spawnShort trips to refill them
No road on a natural wallA wall road costs 45,000 build progress instead of 300
At most 90 road tiles, connected from the spawn to every source and the controllerRoads where creeps actually walk; the routes need about 60
At most 5 road tiles not connected to that networkNo more random stubs

The road checks don't trust anything the bot says. The test walks the road tiles itself, starting next to the spawn, and checks where it can get to.

The new FEEDBACK.md tells the agent the rest in plain words: what's wrong in the code, that status.md has to describe what the code really does, never to use coordinates from the test room, how roads are usually planned in Screeps, and what a simple tower should do (shoot intruders first, heal second, repair only while it keeps a reserve).

I haven't seen the agent's first try at the new M3 yet. That's the next post.

What I learned

  • One good hint beats hours of retries. Twelve hours of runs moved nothing. One file with a concrete suspect and "measure first" got M2 through within a day.
  • The agent builds exactly what the test measures. "At least 5 road tiles" got 50 random ones. If quality matters, the test has to measure quality: where things are, how they connect, what they cost.
  • Fixing one thing can quietly undo another. The blocked-site fix rewrote the builder and dropped the extension priority on the way. Only a test that checks the priority's result keeps it in place.
  • Look at the real thing. Green tests, a pushed commit and a nicely worded status.md all said "done". One screenshot of the room said otherwise. Deploying and watching is still my job, and it's the step that caught this.
  • The agent's notes describe its intentions. status.md said what the code was meant to do. From now on I compare it with the code, not just read it.

Next: the agent's first try at the new M3, priorities, layout and a tower. Then M4, containers and static mining.