BT410 5.3.85: the six-bit hazard surveyed -- draw site named, 94 art files inventoried, a 1996 config typo found

Follow-up survey to 5.3.84, written into L4GREND.NOTES.md rather than left as
conversation.

THE DRAW SITE, NAMED.  This closes a question that had been open across
several sessions ("which of the three DrawBitMapOpaque sites draws
sentinel-bearing sec art").  Answer: none of them.  It is a DrawPixelMap8 --

  BTL4GAU2.CPP:1524, the bgPixelMap widget, MoveToAbsolute(0,0) then a
  full-image OPAQUE blit.  BT_VIS_LOG places it at port=0, the six-bit head.

Every pixel of the colour head's background therefore goes through the
64-entry translation table, sentinels included.

ALSO PROVEN: no drawing operation contains the damage.  The opaque inner loop's
Replace case is

    *dest = (Word)((*dest & bitmask) | color);

which clears THIS port's bits and then ORs the whole table entry back --
including garbage in other ports' bit positions.  Replace leaks exactly like
Or does.

ART INVENTORY.  Swept all 428 PCX/PCC under GAUGE (which is all the art there
is -- nothing lives outside it).  94 carry pixels > 63: index 231 in 53 files
(sparse, 4-7%, the 172x217 avatar CRIT/HEAT silhouettes), 255 in 27 (the *HT
heat backgrounds), 226/228/229 as 1-2px specks in QJAK*, and 254 in 2.

BTSEC1.PCX is the only one whose out-of-range region is a SOLID RECTANGLE and
the only one proven to reach the screen -- 676px at (199,526)-(250,538),
rotation 270 mapping screen = (src_y, 479 - src_x), landing exactly on the
measured mask.

WHAT IS STILL OPEN, recorded as open rather than smoothed over:

  The 354px cluster.  Of the provoke control's 1030 lit pixels, 676 are the
  bar; the remaining 33x32 cluster at (67,3)-(99,34) is NOT file-borne -- no
  gauge file has a count near 354.  So it is generated at runtime.  The
  obvious suspect CreateMutantPixelmap8 is ruled out: it is an inert stub
  returning NULL, so recoloredMech never blits here.  Unattributed; the fix
  covers it regardless.

  A possible second exposure, in-mission.  L4GAUGE.CFG carries 1345
  colour-mapper entries (656 cmCrit, 662 cmHeat, 27 cmArmor), BT_VIS_LOG puts
  ALL of them on port 0, and their mode is ModeSecondaryCritical.  They name
  adpal/adpal2/heatpal, three of which the sweep flags -- ADPAL and ADPAL2 are
  2x5 and ENTIRELY index 99.  Whether that matters turns on whether a mapper
  blits those pixels or merely reads their VGA palette, which nobody has
  checked.  Written down as a hypothesis with that caveat attached, NOT as a
  finding.  If the pixels are used as indices it would dwarf the bar and would
  fire in-mission, which is where the operator sees the artifact.

  The boot cockpit lighting only 1030 pixels says the avatar/mapper art is not
  drawn on THAT screen.  It says nothing about a live mission.

A SHIPPED DATA BUG, found in passing and deliberately NOT fixed:

  L4GAUGE.CFG:2513-2514 name adpa12.pcc -- digit one for lowercase L.  The
  file does not exist; adpal2.pcc does.  Two of 1345 lines, so the GAUSS and
  AFC25 ammo-bin criticals have been loading a missing palette since 1996.
  It is the original's bug and the shipped binary lives with it; the archive
  is sacred, so we live with it too.  Noted so the next person who sees a
  warning about adpa12.pcc does not go hunting for a reconstruction defect.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-30 08:03:00 -05:00
co-authored by Claude Fable 5
parent 943219345a
commit 5a465c2321
@@ -0,0 +1,118 @@
# L4GREND.CPP — reconstruction shadow notes
The shadow exists for ONE reason: to construct a `BTL4GraphicsPort` instead of
an `L4GraphicsPort`, so the colour head's uninitialised translation-table tail
gets zeroed. Everything else in the file is the archive's, verbatim.
The mechanism, the proof, and the honest verification status live in the file's
own header comment. This sidecar carries the survey work that did not belong in
a source comment.
## The hazard, in one line
The colour head is **six bits** (`sec`, mask `0x003F`, `L4GAUGE.CFG`), so
`BuildSecondaryTranslation` (`L4VB16.CPP:5419`) fills only `1<<numberOfBits` =
**64** of `int translationTable[256]`. Any source pixel `> 63` reads
uninitialised memory, and `DrawPixelMap8` ORs the result into the shared
plane-packed framebuffer **unmasked**.
Worth noting that even `Replace` leaks. The opaque inner loop is
```c
color = (Word) translation_table[source_data];
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
```
`& bitmask` clears *this* port's bits, then `| color` ORs the whole table entry
back — including whatever garbage sits in other ports' bit positions. There is
no drawing operation that contains the damage.
## The draw site — answers a long-open question
`restoration/source410/BT_L4/BTL4GAU2.CPP:1524`, the `bgPixelMap` widget:
```c
localView.MoveToAbsolute(0, 0);
localView.DrawPixelMap8(True, 0, bg, 0, 0, // opaque, full image
bg->Data.Size.x - 1, bg->Data.Size.y - 1);
```
`BT_VIS_LOG` places it at `[w] bgPixelMap port=0 at 0,0` — port 0 is `sec`.
Full-image, opaque, on the six-bit head: every pixel of the background goes
through the table, sentinels included. Of the three `DrawBitMapOpaque` sites
that were under suspicion, none is the culprit; this `DrawPixelMap8` is.
## Art inventory — 94 of 428 gauge files carry out-of-range pixels
Swept every `.PCX`/`.PCC` under `ALPHA_1/REL410/BT/GAUGE` (all the art there is
— nothing lives outside that directory). Distinct out-of-range values:
| index | files | shape | reading |
|---|---|---|---|
| 231 | 53 | sparse, ~47%, in a mech-silhouette region of 172×217 `*CRIT`/`*HEAT` art | avatar damage/heat art |
| 255 | 27 | sparse, ~57%, `*HT` art (252×200, 229×199, 303×200) | heat backgrounds |
| 254 | 2 | **solid 52×13 rect** in `BTSEC1.PCX` | the confirmed offender |
| 226/228/229 | 8/8/7 | 12px specks in `QJAK*.PCC` | paint spatter, harmless |
| 99 | 2 | `ADPAL.PCC`, `ADPAL2.PCC` — 2×5, **100%** at 99 | palette swatches, see below |
| 100 | 1 | `HEATPAL.PCC` — 3×3, one pixel | ditto |
| 120, 127 | 1 each | | |
`BTSEC1.PCX` — "BT SEC-ondary", the colour head's own background — is the only
one whose out-of-range region is a **solid rectangle**, and the only one proven
to reach the screen: 676 pixels of index 254 at source (199,526)-(250,538),
which the port's **rotation 270** maps to screen (526,228)-(538,279) via
`screen = (src_y, 479 - src_x)`. The provoke mask measured exactly that box.
## What is NOT yet resolved
**The 354px cluster.** The provoke control lights 1030 pixels on the boot
cockpit: 676 for the bar, and a 33×32 cluster at screen (67,3)-(99,34) that is
*not* file-borne — no gauge file has an out-of-range count anywhere near 354,
and all art lives in that one directory. It is therefore generated at runtime.
The obvious suspect, `CreateMutantPixelmap8` (`BTL4GAU3.CPP:1067`), is ruled
out: it is an inert stub returning NULL, so `recoloredMech` never blits in our
build. Unattributed. The fix covers it either way, since it zeroes the whole
tail regardless of who indexes it.
**The colour mappers may be a second exposure, in-mission.** `L4GAUGE.CFG`
carries **1345** colour-mapper entries — 656 `cmCrit`, 662 `cmHeat`, 27
`cmArmor` — and `BT_VIS_LOG` puts all of them on **port 0**, the six-bit head,
at 50,0. Their mode is literally `ModeSecondaryCritical`. They name
`adpal.pcc`, `adpal2.pcc`, `heatpal.pcc`, `heatpal2.pcc`, three of which the
sweep flags as out-of-range (`ADPAL`/`ADPAL2` are 2×5 and **entirely** index
99; `HEATPAL` has one pixel at 100).
Whether that matters depends on something not yet established: these are tiny
swatch files, and a colour mapper plausibly reads their **VGA palette** rather
than blitting their pixels. Do not repeat this as a finding until someone has
read the mapper's implementation. It is recorded because if the pixels *are*
used as colour indices, every one of 1345 mappers writes an out-of-range index
on the six-bit head — which would dwarf the 676px bar and would fire
in-mission, matching where the operator sees the artifact.
That the boot cockpit lights only 1030 pixels says the avatar/mapper art is not
being drawn on that screen. It does not say anything about a live mission.
## A shipped data bug, found in passing — do NOT fix
```
L4GAUGE.CFG:2513: cmCrit(I,ModeSecondaryCritical,56,adpal.pcc,adpa12.pcc,AmmoBinGAUSS);
L4GAUGE.CFG:2514: cmCrit(J,ModeSecondaryCritical,57,adpal.pcc,adpa12.pcc,AmmoBinAFC25);
```
`adpa12.pcc` — digit one for lowercase L — does not exist. `adpal2.pcc` does.
Two of 1345 lines, so the GAUSS and AFC25 ammo-bin criticals have been loading
a missing palette since 1996. This is the original's bug, present in the
shipped config; the archive is sacred and the shipped binary lives with it, so
we live with it too. Noted only so the next person who sees a warning about
`adpa12.pcc` does not go hunting for a reconstruction defect.
## Method note
Zero is the right fix precisely because it is invisible — and that is what made
it unverifiable. The `BT_TRANS_PROVOKE` positive control (fill the tail with
`0xFF00` instead) is what turned "I cannot see a difference" into "1030 pixels,
here they are, here is the shape". See `emulator/render-bridge/gauge-ab/README.md`
for the rig, `oormask.py` for the mask, and the caution about within-boot vs
across-boot noise floors that nearly cost this fix.