re: motion-independent liveness probe; n looks like craft-per-member

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.
This commit is contained in:
Sylpheed RE agent
2026-08-24 13:01:19 +00:00
parent 08352d09ac
commit 356c4e70f8
4 changed files with 194 additions and 0 deletions

View File

@@ -320,6 +320,16 @@ search cannot find a *schedule*.
record per member (n=1, NOT promoted; the refutation needs another stage's
save, which we do not have — only slot 01 / Stage 02 exists).
❔ Still unmeasured: whether the timetable's `t` is frames or seconds.
* ✅🟡 **Motion-independent liveness probe works; `n` is probably craft-per-member**
(2026-08-24) — [`mission-liveness-probe.md`](mission-liveness-probe.md).
Enumerating by definition pointer instead of by motion removes the ±10 noise
(monotone 298→280). The hunting pilot **does** kill (hull crossing at t=57s).
🔴 "No births in 164 s" does NOT separate the wave models — everything is
pre-allocated, so an arrival must be a STATE CHANGE, not an allocation.
🟡 Turret `sum(n)`=216 vs 214 sites found (vs `Count`=21) suggests the mystery
member field `n` is the craft count per member — NOT promoted: the probe counts
definition-pointer *sites*, and the player (1 member → 2 sites) proves some
entities hold several. **Next: collapse sites into entities, then re-test.**
* 🟡 **COMPETING MODEL (user, 2026-08-24): waves are event-gated, not
clock-driven** — released by kills/objectives rather than at a fixed time, with
the route's start time being a post-trigger delay. Fits the evidence better:

View File

@@ -0,0 +1,86 @@
# 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](mission-wave-arrivals.md)).
`tools/re-capture/liveness_probe.py` scans the entity heap
(`0xBD0000000xBE000000`) 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.