#116: steam JOINERS were silently locked to VETERAN -- restore their experience selector

Oracle isolated it: "standard mode still having heat and leaks only occurred in
steam not in solo.  Sauron and Lynx did not have the issue but Conn Man, Rajel
and myself did."  The night-9 logs close the case:

    affected  (Oracle/ConnMan/Rajel):  [exp] experience=2 heatModelOn=1
    clean     (Sauron's std sessions): [exp] experience=1 heatModelOn=0

CAUSE: the glass front end's JOIN layout trimmed the menu to "the mech list +
the JOIN button; everything else is the operator's call" -- and the experience
selector's hidden default is 2 (veteran).  So HOSTS got whatever they picked
(Sauron hosted the lobbies all night -> his standard landed), while every
JOINER launched as veteran regardless of anything they did -- which is why
Oracle's cycling-the-settings experiment changed nothing, and why solo (full
menu) never showed the problem.  heat >= veteran, hence "standard but heating".

DESIGN CONFIRMED BY THE USER before fixing: experience is PER-PLAYER by the
original design -- the sysop set each user's tier and mixed-experience matches
were legal.  Architecture already supports it end to end: each node's master
player reads its OWN egg's experience (btMission+0xE4 -> BTPlayer @004c0bc8),
so per-node choice IS per-player choice.

FIX: the join layout gains the GroupExperience selector (the selection->egg
write path is the pre-existing host path, field-proven).  Also: the front end
now prints "[fe] pilot experience=<x> (join|host/solo)" at launch, so every
future field log answers this class of report without asking anyone.

VERIFICATION BOUNDARY, stated plainly: builds both configs; the write path is
shared with the host flow which the field already exercises; the visible
selector + the [fe] line need one join-mode launch to eyeball, and the field
re-test is Oracle running a standard steam match as a JOINER and seeing no
heat.

Tooling note recorded in test-harness.md: bash-heredoc python collapses one
backslash level even single-quoted -- a "\n" arrives as a real newline and
replaces silently no-op.  Build backslashes from bytes([92]); verify replaces
by length delta, not by the script saying "fixed".  (This burned four edit
rounds tonight and several earlier C2001 hunts.)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-02 10:40:51 -05:00
co-authored by Claude Opus 5
parent 1bcee1f9eb
commit 3109cfc49a
2 changed files with 19 additions and 2 deletions
+5
View File
@@ -117,6 +117,11 @@ sleep <duration>; kill $relay; bt_kill_ours
- **Stale exe:** `LNK1104` / a bench ignoring new diagnostics = the previous
process still holds `btl4.exe`, or the build silently didn't run — check the
`btl4.vcxproj ->` line printed, then rerun.
- **Editing source through bash-heredoc python collapses `\` one level** even
single-quoted -- a `"\n"` you meant as backslash-n arrives as a real newline,
the "fix" silently no-ops (`good == bad`), and the C2001 hunt repeats. Build
backslashes as `bytes([92])`/`chr(92)`, and verify a replace by LENGTH DELTA
or a re-read, never by the script printing "fixed".
- Bench artifacts (`*.EGG` copies, `*_NNN.png`, bench logs) must be deleted
from `content/` before any dist cut; field logs are never committed.
+14 -2
View File
@@ -742,8 +742,18 @@ static void
{
// JOIN trim: the mech list + the JOIN button; callsign is the edit
// control (repositioned in BTFrontEnd_Run). Everything else is the
// operator's call.
y = MenuTopY; AddGroup(GroupVehicle, MenuCol2X, &y);
// operator's call -- EXCEPT experience, which is PER-PLAYER by the
// original design (the sysop set each user's tier; mixed-experience
// matches were legal), and each node's master reads its OWN egg's
// value, so mixing already works end to end.
//
// #116: this group was missing here, so joiners silently launched with
// the hidden menu default (veteran) no matter what they believed they
// selected -- "standard mode still having heat and leaks only occurred
// in steam": hosts got their pick, all three affected players were
// JOINERS, and the one clean player (Sauron) was the one HOSTING.
y = MenuTopY; AddGroup(GroupVehicle, MenuCol2X, &y);
y = MenuTopY; AddGroup(GroupExperience, MenuCol3X, &y);
AddButton(GroupLaunch, MenuCol5X, MenuClientH - 190, 220, 52);
return;
}
@@ -1173,6 +1183,8 @@ int
strcpy(self.vehicle, kVehicles[menu.selection[GroupVehicle]].key);
strcpy(self.color, kColors[menu.selection[GroupColor]].key);
strcpy(self.experience, kExperience[menu.selection[GroupExperience]].key);
printf("[fe] pilot experience=%s (%s)\n", self.experience,
FeJoinOnly() ? "join" : "host/solo");
strcpy(self.badge, kBadges[menu.selection[GroupBadge]].key);
strcpy(self.patch, kPatches[menu.selection[GroupPatch]].key);
strcpy(self.dropzone, kDropZones[menu.selection[GroupDropZone]].key);