Files
TeslaRel410/emulator/render-bridge/gauge-ab
CydandClaude Fable 5 740ef2b0a7 BT410 Phase 5.3.32: the per-head A/B -- three engineering heads now exact
The gauge framebuffer is PLANE-PACKED: L4GAUGE.CFG gives each port a bit
mask, not a rectangle, so all six heads share the same x/y and are separated
only by bit -- the packing the VDB splits into the pod's physical screens.
Comparing RGB was therefore measuring nothing useful; the "magenta artifact"
just meant the wrong heads were lit at that pixel.

New instruments (emulator/render-bridge/gauge-ab/, with a README):
  planes.py  per-head scoreboard -- shipped vs ours, missing vs extra, per
             port mask, recovering the 16-bit word from DOSBox's RGB565
  BT_VIS_LOG a complete cockpit widget map from the single dispatch every
             gauge widget is built through (MethodDescription::Execute),
             printing name + port + authored position
  ab.sh      stages the fresh build over BTL4REC.EXE and kills any running
             DOSBox before launching -- see below

The fix: the Comm page's pilot roster is the POD roster (the viewpoint mech's
ControlsMapper pilot array, mapper attributes 15/16), not the mission's
player list.  It is zero in a solo mission, so the shipped page draws empty;
ours resolved the local player and painted its icon in colour 0xff.  The gate
belongs in the row source, not PilotList::Execute -- Execute's empty branch
still has to run, because erasing is what the shipped page draws.

  head    shipped    ours   missing   extra          (was)
  Eng1      17981   17981         0       0     (0 / 1030)
  Eng2      17981   17981         0       0
  Eng3      17981   17981         0       0
  Comm      15656   13557      2099       0     (2099 / 1253)
  Heat      21374   20913       566     105     (566 / 990)

Title-band magenta 404 -> 0.  The 2099 Comm pixels we are missing were
missing before the gate, so it is a strict improvement.

Method note, which cost more than the bug: the rig's confs run BTL4REC.EXE
out of the mount while the build writes build410/btl4opt.exe, and nothing
connected the two.  Three measurements ran an hour-old binary, so a change
that "did nothing" three times had never been tested -- and the correct first
hypothesis was discarded on that evidence.  ab.sh now re-stages every launch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 12:04:43 -05:00
..

gauge-ab -- the cockpit A/B rig

Runs the reconstruction and the shipped 4.10 binary against the same mount (same GAUGE/L4GAUGE.CFG, same egg, same mech) and compares what each one paints into the gauge framebuffer.

With L4VIDEO=OFF and L4GAUGE=640x480x16, the DOSBox window is the packed gauge framebuffer -- the exact buffer the pod's VDB splits into its physical heads. So a screen grab is a lossless read of the cockpit.

Running

bash ab.sh rec        # stage the fresh build + run the reconstruction
bash ab.sh shp        # run the shipped binary
powershell -File grab.ps1 -Out ours.png
python3 planes.py shipped.png ours.png

Always launch through ab.sh. The confs run BTL4REC.EXE out of the mount, not build410/btl4opt.exe. Forgetting to re-stage silently measures the previous binary -- on 2026-07-27 that cost a full round of wrong conclusions (a fix "did nothing" three times because the tested exe never changed, and the correct first hypothesis was discarded on that evidence). ab.sh re-stages every time and kills any running DOSBox first (two instances share OUT.TXT and corrupt the trace).

The instruments

planes.py -- the per-head scoreboard (use this first)

The framebuffer is plane-packed: L4GAUGE.CFG gives each of the ten logical ports a bit mask, not a rectangle --

configure(8,Heat, 0,0x4000,clut2,blue, NULL);   # UL
configure(9,Comm, 0,0x8000,clut2,red,  NULL);   # UR

-- so all six heads occupy the same x/y and are separated only by bit. RGB comparison is therefore meaningless: a "magenta artifact" is really the wrong heads lit at that pixel. DOSBox presents the buffer as RGB565 with bit replication, so the original 16-bit word is recovered exactly by R>>3, G>>2, B>>3.

planes.py reports, per head, how many pixels the shipped binary lights, how many we light, how many we're missing, how many are extra, and the bounding box of the extras. Missing vs extra is the useful signal: extras are our bugs, missing is unbuilt work.

score.py -- one whole-frame number

Coarse (the big MFD heads dominate it). Good for "did this regress", useless for locating anything. Prefer planes.py.

BT_VIS_LOG -- the widget map

set BT_VIS_LOG=1 in the conf makes the build print every gauge widget the interpreter constructs, with its port and authored position:

[w] pilotList port=9 at 0,0
[w] rankAndScore port=9 at 33,0
[gen] port=0 x=443 y=322 lampA='sgena.pcc' ... on=1 col0=3 col1=9
[cluster] port=4 x=0 y=240 title='qsensors.pcc' banner=1

The [w] line comes from the single dispatch every widget is built through (MethodDescription::Execute, MUNGA/GAUGREND.CPP), so the map is complete. This is what turns "a diff at framebuffer (67,3)" into "that head has no drawing widget there, so look elsewhere".

Method

Source inspection has now produced five wrong suspects on this one artifact; each was settled -- or killed -- by one instrumented run. So:

  1. planes.py first: which head, and is it missing or extra?
  2. BT_VIS_LOG: which widgets exist on that head, at what position?
  3. Only then read code, and only that widget's.

And re-stage before believing any measurement.