Commit graph

2 commits

Author SHA1 Message Date
alex
d4f9404960 lane G3: civilian growth read and measured; out[6] is not a repair number
findings/subsystems/population-growth.md -- ServerSystem::GrowCivilianPops
0x00754220 read byte for byte, its whole chain, and Ship::RepairCost
0x00815180.

The headline is a correction to the brief's premise. The pass is NOT gated
on imperial carrying capacity. The whole system's civilian delta is clamped
to 20,000,000 -- POPTYPE[1]+0x08, an int64 literal in the executable -- and
on both reference pairs that clamp decides the value: the uncapped delta is
7.5x it and the capacity headroom 25x it. The imperial capacity is pinned
at exactly Size x 1e8 from the corpus alone, by two independent behaviours
of one colony across three turns, with no data files.

Two boundary corrections, both of the rule-17 shape. GrowCivilianPops is a
loop over group types whose back edge lies outside every decompiler `if`,
so it reads as straight-line code if you stop at the first `ret`; its real
end is 0x00754b59. MaxPopGeneric ends at 0x0074a6cd, so the 0x0074a6d0 that
lanes N and E1 both cite for the capacity-surplus pair is a different
function.

A table correction with teeth: InitPopTypeTable never writes the group
ceiling at +0x28/+0x2c. The CRT static initialiser at 0x009abe20 does, to
INT64_MAX, and nothing else touches it -- so the clamp that reads it is
always a no-op. A reader who opens only the obvious initialiser sees zero
there and would cap every carrying capacity in the game at nothing.
Lane N's whole table is otherwise reproduced independently from the
six-register fxch rotation.

output-turn-path.md: out[6] is NOT the ship-repair demand. 0x007460b0 sums
0x0081f8c0, which gates on the design's carried-population bit and computes
GroupIncome over the ship's own Population -- so it is the income of
population carried in slaver and colony hulls, a slot the engine already
had under a name nobody had connected to it. Corrected in place, with
lane-c3.json's three unread stubs superseded by lane-g3.json's read entries.

Ship::RepairCost is unexercised on the corpus and that is a measurement,
not an absence (rule 20): the independent colony keeps a ten-ship fleet in
orbit over Koa'Vo on both reference pairs and its Sav closes exactly with
the demand taken as zero, which it could not do if any hull had a cost.

Engine side: sots-engine wip/growth ed6602e -- reference pair 78 -> 81
closed, 0 regressed; pair 2 36 -> 39 closed, 0 regressed.
2026-09-08 15:53:08 -04:00
alex
3b99e255c7 lane C3: ComputeOutput on the turn path -- the money ComputeBudget actually sums
`ServerSystem::ComputeOutput` 0x00751fb0 and the whole of `ComputeOutputFromRates`
0x00751bb0, read from the instruction stream to the next function start. This is the
function lane E1 correctly identified as the real blocker on P01/P02/P03/P05/P06 after
its own chain came out 25/25 on BnkEl and did not unblock them.

The shape, and the fact everything turns on: construction points the build queue and
the ship-repair pass do not spend are redistributed over trade / terraform /
infrastructure, and the TRADE share is added to the money channel. Unspent
infrastructure points cascade into the terraform pool and unspent terraform points
cascade into money -- two hops, not one. So a colony with an empty build queue earns
the same money whichever way its sliders point, which is why the turn path's money
sits within one trade point of the projected path on this corpus.

Eleven addresses, five of them dropped as agreeing duplicates. New: the repair pass
0x00751590 (the B1 double-run side effect, and its round robin is provably a `min`),
the construction-point helper 0x00746830, the queue-demand walker 0x008251e0, the
ideal-suitability resolver 0x00745d60, and two helpers with non-standard conventions
that would be silently wrong read as thiscall -- 0x0074c6f0 takes `this` in ESI and
0x007460b0 takes the system in EBX.

Corrections in place: `income-term.md`'s "leftover science points" are leftover SHIP
CONSTRUCTION points (there is no science channel in this function), its
science-cascade bullet moves from inferred to instruction-verified, and
`output-term.md`'s 0x00751fa8 boundary is padding -- the `ret 8` is at 0x00751fa0.

Measured, with the engine change (sots-engine wip/output2 d3ee453):

    turn1-state -> turn2-state    209 -> 157   closed 52  regressed 0   (was 51 / 0)
    turn2-state -> turn3-state    108 ->  86   closed 22  regressed 0   (was 21 / 0)

Closed 1 per pair, regressed 0. Every prediction in the doc's section 4 held; the one
that was off is named and explained. The strongest check is not the leaf count but
the eleven-save self-check in section 5.3, where every difference between the turn
path and the projected path decomposes to the unit into the build queue's points.
2026-09-08 14:50:50 -04:00