j142 retire the ADE+SBC gun (rack id 17): the owner watched it, it does not learn, throw it away

Remove guns/bitbrain_net.nim (+README), test_bitbrain_net.nim,
measure_bitbrain_scaling.nim, rack id 17 and all of its plumbing in
selector.nim / ModularBot.nim / env_report.nim, the TR_BITBRAIN_NET switch
and the NEW-NETWORK TR_BITBRAIN_* knobs, and the BitBrainNet arm of
run_prediction_quality.nim.

With id 17 gone there is nothing to disambiguate, so the legacy namespace
becomes the ONLY one: TR_RACK_BITBRAIN always selects id 16 LEADGAIN and
every TR_BITBRAIN_<X> in the frozen 14-suffix alias set always means
TR_LEADGAIN_<X>. The alias layer and its [depr] line stay.

KEPT: the common_libs/bitbrain/ SBC library (learned_surfer imports
bitbrain/sbc), lead_gain at id 16 with env TR_LEADGAIN_* and log tag [lg],
and the c9b6753 crash fix (NumRackGuns widths + test_rack_stat_width).

Tombstone: docs/bitbrain_campaign.md ## RETIRED and one cross-reference line
in docs/gun_campaign.md. Shipped defaults unchanged: clean env -> rack
active 1v1 = PATTERN, movement default strafe.
This commit is contained in:
2026-09-26 19:20:23 +02:00
parent c9b67530db
commit 5e32ec16df
18 changed files with 279 additions and 1732 deletions
+26 -51
View File
@@ -22,7 +22,6 @@ import virtual_bullets
# TR_RACK_KNN=off -> removed from both racks
# TR_RACK_TMPATTERN=off (shipped default for the new TM pattern gun)
# TR_RACK_LEADGAIN=both -> the per-range-band lead-gain corrector (id 16)
# TR_RACK_BITBRAIN=both -> the ADE+SBC gun (id 17); also needs TR_BITBRAIN_NET=1
#
# SHIPPED DEFAULT IS `onlyPattern`: Pattern (id 5) is admitted in both racks and
# every other gun is `off`. This is a deliberate, measured decision, not a
@@ -39,18 +38,17 @@ import virtual_bullets
# TR_RACK_TSETLIN=both TR_RACK_CIRCULAR=both TR_RACK_GUESSFACTOR=both \
# TR_RACK_WALLBOUNCE=both TR_RACK_ACCEL=both TR_RACK_STOPSHOT=both \
# TR_RACK_DISPLACE=both TR_RACK_AVGLEAD=both TR_RACK_DECAYGF=both \
# TR_RACK_KNN=both TR_RACK_TMSELECT=both TR_RACK_LEADGAIN=both \
# TR_RACK_BITBRAIN=both TR_BITBRAIN_NET=1 ./ModularBot
# TR_RACK_KNN=both TR_RACK_TMSELECT=both TR_RACK_LEADGAIN=both ./ModularBot
#
# The mode itself is derived from SERVER truth (`getEnemyCount()`), never from
# the tracker's known-enemy count, by `rackMode` in virtual_bullets — the same
# transition the radar uses.
const
RackGunNames*: array[18, string] = [
RackGunNames*: array[17, string] = [
"HEADON", "LINEAR", "TSETLIN", "CIRCULAR", "GUESSFACTOR", "PATTERN",
"WALLBOUNCE", "ACCEL", "STOPSHOT", "DISPLACE", "AVGLEAD", "DECAYGF",
"KNN", "TMSELECT", "TMPATTERN", "TMHORIZON", "LEADGAIN", "BITBRAIN"]
"KNN", "TMSELECT", "TMPATTERN", "TMHORIZON", "LEADGAIN"]
RackEnvPrefix* = "TR_RACK_"
## THE rack size, derived from `RackGunNames`. Every per-gun-indexed array and
## loop in the bot and in the harness MUST be sized with this, never with a
@@ -64,8 +62,10 @@ const
## (`guns/lead_gain.nim`). It USED to be called BITBRAIN; the name now
## describes its internals (it learns a multiplier for Pattern's lead per
## range band). Its rack id is UNCHANGED so every test that asserts the id
## literals still holds. The `BITBRAIN` name and the `TR_BITBRAIN_*` prefix
## now belong to the ADE+SBC gun `guns/bitbrain_net.nim` (rack id 17).
## literals still holds. It OWNS the `BITBRAIN` name and the `TR_BITBRAIN_*`
## env prefix unconditionally: the ADE+SBC gun that briefly took them (rack
## id 17, `guns/bitbrain_net.nim`) was RETIRED and removed — see
## `docs/bitbrain_campaign.md` §RETIRED.
## SHIPPED DEFAULT: `onlyPattern`. Pattern (id 5) is admitted in both racks;
## every other gun is `off`. The selection mechanism is untouched and remains
## fully functional — only the rack's membership changed. Re-enable any gun
@@ -74,7 +74,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[18, RackMembership] = [
DefaultRackMembership*: array[17, RackMembership] = [
rmOff, # 0 HEADON — off (measured: worst over-selected gun)
rmOff, # 1 LINEAR — off
rmOff, # 2 TSETLIN — off
@@ -91,41 +91,23 @@ const
rmOff, # 13 TMSELECT — off
rmOff, # 14 TMPATTERN — off (already shipped off; TM pattern gun)
rmOff, # 15 TMHORIZON — off (horizon-based TM corrector; expected to lose)
rmOff, # 16 LEADGAIN — off (per-range-band lead-gain corrector)
rmOff] # 17 BITBRAIN — off (the real ADE+SBC gun; also needs TR_BITBRAIN_NET=1)
rmOff] # 16 LEADGAIN — off (per-range-band lead-gain corrector)
## NOTE: the table is registered in the SAME commit as the gun id and the live
## wiring, so `TR_RACK_LEADGAIN=both` / `TR_RACK_BITBRAIN=both` are the ONLY
## things that admit those guns and an unset environment is byte-for-byte the
## shipped Pattern-only rack.
## wiring, so `TR_RACK_LEADGAIN=both` (or the legacy `TR_RACK_BITBRAIN=both`)
## are the ONLY things that admit that gun, and an unset environment is
## byte-for-byte the shipped Pattern-only rack.
const
## ── BACKWARD COMPATIBILITY: the legacy rack knob names ────────────────────
## `TR_RACK_<gun name>` is derived from `RackGunNames`, so renaming a gun
## silently retires its old switch. These entries keep an old switch alive:
## each maps a legacy `TR_RACK_*` name onto the gun id it used to address.
## `TR_RACK_BITBRAIN` is the ONE genuinely ambiguous legacy name — the rack is
## keyed by gun name, and the new ADE+SBC gun is now the one called
## `BITBRAIN`. It is disambiguated by the same switch the knobs use,
## `TR_BITBRAIN_NET` (default 0):
## * unset/0 -> LEGACY: `TR_RACK_BITBRAIN` selects LEADGAIN (id 16), the gun
## it always selected, and the new gun stays off (the shipped default);
## * 1 -> `TR_RACK_BITBRAIN` selects the new BITBRAIN gun (id 17).
## (The new gun additionally requires `TR_BITBRAIN_NET=1` in its own
## `predict`, so even an explicitly racked `TR_RACK_BITBRAIN=both` cannot turn
## it on while the namespace is still in legacy mode.)
## `TR_RACK_BITBRAIN` is the old name of the gun that is now called
## `LEADGAIN` (id 16) — and with the ADE+SBC gun (old id 17) retired, nothing
## else can claim it, so the mapping is UNCONDITIONAL. There is no namespace
## switch any more: `TR_RACK_BITBRAIN` always selects LEADGAIN.
RackLegacyAlias*: array[1, (string, int)] = [("TR_RACK_BITBRAIN", 16)]
RackLegacyAliasGunName* = "LEADGAIN" ## what the legacy name selects today
RackNetGunId* = 17 ## the ADE+SBC gun that owns the name once switched
proc netSwitchOwnsBitbrainName*(): bool =
## `TR_BITBRAIN_NET` (default 0) is THE disambiguation switch for the whole
## `TR_BITBRAIN_*` namespace. Unset/0 => the namespace is LEGACY and belongs
## to the renamed lead-gain corrector; 1 => it belongs to the ADE+SBC gun.
## Defined here (and identically in `guns/lead_gain.nim`) because
## `gun_harness/selector` must not depend on a concrete gun module.
case getEnv("TR_BITBRAIN_NET", "").strip().toLowerAscii()
of "1", "true", "yes", "on": true
else: false
RackLegacyAliasGunName* = "LEADGAIN" ## what the legacy name selects
proc parseRackMembership*(value: string): RackMembership =
## Parse a `TR_RACK_<GUN>` value. Empty / unknown values fall back to the
@@ -148,28 +130,21 @@ proc loadRackMembership*(): array[len(RackGunNames), RackMembership] =
## corresponding CURRENT name is unset, so a migrated config always wins.
result = DefaultRackMembership
var legacyTouched: seq[string]
let netOwns = netSwitchOwnsBitbrainName()
for i in 0..<len(RackGunNames):
let key = RackEnvPrefix & RackGunNames[i]
# While the namespace is LEGACY, `TR_RACK_BITBRAIN` must address ONLY the
# gun it always addressed (LEADGAIN, id 16) — never id 17, or a pre-rename
# `.env` would silently admit a gun that did not exist then.
if not netOwns and i == RackNetGunId: continue
let v = getEnv(key, "")
if v.len > 0:
result[i] = parseRackMembership(v)
if not netOwns:
for (key, gid) in RackLegacyAlias:
let current = RackEnvPrefix & RackGunNames[gid]
if getEnv(key, "").len > 0 and getEnv(current, "").len == 0:
result[gid] = parseRackMembership(getEnv(key, ""))
legacyTouched.add key
for (key, gid) in RackLegacyAlias:
let current = RackEnvPrefix & RackGunNames[gid]
if getEnv(key, "").len > 0 and getEnv(current, "").len == 0:
result[gid] = parseRackMembership(getEnv(key, ""))
legacyTouched.add key
if legacyTouched.len > 0:
let gid = RackLegacyAlias[0][1]
stderr.writeLine("[depr] legacy rack knob " & legacyTouched.join(",") &
" now names the ADE+SBC gun (BITBRAIN, rack id 17); it still selects " &
RackGunNames[gid] & " (rack id " & $gid &
") until TR_BITBRAIN_NET=1. Set TR_RACK_" & RackGunNames[gid] &
" is the old name of TR_RACK_" & RackGunNames[gid] & " (rack id " & $gid &
"); it still selects it. Set TR_RACK_" & RackGunNames[gid] &
" to make it explicit.")
let ActiveRackMembership* = loadRackMembership()
@@ -213,8 +188,8 @@ proc rackActive*(membership: openArray[RackMembership], mode: RackMode): string
# a POLICY: when set, the live selection is a deterministic deficit-round-robin
# over the named, ADMITTED guns instead of `chooseFromFit`'s ranking.
#
# TR_RACK_SHARE=pattern:50,bitbrain:50
# TR_RACK_SHARE=pattern:0.7,bitbrain:0.3
# TR_RACK_SHARE=pattern:50,leadgain:50
# TR_RACK_SHARE=pattern:0.7,leadgain:0.3
#
# Values are RELATIVE weights (fractions or percentages — only the ratio
# matters) and names are case-insensitive `RackGunNames` (the `GunNames` rack