Commit Graph
4 Commits
Author SHA1 Message Date
CydandClaude Fable 5 943219345a BT410 5.3.84: the yellow bar and the MFD bleed are ONE bug -- BTSEC1.PCX index 254, and the offender is named
Second operator report, same day: "what is that yellow orange artifact on the
display, it too shows up here and in bt411 but not in the original" -- a
solid vertical bar beside the RANGE readout on the colour head.

It is the same defect as 5.3.83's MFD bleed.  Not a similar one: the same
676 pixels.

HOW IT WAS CAUGHT.  5.3.83 shipped a fix that could not be verified, because
the fix makes something INVISIBLE and the A/B rig's boot cockpit already
showed zero MFD extras -- the unfixed build looked perfectly clean.  So this
commit adds a POSITIVE CONTROL instead of another argument:

  BT_TRANS_PROVOKE fills the colour head's uninitialised
  translationTable[64..255] with 0xFF00 -- every high-byte head bit --
  rather than the zero the fix installs.  Any draw that indexes the tail
  then lights ALL the mono heads at once.

On the boot cockpit that lights exactly 1030 pixels: Eng1/Eng2/Eng3 +1030
each, Mfd1 +684, Mfd2 +704, Mfd3 +1074, Comm +676, against 0 extras with the
fix.  The bug was firing the whole time.  Our heap simply happened to hold
zeros in that tail -- the same luck the shipped binary has been having, which
is exactly why the operator sees the artifact and the A/B rig does not.

THE OFFENDER, NAMED.  oormask.py renders which pixels those are and prints
their horizontal run lengths.  The mask is a glyph cluster plus 52 runs of
13px -- a SOLID 13x52 BAR at screen (526,228)-(538,279).  Solid means a
rectangle in the source art, so decode the art:

  BTSEC1.PCX, the colour head's own 480x640 background, contains exactly
  ONE out-of-range value in the entire image: index 254, exactly 676
  pixels, a solid 52x13 rectangle at (199,526)-(250,538).

  The sec port is configured at ROTATION 270, mapping source (x,y) ->
  screen (y, 479-x).  That puts the rectangle at screen x 526..538,
  y 229..280.  Measured mask: x 526..538, y 228..279.  Same rectangle, to
  the pixel.

ONE READ, TWO SYMPTOMS.  translationTable[254] is never written (
BuildSecondaryTranslation fills only 1<<numberOfBits = 64 entries), and
DrawPoint ORs the result in unmasked.  Whatever the heap left there decides
which symptom the operator sees:

  low 6 bits set  -> a coloured block on the COLOUR head, beside the RANGE
                     readout.  The yellow-orange bar.
  high 8 bits set -> garbage in the MFD / ENG / COMM planes.  The bleed.

Both reports, one uninitialised int.  It also explains the "not in the
original" asymmetry without needing the original to differ in code: it does
not differ, it is just getting zeros there.  And it explains BT411 showing it
too -- both reconstructions inherit the read from the archive.

5.3.83's zero-fill therefore cures both, and turns a heap-lottery into a
guarantee.  Still not DIRECTLY observed cured, because no rig we have was
showing the artifact to begin with; that honesty is recorded in the file
header rather than smoothed over.

ALSO IN: oormask.py, barbox.py, vis_provoke.conf, and a README section on
positive controls -- when a fix replaces garbage with a benign value, build
the variant that replaces it with a maximally LOUD value, because that turns
"I see no difference" into a number and separates "the fix works" from "this
screen never exercised the path".

METHOD NOTE, recorded in the README because it nearly cost the fix: three
grabs of one running instance score IDENTICALLY, so the within-boot noise
floor is zero -- and that is the wrong floor.  Judging a rebuild needs the
ACROSS-boot floor (~6px on the MFD heads).  A single bad grab, caught
mid-draw, read as a 2700px regression and nearly got a correct change
reverted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 22:36:59 -05:00
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
CydandClaude Fable 5 42ff5c3856 BT410 Phase 5.3.29: the panel titles -- 94.8% identical to the shipped cockpit
Reading the art settled where the titles live: qsensors/qmyomers/qermlas/
qppc/qstrk6.pcc are 299x26 TITLE BANNERS, while the qblh0..7.pcc strings
the cfg hands vehicleSubSystems are 77x120 MECH ICONS (already lit by the
5.3.28 placement fix).  So the authored auxScreenLabel IS the panel title
-- it just belongs on the MFD panel, not only the ENG page.

SubsystemCluster now builds a titleBanner child from the cached label.
Placement was MEASURED against the shipped framebuffer through the A/B rig
(BackgroundBitmap places by left/BOTTOM): a bring-up BT_TITLE_DY knob, then
a green-pixel correlation over the title band, then baked at x+0x09,
y+0xb3 from the panel origin.  "SENSOR CLUSTER", "MYOMERS", "TYPE II 65
TONS" and both "ERMED LASER RANGE 500M" banners now render where the
shipped binary puts them.

Score progression vs the shipped cockpit on identical GAUGE content:
  5.3.26 birth            90.1% identical / 82% coverage
  5.3.28 authored screens 93.2% / 85%
  5.3.29 titles tuned     94.8% / 91%

Also: grab.ps1 now focuses the target window before capturing -- the
screen-copy grabbed whatever was in front, which cost two junk captures
(a white frame and an unrelated 3-D app window).

Gauge fight 11/11 rounds and smoke both clean, zero faults.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 23:09:15 -05:00
CydandClaude Fable 5 24ea06574c BT410 Phase 5.3.28: the visual A/B pass -- 93% pixel-identical to the shipped cockpit
Ran the reconstructed exe and the shipped ALPHA_1 binary against the SAME
GAUGE content, same mount, gauges on, and diffed the 640x480x16
framebuffers.  OUR EXE DRAWS THE COCKPIT: 90.1% pixel-identical on the
first run, and every difference traced to a single root cause.

The authored aux-screen block (screen number / background placement /
label) lives in the subsystem resource -- which is freed with the Mech
ctor's stream buffer (the 5.3.24 use-after-free landmine).  Both this tree
and the BT411 port had stubbed it, which is why BT411's displays show the
same artifacting.  PoweredSubsystem now caches the block at ctor time with
accessors, and btl4gau2 uses the AUTHORED screen instead of a roster-order
stand-in and builds the placement strip art.  Panels snapped onto their
authored screens -- weapon dials now land on the same panels as the
shipped exe, mech icons appear on the sensor/myomer panels, generator
letters correct -- taking the match to 93.2% identical / 85% coverage.

Remaining differences are donor-inherited stubs: the panel title art (now
proven to come from the q-strip statusImage path, not auxScreenLabel --
the label blit is wired and guarded regardless), the pilot name bitmap,
and some lamp frames.

The A/B rig is banked at emulator/render-bridge/gauge-ab/ (both confs +
the window-grab script) so the comparison is repeatable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 22:29:01 -05:00