Files
BT411/scratchpad/wf_0_MessageBoard_decode.md
T
arcattackandClaude Opus 4.8 4a4ec6855c gauge-complete P4e: SectorDisplay reconstructed + registered -> radar SECTOR X/Z read-out LIVE
The "sectorDisplay" cockpit primitive (Secondary overlay, the radar SECTOR X/Z
coordinate read-out) was PROSE-ONLY in btl4gau3 (placeholder Make, no ctor/
methodDescription/registration) -> the config line was parse-SKIPPED and never built.

Reconstructed byte-verified from the disassembly (ctor @4c9e10, Execute @4ca07c,
methodDescription PE-parse): SectorDisplay : GraphicGauge, sizeof 0xC4. Its Execute
reads the linked mech's world position and shows two 100-unit sector numerics:
  numericA = Round(-localOrigin.z * 0.01) + 500
  numericB = Round( localOrigin.x * 0.01) + 500
(rounding = round-to-nearest == FUN_004dcd94, corrected from the reviewer's wrong
"truncate" claim; 0.01 const PE-verified; -Z/+X axis + fchs confirmed from asm).
Overridden slots: LinkToEntity(9) caches the subject, BecameActive(3, non-inactivating),
Execute(16) -> satisfies the container-Execute rule. Layout overflow-locked
(static_assert sizeof<=0xC4). Make/ctor/dtor mirror the registered PilotList sibling;
the config image name is copied (nameCopy) since Execute reads it per-frame.
Registered in BTL4MethodDescription[].

VERIFIED LIVE (BT_SECTOR_LOG): Make port=1 pos=(125,579) image=helv15.pcc gridCached=1;
Execute -Z=960.4 X=361.6 -> sectorA=510 sectorB=504 (Round(9.6)+500=510, Round(3.6)+500=504
-- authentic 100-unit sectors from live mech position). Gauge composite renders full,
no crash. The skip list is now exactly the two remaining widgets (prepEngr x12, messageBoard).

Also: a permanent BT_GAUGE_SKIP_LOG diagnostic (GAUGREND.cpp, gated) that logs each
unregistered gauge primitive the dev-parse skips -- the tool that pinned this down
(earlier "not built" runs were killed before the lazy gauge-renderer init).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 21:25:48 -05:00

332 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
I have fully traced the widget. Here is the complete implementation spec.
---
# MessageBoard — Cockpit Gauge Widget Decode & Reconstruction Spec
**Verdict up front:** `MessageBoard` is *already fully declared* in `game/reconstructed/btl4gau3.hpp` and *documented in prose* in `btl4gau3.cpp`, but has **no method bodies, no `methodDescription`, and no registration** → the CFG keyword `messageBoard` is currently **parse-skipped**. This spec supplies the byte-exact bodies + registration, **corrects three field mislabels** in the existing header, and **confirms the data is DEFERRED (empty board)** — with a correction to the task hint about *which* subsystem is the blocker.
---
## 1. Identity
| Property | Value | Evidence |
|---|---|---|
| Class name | `MessageBoard` | id string `s_MessageBoard_0051bb61` (`part_014.c:3835`); already in `btl4gau3.hpp:260` |
| Base class | `GraphicGauge` (→ `Gauge`) | base ctor `FUN_00444818` (`part_014.c:3857`); `engine/MUNGA/GAUGE.h:400` |
| Config keyword | `"messageBoard"` | `content/GAUGE/L4GAUGE.CFG:4913` (1 use, in `Secondary1`) |
| **Make** | `@004cb678` = `FUN_004cb678` | `part_014.c:3825-3843` |
| **ctor** | `@004cb704` = `FUN_004cb704` | `part_014.c:3849-3866` |
| **dtor** | `@004cb788` = `FUN_004cb788` | `part_014.c:3872-3886` |
| **TestInstance** | `@004cb7e4` (→ `FUN_004448ac` = `GraphicGauge::TestInstance`) | `part_014.c:3892-3897` |
| ShowInstance (empty no-op vtbl slot) | `@004cb7f4` (bare `return`) | `part_014.c:3903-3907` |
| **BecameActive** | `@004cb7fc` = `FUN_004cb7fc` | `part_014.c:3913-3919` |
| **SetSource** (setter; **not** `SetEnable`) | `@004cb818` = `FUN_004cb818` | `part_014.c:3925-3930` |
| **Execute** | `@004cb82c` = `FUN_004cb82c` | `part_014.c:3936-4013` |
| vtable | `PTR_FUN_0051bddc` | ctor `part_014.c:3858`, dtor `:3876` |
| **sizeof** | **`0xA4`** (== Make alloc `FUN_00402298(0xa4)`) | `part_014.c:3832` |
| GUID | none | — |
There is **no `methodDescription` in the binary** for this widget (the binary's Make read raw `DAT_0051b43c..0051b508`); like `PlayerStatus`/`PilotList`/`VertTwoPartBar`, the reconstruction supplies a `methodDescription` and rewires Make to read `methodDescription.parameterList[]`.
---
## 2. What it DISPLAYS + the data binding (DEFERRED — blocker confirmed)
**What it draws:** the secondary MFD's **comm/status message ticker**. Two 128×32 cells at the port origin (`SetOrigin(x,y)`, `offset=(113,607)`):
- **Message cell** (view-rel `(0,0)`): blits one cell of the strip bitmap `btsmsgs.pcx`. Message id → grid cell `col = id&3` (×128 px), `row = id>>2` (×32 px): `srcRect = [cellX, cellY, cellX+0x7f, cellY+0x1f]` (`part_014.c:3969-3979`). `id == -1` → clear the cell to `color` (`:3963-3967`).
- **Name cell** (view-rel `(0x80,0)`): blits the *sender's* name bitmap from the App name/palette cache (`part_014.c:3983-4008`).
**The data source it reads (decoded from `FUN_004cb82c`):**
```
source = this->trackedMech // this[0x24] @0x90 (set by SetSource @004cb818)
player = *(source + 0x190) // mech -> owning BTPlayer (:3949 == MECH_OWNING_PLAYER)
msg = *(player + 0x1dc) // BTPlayer's current status-message record (:3951)
msg == 0 -> messageId = -1, nameEntity = 0 (:3952-3955)
else -> nameEntity = *(msg+0x10), messageId = *(msg+0xc) (:3957-3958)
nameEntity -> +0x1e0 = palette/name key -> App+0xc8 name-bitmap cache lookup (:3992-3994, 4002-4004)
```
`mech+0x190 = owningPlayer (BTPlayer*)` is confirmed by `btplayer.cpp:68` and the `MECH_OWNING_PLAYER` macro; `TeamStatusDisplay` uses the same `mech+0x190` (`btl4gau3.cpp:167`).
**Is the data LIVE now? NO — DEFERRED. Two independent blockers:**
1. **The source is never bound.** `SetSource` (`FUN_004cb818`, the *only* writer of `this[0x24]` besides the ctor's `=0`) has **zero recovered callers** (grep across `reference/decomp/all` returns only its own definition). The Make **ignores** its `entity` param (`FUN_004cb678` never touches `param_4`), so nothing binds a mech at construction either. → `trackedMech` stays `NULL` → the whole Execute body is gated `if (source != 0 …)` (`part_014.c:3949`) → **no-op**.
2. **The message-record feed is a NULL stub.** The record at `BTPlayer+0x1dc` is populated only by `AddStatusMessage(Player__StatusMessage*)`, and that is gated on `StatusMessagePool`**a NULL bring-up stub** (`btplayer.cpp:135` `extern MemoryBlock *StatusMessagePool;`, guarded at `:508` `if (sender_owner && StatusMessagePool)`). No status messages are ever created, so even a bound mech would read `msg == 0` → messageId `-1` → empty.
**⚠ Correction to the task hint:** the source is **NOT** the `SubsystemMessageManager` (0xBD3). That class *is* reconstructed (`game/reconstructed/messmgr.cpp`) but it is the **per-mech DAMAGE/explosion hub** (`ConsolidateAndSendDamage`, `weaponExplosions`, `commonDamageInformation`) — its fields are damage records, not `{msgId, nameEntity}`, and the MessageBoard never references it. The real source is the **`BTPlayer` status-message queue** (`Player__StatusMessage`, `btplayer.cpp:513`) gated by `StatusMessagePool`. **That pool is the blocker to name.**
---
## 3. Class layout (byte-exact) + locks
`GraphicGauge` base ends at `0x90` (`Gauge` 0x48 + `GraphicsView localView` 0x48; confirmed by every sibling: `VertTwoPartBar` first field `tileImage@0x90`, `btl4gaug.cpp:1138`). MessageBoard adds `this[0x24..0x28]`:
```cpp
class MessageBoard : public GraphicGauge {
...
protected:
Entity *trackedMech; // @0x90 this[0x24] source mech (SetSource); ctor=0 ⟵ WAS "int enabled" (MISLABEL)
char *stripImage; // @0x94 this[0x25] interned "btsmsgs.pcx" (held bitmap ref)
int color; // @0x98 this[0x26] param_10 (CFG 4th arg = 0)
int previousNameId; // @0x9C this[0x27] BecameActive=-1 ⟵ WAS "previousMessageId" (SWAPPED)
int previousMessageId; // @0xA0 this[0x28] BecameActive=-2 ⟵ WAS "previousNameId" (SWAPPED)
friend struct MessageBoardLayoutCheck;
};
```
**Three header corrections** vs the current `btl4gau3.hpp:273-279`:
- `int enabled`**`Entity *trackedMech`** (it's a pointer dereferenced `*(src+0x190)` at `:3949`, not a bool; the setter is `SetSource`, not `SetEnable`).
- `previousMessageId`/`previousNameId` are **swapped**. Proof: BecameActive writes `+0x9c=-1`, `+0xa0=-2` (`:3916-3917`); Execute's *message-id* compare is against `+0xa0` (`:3960`) and the *name-entity* compare against `+0x9c` (`:3983`). So `+0x9c=previousNameId(-1)`, `+0xa0=previousMessageId(-2)`. (The prose at `btl4gau3.cpp:784` already states "previousNameId=-1; previousMessageId=-2" — the struct labels contradict the prose.)
**Locks (add to `btl4gau3.cpp`; protected members ⇒ `friend struct`):**
```cpp
struct MessageBoardLayoutCheck {
static_assert(sizeof(GraphicGauge) == 0x90, "GraphicGauge base size");
static_assert(offsetof(MessageBoard, trackedMech) == 0x90, "trackedMech");
static_assert(offsetof(MessageBoard, stripImage) == 0x94, "stripImage");
static_assert(offsetof(MessageBoard, color) == 0x98, "color");
static_assert(offsetof(MessageBoard, previousNameId) == 0x9C, "previousNameId");
static_assert(offsetof(MessageBoard, previousMessageId)== 0xA0, "previousMessageId");
static_assert(sizeof(MessageBoard) == 0xA4, "MessageBoard sizeof == Make alloc 0xa4");
};
```
---
## 4. Full method bodies to write
### 4.0 CFG call shape → `methodDescription`
`content/GAUGE/L4GAUGE.CFG:4912-4917`:
```
offset = (113,607);
messageBoard(
E, # p[0] rate
ModeAlwaysActive, # p[1] mode mask
btsmsgs.pcx, # p[2] strip bitmap
0 # p[3] draw/erase color
);
```
`offset` supplies `position` (x=113, y=607) to Make (the ctor's `SetOrigin`). 4 in-paren params:
```cpp
MethodDescription
MessageBoard::methodDescription =
{
"messageBoard",
MessageBoard::Make,
{
{ ParameterDescription::typeRate, NULL }, // p[0] rate (E)
{ ParameterDescription::typeModeMask, NULL }, // p[1] mode (ModeAlwaysActive)
{ ParameterDescription::typeString, NULL }, // p[2] strip bitmap (btsmsgs.pcx)
{ ParameterDescription::typeColor, NULL }, // p[3] draw/erase color (0)
PARAMETER_DESCRIPTION_END
}
};
```
### 4.1 Deferred data bridge (declare near top of `btl4gau3.cpp`)
```cpp
// Resolve the viewpoint player's current HUD status message for `tracked_mech`.
// Returns True if the mech has a bound owning-player record; fills:
// *messageId -- btsmsgs.pcx strip cell index (-1 = no active message)
// *nameBitmap -- sender's name bitmap (NULL = none / App name-cache not wired)
// DEFERRED: StatusMessagePool (btplayer.cpp) is a NULL stub + BTPlayer+0x1dc is
// never populated, so this returns False today -> the board stays empty. Reads
// the raw BTPlayer/StatusMessage offsets in a COMPLETE-BTPlayer TU (never here),
// dodging the databinding trap. Implement in btplayer.cpp / btl4mppr.cpp.
extern Logical BTResolveMessageBoard(Entity *tracked_mech, int *messageId, BitMap **nameBitmap);
```
(Provide a stub `Logical BTResolveMessageBoard(Entity*, int *id, BitMap **bmp){ *id=-1; *bmp=NULL; return False; }` in `btplayer.cpp` until the feed lands — mirrors `LookupPlayerNameBitmap`/`BTResolveRosterPilot`.)
### 4.2 Make — `@004cb678`
Alloc `0xa4`, construct, then presence-check the strip bitmap (`FUN_00442aec` Get / `FUN_00442c12` Release) and return whether it exists. `param_5`=renderer, `param_5+0x4c+4`=`bitMapBin`.
```cpp
Logical
MessageBoard::Make(
int display_port_index,
Vector2DOf<int> position,
Entity * /*entity -- ignored by the binary (FUN_004cb678)*/,
GaugeRenderer *gauge_renderer
)
{
ParameterDescription *p = methodDescription.parameterList;
MessageBoard *gauge = (MessageBoard *)operator new(0xa4); // FUN_00402298(0xa4)
if (gauge != NULL)
{
new (gauge) MessageBoard(
p[0].data.rate, p[1].data.modeMask,
(L4GaugeRenderer *)gauge_renderer,
display_port_index, // graphics_port_number
position.x, position.y, // x, y (offset=(113,607))
p[2].data.string, // strip image (btsmsgs.pcx)
p[3].data.color, // color (0)
"MessageBoard");
}
// Presence-check the strip bitmap (binary returns this as the Make result).
L4Warehouse *wh = (L4Warehouse *)gauge_renderer->warehousePointer; // renderer+0x4c
BitMap *strip = wh->bitMapBin.Get(p[2].data.string); // FUN_00442aec
if (strip == NULL)
return False;
wh->bitMapBin.Release(p[2].data.string); // FUN_00442c12
return True;
}
```
### 4.3 ctor — `@004cb704`
```cpp
MessageBoard::MessageBoard(
GaugeRate rate, ModeMask mode_mask, L4GaugeRenderer *renderer_in,
int graphics_port_number, int x, int y,
const char *strip_image, int color_in, const char *identification_string)
: GraphicGauge(rate, mode_mask, renderer_in, 0, // FUN_00444818 (owner 0 folded in)
graphics_port_number, identification_string)
{
// vtable PTR_FUN_0051bddc set by the base->derived chain.
stripImage = new char[strlen(strip_image) + 1]; // FUN_004700ac (intern a private copy)
strcpy(stripImage, strip_image);
L4Warehouse *wh = (L4Warehouse *)renderer_in->warehousePointer;
wh->bitMapBin.Get(stripImage); // FUN_00442aec (hold a ref for life)
localView.SetOrigin(x, y); // this+0x48 vtbl+0x10
color = color_in; // this[0x26]
trackedMech = NULL; // this[0x24] (param_1[0x24]=0, :3864)
// previousNameId / previousMessageId set by BecameActive (byte-faithful).
}
```
### 4.4 dtor — `@004cb788`
Release the strip ref (keyed on the name, **before** the free), free the name; **do not** write the base-dtor call (compiler emits `FUN_00444870`).
```cpp
MessageBoard::~MessageBoard()
{
L4Warehouse *wh = (L4Warehouse *)renderer->warehousePointer;
wh->bitMapBin.Release(stripImage); // FUN_00442c12
delete[] stripImage; // FUN_004022e8
stripImage = NULL;
}
```
### 4.5 TestInstance — `@004cb7e4`
```cpp
Logical MessageBoard::TestInstance() const { return GraphicGauge::TestInstance(); } // FUN_004448ac
```
(`@004cb7f4` is an empty no-op virtual slot — `ShowInstance`; omit it and inherit, as `PlayerStatus`/`PilotList` do.)
### 4.6 SetSource — `@004cb818` (retained; no recovered caller ⇒ deferred)
```cpp
void MessageBoard::SetSource(Entity *mech) { trackedMech = mech; } // this[0x24] = param_2
```
### 4.7 BecameActive — `@004cb7fc`
```cpp
void MessageBoard::BecameActive()
{
previousNameId = -1; // this[0x27] @0x9c (0xffffffff, :3916)
previousMessageId = -2; // this[0x28] @0xa0 (0xfffffffe, :3917)
}
```
### 4.8 Execute — `@004cb82c` (safe reconstruction; faithful draw path via the bridge)
```cpp
void MessageBoard::Execute()
{
// FAITHFUL LITERAL: the board only draws while a source mech is bound. The
// binder (SetSource @004cb818) has no recovered caller AND the per-player
// status feed (StatusMessagePool, btplayer.cpp) is a NULL stub, so trackedMech
// stays NULL and Execute is a safe no-op == the DEFERRED / empty board.
if (trackedMech == NULL) // binary gate :3949
return;
// Message record via the safe bridge (NOT raw *(mech+0x190)/+0x1dc offsets:
// the databinding trap -- our compiled BTPlayer/StatusMessage layout != 1995).
int messageId = -1;
BitMap *nameBitmap = NULL;
BTResolveMessageBoard(trackedMech, &messageId, &nameBitmap);
// --- message strip cell (:3960-3981) -------------------------------------
if (messageId != previousMessageId)
{
previousMessageId = messageId;
localView.MoveToAbsolute(0, 0); // vtbl+0x24 :3962
if (messageId == -1) // no message -> clear
{
localView.SetColor(color); // vtbl+0x18 :3964
localView.DrawFilledRectangleToRelative(0x80, 0x20); // vtbl+0x4c :3966
}
else
{
int cellX = (messageId & 3) << 7; // :3969
int cellY = (messageId >> 2) << 5; // :3970
localView.SetColor(7); // FUN_004c2f88()==7 :3971
L4Warehouse *wh = (L4Warehouse *)renderer->warehousePointer;
BitMap *strip = wh->bitMapBin.Get(stripImage); // FUN_00442aec :3974
if (strip != NULL)
localView.DrawBitMapOpaque(color, 0, strip, // vtbl+0x58 :3976
cellX, cellY, cellX + 0x7f, cellY + 0x1f);
wh->bitMapBin.Release(stripImage); // FUN_00442c12 :3980
}
}
// --- sender name cell (:3983-4009) ---------------------------------------
// Binary tracks the name ENTITY pointer + reads (+0x1e0)->App+0xc8 cache; the
// safe bridge form returns the resolved bitmap directly (App name cache is not
// wired -> NULL -> the "clear" branch, same deferral as PilotList).
int nameState = (nameBitmap != NULL) ? 1 : 0;
if (nameState != previousNameId)
{
localView.MoveToAbsolute(0x80, 0); // vtbl+0x24 (name cell x=128) :3984-3985
if (nameBitmap == NULL)
{
localView.SetColor(color); // vtbl+0x18 :3987
localView.DrawFilledRectangleToRelative(0x80, 0x20); // vtbl+0x4c :3989
}
else
{
localView.SetColor(7); // :4000
localView.DrawBitMapOpaque(color, 0, nameBitmap, 0, 0, // vtbl+0x58 :4005
nameBitmap->Data.Size.x - 1, nameBitmap->Data.Size.y - 1);
}
previousNameId = nameState; // :4009
}
}
```
GraphicsView vtable slots confirmed from `engine/MUNGA/GRAPH2D.h`: `SetOrigin@0x10:557`, `SetColor@0x18:568`, `MoveToAbsolute@0x24:581`, `DrawFilledRectangleToAbsolute@0x44:621`, `DrawFilledRectangleToRelative@0x4c:624`, `DrawBitMap@0x54:636`, `DrawBitMapOpaque@0x58:656`, `DrawPixelMap8@0x5c:679`. The binary's name-*erase*-previous path uses `DrawBitMap` (vtbl+0x54, `part_014.c:3995`) — collapsed into the clear branch above since no previous bitmap is tracked in the safe bridge form.
### 4.9 Registration (`btl4grnd.cpp`, before `&BTL4ChainToPrevious` at line 150)
```cpp
&PilotList::methodDescription, // "pilotList"
&GeneratorCluster::methodDescription, // "GeneratorCluster"
&MessageBoard::methodDescription, // "messageBoard" -- sec-MFD comm/status ticker (DEFERRED source)
&BTL4ChainToPrevious
```
Add `static MethodDescription methodDescription;` to the `MessageBoard` class in `btl4gau3.hpp`.
---
## 5. Systemic-check verdicts
- **Container-Execute rule:** N/A — `MessageBoard` is a **leaf** `GraphicGauge`, not a container (no child gauges, no `Execute=Fail` base risk). It **overrides `Execute`** (`FUN_004cb82c`) and **overrides `BecameActive`** (`FUN_004cb7fc`) with a **non-inactivating** body (sets sentinels only) → satisfies the rule inherently. ✅
- **Shadow fields:** none. Derived fields start at `0x90` (`GraphicGauge` ends there); `renderer`/`localView` are inherited base members, accessed by name — no re-declaration. ✅
- **Alias fields:** none. `trackedMech`/`stripImage`/`color`/`previousNameId`/`previousMessageId` are all genuine new slots (`0x90``0xA3`). ✅
- **Phantom fields:** none — last member `previousMessageId@0xA0` (4 bytes) ends at `0xA4 == sizeof == Make alloc`. ✅
- **Field mislabels (fix in header):** `enabled``trackedMech` (pointer, not bool; setter is `SetSource` not `SetEnable`); `previousMessageId`/`previousNameId` **swapped**. ✅ (§3)
- **Databinding NULL risks:** the raw `*(mech+0x190)`, `*(player+0x1dc)`, `nameEntity+0x1e0`, `App+0xc8` reads are the **databinding trap** — kept **out** of this TU via `BTResolveMessageBoard` (complete-BTPlayer TU). The `bitMapBin.Get` result is NULL-checked (`:3975`) before the strip blit. ✅
- **Every-mech crash risk:** none. With `trackedMech==NULL` (always, until wired) Execute early-returns — zero draws, zero visual change to the sec-MFD composite, byte-identical to the current parse-skipped behavior. Make/ctor allocate + hold one bitmap ref (released in dtor, per the corrected base-dtor-glue rule — no explicit base call). ✅
- **`/FORCE` stub risk:** `BTResolveMessageBoard` **must** have a real (stub) definition, or the `/FORCE` link turns the call into a runtime AV (CLAUDE.md gotcha). Provide the returns-`False` stub in `btplayer.cpp`. ⚠
---
## 6. Confidence + unknowns
**Confidence: HIGH** for Make/ctor/dtor/BecameActive/TestInstance/SetSource/layout/registration — all fully recovered, sizeof/vtable/offsets cross-checked against the `VertTwoPartBar`/`PlayerStatus`/`PilotList` templates and the GraphicsView vtable header. The widget will **build, register (stop parse-skipping), construct, and run as a safe no-op**.
**Confidence: HIGH** on the blocker: the board is **DEFERRED/empty** because (1) `SetSource` is never called (no recovered caller) and (2) `StatusMessagePool` is a NULL stub (`btplayer.cpp:135/508`). Both confirmed by grep + source.
**Unknowns / follow-ups (do not block the landing):**
1. **Who calls `SetSource`.** No caller in the recovered window — likely in the gauge renderer's viewpoint-bind step (`GAUGREND`/`btl4grnd`, not in `part_014.c`). To bring the board **alive** without it, self-resolve in Execute: `trackedMech = (Entity*)application->GetViewpointEntity();` (`APP.h:373`) — the accepted approach `PlayerStatus`/`PilotList` already use. Left as the safe no-op by default to guarantee zero regression on the dev-gauge composite.
2. **The `Player__StatusMessage` record layout** (`+0xc` messageId, `+0x10` nameEntity) and the App+0xc8 name-bitmap cache — needed inside `BTResolveMessageBoard` once `StatusMessagePool` is wired. These live in `btplayer.cpp`'s domain (`Player__StatusMessage` ctor at `:513`); decode `FUN_0042e580`=`AddStatusMessage` and the message record ctor to expose `messageId`/`nameEntity` as compiled accessors.
3. **`btsmsgs.pcx` cell grid** (4 cols × N rows of 128×32) is derived from the `(id&3)<<7,(id>>2)<<5` math (`:3969-3970`), not from the file — verify against the asset when the feed is live.
4. Cosmetic: the empty-state `color==0` clear boxes are never painted in the default landing (guarded off); if self-resolve is enabled later, confirm palette index 0 on the sec MFD is background (else the message region paints black — faithful, but verify visually).