Files
BT411/scratchpad/wf_3_MessageBoard_verify.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

7.8 KiB
Raw Blame History

I have completed the adversarial verification against the raw decomp, the CFG, the sibling templates, and the data-binding source files. Every load-bearing claim in the spec was checked. Here is the corrected verdict.


ADVERSARIAL VERIFY — MessageBoard reconstruction spec

Bottom line: the spec is substantially CORRECT and ready-to-implement. All addresses, sizeof, ctor offset writes, the base class, the methodDescription row set, the Make/dtor conventions, and the DEFERRED-data verdict are verified against the binary. The spec's three header corrections are all genuinely correct, and its correction of the task hint (source is BTPlayer status queue, not SubsystemMessageManager 0xBD3) is verified. I found one wrong citation, one fidelity deviation to flag, and two small notes. No blocking errors.

What I verified as CORRECT (accept as-is)

  • Identity / addresses (all confirmed part_014.c): Make @004cb678:3825, ctor @004cb704:3849, dtor @004cb788:3872, TestInstance @004cb7e4:3892FUN_004448ac, no-op slot @004cb7f4:3903, BecameActive @004cb7fc:3913, SetSource @004cb818:3925, Execute @004cb82c:3936, vtable PTR_FUN_0051bddc (:3858/:3876). Base = GraphicGauge (FUN_00444818), ends at 0x90.
  • sizeof 0xA4 == Make alloc FUN_00402298(0xa4) (:3832). ✓
  • ctor offset writes (:3859-3864): [0x25]=stripImage(0x94), [0x26]=color(0x98), [0x24]=trackedMech(0x90)=0; SetOrigin(x,y) via localView vtbl+0x10. ✓
  • The three header fixes are all correct:
    • enabledEntity *trackedMech: 0x90 is a pointer dereferenced at +0x190 (iVar1 = *(*(param_1+0x90)+400), :3950) and written only by SetSource (:3928). It is not a bool. ✓
    • previousMessageId / previousNameId are SWAPPED in the current header. Binary proof: BecameActive writes 0x9c=-1, 0xa0=-2 (:3916-3917); Execute compares messageId vs 0xa0 (:3960) and nameEntity(iVar5) vs 0x9c (:3983). ⇒ 0x9c=previousNameId(-1), 0xa0=previousMessageId(-2) — exactly the spec's relabel, and it matches the prose at btl4gau3.cpp:784. ✓
  • methodDescription rows match the CFG call messageBoard(E, ModeAlwaysActive, btsmsgs.pcx, 0) at L4GAUGE.CFG:4913-4917 under the offset=(113,607) at :4912 → 4 rows typeRate/typeModeMask/typeString/typeColor; position threaded from the offset directive; entity param ignored (binary Make never touches param_4, :3825-3843). This is exactly the PilotList template (btl4gau3.cpp:218-239), except MessageBoard does use position (SetOrigin). ✓
  • Make presence-check + return is byte-faithful and matches the codebase template VertTwoPartBar::Make (btl4gaug.cpp:1099-1107: Get(string); if NULL return False; Release; return True). content/GAUGE/BTSMSGS.PCX exists → returns True in practice. ✓
  • dtor correctly omits the base-dtor call (FUN_00444870 is compiler epilogue glue, :3880) — avoids the double-dtor bug. FUN_004700ac is the string-dup helper used across widgets; freeing via delete[]/FUN_004022e8 is consistent. ✓
  • Data-binding blocker — CONFIRMED on both legs:
    • SetSource (FUN_004cb818) has ZERO callers anywhere in reference/decomp/all/ (grep returns only its own definition) → trackedMech stays NULL. ✓
    • StatusMessagePool = 0 — the NULL stub is real (btstubs.cpp:62), and the only writer of BTPlayer+0x1dc is gated if (sender_owner && StatusMessagePool) (btplayer.cpp:508) → no messages ever created. ✓
    • Task-hint correction is right: SubsystemMessageManager (messmgr.cpp) is reconstructed but is the per-mech damage/explosion hub (ConsolidateAndSendDamage/weaponExplosions), not a {msgId,nameEntity} source; MessageBoard never references it. mech+0x190=owningPlayer confirmed (btplayer.cpp:68, MECH_OWNING_PLAYER); DAT_004efc94==application (App+0xc8 name cache, btplayer.cpp:53). ✓
  • Systemic checks: leaf GraphicGauge (not a container) that overrides both Execute and a non-inactivating BecameActive → Container-Execute/Fail rule satisfied. No shadow/alias/phantom fields (all new slots 0x900xA3, ends exactly at 0xA4). Raw mech+0x190/player+0x1dc/+0x1e0/App+0xc8 reads kept out of the widget TU via the BTResolveMessageBoard bridge (databinding trap avoided). Every-mech crash risk: none (early return on NULL). /FORCE stub for the bridge required. ✓

CORRECTIONS (the list of what I changed)

  1. [Citation fix — §2, §5, §6] StatusMessagePool's NULL definition is btstubs.cpp:62 (MemoryBlock *StatusMessagePool = 0;), not btplayer.cpp:135/508. Those btplayer lines are the extern decl and the guard site; the actual stub lives in btstubs.cpp. The conclusion (feed is dead) is unchanged — only name the correct file so the follow-up (wiring the pool) edits the right place.

  2. [Fidelity deviation — §4.8, must be flagged, not fixed] The Execute name-cell path is a STRUCTURAL simplification, not byte-faithful. The binary stores the previous name ENTITY POINTER at 0x9c and, when the sender changes to "none", looks up that previous entity's name bitmap via its +0x1e0 key and erases it with DrawBitMap (vtbl+0x54, :3992-3996). The spec collapses 0x9c to a boolean nameState (0/1) and drops the erase-previous path. While DEFERRED this is functionally identical (nameEntity always 0, previousNameId init 1 → first Execute takes the iVar5==0 && prev==-1 clear branch, :3986-3990, matching the binary), so it is safe for the landing. But it changes previousNameId's semantics from pointer→int, so when the status feed goes live the entity-pointer tracking + erase branch must be restored for correct name repainting. Keep the spec's body for the deferred landing; add a code comment marking this as the restore point. (The spec does acknowledge the deviation; I am raising it to an explicit action item because it silently redefines a member.)

  3. [Minor note — §1/§4.5] The no-op vtable slot @004cb7f4 ("ShowInstance"): the binary override is a bare return. The spec omits it and inherits (per the PilotList/PlayerStatus precedent). This is only byte-faithful if the GraphicGauge base slot is itself trivial for this call site; if strict fidelity is wanted, add an empty override. Low risk (leaf widget, slot rarely hit) — accept the omission but note it.

  4. [No change, confirmation] Make's bool return on a missing bitmap is binary-faithful and template-matched; because BTSMSGS.PCX is present it returns True, so registration/parse is unaffected. No action.

Everything else in the spec — the layout table + static_assert locks, ctor/dtor/BecameActive/TestInstance/SetSource/Make bodies, the BTResolveMessageBoard bridge + returns-False stub in btplayer.cpp, the methodDescription literal, and the registration line inserted before &BTL4ChainToPrevious in btl4grnd.cpp (after GeneratorCluster) plus adding static MethodDescription methodDescription; to the class — is verified and should be implemented as written.

FINAL CONFIDENCE: HIGH

  • Layout/methods/registration/sizeof/offsets: HIGH — fully recovered and cross-checked against part_014.c:3823-4013 and the PilotList/VertTwoPartBar templates.
  • DEFERRED/empty verdict: HIGH — both blockers independently confirmed in-source (btstubs.cpp:62 NULL pool; SetSource zero callers).
  • Only residual UNKNOWN (non-blocking, for the alive path, not the landing): the exact Player__StatusMessage record layout (+0xc messageId, +0x10 nameEntity) and the App+0xc8 name-bitmap cache shape needed inside BTResolveMessageBoard once StatusMessagePool is wired — decode FUN_0042e580 (AddStatusMessage) + the message-record ctor FUN_0042d990 to expose them as compiled accessors. The default landing (safe no-op) does not touch these.