sots-re/campaign/backlog.md

8.2 KiB
Raw Blame History

Roadmap

Groomed 2026-09-08. Replaces the phase-0/phase-2 backlog, all of which shipped. The board (board.md) is the ledger of findings; this is the plan. The product is sots-engine — our code. RE findings are inputs to it, and the measure of progress is how much of the game runs in our engine, verified against the original. Every number here is measured; the source is named.

1. The engine today (sots-engine main 0592104, 31,980 LOC, ctest 45/45, clean-room, MIT)

module LOC what it is verification
mars/parse, mars/text 1,774 brace-block + flat-KV + CSV readers (the Mars::Script pull tokenizer, first-wins keys) oracle 1,531/1,531 + 64/64
mars/vfs 788 .gob ZIP + native-override VFS (the ./Mods mechanism) 10,268 files CRC-clean
mars/stream 5,407 save reader/writer, 386-class wire schema, SchemaProbe, CoverageArchive 100% named coverage, byte-identical round-trip, 11 saves
mars/rng 244 MT19937 + all seven entry points (NextFloat/NextInt/Chance/NextUInt/FloatRange/IntRangeBell/GaussianRange) live: every draw of a turn attributed
game/data, game/design, game/config 3,835 weapons/sections/tech/strings catalogs, design rules, hull class, tuning 229,042 values 0 diffs; 127/127 designs
game/effects, game/events 1,531 tech effects, EventStorage (turn-bucketed, dedup) live: research slice 35 calls / 0 div
game/sim 3,382 economy (ComputeBudget, output term), research + unlock cascade, colony, movement live: budget 4,437 / output 24,357 / research 35 / movement 45 calls — all 0 div on declared regions
game/nav, game/combat 1,163 route classifier + failure bits; retreat planner offline vs 58 waypoints / 46 plans, 0 failures; retreat never instrumented
app (sots_turn) 1,754 the standalone: load save → walk all three drivers' phase order → write save; divergence + completion metric 11/11 saves run; ref pair 209 → 204 leaves, closed 5 / regressed 0
shim 769 + hooks proxy binkw32.dll + MinHook trace/compare/replace harness — scaffolding, to be displaced it is the instrument, not the product

What the engine can do end to end today: read every shipped asset and every save byte-for-byte, run the economy/research/movement/output pieces to the original's numbers, and step a turn with 14 of 44 driver phases and 2 of 37 tail phases modelled (8 committed). It cannot yet reproduce a turn.

2. The milestone, restated

sots_turn loads a save, runs one strategic turn, and writes an autosave that byte-matches the original's.

Today showed the milestone as first stated is underdetermined on the reference pair: ModCount = 2 + one per command applied from every player's block, and on turn1-state.sav the human block is empty yet 10 non-driver bumps occur — the AI's orders are generated during the turn, after the autosave. Summary.Checksum is fed by ModCount. So, two rungs:

  • Rung A — byte-match modulo the command stream. Every leaf except ModCount, Summary.Checksum, and what the AI's own orders touch. No AI needed. Near target.
  • Rung B — full byte-match. Needs AI order generation in our engine (§4.1), or recorded AI command blocks fed as input. Rung B is where the engine becomes the game.

3. Engine work to Rung A (ranked by leaves closed per lane)

# engine deliverable module RE input (done unless noted) closes
1 income chain DONE, and it did not unblock the phases — TradePointsToMoney + difficulty ×1.1 landed at 25/25 on the BnkEl oracle (lane E1). But ComputeBudget's turn path calls ComputeOutput with the system's own Rts sliders, not ComputeMaxIncome — a strictly larger function where the repair pass and the unspent-industry/terraform cascades are live. The new item 1 is ComputeOutput on the turn path. game/sim lane E1; findings/subsystems/income-term.md P01/P02/P03/P05/P06, ~82 leaves, 2 RNG words
3 encounter-detection draws in the generator model game/sim + app lane I bound; lane H measuring now last 2 RNG words
4 nve visibility record game/sim one mechanism ×8, unread 32 leaves
5 post events into the save's turn bucket (P11 + tail event phases) app + game/events model exists; wiring only events subtree
6 Player.Status restore (S31) app needs the writer between tail 31 and autosave — watchpoint S31 regression
7 tail phases — bankruptcy decision half, turn results outbox swap, per-player sync game/sim + app lane K map; 34/37 stubs tail subtree
8 Rung B: AI order generation new game/ai §4.1 ModCount, Checksum

Rules that hold for every item: formula-held-inputs-missing is evaluated and reported, not written; closed and regressed reported separately, never netted; verified in the phase table means compared against the live game and the build fails if it drifts silently.

4. Future engine modules (breadth, ranked by what it unblocks)

  1. game/ai — AIPlayer, fuzzy IAIRule, StrategyAIAgent. Essentially unread; proven to gate Rung B. Known: AISystem::Write emits nothing; the 3 AIAgent save blocks are cache state (typed, 10 element layouts unexercised).
  2. game/combat beyond the planner — resolver (7,641 B, orchestration only) and retreat are mapped; the six pipeline callees and the tanker fold are unread; nothing here has run under an instrument. Combat simulation (GameCombatSim) stays parked.
  3. trade + spy managers — all 11 virtual targets named; four can draw RNG and none has fired (no trade routes / spy program in the corpus).
  4. net/ — the lockstep protocol. Direct IP works in the original without GameSpy; our engine inherits determinism to the word, so a lockstep peer is mostly serialization we already own.
  5. UI and renderer — not on any path; DXVK carries rendering for the original.

5. Workloads to manufacture (an unexercised path is a hypothesis)

  • orders save → End Turn → autosave — the Rung-A reference (human commands in-file).
  • trade routes + spy program — the four tail draw sites; spies2/SysMem/mts elements.
  • a cruiser (2 census leaves), a DN platform (the third).
  • a Liir fleet — waypoint type 2 is the Liir drive, not a node line; a Hiver game — types 4/5.
  • a battle with res->+4 clear and a partial retreat — resolver + retreat instrumented; tests the NMnx prediction and the predicted zero-ship-fleet bug in the original.
  • ResErrRoll true entering ProcessResearch — save exists; needs one turn funding > ½ a tech.
  • expense sliders / debtor / aid — likely dead in 1.8; debtor ≈ 35 turns. Low priority.

6. Multiplayer revival (lane G2)

  • Tier 0 (hours): /concurrent /join 127.0.0.1:3369 — two clients on one VM, no server. Predictions written; queued behind lane H for VM140.
  • Tier 1: availability responder, byte-specified; probably a no-op (fails open on DNS failure).
  • Tier 3 (config, not code): self-hosted OpenSpy/UniSpy with the swordots/Z5gR9Z/1381 row; fix queryport 3369 (not 6500) and add the 16 custom QR2 keys (ids 50–65).
  • No CD-key code exists; 333networks ruled out (v0 only).

7. Method and infrastructure

  • guides/method-rules.md (18 rules) is the contract for every lane brief. Rule 18 — measure first, the lab exists — is why the RNG ledger closed in one VM session after three static lanes.
  • Reachability claims older than lane V2 are lower bounds; re-check "no caller" findings with tools/vtable_map.py. Never trust Ghidra's function end (five lanes bitten).
  • Regenerate the determinism-oracle autosaves on VM140 (lane N overwrote them; lane H doing it).
  • Board rows superseded by later rows are marked SUPERSEDED at integration — keep doing it.
  • Displace the shim: each hook that reaches replace with 0 divergences is code the original no longer runs. Track that count; it is the honest "how much of the game is ours" number.

Parked

  • Battle-load bug (thread contention) — resume only with a reason.
  • Renderer — after the sim byte-matches.