# N — the population → base-output term The formula that a colony's whole economy hangs off, and the one `src/app` names as its largest unmodelled input. It is now read from the instruction stream and compared against the running game. ## What it is Output points are **linear in population**: ``` outputPerHead = populationTypeOutputModifier x 1.8 / 500000 ``` `1.8` and `500000` are literals in the executable, and so are the imperial (`1.0`) and civilian (`0.33f`) type modifiers — the three-row population-type table is *built in code*, not loaded from the data files. Only the slave row's modifier comes from the data. An imperial population with no station therefore contributes exactly `3.6e-6` output points per head. A system's total output is a **sum of three independent terms**, not one multiplicative chain: ``` base = overHarvestDemand x speciesResourceOutputFactor + (transitResources + availableResources) x stripMineFraction x 0.9 + imperialOutput + civilianOutput + slaveOutput total = addictionModifier x base x playerOutMod x systemOutMod x setupOutputMult x rebOutMod x scOutMod ``` The station bonus multiplies **only** the imperial term; the morale modifier multiplies **only** the civilian term. The previous model in this module applied both to the whole thing, which is why `OutputModifiers` no longer carries `morale` or `stations` — they belong to `GroupOutputInputs`, one population row at a time. ## API `src/game/sim/colony.h`: | function | what | |---|---| | `PopTypeOf(group, tuning)` | the population-type row: output/income modifiers and the row's population cap (imperial 50,000,000, civilian 20,000,000) | | `GroupOutput(GroupOutputInputs, tuning)` | one (group, species) row's contribution — the per-capita law | | `MoraleOutputMultiplier(morale, tuning)` | the civilian morale factor, with both of the original's guards | | `StripMineFraction(StripMineInputs)` | resource extraction efficiency | | `OverHarvestDemand(OverHarvestInputs)` | the strip-mining resource demand, which is also a summand of output | | `SystemBaseOutput(BaseOutputInputs, tuning)` | the three terms summed in the original's association | | `TotalSystemOutputRaw` / `TotalSystemOutput` | the multiplier tail, unrounded and rounded half-to-even | ## Verified against the running game Two hooks in `src/shim/hooks/system_output.{h,cpp}`, both **compare** mode, config `src/shim/shim.cfg.output`: * `Game::ServerSystem::GroupOutput` — the per-capita law itself. **13,105 calls, 0 divergences** across two species and two workloads. * `Game::ServerSystem::ComputeTotalOutput` — the whole sum and multiplier tail. **11,252 calls, 1 divergence**, and that one is a single ulp on one system, in a value the caller rounds to an integer before using — so it cannot move any number the game stores. It is recorded, not fixed. Both functions were checked for stores to the game state before being chosen as compare targets, and each declares a Guard region over the whole system object: **0 undeclared writes in 24,357 calls** turns that check from a claim into a measurement. The neighbouring `ComputeOutputFromRates` is deliberately *not* hooked — it repairs damaged ships in orbit. ### Coverage — read this before quoting the zero 24,357 calls is **13 distinct system states**. Unexercised, and therefore hypotheses: * the over-harvest branch (`SRoh` is 0 on every call in the corpus), including its `max(v, 1)` floor; * the station factor (no system in the corpus has a station); * the slave term (no system in the corpus holds slaves); * both morale branches (every colony sits at 75, strictly between the two thresholds); * the addiction multiplier and the civilian capacity surplus. ## `sim::Narrow` A 32-bit x87 build may leave an intermediate in a register at the register's own precision; the original's x87 runs with its precision-control field at 53 bits and rounds every multiply to double. The first live run made that visible as a one-ulp low result on **every** civilian row — 4,957 divergences that were all the same defect, and none of them the model's. `sim::Narrow` forces the round the original performs anyway, and is a no-op on any SSE2 target. ## Correction shipped alongside `ComputeBankruptcyLimits` used the decimal `-0.15` as the elimination-limit divisor. The image holds `-0.15000000596046448`, a widened float literal. The two disagree for **every** maximum income divisible by 3 — from `maxIncome = 3` upward — and for essentially every empire above about 3,000,000, which is six of the twenty-five bankruptcy records recoverable from the save corpus. Fixed, with `kBankruptcyInterestDivisor` named in the header and a test at the value where it first bites. ## What this does and does not unblock It does **not** unblock `P01`. `ComputeBudget`'s missing input is a system's *money*, which runs this verified total through a second chain with its own population law (`incomeModifier / 14000`, no `1.8`) and its own multipliers. Checked against the bankruptcy-limit oracle over the whole save corpus, that composition reproduces **6 of 25 player-records exactly** — every record whose owner is the human player or an independent colony — and the single-system misses are short by a clean factor of 1.1, the AI trade/income difficulty multiplier, which is not on the wire. So the blocker has moved from the output term to the income tail. `src/app` is unchanged: 5 leaves closed, 0 regressed, on both save pairs.