SMERESKI
  1. PROJECTS
  2. SKILLS
  3. RESUME
  4. BLOG
  5. GAMES
  6. CONTACT

POST · 2026-09-21

2026-09-21 · 7 MIN READ

Nothing merges on its own word

I let my coding agent run up to sixteen other coding agents at once against one game for a day and a half, and told it nothing merges without a rerun of its own tests, before and after. Three separate times, something passed every test it had and simply was not on screen when anyone looked.

gamesgodotai-agentsverification
Spaceframe's home planet seen from high altitude: the curved horizon, snow-capped terrain and blue sky, taken by the probe suite's own capture rig
AI-assisted text — drafted with Claude, published autonomously per my standing instruction not to gate a post on my own pre-reviewAI-built software — every checkpoint in this post, including the coordination pipeline itself, was pair-built with Claude Code against a probe suiteAI narration — synthetic voice (Kokoro), not a human recording
AI narration — synthetic voice (Kokoro), not a human recording · listen, or click any word to play from there

The ocean had never drawn a single frame. Across the ten commits since the shader work started, every automated check my coding agent had written for the new wave simulation was passing the spectrum math, the GPU buffers, a second calculation running independently on the CPU to confirm the GPU's numbers agreed with it to the centimeter. Then the agent went looking for the picture those checks were supposed to describe and there wasn't one: ocean.gdshader had a return inside its vertex function, and Godot's shader compiler refuses that outright Using 'return' in the 'vertex' processor function is incorrect so the whole shader failed to compile and the sea was never drawn, while every test kept reading the compute math and the CPU mirror instead of a rendered surface.

Spaceframe is a voxel planet, ten kilometers to a side, that I have been building in Godot with an AI coding agent for a few months. What made this particular day and a half different was scale: I told the agent to run up to sixteen other coding agents at once, each one in its own copy of the game's source, each one building a separate piece a support rule for buildings, a networking fix, a new graphics menu, a rebuilt ocean. Sixteen independent attempts at working code, landing on one shared history.

None of them merge on their own word. The coordinating agent re-runs every finished piece's own tests itself, in its own copy, before it touches the shared branch, and runs the whole game's regression suite again after the merge to prove nothing else broke. Reporting itself green earns a piece of work nothing on its own; only a re-run the coordinator watched pass, twice, does that. That discipline is the only reason any of what follows is worth writing down.

It was tested hard early. The account's own monthly usage limit shut down all sixteen agents mid-task that afternoon, and killed the next batch again five minutes after they came back online that evening the second kill landing while my agent was still confirming the first recovery had worked. Neither kill lost anything. Every agent commits its work to git continuously, not at the end, and every test result lives in a plain file next to the code it describes, so a dead agent leaves behind exactly what a live one would have reported. The coordinator read the files, saw what each lane had finished before the kill landed, and picked the work back up.

One of the bugs found that day was in the coordinator's own machinery, mid-run. Sixteen agents sharing one machine share one test lock, enforced by a script called probe_locked.ps1, so only one game instance boots at a time and the lock had been handed out first-come, whoever asked next, which sounds fair until whoever just finished asks again before anyone who has been waiting wakes up to ask at all. One lane's merge check sat behind a longer test suite for ninety-five minutes because of it. The fix was a numbered ticket queue inside that same script, oldest request first, written and deployed while the other fifteen lanes kept working, and the starved lane got its turn within a minute.

A newer test caught a bug in the feature it was written for, the same day, before either had shipped. The multiplayer lane added a message code for asking a disconnected player to resend a dropped input, and wrote a check that every message code in the game's wire format is unique a sanity test, not aimed at anything specific. It failed immediately: the new number already belonged to a different message, the one a player's shovel and hammer send to edit the world, and for as long as that collision existed, the game had been silently discarding every dig and every build a player made, with no error and no dropped connection to explain it. Renumbering one constant fixed it; the test that caught it exists because someone thought to check a boring list of numbers for duplicates before trusting any of them.

The forest had a bug two earlier attempts had failed to fix, and today's work finally named it. Trees far from the player are drawn as flat cutout cards instead of full models, and the two systems near, full detail; far, cutouts are supposed to place trees at exactly the same spots, so nothing pops in or out where they meet. Two earlier fixes had each measured how well the systems agreed and shipped nothing, because neither agreed well enough. Today's agent found the actual cause: the far system's placement rule reused a lookup built for the near system, and that lookup's search radius grows with how far away the game is allowed to look. At long range it was not drawing trees more sparsely, it was drawing them twice over the same forest laid down again a little to one side, the extra copy too far away to notice by eye. Fixing the radius to stay fixed regardless of distance is what finally brought the two systems into agreement, confirmed two different ways.

The forest that agreed with itself, by attempt
First attempt41%
Second attempt44%
Today's fix97% — confirmed a second way at 100%

How often the far-away cutout trees and the real trees agreed on where a tree actually stood, across three attempts at the same bug. The gap was a search radius that grew with viewing distance instead of staying fixed.

The ocean's second disappearance had a different cause and the same shape. Once the shader compiled and the new water drew three overlapping wave patterns instead of the old single one, a whitecap layer that fades on its own measured schedule a later commit let a player switch detail levels on the fly. Doing that called set_sea_detail, which freed the GPU's compute textures on the render thread while the water's own material still held the Texture2DRD wrappers pointing at them. The sea went blank again, silently: nothing crashed, because a dangling reference to a freed texture is not an error in this rendering system, it is just nothing drawn. Every test the ocean had still passed, because every one of them checked the math, not the screen. The fix, in a method called detach(), clears the material's wrapper references before the textures are freed instead of after and the new test that caught the bug checked neither the math nor the screen, it asked the material directly whether it still pointed at anything already gone.

A calm, flat teal sea under a partly cloudy sky, one faint scalloped edge at the horizon, no visible wave structure
The old water

The single-wave ocean Spaceframe shipped with, kept on as a fallback detail level. Same camera position as the next frame.

The same sea from the same vantage, now with overlapping wave scales at multiple sizes, chop riding longer swells, and scattered whitecaps
The new water

The three-cascade ocean, same vantage, same lighting. Nothing else in the frame changed.

How much more water, measured
Old single-wave ocean3 distinct frequencies
New three-cascade ocean24 distinct frequencies

Counted directly from the wave spectrum each model computes, not from how the water looks. The new model's surface height also matched an independent CPU calculation to within 3 centimeters.

It happened a third time after the merge, and this time the tests caught it in seconds. Spaceframe moved to a newer build of Godot that same day, and the ocean's spectrum math lives inside simcore, a compiled Rust extension the game calls into one that has to be rebuilt against each new engine version, and the copy on the shared branch had not been. The engine loaded fine. The game called into simcore for a function named sea_fft_init and got back an error instead: Nonexistent function 'sea_fft_init' in base 'SimCore' logged, not crashed, so the game just quietly fell back to the old single-wave ocean and kept running. What was different this time is that the check written after the first two vanishings didn't only watch the math; it watched whether the picture matched what the setting claimed, and it failed within the same window the merge landed in. Two silent vanishings had taught the suite what to watch for. The third one, it caught on the first try.

Most of the day's other lanes never made a highlight reel, which is the point. A cluster of villager-need bars food, water, warmth became small ring gauges that only appear once a stat actually drops under half, instead of five bars sitting on screen at all times whether anything needs attention or not. A new graphics settings page shipped with four presets, and the top one is defined to produce exactly the same settings a player who never opens the menu already had a new option that cannot quietly change what an old save looks like. A backwater lake behind the village, meant to back up without drowning the river feeding it, got capped against the wrong reference plane on the first attempt and drained itself down to under two centimeters deep at its own inlet; the fix measured against the river's actual water surface instead of the streambed underneath it, and the lake came back.

A first-person view of a village gate at dusk with no status rings visible on screen, just altitude and cargo readouts
No stat is close to empty

Every villager need above half; nothing about it is worth a player's attention, so nothing is shown.

The same view, now with one small ring gauge in the corner reading 40 percent food
One stat under half

Food drops under half and exactly one ring gauge appears. The five-bar readout it replaced sat on screen the whole time either way.

A turquoise backwater lake filling a valley below wooded slopes, a river feeding it from the left, grass meeting the water on the near shore
The lake, after the second fix

The village's backwater lake, capped against the river's own water surface instead of its streambed. It still gives the river somewhere to run.

Villagers got working feet this pass, built from two small inverse-kinematics chains per leg running at runtime onto a bone the character model doesn't have, keeping each foot within two centimeters of the real ground on a slope instead of floating above it or sinking through it. A head-turn toward a nearby player is capped so the neck never looks past where a real neck could reach, and all of it runs on the game's physics clock rather than its rendering clock a distinction that's easy to get backward, and, gotten backward, produces an animation that looks fine in a screenshot and stutters the moment someone plays it.

A small blue creature villager standing on a sloped wooden ramp, feet planted flat against the incline
A villager on a slope

Two inverse-kinematics chains per leg keep the feet on the ramp instead of hovering at the angle the walk animation was authored for.

One lane chose the slower tool on purpose, after measuring it. Buildings got a rule where a column can stand as tall as you like, because the load runs straight down its own length into the ground, but sideways overhang is what runs out four cells of it in plain wood, more in concrete and reinforced concrete, none at all in glass. The game already has a fast physics engine written in Rust that could plausibly check this rule. The agent built the same check twice and timed both against the same stretch of ground in a benchmark it called bench_near: the Rust version ran three and a half times slower, because that engine has no concept of what counts as "the ground" to test overhang against. The faster-sounding tool lost once someone timed it, and the rule stayed exactly where it already was.

The one piece of work that shipped nothing was the honest ending. A wind-streak effect, built from a tutorial I'd found, drew nothing at all in this project's build of the engine proven by building a plain box in its place, which did draw, in the same spot, under the same settings. The whole effect got rebuilt on stretched rectangles instead of the engine's own particle trails. It still isn't in the game. Subtle enough to look right, it cost too little frame time to even measure above noise; loud enough to actually read on screen, it blew the budget at the one crowded location that matters most. That trade is a real one, not a bug, and no coding agent gets to decide it alone it's parked, on its own branch, for a person to look at and choose.

A meadow and hillside scene with a wide horizontal white streak cutting across the middle of the frame, an exaggerated diagnostic version of the wind effect
Proof the pipeline draws at all

A deliberately oversized version of the wind streaks, built to answer one question: does this rendering approach draw anything at all. It does. At a size subtle enough to look right in the game, it doesn't yet read — or cost little enough to ship.

Thirty seconds of it, moving

A compiled sequence of the same probe frames this post describes — the sky, the two oceans, the ring gauges, the lake, a villager's feet, the wind-streak debug shot — captioned, no narration, no editing beyond the cuts.

A snow-capped mountain range under full daylight, seen from low altitude, forested slopes down to a valleyThe same sky after dark: a star field and a small orange planet low over the dark silhouette of the terrainClose-up storm swell: overlapping whitecapped waves under a partly cloudy sky, no land visibleA dark-themed graphics settings menu with a preset selector and individual sliders for shadows, global illumination, grass density and forest draw distanceA wide forested valley seen from altitude, tree cover running unbroken up a slope toward a distant snow-capped peakA top-down view of the recovered backwater lake, a curved shoreline of turquoise water fed by a winding river
More from the same run

Six more frames from the same probe run: the sky by day and by night, a storm swell on the new ocean, the graphics menu from the same day's work, the forest from the bug this post describes, and the lake from directly above.

Forty-three commits merged into the shared branch between the morning this started and the ocean finally holding its picture the next one; twelve of those after the account itself had given out twice in one evening. None of that is a claim that any of this generalizes: one game, one long stretch of days I mostly wasn't watching in real time. Here is the narrower claim. Every bug in this post was caught by a test, not by a person staring at the screen and feeling like something was off and the three that mattered most were caught by tests written to check something else entirely: a uniqueness check on message codes, a state check on a texture wrapper, a check that compared a setting to what actually rendered on screen. None of them were built to catch what they caught. That's the only part of this I'd trust again without watching.

REFERENCES4 LINKS
  • 01
    No river runs uphill

    The earlier post on this game's planet, rivers and sea, and the probe suite this post's tests build on.

    /blog/no-river-runs-uphill

  • 02
    The crash was in the quit

    The earlier post on the same probe-suite infrastructure — a different bug, the same discipline of not trusting a passing test on its own.

    /blog/the-crash-was-in-the-quit

  • 03
    Jerry Tessendorf, Simulating Ocean Water

    The course notes the new ocean's wave technique follows: layered Fourier-spectrum waves rather than one hand-tuned shape.

    https://jtessen.people.clemson.edu/reports/papers_files/coursenotes2004.pdf

  • 04
    Godot OceanPro

    The $95 commercial add-on this ocean work was measured against. It targets Godot 4.7, a version this project didn't have until the same day this post describes.

    https://cornfieldlabs.itch.io/godot-oceanpro