devlog.

AgentGB · Cartridge fault

The trainer who saw him black out

Four of the six agents in one swarm film end their run inside Viridian Forest. The first tile is the interesting one: he walks in, is immediately put into a trainer battle, wins it, is put into another one, and then spends the remaining 4,283 decisions of his budget walking in a twenty-eight-tile circle near the door. The fight was not his fault, and it was not the network's. The cartridge had been holding it open since the last time he fainted.

9
Decisions between crossing into the forest and the trainer battle starting
45
Tiles between where he blacked out and where that fight started
32/11,927
Recorded runs that show it — every one of them the same seed
0/32
Of those, how many finished the chain

measured inferred

Measured is a byte read out of a saved state or a field read out of a run record. Inferred is reasoning from one of those to something we did not read. Prior community work is named where it appears.

Nine decisions

He crosses from the Viridian Forest south gate into the forest on decision 4094 and lands on tile (17,47). The emulator's own map data lists that tile as one of four exits back to the gate he just came through — it is the doorway.

He never leaves it. Two decisions later a text box opens: Hey, wait up! What's the hurry? Four decisions after that the screen goes to the battle wipe, and on decision 4103 he is in a fight. Between crossing the boundary and the fight he pressed up, a, up, b, up, b, up, a, a, and his coordinates did not change once.

A Game Boy screen: the player stands at the bottom edge of Viridian Forest among the trees, and a text box reads 'Hey, wait up! What's the hurry?'
Eleven seconds cut from the swarm film, cropped to the first of its six tiles, at the film's own eightfold speed and otherwise untouched. Route 2, the gate, the forest, and the fight — then he wins it, and it starts again.

Decision 4096–4098 · on the doorway tile

Viridian Forest at its southern edge. The player sprite stands one tile inside the map; a text box reads 'Hey, wait up! What's the hu'.
Two decisions after crossing the boundary. He has not moved.

Decision 4108 · the fight

A Game Boy trainer-battle intro: the player's back sprite on the left, a Bug Catcher with a net on the right, and a text box beginning 'BUG CATCHER wa'.
A trainer battle, on the tile the map uses as its own front door.

It is a trainer, and the cartridge says so

measured Read at decision 4110: wIsInBattle ($D057) is 2, which the atlas names as a trainer battle and not a wild one. wCurOpponent ($D059) is 202 — at or above 200 it is a trainer class plus that offset, so class 2, a Bug Catcher. wTrainerClass ($D031) is 2 and agrees. The opponent is a WEEDLE at level 9.

There is nowhere for a Bug Catcher to be standing. The doorway tile is an exit; the fight started with the player one tile inside a map he had entered nine decisions earlier, and forty-five tiles — sixteen columns and twenty-nine rows — from where he last fainted.

The same tile, one visit earlier

This was his third visit to Viridian Forest. On the second he crossed the same boundary and stood on the same tile (17,47) for two decisions and walked on. Nothing happened. His first battle of that visit came ninety-eight decisions later, at (6,12), and it was wild.

Between the second visit and the third, one thing happened to him.

Decision Map Tile Screen $D057 $D059 $D618 Pressed
3303Viridian Forest(17,47)walking in, visit twonone00a
3634Viridian Forest(1,18)a wild CATERPIE, level 4wild00up
3708Viridian Forest(1,18)BLUE blacked out!wild00a
3709Viridian Forest(1,18)the warpblacked-out00a
3711Viridian Forest(1,18)the warpblacked-out01a
3714Viridian City(23,26)awake, 24/24none01a
4088Forest south gate(5,6)walking back upnone01up
4094Viridian Forest(17,47)crossing in, visit threenone01up
4098Viridian Forest(17,47)Hey, wait up!none01up
4110Viridian Forest(17,47)WEEDLE Lv9trainer2024a

measured $D618 is wViridianForestCurScript — how far through Viridian Forest's own map script the game is. It is 0 on both earlier visits, goes to 1 two decisions into the blackout, stays 1 through the warp, the Pokémon Center, Route 2 and the gate, and is still 1 when he steps back onto the doorway tile. The battle takes it to 4.

What survived the blackout

Comparing the same eight bytes at four moments answers which of them carries the fight across.

Address · symbol Walking, d3630 Blacked out, d3709 Awake, d3718 At the door, d4098
$CD60 wMiscFlags bit 00100
$CD2D wEngagedTrainerClass62022027
$CD2E wEngagedTrainerSet7337
$CF13 wSpriteIndex0444
$CC55 wTrainerHeaderFlagBit0444
$DA30 wTrainerHeaderPtr$6651$5A51$5A51$5A51
$D618 wViridianForestCurScript00 → 111
$DA39 wCurMapScript00 → 111

measured Every one of those bytes is 0, or holds an unrelated value, on the last decision of the wild battle. They are set on the next one — the decision the cartridge writes $FF into wIsInBattle, which the atlas names as the player blacked out and which is not a battle. wEngagedTrainerClass reads 202 and wEngagedTrainerSet reads 3 — a Bug Catcher, roster three — and the fight that started at the door was a Bug Catcher leading a level 9 WEEDLE.

$CD60 bit 0 — the flag that says a trainer has spotted the player — is cleared by the time he is awake in Viridian City. So is the engaged-trainer pair, by the time he reaches the gate. What is not cleared is the map's own script index, and the sprite slot and header pointer that tell that script which trainer it is about to run. Viridian Forest's script is left at step 1, which is a trainer is waiting to fight you, and the map runs it the moment the map is loaded again.

The blackout put him a town away and healed his party. It did not put the forest back the way it found it.

inferred Sprite slot 4's stored map coordinates read 22 and 6, and under Gen 1's four-tile bias on sprite coordinates that is tile (2,18) — one step east of (1,18), where he fainted. That is consistent with a Bug Catcher standing directly beside him at the moment the wild encounter started, and it is an inference from the sprite table, not a reading of the trainer's tile.

This one has a name, and it is not ours

The community found and documented this long before we walked into it. It is the trainer escape glitch, also called trainer-Fly, and the variant we hit is the death-warp one: faint to a wild encounter inside a trainer's field of vision, and, in the Glitch City Wiki's words, "the trainer will notice the player on that frame, advancing the meta-map script ID just before the player warps away." Returning to the map gives an instant encounter. The same wiki page names $CD60 bit 0 as the byte set when a trainer spots the player, which is the byte our own read agrees with.

Its wider significance is theirs too. Escaping a trainer battle rather than blacking out is what makes the glitch dangerous: it leaves an encounter staged from stale battle memory, and that is the foundation of the Mew glitch and a component of the arbitrary-code-execution routes speedrunners use in Red and Blue.

What we hit is the tame end of it. Our student blacked out rather than escaping, so the cartridge staged a real Bug Catcher with a real WEEDLE rather than a corrupted one, and nothing about the run afterwards is corrupt. The interesting part is not the mechanism. It is that an agent nobody told about any of this walked into it on its own, and that we can put a rate on it.

How often it happens to us

Every trainer battle a run starts in Viridian Forest is logged with the tile the player was standing on. Across every recorded episode we hold, those tiles cluster hard.

TileTrainer battles started thereWhat it is
(1,18)672Inside the forest
(26,33)157Inside the forest
(27,33)28Inside the forest
(17,47)21A south-gate exit tile
(26,19)7Inside the forest
(27,30)3Inside the forest
(2,19)3Inside the forest

One row is a tile you cannot fight anybody on. Following it out:

PopulationRunsDoorway battleFinished the chain
Every recorded episode we hold44,706
… of those, runs whose goal set can detect it11,927320
… spanning distinct seeds6251
The six paired sweeps of 7 Sep 202639060

measured Thirty-two recorded runs across five separate run roots start a trainer battle on a Viridian Forest exit tile. Every one of the thirty-two is seed 4200126. None of the thirty-two finished the chain.

That seed has been re-run under six different goal configurations in one day, scoring between 91 and 96 whole chains out of 100 between them, and it failed in all six. Only one other seed in the hundred does that. Changing what the student believes about battle screens, about items, about catching, does not touch this one, because none of it is about the student.

What it cost him

He won the forced battle on decision 4251. Three decisions later, on the same tile, BUG CATCHER wants to fight! again, and the same level 9 WEEDLE. That fight ran to 4377.

Then the run stops being a run.

Visit to Viridian Forest Decisions inside Distinct tiles Furthest north
One — decisions 2733–3086353111row 3
Two — decisions 3302–3709407116row 3
Three — decisions 4094–86604,56628row 35

The exit he needs is on row 0. On his first two visits he reached row 3, twice, having walked over a hundred distinct tiles each time. On the third he walked twenty-eight, never got above row 35, entered no battle at all after the two at the door, pressed down 2,358 times, and ran out of budget at (16,38) with the gate goal still latched: the goal that walks him back towards the door he came in through.

What we cannot say from this recording

  • When the sight line actually fired. Every trainer byte is clear on decision 3708, the decision that prints BLUE blacked out!, and set on 3709. One decision is thirty-two emulator frames, so this recording cannot separate the trainer noticed him as the wild battle began and the write happened later from the trainer noticed him as the battle ended. The community describes the first; we measured the write, not the notice.
  • Which trainer the second battle was. No state was saved inside it. It was a Bug Catcher with a level 9 WEEDLE, from the screen, and that is as far as our recording goes.
  • How many other runs black out inside Viridian Forest. Answering that needs per-decision traces for episodes we only hold summaries of. The doorway signature above is what the recorded data can carry on its own, and it is a lower bound: a run that hit the same fault and then died before the goal fired would not appear in it.
  • wTrainerNo ($D05D) proves nothing here. It reads 3 from the first probe to the last and never changes, so its agreeing with roster three is a coincidence, not evidence. The identity comes from wEngagedTrainerSet, which changed.

What it changes

For the student: nothing to fix. He walked a legal route, took a legal encounter, lost it, and was warped away by the game's own rules. Everything after that was the cartridge running a script it should have reset. There is no observation he could have made and no button he could have pressed that would have avoided the second battle, because the fight was already staged before the map was drawn.

For us it changes how one number should be read. Every recorded run of seed 4200126 that reaches the doorway battle fails, thirty-two out of thirty-two, and each one has been counted as one more run that got confused in the forest. It is not that. It is one run that met a documented fault in Pokémon Blue, and none of the six configurations tried on it so far makes any difference, because none of them is about the cartridge. A 96-out-of-100 with this seed inside it is really a 96 out of 99 plus one cartridge bug, and the honest way to report a sweep is to say which of its failures are the agent's.

It also raises the price of a blackout. The healing chamber added last week treats a faint as a cost in decisions — you lose the walk back. It is not only that. Faint on the wrong tile and the map keeps a fight for you, and it will be waiting at the door.


Every byte on this page was read out of a saved state of seed 4200126 replayed from a cold boot, through the grading oracle in src/agentgb/battle.py; symbol names come from AtlasGB's pokemon-rb atlas, which carries each one as rom,live. Run records are AgentGB's own, config 25-link-2026-09-07-item-escape, policy models/pixel-student.npz sha256 b2bb7908…, ROM sha1 d7037c83…, sampled at T=1.0, seed base 42. The clip is a straight cut from pixel-chain-gridAcontrol6.mp4, cropped to the first tile. The oracle is a grading path and never touches the student's own run path. Wider context on the AgentGB project page and in Cartridge finds.

← Back to devlog