entities2.moving() finds entities by displacement between two samples, so anything stationary is invisible -- the entire explanation for the +/-10 swing that made the previous run's count useless. liveness_probe.py enumerates by definition pointer over the entity heap instead, moving or not, and reads hull as f32 at position+0x154. The series is monotone rather than oscillating: 298 -> 280 over 164 s, with the decline matching the 18 disappearance events exactly. The hunting pilot does kill: one hull crossing caught directly, an e010_ADAN_Attacker_S at t=57 s. The previous run's worry that SYLPH_HUNT shoots but never destroys anything is settled. Recorded as a non-result so the next run does not misread it: zero births in 164 s does NOT favour either wave model. The roster finding already established that every participant is allocated at mission load, so neither a clock nor an event model would produce an allocation. An arrival must be a state change on an existing entity. The mystery member field n now has a candidate meaning: the number of craft a roster member spawns. Static sum(n) for turrets is 216 against 214 sites found, with the count already falling before the first sample, where Count alone predicts 21 -- off by an order of magnitude. Not promoted, and the reason is a confound in my own measurement rather than the data: the probe counts definition-pointer SITES, not entities. The player is one member and yields two sites, and DeltaSaber_T yields exactly double its sum(n), so some entity types hold several pointers to their definition. Until sites are collapsed into distinct entities the turret match could be a coincidence between a x1 multiplicity and a x1 ratio. The capital-ship rows undershoot for a separate and expected reason: phases 2 and 3 have not started.
4.0 KiB
A motion-independent live roster — and what n probably is
Status: ✅ the enumeration method; ✅ the hunting pilot gets kills; 🔴 "no
births" cannot distinguish the wave models; 🟡 the member field n looks like a
craft count, with a confound that must be removed before believing it.
✅ Enumerate by definition pointer, not by motion
entities2.moving() finds entities by displacement between two samples, so
anything stationary in the window is invisible. That is the whole explanation
for the ±10 swing that made the previous run's entity count useless
(mission-wave-arrivals.md).
tools/re-capture/liveness_probe.py scans the entity heap
(0xBD000000–0xBE000000) for aligned words equal to a known unit-definition VA
instead. Moving or not, an entity is counted. Hull is f32 at
position + 0x154 (HULL_OFF, already confirmed in pilot.py), so a death is
a hull crossing to ≤ 0.
The difference is immediate — the series is monotone instead of oscillating:
t= 15s 294 alive born 0 died 0 gone 4
t= 36s 290 born 0 died 0 gone 4
t= 57s 289 born 0 died 1 gone 0 <- e010_ADAN_Attacker_S
t= 78s 286 born 0 died 0 gone 4
t=100s 286 born 0 died 0 gone 0
t=143s 282 born 0 died 0 gone 4
t=164s 280 born 0 died 0 gone 2
Total decline 298 → 280 = 18, matching the 18 "gone" events exactly.
✅ The hunting pilot kills
One hull crossing was caught directly — an e010_ADAN_Attacker_S at t = 57 s —
plus 18 disappearances. The previous run's worry that SYLPH_HUNT shoots but
never destroys anything is settled: it does.
🔴 "No births" does not separate the two wave models
Zero entities appeared in 164 s. That looks like evidence against clock-driven arrivals at t = 90/120 s — and it is not, because the roster finding already established that all of a mission's entities are allocated at load. If every participant exists from the first frame, then neither model produces a "birth", and the observation is consistent with both. Recorded so the next run does not mistake it for a result: an arrival must be a state change on an existing entity, not an allocation.
🟡 n looks like the number of craft per roster member
The member tuple's third field n has been ❔ since the roster was decoded.
Comparing the static sum(n) per unit type against what is resident:
| unit | members | sum(n) |
sites found |
|---|---|---|---|
UN_e007_ADAN_Turret |
21 | 216 | 214 |
UN_e105_ADAN_Cruiser |
7 | 7 | 6 |
UN_e106_ADAN_Destroyer |
19 | 19 | 14 |
UN_f105_TCAF_Cruiser |
11 | 11 | 4 |
UN_f106_TCAF_Destroyer |
14 | 16 | 10 |
UN_e010_ADAN_Attacker_S |
9 | 45 | 32 |
UN_f001_TCAF_DeltaSaber_T |
7 | 7 | 14 |
UN_f001_..._Player |
1 | 1 | 2 |
The turret row is striking: 216 predicted against 214 found, with the count
already falling before the first sample. Count alone predicts 21, which is
off by an order of magnitude. So n scaling a member into a flight of craft
fits the dominant unit type well.
It is not promoted, because the measurement has an unquantified confound.
The player is one member and yields two sites, and DeltaSaber_T yields
exactly double its sum(n) — so at least some entity types hold more than one
pointer to their definition. What the probe counts is definition-pointer sites,
not entities, and until those are collapsed into distinct entities the turret
match could be a coincidence between a ×1 multiplicity and a ×1 ratio. The
capital-ship rows undershoot instead, which is separately explained by phases 2
and 3 not having started.
Next
Collapse sites into entities before re-testing n — cluster sites by their
implied entity base and take distinct bases. Then the table above becomes a real
test rather than a suggestive one. The same de-duplication is a precondition for
using this probe to watch an arrival, since an arrival is now known to be a
state change rather than an allocation.