The World Vol 6 · Evolution
ch 69 / 105
Chapter 69

The Same Two Hundred Years, Twice

Replay is a volume finding

This volume has spent twelve chapters producing findings: a population that climbs for about fifteen years and then sits within a few animals of three hundred and thirty-six, one species that splits into several, and archived genes that drift when nothing reads them. Replay needs the same initial state, inputs and deterministic execution rules in the same reference environment.

A deterministic branch may consume a different number of draws for different outcomes and still reproduce exactly. This volume also fixes draw counts for controlled comparisons between branches, so a mutation rate change can be measured without moving every later roll.

A finding from a run you cannot get back is a story. The page needs more: the same seed, same years and same code producing the same archive, even after the valley has spent two hundred years making births, deaths, species and wiring changes.

Four-year rehearsals catch obvious mistakes, but the real failure can hide for a hundred thousand asks. The volume's claims came from two centuries, so the replay proof has to run two centuries too.

The chapter collects the determinism rules already in force, runs the two long worlds beside each other, names the tick where an intentionally broken run parts, and prices ten copies of the valley. The proof is the archive bytes, not the absence of a panic.

◆ Note — volume-six measurement boundary

Every valley on this page is the one the channels, speciation and archive chapters ran: sixteen by twelve cells with the rim cracked and walled, the room rule on, twenty-five animals founded on stream 12 with a founding wiring of a hundred and forty-four links, the eight ground channels open and billed, children sorted into species as they are born, and every birth and death written to an archive. The four-year runs and the two-century run are the same valley stopped at different places, and the four grounds at the end of the page are that recipe on more ground.

Nothing here may be set beside a figure from a chapter before the wiring could grow. Those runs evolved a flat row of three hundred and seventy-eight weights and spent a different count of numbers on every birth, so they are a different history of the same seed.

Determinism rules already in force

Collect them first, because there is nothing new to write. Each of these was settled on the page that needed it, and every one was settled the same way: by taking something that could depend on an outcome and making it depend on nothing at all.

A draw count never depends on what a draw said. The copying chapter takes two numbers off stream 16 for every gene of a child, always: the first decides whether the gene moves and the second is its new value, and the second is taken whether or not it is used. A mutation pass over a genome of G genes is exactly 2G numbers. The crossing chapter takes 1 + G off stream 17 in the same spirit, one for whether the birth has two parents and one a gene, and the per-gene draws happen on a single-parent birth too. These are comparison rules, stronger than replay alone requires. The graph chapter takes exactly four off stream 19 every birth, for add a link, where it goes, add a node and which link is split, mapped onto the candidate list by index. And the birth chapter puts all of that together into one rule with no exceptions in it: a creature that is asked for a child spends 8 + 3G numbers whether the child is born, refused for want of a store or refused for want of ground.

Numbers that will make no difference are drawn anyway. The arena's elite place holds its tournament and runs its whole mutation pass and uses neither, so a run with one champion carried through and a run with none read the same streams in the same order and differ only in which genome sits in slot 0. Without that coupling, the comparison would also include a shift in which random draws reach later slots.

These comparison benches choose an index with int(s.Float64() * n). That spends one draw, at the cost of a small mapping bias when the finite set of floating-point samples cannot divide evenly among the candidates. s.IntN(n) avoids that bias with rejection sampling when needed; its draw count can vary. With the same seeded generator and deterministic call order it still reproduces. The mapping here stays as it is to hold these experiments' draw alignment and their tapes, and not because rejection is nondeterministic: it is not.

Arithmetic happens in a written-down order. A node in a grown controller adds its incoming links ascending by source node number, which is the only order that reproduces the fixed network's row of multiply-adds. The graph chapter turns that off behind a flag and 4,825 of 6,000 output numbers move, none of them by more than three parts in ten thousand million million. Floating-point addition is not associative, so a total is a fact about an order as much as about a set of numbers.

Work is evaluated in a written-down order, and work that draws nothing may be split. The arena scores its genomes in population order, and scoring a genome draws no random number at all. That is what licenses handing the scoring to several goroutines: the generation's digest is the same on one, two, four, eight and sixteen of them. In the valley the same argument runs the other way round, and the phase order is the answer to it: build the view, cast every fan, step the roster in order, bury the dead, mint the births. A newborn goes on the end of the roster and is not stepped on the tick it is born, because the view every creature in that phase is reading was built before the child existed.

The cheap question is asked before the expensive one. The long-run chapter asks the ground whether a creature has anywhere to put a child before the birth touches a generator, and its counterfactual flag asks after. Eight years of the same valley then give 898 births instead of 917, which is a different valley and not the same one running slower. The reason is the rule at the top of this section arriving from the other side. A creature that cannot breed has to cost the pass nothing, because the moment it costs a draw it has moved the sequence for everybody behind it.

The two orders a run of this valley is built on: the five steps of a creature phase, and the five draws of one birth Two stacked panels. The upper panel shows one creature phase as five boxes joined left to right by arrows: build the view, cast every fan, step the roster, bury the dead, and mint the births, the last of them highlighted as the one this chapter breaks on purpose. Two notes beneath say that a newborn goes on the end of the roster and is not stepped on the tick it is born, because the view every creature read was built before the child existed. The lower panel shows one birth as five boxes joined the same way, each naming the stream it draws off and how many numbers it takes: stream eighteen for the mate, one number; stream seventeen for the crossing, one plus one a gene; stream sixteen for the copy, two a gene; stream nineteen for the growth, four numbers; and stream twenty for the placement, two numbers. Two notes beneath say that a founding genome is a hundred and sixty-seven genes, so one birth is five hundred and nine numbers, and that all of them are spent whether the child is born or the birth is refused. ONE CREATURE PHASE, IN THE ORDER IT HAPPENS BUILD THE VIEW CAST EVERY FAN STEP THE ROSTER BURY THE DEAD MINT THE BIRTHS a newborn goes on the end of the roster and is not stepped on this tick, because the view every creature read was built before the child existed ONE BIRTH, AND THE ORDER ITS NUMBERS ARE SPENT IN 18 THE MATE 1 17 THE CROSS 1 + G 16 THE COPY 2G 19 THE GROWTH 4 20 THE PLACE 2 a founding genome is 167 genes, so one birth is 8 + 3 x 167 = 509 numbers spent whether the child is born, refused, or finds nobody to breed with
Figure 69.1 — the two orders every run in this volume is built on, and only one of them is load-bearing. Move a step of the phase and the world changes: cast the fans after the roster has been stepped and every animal sees a valley somebody has already eaten out of. Move a step of the birth and nothing at all happens, because each of those five purposes has a generator to itself and nobody else is reading stream 20. What carries the weight in the lower panel is the count, not the order: five hundred and nine numbers, every time, whatever comes of them.

What is missing is any way to notice. Every rule above is enforced by somebody having written the code that way, and a valley whose breeding pass has been reordered is a valley that still ticks, still closes its grams to the last bits of the adding, still fills up and levels off. It needs an instrument, and the instrument is a tape.

▣ Build · stage 1 — a tape: every tick of a run, folded into sixteen characters
// fold writes one tick of this world into the run's hash: the tick, every
// standing plant, every living creature in roster order and the five
// counters the pass keeps.
//
// The numbers go into one scratch buffer that is emptied and refilled
// rather than allocated, and the whole buffer is handed to the hash in
// one call. A tape that allocated a slice a tick would be the most
// expensive thing in the phase and would be measuring itself.
func (w *run) fold() {
	// The tick that has just run, which is one less than the tick the
	// valley is now standing at: terra.Valley.Tick calls the phase and
	// then moves the clock. Numbering the line for the phase it holds is
	// what lets a tape line and a line of the pool's log name the same
	// tick.
	now := w.v.Now - 1
	b := w.buf[:0]
	b = num(b, uint64(now))
	for _, st := range w.v.Stands {
		b = num(b, uint64(st.At.Y*w.v.Grid.W+st.At.X))
		b = num(b, math.Float64bits(st.Plant.Mass))
	}
	b = w.herd(b)
	b = num(b, uint64(w.r.Gone))
	b = num(b, uint64(w.r.Steps))
	b = num(b, uint64(w.p.Made))
	b = num(b, uint64(w.p.Draws()))
	w.buf = b
	w.h.Write(b)
	if w.Fine {
		w.line("tick %7d  alive %5d  born %6d  draws %13d  %s\n",
			now, len(w.r.Live), w.p.Made, w.p.Draws(), w.At())
	}
}

func body(b []byte, c *beast.Beast) []byte {
	b = num(b, math.Float64bits(c.Pos.X))
	b = num(b, math.Float64bits(c.Pos.Y))
	b = num(b, math.Float64bits(c.Face))
	b = num(b, math.Float64bits(c.Store))
	return num(b, math.Float64bits(c.Ate))
}

// num puts one number on the end of the scratch buffer, biggest byte
// first, so a tape written on one machine reads the same on another.
func num(b []byte, u uint64) []byte {
	return binary.BigEndian.AppendUint64(b, u)
}

// At is the sixteen characters this run has folded so far: every tick it
// has taken, in the order it took them.
func (w *run) At() string { return fmt.Sprintf("%x", w.h.Sum(nil)[:8]) }

The one call not printed there is herd, which puts every living creature into the buffer in roster order. It is three lines long, it is the most obvious code on this page, and it is the whole of the worked failure a few pages down.

Four decisions in the rest of it, and each of them is the difference between an instrument and a decoration. The hash is fed once and never reset, so the sixteen characters at year 200 depend on all 719,550 ticks and not on the last one. Creatures go in in roster order, which is an order the run already has. Every float goes in as the bits it actually is, through math.Float64bits, because printing a float to six places would hide exactly the last-bit disagreements a reordered sum produces. And the numbers go in biggest byte first, so the tape is a property of the run and not of the processor it ran on.

The scratch buffer is the small idea. w.buf[:0] keeps the array and throws away the length, so a tick of a valley with three hundred and thirty-six animals in it refills about eighteen kilobytes of memory the last tick already had. Doing this with a fresh slice would put an allocation on the hottest path in the program, and a measurement that slows the thing it measures is measuring something else.

With that, the rules stop being claims. Take one short run of the valley, four years of it, and change one thing about it at a time. Five of those changes are ones the rules above say cannot be noticed: writing the archive or not writing it, keeping the species register or not keeping it, and casting the fans on two, eight or sixteen goroutines instead of one. One of them is a rule broken on purpose, and it is the least suspicious-looking change in the list.

▣ Build · stage 2 — seven runs of one world, six of which have to agree
$ go run ./cmd/twice -mode holds -years 4
twice: 16x12 valley, 4 years, one change a row

  every row founds the same ground off seed 5, scatters the same herd on
  stream 12 and breeds it through the same pass; the digest folds every tick
  of the run, and draws is every number the pass took off streams 16 to 20

  the run, with                                the rules           digest        draws  the tape
  nothing changed: the run this volume ships    the same 88850053ac0a0767       916356   unmoved
  no archive written                            the same 88850053ac0a0767       916356   unmoved
  no species register kept                      the same 88850053ac0a0767       916356   unmoved
  the fans cast on 2 goroutines                 the same 88850053ac0a0767       916356   unmoved
  the fans cast on 8 goroutines                 the same 88850053ac0a0767       916356   unmoved
  the fans cast on 16 goroutines                the same 88850053ac0a0767       916356   unmoved
  the roster walked from the end                   moved 19229c17411233b9       182222     MOVED

  every row read what the rules say it must: five changes to how the run is
  written down or carried out, none of them visible in the tape, and one
  change to the order the pass walks the roster, which is a different world

The six agreeing rows carry three separate arguments. The archive spends no number off any stream, so a run that keeps a sixteen-megabyte history of itself and a run that keeps none are the same run. The species register spends none either, and on this ground the compatibility threshold never once refuses anybody, so sorting the valley into species changes who breeds with whom exactly nowhere. And the fan casting goes wide because a fan reads ground that cannot move inside a tick and writes into a slice belonging to one animal, so sixteen goroutines do the same work as one in whatever order they like and the digest cannot tell.

The last row is the one to sit with. Walking the roster from the end asks the same creatures, off the same streams, in the same fixed order inside each birth. It is not skipping anybody and it is not drawing anything extra. And it is a different world.

What the draws column misses

The draws column is the first instinct anybody has about a seeded system, and the table shows both what it is good for and where it stops. Six rows spent 916,356 numbers and the seventh spent 182,222, so on this particular run the column happens to shout. Look at what it is actually counting, though: 916,356 numbers over four years is the sum of what every ask cost, and an ask costs 509 numbers whatever happens. The column can tell you how many creatures were asked. It cannot tell you which creatures they were, or in what order, or which of them got the first number off the mate stream.

A run where the order moved and the number of asks happened to stay the same would leave that column unmoved, and there is one on the next page: on the tick these two worlds first part, both of them ask four creatures and both spend the same 2,036 numbers. A ledger of how much was drawn is a check on the draw counts, and the draw counts were never the thing in most danger. The tape is a check on the run.

The twin 200-year run

A four-year run is a rehearsal. The findings this volume is actually making came out of two centuries, and two centuries is where the ways of getting this wrong hide: a divergence that needs a hundred thousand asks to show up, a counter that goes round in year 140, a lineage that only drifts past the compatibility threshold late. So run the whole thing, and run it twice.

⚙ Tool — podman, and why a container belongs on this page

The volume's run script uses a version-tagged Go image: podman run --rm --network none -v "$PWD":/src:z -w /src docker.io/library/golang:1.26 go run ./cmd/twice -mode twice -years 200. For most chapters that is housekeeping. Here it is part of the argument. A seed fixes what the generators hand out; it fixes nothing about the compiler that turned this package into instructions, the standard library the hash and the sorting came from, or the version of Go whose map iteration the failure below depends on. golang:1.26 is mutable, so it does not pin those versions permanently. For a reference capture, resolve and record an image digest, select --platform linux/amd64, and record go version. Fixed arithmetic order is necessary here but does not establish floating-point bit equality across architectures or compiler versions. The original early-volume image digest was not recorded; the contract compatibility note distinguishes that missing provenance from the later digest-pinned stack. man podman-run for the flags, and --network none because a run that reaches the network is a run that depends on the weather somewhere else.

The two runs go side by side on two goroutines, and that is a claim as well as a convenience. Nothing in a run of this valley is shared with anything outside it: the ground, the herd, the pool, the five generators, the species register, the archive and the tape all hang off one value, and no package this volume touches keeps a variable anybody writes to. If that were false, two of them ticking at once would find out.

▣ Build · stage 3 — the pair, launched together and compared at the end
	names := []string{"twice-a", "twice-b"}[:runs]
	pair := make([]*run, len(names))
	var wg sync.WaitGroup
	for i, name := range names {
		at := w
		at.Name, at.Tape, at.Keep, at.Sort = name, true, true, true
		wg.Add(1)
		go func(i int, r run) { defer wg.Done(); pair[i] = r.live(years) }(i, at)
	}
	wg.Wait()

at := w is doing real work in there. run is a struct held by value, so each goroutine is handed its own copy of the settings and then fills in its own valley, roster, pool and hash on top of them, and no two of them share a pointer to anything. The two names are the other half: a run owns its files, and two runs writing to one tape would interleave their lines and produce a file that matched nothing. Every file this bench writes is named for the run that wrote it, and that is not tidiness. The gate that checks this book runs a whole volume's quoted commands in parallel in one working directory.

$ go run ./cmd/twice -mode twice -years 200 -every 20
twice: 16x12 valley, 200 years, run twice at once off seed 5

  each run founds its own ground, scatters its own herd on stream 12,
  writes a line a year to its own tape and every birth and death to its
  own archive; the two runs share no memory and never look at each other

                                            run a            run b
  creatures founded                            25               25
  born                                       1725             1725
  struck off                                 1414             1414
  still walking                               336              336
  species opened                                1                1
  creatures asked for a child              154473           154473
  numbers the pass spent                 79103308         79103308
  links added                                1879             1879
  nodes put in                               3126             3126
  grams minted into newborns         29693.758061     29693.758061
  genomes the pool holds                     1750             1750
  numbers in all of them                   294016           294016
  records archived                           3164             3164
  the whole run, folded          ad43e40c47815685 ad43e40c47815685

  the two tapes, 200 lines each: one line a year, the digest of every tick
  taken up to the end of it
    twice-a.tape                     20400 bytes  sha256 558dc98c09630cbf
    twice-b.tape                     20400 bytes  sha256 558dc98c09630cbf
    cmp                        IDENTICAL

  the two archives: every birth and every death, in the order they happened
    twice-a.jsonl                 16049646 bytes  sha256 577e17a1978bd5db
    twice-b.jsonl                 16049646 bytes  sha256 577e17a1978bd5db
    cmp                        IDENTICAL

  run a's tape, one line in every 20
    year    1  tick    4050  alive     9  born     14  gone     30  draws         26983  ea2c848aac459b99
    year   20  tick   72450  alive   333  born   1091  gone    783  draws      45659395  dd61100260b6d4af
    year   40  tick  144450  alive   333  born   1696  gone   1388  draws      78116885  5128c1329fdfadb2
    year   60  tick  216450  alive   336  born   1718  gone   1407  draws      79073574  402c538dea5f75b3
    year   80  tick  288450  alive   335  born   1718  gone   1408  draws      79073574  066bf69c18c063cf
    year  100  tick  360450  alive   336  born   1720  gone   1409  draws      79077164  a33cb7a5c6cfb947
    year  120  tick  432450  alive   337  born   1722  gone   1410  draws      79079210  a240911e74a57332
    year  140  tick  504450  alive   336  born   1724  gone   1413  draws      79099206  417e6fa040bcbf25
    year  160  tick  576450  alive   336  born   1724  gone   1413  draws      79099206  515773899455cb26
    year  180  tick  648450  alive   336  born   1724  gone   1413  draws      79099206  47055869977557e1
    year  200  tick  720450  alive   336  born   1725  gone   1414  draws      79103308  ad43e40c47815685

  719550 ticks of valley each, and the two of them ran side by side
  1439100 ticks in 7m51.721s, 3051 ticks a second (measured here; yours will differ)

Every column agrees, and the two lines under them are the claim this chapter exists to make. The tapes are twenty thousand four hundred bytes apiece and the same twenty thousand four hundred bytes. The archives are 16,049,646 bytes apiece, three thousand one hundred and sixty-four records of every birth and every death with the whole genome on each born record, and they are the same file. Two hundred years of a world where animals inherit, mutate, cross, grow connections and starve, run twice, and there is nothing anywhere in either of them to tell the two apart.

The tape excerpt says what the run did with the time. Nine animals at the end of the first year out of twenty-five stood up; 333 by the twentieth and never far from that again. The born column reaches 1,091 in the twentieth year, 1,696 in the fortieth and 1,725 in the two hundredth: the valley made nearly all the animals it was ever going to make in its first forty years and then made twenty-nine more in a hundred and sixty. Look at the draws column beside it and the reason is plain. It climbs to 78,116,885 by year 40 and finishes at 79,103,308, so the breeding pass is still asking, still spending its 509 numbers an ask, and still being told there is nowhere to put a child. Nothing has stopped happening. It has stopped succeeding.

Two things deserve a moment before moving on. The first is that this valley is not new. The speciation chapter walked out of the same two centuries with the same 25 founded, 1,725 born, 1,414 struck off, 336 walking and one species, and the archive chapter wrote the same run to a file of 16,049,646 bytes whose sha256 opens 577e17a1. Three benches, written on three different pages for three different arguments, agree with each other down to the sixteen characters at the end of a file. That is what a seed is for, and it is the last thing any of those three pages would have noticed on its own.

The second is the cost, because it is the reason this page can exist at all. The pair took seven minutes and fifty-two seconds here for 1,439,100 ticks of valley. The same bench with -runs 1 takes seven minutes and twenty-six on the same machine for half the ticks, and folds to the same ad43e40c47815685. Both of those are an eight-core Ryzen 7 3700X talking, and yours will differ, but the ratio is the point: the second valley goes on a core that was sitting idle and costs six per cent more wall clock than the first. Doing a thing twice so you can find out whether it means anything is usually sold as doubling the bill. Here it is a rounding error.

⚠ Worked failure — the instrument was the thing that moved

The first version of this tape did not fold creatures off the roster. It folded them out of a map from an identity to a creature, because that map was already sitting there: it is the obvious thing to build when what you want is to look an animal up by number, and once it exists, ranging over it is one line shorter than ranging over the roster and reading the identity off each body.

// herd puts every living creature into the tape: its identity and the
// five numbers a tick can move, in roster order, which is an order the
// run already keeps and never has to invent.
func (w *run) herd(b []byte) []byte {
	if w.Loose {
		return w.mapped(b)
	}
	for _, c := range w.r.Live {
		b = num(b, uint64(c.ID))
		b = body(b, c)
	}
	return b
}

// mapped is the worked failure: the same creatures taken out of a map
// built for convenience instead of off the roster. It is behind a flag
// so what it does can be run rather than described, and it is off in
// every run this bench ships.
func (w *run) mapped(b []byte) []byte {
	byID := make(map[sim.EntityID]*beast.Beast, len(w.r.Live))
	for _, c := range w.r.Live {
		byID[c.ID] = c
	}
	for id, c := range byID {
		b = num(b, uint64(id))
		b = body(b, c)
	}
	return b
}

The two loops put exactly the same creatures in with exactly the same numbers. Here is what one world folded both ways comes to, over five runs of it.

$ go run ./cmd/twice -mode loose -years 4 -times 5
twice: the same world folded two ways, 5 times over

  nothing about the valley changes between these rows: same ground, same
  herd off seed 5, same pass, same 4 years. The left column folds the
  tape off the roster, in roster order. The right column folds it off a
  map from an identity to a creature, built fresh every tick

     run folded off the roster       agrees off a map: agrees
       1     88850053ac0a0767            -              -
       2     88850053ac0a0767          yes             no
       3     88850053ac0a0767          yes             no
       4     88850053ac0a0767          yes             no
       5     88850053ac0a0767          yes             no

  5 runs of one world folded off the roster, 1 digest between them
  5 runs of the same world folded off a map, 5 digests between them

Start from the column that behaves strangely, because it is the one carrying the diagnosis. Five runs of one seed and five different answers, and a sixth run gives a sixth. An evolutionary run that had genuinely gone nondeterministic would not do that. A race between goroutines gives a handful of answers with one of them common; an uninitialised value gives you the same wrong answer most days; a run reading the clock gives you something that drifts with the time of day. Five for five, every time, is something that is being randomised on purpose.

And the other columns say where it is not. The left-hand fold of those same five runs agrees with itself, so the valleys are identical valleys: same births, same deaths, same stores, tick for tick. Nothing about the world moved. What moved is the order the instrument read the world in. Go randomises the starting point of every range over a map deliberately, so that nobody writes code that quietly depends on an order the language never promised, and this tape depended on it about two hundred times a second.

The repair is the three-line loop, and the rule under it is worth more than the repair: a check has to be at least as ordered as the thing it is checking. The roster is a list, and this run has been careful about its order since the first creature was stood up on it. The map was never ordered at all, and a fold over it was asking a question the run has no answer to.

First divergence tick

Now break one of them, on purpose, and go and find the damage. The rule to break is the one the last figure highlighted, because it is the one with the least defending it. No test asserts it and no assertion checks it: the whole of its enforcement is a sentence in a doc comment, the birth chapter's own, saying that the roster is walked once, in roster order, at most one child per parent per tick. The first clause and the last would break something a reader could see. The middle one would not.

▣ Build · stage 4 — the same pass, walked from the end
	// Backward is the breeding pass walking the roster from the end
	// instead of the beginning. It asks the same creatures, spends the
	// same numbers off the same streams and never once looks at a
	// creature it was not going to look at; all it changes is which of
	// them reaches the front of the queue. It is kept behind a flag so
	// what a reordered pass does to a run can be run instead of
	// described, and it is false in every pool this book ships.
	Backward bool

Three lines inside Breed read it, and the walk the birth chapter published is the same walk with k counting and i naming the creature.

	for k := 0; k < n; k++ {
		i := k
		if p.Backward {
			i = n - 1 - k
		}
		b := live[i]

Everything downstream of that line is untouched. The threshold is read first, so a creature that cannot pay still costs the pass nothing. The ground is asked before any generator is. The five draws happen in the order 18, 17, 16, 19, 20. The count of numbers an ask spends is the same count. This is a reordering and nothing else, of the kind that arrives in a commit called "iterate backwards to allow removal during the walk".

The hunt has two passes in it, and the two-pass structure is the content. A tape with a line a year is two hundred lines for two centuries, cheap enough to write on every run, and it narrows a divergence from seven hundred and twenty thousand ticks to three thousand six hundred. A tape with a line a tick names the tick and costs a file of seven hundred thousand lines, which is not something to leave switched on. So the coarse tape says how far you have to run, and then you run that far again with the fine one.

▣ Build · stage 5 — narrow to a year, then to a tick, then to the four asks on it
$ go run ./cmd/twice -mode hunt -years 4
twice: one ordering rule broken, and the tick the two runs part on

  16x12 valley, seed 5, 4 years, and one difference: run b's breeding
  pass walks the roster from the end instead of the beginning. It asks the
  same creatures, spends the same numbers off the same streams, and changes
  nothing but which of them is asked first

  pass one: a line a year
    the tapes agree on 0 lines and part on line 1
    a: year    1  tick    4050  alive     9  born     14  gone     30  draws         26983  ea2c848aac459b99
    b: year    1  tick    4050  alive    10  born     15  gone     30  draws         61080  3a9de92200f99a50
    so the difference is somewhere inside 3600 ticks, and a year tape
    cannot say where. Run both again with a line a tick

  pass two: a line a tick, over the 1 years up to it
    the tapes agree on 603 lines and part on line 604
    a: tick    1504  alive    22  born      1  draws          3563  8afe8f97266dee4e
    b: tick    1504  alive    21  born      0  draws          3563  d0eaf1ecdff69de8

  what the breeding pass did on tick 1504, in each run
  run     asked   parent   mate  child     grams   the price   the store
  a           1        2     23     26   40.0000    360.0000    360.0600  born
  a           2       19      0      0   40.0000    360.0000    360.0600  nowhere to put it
  a           3       22     23      0   40.0000    360.0000    360.0600  nowhere to put it
  a           4       23     22      0   40.0000    356.8231    360.0600  nowhere to put it
  b           1       23     22      0   40.0000    360.0000    360.0600  nowhere to put it
  b           2       22     23      0   40.0000    360.0000    360.0600  nowhere to put it
  b           3       19      2      0   40.0000    360.0000    360.0600  nowhere to put it
  b           4        2     19      0   40.0000    356.8231    360.0600  nowhere to put it

  and what the two worlds came to after 4 years
                                          a: in order  b: from the end
  born                                             74               83
  struck off                                       84               89
  still walking                                    15               19
  creatures asked for a child                    1800              358
  numbers the pass spent                       916356           182222
  species opened                                    1                1
  the whole run, folded              88850053ac0a0767 19229c17411233b9

Tick 1,504, and the six hundred and three ticks before it are identical in both worlds down to the last bit of every store. Both passes then ask exactly four creatures, and they are the same four: 2, 19, 22 and 23, the animals whose stores have just closed over 360.0600 with an open cell somewhere in reach. Both spend 2,036 numbers doing it, four asks at 509 apiece. The two blocks hold the same identities in opposite order and nothing else about them differs.

Read the price column down each block before anything else, because it settles what is going on. Ask one, ask two and ask three each describe a child costing exactly 360.0000, and ask four describes one costing 356.8231, in both runs. The price is a property of the place in the queue and not of the animal: the fourth ask of the tick takes the fourth block of numbers off the mutation stream wherever it happens to be standing, and that block moved one of the factors the price is worked out from far enough to take 3.1769 off it. In one run the animal holding the fourth place is creature 23. In the other it is creature 2.

Which leaves the one row in eight that says born. Nobody here fails to pay; every store covers every price. Seven of the eight children are refused because the two placement numbers named a cell with a body already on it, and the eighth is not. Creature 2 is asked first in the forward run, so it draws the first angle and the first distance of the tick, and from where it is standing that pair of numbers points at open ground. In the backward run those same two numbers go to creature 23, which is standing somewhere else, and they point at a cell that is taken. Creature 2 gets the fourth pair instead, and so does everybody else, and nothing is born at all. Look at the mate column on the way past: creature 2 is paired with 23 in one run and with 19 in the other, off one number indexed onto its list of eligible neighbours.

After that the two valleys are different places. By the end of the fourth year one has made 74 animals and the other 83, one is asking 1,800 creatures for children and the other 358, and there is no sense in which either is the correct answer. The seed is the same. The ground is the same. The rules of the world are the same to the decimal. What differs is which of four animals was reached first on one tick in the first year.

Four tests hold the two halves of that down, and they run in a tenth of a second on a plate of ground with twenty-four animals on it, which matters: a claim that needs eight minutes of valley to check is a claim nobody checks.

$ go test -count=1 ./internal/gene/ -run 'OneSeedFolds|WalkingTheRosterFromTheEnd|OneOrderedPhase|APoolCounts' -v
=== RUN   TestOneSeedFoldsToOneNumberHoweverOftenItIsRun
--- PASS: TestOneSeedFoldsToOneNumberHoweverOftenItIsRun (0.05s)
=== RUN   TestWalkingTheRosterFromTheEndIsAnotherWorld
--- PASS: TestWalkingTheRosterFromTheEndIsAnotherWorld (0.03s)
=== RUN   TestOneOrderedPhaseSpendsWhatAnyOtherOrderSpends
--- PASS: TestOneOrderedPhaseSpendsWhatAnyOtherOrderSpends (0.00s)
=== RUN   TestAPoolCountsEveryNumberItIsHolding
--- PASS: TestAPoolCountsEveryNumberItIsHolding (0.01s)
PASS
ok  	theworld/internal/gene	0.095s

The third of those is the one whose body matters. It runs a single phase forward and the same single phase from the end, off two identical plates, and then demands three things: that both spent the same numbers, that both asked the same count of creatures, and that the set of animals in one run's log is exactly the set in the other's. All three hold. The test that would catch the reordering is the first one, and it catches it by folding the world rather than by counting anything.

Hunting first divergence

Nothing above is about creatures, and the procedure is the same in any system where two runs are supposed to agree and do not.

Fold, do not print. Seven hundred thousand ticks of three hundred animals cannot be read. Sixteen characters can be compared by a test, on every commit, for nothing, and a fold that includes every tick answers "is this the same run" without anybody deciding in advance which part of the run to watch.

Keep a coarse tape always and a fine one on demand. A line a year is two hundred lines and costs nothing, and it converts "somewhere in two centuries" into "somewhere in this year". A line a tick is seven hundred thousand lines and answers the question, and it is affordable precisely because the coarse tape has already said how far to run. Two resolutions is the whole method, and it is the same one a bisect over commits uses.

Read the symptom's arithmetic before its content. Five runs, five answers, means something is being randomised on purpose. Two runs that agree with each other and disagree with a third mean two versions of something. Two runs that part on one tick and agree perfectly before it mean a single event, and the thing to do next is print that event and nothing else. The eight rows above are the whole diagnosis, and everything before them was narrowing.

An ordering rule needs a flag, not a comment. Every counterfactual in this volume is switchable, so a claim about what would happen otherwise is a run instead of a memory. That is the difference between "walking the roster backwards would give a different valley" and this page, which can say the tick.

Scaling ticks, memory and bytes

The last question a run of this size raises is what a bigger one would take, and it has three answers rather than one: the ticks, the memory, and the file. They do not scale the same way and only one of them is a fact about a machine.

So measure the scaling instead of guessing it. The same recipe goes on four grounds, the last of them ten times the first, all four founded off the same seed with a herd in proportion and run for four years apiece.

▣ Build · stage 6 — the same recipe on ten times the ground
$ go run ./cmd/twice -mode size -years 4
twice: the same recipe on four grounds, 4 years each

  every ground is founded off seed 5 and scattered with a herd in
  proportion to it on stream 12, bred through the same pass, sorted into
  species and archived. The last of the four is ten times the first

  16x12: 192 cells, 176 a creature can stand on, 25 founded
    74 born, 84 struck off, 15 walking, 123 plants standing at 6572.0 grams
    99 genomes held, 16546 numbers in them, 0.13 MB of genome at 8 bytes each
    183 records archived, 892439 bytes, 4876.7 bytes a record
  13950 ticks in 2.533s, 5508 ticks a second (measured here; yours will differ)

  32x12: 384 cells, 368 a creature can stand on, 56 founded
    199 born, 206 struck off, 49 walking, 284 plants standing at 16413.5 grams
    255 genomes held, 42600 numbers in them, 0.33 MB of genome at 8 bytes each
    461 records archived, 2291268 bytes, 4970.2 bytes a record
  13950 ticks in 5.047s, 2764 ticks a second (measured here; yours will differ)

  32x24: 768 cells, 752 a creature can stand on, 118 founded
    215 born, 289 struck off, 44 walking, 643 plants standing at 29804.2 grams
    333 genomes held, 55635 numbers in them, 0.42 MB of genome at 8 bytes each
    622 records archived, 2993028 bytes, 4811.9 bytes a record
  13950 ticks in 10.214s, 1366 ticks a second (measured here; yours will differ)

  80x24: 1920 cells, 1904 a creature can stand on, 303 founded
    774 born, 891 struck off, 186 walking, 1677 plants standing at 90803.8 grams
    1077 genomes held, 180068 numbers in them, 1.37 MB of genome at 8 bytes each
    1968 records archived, 9711770 bytes, 4934.8 bytes a record
  13950 ticks in 24.618s, 567 ticks a second (measured here; yours will differ)

The standable cells go 176, 368, 752 and 1,904, which is 1, 2.09, 4.27 and 10.82 times the first. Read the other columns against those four numbers. The ticks a second go 5,508, 2,764, 1,366 and 567, so a tick costs 1, 1.99, 4.03 and 9.71 times what it cost on the small ground: the price of a tick tracks the amount of ground within a few per cent the whole way up, because what a tick does is walk everything standing on it. The genomes held go 99, 255, 333 and 1,077 and the archive goes 892,439 bytes to 9,711,770, which is the same column twice over, since a record is written for every birth and every death and nothing else. Those two wander in the middle of the table, because four years is not long enough for four grounds of different sizes to fill at the same rate, and they arrive at the far end at 10.88 times the first against 10.82 times the ground.

Memory here is counted and not measured, which is the only way it can be quoted at all. The pool holds every genome the run has ever made, a genome is a known count of numbers, and eight bytes a number is arithmetic anybody can check on any machine. A reading of the heap would be a fact about this collector on this afternoon, and it would not be the same twice.

∑ Math Interlude — a run ten times the size, in ticks, memory and bytes

Numbers first, and all of them are on this page already. Two centuries of the small valley: 719,550 ticks, 336 animals still walking, 1,750 genomes in the pool holding 294,016 numbers between them, and an archive of 3,164 records in 16,049,646 bytes. The pair of them took seven minutes and fifty-two seconds here.

Now ten times the ground. That is 1,920 cells against 192, of which 1,904 carry a creature against 176, so 10.8 times the standable ground. The room rule has not changed and nothing in it counts animals: a cell of ground carries one body, births are refused when there is nowhere to put them, and the population walks to whatever number that produces. So 336 becomes 336 × 10.8, which is about 3,600 animals.

The three answers are then three multiplications, each with its own measured factor. Ticks: 9.7 times as dear a tick, so seven minutes fifty-two becomes 7.87 × 9.7 = 76 minutes for the pair. Genome memory: 10.9 times as many genomes, so 294,016 numbers becomes about 3.2 million, which at eight bytes each is about 24 megabytes. Archive: 10.9 times as many records, so 3,164 becomes about 34,000, and at the 5,073 bytes a record this run averaged that is about 165 megabytes.

N ≈ 1.9 × A, animals standing on A cells of usable ground

t = T ÷ r, and r falls in proportion to A

bytes = R × c, records times what a record costs

Acells of ground a creature can stand on: 176 in this valley, 1,904 in one ten times the size
Nanimals standing once the room rule has settled: 336 here, about 1.9 to a cell
Tticks a run covers: 719,550 for two centuries, and the same on any ground
rticks a second, the only figure here that belongs to a machine: 3,051 for the pair on this one
thow long the run takes, which is T divided by r
Rrecords the archive ends with: one a birth, one a death, 3,164 here
cbytes a record costs, nearly all of it the wiring: 5,073 on average in this run

Two things that arithmetic does not cover, and both of them bite on a longer run rather than a wider one. The archive and the pool grow with every creature that has ever lived, not with the ones alive, so doubling the length of a run doubles both while the population sits still. And c is not a constant: a record carries the whole wiring, and a wiring grows a link or a node every time a birth's four numbers say so. Over these two centuries the average genome came to 168 genes against a founder's 167, because a wiring that grows has to survive to be inherited and almost none of them do. A run whose lineages stayed alive longer would pay more per record every year it ran.

Why run bytes are the result

Everything on this page comes back to one asymmetry. A simulation hands you a number, and the number is worth exactly as much as your ability to produce it again. Not because anybody doubts you: because a number you can produce again is a number you can vary. Change the room rule and re-run and the difference is the rule's doing. Change nothing and re-run and the difference is a bug in your bookkeeping. Without the second half, the first half is guesswork with decimal places on it.

The rules that buy it are small and they are all of the same kind: refuse to let an outcome decide how much work gets done. Draw the same count of numbers whether the birth happens or not. Ask the cheap question before the generator so a creature that cannot breed costs nothing at all. Take a choice with a multiply and a floor, never with a function that redraws when it dislikes the first answer. Add a node's inputs in an order somebody wrote down. Walk the roster the way the roster is ordered. None of them is clever, none costs anything, and every one of them is easy to undo by accident while tidying up, which is what the tape is for.

One clause of that carries further than the rest, and it is the one the failure box paid for: hold the instrument to a higher standard than the thing it measures. A nondeterministic check pointed at a deterministic world reports its own defect in the world's name, and it is convincing while it does it.

✓ Checkpoint — a tape, a divergence and a run that fits
  • Given a run that will not reproduce, You can name the three kinds of bookkeeping to suspect, and say which of them a count of numbers drawn will never catch.
  • You can write a tape for a simulation: what goes into the fold, in what order, why a float goes in as its bits, and why the creatures come off a list and not off a map.
  • Shown five runs of one seed giving five different digests, You can say what that rules out, and tell it apart from what a race between goroutines or two versions of a library would produce.
  • You can narrow a divergence in a seven-hundred-thousand-tick run down to one tick without recording every tick of it, and say what each of the two tapes costs and buys.
  • Reading the eight asks on the tick two runs part on, You can explain why the fourth ask describes a child costing 356.8231 in both of them when the fourth animal is a different animal in each.
  • Given one measured run and a ground ten times the size, You can work out the ticks, the genome memory and the archive bytes, and say which of those three is the only one that belongs to a machine.
⚡ Exercises — try first, then reveal
Exercise 1 — is it the two goroutines that make them agree? The pair runs side by side, so a suspicious reader might wonder whether the two runs are agreeing because something is shared between them. Predict what one run alone folds to, then check with go run ./cmd/twice -mode twice -years 4 -runs 1 against go run ./cmd/twice -mode twice -years 4.

One run alone makes 74 animals, leaves 15 walking and folds to 88850053ac0a0767, which is what each of the pair folds to and what the unchanged row of the seven-run table folds to. Sharing would show up as agreement that disappears when the runs are separated, and this is the opposite: the digest is the same whether the valley is ticked beside another one or on its own.

It is a cheap check and it is the right instinct. Two runs in one process can agree for a bad reason, and the way to find out is to take the process apart. The stronger version of the same check uses a clean container with the same recorded toolchain, image content and platform. Compare its first-year digest with ea2c848aac459b99; a mutable tag alone does not establish those reference conditions.

Exercise 2 — is the table a fact about seed 5? Six rows agreed and one moved. Predict whether that pattern is a property of this seed or of the rules, then run go run ./cmd/twice -mode holds -years 4 -seed 7.

The pattern holds and every number in it changes. Seed 7 folds to 9da8f7dbc6f142b5 across all six rows that must agree, and the pass spends 274,381 numbers instead of 916,356: a valley that asks a third as many creatures for children over the same four years. The backward row moves as before, to c67b34d1891e8d5b on 35,630 numbers.

That is the distinction the whole page rests on. The digest is a fact about one seed and is meant to be. Which changes move it is a fact about the rules, and has to be hold across seeds under the declared reference conditions. Testing seed 7 widens the evidence beyond seed 5; neither example proves every possible seed or cross-platform floating-point replay.

Exercise 3 — the portrait, twice. The valley is not the only thing in this volume with a run behind it. Write the appearance bench's lineage to two differently named archives with go run ./cmd/looks -mode draw -limb 200 -roll draw-a.jsonl and again with -roll draw-b.jsonl, then cmp them.

cmp draw-a.jsonl draw-b.jsonl says nothing, which is cmp saying the two files are the same 9,576,460 bytes: a thousand and one births down one branching line, every wiring, every innovation number and every look gene in the same order. The card hash printed at the end of both runs is 48416baa1f0410a9, and the four tips are the same four animals with the same coats.

Read the bytes a record while you are here, because they say something the valley cannot. Those thousand and one records average 9,567 bytes against the 5,073 of the two-century valley, and the difference is entirely wiring: a bench lineage breeds every genome it makes, so its controllers grow for a thousand generations, while almost every wiring the valley grows dies before it can be inherited.

So the volume closes with a valley somebody else can run. Twenty-five animals stood up on sixteen by twelve cells of ground, each with a store of two hundred and its ten body factors all at 1.00, and two hundred years later three hundred and thirty-six are walking about on it with no two of them the same numbers: bodies their parents' arithmetic priced, wirings that can grow a connection to a sense every ancestor was deaf to, three genes nothing has ever read, four more that decide a coat. Nothing in those two centuries said what a good animal was. Nothing compared two creatures except to ask whether one was near enough and like enough to be a parent. And the whole of it comes back from a seed and a bench, byte for byte, in eight minutes.

What it cannot do is the thing a tape makes impossible to look away from. One species opened in the first year and one species was standing at the end. The distance, the threshold and the register are built, tested and shown splitting a line on a bench, and the valley never came near them: sixteen cells of ground with a six-cell mate box on it is one neighbourhood, and 1,725 births spread over two centuries put the deepest line fifty generations from a founder where the bench that did split needed two thousand births of one line. So two hundred years of this world, run twice, is one experiment measured twice over, and not two experiments to set against each other.