SeekVoltageGraph: full reconstruction -- the eng-page POWER graph + top-box eraser (Gitea #11)

The #10 audit's one WRONG: the port Execute was a bring-up no-op, so the
emitter/myomer engineering pages never erased their top data box -> stale
sibling-page ghosts on the shared Eng bit-plane (SYSTEM 10 PPC showing the
Streak ammo box, etc).  Full faithful widget landed:

- btl4gau2: ctor/BecameActive/Execute/clear/ticks/cursor recovered from the
  capstone disasm of @004c6798/@004c6920/@004c6934/@004c6be4/@004c6c30/
  @004c6c6c (Ghidra dropped every x87 arg).  Plot: v=0..12000 step 1200,
  x=Round(response(v)*230), y=Round(v*(1/12000)*187) (ld80 @004c6bd0/@004c6d74
  = exactly 1/12000); change-test samples the response at 12000V vs the 9999
  activation sentinel; XOR op for tick/cursor move-by-redraw; destroyed branch
  centres edestryd.pcc and revives via own vtbl+0xC (BecameActive, slot 3 of
  PTR_0051a1fc -- vtable-dump verified).
- The vtbl+0x3C sampler identified from the binary vtables: Emitter slot 15
  @004bb42c = sqrt(P(v)/2.0e8), P @004bb3f4 = damageFraction*v^2*0.5*
  energyCoefficient; Myomers slot 15 @004b8f94 = sqrt(AvailableOutput(v)*3.6/
  350).  FUN_004dd138 == sqrt (part_015.c:4026): myomers' fabs reading
  corrected, GetSpeedReading renamed SeekVoltageResponse.  Port dispatch via
  complete-type bridges BTSeekVoltageSample/BTMyomersSeekSample +
  BTSubsystemDestroyed (databinding rule).
- Emitter's AUTHENTIC attribute table recovered (binary @0x511dd4, ids
  0x1D-0x25) and published: Laser*/Seek*/OutputVoltage@0x414 (currentLevel,
  RAW volts -- the live-cursor feed).  Field renames per the table:
  0x3F8 minSeekVoltageIndex / 0x3FC maxSeekVoltageIndex (static_assert-locked).
  The MechWeapon 0x1D OutputVoltage PORT ALIAS retired (binary table ends
  0x1C; Find walks lowest-id-first, the alias shadowed the authentic row).
  PPC::DefaultData -> Emitter::GetAttributeIndex().
- mech4: BT_PRESET_HOLD=<n> (freeze the #9 preset cycler after n pulses) for
  steady-state pixel verification; BT_SEEK_LOG diag.

Verified live (BLH, autofire): both #10 repro pairs held ghost-free for
minutes (SYS09->SYS10 PPC, SYS02->SYS04 ERMed, SYS05->SYS06 Myomers); curves
draw with live cursors; one replot per activation; quad panels/J-K-L/sec
panel un-regressed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-19 20:27:39 -05:00
co-authored by Claude Fable 5
parent f1a6ccbaaf
commit 63b168cb92
15 changed files with 594 additions and 109 deletions
+44 -5
View File
@@ -567,8 +567,9 @@ dev-parse skips — the tool that pinned the last 3 (⚠ the gauge renderer buil
long enough for BuildConfigurationFile; a too-early kill shows [gparse]=0 and looks like "not built"). Remaining gauge
work is DATA FEEDS, not widgets — [UPDATE 2026-07-12: the 0xBD3 untangle landed (task #7) and the valve
CONTROL landed (task #13, live MoveValve via the rookie-role gate); only the message half remains]: the
status-message queue (StatusMessagePool) — deferred systems, cleanly marked. `SeekVoltageGraph::Execute` (@004c6934)
is a cluster-child (not config-called) its 4 Seek* attributes are the only remaining publish, non-blocking.
status-message queue (StatusMessagePool) — deferred systems, cleanly marked. [UPDATE 2026-07-19 Gitea #11:
`SeekVoltageGraph` (@004c6934, a cluster-child not config-called) is now FULLY reconstructed and its Seek*
attributes published on Emitter+Myomers — see the AUDIT finding A addendum below.]
### Phase 3 — SIM/MODEL
-**Aggregate HeatSink-bank** (0xBBE) — DONE (commit 16f5f54). Reconstructed `AggregateHeatSink : HeatSink`
@@ -679,7 +680,7 @@ reconfigure/externalConfigure); parse-skip list EMPTY ([gskip]=0), all 50 attr b
| 16 | Eng pages: prepEngr SYSTEM NN + subsystem label + class cells | roster walk, sub+0x1dc auxScreen == screen (BTGetSubsystemAuxScreen) | FUN_004c7e48 matched line-by-line; [vss] dump: scr1/2/4=PPC/Strk6/ERMed, 5-8=Sens/Myo/ERMed/ERMed, 9/10=Strk6/PPC — page headers+labels CORRECT | T1/T2 | CORRECT |
| 17 | Eng ballistic page: ammoCountB / jam / fire / reload numeric / destroyed lamp | bin count bridge + weaponAlarm@0x364 (MechWeapon layout static_assert-locked) | ctor @004c9558 coords matched; LIVE renders | T2 | CORRECT |
| 18 | Eng ballistic page: eject wipe (BitMapInverseWipeScalar @004c61c8) | subsys+0x3f8 eject timer | port tracked NULL (class not reconstructed) | T3 | DEFERRED-FEED |
| 19 | Eng emitter/myomer pages: SeekVoltageGraph (POWER curve) | 4 Seek* attrs + subsystem vtbl+0x3C sampler | WRONG — port Execute is a bring-up no-op (btl4gau2.cpp:331); see finding A below | T1 (binary) | WRONG (filed) |
| 19 | Eng emitter/myomer pages: SeekVoltageGraph (POWER curve) | 4 Seek* attrs + subsystem vtbl+0x3C sampler | WAS WRONG (bring-up no-op Execute) — **FIXED (Gitea #11, 2026-07-19)**: full reconstruction, see finding A addendum | T2 | CORRECT (fixed) |
| 20 | Eng emitter page: seek-step lamp (bteseek) | Emitter::seekVoltageIndex@0x3F0 (static_assert-locked) | @004c93b0 :2146 | T2 | CORRECT |
| 21 | Eng myomer page: seek-step lamp | Myomers@0x320 INFERRED (ctor @004c8df4 not in the decomp export) | marked in code | T3 | CORRECT (best-effort; flagged) |
| 22 | Eng page: linked heat-sink number (hs+0x1d4 guarded raw) | PrepEngr numeric #2 | marked BEST-EFFORT (guarded) | T3 | CORRECT (guarded; flagged) |
@@ -707,8 +708,9 @@ reconfigure/externalConfigure); parse-skip list EMPTY ([gskip]=0), all 50 attr b
| 44 | HUD: PNAME1-8.bgf 3D name marker chain | — | deferred | T4 | DEFERRED-FEED |
| 45 | HUD attr table @005110b8 (ids 3-0xD) | hud.hpp/CLASSMAP corrected this audit | finding B below | T1 | CORRECT (fixed) |
**Counts: 34 CORRECT · 1 WRONG (filed: SeekVoltageGraph) · 6 AUTH-STATIC (incl. dual-verdict rows
13/29/39) · 6 DEFERRED-FEED (rows 18/24/34-duck/35/44 + the sec messageBoard partial).**
**Counts: 34 CORRECT · 1 WRONG (filed: SeekVoltageGraph — since FIXED, Gitea #11) · 6 AUTH-STATIC
(incl. dual-verdict rows 13/29/39) · 6 DEFERRED-FEED (rows 18/24/34-duck/35/44 + the sec
messageBoard partial).**
(Dual-verdict rows counted in both columns.)
### Finding A — the "SYSTEM 10 PPC ammo readout" (issue entry point a) — ROOT-CAUSED, FILED
@@ -741,6 +743,43 @@ DrawTicks @004c6c6c, DrawCursor @004c6c30, clear @004c6be4 — Ghidra dropped th
tools/disas2.py). An erase-only patch was deliberately NOT made (it would be a stand-in for the
missing curve).
**✅ RESOLVED (Gitea #11, 2026-07-19) — the full widget landed (btl4gau2.cpp/.hpp):**
- **x87 recovery (capstone, tools/disas2.py):** plot step/limit _DAT_004c6bdc/_be0 = 1200/12000;
the 80-bit consts @004c6bd0/@004c6d74 = EXACTLY 1/12000 (the voltage→y normaliser);
x = Round(response(v)·xScale 230), y = Round(v·(1/12000)·yScale 187); change-test = the
response sampled at 12000 V vs the @0xAC cache (9999 activation sentinel); clear @004c6be4 =
SetOperation(Replace)+color 0+filled 1000×1000 clipped to the view; ticks @004c6c6c = per-gear
loop [*min..*max], current gear = full L, others 10-px stubs, XOR pair to move; cursor
@004c6c30 = 8×8 XOR square at (x-4,y-4) from the LIVE voltage (*this[0x29]); destroyed branch =
centred edestryd.pcc via (Round(xScale)-w)/2; revive → own vtbl+0xC == BecameActive (slot 3 of
PTR_0051a1fc, vtable-dump verified). Members this[0x30..0x32] = cursorX/cursorY/tickIndexShown.
- **The vtbl+0x3C sampler identified from the vtable dumps** (Emitter @00512078 slot 15 =
@004bb42c; Myomers @005117dc slot 15 = @004b8f94): Emitter = sqrt(P(v)/2.0e8f [0x4d3ebc20]),
P @004bb3f4 = damageFraction@0x444 · v² · 0.5 [_DAT_004bb428] · energyCoefficient@0x454;
Myomers = sqrt(AvailableOutput(v)·3.6/350). **FUN_004dd138 == sqrt** (part_015.c:4026) — the
myomers.cpp "fabs / fp-magnitude" reading was corrected and the best-effort name
GetSpeedReading renamed **SeekVoltageResponse**. Port dispatch: `BTSeekVoltageSample`
(emitter.cpp) → `BTMyomersSeekSample` (myomers.cpp) complete-type bridges;
`BTSubsystemDestroyed` (powersub.cpp) for the simulationState==1 test.
- **Emitter's AUTHENTIC attribute table recovered + published** (binary @0x511dd4, ids
0x1D-0x25 chained after MechWeapon's 0x1C): LaserOn@0x418(firingActive), LaserScale@0x42C,
LaserRotation@0x41C, CurrentSeekVoltageIndex@0x3F0, RecommendedSeekVoltageIndex@0x3F4,
MinSeekVoltageIndex@0x3F8, MaxSeekVoltageIndex@0x3FC, SeekVoltage@0x400,
OutputVoltage@0x414(currentLevel — RAW volts, the cursor feed). Emitter field renames per the
table: @0x3F8 minSeekVoltageIndex, @0x3FC maxSeekVoltageIndex (static_assert-locked). The
MechWeapon 0x1D "OutputVoltage" PORT ALIAS was RETIRED (binary table ends 0x1C; Find walks
lowest-id-first so the alias shadowed the authentic row — the cursor would have read the 0..1
rechargeLevel instead of volts). PPC::DefaultData → Emitter::GetAttributeIndex().
- **Verified live** (BLH DEV.EGG, BT_AUTOFIRE + BT_PRESET_TEST + the new **BT_PRESET_HOLD=<n>**
steady-state hold): both #10 repro pairs ghost-free held for minutes (SYS09 Streak→SYS10 PPC;
SYS02 Streak→SYS04 ERMed; SYS05 Sensors→SYS06 Myomers); curves draw (emitter = straight line,
authentically — sqrt of v² is linear; myomer = steep low curve), cursors track the charge
cycle, gear ticks render; [seek] log (BT_SEEK_LOG) shows exactly ONE replot per activation,
all 6 graph instances. NOTE: a BT_SHOT landing exactly on a page-switch frame can capture the
1-frame label-vs-box transition (PrepEngr labels draw in BecameActive; the box clears at the
graph's next rated Execute) — the binary has the same lag class; it self-heals next frame and
the 90/120 cadence phase-lock made it look persistent during cycling verification.
### Finding B — HUD binary attr table @005110c0 conflict (issue entry point b) — RESOLVED, FIXED
Re-dumped section_dump.txt @5110b8: the table starts ONE RECORD EARLIER than transcribed — a full
16-byte record {id 3, "FlickerRate", 0x1D8|1, 0} (the old reading took the FlickerRate name ptr