Days five and six stopped at 17:53 on 16 October, with 29 rows on the research map and 28 of them reviewed, and the combat run, the first run of the simulation, still to come. This post covers the rest of that evening and the five days after it, to 12:11 on 21 October. The map now has 36 rows and 35 are reviewed. The one that is not is again the newest: a row called chain, added on the 20th, for the core specs run as one chain from the game seed to the drops on the floor, with nothing read from the game in between.

The difference from the earlier posts is that I did not play. Seven sessions of day six were mine; in these five days none were. The record of what I did is short: on the evening of the 16th I approved six plans to run unattended, on the 20th five more and the order of what was left, on the 17th I ran one command as root, to show that the firewall already blocked the game’s port from outside, which was the condition on letting two clients into one game, I accepted the seven decisions put to me, I paused the lanes twice, and on the 20th I asked for the backlog to be archived because it was getting large. Everything else below was done by the lanes, each an agent with its own copy of the repository, on the harness, the game under a debugger with a logger attached, through nights in which the machine was shut down, suspended for nine hours, suspended for seven, and once out of memory.

The map of the work

The research map at each cut-off

  • not started
  • planned
  • findings
  • draft spec
  • reviewed spec

3 reviewed spec 1 findings 1 planned 23 not started of 28

Core

  • rng reviewed spec
  • items/tc findings
  • items/quality not started
  • items/affixes not started
  • items/uniques-sets not started
  • items/properties not started
  • monsters/pool not started
  • monsters/spawn not started
  • monsters/special not started
  • drlg/overview planned
  • drlg/preset not started
  • drlg/maze not started
  • drlg/outdoor not started
  • drlg/warps not started
  • objects not started

Enablers

  • data/excel reviewed spec
  • data/calc not started
  • data/strings not started
  • rng/seeds reviewed spec
  • drlg/collision not started
  • save/d2s not started

Creation paths

  • items/vendors not started
  • items/cube not started
  • items/sockets-runewords not started
  • items/quest-drops not started
  • monsters/stats not started
  • hirelings not started
  • player/creation not started

28 reviewed spec 1 planned of 29

Core

  • rng reviewed spec
  • items/tc reviewed spec ↑
  • items/quality reviewed spec ↑
  • items/affixes reviewed spec ↑
  • items/uniques-sets reviewed spec ↑
  • items/properties reviewed spec ↑
  • monsters/pool reviewed spec ↑
  • monsters/spawn reviewed spec ↑
  • monsters/special reviewed spec ↑
  • drlg/overview reviewed spec ↑
  • drlg/preset reviewed spec ↑
  • drlg/maze reviewed spec ↑
  • drlg/outdoor reviewed spec ↑
  • drlg/warps reviewed spec ↑
  • objects reviewed spec ↑

Enablers

  • data/excel reviewed spec
  • data/calc reviewed spec ↑
  • data/strings reviewed spec ↑
  • rng/seeds reviewed spec
  • drlg/collision reviewed spec ↑
  • save/d2s reviewed spec ↑

Creation paths

  • items/vendors reviewed spec ↑
  • items/cube reviewed spec ↑
  • items/sockets-runewords reviewed spec ↑
  • items/quest-drops reviewed spec ↑
  • monsters/stats reviewed spec ↑
  • hirelings reviewed spec ↑
  • player/creation reviewed spec ↑

Simulation

  • combat/formulas planned

32 reviewed spec 3 findings of 35

Core

  • rng reviewed spec
  • items/tc reviewed spec
  • items/quality reviewed spec
  • items/affixes reviewed spec
  • items/uniques-sets reviewed spec
  • items/properties reviewed spec
  • monsters/pool reviewed spec
  • monsters/spawn reviewed spec
  • monsters/special reviewed spec
  • drlg/overview reviewed spec
  • drlg/preset reviewed spec
  • drlg/maze reviewed spec
  • drlg/outdoor reviewed spec
  • drlg/warps reviewed spec
  • objects reviewed spec

Enablers

  • data/excel reviewed spec
  • data/calc reviewed spec
  • data/strings reviewed spec
  • rng/seeds reviewed spec
  • drlg/collision reviewed spec
  • save/d2s reviewed spec
  • drlg/lifecycle reviewed spec

Creation paths

  • items/vendors reviewed spec
  • items/cube reviewed spec
  • items/sockets-runewords reviewed spec
  • items/quest-drops reviewed spec
  • monsters/stats reviewed spec
  • hirelings reviewed spec
  • player/creation reviewed spec

Simulation

  • combat/formulas reviewed spec ↑
  • stats/aggregate reviewed spec
  • stats/states reviewed spec

Game rules

  • quests/progression findings
  • quests/travel findings
  • items/economy findings

35 reviewed spec 1 findings of 36

Core

  • rng reviewed spec
  • items/tc reviewed spec
  • items/quality reviewed spec
  • items/affixes reviewed spec
  • items/uniques-sets reviewed spec
  • items/properties reviewed spec
  • monsters/pool reviewed spec
  • monsters/spawn reviewed spec
  • monsters/special reviewed spec
  • drlg/overview reviewed spec
  • drlg/preset reviewed spec
  • drlg/maze reviewed spec
  • drlg/outdoor reviewed spec
  • drlg/warps reviewed spec
  • objects reviewed spec
  • chain findings

Enablers

  • data/excel reviewed spec
  • data/calc reviewed spec
  • data/strings reviewed spec
  • rng/seeds reviewed spec
  • drlg/collision reviewed spec
  • save/d2s reviewed spec
  • drlg/lifecycle reviewed spec

Creation paths

  • items/vendors reviewed spec
  • items/cube reviewed spec
  • items/sockets-runewords reviewed spec
  • items/quest-drops reviewed spec
  • monsters/stats reviewed spec
  • hirelings reviewed spec
  • player/creation reviewed spec

Simulation

  • combat/formulas reviewed spec
  • stats/aggregate reviewed spec
  • stats/states reviewed spec

Game rules

  • quests/progression reviewed spec ↑
  • quests/travel reviewed spec ↑
  • items/economy reviewed spec ↑

The arrow marks a row that moved since the previous snapshot. Source: docs/specs/README.md at commits 8faba4f2, 33dc648, 02d790d and 483728e. The Game rules band was added by ADR-0017 on the evening of 16 October; the chain row by plan 0048 on the 20th.

Show as a table
Subsystem Day 1Day 6Day 8Day 11
rng reviewed specreviewed specreviewed specreviewed spec
items/tc findingsreviewed specreviewed specreviewed spec
items/quality not startedreviewed specreviewed specreviewed spec
items/affixes not startedreviewed specreviewed specreviewed spec
items/uniques-sets not startedreviewed specreviewed specreviewed spec
items/properties not startedreviewed specreviewed specreviewed spec
monsters/pool not startedreviewed specreviewed specreviewed spec
monsters/spawn not startedreviewed specreviewed specreviewed spec
monsters/special not startedreviewed specreviewed specreviewed spec
drlg/overview plannedreviewed specreviewed specreviewed spec
drlg/preset not startedreviewed specreviewed specreviewed spec
drlg/maze not startedreviewed specreviewed specreviewed spec
drlg/outdoor not startedreviewed specreviewed specreviewed spec
drlg/warps not startedreviewed specreviewed specreviewed spec
objects not startedreviewed specreviewed specreviewed spec
chain β€”β€”β€”findings
data/excel reviewed specreviewed specreviewed specreviewed spec
data/calc not startedreviewed specreviewed specreviewed spec
data/strings not startedreviewed specreviewed specreviewed spec
rng/seeds reviewed specreviewed specreviewed specreviewed spec
drlg/collision not startedreviewed specreviewed specreviewed spec
save/d2s not startedreviewed specreviewed specreviewed spec
drlg/lifecycle β€”β€”reviewed specreviewed spec
items/vendors not startedreviewed specreviewed specreviewed spec
items/cube not startedreviewed specreviewed specreviewed spec
items/sockets-runewords not startedreviewed specreviewed specreviewed spec
items/quest-drops not startedreviewed specreviewed specreviewed spec
monsters/stats not startedreviewed specreviewed specreviewed spec
hirelings not startedreviewed specreviewed specreviewed spec
player/creation not startedreviewed specreviewed specreviewed spec
combat/formulas β€”plannedreviewed specreviewed spec
stats/aggregate β€”β€”reviewed specreviewed spec
stats/states β€”β€”reviewed specreviewed spec
quests/progression β€”β€”findingsreviewed spec
quests/travel β€”β€”findingsreviewed spec
items/economy β€”β€”findingsreviewed spec

Seven rows are new. Two are the second simulation phase, stats and states. One is room lifecycle, an enabler that nothing had named until the lifecycle run found that a room put to sleep and woken again creates things. Three are a new band, game rules: quest progression, travel, and the item economy, two areas the project’s second decision had kept out of scope on day one. And one is the chain.

Every row went the same way as before: a static reading of the code tagged [I], a harness run under the debugger that raises what it reproduces to [C], a spec, a review by an agent that did not write it. The runs of the window:

RunWhat the model reproducedMismatches
Combat40 logs, 40,655 attack and on-hit events, chained on the seeds0
Stats and states18 sessions; 891,844 stat reads, 3,643 state applies, 54,719 regeneration ticks0
Room lifecycle13 sessions, 2,215,807 checks; 2,440 room releases and 1,362 restores0
Lifecycle, the town-follow3 Hell sessions, 675,849 checks4, explained
Quests and travel, three runs45 sessions, 45,714 checks0
Economy, two runs33,901 price calls, 1,061 durability rolls, 1,412 wear events, 14 resurrections0
Two clients19 sessions with two real game clients; 417 party kills, 385 experience shares, 230 player-against-player0
Simulation shortfalls31 combat logs, 18,737 events; 10 stats logs; 1 travel log0
Objects, the sweep22 sessions, 234,315 checks0 in the model
Items, three sweep batches35 sessions; 873 treasure class calls, 1,043 creations, 1,078 throwable picks0
Skills, eleven emulated batches99,450 cases of the skill and missile functions, run in the disassembler with no game0
Seed to world, run 128 logs, 156 levels, 9,057 objects, 1,286 items from the game seed alone2, open

A check is one value the model predicted and the game logged. A treasure class, which the table names twice, is the row of the drop table a monster or a chest rolls on. The sessions were driven by the agents from screenshots with the pilot from day four, except the eleven skills batches, which ran in the emulator the day six post described, under a rule that was widened on the 20th, below.

The combat run

Day six ended with the combat formulas read from the code and the harness run waiting. The run was accepted at 19:26 on the 16th, ninety minutes after that post’s cut-off: 19 sessions, 15,358 events, zero mismatches. The plan had asked for 2,000 player attacks and got 2,030; it had asked for 1,000 monster attacks and got 4,533, because monsters miss a lot: 697 hits against 3,836 misses, 2,243 of them blocked. Every kind of event had to be chained, the second event’s entry seed predicted from the first’s exit, at least twenty pairs per kind, and β€œevery kind passes the floor of 20 on both ends.”

Events in the first combat batch, 19 sessions

One event is one call of a named entry point: an attack resolved against one target, one on-hit effect applied.

Monster attacks on the player 4,533
Player attacks on monsters 2,030
Missile defence rolls 1,957
Mercenary attacks 1,259
Nova hits 519
Crushing blows 316
Deadly strikes 250
Open wounds 246

docs/findings/combat/experiments.md, run:2026-10-16-combat. The resume lane brought the run to 40 logs and 40,655 events by the next morning.

Show the numbers
events
Monster attacks on the player 4,533
Player attacks on monsters 2,030
Missile defence rolls 1,957
Mercenary attacks 1,259
Nova hits 519
Crushing blows 316
Deadly strikes 250
Open wounds 246

What the first batch could not reach was Andariel in Hell: the lane ran out of time, two attempts, and the record says so. A resume lane took the shortfalls and stopped the same evening at β€œthe owner’s deadline for the machine”. It finished at 07:56 the next morning with 40 logs and 40,655 events, still zero mismatches, and the three things that needed a boss: crushing blow on an act boss, 34 events on Andariel, is one eighth, as read; on superuniques, 55 events, also one eighth; and the mercenary’s damage percent against her is 50 in Normal, 35 in Nightmare and 25 in Hell, one read indexed by the difficulty, and the 25 in Hell is what tells that column from its neighbour, which holds 20.

The run also caught the reading in a mistake. The reading said open wounds on an act boss does the full amount, and the spec said so too. The checker had been written from the code’s test, which halves the bleed for any monster carrying the type flags 0x0C, and Andariel carries 0x08, the unique flag. All 63 of her wounds were halved. The review’s words: β€œthe finding’s β€˜no /2 for a boss’ and the spec’s β€˜act bosses take the full amount’ were wrong, and the checker had modelled it right all along.” The spec closed on the 17th at 08:16 with 190 confirmed claims against 139 inferred, and the four community claims that day six listed as contradicted, the class level bonus, the absorb healing, crushing blow on uniques and its player-count scaling, were confirmed as contradicted by the run. The shortfalls run three days later added the champions: β€œ52 crushing blows on champions took 1/4.” Not one eighth.

One monster did not fit the model: a session with Fleshripper, a unique knife that prevents monsters from healing, left 101 mismatches, all in a kill handler that runs inside the delivery and that nobody had read. The session was set aside and the handler went to the skills plan, where on the 20th the reading found where the dagger’s state is applied: inside the to-hit roll’s success branch, between the hit and the block.

The dagger that broke the model

  • Fleshripper, a unique fanged knife: the inventory picture, its drop frames and a character holding it Fleshripper, whose prevent-heal state lands between the hit and the block

The item sheet from the project's tools/item_art.py: the inventory picture and the frames of the item falling to the ground. Diablo II art Β© Blizzard Entertainment.

Stats and states

The second simulation phase was approved on the evening of the 16th and closed on the 17th at 20:06. It is the part of the game that adds things up: how an item’s bonus reaches the wearer’s strength, and how a timed state, a shrine’s blessing, an aura, a curse, is applied, refreshed and expires. Eighteen sessions with six characters built by the tools, zero mismatches, and the counts are the kind a run of a tree produces: 891,844 stat reads in the logged windows, 232,042 cache writes, 17,634 requirement checks, 3,643 state applies, of which 2,608 were refreshes of a state already there, and 6,207 aura durations, every one of them the aura’s delay plus one.

The static reading had claimed that no function in this phase draws a random number, and the plan turned the claim into a check: the seed logged on entry and exit of every event kind. One kind drew. A damaging aura, Sanctuary, takes β€œone RNG_RangeB per hit”, so it was checked by chaining instead, 746 pairs. On the 21st the catalogue read it narrower: one draw per run of the aura, whatever the number of units it hits, still inferred.

Three things in the spec that a player would not guess. An item’s per-level bonus, the kind that grows with your character level, β€œis not refreshed when the wearer levels up”, 94 entries, confirmed; it is recomputed when the item is moved. The ethereal requirement discount of ten decided 30 of the requirement checks in the run, a character with strength 115 to 124 against a pair of War Boots that want 125. And a refresh of the whole tree runs every 136 frames with no player action at all; what queues it was not read. The community’s guide says stat operation 6 β€œdoes not work” and operation 7 updates only on the client; the server computes both, and no stock item reaches them, because the two affixes that use them cannot spawn. The review also struck a number from the reading, β€œ96 s at 25 frames a second” for a shrine, because the project’s rule since day six is that timing is stated in frames and nothing else.

Rooms that sleep

Day six’s post did not mention room lifecycle because nobody had named it. The game puts a room to sleep when no player is near, and wakes it when one comes back, and the waking recreates monsters, objects and items from records it kept. Any reimplementation has to do this the same way, or a player who walks away and returns finds a different room. The plan was approved at 21:15 on the 16th, and its run on the 17th was the largest of the window: 13 sessions, 2,215,807 checks, 2,440 rooms released and 1,362 restored, 2,035 monsters brought back, every one of them with the life the model predicted.

The code reading was wrong in four places, three of them: An item restore takes two draws on the game seed, and a simple item comes back with a start seed of zero. A player’s visit between two release passes does not reset the idle count. And the reading’s headline surprise, a dead champion saved and restored alive, turned out unreachable: β€œThe save test’s 0x18 mask is β€˜special or minion’. Every logged champion carries 0x08, so a dead champion is never saved.”

Against the community, the lifecycle spec contradicts a belief players repeat often. A level without the SaveMonsters flag is said to leave its monsters β€œinjured”; in 1.14d, β€œany other live monster of a released room is freed without a record, and the room is not populated again, so it is gone, not injured.” Blood Raven is said to be back at full health after twenty minutes; the rule is that a restored monster keeps its saved life if fewer than 7,500 frames passed between the save and the restore, and gets its maximum otherwise. And Prevent Monster Heal is said to reset when you walk too far: nothing resets by distance, β€œa released and restored monster is a new unit.”

The monster the twenty-minute rule is told about

  • Blood Raven: a corrupt rogue archer with a bow, standing still Blood Raven, as the game draws her class

Composed from the game's own sprite layers with tools/cof.py, first frame of the neutral pose with the bow, without the colour shift a superunique gets in the game. Diablo II art Β© Blizzard Entertainment.

One case the run could not reach was a monster following the player into town. A follow-up batch tried three Hell sessions on the 17th and finished on the 18th with 675,849 checks and the only non-zero mismatch count of a finished run in the window: four. All four were explained the same way, a flag bit the restore does not copy back, four of 1,689 monster records. The chaser never crossed a town, and an offline scan of 106 town layouts showed why it cannot: of 93,944 cell pairs, zero routes through a town are shorter, because β€œeach town’s interior meets its neighbour level at one gate.” The batch also reads the sweep for expired items as running every 1,500 frames and not every 20, as the reading had said; the 20 belonged to the quest timer beside it. That one stays inferred: the run excludes 20 without confirming 1,500.

The run had a mishap, and the mishap became a rule. One launch overlapped a running development session on the same harness slot, both were killed, and the partial log of the overlapped launch was deleted. The play guide now says: β€œPartial logs are kept. An aborted session, or one that overlapped another on the same slot, leaves a partial log: keep it… and never delete it.” And the third Hell session was killed at 21:38 on the 17th, when the machine shut down with it in the middle of its second pass of leaving the room and returning; its partial log is part of the record, and the lane’s draft text, kept in scratch, was lost and rewritten from its anchors.

The sweep

Day six introduced plan 0038, the sweep of the 1,526 inferred statements the reviewed specs still carried, sorted into batches: static ones, where a kept log or a second source already holds the evidence, and harness ones, which need new sessions. Two batches had run by that post’s cut-off. Eighteen more ran in this window.

What each sweep batch raised

A statement is raised when the batch's evidence covers it whole, in part when it covers some of its cases; a shortfall is a statement the batch set out to reach and did not.

  • raised
  • raised in part
  • shortfall
S1e, emulation: calc, excel, strings, rng, saves 74
S2c, static: items 75
S1b, static: data, rng 75
S1a, static: the save file 54
H4b, harness: monsters 45
S2b, static: affixes, properties, uniques 49
H5c, harness: levels and warps 40
S3a, static: monsters, hirelings, player 39
S4b, static: levels and objects 39
H5e, harness: mazes 22
H5a, harness: level links 16
S1f, emulation, second batch 15
H2b, harness: the item chain 20
H2a, harness: treasure classes 17
S3b, static: monsters, hirelings, player 15
H5b, harness: objects 28
H6d, harness: quest drops 16
H2c, forced tables: throwables 7

docs/plans/0038-inferred-claims-sweep.md, the review's final line of each batch. H5b's record counts rows of the inventory, the others count statements.

Show the numbers
raisedraised in partshortfall total
S1e, emulation: calc, excel, strings, rng, saves 6914 74
S2c, static: items 48270 75
S1b, static: data, rng 47280 75
S1a, static: the save file 39150 54
H4b, harness: monsters 3591 45
S2b, static: affixes, properties, uniques 30181 49
H5c, harness: levels and warps 23611 40
S3a, static: monsters, hirelings, player 20190 39
S4b, static: levels and objects 19137 39
H5e, harness: mazes 1822 22
H5a, harness: level links 1600 16
S1f, emulation, second batch 1500 15
H2b, harness: the item chain 1451 20
H2a, harness: treasure classes 1250 17
S3b, static: monsters, hirelings, player 1140 15
H5b, harness: objects 10117 28
H6d, harness: quest drops 592 16
H2c, forced tables: throwables 421 7

Two batches ran in the emulator rather than the game, the method ADR-0015 admitted on day six: one function of the binary at a time, in Ghidra’s processor emulator, on inputs the batch chose, with every memory read traced. The first emulated 28,643 cases over ten families of functions and every one matched bit for bit, with a negative control failing as it should. The second added 18,800 and a guard directive, so that a case whose program counter reaches a fatal path stops instead of wandering. It also found a limit of the emulator itself: under its instruction model, dividing the smallest 32-bit integer by minus one returns zero where the real processor traps. β€œIt does not change a decision, so nothing goes to the owner.”

Two statements came back contradicted. The seeds spec had said that a seed of 2Β³ΒΉ or more is given on the command line as its negative decimal. The run showed the parser copies a switch’s text only up to the next dash, so -seed -1 arrives empty, reads as zero, and the game takes the clock; a value of 2Β³ΒΉ or more saturates. The seeds you can reproduce from the command line are 1 to 0x7FFFFFFF. And the Cube spec said the cow portal’s spot search draws; it does not, the portal object does, 171, 173 and 171 steps in the three openings. The treasure-class batch found the kind of overclaim a sweep exists for: the quality roll’s clamp, which the step note said β€œnever acted in the runs”, acts in 667 of the batch’s rolls and decides 138. The note was true of the two quality runs it was written on, a week earlier.

A re-tag recounts a spec after its batches land:

Confirmed claims in the re-tagged specs, before and after the sweep

  • before
  • after
items/tc 49 119
items/affixes 112 152
items/properties 130 152
drlg/preset 98 134
data/calc 77 129
drlg/maze 105 122
drlg/room-tiles 89 120
drlg/warps 91 104
drlg/outdoor 170 180
rng/seeds 62 76
drlg/README 60 75
rng/README 22 28

The front-matter counts each re-tag round records in docs/plans/0038-inferred-claims-sweep.md. The inferred count falls by about as much as the confirmed count rises; items/tc went from 81 inferred to 60.

Show the numbers
beforeafter
items/tc 49119
items/affixes 112152
items/properties 130152
drlg/preset 98134
data/calc 77129
drlg/maze 105122
drlg/room-tiles 89120
drlg/warps 91104
drlg/outdoor 170180
rng/seeds 6276
drlg/README 6075
rng/README 2228

The inventory at the cut-off: 567 statements in static batches, 526 in harness batches, 414 blocked, and 17 raised at the inventory itself. Of the blocked, 288 have no reachable evidence, 73 need an edited table, 28 need the simulation, 7 need two players in one game, and 10 need me to play. Day six counted twenty-one harness batches still to run; twelve are left, in an order I set on the 20th, core and enablers first.

Game rules

The project’s second decision, on day one, drew the scope around creation: items, monsters, levels. Day six brought in the simulation. On the evening of the 16th a third decision, ADR-0017, brought in what the ADR calls game rules, two areas, three rows on the map, outside the simulation’s phase order: quest progression and travel, and the item economy. Its reason: β€œA reimplementation that has every creation path but no quest progression, no waypoints and no prices is not a playable game, and those are the gaps a reimplementer meets first after the world generator.” The evidence rule is by the shape of the claim. A one-shot function, a price, a repair cost, a gold amount, is reproduced as a creation path is; an event-driven change, a quest bit set by a kill, a durability point lost on a hit, is reproduced per event under the simulation’s rule. And the ADR names the cost: β€œQuests are hardcoded. There is no quest table; 1.14d inlines each quest’s callbacks.”

Quests and travel

Three runs, on the 17th, 18th and 19th: 11, 21 and 13 sessions, 45,714 checks, zero mismatches. The static reading of the quests had 596 symbols and the spec that came out of it is the most inferred on the map, 322 inferred against 117 confirmed, because every quest’s callbacks are code, and there are a lot of callbacks that no session reached.

What the runs settled. A town portal takes three draws, not the five the reading said: β€œBoth ends come out of SUnitCreate already in their mode… so neither the creation nor the following SetMode draws.” The door to the Arreat Summit reads one byte, quest 35’s private β€œdone in this game”, and refused both characters built to test it, one without the word, one with every quest done. A handler of quest 11 writes a bit of quest 12’s word while quest 11 is switched off, 44 writes. The stones of the Tristram cairn have to be touched in an order, and the order is a draw on the quest seed, made once per game at the first use of the decoded scroll. Tyrael’s travel to Harrogath is not a line in his menu: the stock menu has no travel line, and the travel is the portal object beside him. And the hostility delay the community gives as ten seconds for leaving town: β€œheld for waypoints (10 000 ms), contradicted for portals: the portal gate waits 5000 ms.”

Two things about the method. The third run’s review lowered the menu lines that had been confirmed from a screenshot: β€œA screenshot is not enough for a [C].” And the night between the 18th and 19th was the first of the window’s bad nights: the machine suspended for about nine hours, the game exited, and the driver kept clicking into the window that was no longer there until the main session killed it at 07:23. Each session now has a watchdog.

The first run reached no Hell session: β€œthe scripted walk to the town waypoint failed in five Hell launches.” The third got two. No waypoint was activated from its dormant state, because every waypoint the sessions met was already active. And the boss steps of the quests, the kills that turn a quest’s bits, were marked as candidates for me to play, with the note β€œStill optional”. I have not played them.

The economy

Buying, selling, gambling, repair, hiring and resurrecting a mercenary, gold on the floor and gold lost at death, and the wear of items in combat. The run started on the 17th, was rotated between lanes, and closed on the 19th with 26,525 price calls over 3,762 distinct inputs, 138 repair-all sums, 22 hires, 14 resurrections of which 4 were refused, 20 death losses, 1,061 durability rolls and 1,412 wear events, zero mismatches. A second run the same day added 7,376 price calls for the cases the first had missed: crafted items, repair in Hell, gambling at level 3.

Against the community the economy spec compared 22 claims:

Twenty-two community claims about prices and wear, against the code

  • held
  • held with refinement
  • contradicted
  • not covered
items/economy 22

docs/specs/items/economy.md Β§ Leads. Five of the six contradicted claims were also reproduced by the run; the sixth, Books, is equal on stock data.

Show the numbers
heldheld with refinementcontradictednot covered total
items/economy 10561 22

The contradicted ones:

  • An ethereal item sells for 25 percent less. It sells for a quarter: the sell value is shifted right by two. A class item is quartered again.
  • An ethereal throwing weapon is always worth one gold. A stack of ethereal javelins sold for 1,040 at every one of fifteen vendors.
  • An affix’s price multiplier is in 1,024ths for buying and 4,096ths for selling. All three values divide by 1,024.
  • The gamble cost column is the gambling price. It is read only for rings, amulets and items of version 0; every other gamble price is computed.
  • Armour wears by slot weights 2, 3, 2, 1, 1, 1 for head, body, shield, waist, feet, hands. The table in the binary has seven slots at 3, 5, 4, 4, 2, 2, 2, and 964 of 964 wear picks in the run named the slot whose item then wore.

What held, exactly: the 4 percent chance of weapon wear and 10 percent of armour wear per hit, the death loss of min(L, 20) percent with 500 gold per level kept in single player, the resurrect cost of LΒ² / 2 Γ— 15 capped at 50,000. And β€œβ€˜Sell mult’ is the buy price.” There is a function to charge for healing, and nothing calls it: 1.14d heals for free. The code reading had been wrong about one thing, which the first check caught in four failed resurrections: a refused resurrection pays nothing and revives nothing, which the finding had not said. And a detail of the client the run noticed on the way: it asks β€œRepair… Gold: cost β€” Yes / No” even when you cannot pay.

The gold the economy run counted

  • Wirt's Leg, a wooden leg used as a club: the inventory picture, its drop frames and a character holding it Wirt's Leg, under which the run counted 18 piles of gold and reproduced every one

From tools/item_art.py. The second economy run checked the gold Wirt's body drops: the count of piles and the item level of each. Diablo II art Β© Blizzard Entertainment.

Two players in one game

ADR-0008, the two-client harness, had been proposed since day two and accepted on the 16th, on one condition: before any session hosts a game, the lane makes sure that port 4000, the game’s port, cannot be reached from outside the machine, and records how. That was my one root command of the window, on the 17th. The record quotes the output of ufw status verbose line by line, β€œDefault: deny (incoming)”, the only allowed ports, and ends: β€œNo rule names 4000, no range contains it, and no rule is portless. So TCP 4000 is dropped on every non-loopback interface… This meets ADR-0008’s condition.” The lane’s request had said β€œNothing else is asked: no probe, no second machine.”

The run itself was on the 20th: 19 sessions with two real clients on two harness slots, the joiner steered from the host’s log because the joiner has no debugger, 417 party kills with drops, 46 vendor stock events with two players present, 385 experience shares, 12 quest bits written with both players in the game, 230 attacks of one player on another, every checker at zero mismatches. Four times a checker had to change, and each time the review ruled β€œthe checker, not the game, was wrong”: one had hard-coded a single player. What the two clients found that one could not: the party experience share is computed with an 80-bit floating-point product of the share and the level, not rounded to 32 bits, and 98 inputs separate the two; the stock client refuses to declare hostility outside town; a dead player has a mode of his own, 17.

The review also found that the script which checked the firewall before each hosting session always exited zero, so the guard it was in would never have stopped a session. It is fail-closed now, and the rule says never to call it without || exit 1. The re-tag raised 28 claims across eleven specs, the two-player cases the sweep had blocked fell from 14 to 7, and the plan closed at 15:23 on the 20th. Four cases that need two players at a boss were left for me, β€œNot blocking anything.”

Skills, in two plans

Phase three of the simulation is skills and missiles, and it is bigger than the first two together: 357 skills, 64 distinct start functions and 138 do functions on the server, 684 missile rows with their own do, hit and damage functions. ADR-0020, accepted on the 20th, splits it: β€œRead literally, ADR-0014 would hold monster AI (phase 4) until every one of those functions has a reviewed spec.” Plan 0045 is the machinery, dispatch, packets, missiles and event handlers, and its spec is the phase’s spec; plan 0046 is the catalogue of every numbered function, and runs beside phase four without blocking it. On the same day I swapped phases four and five: animation and frame timing before monster AI, β€œsince skill and combat timing need frame counts first.”

The machinery’s static phase closed on the 20th. The progressive finisher’s seed step is a peek, saved and restored, not a draw. Against 61 community claims about skills and missiles, 27 held, 25 held with refinement, 5 were contradicted and 4 not covered, all of it read from the code and tagged inferred, with a caution in the finding: a contradiction from a community source β€œmay be a Resurrected change.” The contradicted five, each now a case for the harness phase: a raised skeleton’s level is not the caster’s but min(max(L Γ— 3/4 + skill level, 1), L); a missile’s velocity is (VelLev Γ— lvl) / 8 + Vel, shifted left by eight, not Vel plus VelLev per level; Accel is added on every fifth path step, not every frame; LevRange has no minus one; and a missile that misses with pierce is freed at that unit, it does not keep flying.

The catalogue is 310 entries, and it runs in the emulator, because a function that creates a missile cannot be run in the game a thousand times with chosen inputs, and it can in the emulator. Fifteen batches; by the cut-off eleven were accepted, 230 of the 310 entries, 99,450 cases, zero mismatches. The Amazon batch’s first session was killed by the out-of-memory handler before it checked; the kept run is the second.

The first batch produced a decision. Most catalogue functions end in a call whose inputs cannot be declared, a unit allocation, the path planner, a monster spawn, and the lane had stopped its cases at that call and claimed what happened before it. The review found that this β€œdoes not meet ADR-0015 (1) and (3) as written”, held the batch’s claims at inferred, and drafted ADR-0021 for me: a case may end at an observed boundary, a named callee’s entry, where the emulator stops before the first instruction and records the registers, the stack and the memory, and the claim covers β€œnothing after the call.” The rejected alternative was to read the old rule as already allowing it: β€œwidening an evidence rule by reading belongs in an ADR, not in a review.” I accepted it at 14:56 on the 20th and the batch’s claims went to confirmed without a re-run.

What the emulator found that the reading had not: the do function of Fend, Zeal and Fury β€œreturns 0 on every path”; two start functions pass zero as the attack rating to the melee hit test, so Power Strike’s to-hit bonus never reaches it; the elemental damage roll of one function is made once per run and not once per unit, which the stats spec had as β€œper hit”; Blade Fury’s hit creates a missile of class 0, which is the arrow; the rings never test their step count, so a count of zero never ends. And one for the paladins: a function that Raise Skeleton and Revive run before anything else β€œhits a player caster of class 3 for maxhp / 8”, class 3 being the paladin in the class order, inferred: no case ran it with a paladin.

Seed to world

Every spec in the core band was checked with oracles at its edges: a value read from the game instead of predicted, where the thing that produced it belonged to another spec. The treasure class run read the monster’s seed from the log; the drop run read the item’s. That was by design, ADR-0004, and it left a question the plans never asked: do the specs compose? Plan 0048 asks it. Its phase 0 inventoried 31 oracles across the core specs and assigned ten to be retired. Phase 1 retired eight: staff mods, the unit seed after creation, the preset window’s monsters, one object function, the units of one placement path, another room’s seed as chain state, gold items’ seeds, an object’s drop. Two it could not: one is read and still logged, one is named and not modelled. The tool that runs the chain is tools/chain.py.

Phase 2’s bar is the first time this project has asked for the whole thing: β€œ2 000 room populations end to end from the game seed (no seed oracle in the window); 300 objects’ creations; 100 special monsters…; 500 drops predicted from the dying unit’s logged seed through TC, quality, affix, unique or set and property rolls with no builder oracle.” Run 1 started on the 20th and ran through the night. One session was cut at 20:12 when the out-of-memory killer took the lane’s agent and driver together and the game ran on without a pilot until its timer. Another sat through a seven-hour suspend and checked clean. The result: 28 logs, 26 passing, 156 levels of every generator type in every act and difficulty, 9,057 objects, 44 champion and 110 unique packs with 147 mod rolls, 849 monster drops with 951 items, 2,514 treasure class calls and 1,286 item creations, none failed. Two logs each had one mismatch in the objects model, and the lane’s own explanation of them was wrong; the review’s reading is that the two candidates are monsters re-created after their room was released and returned, β€œthe re-creations have no CM line and no modelled mark.” Short of the bar: 1,222 of the 2,000 populations, which is about sixteen more sessions. Run 2 is on slot 1 now. The chain row was added to the core band at the phase 0 review, which is why the map has one row unreviewed.

The first end-to-end run against its bar

What phase 2 asked for from the game seed alone, and what the 26 passing logs of run 1 delivered.

  • asked
  • delivered
Room populations with no seed oracle 2,000 1,222
Monster drops predicted to the item 500 849
Object creations 300 9,057
Champion and unique packs 100 154

docs/plans/0048-seed-to-world.md, the Phase 2 done-when and the review's corrected counts. Only the populations fell short; run 2 is for them.

Show the numbers
askeddelivered
Room populations with no seed oracle 2,0001,222
Monster drops predicted to the item 500849
Object creations 3009,057
Champion and unique packs 100154
flowchart TB
gs["game seed"] --> lv["level seeds and layouts: drlg/overview, preset, maze, outdoor, warps"]
lv --> ob["objects, chests and shrines: objects"]
lv --> pop["room populations: monsters/pool, spawn, special, stats"]
pop --> kill["a monster dies: its logged seed"]
kill --> tc["treasure class and NoDrop: items/tc"]
tc --> q["quality: items/quality"]
q --> af["affixes, uniques and sets, properties"]
af --> floor["the item on the floor, with its stats"]

How it was run

The lanes ran as on day six: at most two harness lanes on slots 1 and 2, slot 0 mine, at most two static Ghidra lanes, each lane with its own copy of the repository, a review by the architect in landing order, and a rule from the 20th that a phase whose prerequisite has not landed is skipped, not waited on. What changed is that the reviews are now counted. On the 17th a ledger went in, one row per lane and one per review by the reviewing agent, the one the project calls the architect: tokens, tool uses, wall minutes, the verdict, and the fixes by category. In the window it holds 121 lane rows and 107 reviews. Two verdicts were a plain accept, six lanes were merged with no review, bookkeeping and one at my request, none was a reject, and the other 113 were β€œaccept with fixes”, 514 fixes in all.

What the reviews fixed, 16 to 21 October

Each fix counted once, in the first category that fits, in the order the ledger lists them.

Overclaim: a tag or wording stronger than the evidence 142
Omission 112
Misread: a statement the code or data contradicts 80
Stale cross-reference 45
Other 43
Miscount: a count not recounted 40
Wrong anchor 21
Under-claim 16
Tool not kept 10
Symbol clash 3
Bookkeeping splice 2

docs/plans/metrics.md. The file's own warning: 'Fix counts are the reviewer's classification, not a measure of the lane's quality: a review that reads more finds more.'

Show the numbers
fixes
Overclaim: a tag or wording stronger than the evidence 142
Omission 112
Misread: a statement the code or data contradicts 80
Stale cross-reference 45
Other 43
Miscount: a count not recounted 40
Wrong anchor 21
Under-claim 16
Tool not kept 10
Symbol clash 3
Bookkeeping splice 2

The ledger has a purpose beyond counting: every few reviews the reviewer reads its recent rows and promotes any fix seen twice into a rule in the lane’s own list, and drops a rule that has not recurred in thirty reviews. The lists exist now, one per lane skill, each rule with the lane it was seen in. From the reverser’s: β€œA new code reading is [I]. [C] needs a named second source.” β€œRecount every count from the binary with a kept command, never from memory or a partial scan.” β€œβ€˜Never’, β€˜only’, β€˜no X’: say what the run separates. If one case carries both readings (Andariel has flag 0x08 and boss), that half stays [I].” And from the architect’s own list, which it calls its blind spots: β€œA claim settled at review gets the lane’s scrutiny.” β€œLabel a plan’s estimates as estimates.”

The backlog changed shape twice. On the 17th it was one file of 730 lines and 519 entries, 464 of them struck, and in two days about 170 had been added and β€œalmost every lane merge conflicted in this file.” ADR-0018 made it one file per entry, with no committed index, β€œbecause a shared index would bring back the hot spot.” Three days later the folder held 55 open and 80 closed entries, I said it was getting large, and ADR-0019 moved the closed ones to an archive. At the cut-off: 43 open, 186 archived.

And the nights. The 17th: a shutdown at about 21:38 that killed a Hell session mid-cycle. The 18th to 19th: the nine-hour suspend. The 19th, a Sunday: by ten in the morning three lanes had β€œstopped at the owner’s usage limit”, my subscription’s cap, and nothing landed after. The 20th: a debugger crash under Wine in the middle of a batch, a thread race in gdb 18.1; at 20:12 the memory manager killed every agent at once, no resume note; and from 23:17 to 06:20 the machine slept again, so the ledger books 428 of one lane’s 624 wall-clock minutes as suspend. None of it lost a claim.

The numbers

Where it is now, against day one and day six

Reviewed specs (28 rows to day 4, 29 on day 6, 35 on day 8, 36 on day 11)

3 day 1
28 day 6
32 day 8
35 day 11

[C] confirmed claims in findings

48 day 1
1,150 day 6
1,773 day 8
2,540 day 11

[I] inferred claims in findings

175 day 1
1,189 day 6
1,896 day 8
2,667 day 11

Named addresses in Game.exe

278 day 1
1,814 day 6
2,772 day 8
3,373 day 11

Python tools

26 day 1
91 day 6
144 day 8
170 day 11

Closed plans

5 day 1
36 day 6
39 day 8
44 day 11

Each measure has its own scale. Sources: the research map, docs/findings, re/symbols.csv, tools/ and docs/plans/done at each cut-off.

Confirmed and inferred claims in the findings

[C]: read in the code and confirmed by something independent, usually a run. [I]: read in the code only. Nights are cut out.

  • [C] confirmed
  • [I] inferred
0 200 400 600 800 1000 1200 1400 1600 1800 2000 2200 2400 2600 2800 11 Oct 12 Oct 13 Oct 14 Oct 15 Oct 16 Oct 17 Oct 18 Oct 19 Oct 20 Oct 21 Oct [C] 2540 [I] 2667

The empty 18th and 19th are the suspend and the limit. On the 20th both lines climb together because every new reading lands as [I] and its run raises part of it.

Show the numbers
Time[C][I]
11 Oct 10:31 0 0
11 Oct 13:35 7 15
11 Oct 15:05 21 58
11 Oct 16:00 28 59
11 Oct 16:25 42 62
11 Oct 17:57 45 104
11 Oct 19:06 48 148
11 Oct 20:11 48 175
11 Oct 22:12 57 176
11 Oct 22:23 57 176
12 Oct 08:04 80 173
12 Oct 08:41 103 183
12 Oct 09:02 104 184
12 Oct 09:31 108 217
12 Oct 09:58 109 228
12 Oct 10:16 117 278
12 Oct 10:42 135 295
12 Oct 11:51 139 295
12 Oct 12:21 159 291
12 Oct 13:41 161 292
12 Oct 14:10 168 295
12 Oct 15:19 168 320
12 Oct 15:46 184 354
12 Oct 15:58 184 354
13 Oct 08:05 196 348
13 Oct 08:26 204 374
13 Oct 08:33 205 422
13 Oct 10:11 206 448
13 Oct 13:43 223 449
13 Oct 15:59 225 452
13 Oct 18:56 229 453
13 Oct 19:21 236 452
13 Oct 19:28 240 455
13 Oct 21:15 279 429
13 Oct 22:02 279 442
14 Oct 08:11 279 442
14 Oct 08:49 282 443
14 Oct 09:21 282 493
14 Oct 09:36 282 495
14 Oct 09:49 290 536
14 Oct 10:00 291 537
14 Oct 10:09 293 586
14 Oct 10:20 293 587
14 Oct 11:05 332 567
14 Oct 13:10 356 562
14 Oct 17:35 376 560
14 Oct 19:22 376 611
14 Oct 19:56 395 651
14 Oct 20:36 402 691
14 Oct 20:50 446 721
14 Oct 20:59 451 757
14 Oct 21:16 461 796
14 Oct 22:37 506 772
14 Oct 22:50 545 743
15 Oct 02:10 574 733
15 Oct 02:44 587 732
15 Oct 02:54 612 737
15 Oct 03:05 619 727
15 Oct 03:29 629 739
15 Oct 03:57 671 738
15 Oct 04:14 711 716
15 Oct 07:39 718 733
15 Oct 08:47 729 737
15 Oct 08:48 737 779
15 Oct 08:54 746 782
15 Oct 09:05 771 791
15 Oct 09:17 773 848
15 Oct 19:08 774 890
15 Oct 19:10 786 941
15 Oct 19:13 797 940
15 Oct 19:25 801 982
15 Oct 19:33 829 1015
15 Oct 19:38 829 1057
15 Oct 19:48 841 1064
15 Oct 19:56 845 1066
15 Oct 20:13 845 1072
15 Oct 20:24 848 1095
15 Oct 23:42 875 1092
15 Oct 23:54 886 1095
16 Oct 00:15 886 1094
16 Oct 00:21 889 1096
16 Oct 01:43 905 1093
16 Oct 02:23 918 1098
16 Oct 02:28 923 1103
16 Oct 03:49 956 1090
16 Oct 06:40 987 1065
16 Oct 14:29 1003 1072
16 Oct 15:31 1023 1075
16 Oct 16:08 1023 1152
16 Oct 17:21 1080 1181
16 Oct 17:36 1140 1189
16 Oct 17:53 1150 1189
16 Oct 18:24 1174 1194
16 Oct 18:34 1228 1208
16 Oct 18:35 1267 1217
16 Oct 19:26 1281 1238
16 Oct 19:29 1321 1250
16 Oct 20:49 1391 1257
16 Oct 21:01 1412 1263
16 Oct 21:29 1486 1263
16 Oct 22:07 1505 1269
16 Oct 22:19 1515 1306
16 Oct 22:26 1566 1314
16 Oct 22:41 1577 1319
17 Oct 07:51 1577 1367
17 Oct 07:56 1585 1375
17 Oct 08:02 1597 1380
17 Oct 08:35 1612 1432
17 Oct 08:47 1650 1434
17 Oct 09:04 1647 1430
17 Oct 09:09 1647 1512
17 Oct 09:45 1657 1536
17 Oct 09:55 1669 1539
17 Oct 10:44 1670 1729
17 Oct 10:50 1670 1796
17 Oct 10:58 1670 1808
17 Oct 11:07 1681 1816
17 Oct 11:15 1683 1826
17 Oct 16:44 1707 1827
17 Oct 17:18 1707 1838
17 Oct 17:33 1707 1839
17 Oct 18:26 1708 1849
17 Oct 19:16 1746 1858
17 Oct 19:27 1747 1870
17 Oct 20:06 1747 1871
17 Oct 20:56 1770 1884
18 Oct 20:09 1773 1896
19 Oct 08:00 1788 1907
19 Oct 08:10 1804 1923
19 Oct 08:44 1805 1924
19 Oct 09:26 1814 1929
20 Oct 08:30 1849 1953
20 Oct 09:11 1849 1955
20 Oct 09:54 1853 2032
20 Oct 10:17 1856 2059
20 Oct 10:29 1914 2070
20 Oct 10:51 1917 2110
20 Oct 10:58 1947 2125
20 Oct 11:19 1973 2133
20 Oct 11:51 1973 2188
20 Oct 12:29 1973 2189
20 Oct 13:11 2022 2217
20 Oct 13:20 2036 2266
20 Oct 14:53 2037 2268
20 Oct 14:53 2076 2308
20 Oct 14:56 2099 2293
20 Oct 14:57 2108 2300
20 Oct 15:43 2110 2302
20 Oct 15:47 2154 2360
20 Oct 18:55 2178 2374
20 Oct 18:55 2230 2414
20 Oct 19:19 2230 2416
20 Oct 19:54 2272 2450
20 Oct 21:31 2312 2484
20 Oct 22:21 2347 2508
20 Oct 23:11 2381 2538
21 Oct 07:17 2420 2570
21 Oct 07:37 2431 2581
21 Oct 07:46 2445 2586
21 Oct 08:21 2479 2619
21 Oct 11:24 2489 2628
21 Oct 11:53 2539 2667
21 Oct 11:57 2540 2667

On day six the findings held 1,150 confirmed claims against 1,189 inferred. Now 2,540 against 2,667, and the share is the same, 49 percent, because every reading of a new area arrives inferred and its run confirms a part. The specs, which are the deliverable, went from 2,546 confirmed and 1,539 inferred to 3,791 and 2,322. The named addresses in Game.exe went from 1,814 to 3,373, the tools from 91 to 170, the save recipes from 112 to 233, the closed plans from 36 to 44. The wiki, which day six said was good and needed improvement, gained pages for combat, stats and states, quests and the economy.

What is open

  • The skills run. Plan 0045’s harness phase waits for both slots: the five contradicted missile claims, Blaze, a skill no run has cast, and the Fleshripper handler. The map’s three skills rows are added when it starts.
  • The catalogue’s last four batches: items with Unsummon, then three more.
  • Seed to world, run 2: the re-creation marks logged and modelled, the two mismatches re-checked, about sixteen sessions.
  • The sweep’s remaining batches, twelve, and the 414 blocked statements, ten of which need me.
  • Phases four and five, animation and frame timing, then monster AI: no plan yet; the pipelining decision lets phase four’s plan follow the skills run.
  • The things only I can play, all marked optional: the forge, Andariel and the Ancients with a second player, the boss steps of the quests, the Diablo pair of the quest-drops batch, and a Hellforge session in Hell for one treasure class property, where the pilot β€œdied at hop 19 in the River of Flame.”

The voxel engine ran its own five days in the other repository, and went from version 0.3 to 0.24.