Z: the first instrumented battle in this campaign costs zero RNG words
A Von Neumann encounter at Gallandro on turn 54 gave the workload the finding said did not exist. Auto-resolved, with P10 committed before the click. P10 predicted a non-zero tail cost and was wrong: res_no_battle flipped to 0 for the first time in 55 turns, the fleet was destroyed, and the generator moved by zero. The bracket residual stayed 0, so combat proper drew nothing either -- all 22 words were inside ProcessTurn, exactly as on a peaceful turn. That is the strong form of lane J's static reading, and it means a reimplementation can model a turn's RNG while modelling nothing about combat. One auto-resolved encounter against an NPC is not combat in general, and 10.2 says so at length.
This commit is contained in:
parent
932f366597
commit
9fa1ee2600
1 changed files with 58 additions and 13 deletions
|
|
@ -305,19 +305,9 @@ would have said so by construction rather than by anyone noticing.
|
|||
|
||||
## 8. What is not settled, listed as loudly as the results
|
||||
|
||||
* **The combat resolver has still never run under an instrument.** Every encounter this workload produced
|
||||
had the no-battle flag set, so `ApplyEncounterResult` was a no-op every time; its measured 0 words says
|
||||
nothing whatever about combat's RNG cost, and the residual-0 result above holds only for turns with no
|
||||
battle.
|
||||
|
||||
Lane J read all 7,641 bytes of it in parallel with this run (`combat-resolver.md`; and note **7,641**, not
|
||||
the 7,499 Ghidra reports — method rule 17). Its conclusion pairs with this one exactly: **the resolver has
|
||||
no unconditional draw.** All three sites in its subtree are conditional — a node-cannon `NextInt`, an
|
||||
inlined `NextFloat` per back-engineering candidate, and a `NextInt` per successful roll of that. So lane
|
||||
J's cheap first prediction is directly testable with this instrument: **a plain fleet battle with no node
|
||||
cannon and no salvage should cost the same 18–22 words as a peaceful turn.** That is the next run this
|
||||
hook family should do, and it needs a workload nobody has built yet: a save where two hostile fleets
|
||||
actually meet.
|
||||
* ~~The combat resolver has never run under an instrument.~~ **It has now, once — see §10. It cost 0
|
||||
words.** What remains unsettled is everything a single auto-resolved encounter cannot speak for; §10.2
|
||||
lists it.
|
||||
* **Node-line expiry did not fire.** See §9 for the quantified distance rather than an absence.
|
||||
* **A turn with a genuinely empty encounter vector was not observed** (§4). Both saves produce exactly one
|
||||
sighting encounter on every turn. The tail-runs-every-turn claim is settled; the no-encounters variant is
|
||||
|
|
@ -410,3 +400,58 @@ Compare mode was **not** run on this hook for the same reason: with a prediction
|
|||
`ours` would advance the scratch generator by nothing, diff clean, and prove only that the harness works.
|
||||
The model becomes checkable the first time a line expires, and the descriptor is ready for that day.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 10. A real battle, measured — and it costs nothing
|
||||
|
||||
The turn-54 End Turn of the long run stopped on an **Encounter at Gallandro**: the player's five ships
|
||||
(3 DE Colonizer, 2 DE Armor) against a **Von Neumann**. That is the workload §8 said did not exist and lane
|
||||
J's `combat-resolver.md` asked for — every encounter in 54 turns until this one had `res->+0x4` set, making
|
||||
`ApplyEncounterResult` a whole-function no-op. **Auto Resolve** was chosen (the dialog's four options are
|
||||
Fight Manually / Auto Resolve / Fight Manually If Opponent Does / Retreat), and the prediction was committed
|
||||
to `sots-engine/docs/Z-tail-rng.md` §7 with the dialog still on screen and unclicked.
|
||||
|
||||
| turn | `res_no_battle` | `ApplyEncounterResult` words | tail words | `ProcessTurn` words | bracket | residual |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 52 | 1 | 0 | 0 | 18 | 18 | 0 |
|
||||
| 53 | 1 | 0 | 0 | 18 | 18 | 0 |
|
||||
| 54 | 1 | 0 | 0 | 16 | 16 | 0 |
|
||||
| **55** | **0** | **0** | **0** | 22 | **22** | **0** |
|
||||
|
||||
**P10 predicted a non-zero tail cost and was wrong.** The first battle this campaign has ever instrumented
|
||||
moved the strategic generator by **zero words**, and the bracket residual stayed 0 — so combat proper
|
||||
(`RunCombatRound` / the combat server, which run between `ProcessTurn` and the tail and are hooked by
|
||||
nobody) drew nothing either. Every one of the turn's 22 words was inside `StrategyServer::ProcessTurn`, just
|
||||
as on a peaceful turn.
|
||||
|
||||
That is the *strong* form of lane J's reading. Lane J established from the instruction stream that the
|
||||
resolver has **no unconditional draw** — its three sites are a node-cannon `NextInt`, an inlined `NextFloat`
|
||||
per back-engineering candidate, and a `NextInt` per successful roll of that. This run shows that on an
|
||||
ordinary encounter **none of the three fires**, and lane J's own cheap prediction — *a plain fleet battle
|
||||
should cost the same as a peaceful turn* — holds exactly.
|
||||
|
||||
### 10.1 Why this matters to the standalone
|
||||
|
||||
A reimplementation that models a strategic turn's RNG and **nothing about combat** reproduces the generator
|
||||
correctly through a battle. Combat's effect on the save is entirely in the state it writes, not in the
|
||||
generator it advances. That is a much cheaper milestone than "read the 7,641-byte resolver first", and it
|
||||
was not knowable before this run: the honest prior was lane K's "draw counts are entirely combat-dependent
|
||||
and unknown".
|
||||
|
||||
### 10.2 What one battle does not settle — and it is a lot
|
||||
|
||||
* **One encounter, auto-resolved.** `Auto Resolve` may not take the same path as a manually fought battle;
|
||||
the tactical engine has its own `Mars::CombatSim` generator at `sim+0x108` (§7) which nothing here
|
||||
watches. A manually fought battle is a different experiment and has still never been run.
|
||||
* **The opponent was a Von Neumann**, an NPC pseudo-player, not a rival empire's war fleet. No node cannon
|
||||
was present, so R1 could not fire; whether R2's salvage roll was skipped because no candidate had a
|
||||
non-zero salvage slot, or because the arm was not reached at all, is not distinguishable from a word
|
||||
count of 0.
|
||||
* **A cost of 0 is the easiest number to produce by accident.** It is exactly what a hook that compared
|
||||
nothing would report. The reasons to believe it here are that the same hook reported 18–22 for
|
||||
`ProcessTurn` on the same turn, that `res_no_battle` flipped to 0 for the first time in 55 turns on
|
||||
exactly the turn the battle happened, and that the player's fleet was destroyed — the battle demonstrably
|
||||
occurred. It is still one observation.
|
||||
* **No `EVENT_*` or state-side check was made.** These hooks declare the generator and nothing else, so
|
||||
this says the battle was RNG-free and says nothing about whether it was *computed* correctly.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue