# ✅ The two enumerations are two different structures — and only one is complete Measured 2026-08-26, live flight HUD, movers precondition checked (18 002). ## The stage changed between runs — earlier cross-run comparisons were invalid `LOAD GAME → slot 01` did **not** land on the same mission it did earlier today. This run's definition table has **14** entries and no asteroids at all: ``` UN_bf001_TCAF_SchlosBase UN_f101_TCAF_Acropolis UN_f201_TCAF_Tanker UN_e105_ADAN_Cruiser UN_e106_ADAN_Destroyer UN_e108_ADAN_ASFrigate UN_e201_ADAN_ISCMissile UN_f003_TCAF_ArrowHead UN_f105/f106 TCAF ... ``` That is the **Stage 02 escort mission** (the `ACROPOLIS` of [`autopilot-memory-driven.md`](autopilot-memory-driven.md)), not the S01 training area with `UN_S01_Asteroid_cmesh_*` that earlier runs loaded. Slot 01 is the **auto-save**, so the mission it restores moves as the save is written. ❌ **This invalidates the earlier "101 vs 42" comparison outright** — those two numbers came from *different stages*, not merely different moments. And it means no runtime roster is reproducible across runs unless the stage is verified first. ## Same moment, same stage, both methods | type | `INST_VTABLE` scan | moving + `+0x130` | |---|---|---| | `UN_e007_ADAN_Turret` | 21 | 14 | | `UN_e010_ADAN_Attacker_S` | 9 | 8 | | `UN_f001_TCAF_DeltaSaber_T` | 7 | 7 | | `UN_f001_TCAF_DeltaSaber_T_Player` | 1 | 1 | | `UN_e106_ADAN_Destroyer` | 19 | **0** | | `UN_f106_TCAF_Destroyer` | 14 | **0** | | `UN_f105_TCAF_Cruiser` | 11 | **0** | | `UN_e105_ADAN_Cruiser` | 7 | **0** | | `UN_e108_ADAN_ASFrigate` | 9 | **0** | | `UN_e201_ADAN_ISCMissile` | 9 | **0** | | `UN_f003_TCAF_ArrowHead` | 6 | **0** | | `UN_f101_TCAF_Acropolis` / `bf001_SchlosBase` / `f201_Tanker` | 1 each | **0** | | **total** | **116** | **30** | ## ✅ The absence is structural, not a filter artifact The obvious explanations were tested and **both fail**: * **Speed band.** `moving()` filters displacement to `lo=1.0 … hi=4000.0` per 0.5 s, which would exclude a slow capital ship. Dropping the floor to **0** and the ceiling to 1e12 raised the count 30 → 59 and recovered the `_Player` — but still **only 4 types**. Capital ships never appear. * **Address window.** `moving()` defaults to `0xBD000000–0xBE000000`. Scanning the **whole map** with no speed floor gives 181 824 movers and **still 4 types**. So the ten missing types do not have a definition pointer at `position + 0x130` anywhere in memory that a moving-triple scan can reach. **The `+0x130` block is not the universal entity record — it belongs to a subset.** 🟡 The subset is *nearly* "small craft": every type it does cover is a fighter, attacker or turret. But `UN_f003_TCAF_ArrowHead` is a TCAF fighter and reads **0**, so "small craft" is not the rule. ❔ What actually distinguishes them is not established — plausibly an active-flight-model flag, with parked wingmen and capital ships handled by a different update path. ## ✅ They live in different regions, which is why they are different structures ``` vtable instances : 0xbc372cc0 .. 0xbc9bc720 (116) ENT_VA window : 0xbd000000 .. 0xbe000000 instances inside that window : 0/116 ``` **Zero** of the 116 vtable objects lie in the window where the `+0x130` position blocks are found. This is independent confirmation of [the earlier refutation](entity-position-anchor-refuted.md): the vtable object and the position block are separate allocations in separate regions, not two views of one record. ## Which list to use * **Completeness** — the `INST_VTABLE` scan. It sees all 14 types including stations, capital ships and the objective-critical `Acropolis`. * **Motion state** — the `+0x130` blocks. They carry position, speed, orientation (`pos−0x70`, stride 16) and hull (`pos+0x154`), but only for ~4 types. * An autopilot that must protect the `Acropolis` **cannot** locate it through the `+0x130` method at all. That is a concrete limit on the existing approach. ## Also confirmed The exact **2× duplication** reappeared: def-pointer hits come in pairs `0x1000` apart with byte-identical positions (`0x011db3bd80` / `0x011db3cd80`, both `(-1654.7, -3992.7, 458.2)`, both moving 424.482). ❌ It is **not** page aliasing in `gmem.MAP` terms — aliased VAs share one *file offset*, and these differ by `0x1000` in the offset itself, so they are genuinely two copies. ❌ **Correction to [the previous note](entity-count-discrepancy-resolved.md):** it said "at least one of the counts was un-deduplicated". That is wrong — `entities2.py` prints its count *after* `ents = list(uniq.values())`, so the 101 was already deduplicated. The gap was the stage change, not duplication.