Controls: the .CTL positional-id off-by-one -- CONFIRMED live and FIXED (step 2a)

The streamed L4 mapping resource carries the binary's positional attribute ids
(stick=3, throttle=4) but MechControlsMapper chained from Subsystem::NextAttributeID
== 2 -- every streamed record resolved ONE MEMBER LATE (attr 4 -> pedalsPosition,
verified via the new permanent BT_CTRLMAP_LOG diagnostic in CreateStreamedMappings).
A latent real-pod bug: the serial RIO throttle would drive the pedals member; the
dev keyboard bridge masked it. Fix per the mechweap/mech attrPad idiom: ids pinned
to the binary numbering, id-2 gap padded, static_assert-locked. Torso + weapon
chains verified already aligned. Regression: BT_FORCE_THROTTLE headless walk clean
(speedDemand=61.501 through authentic InterpretControls, gait cycles, no faults).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-17 21:59:51 -05:00
co-authored by Claude Fable 5
parent 3f49915d76
commit b26e8205e3
7 changed files with 113 additions and 24 deletions
+39
View File
@@ -19,3 +19,42 @@ first); this file carries the step-by-step detail, evidence, and verification tr
(purity build); `-DBT_GLASS=ON` and ON/ON configures print correct gate state; the
BT_STEAM-without-BT_GLASS negative test FATAL_ERRORs. Full 3-config BUILD matrix becomes
meaningful from step 2 (first gated code) and is re-run there.
## 2026-07-17 — Step 2a: the .CTL positional-attribute off-by-one — CONFIRMED and FIXED (ungated)
**The bug [T2, live-verified]:** the streamed `.CTL` "L4" mapping resource carries the 1995
binary's positional attribute ids (stick=3, throttle=4, ...), resolved at install time by
`Simulation::GetAttributePointer(id)``AttributeIndexSet::Find(id)` = `attributeIndex[id-1]`
(positional). `MechControlsMapper` chained its enum on `Subsystem::NextAttributeID == 2`, but
the binary's chain reaches 3 (one base attribute we don't publish) — so EVERY streamed mapper
record landed one member late.
**Evidence (new `BT_CTRLMAP_LOG=1` diagnostic in `LBE4ControlsManager::CreateStreamedMappings`,
`engine/MUNGA_L4/L4CTRL.cpp` — permanent, env-gated, default off).** Before the fix
(`build-pod` Debug, `-egg DEV.EGG`, dev platform):
```
rec 0 subsys 0 group 1(Joy) elem 0 attrID 3 -> +0xe4 (= throttlePosition: WRONG, stick intended)
rec 1 subsys 0 group 0(Scalar) elem 0 attrID 4 -> +0xe8 (= pedalsPosition: WRONG, throttle intended)
rec 2 subsys 0 group 3(Button) elem 63 attrID 6 -> +0xf0 (= speedDemand: WRONG, reverse intended)
rec 4-6 attrID 10/11/12 -> lookRight/lookBehind/lookDown (one late; LookLeft/Right/Behind intended)
```
Spacing attr3→attr4 was 4 bytes (Scalar) where stick→throttle must be 8 (ControlsJoystick).
The weapons chain (attrID 19 → +0x31c TriggerState) was already correct — mechweap was
pad-aligned in task #16 (gotcha #11). Torso (subsys 17) also aligned (MechSubsystem publishes
binary id 2). ONLY the mapper chain (subsys 0) was off. On the dev box the keyboard INPUT
BRIDGE (writes the mapper members directly, after the engine push) masked it; on a REAL POD the
serial RIO throttle scalar would have driven `pedalsPosition` and the stick x/y would have
driven throttle+pedals — the Phase-8 landmine prior art predicted.
**The fix (ungated, pod-correctness — user-approved 2026-07-17):** `mechmppr.hpp` pins the enum
to the binary numbering (`MechControlsMapperPadFirstAttributeID = 2`, stick=3 ... PilotArray=
0x16); `mechmppr.cpp` pads id 2 with a valid never-bound entry (the mech.cpp attrPad idiom) and
locks the base + pinned ids with `static_assert`s. `L4MechControlsMapper::TargetRangeExponent`
(chained) moves 0x16→0x17, matching the binary's own arithmetic; it is bound by name (audio
zoom-blip), so no consumer shifts.
**After the fix:** `attrID 3 -> +0xdc` (stick), `attrID 4 -> +0xe4` (throttle, 8-byte spacing
✓), `attrID 6 -> +0xec` (reverse), `10/11/12 -> +0xfc/+0x100/+0x104` (the look trio); torso +
weapons unchanged. Regression: headless forced-walk run (`BT_FORCE_THROTTLE=1`) drives normally
`[mppr] thr=1 -> speedDemand=61.501`, gait cycles, position advances, 31/31 subsystems
simulated, no faults.