Files
Sylpheed/docs/re/entity-position-anchor-refuted.md
Sylpheed RE agent 0256d71e78 re: refute my own position anchor, withdraw the entities2 "defect", find the trap
Three results, two of them against my own earlier claims:

 - REFUTED: position = instance - 0x12c.  The corpus anchors on position (def ptr
   at +0x130, orientation at -0x70, hull at +0x154) and name_of reads the def ptr
   at instance+4, which predicts -0x12c.  Measured over all 42 named instances:
   almost every read is (0,0,0), three are garbage, and 0/42 move.  The vtable
   object and the position block are different structures.

 - WITHDRAWN: last iteration's claim that entities2.py's ENT_VA window is aimed at
   the definitions rather than the instances.  entities2 does not look for vtable
   objects at all -- it hunts moving position triples and checks +0x130, the
   documented anchor -- and it had worked minutes earlier (6914 movers, +0x130
   voted 92x; then 6634/138x).  I built the defect report on the single sample in
   between that returned zero.  The +0x29d0 position candidate falls with it.

 - FOUND: sampling 64 spots across the 505 extents (357 MB) twice, 2.5s apart,
   with the mission visibly running, only 5 change.  The megabyte holding all 42
   instances is byte-identical over seconds, as is its primary-VA counterpart.
   The mapping IS live (5 regions prove it); what is undetermined is whether the
   entity records are simply static or whether writes land in a different alias.
   Either way: verify a region changes before measuring through it.
2026-08-26 21:36:47 +00:00

4.2 KiB
Raw Permalink Blame History

Two of my own claims, refuted — and a live-memory trap behind both

Measured 2026-08-26, Canary on the retail disc, save slot 01, Stage 01, in flight with a live HUD (TIME 00:28.42, speed 350, target on radar, dialogue mid-render — the game was unambiguously running throughout).

Refuted: position = instance 0x12c

The corpus anchors the entity layout on position: autopilot-memory-driven.md gives the definition pointer at position + 0x130, orientation at position 0x70, hull at position + 0x154. gworld.py's name_of() reads the definition pointer at instance + 4. If those name the same field, instance + 4 = position + 0x130, so position = instance 0x12c.

They do not. Read at instance 0x12c for all 42 named instances:

UN_f001_TCAF_DeltaSaber_T_Player   (     0.0,      0.9,      0.1)   moved 0.00
UN_e106_ADAN_Destroyer             (   -48.9,      0.0,      0.0)   moved 0.00
UN_S01_Asteroid_cmesh_01a          (2.07e11,      0.0,      0.0)   moved 0.00
...
moved in 0.8 s : 0/42

Almost every read is (0, 0, 0), three are garbage, and nothing moves. The vtable-bearing object and the position block are two different structures that merely name the same units. The prediction was clean and it was wrong.

Withdrawn: "entities2.py's VA window is aimed at the wrong region"

Last iteration I recorded ENT_VA_LO/HI = 0xBD0000000xBE000000 as a defect, on the grounds that the live instances sit at 0xBC384CE00xBC9BAC20 and the window "covers the definitions instead".

That reasoning was wrong. It assumed the thing the window should contain is the vtable-bearing instance — but entities2.py does not look for those. It hunts moving position triples and checks +0x130 for a definition pointer, exactly the documented anchor. And in the run where I called it broken it had worked moments earlier: 6914 movers, +0x130 voted 92×, then 6634 and 138× on a re-run. I built a defect report on the one sample in between that returned zero — the same single-sample error this corpus keeps logging.

The window may still be imperfect (it is hardcoded, and the heap moves). But it is not "aimed at the definitions", and nothing here shows it needs changing.

🟡 The +0x29d0 position candidate is not trustworthy either

It was read through the same region that is shown below not to be updating, so what it captured is load-time data, not a live position. Withdrawn pending a re-measurement through a region that demonstrably changes.

The trap: most of guest memory is not changing while the game runs

Sampling 64 spots of 64 KB spread across the mapping's 505 extents (357 MB), twice, 2.5 s apart, with the mission visibly running:

CHANGING: 5 / 64
   0x007006f000   0x00704db000   0x0070557b000   0x00705df000   0x0080240000

Everything else — including the megabyte containing all 42 live instances (0x11c37d780), and that region's primary-VA counterpart at 0x00bc300000 — is byte-identical over seconds. So:

  • The mapping is live. Five regions prove it, so "the shm view is stale" as a blanket claim is refuted.
  • The entity-object region genuinely does not change on a seconds timescale.
  • Not determined: whether that is because those records are static metadata and the moving state lives elsewhere, or because the guest physical page is aliased at several file offsets and writes land in a different one. Both fit the evidence. gmem.primary_va(0x11c384ce0) = 0xbc384ce0 shows the alias relationship exists; it does not show which copy the guest writes.

Consequence for anyone reading guest memory here: verify the specific region you are sampling actually changes before drawing conclusions from it. A scan that finds correct, name-resolving records can still be reading a snapshot.

Still open

  • Where the live position blocks are. The five changing offsets above are the place to start, but moving() takes VAs and converts with gmem.va_to_off, while those five are file offsets — they are not the same number and must be converted before they can be scanned.
  • Whether entities2.py's window needs any change at all.