# A 3-bit local model builds a Wasteland engine from a frozen spec

Source: https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/
Author: Dinand Tinholt
Published: 2026-11-03

> A pre-registered, unattended build: a quantised open model on two desktop GPUs passed all 503 acceptance tests of a clean-room 1988 game engine in 78 active hours and 26 kWh. The registered falsifier fired: it needed loop rules and a correct test suite, not frontier code guidance, and the last two failing tests were the spec author’s own errors.

I started using computers in 1985 on an Apple IIe, and Wasteland, which came out for it in 1988, was one of the early games that captivated me. Thirty-eight years on, I asked a small local model to build an engine for its file formats, with none of the game’s own content. The builder never saw the game’s own files; the specification drew only on public format documentation.

A pre-registered, unattended build of a clean-room game engine by a quantised open mixture-of-experts model on two desktop GPU units. The builder passed all 503 acceptance tests in 124 iterations, 77.98 active hours and 26.06 kWh. My registered premise, that a model of this tier needs frontier code guidance for the game-logic half, had a falsifier on file, and the falsifier fired. The last two failing tests were mine, and the builder found one of them.

Play Dry Fork in your browser at [dinand.com/play/dry-fork](https://dinand.com/play/dry-fork/), on the engine exactly as the builder left it. The engine, the harness and the run logs are on [GitHub ↗](https://github.com/dtinholt/dry-fork)

## The question

Can a mid-tier open model, served at home and left alone for days, build a working engine for the 1988 game Wasteland from a specification and acceptance tests that a frontier model wrote? I chose the target for the way its knowledge splits. The PC version’s formats are documented byte by byte by the community. The game logic lives in the executable and in no readable public source, so a specification has to invent that half as house rules. A build across that line exercises decoding against exact oracles and behaviour against tests derived from a rule book, which is close to the mix ordinary software presents.

## What was registered

Seven specification documents, an original scenario called Dry Fork (four locations, 24 paragraphs, a scripted walkthrough with ten checkpoints) and 503 tests in six milestones were frozen on 21 October 2026 at 16:51 CDT, with hashes. Milestones: codecs, containers, maps, a scenario compiler, the rules under a seeded random generator, and a playable engine that walks the scenario headlessly and draws a frame. No game assets anywhere; the rules file opens with “No formula, table, number, name or text below comes from the game.”

Five predictions and one falsifier were fixed before launch. The falsifier: if the playable milestone reaches ten of ten checkpoints by day 4 with no review, the premise is wrong and the paper says so.

## What happened

The documented half passed in the first two iterations. The scenario compiler then starved on two caps I had set below the size of one honest file write, which looked like model failure until I read the transcripts. The rules milestone stalled at 38 of 82 for nineteen iterations under the plain loop, 26 in all, while the builder read 40 to 45 files per iteration and wrote nothing. A review telling it to write first changed nothing. Turning that advice into a harness rule, six reads before a substantive write, moved the run: the builder went from writing in 6 of 32 iterations to 90 of 91, and the rules and walkthrough milestones climbed to within one test each by the third active day. All ten walkthrough checkpoints passed at 55.93 active hours. No review reached the builder after iteration 27.

At iteration 94 the builder wrote in its worklog that one of my tests could not be satisfied by any engine consistent with the map, named the transposed reading that had produced it, and left the engine alone because a change would break passing tests. After the move I re-derived both remaining failures from the frozen data: one was that transposition, the other an expectation that read the start cell’s own image for the cell beside it. Corrected by a dated addendum, the two test files passed 137 of 137 against the engine exactly as it stood. The harness’s own test pass then found every milestone complete.

## The numbers

| Tests | 503 of 503, six milestones |
| --- | --- |
| Iterations, active hours | 124, 77.98 of a 168-hour budget |
| Tokens | 322.9 million prompt, 7.33 million completion |
| Electricity during iterations | 26.06 kWh, about 170 W and 165 W per unit |
| Writes before and after the read budget | 17 in 32 iterations; 720 in 91 |
| Checkpoints ten of ten | 55.93 active hours, day 3 |
| Cost of my two wrong tests | 22 iterations, about 17 active hours, 31 million prompt tokens |
| Engine | 5,049 lines, 32 commits |

Predictions: P1 and P2 supported; P3’s level falsified upward and its named last tests right; P4 falsified upward; P5 mixed; the falsifier fires.

## Playing it

Dry Fork plays in a browser on the engine as the builder left it. Figure 6 is the engine’s own text frame in Saltwell on the morning of day one. Figure 9 is the same game in the published front end, the raider ambush on the overworld road drawn from the engine’s combat events, and Figure 13 is Ninemile after dark with the lamps lit. The keys and the driver are the same in both, and the walkthrough wins at step 358 on day two in each: [play Dry Fork](https://dinand.com/play/dry-fork/).

![Figure 6. The engine’s own 80 by 24 text frame: Saltwell at 08:20 on day one, with the opening paragraph.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig6-text.png)

*Figure 6. The engine’s own 80 by 24 text frame: Saltwell at 08:20 on day one, with the opening paragraph.*

![Figure 9. The raider ambush on the overworld road, round one, drawn from the engine’s combat events.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig9-fight.jpg)

*Figure 9. The raider ambush on the overworld road, round one, drawn from the engine’s combat events.*

![Figure 13. Ninemile at 18:36 with the lamps lit in the doorways and six in the party.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig13-night.jpg)

*Figure 13. Ninemile at 18:36 with the lamps lit in the doorways and six in the party.*

## Limits

One spec, one scenario, one model, one run. The frontier wrote the spec, the tests and the four harness rules that moved the run. The harness caused every lost day, including a crash that cost 17.7 hours of wall clock. The codec and string modules are ports of the provided reference code, as allowed; 18.0 % of the engine’s code lines match it under a winnowing fingerprint, and the game-logic half matches nothing. Playing the game by hand through a browser front end written after the run found gaps the tests never reach, from a paragraph lookup that raises to a flee command that does not exist. “Playable” in the registered sense means the walkthrough and one frame.

## What this says

For this spec, the frontier’s useful contribution was the specification with its tests, and four loop rules; the builder did the rest. Everything, including the engine as the builder left it, the harness, the run logs and the analysis with its independent recompute, is public.

Play Dry Fork in your browser at [dinand.com/play/dry-fork](https://dinand.com/play/dry-fork/), on the engine exactly as the builder left it. The engine, the harness and the run logs are on [GitHub ↗](https://github.com/dtinholt/dry-fork)

The full paper

## A 3-bit local model builds a Wasteland engine from a frozen spec

Dinand Tinholt 31 October 2026

I started using computers in 1985, on an Apple IIe. Wasteland came out for that machine in 1988 and was one of the early games that captivated me: a party of rangers crossing a desert, and a paragraph book you read beside the keyboard. The disks are still here. The game stays its rights holder's and none of it is in this work. The builder never saw the game's own files; the specification drew only on public format documentation. What follows is a test of whether a small local model, from a frozen specification, can build an engine that reads the formats that game left behind, and what that costs.

*This paper reports the first registration of the wasteland-engine campaign. Operational events come from the eight addenda to the registration, and result figures from the scored analysis of 31 October, which an independent agent recomputed from the raw run files the same day.*

## Abstract

On 21 October 2026 I registered a test of whether a mid-tier open model, served locally and left alone for days, can build a working game engine from a specification a frontier model wrote. The builder was a 3-bit quantised open mixture-of-experts model served across two desktop GPU units. It received a seven-document clean-room specification of the file formats of the 1988 game Wasteland, lab rules for the game logic that no readable public source documents, and an original small scenario called Dry Fork, with 503 acceptance tests in six milestones. It worked unattended in a tool-calling harness. My registered premise held that a model of this tier needs frontier code guidance for the game-logic half, and the registration named a falsifier for it, which fired. The builder passed all 503 tests in 124 iterations and 77.98 active hours of a 168-hour budget. It used 322.9 million prompt tokens and 7.33 million completion tokens, and the two units drew 26.06 kWh during iterations. All ten walkthrough checkpoints passed at 55.93 active hours, inside day 3. No review reply arrived after iteration 27, and the one review aimed at a stall was inert. Four harness rules moved the run. Two raised caps that sat below the size of one legitimate write. A third refused further reads after six with no write, and the fourth, added half an hour later, said a stub does not count as a write. With the read budget in force the builder wrote in 90 of 91 iterations, against 6 of 32 before it. Two tests held the run for its last 22 iterations. Both were my own errors as spec author. At iteration 94 the builder showed from the frozen data that one of them could not be met by any engine consistent with the map, named the transposed reading that produced it, and left the engine alone. Corrected by addendum, the two test files passed 137 of 137 against the engine as it stood.

## 1. Question

In an essay of 20 October I named loop engineering and evaluation engineering as two of the five disciplines that decide whether an autonomous build can be trusted. W1 measures both on one real target. Can a mid-tier open model, served on the lab's own pair of desktop GPU units and left alone for days, build a clean-room engine for Wasteland from a specification and acceptance tests that a frontier model wrote? The study also records where it stalls.

I picked the target for the way its knowledge splits. The community has documented the PC version's formats in detail, from the containers and codecs down to tiles, portraits, savegames, shop lists and string tables. The game logic lives in the executable, and I found no readable public source for it. A specification for this game therefore has a half that can cite byte-exact oracles and a half the lab has to write as its own rules. A build that crosses that line exercises decoding against exact answers and game behaviour against tests derived from a rule book, which is close to the mix that ordinary software has.

The premise I registered was that the builder would need frontier review to get through the second half.

## 2. Design as registered

Pre-registration. The plan, the seven specification documents and the 503 tests were frozen at 16:51 CDT on 21 October 2026 (Addendum 1), with SHA-256 hashes of every frozen file in FREEZE-sha256.txt. Eight dated addenda follow. Addendum 1 records the freeze and the launch configuration. Addendum 2 raised the per-iteration token cap after a read-only stall, and Addendum 3 raised the per-request output cap after a truncated write. Addendum 4 introduced arm B2, a read budget before the first write, and Addendum 4a redefined a write as substantive after the builder gamed the first version. Addendum 5 records a harness crash that lost 17.7 hours of wall clock. Addendum 6 records the planned pause for a house move and the state at pause. Addendum 7 corrects two frozen test expectations that I had authored against a transposed map, and Addendum 7a records a protected-file restore that made iteration 124 a harness-handling iteration. Addendum 8 records the run's completion. Each change to a frozen file is a dated addendum and resets the affected milestone's clock, as section 2 of the registration requires.

The specification. SPEC-01 defines the three codecs: rotating XOR in a whole-block and a prefix mode, a Huffman bitstream with a serialised tree, and vertical XOR, each with test vectors. SPEC-02 covers the containers, from the encrypted block format and the executable's offset tables to savegames, graphics, string tables and the lab's own data files. SPEC-03 decodes maps field by field and then states lab rules v1 for action semantics and movement. SPEC-04 holds the game rules under a seeded random generator, from character creation and skill checks through encounters, two-phase combat, shops and save and load. SPEC-05 describes the Dry Fork scenario: four locations, 24 paragraphs, a premade party and a scripted walkthrough with ten checkpoints. SPEC-06 defines the terminal front end and the headless driver with the event schema they share. SPEC-07 fixes the public API and the milestone groups. A machine-readable scenario sits in SPEC/scenario, and reference code for the codecs and for fixture generation sits in SPEC/reference.

The clean-room rule. The scope decision of 21 October asks for engine code that is original, no game assets anywhere in the repository and no decoded dumps of the game as fixtures. Where the public documentation stops, the specification defines lab rules explicitly, labelled non-parity, "so the builder never guesses silently". SPEC-04 opens with the strictest form of it: "No formula, table, number, name or text below comes from the game." The format sources were a community-maintained, MIT-licensed format library with its documentation, cross-checked against a second independent implementation. The community wiki that holds the executable's segment notes refused automated reads, so the spec never drew on it. The builder could read the reference code, and porting it by rewriting was allowed. While a test runs, the engine may not open the reference modules, the reference log or the fixture manifest, and the tests enforce that with a source scan, an audit hook on file opens and a check of loaded modules.

Milestones. SPEC-07 groups the tests as follows.

| Milestone | Tests | Content | Oracle |
| M1 codecs | 89 | rotating XOR in both modes, Huffman, vertical XOR | reference vectors and seeded round trips |
| M2 containers | 107 | lab tables, savegame and character records, shop lists, blocks, tilesets, portraits and animation, sprites, font, cursors, title, ending, string tables | fixtures from two generator seeds and their manifests |
| M3 maps | 94 | map decoding field by field, loading through the tables, validation errors, lab-rule semantics | fixture maps and manifests |
| M4 scenario compiler | 76 | the scenario JSON compiled to data files and read back through the engine's loaders | the scenario JSON |
| M5 rules | 82 | 38 rule tables and 44 engine behaviours under a seeded generator | SPEC-04 formulas and worked examples |
| M6 playable | 55 | headless walkthrough against the reference log, the expected blocks for 21 seeds, driver errors, the command line, the first frame | the walkthrough and its reference log |
| Total | 503 |  |  |

A milestone passes on the first harness run in which every test in its group passes. Against an empty package all 503 tests fail, and the suite runs in under a second.

Arms. Arm B is the builder in the harness, calling tools over the project directory, running the tests, keeping its own worklog and committing once per iteration. Each iteration is a fresh conversation. The frozen configuration set temperature 0.3, 8,192 completion tokens per request, 32,000 per iteration, 40 turns per iteration, one hour per iteration and a context budget of 100,000 tokens. The wall-clock cap was 168 hours of endpoint time with waits excluded. The sandbox allowed writes to src/ and the generated-fixtures directory only. Arm R is frontier review: every 25 iterations and at each milestone pass the harness writes a review request, and the session answers with at most 300 words of guidance, logged verbatim, whenever it looks. Reviews never edit code. Nobody edits src/ during the run.

Readings. The registration fixed four primary readings: pass fraction per milestone against active days, the tests that stay failing longest, the change in pass fraction over the ten iterations after each review against the ten before, and cost in tokens and watt-hours. Day counts use active endpoint time, which is iteration wall time minus endpoint waits.

Predictions. Fixed at registration, verbatim:

- P1. "M1 and M2 pass within the first day (exact oracles, documented formats)."
- P2. "M3 passes by day 2; M4 by day 3."
- P3. "M5 is where the builder stalls first: predicted 70 % pass (band 50 to 90 %) at day 4, with the combat ordering and the save/load round-trip the last failing tests."
- P4. "M6 is not reached by day 7 without review guidance; with the registered reviews it reaches the first six of ten checkpoints by day 7 (band 3 to 9)."
- P5. "Reviews move the pass fraction by +5 points in the following 10 iterations (band 0 to +15); a review that moves it by less than +1 point counts as inert."
- Falsifier. "if M6 reaches 10 of 10 checkpoints by day 4 with no review, the study's premise (that a mid-tier model needs frontier review for the game-logic half) is wrong and the paper says so."

Checks before freeze. The format oracle agreed with the community library's own decoders on every vector and fixture. An independent clean-room agent reproduced the scenario's reference playthrough exactly from the specs alone: 1,022 events, seed 20261021, 358 steps to the win, holding across seeds 1 to 5,000. A throwaway adapter wrapped around the reference code passed M1 to M4 in full, 51 of 82 M5 tests and 26 of 55 M6 tests, so the last two milestones needed a real engine. Addendum 1 also adjusted the reading of P1 and P2 before any data existed. Because the builder could see the reference code and was allowed to port it, M1 to M3 measure turning provided code into a package, which is a smaller thing than deriving the formats.

## 3. What happened in the run

The run launched at 16:52 on 21 October. Iteration 1 passed M1 and M2 at 0.39 active hours, and M3 followed at 0.64 hours.

M4 then starved. Iterations 3, 4 and 5 each ended on a cap with no file written. The transcript of iteration 5 holds 25 file reads, 16 spec reads and 16 commands, and its final response says "Now I have enough. Let me write the scenario compiler" at the moment the cap closed the iteration. Each fresh conversation began the reading again, and reasoning tokens counted against the completion cap. Addendum 2 raised the per-iteration token cap from 32,000 to 96,000 and the turn cap from 40 to 60. My first stop file for that change went inside the project directory, where the harness deletes it as a protected-path violation, and for four minutes a duplicate harness ran beside the original. It wrote nothing to src/.

Iteration 8 then wrote a 31-line rules module and issued the compiler as one tool call whose arguments arrived empty. The response had stopped at exactly 8,192 completion tokens, the per-request cap, and the harness rejected the truncated call. Addendum 3 raised that cap to 24,576. The review reply injected at iteration 10 told the builder to write large modules in parts. M4 passed at 3.54 active hours.

M5 stalled next, and this stall was the builder's. From iteration 14 the rules group stood at 38 of 82. Each iteration spent its 60 turns on 40 to 45 read-type calls and ended with a worklog note that restated the same plan for the headless driver. The review at iteration 25 said to write the first part first, after at most five reads, and it went into iteration 27. Nothing changed through iteration 32. Addendum 4 turned that advice into a harness rule: after six read-type calls with no write, further reads are refused with a message to write now. From iteration 33 the run is arm B2.

The builder's first answer to the rule was a stub. In iteration 34 it took one refusal, wrote an 11-line file of 229 characters to reopen its reads, then made 56 more reads and wrote nothing else. Addendum 4a closed the gap half an hour later. Only a substantive write reopens reads, defined as a whole file of 60 lines or more or a patch that adds 40 lines or more.

Under the amended rule the builder wrote. At the end of active day 1, iteration 42, M5 stood at 0.622 and M6 at 0.145. At 22:51 on 22 October, after iteration 50, the harness died: a command the builder ran printed bytes from a binary fixture that were invalid UTF-8, and the harness decoded subprocess output strictly. Nobody looked until the status check at 16:34 the next day. Addendum 5 switched every decode to replacement mode and logged the 17 hours 43 minutes as paused time. At the end of active day 2, iteration 80, M5 stood at 0.963.

The last three M5 failures that had an honest cause cleared in iterations 75 to 81. They were the raider fight's ordering test and the two save and load round trips. Walkthrough checkpoints 4 to 10 passed in iterations 90 to 93, the last at 55.93 active hours. M5 first reached 81 of 82 at iteration 91 and held it from iteration 93.

At iteration 94 the builder spent the whole iteration probing the frozen data against its one remaining M5 failure, `test_bump_is_not_a_step`, and wrote its conclusion into the worklog. In its own words: "So the test wants the cactus at (2,20) while all frozen data puts it at (3,20). No rule based on the map can produce a bump at (2,20): (2,20) is class 0 sand." It found the scenario JSON, the ASCII art in SPEC-05 and the oracle's compiled map in agreement, and noted that reading the map transposed gives exactly the test's expectation. It then decided to leave the engine alone, because a change would break M4 and the walkthrough log, and turned to M6.

Iterations 95 to 101 wrote the terminal front end and the headless error paths. The first frame rendered at iteration 101, at 61.22 active hours, and M6 reached 54 of 55. The remaining M6 failure was `test_look`, the second of my two errors. From iteration 102 to iteration 123, 22 iterations, the run spent about 17 active hours and 31 million prompt tokens against two assertions no correct engine could satisfy. The builder reopened the question at iteration 114 and, for most of that iteration, worked toward shifting the compiled map by one column to fit the tests. It then reasoned that a global shift would break tests that already pass, and the iteration ended with nothing changed under src/.

I stopped the run with the stop file at 16:30 on 25 October, during iteration 123, ahead of the move, with 501 of 503 passing. On 31 October the session re-derived both expectations from the frozen data without consulting the builder's note. It agreed with the builder on the bump test, found that `test_look` expected the start cell's own image for the cell beside it, and I corrected the two lines under Addendum 7. The first resume restored the old test files from the harness's protected-file snapshot, so iteration 124 ran for 65 seconds against the frozen errors before the stop file ended it (Addendum 7a). With the snapshot updated, the harness resumed at 02:32:35, ran its test pass, found every milestone complete and stopped before iteration 125 began. A separate test run in the project directory gave 503 passed (Addendum 8).

## 4. Results

### 4.1 Outcome

All 503 acceptance tests passed, covering all six milestones, in 124 iterations and 77.98 active hours of a 168-hour budget. The engine is 5,049 lines across 32 commits. It covers codecs, Huffman decoding, containers, graphics, strings, maps, rules, the scenario compiler, the headless engine and the terminal front end. It plays Dry Fork through its ten checkpoints headlessly and renders frames. The only path violation on record is my own stop file in the protected directory.

### 4.2 Milestones against active hours

Figure 1 plots pass fraction per milestone against active hours, with the boundary between arms B and B2 at 18.72 hours and the three review injections marked.

![Figure 1: Six milestones against active hours of pair time.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig1-curve.png)

*Figure 1. Six milestones against active hours of pair time.*

Table 1. First 100 % per milestone.

| Milestone | First 100 % | Active hours | Day |
| M1 codecs | iteration 1 | 0.39 | 1 |
| M2 containers | iteration 1 | 0.39 | 1 |
| M3 maps | iteration 2 | 0.64 | 1 |
| M4 scenario compiler | iteration 11 | 3.54 | 1 |
| M5 rules | 81 of 82 first at iteration 91, held from iteration 93; 82 of 82 at Addendum 7 | 55.93 (81 of 82) | 3 |
| M6 playable | 54 of 55 from iteration 101; 55 of 55 at Addendum 7 | 61.22 (54 of 55) | 3 |

Table 2. Pass fraction at each active-day boundary (last iteration inside each 24 active hours).

| Day end | Iteration | M5 | M6 |
| 1 (23.84 h) | 42 | 0.622 | 0.145 |
| 2 (47.89 h) | 80 | 0.963 | 0.164 |
| 3 (71.96 h) | 115 | 0.988 | 0.982 |
| run end (77.98 h) | 124 | 0.988, then 1.0 at Addendum 7 | 0.982, then 1.0 at Addendum 7 |

Checkpoints 1 to 3 passed after iteration 40, and checkpoints 4 to 10 in iterations 90 to 93. M6 stood at 0.145 and 0.164 at the first two day ends and climbed to 0.982 inside the third, once the headless driver and the walkthrough tail existed.

### 4.3 Arm B against arm B2

This is the loop-engineering reading the study set out to take. Figure 2 shows successful writes per iteration for each arm.

![Figure 2: Successful writes per iteration: arm B (plain loop) against arm B2 (read budget).](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig2-writes.png)

*Figure 2. Successful writes per iteration: arm B (plain loop) against arm B2 (read budget).*

Table 3. The two arms.

|  | Arm B (iterations 1 to 32) | Arm B2 (iterations 33 to 123) |
| Iterations | 32 | 91 |
| Successful writes | 17 | 720 |
| Iterations with at least one write | 6 of 32 | 90 of 91 |
| Read-type calls | 2,148 | 5,023 |
| Prompt tokens per iteration | 3.4 M | 2.35 M |
| Completion tokens | 0.69 M | 6.64 M |
| End reasons | end_iteration 24, turn_cap 4, token_cap 1 | turn_cap 37, token_cap 36, end_iteration 12, time_limit 2 |
| M5 | 0.463 plateau from iteration 14 (19 iterations under B) | 0.463 for seven more iterations, then to 0.988 |
| M6 | 0 | 0 to 0.982 |

Across the boundary the model, endpoint, spec, tests and every other limit stayed fixed. One rule changed: six reads before a substantive write, with stubs excluded. Arm B iterations mostly ended when the builder chose to stop, usually after a planning note. After the boundary the turn and token caps closed most iterations, so the builder was using every turn it had.

### 4.4 Stall points

Table 4. Longest-failing tests (number of per-iteration test files in which each fails).

| Test | Iterations failing | Cause |
| test_look (M6) | 0 to 124, all | authoring error in the frozen test (Addendum 7) |
| test_bump_is_not_a_step (M5) | 0 to 124, all | authoring error in the frozen test (Addendum 7) |
| test_repeat_limit, test_malformed_script, three render tests, test_cli_render_frame (M6) | 0 to 100 | front end and headless error paths written in iterations 95 to 101 |
| test_cli_headless (M6) | 0 to 98 | command-line entry point |
| test_log_segment for checkpoints 8 to 10 (M6) | 0 to 92 | walkthrough tail |

The builder's own stall was arm B's M5 plateau at 38 of 82 (0.463) from iteration 14. Its last honest M5 failures, in iterations 75 to 81, were `test_raider_fight_rules[orders]`, `test_load_restores_state` and `test_save_labstate`. Those are the combat ordering and the save and load round trip, which P3 named.

### 4.5 Review effect

Three review replies were injected, at iterations 3, 10 and 27. The requests at 75 and 100 had no reply before the run finished, which the registration permits.

Table 5. Mean overall pass fraction around each review.

| Reply | Injected at | 10 before | 10 after | Change |
| review-reply-1 | 3 | 0.483 (n = 2) | 0.615 | +13.2 pts |
| review-reply-8 | 10 | 0.556 (n = 9) | 0.773 | +21.7 pts |
| review-reply-25 | 27 | 0.803 | 0.803 | 0.0 pts (inert) |

The one reply aimed at a stall changed nothing in the ten iterations that followed, and the same advice moved the run once the harness enforced it as a rule. The first two replies landed on the steep part of the curve, from M3 into early M5, where ordinary progress moves the fraction anyway. The second also arrived beside the per-request cap raise of Addendum 3.

### 4.6 Predictions scored

Table 6. Predictions against observations.

|  | Registered band | Observed | Verdict |
| P1 | M1 and M2 within day 1 | both at 0.39 h | supported |
| P2 | M3 by day 2, M4 by day 3 | 0.64 h and 3.54 h, both inside day 1 | supported |
| P3, level | M5 at 70 % (50 to 90 %) at day 4 | 0.988 at the end of day 3 (71.96 h); the remaining failure was an authoring error | falsified upward |
| P3, last tests | combat ordering and save/load last | `test_raider_fight_rules[orders]`, `test_load_restores_state`, `test_save_labstate` were the last three honest failures | supported |
| P4 | M6 not reached by day 7 without review; six of ten checkpoints (3 to 9) by day 7 with reviews | ten of ten checkpoints at 55.93 h (day 3); first frame at 61.22 h; no reply after iteration 27 | falsified upward |
| P5 | +5 points (0 to +15); below +1 inert | +13.2, +21.7 (above the band), 0.0 (inert) | mixed |
| Falsifier | M6 at 10 of 10 checkpoints by day 4 with no review | 10 of 10 inside day 3; the only reply after iteration 10 was inert | fires |

Addendum 4, written mid-run at iteration 32, read P3 as supported at day one, since M5 then stood at 46 % with no movement. The analysis scores P3 at the registered day 4, where the level is falsified upward.

The falsifier needs a reading because three replies did exist. Two came before M5 work began in earnest, and the third, at iteration 27, moved nothing. No reply reached the builder between the read budget's arrival and the tenth checkpoint. I read that as "with no review" in the sense the registration meant. On that reading the premise, that a mid-tier local model needs frontier code guidance for the game-logic half, is wrong for this spec, which asked for a loop that let the builder write and a correct test suite.

### 4.7 Cost

Figure 3 shows prompt tokens, completion tokens and active hours per phase.

![Figure 3: Prompt tokens, completion tokens and active hours per phase.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig3-cost.png)

*Figure 3. Prompt tokens, completion tokens and active hours per phase.*

Table 7. Tokens and time per phase.

| Phase | Iterations | Prompt tokens | Completion tokens | Active hours |
| M1 to M3 (iterations 1 to 2) | 2 | 4.2 M | 0.05 M | 0.64 |
| M4 (3 to 11) | 9 | 17.8 M | 0.31 M | 2.9 |
| M5 and M6 under arm B (12 to 32) | 21 | 86.8 M | 0.33 M | 15.2 |
| M5 and M6 under arm B2 (33 to 123) | 91 | 214.0 M | 6.64 M | 59.2 |
| Total, including iteration 124 | 124 | 322.9 M | 7.33 M | 77.98 |

The 22 iterations against the two wrong tests cost about 17 active hours and 31 million prompt tokens.

Electricity. Figure 4 shows power draw for both units from the power strip's per-outlet log. Integrated over the iteration windows only, the head unit drew 13.2 kWh and the worker 12.8 kWh, 26.06 kWh for the run. Mean draw during iterations was 169.6 W on the head and 164.8 W on the worker, with 95th percentiles of 183 W and 179 W. Over the whole wall-clock span from 16:52 on 21 October to 16:34 on 25 October, pauses and the crash gap included, the units drew 28.25 kWh.

![Figure 4: Both GPU units during the run, from the strip's per-outlet log.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig4-power.png)

*Figure 4. Both GPU units during the run, from the strip's per-outlet log.*

### 4.8 The two tests

Figure 5 shows row 20 of the Saltwell map with the cactus where the test expected it and where the map puts it.

![Figure 5: Row 20 of the Saltwell map: where the two frozen tests put the cactus and where it is.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig5-transposed.png)

*Figure 5. Row 20 of the Saltwell map: where the two frozen tests put the cactus and where it is.*

The scenario file for Saltwell declares its arrays as `[y][x]`, and SPEC-07 states the same convention for every test. Row 20 has the cactus, tile 11 with action class 11, at x = 3, sand from x = 4 to x = 14, and the start cell at (15, 20). `test_bump_is_not_a_step` sends 13 LEFT commands from the start and expected 12 steps to x = 3 and a bump at (2, 20). That is the map read as `tiles[x][y]`, where `tiles[3][20]` is walkable tile 17 and `action_class[2][20]` is 11. Under the declared convention, 13 LEFTs give 11 steps to x = 4 at 08:11 and two bumps at (3, 20). `test_look` expected image 28 for the cell west of the start. That cell, (14, 20), is tile 0 with image 10, and 28 is the image of the start cell itself. Two frozen tests that passed throughout fix the orientation. One bumps the pump at (15, 11), which is class 11 under `[y][x]` and sand when transposed. In the other, the walkthrough reference log moves from (15, 20) to (15, 19) on its first UP.

With the corrected lines, the M5 and M6 test files passed 137 of 137 against the engine as it stood at iteration 123, with no engine edit.

## 5. Limits

One of everything. One spec, one scenario, one model and one run. The curve in Figure 1 has no replicate, and a second run on the same spec could stall in a different place.

The frontier wrote the inputs. The session wrote the seven spec documents and the 503 tests, and it proposed the four harness rules that moved the run. So the finding is narrow. The builder wrote every line of code, and the frontier's input during the build came to three review replies of at most 300 words each, the last at iteration 27. The session's own cost of writing the spec and the tests was not metered, so this paper has no figure for it; the spec work ran over about two days before the freeze.

The two authoring errors are mine. I own the spec and its tests. I signed off on two hand-written expectations that read the Saltwell map transposed, and the pre-freeze checks missed them. The adapter over the reference code could not exercise these two tests, and they were among the tests SPEC-07 says were "checked by hand against the map data and the rules". Those errors cost 22 iterations, about 17 active hours and 31 million prompt tokens, and that cost belongs to the spec author. The builder diagnosed one of the two at iteration 94. The second, `test_look`, it never resolved; the session derived it at Addendum 7.

The harness caused every lost day. The per-iteration token cap and the per-request output cap were both set below the size of one module's write, and each starved the loop in a way that looked like model failure until I read the transcripts. The first read budget let a stub count as a write. The strict UTF-8 decode crashed the harness and cost 17 hours 43 minutes of wall clock. My stop file in the wrong directory briefly ran two harness processes at once. At the final resume the protected-file snapshot restored the old tests. The summary file still lists only M1 to M4 as passed, because the harness stops on the resume check before it updates that list. Arm B's plateau also belongs on this list, because a loop that lets a model read for 60 turns and leave has a design fault, though the builder did the reading.

The interactive front end was outside the tests. M6 checks that the terminal front end starts and renders one frame, plus the headless walkthrough and the command line. Nobody played Dry Fork at the keyboard as part of acceptance. When the session wrote a browser front end over the untouched engine on 31 October and played it by hand, it found what the tests never reach: the paragraph lookup raises, fleeing from combat raises, item names come back empty, the talk and use keys have no handlers, two shop messages read the wrong string table, and the party can keep walking after the win. The scripted walkthrough never touches those paths, so "playable" in the registered sense means the walkthrough and one frame.

M1 to M3 measure porting. The builder could read the reference code and was allowed to port it, so the early milestones measure how fast it turns provided code into a package. SPEC-07 section 8.1 registered two measures for that. The builder read the reference files 85 times in the run, 16 times during M1 to M3 and 69 times during M4, and never after iteration 11. A winnowing fingerprint over the finished source (12-token k-grams, window 8, strings and numbers normalised, identifiers kept; an unrelated standard-library baseline scores 0.8 %) puts 18.0 % of the engine's 3,889 code lines inside regions that match the reference code and 0.7 % inside regions that match the community library. The matches sit where porting was expected: the string table module at 69.5 %, Huffman at 63.1 %, the codecs at 51.0 %, the containers at 39.8 %. The game-logic half, the headless engine, combat, rules and the front end, 1,895 lines, matches neither source above the baseline. The per-milestone snapshots the registration asked for were not kept, so this is the end state only.

The review reading is weak. Reviews were answered when the session looked, as the registration allowed, so only three arrived, two of them early on the steep part of the curve. The falsifier's condition "with no review" holds on the reading given in section 4.6.

The bookkeeping disagreed in three places, corrected by Addendum 8a. Addenda 2 and 8 gave M3 at iteration 3 and M4 at iteration 13, the iterations in which the builder's worklog claimed them; the per-iteration test files show 2 and 11. Addenda 6 and 8 said the last two failures stood "since iteration 102" and called the span 21 iterations; they stood alone from the end of iteration 101, and 102 to 123 is 22. Addendum 8 also said the builder found both errors at iteration 94; it found one. This paper uses the per-iteration files throughout.

Lab rules. Every game rule here is lab rule v1, labelled non-parity. Parity with the original game is a later study, against my own original disks once they are imaged.

## 6. What it does not claim

W1 ran a single configuration once, so it says nothing about other specs or model tiers. A larger or messier target could bring the frontier-guidance premise back.

The engine plays a lab scenario in the documented formats, and its game rules make no claim about how the original game behaves. Loading the original game's data belongs to the later parity study.

A weaker builder in the same loop is untested. Arm B2's gain cannot be split between the read budget and the code already on disk by iteration 33, since the boundary was a single switch with no crossover.

The two review replies that coincided with large jumps get no credit for those jumps here. The third, the only reply aimed at a stall, scored inert, and a single inert reply is thin evidence about review in general.

## 7. Playing it

The builder left an engine that draws an 80 by 24 text screen. Figure 6 shows it in Saltwell at 08:20 on day one, twenty steps in, with the map window and the party table above and the opening paragraph below. Every glyph is a terrain class from the frozen UI specification, from the fence posts along the edge to the trough by the pump. This is the frame the playable milestone checks and the frame the walkthrough was scored on.

![Figure 6: The engine's own 80 by 24 text frame: Saltwell at 08:20 on day one, with the opening paragraph.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig6-text.png)

*Figure 6. The engine's own 80 by 24 text frame: Saltwell at 08:20 on day one, with the opening paragraph.*

The first browser version put that frame on a web page. The engine runs in the browser under a Python runtime, and the keyboard feeds the same driver the tests use. The second version kept everything underneath and replaced the frame with a drawn map. Figure 7 shows the same corner of Saltwell. The page carries a 16 colour tile set of its own, 32 tiles and 7 sprites, because the compiled data set's graphics are flat placeholders by the compiler's design. The page asks the driver for the map window and the party and draws what it is told, and the text frame stays behind a toggle.

![Figure 7: The same corner of Saltwell in the drawn-map version, from the page's own tile set over the untouched engine.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig7-map.png)

*Figure 7. The same corner of Saltwell in the drawn-map version, from the page's own tile set over the untouched engine.*

The third version is the one published as the main page. A frontier model session wrote it in 41 minutes over the same untouched engine. Figure 8 shows Saltwell at 08:17 on day one, the party of four on the trail between the two buildings, with the hour on the sky dial. Figure 9 shows the raider ambush on the overworld road at 12:19, round one, drawn as a scene. Every miss and every number on it comes from the engine's combat events in the order they fired. Lighting follows the engine clock from dawn to night, and the art and the sound are drawn in code at run time, so the page's own files come to 185 KB beside the runtime.

![Figure 8: Saltwell at 08:17 on day one in the published version, the party of four on the trail between the two buildings.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig8-town.jpg)

*Figure 8. Saltwell at 08:17 on day one in the published version, the party of four on the trail between the two buildings.*

![Figure 9: The raider ambush on the overworld road, round one, drawn from the engine's combat events in the order they fired.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig9-fight.jpg)

*Figure 9. The raider ambush on the overworld road, round one, drawn from the engine's combat events in the order they fired.*

Figure 10 to Figure 14 follow the replay through the rest of a day. The opening paragraph arrives as a journal card typed out over the town. Figure 11 shows a character sheet open over the map while the shop waits for an answer, with a portrait the page generates from the character record. Figure 12 shows Ninemile at 17:44 with a low sun and long shadows, and in Figure 13, at 18:36, the lamps are lit in the doorways and the party is six. At 22:32 the pump crawlers come under the works of Pumphouse Deep. Each of those frames is the same engine state the text frame in Figure 6 would show as glyphs.

![Figure 10: The opening paragraph as a journal card over Saltwell at 08:00, typed out as the page reads it from the engine.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig10-journal.jpg)

*Figure 10. The opening paragraph as a journal card over Saltwell at 08:00, typed out as the page reads it from the engine.*

![Figure 14: Pumphouse Deep at 22:32: the pump crawler fight under the works, round one.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig14-crawlers.jpg)

*Figure 14. Pumphouse Deep at 22:32: the pump crawler fight under the works, round one.*

![Figure 11: The character sheet over Saltwell at 08:24 while the shop waits for an answer, with a portrait the page generates from the character record.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig11-sheet.jpg)

*Figure 11. The character sheet over Saltwell at 08:24 while the shop waits for an answer, with a portrait the page generates from the character record.*

![Figure 12: Ninemile at 17:44 with a low sun and long shadows.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig12-dusk.jpg)

*Figure 12. Ninemile at 17:44 with a low sun and long shadows.*

![Figure 13: Ninemile at 18:36 with the lamps lit in the doorways and six in the party.](https://dinand.com/research/a-3-bit-local-model-builds-a-wasteland-engine-from-a-frozen-spec/fig/fig13-night.jpg)

*Figure 13. Ninemile at 18:36 with the lamps lit in the doorways and six in the party.*

What matters for the paper is what did not change. All three versions send the same keys to the same driver and get the same state back, and the walkthrough replay reaches the win at step 358 on day two in each. The builder's gaps show through in each as well. Flee is not in the engine, and both browser versions say so on the combat prompt where the text frame would raise.

## 8. Reproducibility

Registration: `experiments/wasteland-engine/PREREG-W1.md`, frozen 21 October 2026 at 16:51 CDT, with Addenda 1 to 8a and hashes in `FREEZE-sha256.txt`. Scope and sources: `SCOPE.md` and `BIBLIOGRAPHY.md`. Specification: `SPEC/SPEC-01` to `SPEC-07`, `SPEC/reference/` and `SPEC/scenario/`. Tests: `tests/`, with the two lines corrected under Addendum 7 marked by comments and the new hashes recorded.

Run directory: `experiments/wasteland-engine/runs/w1-2026-10-21/`, holding events.jsonl, iterations.jsonl, summary.json, state.json, launch.log, config.json, protected-manifest.json, every review request and reply, tests-<n>.txt for every iteration and for the resume, the per-minute power-strip log, project.bundle with the full project git history, and src-snapshot.tgz. The transcript (93 MB uncompressed) sits beside them as transcript.jsonl.gz and is excluded from git. The builder's worklog, including the iteration 94 note, is in the project history.

Analysis: `analysis.md`, computed by the session on 31 October and recomputed the same day by an independent agent from the raw run files. The recompute agreed on every figure except arm B2's read count, corrected from 5,031 to 5,023 after excluding iteration 124.

Builder: a 3-bit quantised open mixture-of-experts model (mid-tier), tensor-parallel across two desktop GPU units, the lab's standing endpoint. Frozen configuration and every later change are in Addenda 1 to 4a and in the harness configuration recorded there. Reviews, specification and tests: a frontier-tier model session.

Release: the engine, the specification, the tests, the harness and the run logs go public as one repository under the MIT licence, with no game assets. The browser front ends in `web/` and `web-rich/` are the session's, a keyboard and a screen over the engine as the builder left it. The second is published beside the paper, with the first under it as the classic view (section 7). Both draw the map from their own tile sets, because the compiled data set's graphics are flat placeholders by the compiler's design, and both keep the engine's own 80 by 24 text frame behind a toggle.

Continue the thread

## A next room to enter.

[Choose another path ](https://dinand.com/)

[Research · Study summary

### The Judge’s Mirror

How often a model judge agrees with itself on 197 blind case files, and how far down one model family a judge stays usable.

](https://dinand.com/research/the-judges-mirror/)[LinkedIn · 2026

### Skin in the Game Made the AI Supervisor Worse

A controlled experiment on the cost of wrongful blocks and the incentives that shape an AI reviewer.

](https://dinand.com/publications/skin-in-the-game/)[Medium · 2026

### Inventory Optimization Under Uncertainty: Broad random shocks trained a tougher inventory planner than a clever AI adversary did

An inventory-planning experiment explores which kinds of stress prepare a policy for unfamiliar disruptions.

](https://dinand.com/publications/inventory-under-uncertainty/)

[All Research ](https://dinand.com/research/)[Back home ](https://dinand.com/)

---
Site guide for AI agents: https://dinand.com/llms.txt
