sots-re/findings/subsystems/trade-and-spy-workload.md
alex 7d51767e87 lane L3: both containers filled, and filling them does not make the tail draw
Three lanes could not build this workload. VM144 built both halves from a cold main
menu on a stock, unmodified install -- no data file touched, no save edited -- and the
answer to the question they were built to ask is no.

TRADE. The premise everyone carried, that trade needs station construction plus its
tech, is wrong about the station: StrategyVars.txt makes a trade station a +2-routes,
+25%-income bonus, and NumTradeRoutesSupported has a floor of 1 per owned system, so
the population thresholds scale the count and do not gate it. The gate is one tech,
CCC_FTLEcon, and Zuul cannot research it at all. 20 routes and 6 trade sectors by
turn 4; 21 by turn 13.

SPY. Lane W3: "no lane has identified which UI produces a spy-program entry." It is
the fleet panel's Special menu, and the reason nobody found it is that the ship a spy
docks with is the Cruiser REPAIR AND SALVAGE mission section -- nothing in the UI
calls it a tender or mentions spies. Prediction S1 holds: the container grows at Build
Spy while the craft is still docked (tdep=-1, atto=<tender>), so no enemy colony and no
asteroid belt are on the critical path, which is what every earlier cost model assumed.

THE MEASUREMENT. With 21 routes, 6 sectors and 1 spy craft live, lane H's eleven entry
probes report the four outer tail callees entered exactly once per turn, as always, and
SpyManager::Slot13RngCallee, TradeManager::Slot13RngCalleeA and CalleeB entered ZERO
times -- this turn and across all seven instrumented turns, every probe installed=true.
The RNG ledger and the standalone's generator model do NOT need extending on account of
either container being non-empty. The next condition is active contents, not present
contents: tsnumflt=0 on every sector and spyon=0 on the spy.

WHAT ELSE FELL OUT. The trade-route vector is torn down and rebuilt every turn inside
ServerTradeManagerImpl::vslot9 (lane V2's phase-23 call 5 of 8, previously "draw-free"
and unexplained) -- an agreement, dropped rather than re-minted, as is the AI2 growth
helper. Two addresses are minted, both trapped live and both `mapped` not `verified`
because ReVa was unreachable: ShipAction_BuildSpy 0x00789620, a sibling of lane B6's
stack-built-fptr-table entry 0x120 bytes away, which is why no call-graph sweep ever
found this writer; and ServerSpyManager_CreateSpyCraft 0x008383c0.

And a correction with teeth: `spies2` is 0 in all 28 systems of a save that DOES have a
spy. The natural reading of lane W's count-0-in-11-saves was "no save has ever had one".
That reading is dead; spies2 is not the spy list, or it only fills for a deployed spy.

The research click path is written down for the first time (§4): clicking a tech node is
a PREVIEW, the bottom-left button confirms, Esc leaves without confirming, and the tree
pans only on a right-drag of about 600 px. That, not the tech cost, is what stopped
three lanes.

Saves: human-turn{5,8}-traderoutes, human-turn11-spytechs, human-turn15-spyprogram --
all --strict clean, 0 errors, 0 warnings.
2026-09-08 19:46:16 -04:00

24 KiB

The trade-route and spy-program workload

Lane L3, 2026-09-08. Guest VM144 (sots-re-win10-144, re@192.168.10.144, a ZFS clone of VM140). Shim builds l3cont-0117495-20260908T2107Z and l3cont2-0117495-20260908T2124Z.

Three lanes failed to build this workload. This one built both halves, from a cold main menu, in one session on a stock unmodified install. The headline result is nevertheless a negative one, and it retires lane W3's open risk rather than confirming it.


0. Summary

question answer
Can the trade-route vector be made non-empty? Yes. 20 routes, 6 trade sectors, from turn 4 of a stock custom game; 21 by turn 13.
Can the spy-program vector be made non-empty? Yes. count=1 on turn 14, from the fleet panel's Special -> Build Spy.
Do saves now exist? Yes. Four, all --strict clean: human-turn5-traderoutes.sav, human-turn8-traderoutes.sav, human-turn11-spytechs.sav, human-turn15-spyprogram.sav (both containers non-empty).
With 21 routes and a spy program live, do the four tail callees draw RNG? No. All three inner RNG-bearing callees are entered 0 times, this turn and cumulatively across 7 instrumented turns.
Does the RNG ledger / standalone generator model need extending? No -- not for either container being non-empty. The gate is deeper than "the container is empty", and §3.5 names the next condition.

1. Why the previous lanes' cost estimate was wrong

tail-probes.md §3.2 and every brief since carried this premise: trade income needs trade-station construction plus its tech, which from ref-turn2 is tens of 30-60 s End Turns. Both halves of that are wrong, and the second one is wrong for a reason worth stating.

A trade station is not a prerequisite. Read out of Data/Strategy/StrategyVars.txt (inside sots.gob, which is a plain ZIP):

STATION_BONUS_TRADE_INCOME  0.25   // Increases value of system trade routes.
STATION_TRADE_NUMROUTES     2      // Routes possible with trade station.

A station adds two routes and a 25 % income multiplier. The gate is one tech, CCC_FTLEcon, which sets ServerPlayer+0xff (CnTrd); StrategyServer::RegisterTradeSystems 0x007adc80 then registers ServerSystem::NumTradeRoutesSupported 0x00819d20 slots for every owned system, and that function has a floor of 1. The population thresholds

TRADE_ROUTE_REQ_CIVPOPULATION  200000000
TRADE_ROUTE_REQ_IMPPOPULATION  500000000

scale the count; they do not gate it. And they were never close to binding anyway: the reference game's own homeworld at turn 2 already reads Civilian 520,000,000 / Imperial 2,000,000,000, i.e. 3 + 4 = 7 route slots from the homeworld alone.

The real cost was the tech, and the real obstacle was the research UI. See §4.


2. The recipe that worked, end to end

Stock game, stock data files. Nothing in sots.gob or any loose data file was modified, and no save was edited; the resulting saves are legitimate corpus members.

  1. Main menu -> Single Player (512,449) -> Custom (445,357) -> OK (551,451).
  2. On Custom Game Setup the sliders respond to a plain click on the track. The ones that matter, and what previous lanes did not know existed:
    • Initial Colonies 10 (max) - ten developed systems at turn 1;
    • Initial Treasury 9,850,000 (max);
    • Initial Technologies 15 (max) - random techs, and the roll included CCC_FTLBrdB, which is the parent of both CCC_FTLEcon and CCC_SpyBm;
    • Research Efficiency 146 % (max), Economic Efficiency 148 % (max);
    • Number of Stars 28, Distance 5 ly (min) - so systems fall inside one TRADE_SECTOR_SIZE 10.0 cell;
    • species Human (CCC_FTLEcon is Zuul:0 in MasterTechList.tech - a Zuul game cannot do this at all), 2 players. Player species defaults to Random: set it explicitly on the launch screen via the card's setup button (359,486) -> Select Species dropdown (557,117).
  3. Research CCC_FTLEcon. One turn at these settings.
  4. End Turn. The routes appear on the next End Turn's arming.

Turn 4 -> 5 was the first End Turn with a non-empty container. Total elapsed from a cold main menu: about 50 minutes, most of it spent on §4.


3. The measurement

Instrument: watch.mode=cont, a third mode added to lane W3's watchpoint module (src/shim/hooks/watchpoints.cpp). Same single arming detour on StrategyServer::ApplyAllTurnCommands (RVA 0x0038f6a0), same VEH, same canary. Two changes: all four debug slots go on the two ends of the two containers (_Myfirst and _Mylast, so an allocation and an append are separable), and it re-arms and re-logs on every End Turn instead of only the first.

3.1 The control (rule 19)

shim.cfg.l3cont and shim.cfg.l3control differ in exactly one key, watch=. Both were run on ref-turn2.sav, one End Turn each, on VM144:

run (Autosave EndTurn).sav (Autosave).sav
watch=off bb4fd9ac89f41e3b… 978041acd168b56e…
watch=on bb4fd9ac89f41e3b… 978041acd168b56e…
published oracle bb4fd9ac89f41e3b… 978041acd168b56e…

Byte-neutral, and the clone reproduces VM140's determinism oracle exactly - which is also the adoption check for VM144.

The armed control run reproduced lane W3's numbers through a different arming path:

watch: trade routes -- manager=0x0d812270 (S+4+0x154) vector@mgr+0x3c first=0 last=0 end=0 count=0
watch: spy programs -- manager=0x0d82da80 (S+4+0x158) vector@mgr+0x10 first=0 last=0 end=0 count=0
watch: SELFTEST canary writes=1 traps=1 dr7=0xdddd0055 PASS

The canary passes on every turn, not just the first (the counter is now read as a delta).

3.2 The workload

turn 1->2   trade routes count=0    spy programs count=0
turn 2->3   trade routes count=0    spy programs count=0
turn 3->4   trade routes count=0    spy programs count=0
turn 4->5   trade routes first=0x33288560 last=0x332885b0 end=0x332885d0 count=20
            spy programs count=0
turn 8->9   trade routes count=20   (reloaded from the save - the routes survive save/load)

_Myfirst, _Mylast and _Myend all moved off zero together on the same turn, which is the first allocation of a default-constructed vector - exactly the transition lane W3 said it could not distinguish from an emptied one.

3.3 Who fills it, measured not read

Debug-register traps, exe base 0x006b0000 (ASLR delta 0x2b0000), 40 hits on the reload turn:

slot writer VA owning function x returns to
trade _Mylast 0x00841e57 FUN_00841cd0 +0x187 20 0x00868092 (inside 0x00868060)
trade _Mylast 0x00868328 FUN_00868060 +0x2c8 20 0x007d97df

0x007d97df is the return address of the call at 0x007d97dd, and lane V2 already named that site: OnAllCombatDone_Tail phase 23, call 5 of 8, target ServerTradeManagerImpl_vslot9 = 0x00868060 (vftable 0x00a31b74 slot 9). Lane V2 recorded that slot as "closure 185 functions, draw-free" and did not know what it was for.

ServerTradeManagerImpl::vslot9 is the trade-route builder, and it tears the vector down and rebuilds it from scratch every turn: 20 _Mylast writes from a helper called at +0x32 (the clear) and 20 from the body at +0x2c8 (the refill), on a turn whose count is 20 both before and after. On the first turn the routes existed, the growth helper 0x00483410 (already named by lane AI2, "vector too long") appears in the trap set as well, because that was the allocation.

This is an agreement, not a new address: 0x00868060 is already lane-v2.json's ServerTradeManagerImpl_vslot9 and 0x00483410 is already lane-ai2.json's growth helper, so both are dropped rather than re-minted. ReVa/CT111 was unreachable this session (ReVa (CONNECTION_CLOSED)), so no body was read in Ghidra and nothing beyond the trap is claimed.


3.4 The spy program

The spy half was built too, on the same game, four turns later. Full click path in §5. The container transition, from the same instrument:

turn 12->13  spy programs count=0      (tender built, Build Spy ordered)
turn 13->14  spy programs count=0      (arming is at ApplyAllTurnCommands ENTRY, before the
                                        order is applied -- the count lags the order by one turn)
turn 14->15  spy programs first=0x3f025ad0 last=0x3f025ad4 end=0x3f025ad4 count=1

_Myfirst, _Mylast and _Myend again moved off zero together: one element, first allocation.

Prediction S1 holds. ServerSpyManager's vector is the spy-craft list and it grows at Build Spy, while the craft is still docked to its tender - tdep = -1, spyon = 0, atto = <tender ship id> in the save. No second empire, no enemy colony and no asteroid belt are needed to make this container non-empty. Every earlier lane's cost model for the spy half assumed Deploy; Deploy is not on the critical path.

Who writes it, trapped live. The single allocation arrived on the turn thread as one chain:

0x00789620 +0x53  ->  0x008383c0 +0x9c  ->  0x0059f1a0 +0x5f  ->  0x00483410 +0x7c/+0x82

0x00483410 is lane AI2's already-named vector growth helper and 0x0059f1a0 is the push_back wrapper lane AI3 already uses by address. The two new ones are recorded in ghidra/addresses.d/lane-l3.json as ShipAction_BuildSpy 0x00789620 and ServerSpyManager_CreateSpyCraft 0x008383c0, status: mapped rather than verified because ReVa/CT111 was unreachable this session and no body was read.

0x00789620 sits 0x120 bytes after lane B6's ShipBorneBuildQueue_ProcessTurn 0x00789500, which lane B6 flagged as a new indirection class: zero call sites, no vtable slot, its address written into a stack-built function-pointer table by the ship-action dispatcher. Build Spy is SHIPACTION_BUILDSPY, so this is that table's sibling entry - which is why no call-graph sweep ever found the spy container's writer.

3.5 Do the tail callees draw now? No, on either container.

Lane H's eleven register-transparent entry probes, shim.cfg.l3probe (lane H's shim.cfg.hp11 verbatim plus the three watch.* keys, so the counts are comparable line for line). Seven instrumented End Turns, the last of which had 21 trade routes, 6 trade sectors and 1 spy program live:

probe calls, last turn since launch (7 turns) lane H baseline (empty containers)
ServerSpyManager::vslot13 1 7 1
ServerSpyManager::vslot14 1 7 1
ServerTradeManagerImpl::vslot13 1 7 1
ServerTradeManagerImpl::vslot15 1 7 1
SpyManager::Slot13RngCallee 0 0 0
TradeManager::Slot13RngCalleeA 0 0 0
TradeManager::Slot13RngCalleeB 0 0 0
ServerTradeManager::CreateRaidEncounter 0 5 1
ServerTradeManager::GenerateTradeRaidEncounters 1 7 1
ServerSpyManager::vslot15 [control] 1 7 1
ServerTradeManagerImpl::vslot14 [control] 1 7 1

Every probe reports installed=true, so these are measured zeros, not MinHook failures.

Filling either container is not sufficient to make the tail draw. The RNG ledger and the standalone's generator model do not need extending on account of the trade-route or the spy-program vector being non-empty. Lane W3's open risk is retired, in the direction nobody expected - and it is retired by evidence, not by the absence of it.

The next condition, and it is now cheap to test. The containers are non-empty but their contents are inert, and the saves say so precisely:

  • every trade sector has tsnumflt = 0 - no freighters in service. TRADE_ROUTE_STARTUP_TURNS is 3, TRADE_ROUTE_MAX_FREIGHTERS 5, and TRADE_RAID_ODDS_PLAYER 0.07: a raid roll needs something to raid. (CreateRaidEncounter was entered 5 times in 7 turns with, on lane H's reading, an empty candidate list.)
  • the one spy has tdep = -1 and spyon = 0 - built but never deployed. vslot13/vslot14 loop over the spy list; the per-element body almost certainly wants a spy that is at a system.

So the hypothesis for the next lane is active contents, not present contents: build freighters from the sector summary's Build Freighter button, and Deploy the spy at an enemy system with an asteroid belt (STARMAP_ASTEROIDBELT_ODDS 25 %), then re-run shim.cfg.l3probe. Rule 20 applies to this paragraph as much as to anything: the table above separates "vslot15 did not run" from "vslot15 ran and found nothing", and it says the latter.

4. The research click path - the thing that actually cost the day

No lane had written this down, and it is why three lanes could not get a tech. Lane O saw the bottom-left button on the Research screen and recorded it as "Cancel research, NOT back". It is both, depending on state, and when nothing is being researched it is the confirm:

map: Research (55,124)
  navigate to the tech (see below)
  click the tech node            -> the bottom bar previews "<tech>, N turns to complete."
                                    THIS DOES NOT ASSIGN ANYTHING
  click the bottom-left button (91,715)
  Confirm Research dialog -> OK  (~(595,393); the dialog is centred, read it off a screenshot)
  leave with the bottom-right circle (999,715)   -- NOT Esc

Three traps, each of which cost a run:

  • A click on a tech node is a preview, not an assignment. The bottom bar says "N turns to complete" either way. The map's ticker keeps saying No Research Project Assigned. and savings keep growing by the full income - that is the tell.
  • Esc leaves the screen but does not confirm, and the previewed selection is lost. Use the bottom-right circle.
  • Once a project is running, the top-of-screen Savings <-> Research slider does something visible (clicking its right end took FTL Economics from "2 turns" to "1 turn"), and the in-progress tech shows as an extra icon next to the species portrait on the map.

Navigating the tree. The categories sit on a rotating sphere, the labels do not line up with the branches drawn above them, and the campaign's click helper had no drag verb, which is why earlier attempts read as "the screen ignores input".

  • Right-button drag pans; left-drag and edge-scroll do nothing. A drag/rdrag/sdrag/ wheel verb was added to C:\SOTS\ui\click_helper.ps1 on VM144 (backup at click_helper.ps1.preL3); it is additive and existing verbs are untouched.
  • A ~600 px horizontal right-drag is one category step; the response is non-linear, so shorter drags fling several categories and are unusable. One drag per cmd.txt, screenshot between. Batched drags drop about half, exactly like batched clicks.
  • Dragging left moves the camera right. The order wraps: … Ballistic, C3, Xenotech, Industrial, Biological, Drone, Star Drives, Warhead, Shield, Power, Torpedo, Energy, C3 …
  • The wheel zooms but re-centres the camera somewhere else, so zoom is not usable for targeting. Work at the zoom the screen opens at.
  • Double-clicking a node opens a large readable detail card for it (title, description, "N turns to complete") with its children drawn below - the one genuinely useful navigation aid.
  • The tree only draws the researched frontier plus one step. A tech whose parent is unresearched is not on screen at all, which is why the Industrial branch looked like two nodes.

5. The spy path, start to finish

Lane W3: "no lane has identified which UI produces a spy-program entry." It is the fleet panel's Special button, and here is the whole thing. Every precondition was read out of the shipped data files and the binary's own refusal strings first, then executed.

The ability gate. Species/<race>/sections/_Spy.shipsection:

entity_class "SpyShip"    section_type mission    section_class destroyer
nodesign 1                spy 1                   cost 20000
requires CCC_SpyBm
requires IND_SlvgTech

nodesign 1 means the spy craft is never designed and never appears in a build queue - it is produced by a ship action, which is why looking for it in the Design or Build screens finds nothing.

The tender. Can't build spy: Fleet does not have a ship spy can dock with. The ship needs a section carrying spytender, and in this image there is exactly one per race:

CRRepairandSalvage - the Cruiser "Repair and Salvage" mission section (requires IND_SlvgTech, cost 60,000). Nothing in the UI calls it a tender, and nothing links it to spies. This is the single fact that makes the whole path findable.

The tech chain (RP from TechTree/MasterTechList.tech); at this game's settings each of these completed in one turn:

CCC_ROOT -> CCC_FTLBrdB (4,000) -> CCC_SpyBm (12,000)             [spy craft half]
IND_OrbFound -> IND_CruisCon (16,000) -> IND_SlvgTech (12,000)     [tender + spy craft half]

CCC_FTLBrdB is shared with the trade chain, and the Initial Technologies 15 roll supplied it.

The click path, executed on turns 11-14 at 1024x768:

  1. Design (142,124). Click Cruiser in the left list (104,267) to switch hull class. The design has three slots - Command / Mission / Engine - each with < > arrows; click the Mission slot's right arrow (710,483) until the title reads Repair and Salvage* (five clicks from Armor, through Medium Defense Platform). Bottom-left Save Design (135,715) -> name prompt -> OK.
  2. Build (221,124) -> Cruiser (104,276) -> the Repair and Salvage row (74,130) -> Add To Queue (125,715). ETA 2 turns at a developed homeworld.
  3. Two End Turns. The fleet panel then lists Alpha Fleet* / CR Repair and Salvage 9/9 and the Manage Fleets / Move / Special buttons light up.
  4. Special (229,464) -> the menu is Repair / Scuttle / Build Spy / Auto-repair / Flag As Guard. Build Spy at (277,517).
  5. Dialog Build Spy At <system>? / "Select ships for spy craft to dock with:" -> Select All (361,566) -> OK (599,566). The ship's row gains a leading * and a spy glyph: the order is queued, not yet executed.
  6. End Turn - the order is applied. End Turn again and the container reads count=1; the arming point is ApplyAllTurnCommands entry, so the count lags the order by one turn.

Everything the engine will refuse, from its own strings (none of these bit, but they are the map):

  • build - your own system, player has both techs, the fleet contains a tender, that ship is not already carrying a spy and is not busy;
  • deploy - not your own system, no enemy fleet present ("You gotta fight 'em."), no spy already there, and Can't deploy spy: Spy requires an asteroid belt to hide. (SPYSHIP_NEARBY_ASTEROID_RANGE 500.0; STARMAP_ASTEROIDBELT_ODDS 25 %).

Deploy was not done - it needs a fleet move to an enemy system with an asteroid belt, and §3.5 says it is the most likely next gate for the spy RNG callees. It is the one step of this subsystem still unexercised.

What the save now proves about the wire format. spymgr is populated for the first time in the corpus:

spymgr { xsid 2, nspy 1,
         spy { sid 1, sown 16, atto 3728, deat 0, tdep -1, cbh 0,
               sdo 0, sdet -1, spyon 0, spyat 0, cm 0, cmo 0, ncp 0 } }

sown 16 is the player id of re; atto 3728 is the tender's ship id; tdep -1 is "never deployed". Every member layouts.md lists for Game::SpyCraft is present, which confirms that record - but note that the on-the-wire order is not the memory order: sdo and sdet (memory +0x3c, +0x40) are written between cbh and spyon, not last. And ncp (memory +0x2c, typed as a 0x10 vector) serialises here as a bare count of 0, so an empty vector member is indistinguishable on the wire from a scalar zero until a save has a non-empty one.


6. Artifacts

what where
turn-5 save, the first trade routes in the corpus verify/results/saves/human-turn5-traderoutes.sav (72,204 B, --strict clean, 0 issues)
turn-8 save, routes matured, one sector secure verify/results/saves/human-turn8-traderoutes.sav (76,554 B)
turn-11 save, all four spy techs researched, no tender yet verify/results/saves/human-turn11-spytechs.sav (81,702 B)
turn-15 save, BOTH containers non-empty - 21 trade routes, 6 sectors, 1 spy craft verify/results/saves/human-turn15-spyprogram.sav (87,736 B, --strict clean, 0 issues)
probe-run trace, 7 End Turns of entry counts + RNG ledger verify/traces/l3-probe-turn8-turn15.jsonl
probe-run shim logs and watch hits verify/results/shim/l3/l3-probe-run-{shim.log,watch.txt}, l3-spy-run-{shim.log,watch.txt}
the two addresses this lane mints ghidra/addresses.d/lane-l3.json (ShipAction_BuildSpy, ServerSpyManager_CreateSpyCraft)
the instrument sots-engine src/shim/hooks/watchpoints.cpp (watch.mode=cont), src/shim/shim.cfg.l3cont, .l3control, .l3probe
predictions written before the build (rule 2) sots-engine docs/L3-predictions.md

What the trade saves contain that no earlier save does. trdmgr is populated: NumTradeSectors 6, SctSize 8.0, and six TradeID/Trade records each with tsgridID, tsctr, tssec/tsct/tscr, ptssec/ptsct/ptscr, an fwarn vector, tsnumsys and its tssys member list, and tsnumflt. In turn2-state.sav the same trdmgr block holds NumTradeSectors and nothing else. spymgr likewise goes from xsid/nspy 0 to a populated spy record (§5).

spies2 is still 0 in all 28 systems even so. Lane W flagged spies2 / SysMem / mts as hypotheses with count 0 in all 11 saves, and the natural reading was "no save has ever had a spy". That reading is now falsified: this save has a spy, in spymgr, and spies2 is still empty in every system. spies2 is therefore not the spy list - it is something else, or it only fills for a deployed spy. Whoever picks that up should start from the turn-15 save rather than from the assumption.

An engine defect found and fixed. hooks=off returned from Shim_Init before install_watchpoints, so hooks=off watch=on printed watch=on in the banner and armed absolutely nothing - a config that would have reported a confident zero. src/shim/main.cpp now installs the watchpoint module (and MinHook) on the hooks=off path when watch=on. This matters for any long play session: the template hooks cost 30-45 s per End Turn and measure nothing a container watch is asking about.


7. VM144 as left

Main menu, profile re, screenshot-verified. Shim build l3cont2-0117495-20260908T2124Z from C:\SOTS\shimdist-l3; C:\SOTS\shim.cfg is a copy of shim.cfg.l3probe. Original config saved at C:\SOTS\ui\preL3-shim.cfg.

C:\SOTS\ui\click_helper.ps1 has four new verbs and its pre-lane backup is click_helper.ps1.preL3. The additions are purely additive - every existing verb is byte-for-byte unchanged - and they are what made the research and design screens drivable at all:

drag  x1 y1 x2 y2     left-button drag
rdrag x1 y1 x2 y2     RIGHT-button drag, 30 steps  <- the only thing that pans the tech tree
sdrag x1 y1 x2 y2     slow left drag, 40 steps
wheel x y delta [n]   n wheel notches (delta may be negative)

SavedGames gained four files (MyGamel3tradeturn{5-traderoutes,8-tr,11-spytechs,15-spy}.sav) plus the game's three autosaves, so every Load-dialog row position recorded by earlier lanes has moved on this guest. Screenshot the dialog; do not reuse a remembered row. The repo copies of those four saves are the canonical ones.

Also left in place, all harmless: C:\SOTS\shimdist-l3\, C:\SOTS\l3data\ (the config text files extracted from sots.gob), and C:\SOTS\ui\l3-*.ps1 (the gob extractor, the click-helper patchers, a display-mode lister).

Guest adoption notes for the next clone. VM144 came up with no IPv4 in the host's ARP cache; it had one all along (192.168.10.144, DHCP from 192.168.0.1, /16). Two things worth knowing: ssh re@<addr> works directly from the dev box, and when the IPv4 address is genuinely unknown, ssh -6 re@fe80::…%vmbr0 from the PVE host works - the link-local address is in ip neigh on spicy even when the v4 one is not, and Windows answers SSH on it while dropping ICMP. That is a faster route in than a console screendump. The clone reproduces VM140's determinism oracle byte for byte (§3.1), which is the adoption check worth running first.