FIX an incomplete commit: TMHORIZON was admitted unconditionally at HEAD

MY ERROR. `aed579b` committed `ModularBot.nim` (which wires the new gun as id 15)
and `guns/tm_horizon.nim`, but I staged only three files and left job-72's RACK
REGISTRATION behind in the working tree. Consequence at HEAD:

- `common_libs/gun_harness/selector.nim` still had the 15-entry rack table
  (ids 0..14) with no TMHORIZON name, so
- `TR_RACK_TMHORIZON` was never read (a silent no-op), and
- id 15 is PAST the table, and `rackAdmitted` documents "an id past the
  membership table is admitted" -> **TMHORIZON was admitted unconditionally**.

So the committed default rack was `Pattern + TMHORIZON`, not the intended
`Pattern only`, and the gun could not be switched off by env at HEAD. This was
caught by a live A/B job that had to work around it with `GUN_RACK_DISABLE=15`.

FIX (this commit): the rack table goes to 16 entries with `TMHORIZON` appended at
id 15 defaulting to `rmOff`, plus the two tests whose length literals follow it
(`test_rack_membership` 15->16, `test_tm_pattern_registration` 15->16).
`DefaultRackMembership` is again Pattern-only with every other gun `off`.

NOTE ON SCOPE: `selector.nim` in the working tree also contains a CONCURRENT job's
power-policy threading (an `enemyEnergy` parameter). That work is still in flight
and is deliberately NOT included here - only the three rack hunks were staged.
The remainder stays unstaged for its own commit.

The lesson, recorded because it has bitten twice tonight in different forms: a
change is not committed until its registration/table counterpart is, and
`git add` of a hand-picked file list is exactly how a half-change ships.
This commit is contained in:
2026-09-22 23:46:56 +02:00
parent 9ba932d1b1
commit 81af5854df
3 changed files with 8 additions and 7 deletions
+5 -4
View File
@@ -44,10 +44,10 @@ import virtual_bullets
# transition the radar uses.
const
RackGunNames*: array[15, string] = [
RackGunNames*: array[16, string] = [
"HEADON", "LINEAR", "TSETLIN", "CIRCULAR", "GUESSFACTOR", "PATTERN",
"WALLBOUNCE", "ACCEL", "STOPSHOT", "DISPLACE", "AVGLEAD", "DECAYGF",
"KNN", "TMSELECT", "TMPATTERN"]
"KNN", "TMSELECT", "TMPATTERN", "TMHORIZON"]
RackEnvPrefix* = "TR_RACK_"
## SHIPPED DEFAULT: `onlyPattern`. Pattern (id 5) is admitted in both racks;
## every other gun is `off`. The selection mechanism is untouched and remains
@@ -57,7 +57,7 @@ const
## it never spawns a virtual bullet unless explicitly enabled, so the shared
## VirtualTracker ring head — and every other gun's learning order — is
## unchanged.
DefaultRackMembership*: array[15, RackMembership] = [
DefaultRackMembership*: array[16, RackMembership] = [
rmOff, # 0 HEADON — off (measured: worst over-selected gun)
rmOff, # 1 LINEAR — off
rmOff, # 2 TSETLIN — off
@@ -72,7 +72,8 @@ const
rmOff, # 11 DECAYGF — off
rmOff, # 12 KNN — off
rmOff, # 13 TMSELECT — off
rmOff] # 14 TMPATTERN — off (already shipped off; TM pattern gun)
rmOff, # 14 TMPATTERN — off (already shipped off; TM pattern gun)
rmOff] # 15 TMHORIZON — off (horizon-based TM corrector; expected to lose)
proc parseRackMembership*(value: string): RackMembership =
## Parse a `TR_RACK_<GUN>` value. Empty / unknown values fall back to the
+2 -2
View File
@@ -164,8 +164,8 @@ proc testDefaultsOnlyPattern() =
let loaded = loadRackMembership()
check "defaults: with a clean environment loadRackMembership() == shipped table",
loaded == DefaultRackMembership
check "defaults: RackGunNames covers the shipped 15-gun rack",
RackGunNames.len == 15 and DefaultRackMembership.len == 15
check "defaults: RackGunNames covers the shipped 16-gun rack",
RackGunNames.len == 16 and DefaultRackMembership.len == 16
proc testFloorRespectsAdmission() =
## The FLOOR path (`bestRate <= 0` or below the floor rate) historically fell
@@ -62,7 +62,7 @@ proc seedOldRack(t: var VirtualTracker, targetId: int) =
# ── registration table ────────────────────────────────────────────────────────
proc testTable() =
check "rack: RackGunNames has 15 entries", RackGunNames.len == 15
check "rack: RackGunNames has 16 entries", RackGunNames.len == 16
check "rack: the new gun is named TMPATTERN at id 14",
RackGunNames[TmPatternId] == "TMPATTERN"
check "rack: the new gun defaults to `off`",