The World Vol 5 · Bodies and Brains
ch 50 / 105
Chapter 50

What the Body Leaves

The death line in the roster

A creature can see, choose and pay, and every tape still ends with the animal standing there. Even a store that has been below zero for two hundred ticks keeps being charged.

A creature whose store reaches nothing when its tick closes is struck off the roster at the end of the phase, never in the middle of it, and every gram of its body goes onto the cell it was standing on as litter. The pile rots through the same bed call the plants have used since winter entered the valley.

The timing matters. Clamping the store at zero forgives a bill, so the arithmetic leaves the store under zero and marks the body dead. Removing the body in the middle of the phase would change which creature gets the next turn and which index the loop reads next.

The grams matter too. A browser is forty grams of body. If it vanishes, forty grams leave the world without a line in the books. If it stays in the roster after death, the valley is holding tissue that should be rotting.

The roster and the valley tick are the two missing pieces. The roster owns identities, order and running totals; the tick gives the carcass a place in the same schedule as plant litter. The nutrient books then expose the second half of the design: a creature has grams to return, but no mineral account of its own.

The roster list and tick hook

Start with the list, because everything else hangs off it. It holds the creatures in the order they are stepped, hands out the identities the log names them by, and keeps the running totals that a dead creature would otherwise take with it when it goes.

▣ Build · stage 1 — the roster, and the numbers it keeps
// internal/beast/roster.go

// Roster is every creature the valley is running, held in one place
// and stepped in one order. Live is that list and its order is the
// stepping order: creatures are added in founding order and never
// re-sorted, so the sequence in which three animals reach the same
// plant is a fact about the run.
//
// The five totals are the roster's half of the valley's books: three
// in grams and two counts. They are kept here and not on the creatures
// because a dead creature leaves the list, and a number that leaves
// with it is a number that stops being in anybody's books.
type Roster struct {
	Live []*Beast     // the creatures, in the order they are stepped
	Next sim.EntityID // the next identity nobody has ever carried

	Stood float64 // grams of body every creature ever put on this roster was stood up with
	Ate   float64 // grams this roster has taken off standing plants
	Fell  float64 // grams of carcass this roster has handed to the litter
	Gone  int     // creatures struck off
	Steps int     // creature-ticks this roster has actually handed out

	eyes []Ray  // one fan, read into once per creature per tick
	row  Senses // one sensor row, filled once per creature per tick
}

// NewRoster opens an empty one. Identities start at 1, because 0 is the
// value a creature carries before anything has named it and Tag reads
// it as unclaimed.
func NewRoster() *Roster {
	return &Roster{Next: 1, eyes: Eyes()}
}

// Add puts one creature on the roster, hands it the next identity, and
// charges its body to the opening stock. Those grams were never
// manufactured out of light by anything in this valley: a founding
// creature is opening stock exactly as a founding plant is, and the
// books have to say so before the run starts rather than discover it
// afterwards.
func (r *Roster) Add(b *Beast) {
	if b.ID == 0 {
		b.ID = r.Next
		r.Next++
	}
	r.Stood += b.Kind.Bulk
	r.Live = append(r.Live, b)
}

// Walking is the grams standing in living creature bodies right now. A
// browser's body does not change mass: what a mouthful buys is energy
// in the store, and the store is not made of grams. So this is the
// count times the row's bulk, and it goes down in whole bodies.
func (r *Roster) Walking() float64 {
	t := 0.0
	for _, b := range r.Live {
		t += b.Kind.Bulk
	}
	return t
}

Ate and Fell sit on the roster and not on the creature, and that placement is the whole reason the roster keeps books at all. Every creature already counts the grams it has taken off the valley. The moment it is struck off the list, that count goes out of scope with it, and the valley's total silently drops by whatever the dead animal had eaten in its life. A total that has to survive the thing it is counting belongs to whatever outlives it.

Stood is the same argument pointed the other way. A creature is put in the valley by a bench with a body it did not grow, exactly as a founding plant is stood up holding tissue no leaf ever fixed. The terrarium already has a word for that, Opened, and it counts it as stock the valley began with. A founding population of creatures is more of the same, so it is counted the same, on the tick they arrive, long before anybody notices the sums are out.

Now the tick. The creature phase has to run at one particular point in it, and the point is not a matter of taste. A creature grazes tissue, so it has to come after the plants have grown this tick's grams, or a mouth is always eating yesterday. A carcass lands in the litter, so it has to come before the weather works on the ground, or a body that died this morning sits untouched until tomorrow while a plant that died beside it is already rotting. There is exactly one gap that satisfies both, and terra gets one new field to mark it.

▣ Build · stage 2 — one field on the valley, and the closure that fills it
// internal/terra/valley.go, inside type Valley

	// Phase is the one seam this valley leaves for whatever lives in
	// it. It is called once a tick, after the plants have eaten and
	// before the weather works on the ground, and terra neither knows
	// nor cares what registers itself here. A valley with nothing
	// walking about in it leaves it nil, and a nil hook is not a
	// branch anything can see from outside: the run it produces is the
	// run the terrarium produced before this field existed.
	Phase func()
// internal/terra/valley.go, inside func (v *Valley) Tick

	v.Stands = live

	// Whatever lives in this valley gets the tick here: after every
	// plant has eaten, grown, seeded and been buried, and before the
	// rain, the sun and the rotting touch the ground. A creature that
	// grazes on this line takes tissue that grew a few statements ago,
	// and anything it drops on the ground is lying there in time for
	// the rotting at the bottom of this same tick.
	if v.Phase != nil {
		v.Phase()
	}

	v.Bed.Shower(v.Fall*wet, v.Full)
// internal/beast/roster.go, continued

// Hook is the roster wrapped up as the one function terra.Valley.Phase
// takes: a closure over this roster and this valley, holding the scale
// the sensor row is divided by. Registering it is the whole of wiring
// creatures into the tick.
//
// Deaths and refusals go to the caller through the two functions,
// because terra's hook hands nothing back and this package has no log
// of its own. Either may be nil in a run that does not want them.
func (r *Roster) Hook(v *terra.Valley, sc Scale, buried func(Carcass), no func(error)) func() {
	return func() {
		died, refused := r.Phase(v, sc)
		if buried != nil {
			for _, c := range died {
				buried(c)
			}
		}
		if no != nil {
			for _, err := range refused {
				no(err)
			}
		}
	}
}

A function field and a nil check is the smallest thing that could work here, and small matters more than usual, because terra is the package this whole world's arithmetic has been settled in. It learns nothing. It does not import beast, has no idea a creature exists, and cannot tell whether the thing it just called ate a plant or printed a line. Everything specific lives in the closure the other package builds, which is why the hook takes no arguments and returns nothing: anything either side needs, the closure already has.

The nil check is the other half. A valley with nobody in it takes a branch that does nothing, and doing nothing changes no float in the world, so a terrarium run with this field present has to be bit for bit the terrarium run without it. That is a claim, and it is cheap to check.

$ go run ./cmd/books -mode quiet -years 12 -herd 4 -store 400
books: seed 5, 12 years, the valley the terrarium closed on
       brake 1, creep 0.0010, rim walled and cracked

                                                          world           census
  terra.Valley.Phase is nil                    54a0214c09b3d357 bfb496d523badb49
  an empty roster registered into it           54a0214c09b3d357 bfb496d523badb49
  4 creatures on that roster                   9814edfd97afddc3 c41d9b7f35aadab3

  the first two lines agree, so a hook nothing has registered anything into
  costs the terrarium nothing: an empty valley runs the run it always ran
  the third does not agree, and it is not meant to: bites and carcasses reach the ground

Twelve years is enough to prove the hook is inert and nothing like enough to prove the valley is unmoved, so the same comparison is run out to the length the terrarium closed its own books on: a thousand years, three million six hundred thousand ticks, every one of them calling a creature phase that has nobody on it.

$ go run ./cmd/books -mode keep -years 1000
books: seed 5, 1000 years, an empty roster hooked into every tick

  world    df1c117e69bdf157   the terrarium's own, unmoved
  census   75c77a67f6f430bb   the terrarium's own, unmoved

Both digests are the ones the valley closed on before any of this existed: the world digest over the bed's two numbers on every cell and every plant's cell and mass, and the census digest folded over all thousand midsummers. The third line of the twelve-year run is the interesting one in the other direction. Put four creatures on that roster and the digests move, and they are supposed to. Creatures eat plants and drop bodies on the ground; a valley that ran identically with animals in it would be a valley where the animals were decoration.

The store reaches zero

The phase itself is a loop with two halves, and the line between them is the design. The first half steps every creature. The second half deals with the ones that stopped.

One field goes on the creature first. The phase has to ask each animal what it wants, and the answer comes from the seam the action chapter left: twenty-four numbers in, one of six out. Two creatures standing side by side may be driven by two different things, so the answer to "what drives this one" belongs on the body and not on the loop that walks it.

▣ Build · stage 3 — the phase, and the list it fills as it goes
// internal/beast/body.go, inside type Beast

	// Mind is whatever answers for this creature when the phase asks
	// it what it wants. It is a field on the body and not an argument
	// to the phase because two creatures standing side by side may be
	// driven by two different things, and the roster that steps them
	// has no business knowing which is which.
	Mind Mind
// internal/beast/roster.go, continued

// Carcass is one death, written down at the moment the store went
// under: who it was, the cell it was standing on, and the grams of body
// that are about to become litter. It is a record and not a request,
// which matters because it is made in the middle of the phase and acted
// on at the end of it.
type Carcass struct {
	Who   sim.EntityID
	Name  string
	At    sim.Coord
	Grams float64
	Tick  int
}

// Phase is one creature phase: the whole roster stepped once, in
// order, and then the dead buried.
//
// Every creature is handed the same View, built once before the first
// of them moves, so all of them read the world as it stood when the
// phase opened. Each one looks, fills the row, is asked what it wants
// by whatever is driving it, and does it. Nothing in the loop touches
// anything but the creature whose turn it is.
//
// A creature whose store is at nothing when its tick closes is written
// into died and left exactly where it is. It is not removed here, and
// the reason is that removing it here would change the world underneath
// the creatures that have not been stepped yet: the View they are all
// sharing indexes it as an occupant of its cell, so striking it off in
// the middle would leave the index describing a valley that no longer
// exists, and a creature stepped ninth would see something a creature
// stepped first did not. The list is edited once, at the end, when
// nobody is reading it.
func (r *Roster) Phase(v *terra.Valley, sc Scale) (died []Carcass, refused []error) {
	w := NewView(v, r.Live)
	for _, b := range r.Live {
		b.Look(w, r.eyes)
		b.Read(&r.row, r.eyes, w, sc)

		a := Rest
		if b.Mind != nil {
			a = b.Mind.Pick(&r.row)
		}
		t, err := b.Do(a, w)
		if err != nil {
			refused = append(refused, err)
		}
		r.Ate += t.Grams
		r.Steps++

		if t.Left <= 0 {
			b.Dead = true
			died = append(died, Carcass{Who: b.ID, Name: b.Name, At: b.Cell(),
				Grams: b.Kind.Bulk, Tick: v.Now})
		}
	}
	if len(died) > 0 {
		r.bury(v, died)
	}
	return died, refused
}

The View is the load-bearing detail in that comment. It is an index of what is standing on which cell, built once, and every creature in the phase reads the same one. Take a creature off the roster in the middle of the loop and the index still has it standing there, so a creature stepped ninth casts a ray at an animal that was removed four creatures ago. Leaving the dead where they are until the loop is over is what keeps the index honest for the whole of it.

The death test reads t.Left, which is the number the tally recorded when that tick's last charge had gone through. There are two ledgers on a creature in this package and only one of them is on this path. The still-life one, Ledger, belongs to the method that charges a body against a single plant with no actions and no movement in it; the phase never calls that method, so its closing figure is never filled in and a test written against it would be a test of a number nothing wrote. Do charges through Step and reports through Tally, so Tally is where the store's last word for the tick is.

And the creature is left exactly where it is. It is marked, it goes on a list, and the loop carries on to the next one. Nothing is removed, dropped or moved while the loop is running.

The second half is four lines of doing and one paragraph of deciding. The doing is easy: drop the grams and rebuild the list. The deciding is what a carcass is worth to the ground it lands on.

▣ Build · stage 4 — the burial, and the number that is deliberately zero
// internal/beast/roster.go, continued

// bury is the end of the phase. Every carcass of this tick goes onto
// the cell its creature was standing on, as a Pile, through the same
// terra.Bed.Fall a plant's dead tissue goes through; then the roster is
// rebuilt without the dead, in place, keeping the order of everything
// that is still walking.
//
// A carcass carries grams and no nutrient, and that is a decision
// rather than an omission. The nutrient number on a Pile is what the
// dead thing borrowed out of the bed to build itself: a plant is
// charged its Holds() the day it germinates and hands the same figure
// back the day it stops, which is why the second column closes. A
// browser never borrowed. Nothing about it is ever charged against a
// cell's nutrient, and every gram it added to itself came off a plant's
// standing mass and was spent as energy. The minerals in those grams
// went back into the ground on the tick the bite was taken, so by the
// time a carcass lands there is nothing left owing on it. Writing a
// positive nutrient figure onto it would hand the soil units nobody
// ever took out of it, which is manufacturing, and this valley does not
// manufacture.
func (r *Roster) bury(v *terra.Valley, died []Carcass) {
	for _, c := range died {
		v.Bed.Fall(c.At, terra.Pile{Mass: c.Grams})
		r.Fell += c.Grams
		r.Gone++
	}
	live := r.Live[:0]
	for _, b := range r.Live {
		if !b.Dead {
			live = append(live, b)
		}
	}
	for i := len(live); i < len(r.Live); i++ {
		r.Live[i] = nil
	}
	r.Live = live
}

A terra.Pile holds two numbers, grams and nutrient, and they are counted separately because they leave separately: the grams go off as the rotting burns them and the nutrient goes down into the cell underneath. A dead plant fills in both. Pile{Mass: c.Grams} fills in one, and leaves the other at nothing on purpose.

The argument is about borrowing. The nutrient figure on a plant's pile is what that plant took out of the bed to build itself with: the terrarium charges a seedling's nutrient against the ground the day it germinates, and hands the identical figure back to the litter the day it stops standing. It is a loan and a repayment, and that is the reason the nutrient column closes at all. A browser never borrowed. Nothing about a creature is ever charged against a cell's nutrient, not when it is stood up and not when it eats; its opening forty grams are stock the run began with, and every gram it puts inside itself afterwards comes off a plant's standing mass and is spent as energy. The minerals that came off with those grams were handed back to the ground on the tick of the bite, by the line in Graze that does nothing else, so a carcass arrives with nothing owing on it. Writing a positive nutrient figure onto its carcass would hand the soil units nobody ever took out of it. That is manufacturing, and the rule this whole volume is written to says the valley does not manufacture.

Which is also the reason beast.Kind does not grow a Hunger column to hold the conversion. There is no conversion to hold. A row grows a column when two creatures would need different values in it, and a second animal that really did draw nutrient out of the ground would need one; the browser needs a zero, and a zero that follows from the design does not need a field to say it.

One creature, on ground with nothing growing on it, resting every tick so that the only thing charging the store is the body itself. The row says how long that lasts before the run starts.

$ go run ./cmd/books -mode clock -found 0 -ticks 60 -every 10
books: 12x8 valley, tick 901, year 1 summer, 0 plants standing at 0.0 grams

  creature 1 stood on 9,6 with 8.0000 in the store, resting every tick
  a resting body earns nothing and is charged 0.1600 a tick, so the row says
  the store is gone after 8.0000 / 0.1600 = 50.0 ticks
  the valley was founded with no plants, so every gram of litter in it
  is this creature

   tick      store    walking   roster       litter       rotted
     10     6.4000    40.0000        1       0.0000       0.0000
     20     4.8000    40.0000        1       0.0000       0.0000
     30     3.2000    40.0000        1       0.0000       0.0000
     40     1.6000    40.0000        1       0.0000       0.0000
     50    -0.0000     0.0000        0      39.6468       0.3532
     60    -0.0000     0.0000        0      36.2706       3.7294

  creature 1 stopped on the phase of tick 950, standing on 9,6
  40.0000 grams of body went to terra.Bed.Fall as a Pile on that cell, the same
  call a dead plant's tissue goes through, and terra.Bed.Rot works on it at
  the valley's own 0.0100 a tick times the warmth, the rate the plants rot at
  the roster handed out 50 creature-ticks and is holding 0 creatures
  handed to the litter 40.0000 grams, still lying 36.2706, rotted away 3.7294,
  and those last two come to 40.0000

Fifty ticks, named in advance by dividing a store by a bill, and the store lands on -0.0000. That is a negative zero, which is what a float64 prints when a subtraction takes it a hair under and the hair is smaller than four decimal places can show. The test in the phase is t.Left <= 0, and a hair under nothing is under nothing, so the creature stops on the tick the arithmetic named rather than buying one more.

Watch the walking and litter columns swap on that line. Forty grams leave the roster and 39.6468 arrive in the litter, and the missing 0.3532 is not missing: it is in the rotted column, on the same row. The carcass fell before the weather ran, so the rotting at the bottom of that same tick took its first share of it immediately, exactly as it would have from a plant that died on the same tick. Ten ticks later 3.7294 grams have burned off and 36.2706 are still lying there, and the two of them add back to 40.0000. That is what the placement of one line in terra.Valley.Tick bought.

∑ Math Interlude — two totals that have to be the same number

An audit of a closed world is one subtraction. Add up everything that ever went in, add up every place a gram can be now, and take one from the other. If the answer is not nothing, some line is missing.

Three things go in. The valley was founded with plants standing in it, which for the run at the end of this chapter comes to 11.250000 grams. Its leaves manufactured 43,613.746056 grams out of light over two years. And twelve creatures were stood up at 40 grams a body, which is 480.000000. Those three add to 44,104.996056 grams, and nothing else has ever entered.

Nine places a gram can be. Standing in a living plant, 2,361.841868. Walking about in a living body, 0.000000, because none of the twelve is left. Flying as a seed, 0.000000. Waiting in the seed bank, 286.000000. Lying in the litter, 1.057533. Burned as plant upkeep, 38,432.484261. Rotted off the litter, 659.660979. Blown over the rim, 77.000000. And eaten, 2,286.951415, which is grams a mouth took off a stand and a store spent as energy. Those nine add to 44,104.996056 as well, and the subtraction leaves 0.000000.

To the last bit it leaves −7.421e−10 instead of exactly nothing, and that residue is the arithmetic and not the model. Forty-four thousand grams accumulated over six thousand seven hundred and fifty ticks of adding tenths and hundredths to a float64 cannot land on a round number, and a difference of seven ten-thousand-millionths on a total of forty-four thousand is fourteen significant figures of agreement. A ledger that came out at exactly 0 would mean somebody was rounding.

in = O + B + S
out = p + c + a + k + l + u + r + w + e
in − out = 0

Ograms the valley was founded with, standing in plants nothing grew; 11.250000
Bgrams ever manufactured out of light; 43,613.746056
Sgrams of creature body the run was stood up with; 480.000000
pstanding in living plant tissue now
cwalking about in living creature bodies now
aflying, as seed still in the air
kwaiting, as seed buried in the ground
llying in the litter, plants and carcasses together
uburned by plants as the upkeep of standing there
rrotted off the litter and gone
wblown over the rim and out of the valley
eeaten: taken off a stand by a mouth and spent as energy

Twelve dead browsers

One creature dying says nothing about the order deaths are applied in, because with one creature there is no order. Twelve of them with identical stores and identical bills all run out on the same tick, and that is the case the rule was written for.

$ go run ./cmd/books -mode phase -herd 12 -ticks 55
books: 12x8 valley, tick 901, year 1 summer, 12 plants standing at 1517.5 grams

  12 creatures on stream 12, every one of them resting with 8.0000 in the store
  a rest costs nothing and the body costs 0.1600, so every one of them
  runs out on the same tick: 50.0
  deaths are applied at the end of the phase, when nobody is reading the roster

   tick   roster  stepped    walking in the litter
     10       12       12   480.0000       0.0000
     20       12       12   480.0000       0.0000
     30       12       12   480.0000       0.0000
     40       12       12   480.0000       0.0000
     50        0       12     0.0000     475.7615
     55        0        0     0.0000     455.0853

  12 creatures struck off, 480.0000 grams of carcass handed to the litter
  the roster handed out 600 creature-ticks over 55 ticks

The row for tick 50 is the whole rule in its middle two columns. The roster is empty when the tick ends, and the phase inside that tick handed a tick to twelve creatures. Both are true at once, and they can only both be true if the list was edited after the loop had finished with it. Six hundred creature-ticks over fifty-five ticks is twelve of them for fifty ticks and none for the five after, which is the same fact counted from the other end.

The litter stops short of 480, at 475.7615, and that is the rotting again, taking its share of twelve piles on the tick they landed. Five ticks later it is down to 455.0853 and the valley is quietly turning twelve browsers back into soil.

⚠ Worked failure — burying them as they fall

Collecting the dead into a list and dealing with them afterwards looks like ceremony. The obvious version does the work where the work is discovered: the store goes under, drop the grams, take the creature off the list, carry on. Nothing has to be remembered between the discovery and the doing, and no second list of anything exists at any point.

// internal/beast/roster.go, inside Phase, with Hasty set

		if t.Left <= 0 {
			b.Dead = true
			c := Carcass{Who: b.ID, Name: b.Name, At: b.Cell(),
				Grams: b.Kind.Bulk, Tick: v.Now}
			died = append(died, c)
			if r.Hasty {
				r.bury(v, died[len(died)-1:])
			}
		}

The flag sits on the roster beside the totals and is false in every roster this book ships, so the failure can be run instead of described. Same twelve creatures, same stores, same tick.

$ go run ./cmd/books -mode phase -herd 12 -ticks 55 -hasty
books: 12x8 valley, tick 901, year 1 summer, 12 plants standing at 1517.5 grams

  12 creatures on stream 12, every one of them resting with 8.0000 in the store
  a rest costs nothing and the body costs 0.1600, so every one of them
  runs out on the same tick: 50.0
  deaths are applied the instant the store goes under, in the middle of the phase

   tick   roster  stepped    walking in the litter
     10       12       12   480.0000       0.0000
     20       12       12   480.0000       0.0000
     30       12       12   480.0000       0.0000
     40       12       12   480.0000       0.0000

  the tick loop stopped on tick 50 and the run went no further
  panic: runtime error: invalid memory address or nil pointer dereference
  12 creatures were on the roster when that phase opened; it gave a tick to
  6 of them and then reached a slot the burial had already blanked, leaving
  6 creatures standing that nothing has asked anything of

Forty-nine ticks of a table that reads exactly like the good one, then a nil pointer. Reason it out from the symptom. The panic is a nil *Beast, and there is only one place in this package that ever writes a nil into that slice: the loop at the bottom of bury that blanks the tail after compacting. So the burial and the walk are looking at the same array at the same time, and the count in the last line says how the collision goes. Six is half of twelve, and half is not a coincidence. Every iteration buries one creature, which shortens the live part of the array by one and blanks one more slot from the end; meanwhile the loop index moves up by one. The two meet in the middle, at index six of twelve.

The compaction is the part that makes it a nil and not merely wrong. live := r.Live[:0] gives a slice that shares its backing array with the one the range is walking, so appending survivors into it overwrites the very entries the loop has not reached yet. Six of the twelve get shifted down past the index the loop is at, and are never asked what they want to do. They are not dead, they are not stepped, and if the walk had run out of creatures before it ran out of blanks they would have gone on standing there for the rest of the run, paying nothing and eating nothing, and no column anywhere would have said so.

The general rule is older than this valley and has nothing to do with animals. Do not edit a collection while something is iterating it. Go will not stop you, because a slice is a window onto memory and both the walk and the edit are perfectly legal operations on that memory. What saves you is putting the edits somewhere until the walk is over, which is what the died slice is. It exists so that the answer to "what changed during this phase" is computed during the phase and applied after it, and the phase itself only ever reads.

Why the audit has to close

Let the twelve loose on the valley properly this time, with full stores and the rule that hunts plants, and let the year run over them.

$ go run ./cmd/books -mode run -herd 12 -store 400 -years 2
books: 12x8 valley, tick 901, year 1 summer, 12 plants standing at 1517.5 grams

  12 creatures on stream 12, 400.0000 in every store, each one driven by
  the rule that turns to the nearest plant ray, walks it down and bites
  the creature phase is registered into terra.Valley.Phase and runs once a
  tick, after the plants have eaten and before the rain reaches the ground

    tick   season  alive      eaten    carcass   standing       litter
    1351   summer     12   581.1966     0.0000     188.24       0.3807
    2251   autumn     12  1872.5646     0.0000     299.52       6.1668
    3151   winter     12  2286.9514     0.0000       0.00       1.5007
    4051   spring      0  2286.9514   480.0000    1632.36      96.0403
    4951   summer      0  2286.9514   480.0000     638.43       0.0588
    5851   autumn      0  2286.9514   480.0000    1564.64      27.9796
    6751   winter      0  2286.9514   480.0000    1363.98       5.4533
    7651   spring      0  2286.9514   480.0000    2361.84       1.0575

  12 creatures started, 12 struck off, 0 still walking
  29307 creature-ticks handed out over 6750 ticks of valley

Read the standing column down and the story is not subtle. The valley held 1,517.5 grams of plant on the tick the herd was let into it. Four hundred and fifty ticks later it holds 188.24, and 581 of the missing grams are inside twelve browsers. Autumn is the herd's quarter: the plants put mass on faster than the mouths take it off, the browsers still get 1,291 grams out of the quarter, more than twice what the whole of summer gave them, and the valley ends it standing higher than it began it. Then winter. Every plant that was still up comes down, standing reads 0.00, and the eaten column arrives at 2,286.9514 and never moves again, because there is nothing left in the valley to bite. All twelve are alive on that line and none of them is on the next one. Nothing in the model was tuned to produce that. A browser cannot keep a season's worth of energy in a store that holds 400 units against a body burning 0.16 of them a tick, and there is nowhere else in this world for food to be kept.

Then the half that is not about starving. With the herd gone the valley climbs back past 1,600 grams by that spring and past 2,300 by the second one, and the 480 grams that used to be twelve animals go into the litter and out of it again as the rotting works through them. Everything above is a summary, though, and a summary is where a missing gram hides. The audit is the block the run finishes on.

$ go run ./cmd/books -mode run -herd 12 -store 400 -years 2
  the books in grams
    the valley opened with      11.250000      plants founded on the first tick
    built out of light       43613.746056      every gram the leaves ever fixed
    creatures stood up         480.000000      bodies the run opened with
    in                       44104.996056

    standing                  2361.841868      living plant tissue
    walking                      0.000000      living creature bodies
    in the air                   0.000000      seeds still flying
    in the bank                286.000000      seeds waiting in the ground
    lying dead                   1.057533      litter: plants and carcasses together
    burned as upkeep         38432.484261      grams a plant spent on standing there
    rotted                     659.660979      grams the litter has burned off
    blown away                  77.000000      seeds that left over the rim
    eaten                     2286.951415      grams a mouth took and a store spent
    out                      44104.996056
    difference                  -0.000000      -7.421e-10, which is the last bits of the adding

  the two lines the creature phase owns, checked against each other
    12 creatures struck off at 40 grams a body is 480.000000 grams of carcass
    handed to terra.Bed.Fall                        480.000000 grams
    difference                                      0.000000 grams

Three lines on that page are the creature phase's and the rest were the terrarium's already. creatures stood up is the stock the run began with. walking is what is left of it in living bodies. eaten is grams that came off a plant, went into a store as energy and were spent, which makes it a sink in exactly the way burned is a sink: the gram is gone and the ledger says where it went. There is no carcass line, because a carcass is not a place a gram can be. It is a gram moving from walking into lying dead, and both of those columns were already there.

The bottom three lines are the check that the middle of the ledger cannot make. A total that balances is not the same as a total that is right, because a wrong number in one column and its mirror image in another balance perfectly. So the carcasses are counted a second way, from an entirely different direction: twelve creatures struck off, at the bulk written in the row they were stamped from, is 480 grams that ought to have gone through terra.Bed.Fall, and 480.000000 went through it. That one is exact rather than nearly exact, because it is twelve additions of the same whole number and nothing has divided anything.

Where the creature phase sits inside one tick, and every place a gram of the valley can be The upper panel shows one tick as four boxes left to right: plants eat and grow, then plants die and seeds fly, then the creature phase highlighted as the new one, then rain sun and rotting. A line beneath says the valley calls one function field between the third and fourth, and that a carcass dropped there is rotting before the tick closes. The lower panel shows the paths a gram takes. A box for standing plant tissue has two arrows out of it: one to a box for eaten grams, spent as energy and gone, labelled as a bite through Graze; and one down to a box for the litter, labelled the plant stops. A box for walking creature bodies has an arrow into the same litter box, labelled the store reaches nothing and the grams go through Bed dot Fall. The litter box has one arrow out to a box for rotted grams, labelled Bed dot Rot. The two boxes on the right are marked as ends, places a gram stops being anywhere. ONE TICK, AND WHERE THE CREATURE PHASE SITS IN IT PLANTS EAT AND GROW PLANTS DIE, SEEDS FLY THE CREATURE PHASE RAIN, SUN, ROTTING one function field on the valley, called here, taking nothing and returning nothing a carcass dropped on this line is already rotting before the tick closes EVERY PLACE A GRAM CAN BE, AND THE CALL THAT MOVES IT STANDING EATEN: SPENT AS ENERGY, GONE THE LITTER ROTTED, GONE WALKING A BITE: GRAZE THE PLANT STOPS THE STORE HITS NOTHING BED.ROT both arrows into the litter are the same call, terra.Bed.Fall, on the cell it happened
Figure 50.1 — the tick above and the grams below. The two boxes on the right are the only places in the picture a gram stops moving, and everything else is somewhere it is being kept. A creature adds one box, walking, and one arrow out of it, and that arrow goes to a box the plants were already using.

The generalisation is not about valleys. A ledger like this only tells you anything if the world it covers is closed, meaning every route in and out is a line on the page. The moment one is missing, the difference column stops being a check and becomes a place for the error to live: it will still print a number, and the number will be whatever the missing route happens to have moved. That is why blown away is on the page even though those grams left the valley for ever, and why eaten is on it even though the grams became heat. Both are exits, both are counted, and the total that has to match is the one at the top.

The mineral count

That difference column closed to fourteen significant figures and it was still not the whole truth about the run. An audit checks the things it has columns for, and every column above is grams. The terrarium has kept a second set of books since it learned to rot, counted in nutrient units, and the creature phase has no line in them anywhere.

Those books work by lending. A plant is charged nutrient against the cells its roots reach as it grows, at its row's Hunger for every gram it puts on, and Holds() is what it is carrying at any moment: standing mass times that rate. The day it stops standing, the identical figure goes into the litter on its cell and rots down into the ground underneath. A loan and a repayment, and that is the only reason the second column has ever closed.

A mouth is the thing that arrangement was never written for. A bite takes standing tissue off a plant, and standing tissue is holding minerals the plant borrowed to build it. The grams have somewhere to go: they become energy, a body burns them, and eaten is the line that says so. The minerals have nowhere. A creature is never charged nutrient, not for the body it was stood up with and not for a mouthful, so it has no account for minerals to sit in. So the bite hands them back where they came from: on the tick a mouth closes, the nutrient that mouthful was carrying lands on the cell the plant is standing on, through the same terra.Bed.Fall the plant's own burned upkeep has always gone through. The loan belonged to the plant, and it is settled the moment the tissue leaves the plant, whether it left by dying or by being eaten.

-mode dirt adds that column up over the same two years, once for the valley with the twelve in it and once for the valley with nobody.

$ go run ./cmd/books -mode dirt -herd 12 -store 400 -years 2
books: the nutrient books over 2 years, the same valley twice
       400.0000 in every store, the rule that hunts the nearest plant

                               no creatures      12 browsers
  the valley opened with         528.000000       528.000000   soil cells full of it on the first tick
  in living tissue               226.782456       213.310767   drawn out of the ground and still standing
  in the air                       0.000000         0.000000   locked up in seed still flying
  in the bank                     23.320000        19.680000   locked up in seed waiting in the ground
  lying in the litter            257.597260       249.259994   dead tissue that has not rotted down yet
  in the soil                     13.760284        40.769239   back in the cells, ready to be drawn again
  blown away                       6.540000         4.980000   left over the rim inside a seed

  out                            528.000000       528.000000
  difference                      -0.000000         0.000000

  eaten                            0.000000      2286.951415   grams a mouth took off a stand
  residue                        -2.274e-13        6.821e-13   the last bits of the adding

Both columns come to 528.000000, and that opening figure was not measured either: this valley has forty-four cells a root can live in, twelve units were put in each of them on the first tick, and there is no route into this world for a forty-fifth. The residues are printed instead of rounded off for the reason the grams residue is printed. Minus 2.274e−13 on the empty valley and 6.821e−13 on the grazed one are the last bits of the adding, and a column that came out at exactly zero would mean somebody had been tidying. The eaten line underneath is in grams rather than units and is there to tie the two pages together: 2,286.951415 is the same figure the audit printed, taken off the same stands on the same ticks.

Now stop reading the totals and read across the rows, because they do not match and are not meant to. The grazed valley holds less in living tissue, 213.310767 against 226.782456, less in the litter, and nearly three times as much in the soil: 40.769239 units of free mineral against 13.760284. That is what a mouth does to this ledger. Tissue a browser eats gives its minerals up on the tick of the bite; tissue nothing eats keeps them until the plant dies, then keeps them again as litter until the rotting has worked through the pile, which takes most of a season. Grazing shortens the route a mineral takes back to the ground. It takes none out of The Hollow.

The size of that soil row is why the shortcut matters. Fourteen units spread over forty-four cells is what the ungrazed valley has free at the end of two years, and everything else it owns is locked up inside something. When the circulating pool is that thin, how fast minerals come back to it is what decides how much the leaves can build, because a root that reaches no nutrient has a plant that is nutrient-limited whatever the sky is doing. So the arithmetic runs the way it does not sound as though it should. Twelve browsers take 2,286.951415 grams out of this valley over two years, and the valley builds more than it would have built if they had never been in it.

$ go run ./cmd/books -mode run -herd 0 -store 400 -years 2
  the books in grams
    the valley opened with      11.250000      plants founded on the first tick
    built out of light       43137.313190      every gram the leaves ever fixed
    creatures stood up           0.000000      bodies the run opened with
    in                       43148.563190

    standing                  2320.368868      living plant tissue

Same seed, same weather, same founding generation, nothing walking about in it: 43,137.313190 grams built out of light, 2,320.368868 standing at the end. With the twelve in it the leaves built 43,613.746056 and 2,361.841868 was left standing, so the grazed valley finished 476.432866 grams ahead on what it manufactured and 41.473000 grams ahead on what it was holding, and fed a herd on the way. Nothing was tuned to get that. Chewing tissue up and dropping its minerals on the ground is a faster way to get them back into circulation than waiting for the plant that grew them to die.

One line of Graze is doing all of it, and the creature carries a flag that switches it off, so this is a run and not a claim. Unpaid is named for the ground and not for the animal, because a creature carrying it eats exactly what it always ate and every unit that goes missing goes missing from the bed. Set it and the grams still leave the plant; the minerals they were holding land nowhere.

$ go run ./cmd/books -mode dirt -herd 12 -store 400 -years 2 -unpaid
books: the nutrient books over 2 years, the same valley twice
       400.0000 in every store, the rule that hunts the nearest plant
       a bite hands the minerals it took back to no cell

                               no creatures      12 browsers
  the valley opened with         528.000000       528.000000   soil cells full of it on the first tick
  in living tissue               226.782456       107.847762   drawn out of the ground and still standing
  in the air                       0.000000         0.000000   locked up in seed still flying
  in the bank                     23.320000        18.450000   locked up in seed waiting in the ground
  lying in the litter            257.597260       152.110345   dead tissue that has not rotted down yet
  in the soil                     13.760284        74.951173   back in the cells, ready to be drawn again
  blown away                       6.540000         3.720000   left over the rim inside a seed

  out                            528.000000       357.079280
  difference                      -0.000000       170.920720

  eaten                            0.000000      2051.824604   grams a mouth took off a stand
  residue                        -2.274e-13        1.709e+02   the last bits of the adding

357.079280 of 528. That is 170.920720 units gone, a third of everything The Hollow has ever had, with no line on any page to say where. Read down the browsers' column and there is nowhere it could be hiding: less standing, less in the bank, less in the litter, less blown over the rim, and the free soil pool up instead of down, because a valley short of a third of its minerals grows less tissue to lock the rest of them into. The bottom line is the one to look at hardest. That residue column exists to print the last bits of the adding, a rounding crumb in the region of 1e−13, and on this run it reads 1.709e+02: the hole itself, printed in the notation the page reserved for noise.

Now run the grams over the same two years with the same flag set.

$ go run ./cmd/books -mode run -herd 12 -store 400 -years 2 -unpaid | tail -8
    eaten                     2051.824604      grams a mouth took and a store spent
    out                      35397.770577
    difference                   0.000000      3.711e-10, which is the last bits of the adding

  the two lines the creature phase owns, checked against each other
    12 creatures struck off at 40 grams a body is 480.000000 grams of carcass
    handed to terra.Bed.Fall                        480.000000 grams
    difference                                      0.000000 grams

Fourteen significant figures, and the carcass check agrees with itself to the gram. That audit is as clean with a third of the valley's minerals missing as it was without. The audit that was being read every time said zero, because the units it was adding up were not the units going missing.

So the generalisation the grams audit started has a second half. A closed-world check is only closed in the currency it counts. Grams and minerals leave a plant together and then travel apart, so anything that can move one of them without the other needs both columns totalled, or the untotalled one becomes where the error lives. It will not announce itself. The books somebody is adding up go on coming out at zero.

✓ Checkpoint — what the roster can now be asked
  • Say why the running totals for grams eaten and grams buried live on the roster and not on the creature, and what breaks in the ledger if they live on the creature.
  • Given the browser row and a starting store, name the tick a resting creature stops on before running it, and say why a store printing -0.0000 satisfies a test written as <= 0.
  • Defend the zero in Pile{Mass: c.Grams} by saying where the minerals in a mouthful had already gone, and say what a second kind of creature would have to do to the ground before the row needed a column for it.
  • Shown a phase that steps twelve creatures and ends with an empty roster, say which of those two happened first and why the other order panics at index six.
  • Name the three lines the creature phase adds to the valley's grams and say which of them is a sink, and say what a grams ledger closing to fourteen figures still fails to prove about the nutrient books.
  • Explain why the carcass total is checked a second time against the count times the row's bulk, when the difference column already reads zero.
⚡ Exercises — try first, then reveal
Exercise 1 — give them a bigger store. The herd in the phase run all stop on tick 50 because they all open with 8.0000. Predict the tick for a store of 20, then check it with go run ./cmd/books -mode phase -herd 12 -ticks 140 -store 20.

Tick 125, and the run says so on its third line before the table starts: 20 divided by the 0.1600 a forty-gram body costs a tick. What does not change is the more useful half. Twelve are still stepped on the phase they die on, 480.0000 grams are still handed to the litter, and the list is still edited once, after the loop. The store decides when, and nothing about when touches the order.

$ go run ./cmd/books -mode phase -herd 12 -ticks 140 -store 20 | tail -8
    110       12       12   480.0000       0.0000
    120       12       12   480.0000       0.0000
    125        0       12     0.0000     475.5759
    130        0        0     0.0000     454.0273
    140        0        0     0.0000     413.6711

  12 creatures struck off, 480.0000 grams of carcass handed to the litter
  the roster handed out 1500 creature-ticks over 140 ticks
Exercise 2 — take the plants away and watch the ledger. Run the audit on a valley founded with nothing growing in it: go run ./cmd/books -mode run -herd 12 -store 400 -years 1 -found 0. Which columns go to zero, and does the difference still close?

Everything on the plant side goes to nothing: nothing was founded, nothing was built out of light, nothing is standing, nothing is in the bank, nothing blew away and nothing was burned as upkeep. What is left is 480 grams of body going into the litter and burning away again, which after a year is 479.939951 rotted and 0.060049 still lying. It closes, but look at the residue: −2.274e−13 on a total of 480, against −7.421e−10 on a total of forty-four thousand. A smaller ledger has fewer additions in it and loses fewer bits doing them.

$ go run ./cmd/books -mode run -herd 12 -store 400 -years 1 -found 0 | tail -15
    walking                      0.000000      living creature bodies
    in the air                   0.000000      seeds still flying
    in the bank                  0.000000      seeds waiting in the ground
    lying dead                   0.060049      litter: plants and carcasses together
    burned as upkeep             0.000000      grams a plant spent on standing there
    rotted                     479.939951      grams the litter has burned off
    blown away                   0.000000      seeds that left over the rim
    eaten                        0.000000      grams a mouth took and a store spent
    out                        480.000000
    difference                  -0.000000      -2.274e-13, which is the last bits of the adding

  the two lines the creature phase owns, checked against each other
    12 creatures struck off at 40 grams a body is 480.000000 grams of carcass
    handed to terra.Bed.Fall                        480.000000 grams
    difference                                      0.000000 grams
Exercise 3 — make the tests say it. The package carries four claims about this chapter as tests. Run go test ./internal/beast/ -run 'Hook|Phase|Carcass|Books' -v and match each name to the paragraph in this chapter that argues for it.

The first is the hook being inert, which is the claim the whole volume rests on. The second is the phase-order rule, asked as a count: twelve creatures on the roster, twelve ticks handed out on the phase they die on. The third is the mass rule for the one transfer this chapter adds, checking that the litter plus everything rotted off it comes to the bodies struck off and nothing else. The fourth is both ledgers at once, run on a valley that is really being eaten: the grams have to close, and so do the minerals, and it is the second of those a bite can quietly break.

$ go test ./internal/beast/ -run 'Hook|Phase|Carcass|Books' -v
=== RUN   TestAnEmptyHookLeavesTheTickAlone
--- PASS: TestAnEmptyHookLeavesTheTickAlone (0.92s)
=== RUN   TestEveryCreatureGetsItsTickOnThePhaseItDiesOn
--- PASS: TestEveryCreatureGetsItsTickOnThePhaseItDiesOn (0.00s)
=== RUN   TestEveryGramOfCarcassReachesTheBed
--- PASS: TestEveryGramOfCarcassReachesTheBed (0.00s)
=== RUN   TestTheBooksCloseOnAValleyBeingEaten
--- PASS: TestTheBooksCloseOnAValleyBeingEaten (0.32s)
PASS
ok  	theworld/internal/beast	1.245s

Twelve browsers ate a valley down to nothing and starved in its first winter, and the only thing choosing anything for them was twenty lines of hand-written rule that turns toward the nearest plant its rays can see. Nothing in the apparatus cares that the rule is hand written. The seam it plugs into takes twenty-four numbers and returns one of six, and the next thing to sit behind that seam is arithmetic: multiply a number by a weight, add the results together, and decide.