re: UnitGroup member field n is a unit count, bounded by the formation
FormationSet_S<NN>.tbl records are slot lists -- 1 + 8*FrameCount fields, exactly. Resolving every squadron's FormationID and comparing gives sum(n) <= FrameCount holding 1159/1160 across all 28 stages, 0 unresolved, with 539 filling the formation exactly. The single violation is a debug leftover (S20, AI_Test / MessageSet_test, Formation_1_only with n=2) and is recorded. The old 'n is not the _NN suffix of FormationID' observation was right but drew the wrong conclusion: the suffix IS FrameCount, so n=9 against _30 just means 9 units in 9 of 30 slots. Also: FormationID does not hash into its table (0/16). FormationSet carries a name roster record -- no FrameCount, fields are (tag, name, '') with the tags being the record keys -- the same convention as Enumerate_Squadrons. Second occurrence of 'keys are resolved by an in-table roster, not by hashing'. Does not close the 387-vs-300 gap, and the key derivation stays open.
This commit is contained in:
@@ -62,9 +62,10 @@ Five named fields, always present and always these five:
|
||||
`UN_e007_ADAN_Turret`, `UN_bf001_TCAF_SchlosBase`.
|
||||
* message set — the squadron's radio chatter, e.g. `MessageSet_Ellen`,
|
||||
`MessageSet_ADAN_plA`.
|
||||
* `n` — 🟡 **unidentified**; integer 1…30, dominated by 1 (735) and 9 (197).
|
||||
It is *not* the `_NN` suffix of `FormationID` (`Formation_ADAN_Turret07_30`
|
||||
pairs with `n = 9`). Plausibly a spawn or wing size, untested.
|
||||
* `n` — ✅ **the number of units this tuple instantiates**, filling slots of the
|
||||
squadron's formation. Integer 1…30, dominated by 1 (735) and 9 (197). See
|
||||
*"What `n` counts"* below — the old note that it is "not the `_NN` suffix of
|
||||
`FormationID`" was right but drew the wrong conclusion.
|
||||
* identity — 63 distinct: named pilots (`ELLEN`, `SANDRA`, `RAYMOND`, `YOJI`),
|
||||
ship nameplates (`NP_Charon`, `NP_Amalthea`, `NP_Olympus`), carrier tags
|
||||
(`Carrier_ADAN01`), cargo tags (`CARGO_1`), or empty.
|
||||
@@ -120,3 +121,65 @@ missing S17 stage record.
|
||||
positions are not in this file. The next places to look are
|
||||
`Formation_*.tbl` (the formation geometry and possibly its timing) and
|
||||
`EnumSquadron_Test.tbl`, both named by the stage record.
|
||||
|
||||
|
||||
## ✅ What `n` counts — bounded by the formation, 1159 of 1160
|
||||
|
||||
`n` is the **number of units the member tuple instantiates**. The evidence is a
|
||||
hard, falsifiable inequality against a table `UnitGroup` never mentions.
|
||||
|
||||
`FormationSet_S<NN>.tbl` is the same IDXD container, and a formation record is a
|
||||
**slot list**: one named field `FrameCount` plus 8 positional fields per slot —
|
||||
`FrameCount = 4 → 33` fields, `14 → 113`, `30 → 241`, `32 → 257`, i.e.
|
||||
`1 + 8·FrameCount`, exactly.
|
||||
|
||||
Resolving each squadron's `FormationID` to its formation (below) and comparing:
|
||||
|
||||
```
|
||||
sum(n) <= FrameCount: HOLDS 1159 VIOLATED 1 unresolved 0
|
||||
of the holders, sum(n) == FrameCount exactly: 539
|
||||
```
|
||||
|
||||
Across all 28 stages, **every** `FormationID` resolves and **every** squadron
|
||||
but one fits its formation, with 46 % filling it exactly. A field unrelated to
|
||||
formation size would not do that.
|
||||
|
||||
**The one violation is a debug leftover**, recorded rather than swept up: S20
|
||||
(a tutorial stage), `Formation_1_only` (`FrameCount = 1`) with `n = 2` —
|
||||
`AIID = AI_Test`, `msg = MessageSet_test`, no identity, unit
|
||||
`UN_e015_ADAN_Puppy_2`. It is still a literal violation of the invariant.
|
||||
|
||||
### ✅ The formation name's trailing number IS `FrameCount`
|
||||
|
||||
`Formation_ADAN_Turret07_30` → `FrameCount = 30`; `Formation_TCAF_ArrowHead02_32`
|
||||
→ 32; `Formation_4_Bird` → 4 (leading, this family has no suffix). So the old
|
||||
observation that `n = 9` does not match the `_30` in
|
||||
`Formation_ADAN_Turret07_30` is correct and **not** evidence against `n` being a
|
||||
count: 9 units occupy 9 of that formation's 30 slots.
|
||||
|
||||
### ✅ How `FormationID` resolves — the same roster trick
|
||||
|
||||
`FormationID` does **not** hash into the table: `name_hash("Formation_4_Bird")`
|
||||
= `0x6286edad`, and the record key is `0x22a5eeed` — 0 of 16 resolve that way.
|
||||
`FormationSet_S02.tbl` has **17 records for 16 formations**, and the extra one is
|
||||
a **name roster**, exactly like `Enumerate_Squadrons` here: it carries no
|
||||
`FrameCount` and its fields are `(tag, name, "")` triples whose **tags are the
|
||||
record keys**. Find it by its missing `FrameCount`, map name → key, done.
|
||||
|
||||
That is the same convention twice in two different tables, which is worth
|
||||
remembering for the next one: **a table's record keys are resolved by a roster
|
||||
record inside the table, not by hashing the name.**
|
||||
|
||||
### 🟡 What this does not settle
|
||||
|
||||
* It shows `sum(n)` *fits* the formation, not that each unit is separately
|
||||
instantiated. "Slots consumed" and "units spawned" are indistinguishable here.
|
||||
* It does **not** close the 387-vs-~300 gap in
|
||||
[roster-to-craft-link](../roster-to-craft-link.md). Σ`n` over all of Stage 02
|
||||
is 387 against 296–300 live craft. That count was measured mid-mission after
|
||||
kills, and squadrons deploy across phases, so the two are not comparable as
|
||||
they stand — but the earlier note rejected `n = 387` as *the* craft count on
|
||||
the assumption that everything deploys at once, and that assumption is still
|
||||
untested.
|
||||
* The **key derivation** stays ❔. The roster makes it unnecessary, but the tag
|
||||
is not `name_hash`, so a second hash function is still unidentified.
|
||||
|
||||
@@ -32,6 +32,15 @@
|
||||
# emulator survives BETWEEN calls in a turn:
|
||||
# freeze_waitobj.sh boot [fly_s] boot, fly, capture `healthy`, leave running
|
||||
# freeze_waitobj.sh watch [secs] poll for the freeze, capture `frozen`
|
||||
# freeze_waitobj.sh run [fly_s] boot + healthy + watch, end to end
|
||||
#
|
||||
# `run` exists because the whole experiment does not fit one Bash call and a
|
||||
# `timeout` kills the process group -- it took the emulator down once. Launch it
|
||||
# detached (`nohup ... &`) and poll the log instead.
|
||||
#
|
||||
# SYLPH_INDUCE=1 starts heavy_read.py the moment flight begins, to test whether
|
||||
# the freeze follows our instrument rather than the mission (see the n=1 entry in
|
||||
# mission-freeze-resume-spin.md). The control is the same script without it.
|
||||
set -u
|
||||
export HOME=/sylph-home/re SDL_AUDIODRIVER=dummy DISPLAY=:98
|
||||
export PYTHONPATH=/sylph-home/.local/lib/python3.12/site-packages
|
||||
@@ -111,7 +120,7 @@ if [ "$MODE" = watch ]; then
|
||||
echo "NO FREEZE within ${SECS}s (still animating)"; exit 1
|
||||
fi
|
||||
|
||||
# ---- boot mode ----
|
||||
# ---- boot / run mode ----
|
||||
FLY="${FLY:-150}"
|
||||
"$SD/launch_mission.sh" fly || { echo "BOOT FAILED"; exit 1; }
|
||||
CFG=/tmp/nav-fz.json
|
||||
@@ -123,7 +132,17 @@ for t in 1 2 3; do
|
||||
</dev/null >/tmp/fz-pilot.log 2>&1 & echo "--- pilot flying"; break
|
||||
fi
|
||||
done
|
||||
if [ "${SYLPH_INDUCE:-0}" = 1 ]; then
|
||||
nohup python3 "$SD/heavy_read.py" 4000 2 cpu </dev/null >/tmp/heavy.log 2>&1 &
|
||||
echo "--- INDUCER ON from flight start ($(date +%T))"
|
||||
else
|
||||
echo "--- inducer OFF (control run)"
|
||||
fi
|
||||
echo "--- flying ${FLY}s to the healthy control capture"
|
||||
sleepfor "$FLY"; capture healthy
|
||||
python3 "$SD/waitobj_report.py" healthy
|
||||
echo "BOOT PHASE DONE -- emulator left running; now: freeze_waitobj.sh watch"
|
||||
echo "BOOT PHASE DONE -- emulator left running"
|
||||
if [ "$MODE" = run ]; then
|
||||
echo "--- watching for the freeze ($(date +%T))"
|
||||
exec "$0" watch "${WATCH_S:-1500}"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user