The World Vol 4 · The Terrarium
ch 44 / 105
Chapter 44

A Valley That Stays Green

The three repairs

The diagnosis names three failures: growth does not slow when the valley fills, stranded nutrient has no path back to a root, and seeds crossing the rim carry matter out of the world. Measure each repair alone against the collapsed valley, then combine only the repairs whose own column explains what they changed.

The prediction is allowed to be wrong. The density brake was costed at 22 plants, a 2,363.6-gram crop, 1,166 seeds each autumn, and about 30 years before all 528 nutrient units were out of reach. Those numbers came from arithmetic, not a run.

The final run keeps what the measurements earn. It walls the rim, lets stranded nutrient creep back toward roots, and cuts rock cracks where one row can anchor without being erased by the row that wins open soil.

The density brake alone

The coefficient is one line of arithmetic. Count what is standing, divide by the cells a root can live in, take the answer from one. K is read off the bed at the moment the valley is stood up, so a map with more soil in it gets a larger K and nobody edits a constant to make that happen.

▣ Build · stage 1 — a coefficient that falls as the valley fills
// internal/terra/valley.go

// Crowd is the coefficient every income in the valley is multiplied by
// this tick: 1 - Brake*N/K, floored at nothing. N is read off the
// stands and K off the bed, so neither number is a constant somebody
// chose. With no brake set it is exactly one and every multiplication
// by it leaves its number alone.
func (v *Valley) Crowd() float64 {
	if v.Brake <= 0 || v.Cells == 0 {
		return 1
	}
	c := 1 - v.Brake*float64(len(v.Stands))/float64(v.Cells)
	if c < 0 {
		return 0
	}
	return c
}
	// The warmth says how fast the chemistry runs and the crowding says
	// what share of it the neighbours leave; both are multipliers on the
	// same income, so the tick multiplies them together once and every
	// plant is handed the product.
	crowd := v.Crowd()
	for _, st := range v.Stands {
		var l Ledger
		if st.Sleep {
			l = st.Plant.Sleep(st.Kind.Doze)
		} else {
			g := v.Bed.Offer(st.At, st.Plant.Root, st.Lit)
			l = st.Plant.Grow(g, warm*crowd)

Germination takes the same coefficient. A seed asking whether the ground under it can cover a seedling's first bill is asking the question a grown plant answers every tick, and a valley that throttled the grown plants while letting the seedlings start at full rate would be answering it two ways at once. Both the landing test and the seed bank's quarterly stir are handed warm*crowd in place of the warmth alone.

$ go run ./cmd/hold -mode brake -years 200 -every 25 -brake 1
hold: the brake and nothing else. seed 5, K = 44 cells a root can live in,
      c = 1 - 1.00*N/K multiplied into every income, 200 years, 528.0 units in the ground

   year       moss       herb      scrub       tree  standing  in reach  stranded    gone
          n   mass   n   mass   n   mass   n   mass     grams     units     units   units
      1   3   73.0   3   55.5   3  348.0   3  976.8    1453.4   148.356     0.000   0.000
      2   1    0.2   2    2.0  18  771.6   6 1435.7    2209.5    87.497     4.137   1.980
      3   0    0.0   0    0.0  23  853.3  10 1348.5    2201.8    81.236    11.548   4.200
     25   0    0.0   0    0.0  27  124.6  16  233.3     357.9   357.650    73.230  26.820
     50   0    0.0   0    0.0  26  119.6  17  247.4     367.0   328.858    92.400  33.480
     75   0    0.0   0    0.0  27  316.1  16  640.1     956.1   152.610   136.710  49.050
    100   0    0.0   0    0.0  28  131.9  14  204.9     336.8   238.083   165.360  59.760
    125   0    0.0   0    0.0  26  230.7  16  442.8     673.5   114.096   207.660  76.380
    150   0    0.0   0    0.0  24  447.3  17  639.4    1086.7     1.424   234.810  83.100
    175   0    0.0   0    0.0  22  189.4  20  533.8     723.2     6.767   276.900  94.950
    200   0    0.0   0    0.0  23  204.8  19  302.8     507.5     1.300   316.230 108.840

  what chapter 43 predicted a brake would do, and what it did
                                           predicted    measured
  plants standing                                 22          42
  grams one of them holds                     107.44       12.08
  the standing crop, in grams                 2363.6       507.5
  seeds released a year                         1166          63
  the share of them that strands               0.492       0.513
  nutrient units out of reach a year           17.21        2.13
  years the valley's units cover                30.7       248.4

  the coefficient at the last tick 0.045, world 1c2ee82130a87de6, census de0c1d2f1c0d5021

Read the standing column first. The braked valley carries 507.5 grams and 42 plants at year 200, and every printed census from year 25 on has at least forty-one plants in it. The same valley with the coefficient left out finished those two centuries holding 1.8 grams and one scrub. Whatever else the brake failed to do, it stopped the collapse.

Now the table underneath, which is what the run was made for. Predicted twenty-two plants, measured forty-two. Predicted 107.44 grams each, measured 12.08. Predicted a standing crop of 2363.6 grams, measured 507.5. Predicted 1,166 seeds a year, measured 63. This is not a prediction that missed by a little.

The assumption the costing flagged as its weakest is the one that survived. A braked seed rain was assumed to strand at the fraction a crashing one stranded at, 0.492, and the braked run strands 0.513 of its rain: two hundredths apart, on a quantity nobody had any right to be confident about. Flagging it was correct and it held anyway.

What broke is a step that was never questioned. N = K/2 is where N(1 − N/K)M is largest, and that is a fact about the crop, not about the plants. Nothing in a growth coefficient steers a population to the best point of the crop curve. A population goes to the count where the plants standing up match the plants falling over, and here that count is forty-two of forty-four cells: the coefficient at the last tick reads 0.045, so every plant in the valley is growing at four and a half per cent of the rate it would manage with the ground to itself. The brake did not pick a crop. It picked a size of plant, and the plants got small enough to leave every cell full.

∑ Interlude — where a crop is largest, and where a population stops

Numbers first. Forty-four cells, and a lone scrub reaching 214.87 grams on open ground. Put twenty-two plants in and the coefficient is one half, so each of them tops out near 107 grams and the crop is about 2,364. Put forty-two in and the coefficient is 0.045, each of them tops out near 10 grams, and the crop is a few hundred. The first number is the biggest crop the arithmetic allows. The second is where the valley actually went.

Two different questions are hiding in that. Write the crop as a function of the count:

C(N) = N · (1 − N/K) · M, largest at N = K/2

That maximum is a property of the formula. Solving it tells you what the ground could carry if something arranged the count for you. Nothing does. The count moves by its own rule: seedlings arrive at some rate that depends on N, plants fall at some other rate that depends on N, and the population sits still where those two are equal.

r(N) = d(N) is the resting count, and it has no reason to be K/2

The two conditions come from different equations and there is no mechanism connecting them. To make a population settle where the crop is largest you have to arrange for the deaths to happen there, and a coefficient on growth arranges nothing of the kind. This is the general lesson under the missed prediction: solving for the best value of a quantity is not the same work as finding out what value the system will take, and only one of those two is answered by running it.

Nplants standing in the valley right now
Kcells a root can live in: 44 on this map
Mgrams one plant reaches with the ground to itself: 214.87
C(N)the standing crop the coefficient allows at that count
r(N)seedlings that stand up in a year at that count
d(N)plants that stop standing in a year at that count

The last two rows of the table are the ones the diagnosis was really asking about, and the verdict in them survives the wrecked arithmetic: a brake on its own is not a cure. The braked valley pushes 2.13 nutrient units a year out of reach against the 17.21 that were costed, so its stock covers 248 years instead of thirty. Eight times longer, and still finite. At year 200 it has 316.230 units stranded on rock and under water, another 108.840 gone over the rim, and 1.300 units left anywhere a root can reach.

Creep and the rim

The soil chapter left a method called Regen in the bed and its own comment called it the weakest thing on the page: it trickles a fixed amount into every cell up to a cap, out of nothing at all. Calling it now would end the stranding and end the audit in the same commit. Every ledger in this volume closes to six decimals because nothing in the world invents matter, and a valley with a tap in it can no longer tell a leak from a rate somebody guessed. So the placeholder stays a placeholder, and the repair moves what is already there.

▣ Build · stage 2 — nutrient that can change cells
// internal/terra/bed.go

// Creep moves nutrient sideways: one double-buffered sweep of the grid,
// built the way the water rule is built, where every cell hands the share
// rate of what it is holding to the cells beside it and keeps the rest.
// It is a move and never a gift, so the valley's stock is exactly what
// it was before the sweep, and nutrient that rotted onto bare rock can
// finally reach a root three cells away. It hands back the units that
// changed cells.
func (b *Bed) Creep(rate float64) float64 {
	...
	for y := 0; y < b.H; y++ {
		for x := 0; x < b.W; x++ {
			c := sim.Coord{X: x, Y: y}
			i := b.index(c)
			have := b.cells[i].Nutrient
			...
			share := rate * have / float64(n)
			for k := 0; k < n; k++ {
				b.next[side[k]] += share
				b.next[i] -= share
				moved += share
			}
		}
	}
	for i := range b.cells {
		b.cells[i].Nutrient = b.next[i]
	}
	return moved
}

Two details in that loop are the whole of its correctness. Every cell reads from b.cells and writes into b.next, so a cell's gift does not depend on whether its neighbour has been visited yet, and the sweep gives the same answer whichever corner it starts in. And the same share is added to the neighbour and subtracted from the donor in adjacent statements, so conservation is a property of how the code is written and not something checked afterwards.

$ go run ./cmd/hold -mode creep -years 120 -brake 1 -wall -rim 1.5
hold: nutrient allowed to move between cells, 120 years, brake b = 1.00
      every rate below is the share of a cell's nutrient that leaves it a tick

    a tick     a year      moved   in reach   stranded  standing   rows      n
    0.0000       0.00        0.0      0.331    526.039     606.2      2     42
    0.0002       0.72    23991.1      1.905     82.586    2853.0      2     44
    0.0010       3.60   132044.7      1.953     80.177    2984.0      2     44
    0.0050      18.00   531940.4      2.078     30.545    2954.2      2     44
    0.0200      72.00  2331378.6      2.348      8.930    3085.2      2     44

The first line is the valley with no path at all: 526.039 of its 621 nutrient units lying where no root reaches, and 606.2 grams standing. Every line under it has a path, and they are all the same valley. Between 0.0002 and 0.02 a tick the rate spans a hundredfold, and the standing crop across that whole span moves by eight per cent. Having a path is the repair. How fast it runs is a detail, and finding that out cost one sweep of a number that looked like the important knob.

One column reads oddly until you see what it is measuring. The nutrient a root can reach never gets above 2.4 units out of 621 in any run with a path. That is a valley spending its stock as fast as it arrives: 2 units in reach and 3,000 grams standing is what a working circulation looks like from the outside, and the number to watch is the stranded column beside it, which drops from 526 to 80 the moment the sideways sweep is switched on.

The rim wants a decision instead of a mechanism, and there are three honest ones. Let the valley bleed and choose run lengths that admit it. Bring nutrient in from outside, which is the tap again. Or make the rim real: the valley sits in a bowl of rock, and a seed that reaches the wall drops at the foot of it. The third one keeps the world closed and costs a single branch in the landing code, so that is the one this book takes.

▣ Build · stage 3 — a rim a seed cannot cross
	if !v.Bed.In(c) {
		if !v.Wall {
			// It left over the rim. The grams go with it: this is the
			// one way matter leaves the valley for good.
			v.Seed.Fate[sd.Kind][OffMap]++
			v.Blown += s.Seed
			v.BlownN += s.Seed * s.Hunger
			return
		}
		// The rim is rock and rock is in the way. The seed stops at the
		// foot of it, on the last cell of the valley it was over.
		c = v.Bed.Edge(c)
	}

Edge clamps a coordinate back onto the grid, so a seed blown out past the top-left corner lands on the top-left cell. From there it runs the same four tests every other seed runs, and the rock it has landed on refuses it exactly the way rock always did.

⚠ Worked failure — a leak sealed on a valley that could not spend what it kept

The wall went in on its own, against the crashing valley, with a simple sum in front of it. Two centuries of that valley put 151.500 nutrient units over the rim, 28.7 per cent of everything it ever owned. Keep those and the valley should last appreciably longer, and the census should show it inside a few decades.

$ go run ./cmd/hold -mode rim -years 200 -brake 0
hold: the rim, four ways, 200 years each, brake b = 0.00
      the last column is every census of the run folded into one digest

  rim         creep  standing  in reach  stranded     gone             census
  open       0.0000       1.8     0.001   376.280  151.500   9d34c222edacd7bb
  open       0.0010     345.4     0.251    14.632  438.900   ea9e3c9869de3b1b
  walled     0.0000       1.8     0.001   527.780    0.000   9d34c222edacd7bb
  walled     0.0010    2556.2     1.431   118.489    0.000   587c166214546d30

Compare the first line with the third. Both finish at 1.8 grams. Both leave 0.001 units within reach of a root. And the last column settles it beyond argument: that digest folds every row of every census of the run into one running hash, so two runs agreeing there agree on 200 years of four rows to the last bit. Sealing the rim changed absolutely nothing.

The reasoning back from that is short once you look at where the units went. In the open run 151.500 of them left the valley. In the walled run those same seeds stop at the wall and rot on the rock cells under it, and the stranded column goes up by exactly what the gone column lost: 376.280 becomes 527.780. Bed.Rot puts the nutrient into the cell the litter was lying on, and Bed.Roots never looks at a rock cell. Gone from the world and out of reach are the same condition as far as a plant is concerned. A boundary is a leak only when the inside can spend what stays behind it.

Lines two and four are the same pair of runs with the sideways sweep on, and they are the reason the wall is in the finished valley. With the rim open, 438.900 units blow out in two centuries and the crop is down to 345.4 grams. With the rim walled, nothing leaves, the sweep keeps handing the rock's nutrient back to the soil, and the valley is holding 2556.2 grams at year 200 with no brake in it at all.

That last figure deserves to be said out in the open, because it is not what the last two chapters were pointing at. The runaway loop those chapters spent themselves diagnosing does not, by itself, end a valley whose matter cannot escape it. Close the boundary and give the stranded stock a way home and the unbraked valley is still standing after two hundred years. The brake stopped the collapse and did not save the valley; the return path saved the valley without touching the loop. Both of those came out of runs that changed one thing.

Rock-crack refuges

Two rows lost this valley in its first year, and a refuge is the standard answer to that: ground the competition cannot follow a lineage onto, so that whatever kills the open valley does not kill everywhere at once. Two candidates were on the table, the rocky rim and the deep shade. Both can be built and measured, and only one of them turns out to be a refuge here.

▣ Build · stage 4 — cracks in the rim, and who fits in one
// Rim cracks every cell of bare rock that shares a side with soil,
// walked in row order, and hands back how many it made. Which cells
// those are is read off the terrain rather than chosen: the rim of a
// valley is where the rock meets the ground. The slot is how wide those
// cracks are, in cells of root: it is the one number that decides which
// rows the refuge is a refuge from.
func (b *Bed) Rim(hold Cell, slot float64) int {
	b.slot = slot
	...
}

// Fits reports whether a root of this reach can anchor in this cell.
// Open ground takes any root there is. A crack takes only a root that
// fits inside it, which is a threshold on a trait and not a list of
// species: any row this book ever adds is admitted or refused by the
// same one number.
func (b *Bed) Fits(c sim.Coord, root float64) bool {
	if !b.Cracked(c) {
		return true
	}
	return root <= b.slot
}

A cracked cell is rootable ground holding a quarter of what open soil holds, and the founding draw, the landing test and the seed bank all run through Fits before anything is allowed to stand in one. At a slot of 1.5 cells the moss at 1.0 and the herb at 1.5 are admitted; the tree at 2.5 and the scrub at 3.0 are not. Nothing in that rule mentions a species, so a fifth row added to the table tomorrow is judged by the same number.

Before the refuge can be judged, the two rows it is for have to be priced. Every row in the table spends part of the year with its leaves down, paying a share of its usual upkeep out of standing tissue and earning nothing, and that is arithmetic anybody can do before running a valley at all.

▣ Build · stage 5 — a winter, priced per row, then the refuge measured
$ go run ./cmd/hold -mode refuge -years 150 -brake 1 -wall -soak 0.001
hold: a winter priced per row, and then a refuge built in the rock

  row          cue   wake   asleep  of one gram   so needs     holds
  moss      warmth   0.15      911     0.000106      473.5      47.2
  herb      warmth   0.50     1799       annual          -      38.0
  scrub   daylight   0.80     1411     0.797895        0.2     214.9
  tree    daylight   1.00     1799     0.798605        0.6     632.8

  asleep is ticks of the 3600 with its leaves down; of one gram is what its
  dozing upkeep leaves of a gram over those ticks; so needs is the mass it
  must go into winter with to come out above its own least mass; holds is
  what one of them reaches standing alone on this valley's open ground

  one moss founded alone on open ground, nothing else in the valley
    tick   season   warmth   awake    grams
     900   summer    0.854    true  47.1246
    1800   autumn    0.854    true  33.2887
    2700   winter    0.146   false   2.0692
    3600   spring    0.146   false   0.0000
  and then it is gone: 0 standing, 1 of its row starved

The moss goes into winter for 911 ticks at half its upkeep, and half of two per cent a tick, compounded 911 times, leaves 0.000106 of a gram. To come out of that above its own least mass of 0.05 grams it would have to go in holding 473.5. One moss with the entire valley to itself, in full daylight, with nothing standing anywhere near it, reaches 47.2. The trace under the table is the same sentence with the model saying it: 47.1246 grams at midsummer, 33.2887 at the turn of autumn, 2.0692 at the turn of winter, nothing at all by spring, and the death register says starved.

So the moss loses this valley to its own dormancy bill, by a factor of ten, on ground no other plant has touched. A place the competition cannot reach is no use to a row whose problem arrives in November.

$ go run ./cmd/hold -mode refuge -years 150 -brake 1 -wall -soak 0.001   (the tables after the trace)
  the same 150 years with the rim left as rock and cracked two ways.
  Years is censuses of the 150 with one of that row standing at midsummer and
  last is the last of those. Seeded is the last year one of that row let go
  of a seed, whatever the census saw, and cracks counts the stands of it that
  were in the rim rather than on open ground
                                             moss                        herb
  rim       slot    K  years   last seeded cracks  years   last seeded cracks
  rock       0.0   44      2      2      2      0      1      1      3      0
  cracked    1.0   75      4      4      4      5      3      3      5      0
  cracked    1.5   75      4      4      4      5     21     93    150     65

  the scrub and the tree stood at every one of the 150 censuses of all three
  runs, and neither of them ever stood in a crack: no root that wide fits

  and at the last census of the cracked run, 31 of the 31 cracks were inside
  the root disc of something too wide to stand in one

  the shade at that same census: of the 75 cells a root can live in, the
  darkest holds 3.900 light and the brightest 13.655, at warmth 0.854 and c = 0.413
  row      needs light   cells too dark
  moss           0.378                0
  herb           4.721                7
  scrub          1.888                0
  tree           1.133                0

The controlled comparison is the second and third rows of that table. Both have the same 31 cracks and the same K of 75; the only difference between them is the slot, which is the rule about who may anchor. At a slot of 1.0 the herb is refused and its last seed goes into the air in year 5. At 1.5 the herb is admitted, 65 of its stands over the run are in the rim rather than on the valley floor, and it is still letting go of seed in year 150. Same ground, same count of cells, different admission rule. The refuge is doing that, and not the extra soil that came with it.

Two limits in that block are belongs on the page. The refuge leaks: at the last census all 31 cracks were inside the root disc of something too wide to stand in one, so a crack keeps a stem out and lets a root in, and the herb in the rim is drinking from a cell two scrubs are also drinking from. And the deep shade is no refuge whatever. The darkest cell a root can live in holds 3.900 light at that census, and the light a seed needs before it can start there is 0.378 for the moss, 1.133 for the tree, 1.888 for the scrub and 4.721 for the herb. Shade in this valley shuts exactly one row out of exactly seven cells, and that row is the small one. It keeps the scrub out of nowhere at all.

The six-coefficient sweep

One coefficient on one map is a setting somebody liked. The question is which values hold a valley and which do not, and the only way to know the edges of that is to walk across them: three world seeds, six coefficients, every other repair in place.

▣ Build · stage 6 — eighteen valleys, one hundred and twenty years each
$ go run ./cmd/hold -mode sweep -years 120 -seeds 3,5,7 -band 0,0.5,1,1.5,2,3 -wall -soak 0.001 -rim 1.5
hold: the density coefficient swept across 120 years, every other repair on
      cracked rim at a slot of 1.5, walled, creep 0.0010 a tick

    seed     K      b  standing   moss   herb  scrub   tree  least 20  in reach
       3    70   0.00    2042.8     26      4      0    120    2035.4     1.650
       3    70   0.50    2111.3      6      4      0    120    2095.7     1.704
       3    70   1.00    2119.7      8      5      0    120    2102.7     1.744
       3    70   1.50    2028.3      4      6      0    120    2013.9     3.203
       3    70   2.00     590.1      4      7      0    120     590.1   304.682
       3    70   3.00     209.3      4      3      0    120     209.3   377.241
       5    75   0.00    2843.9      4      2    120    120    2823.0     1.808
       5    75   0.50    3355.9      4      3    120    120    3340.8     1.945
       5    75   1.00    2984.0      4     21    120    120    2966.1     1.953
       5    75   1.50    1280.6      3      8    120    120    1269.3   259.095
       5    75   2.00    1479.8      3      5    120    120     197.1   206.076
       5    75   3.00     545.3      2      4    120    120     543.3   355.775
       7    81   0.00    3070.8      2      1    120    120    3022.7     2.032
       7    81   0.50    3155.1      2      1    120    120    3108.6     2.119
       7    81   1.00    3128.1      2      2    120    120    3128.1     2.507
       7    81   1.50    1102.5      2      3    120    120     748.9   389.296
       7    81   2.00     297.1      2      3    120    120     282.4   563.262
       7    81   3.00     589.5      2      2    118    120     568.6   485.736

  the four row columns are years of the 120 with one of that row standing,
  and least 20 is the smallest standing crop of the last twenty years

The band is wide at the bottom and has an edge at the top. From 0 to 1 all three worlds finish standing, with between 2042.8 and 3355.9 grams of crop and their smallest year of the last twenty within a few per cent of the ending. At 1.5 two of the three have turned: seed 5 drops to 1280.6 grams and seed 7 to 1102.5, and the last column on those two rows goes from about two units to 259.095 and 389.296. Seed 3 holds at 1.5 and goes at 2, and by 2 every world has lost half its crop or more.

That last column is the tell, and it says something the standing column alone does not. A valley with 563.262 nutrient units within reach of a root and 297.1 grams standing on it is starving on a full larder, which is where the crashing valley ended up from the opposite direction. Too much brake empties a valley about as thoroughly as none at all, and the only difference is which column tells you first.

The valley this book keeps runs at b = 1, the coefficient the diagnosis derived. The sweep puts it at the top edge of the band, and the choice costs something measurable: on seed 5 it holds 2984.0 grams against 3355.9 at b = 0.5. What it buys is the herb, which appears at 21 censuses of the 120 at b = 1 and 3 at b = 0.5. A coefficient that leaves a little more room decides which rows can use it.

▣ Build · stage 7 — a thousand years, all three repairs in
$ go run ./cmd/hold -mode long -years 1000 -every 100 -brake 1 -wall -soak 0.001 -rim 1.5 -shot assets/frames/valley-year-1000.png
hold: 1000 years of the repaired valley, seed 5
      brake b = 1.00 on K = 75, creep 0.0010 a tick, rim walled and cracked
      31 cracks at a slot of 1.5, 621.0 nutrient units in the ground

   year       moss       herb      scrub       tree  standing  in reach  stranded    gone
          n   mass   n   mass   n   mass   n   mass     grams     units     units   units
      1   3  117.4   3   98.8   1  192.0   1  375.6     783.7   310.928    19.836   0.000
      2   2    0.5  12   12.0   8  313.7   2 1102.4    1428.7   243.495    72.144   0.000
      3   1    0.2  12   12.0  22 1316.0   3 1055.3    2383.5   109.414    85.667   0.000
    100   0    0.0   0    0.0  37 1918.7   7 1101.3    3020.0     1.966    83.347   0.000
    200   0    0.0   0    0.0  32 1561.6  10 1301.6    2863.2     1.880    76.737   0.000
    300   0    0.0   0    0.0  34 1596.4  10 1303.6    2900.0     1.917    70.061   0.000
    400   0    0.0   0    0.0  32 1343.3  12 1457.6    2800.9     1.894    62.918   0.000
    500   0    0.0   0    0.0  29 1118.9  15 1572.0    2690.8     1.881    57.353   0.000
    600   0    0.0   0    0.0  28  914.2  16 1666.7    2580.9     1.837    56.871   0.000
    700   0    0.0   0    0.0  23  702.6  20 1803.2    2505.8     1.845    45.760   0.000
    800   0    0.0   0    0.0  29 1015.1  15 1622.5    2637.5     1.865    53.660   0.000
    900   0    0.0   0    0.0  27  984.1  16 1653.9    2638.0     1.885    51.969   0.000
   1000   0    0.0   0    0.0  27  943.9  17 1718.3    2662.2     1.906    46.544   0.000

  every row over the whole run. Seen is censuses with one of that row
  standing at midsummer; the two last columns are the last year one of
  them let go of a seed and the last year one of them stood up at all
           peak n  in year    seen  released     grew   seeded sprouted
  moss          3        1       4         6        5        4        4
  herb         12        2      21     23227    11614     1000     1000
  scrub        38        9    1000    431215      520     1000     1000
  tree         22      677    1000     56431       62     1000      986

The census stops moving in any direction after the first century. Year 100 reads 3020.0 grams and year 1000 reads 2662.2, and everything between wanders inside that. What does move is the mix: 37 scrubs and 7 trees at year 100, 27 scrubs and 17 trees at year 1000, trading slowly back and forth on the way. No line of code arranges that. It is what two rows do on ground where both of them can pay their bills, and the run that crashed lost its last tree in year 86.

The row table underneath is where the census gets caught out. The moss put its last seed into the air in year 4, and that lineage is finished. The herb was last seen standing at a midsummer census in year 93, and it released a seed in year 1000 and put a seedling up in year 1000. It has been there the whole time. A herb is an annual whose leaves come up on warmth, and the warm half of this calendar runs from mid-spring to mid-autumn: one that comes up after the midsummer tick lives out its season and is gone before the next one, so the census can only catch the few that sprouted in the weeks before it. 11,614 herbs stood up over the run and one reading a year saw twenty-one years of them. A row a census calls extinct can be seeding nine centuries later.

▣ Build · stage 8 — the same run, printed cell by cell
$ go run ./cmd/hold -mode long -years 1000 ...   (the tables after the census)
  the valley at year 1000, cell by cell, in two columns
    ############
    #ststtsstss#
    #sssstststs#
    #s~~~~~stss#
    #s~~~~~~sss#
    #ttt~~~~stt#
    #ttt~ssssts#
    ############
    cell   row    grams   light in reach     cell   row    grams   light in reach
   1,1   scrub   84.238  12.374   0.3067    8,3    tree  262.359   4.135   0.6986
   2,1    tree   56.042  10.054   0.3151    9,3   scrub   19.970   3.468   0.8585
   3,1   scrub   28.204   6.667   0.5454   10,3   scrub   22.532   5.262   0.7182
   4,1    tree   97.279   7.595   0.4650    1,4   scrub   20.730   8.823   0.5117
   5,1    tree  178.125   6.644   0.5004    8,4   scrub   21.592   3.696   0.9223
   6,1   scrub   36.213   6.082   0.7698    9,4   scrub   26.348   4.431   0.8256
   7,1   scrub   26.419   4.425   0.8119   10,4   scrub   28.884   4.951   0.6956
   8,1    tree   75.701   5.851   0.5408    1,5    tree  111.451   9.149   0.3966
   9,1   scrub    8.547   6.334   0.5558    2,5    tree   25.329   9.149   0.3972
  10,1   scrub   62.889  13.175   0.4174    3,5    tree  151.871   9.430   0.3812
   1,2   scrub   76.929  12.068   0.3344    8,5   scrub   29.235   4.628   0.6747
   2,2   scrub   37.953   9.806   0.4348    9,5    tree  188.486   4.800   0.6216
   3,2   scrub   35.815   6.468   0.6670   10,5    tree  101.790   8.295   0.4086
   4,2   scrub   47.365   7.595   0.6052    1,6    tree   34.752   9.430   0.3800
   5,2    tree   96.239   6.413   0.5180    2,6    tree   50.353   9.430   0.3800
   6,2   scrub   22.463   3.806   0.8134    3,6    tree   70.372   9.669   0.3678
   7,2    tree  144.827   4.209   0.7093    5,6   scrub    0.500  12.161   0.3004
   8,2   scrub   13.523   5.373   0.6893    6,6   scrub   23.302  15.701   0.2180
   9,2    tree   31.786   5.571   0.5648    7,6   scrub   63.262  10.516   0.3539
  10,2   scrub   48.834   7.711   0.6245    8,6   scrub   48.399   8.129   0.6228
   1,3   scrub   24.927  10.121   0.4837    9,6    tree   41.561   8.074   0.4154
   7,3   scrub   29.159   5.331   0.9217   10,6   scrub   55.664   8.962   0.4296

  the books in nutrient units
    the valley opened with     621.000000
    in living tissue           314.382078
    in the air                   0.000000
    in the bank                 43.040000
    lying dead                 215.127886
    in the ground               48.450035
    blown away                   0.000000
    difference                   0.000000

  2662.2 grams standing, 44 plants, 2 rows at this census, 1.906 units in reach
  510879 seeds released, 12201 germinated, 646 waiting in the ground
  world df1c117e69bdf157, census 75c77a67f6f430bb after 3600000 ticks
  3600000 ticks in 3m22.21s, 17803 ticks a second (measured here; yours will differ)
  frame b337de56fa55727da760f7da00aea5215a703e3984129b05d42b517ce7e955b6, wrote assets/frames/valley-year-1000.png

Count the letters on the map and there are 44 of them on 44 cells of soil: at year 1000 every cell of open ground in this valley has something standing on it. None of the 31 cracks does, at that instant. The cell table beside it is the census the volume has been working towards, one line per plant, its grams, the light on its cell and the nutrient its roots can reach, and all of it replays from the world seed.

The books close at 0.000000 across 3.6 million ticks with a sideways sweep running in every one of them, and the blown-away line reads 0.000000: in a thousand years nothing at all left this valley. The run cost 3m22.21s here, at 17,803 ticks a second against the eighty-odd thousand the same module manages on the valley that died. A world with 44 plants in it costs four or five times as much per tick as an empty one, and that is the bill for the repair: every one of those plants reads a root disc and writes a crown into the light field, every tick, for ever. Your machine will give you a different pair of numbers and the same ratio.

⚙ Tool — the runs on this page are replayed, not remembered

Every command printed above is run again when this volume's contract is checked: podman starts a container on a pinned Go image, copies the module into it, runs the commands in order and diffs the output against the committed transcript. Anything that drifts by a digit fails there. One line on this page cannot be replayed and says so where it is printed: the ticks a second, which measures a machine and not a valley. man podman-run if you want to see what the bench is doing.

The three repairs on the loop, and what each one left standing Two stacked panels. The upper panel is the reproduction loop drawn as four boxes in a ring: nutrient in reach feeds income each tick, income each tick feeds grams standing, grams standing feeds seeds and then plants, and seeds and then plants feeds nutrient in reach. Three additions are marked. A dashed line runs back from grams standing to income each tick, labelled the brake, c equals one minus N over K, and it is the only arrow on the diagram that pushes the other way. Below the seeds box, an arrow drops into a box marked out of reach, rock and pond, and a second arrow returns from that box round the left-hand side into nutrient in reach, labelled creep. A second arrow from the seeds box drops towards a box marked over the rim and is stopped by a short dashed bar marked the wall. The lower panel is four horizontal bars of the standing crop at year 200: no repairs, 1.8 grams with 527.8 nutrient units out of reach; the brake alone, 507.5 grams with 425.1 out of reach; creep and a walled rim, 2556.2 grams with 118.5 out of reach; all three repairs, 2863.2 grams with 76.7 out of reach. THE LOOP WITH THE THREE REPAIRS DRAWN IN NUTRIENT IN REACH 1.906 units in reach INCOME EACH TICK the least of three GRAMS STANDING 2662.2 at year 1000 SEEDS, THEN PLANTS 510879 in a millennium roots draw, crown fixes a quarter of the mass one seed in forty-two takes the brake: c = 1 - N/K OUT OF REACH: ROCK AND POND 46.544 units at year 1000 half the seed rain lands here creep hands it back, a share of a cell a tick OVER THE RIM 0.000 units, ever the wall WHAT EACH REPAIR LEFT STANDING AT YEAR 200 grams out of reach no repairs 1.8 527.8 the brake alone 507.5 425.1 creep, walled rim 2556.2 118.5 all three repairs 2863.2 76.7 the fourth valley has 621 units to spend, the other three have 528
Figure 44.1 — the ring is the one the diagnosis drew, with the three repairs marked on it: one arrow that pushes back, one that carries stranded nutrient home, and one boundary a seed cannot cross. The bars underneath are the same four valleys at year 200, and the pair of numbers on each row is the argument of the chapter: standing crop on the left, nutrient nothing can spend on the right.
A top-down valley, 192 by 128 pixels tripled: brown soil around a large blue pond, with a thin green plant standing on every patch of soil, evenly spaced across the whole map, some of them taller and branched. The rock border is bare.
Figure 44.2assets/frames/valley-year-1000.png: the valley at the last midsummer of a thousand-year run, drawn by the painter the seeding chapter wrote. Forty-four plants on forty-four cells of soil, twenty-seven scrubs and seventeen trees, and 0.000 nutrient units lost over the rim since the world opened.

Measured repairs

The method under this page is older than any of the mechanisms in it. Change one thing. Run the whole system. Print the result beside the number you expected before you ran it. Every finding above came out of that, and two of them contradicted the number written down before the run, which is the only sign that the discipline is doing any work.

A costed prediction is write down exactly because it can fail in a locatable place. The costing that opened this page was wrong by a factor of eight on the number it cared about, and because every step of it was printed it took one run to see that the flagged assumption held and an unflagged one broke. A prediction written as a sentence would have been wrong in an unlocatable way. Write the intermediate quantities down and a wrong answer tells you which step to fix.

Two of the repairs generalize past valleys. The first is what the rim taught: a boundary is a leak only when what stays behind it can be used, so before sealing anything, ask what the inside can spend. Sealing this one moved 151.500 units from a column called gone to a column called stranded and produced a byte-identical census. The second is what the refuge taught: a place a competitor cannot follow you to is an answer to being excluded from places, and the moss was being excluded from a season. Diagnose the exclusion before building the refuge, or you will build a good mechanism for the wrong row.

The instrument that made the rim finding legible is copy too. Folding every census of a run into one hash turns two hundred tables into sixteen characters, and two runs that agree there agree everywhere, including on the years nobody printed. Sampling cost this volume a worked failure twice over: a seed pool sized from a column that was structurally zero, and a row declared extinct in year 93 that was still seeding in year 1000. Both were readings taken at the wrong moment. A digest over everything is cheap insurance against the moment you chose.

✓ Checkpoint — what the repaired valley taught
  • write a density coefficient whose K is read off the map instead of typed into the source, and say why the same coefficient has to reach the germination test as well as the growth of a standing plant.
  • Given a costed prediction that came out wrong, you can put its steps in a column beside the measured ones and name which step failed, and you can tell a wrong assumption from a wrong piece of arithmetic.
  • say why the count that makes a crop largest and the count a population settles at are answers to different questions, and what a growth coefficient does not decide.
  • move a conserved quantity between cells with a double-buffered sweep that gives and takes in the same statement, and argue why that beats topping every cell up from nothing.
  • test whether a boundary is really a leak by asking what the inside can spend, and fold a run's whole census into one digest so two runs cannot appear to agree by accident.
  • Handed a row that is dying out, you can price its dormancy against its ceiling before building anything, and tell an exclusion in space from an exclusion in the calendar.
⚡ Exercises — try first, then reveal
Exercise 1 — take the wall down. The finished valley has all three repairs. Predict what three centuries of it look like with the rim open again, then run go run ./cmd/hold -mode long -years 300 -every 100 -brake 1 -soak 0.001 -rim 1.5 and read the books at the foot of it.

The blown-away line reads 586.270 of the valley's 621 nutrient units, and what is left standing at year 300 is 199.1 grams on 22 plants, with 0.120 units anywhere a root can reach. The sideways sweep is still running and the brake is still on; they are recirculating a stock that is nearly all gone.

The interesting part is the rate. The bleed averages under two units a year and it takes the valley apart anyway, because there is no arrow bringing any back. A loss that is invisible in a decade decides a millennium, and the only defence is a ledger long enough to show it.

Exercise 2 — brake too hard. The sweep says the band ends somewhere between 1 and 1.5. Predict what a coefficient of 2 does to a valley with every other repair in place, then run go run ./cmd/hold -mode sweep -seeds 5 -band 2 -years 120 -wall -soak 0.001 -rim 1.5.

It finishes at 1479.8 grams, which does not look like a failure until the two columns beside it are read: the smallest crop of the last twenty years is 197.1 grams, so that valley is swinging by a factor of seven, and 206.076 nutrient units are sitting within reach of a root that cannot grow fast enough to spend them.

A brake strong enough to hold the count down also holds the plants below the size at which they can use what they are standing on. The failure looks nothing like the crash and ends in the same place, and the column that tells you which one you are in is the nutrient a root can reach.

Exercise 3 — give the moss twice the sky. The moss needs 473.5 grams to survive a winter and reaches 47.2. Predict whether doubling the daylight closes that gap, then run go run ./cmd/hold -mode refuge -years 5 -light 24 and read the first table and the trace.

What it holds doubles to 94.3 grams and what it needs does not move at all: 473.5, the same figure. The trace shows the same death on the same schedule, 94.2493 grams at midsummer, 4.1384 at the turn of winter, gone by spring.

The needs column is upkeep, dormancy length and least mass multiplied together, and daylight is in none of the three. Doubling an input that only appears on one side of a comparison cannot change which side wins, and the arithmetic said so before the run did.

That is the volume. A plant was a budget kept once a tick, then the ground under it got two numbers a root could spend, then water arrived somewhere in particular and ran downhill, then the crowns started taking the light before anything under them could read it. Four of those budgets became four rows of a table, a year turned growth into something the calendar does to a plant, and seeds put the next generation on the wind. Two hundred unpaced years killed all of it, the loops went on paper, and three repairs came off that diagram and were built one at a time. What runs now is a valley that feeds itself for a thousand years and closes its books to six decimals. It has one thing nothing else in the world has yet: a standing crop, sitting there, paid for and unclaimed. The next thing to arrive will eat it, and a creature turns out to keep the same four columns a plant keeps, read from the other side of the meal: what it takes in, what standing still costs it, what moving costs on top of that, and what is left over to grow on.