ai: bind the fleet-gather ordering contract where it will be needed
The gather/mint subsystem is not written yet, so this records the requirement at the emission layer rather than building the subsystem speculatively. Measured, not guessed: the original's assignment pass walks a container keyed on fleet->Location, a heap pointer, so its whole observed outcome set on a rich turn is the two orderings of two heap pointers under LFH randomisation. There is no original order to match -- it is neither ascending systemId nor ascending minimum ship id in any process observed -- so we choose one member of its outcome set and say so. The order must be imposed at the gather, not at assignment: the fleets already carry their ids when the assignment walk first touches them.
This commit is contained in:
parent
55408a980a
commit
45b16ef626
1 changed files with 39 additions and 0 deletions
|
|
@ -162,6 +162,45 @@ struct ColonizeOrder {
|
||||||
int trailing = 0;
|
int trailing = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// A CONTRACT FOR WHOEVER BUILDS THE FLEET GATHER
|
||||||
|
//
|
||||||
|
// These take `fleetId` as a parameter: this layer emits orders and does not form fleets or mint
|
||||||
|
// ids. The subsystem that does is not written yet, and when it is, it inherits a requirement that
|
||||||
|
// was measured rather than guessed, so it is recorded here where it cannot be missed.
|
||||||
|
//
|
||||||
|
// In the original, two processes running the same turn from the same save with the AI's seeds
|
||||||
|
// pinned produce different saves -- 35 leaves of 61,147, and all 35 are one transposition: two
|
||||||
|
// fleets exchange contents. The command blocks differ in exactly three words. The id counter is
|
||||||
|
// deterministic; the ids are minted in the same order every time. What varies is WHICH GROUP EACH
|
||||||
|
// ID LANDS ON, because the pass that assigns them walks a container ordered by
|
||||||
|
// `fleet->Location` -- a HEAP POINTER, with the fleet pointer breaking ties. Under LFH
|
||||||
|
// randomisation two allocations of the same size land in either relative order, so the original's
|
||||||
|
// whole observed outcome set on that turn is the two orderings of two heap pointers.
|
||||||
|
//
|
||||||
|
// Three consequences bind us:
|
||||||
|
//
|
||||||
|
// 1. **Order the groups by a key that is a function of the save, and mint in that order.**
|
||||||
|
// `(systemId, then minimum ship id)` with a total tie-break. Any deterministic key would do:
|
||||||
|
// the original's order is NOT ascending systemId and NOT ascending minimum ship id in any
|
||||||
|
// process observed, so THERE IS NO ORIGINAL ORDER TO MATCH -- we are choosing one member of
|
||||||
|
// its outcome set, not reproducing a hidden rule. Say so; do not let a later reader mistake
|
||||||
|
// this for a recovered behaviour.
|
||||||
|
// 2. **Impose it where the groups are gathered and the ids are minted, not at assignment.**
|
||||||
|
// The fleets already carry their new ids when the assignment walk first touches them, so
|
||||||
|
// canonicalising at assignment is one level too low and fixes nothing.
|
||||||
|
// 3. **A byte-exact replay needs the original's order, and the block already carries it.**
|
||||||
|
// List 10 records `{systemId, fleetId, ships[]}` per group in visit order, so every captured
|
||||||
|
// run states its own order for free. An optional override that replays a captured order is
|
||||||
|
// what turns "equal modulo a relabelling" into "equal" -- three words per new fleet, the same
|
||||||
|
// cost class as pinning a seed.
|
||||||
|
//
|
||||||
|
// Evidence: sots-re `findings/control-flow/fleet-visit-order-mechanism.md` (the container and its
|
||||||
|
// key, measured across three processes including a branch flip),
|
||||||
|
// `findings/control-flow/pinned-seed-rich-turn.md` (the residue),
|
||||||
|
// `findings/resolutions/2026-09-09-fleet-id-order-residue.md` (the ruling).
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// List 8. The route is a counted vector of system ids, so a multi-hop order is longer on the wire
|
// List 8. The route is a counted vector of system ids, so a multi-hop order is longer on the wire
|
||||||
// than a single-hop one -- but it is still ONE element and therefore ONE counter bump.
|
// than a single-hop one -- but it is still ONE element and therefore ONE counter bump.
|
||||||
struct FleetMoveOrder {
|
struct FleetMoveOrder {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue