This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/mission-wave-arrivals.md
Sylpheed RE agent 8cc0b22967 re: diff inside the 116 entity records — no arrival flag found, two probe defects
Since the record count is flat, an arrival would have to flip a field inside a
record. This diffed all 116 records every 5 s for 170 s of Stage 02 flight.

The prediction under test -- groups of 3, 3, 3, 2, 1 records changing state at
t = 90, 120, 170, 210, 240 s -- did not appear. Changes are spread evenly across
ticks with no cluster at any predicted time and no field that transitions once
for exactly three records. Three explanations survive and this run cannot
separate them: the timetable's t is not seconds (at 30 Hz the whole phase-1
schedule finishes inside 8 s, before the first sample); arrival is not marked in
these records; or the mission was not in phase 1.

Supporting, not conclusive: only 10 of 116 records ever changed a byte, and 106
never changed at all. Live entities would be moving, so that fits the
pre-allocated roster reading -- but Stage 02's roster is turret-heavy and a
turret does not move while alive, so "inert" and "not yet arrived" are not
distinguishable here.

Two defects in my own probe, recorded rather than quietly fixed:

  - label() resolved to '?' for all 116 records, so nothing could be tied back
    to a squadron. That association is what would have made the result
    decisive -- "the three records that changed at t=90 are ADN110, ADN111,
    ADN112" is evidence; "records 18, 32, 99" is not. unit_discover.py already
    solves this and should be reused.
  - RECLEN=0x200 was assumed, not measured. The busiest fields are the last
    eight words of the window, which is what spilling into the next object
    looks like.

Method error kept: the first attempt deferred all analysis to the end and the
turn timeout killed it with 240 s of data in memory and nothing written. The
probe now streams transitions to disk and prints a partial ranking every 60 s.
With a 219 s cold-boot title movie, an end-only report has ~300 s of budget and
one bad estimate loses the whole run.
2026-08-24 12:21:48 +00:00

7.3 KiB
Raw Blame History

The arrival timetable, and what the entity table is really counting

Status: ✅ the static arrival timetable is in Route_S<NN>.tbl; 🟡 the runtime entity table appears to be one record per roster member, pre-allocated (n = 1); 🔴 counting entity records does not show wave arrivals; ❔ the timetable's time unit is still unmeasured.

✅ The arrival timetable is the routes' first keyframe time

Each record in Route_S<NN>.tbl starts with a time (structures/stage-mission-tables.md), and that time is not always zero. For Stage 02, grouping the 120 route records by phase and by first-frame time gives a timetable:

phase t=0 50 60 90 120 150 170 210 240
1 25 3 3 3 2 1
2 37
3 36 1 1 3 1 4

Phase 2 has every route at t = 0, which is the useful detail: it means t is measured from the start of its phase, not from the start of the mission. Entering a phase releases that phase's t = 0 group, and the rest arrive on the offsets above.

That is the "algorithm with parameters" this line of work was after: the schedule is data — squadron, phase, arrival time, and the path flown in — spread across UnitGroup (who) and Route (when and from where). Stage 02 phase 1 spawn points span x ∈ [-47371, 20800], y ∈ [-18856, 27395], z ∈ [-25349, 25036].

❔ The time unit is not measured. At 30 Hz, t = 240 is 8 s; as seconds it is 4 min. Distinguishing them was the point of the run below, and the run did not manage it.

🔴 Counting entity records does not show arrivals

One Stage 02 flight, 210 s sampled every 15 s, counting aligned occurrences of the spawned-entity vtable 0x820af030 (structures/unit-struct-runtime.md) in an 8.3 MB span of guest RAM:

t=0s 116   t=45s 116   t=90s 116   t=135s 116   t=180s 116   t=210s 116

Perfectly flat. No steps at 90, 120, 170, 210 or anywhere else. The hypothesis that a live entity count would step up at the timetable's offsets is refuted for this proxy — but the reason matters more than the refutation.

🟡 116 records, 116 roster members

UnitGroup_S02.tbl has 111 squadrons whose Count fields sum to 116 members. The entity table holds 116 records, from the first sample onwards.

The natural reading is that the game allocates one entity record per roster member when the mission loads, and that arriving on a route makes an existing record active rather than creating a new one. That would explain the flat count exactly, and it would mean 0x820af030 records are a roster, not a live population — consistent with the existing note in unit-struct-runtime.md that these records are "not live state".

This is one data point and must not be promoted on it. 116 = 116 is a striking match but n = 1, and the obvious refutation has not been run: load a different stage and check the record count against that stage's member sum (S01 = 42, S10 = 14, S16 = 2, S29 = 95). S16 with 2 members would be decisive and cheap if a save for it existed — the only save slot available is Stage 02, which is the blocker.

What this run did not settle

  • The timetable's time unit (frames vs seconds).
  • Whether arrivals are visible at all from memory, and where. The live/dead flag is presumably a field inside the 116 records; diffing those records over a mission is the obvious next probe, and it is well scoped now that the record set is bounded and located.
  • Whether the 116↔116 match generalises.

Operational note

Cold, the boot spent 204 s in the title movie before the first Ⓐ — the wait_screen oracle correctly refused to tap through it. A 300 s probe plus that boot exceeded a 580 s turn budget and the first attempt was killed with its output still in the pipe. Log runs to a file (> /tmp/x.log 2>&1) rather than piping to tail, or a timeout loses the evidence as well as the run.


Follow-up: diffing inside the 116 records (2026-08-24)

Status: 🟡 supporting evidence for the pre-allocated-roster reading; 🔴 the arrival flag was not found; 🔴 two defects in my own probe recorded.

The count being flat meant an arrival must flip a field inside a record, so this diffed all 116 records (0x200 bytes each) every 5 s for 170 s of Stage 02 flight, under the pilot. tools/re-capture/wave2_probe.py.

🟡 Only 10 of 116 records are dynamic

Across the whole run, 10 distinct records ever changed a byte. The other 106 never changed at all — not one word, over 170 s of live mission.

That is a second, independent line of support for the reading in the section above: if all 116 were live entities they would be moving, and position words would churn in most of them every tick. Instead the overwhelming majority are inert, which is what a pre-allocated roster of not-yet-activated members looks like. It is still not proof — Stage 02's roster is heavy with UN_e007_ADAN_Turret entries, and a turret does not move even when it is very much alive, so "inert" and "not yet arrived" are not distinguishable from this run alone.

🔴 No transition matching the arrival timetable

The prediction under test was groups of 3, 3, 3, 2, 1 records changing state at t = 90, 120, 170, 210, 240 s. Nothing of the sort appeared. Field-change events are spread evenly across ticks (1–7 words per 5 s tick, 1052 in total), with no cluster at any predicted time and no field that transitions once for exactly three records.

So one of these is true, and this run cannot say which:

  • the timetable's t is not seconds (at 30 Hz the whole phase-1 schedule finishes inside the first 8 s, before the probe's first sample);
  • arrival is not marked in the 0x820af030 record at all;
  • phase 1 was not where the mission actually was during the run.

🔴 Two defects in this probe

  • label() failed for all 116 records — every one resolved to ?. The object+0x04 → name_record+0x10 → char* chain from structures/unit-struct-runtime.md did not resolve here. Without labels the records cannot be tied back to squadrons, which is exactly what would have made the result decisive: "these three records that changed at t=90 are ADN110, ADN111, ADN112" is evidence, "records 18, 32, 99" is not. unit_discover.py already solves this association and should be reused rather than re-derived.

  • RECLEN = 0x200 is probably too wide. The busiest fields by far are +0x1e0 … +0x1fc — the last eight words of the window — which is what spilling into the next object looks like. The record's true size was assumed, not measured.

  • A method error worth keeping: the first attempt deferred all analysis to the end of the run, and the turn's timeout killed it with 240 s of collected data still in memory and nothing written. The probe now streams every transition to /tmp/wave2-trans.tsv and prints a partial ranking every 60 s. Combined with the 219 s cold-boot title movie, a run that only reports at the end has perhaps 300 s of usable budget and one bad estimate loses everything.

Next

Fix the record→squadron association first (reuse unit_discover.py), and measure the record stride instead of assuming 0x200. Until a record can be named, no diff of these records can confirm or refute an arrival.