# L5 — `ComputeBudget` compare at the interest boundary, with a failing control VM146, 2026-09-08. Input save `turn1-state.sav` (= `Autosave EndTurn - turn2.sav`, 64,967 B, sha256 `a3f9dc4b49fc669c…`). Identical UI path for all three runs. ## Runs | run | build | `hooks` | `ComputeBudget` | dll md5 | |---|---|---|---|---| | control | `l5A-widened` | `off` | not installed | `F8DFC4AEE31FA60C5A2BE1E70CC38633` | | A | `l5A-widened` | `trace` | `compare` | `F8DFC4AEE31FA60C5A2BE1E70CC38633` | | B | `l5B-decimal-CONTROL` | `trace` | `compare` | `0FCC19DC2B9A769DB5FE2C4DC4683C78` | A and B are the same source except `kSavingsInterestRate` / `kDebtInterestRate`: widened floats in A, exact decimals in B. That is our side of the compare only. ## tracecmp ``` A calls 3895 compared 3895 diverged 0 invalid 0 undeclared writes 0 B calls 2718 compared 2718 diverged 1359 invalid 0 undeclared writes 0 ``` ## Coverage — distinct states, not call counts | treasury (`Sav`) | multiple of 100 | calls (A) | calls (B) | diverged (B) | game `savingsInterest` | exact decimal | |---:|---|---:|---:|---:|---:|---:| | 0 | — | 303 | 303 | 0 | 0 | 0 | | 38,100 | **yes** | 1 | 1 | **1** | 380 | 381 | | 50,000 | **yes** | 1,371 | 1,358 | **1,358** | **499** | 500 | | 92,651 | no | 28 | 28 | 0 | 926 | 926 | | 289,688 | no | 2,192 | 1,028 | 0 | 2,896 | 2,896 | **5 distinct treasury states, 2 on the rounding boundary.** Compare with the run this replaces: 4,437 calls, 20 distinct states, none on a boundary. `projected` split in A: 3,888 turn-path, 7 UI. Diverging fields in B (per call): `savingsInterest` 1,359, `available` 1,359, `researchMoney` 1,317. Sample diff at `Sav = 50,000`: ``` side.budget.after.v.savingsInterest orig 499 ours 500 side.budget.after.v.available orig 239091 ours 239092 side.budget.after.v.researchMoney orig 59772 ours 59773 ``` ## Live constants, read on every one of A's 3,895 records ``` savingsInterestRate 0.009999999776482582 = (double)0.01f debtInterestRate 0.15000000596046448 = (double)0.15f researchYieldFactor 0.8500000238418579 = (double)0.85f protectionFactor 3.29999995 = (float)3.3 [slot non-null; file image is zero] ``` ## Live per-player flags (all 8 players of `turn1-state`) | PlyrIdx | isAI | npc | ownedSystems | aidf | |---:|---|---|---:|---:| | 0 | false | false | 1 | 1 | | 1 | **true** | false | 1 | 1 | | 2 | true | true | 0 | 1 | | 3 | true | true | 0 | 1 | | 4 | true | true | 0 | 1 | | 5 | true | true | 0 | 1 | | 6 | true | true | 0 | 1 | | 7 | true | true | **1** | 1 | Exactly one AI-and-not-NPC player; the human is neither; player 7 owns a system and is an NPC, which is why T31 calls it ambiguous. `researchMoney`: 9 distinct values across A (`0, 24717, 59772, 59922, 60521, 68047, 217752, 218204, 218508`). **None is a multiple of 40,000**, so the research-yield-factor width is unexercised. ## Autosaves | run | `(Autosave EndTurn).sav` | `(Autosave).sav` | |---|---|---| | control | `a3f9dc4b49fc669c…` | `62061918176e3441…` | | A | `a3f9dc4b49fc669c…` | `7fc9e6ab46b47794…` | | B | `a3f9dc4b49fc669c…` | `ab4ac2d7e2977260…` | Pre-turn identical in all three. Post-turn differs by exactly four leaves per pair, all in one shadow empire's AI research pick — **not the hook**; see `findings/subsystems/turn1-to-turn2-nondeterminism.md`.