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
+23
View File
@@ -2124,6 +2124,29 @@ void
if (mapping->mappingType == ControlsMapping::DirectMapping)
{
attribute = subsystem->GetAttributePointer(mapping->attributeID);
//
// BT_CTRLMAP_LOG=1: dump each streamed .CTL record and the member
// OFFSET its attributeID resolved to on the live subsystem. The
// stream carries the 1995 binary's positional attribute ids, so a
// resolved offset that differs from the binary's member offset for
// that id means the reconstruction's id chain is misaligned (the
// gotcha-#11 class). Audit trail: docs/GLASS_COCKPIT.md step 2a.
//
{
static const int s_ctrlmapLog =
(getenv("BT_CTRLMAP_LOG") != 0 && *getenv("BT_CTRLMAP_LOG") != '0');
if (s_ctrlmapLog)
{
DEBUG_STREAM << "[ctrlmap] rec " << i
<< " subsys " << mapping->subsystemID
<< " group " << (int)mapping->controlsGroup
<< " elem " << element
<< " attrID " << (int)mapping->attributeID
<< " -> +0x" << std::hex
<< (attribute ? (int)((char*)attribute - (char*)subsystem) : -1)
<< std::dec << "\n" << std::flush;
}
}
switch (mapping->controlsGroup)
{
case ScalarGroup: