re: the chatter phase merge is not additive; 224 authored variants never play

sub_82215A58 reads CrewCount + PresetMessage_Phase1/2/3 and reaches the loader
from ONE call site, so the three phase tables fold into one map keyed by the
event record name.  Every merge collides; sub_82213840 reconciles on the
message list plus +16/+17/+18/+20/+24/+28 (NOT the +32 Yes mask), and the
incumbent always wins.  Measured: 26432 collisions, 26208 identical, 224
different (189 differ only in the message list), 0 mask-only differences.

Refuted handle: intersecting functions by the object's offsets finds dozens of
unrelated layouts -- offset shape is not an identifier.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Claude (auto)
2026-08-27 16:50:42 +00:00
parent c4fd90baa9
commit 6ee041c1bf
5 changed files with 179 additions and 5 deletions

View File

@@ -4199,3 +4199,49 @@ event or per speaker, and what `IntervalFluctuation` randomises against all live
in the *consumer* of the 40-byte object, which this iteration did not read.
`Pattern`'s `Window` is named, not measured. Also still open from the earlier
entries: which of the 49 speakers are wingmen.
---
## ✅🔴 2026-08-27 — how the three phase tables merge, and one refuted handle
Continues the entry above. **Docs checked:** `preset-message-rules.md` (mine),
`mission-phase-deployment.md` and `mission-phase-membership.md` (they own
`UnitMessageSet_S<NN>.tbl` and its `CrewCount` + `PresetMessage_Phase1/2/3`
what they do **not** say is what happens when the three tables are loaded),
`idxd-tag-hash.md` (owns the hash family the map key comes from).
**The three phase tables become ONE map.** `sub_82215A58` references exactly
`CrewCount` and `PresetMessage_Phase1/2/3` and reaches the loader from a **single**
call site (`0x82215D98`). The map is keyed by a hash of the *event record's name*
(`sub_82455C78`). All 64 event names recur in every phase table, so **every merge
collides**.
**`sub_82213840` is the reconciliation comparator** — called from nowhere but
the loader. It compares the two message-id vectors elementwise plus `+16`
`Probability`, `+17` `Priority`, `+18` `Pattern`, `+20` `Interval`, `+24`
`IntervalFluctuation`, `+28` `EffectiveTime`. It does **not** compare `+32` (the
`Yes` mask) or `+36`. On a collision the loader frees the newcomer and keeps the
incumbent either way; a mismatch also clears the byte it returns, which the
caller propagates.
**Measured on disc** (regenerator extended, numbers in `data/preset-messages.txt`):
298 `UnitMessageSet` records name ≥2 phase tables; **26 432** duplicate-key
insertions; **26 208 (99.15 %)** identical; **224 different**, of which **189
differ only in the message list**. ⇒ **The phase tables are not additive**
phase 1 wins and **224 authored variants never play**. A port that merges
additively, or lets a later phase override, will not match the game.
**A negative worth keeping:** **zero** pairs agree on the six compared fields
while disagreeing on the `Yes` mask, so the comparator's exclusion of `+32`
changes nothing on the shipped disc. It looks like a latent bug until counted.
🔴 **Refuted handle for the firing policy.** I tried to find the consumer by
intersecting functions that touch `+16`/`+17`/`+18`/`+20`/`+28`/`+32`/`+36`.
It returns dozens of unrelated functions across the binary — **offset shape is
not an identifier**, which the corpus already warns about and I re-learned by
spending a query on it. The remaining handle is the map's consumer reached via
`sub_82215A58``sub_82214050`.
**Still open:** the firing policy proper (who rolls `Probability`, compares
`Priority`, ticks `Interval`, what `IntervalFluctuation` randomises); which of
the 49 speakers are wingmen.