7a6237ec20
The gun at rack id 16 learned a multiplier for Pattern's lead, separately
per range band. It was called BITBRAIN and shipped a TR_BITBRAIN_* prefix,
which is why the name read as a neural network it no longer contains.
guns/bitbrain_gun.nim -> guns/lead_gain.nim (rack id 16 UNCHANGED)
RackGunNames[16] BITBRAIN -> LEADGAIN
TR_BITBRAIN_* knobs -> TR_LEADGAIN_*
[bb] log line -> [lg]
BACKWARD COMPATIBILITY is mandatory: the live .env carries
TR_RACK_BITBRAIN=both, TR_BITBRAIN_GAINS, TR_BITBRAIN_MEM=decay and
TR_BITBRAIN_LOG=1, and those must keep behaving identically. The new ADE+SBC
gun (next commit) claims the BITBRAIN name and the TR_BITBRAIN_* prefix, so
the namespace is disambiguated by ONE deterministic switch, TR_BITBRAIN_NET
(default 0):
TR_BITBRAIN_NET unset/0 -> LEGACY: the 14 frozen legacy suffixes are aliases
for TR_LEADGAIN_*, and TR_RACK_BITBRAIN still
selects rack id 16. One [depr] line on stderr
names the new spelling of each honoured knob.
TR_BITBRAIN_NET = 1 -> the TR_BITBRAIN_* names belong to the new gun.
The legacy suffix set and the new gun's knob set are DISJOINT, so no name is
ever claimed twice; the new name always wins over its alias.
Parity: shipped rack is still onlyPattern, shipped movement is still strafe.
Guards unchanged: test_env_report 25, test_rack_membership 48,
test_tm_pattern_registration 20, test_lead_gain_registration 13 (was
test_bitbrain_registration), test_bitbrain 56, test_gun_harness 39,
test_tfil_commit_env 30. New: test_lead_gain_legacy 24.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
176 lines
7.4 KiB
Nim
176 lines
7.4 KiB
Nim
## Backward-compatibility guard for the LEADGAIN rename (gun id 16).
|
|
##
|
|
## The owner's live `.env` predates the rename and carries `TR_RACK_BITBRAIN`,
|
|
## `TR_BITBRAIN_GAINS`, `TR_BITBRAIN_MEM`, `TR_BITBRAIN_LOG`. Those names used to
|
|
## address the corrector that is now called LEADGAIN, and they MUST keep working,
|
|
## because the `TR_BITBRAIN_*` prefix now belongs to the new ADE+SBC gun
|
|
## (`guns/bitbrain_net.nim`, rack id 17). This test pins the disambiguation:
|
|
##
|
|
## * `TR_BITBRAIN_NET` unset/0 -> LEGACY MODE: every `TR_BITBRAIN_<X>` in the
|
|
## frozen `LegacyKnobEnvNames` set is an alias for `TR_LEADGAIN_<X>`, and
|
|
## `TR_RACK_BITBRAIN` still selects rack id 16.
|
|
## * `TR_BITBRAIN_NET=1` -> NEW-NETWORK MODE: the `TR_BITBRAIN_*` names
|
|
## belong to the new gun; this gun reads only `TR_LEADGAIN_<X>`.
|
|
##
|
|
## The two name sets are DISJOINT, so the mapping is total and deterministic.
|
|
## No Java, no battle, no network build.
|
|
##
|
|
## Run: nim c -r common_libs/tests/test_lead_gain_legacy.nim
|
|
|
|
import std/[os, strutils]
|
|
import gun_harness/virtual_bullets
|
|
import gun_harness/selector
|
|
import guns/lead_gain
|
|
|
|
const LeadGainId = 16
|
|
|
|
var failures = 0
|
|
proc check(name: string, ok: bool) =
|
|
if ok: echo "PASS: ", name
|
|
else: echo "FAIL: ", name; inc failures
|
|
|
|
proc clearEnv() =
|
|
for suffix in LegacyKnobEnvNames:
|
|
delEnv(LegacyPrefix & suffix)
|
|
delEnv(NewPrefix & suffix)
|
|
delEnv(LegacyRackEnvName)
|
|
delEnv("TR_RACK_" & RackGunNames[LeadGainId])
|
|
delEnv(LG_NET_SWITCH_ENV)
|
|
|
|
# ── the alias table itself ───────────────────────────────────────────────────
|
|
|
|
proc testAliasTableIsDisjoint() =
|
|
## Every legacy name must be a `TR_BITBRAIN_<X>` whose `X` is in the frozen
|
|
## set, and the new name must be the `TR_LEADGAIN_<X>` of the same suffix.
|
|
var ok = LegacyKnobEnvNames.len == 14
|
|
var suffixes: seq[string]
|
|
for s in LegacyKnobEnvNames:
|
|
if s.len == 0 or s in suffixes: ok = false
|
|
suffixes.add s
|
|
check "table: 14 unique legacy suffixes", ok
|
|
check "table: the legacy prefix is TR_BITBRAIN_", LegacyPrefix == "TR_BITBRAIN_"
|
|
check "table: the new prefix is TR_LEADGAIN_", NewPrefix == "TR_LEADGAIN_"
|
|
# The corrector's own live knobs must all be in the alias set, otherwise the
|
|
# owner's `.env` silently stops working.
|
|
for knob in [LG_MEM_ENV, LG_GAINS_ENV, LG_LOG_ENV, LG_MIN_OBS_ENV, LG_DECAY_ENV,
|
|
LG_DECAY_FRAC_ENV, LG_RESET_ON_TARGET_ENV, LG_N_ENV, LG_NADE_ENV,
|
|
LG_RANGE_ENV, LG_WARMUP_ENV, LG_ADAPT_ENV, LG_CALIB_ENV, LG_SEED_ENV]:
|
|
let suffix = knob[NewPrefix.len .. ^1]
|
|
if suffix notin LegacyKnobEnvNames: ok = false
|
|
check "table: every corrector knob has a legacy alias", ok
|
|
|
|
# ── the switch ───────────────────────────────────────────────────────────────
|
|
|
|
proc testSwitch() =
|
|
clearEnv()
|
|
check "switch: unset => legacy mode (new ADE+SBC namespace disowned)",
|
|
not netSwitchOn()
|
|
putEnv(LG_NET_SWITCH_ENV, "0")
|
|
check "switch: 0 => legacy mode", not netSwitchOn()
|
|
putEnv(LG_NET_SWITCH_ENV, "1")
|
|
check "switch: 1 => new-network mode", netSwitchOn()
|
|
putEnv(LG_NET_SWITCH_ENV, "yes")
|
|
check "switch: yes => new-network mode", netSwitchOn()
|
|
putEnv(LG_NET_SWITCH_ENV, "banana")
|
|
check "switch: an unknown value is NOT new-network mode (fails safe)",
|
|
not netSwitchOn()
|
|
clearEnv()
|
|
|
|
# ── knob aliasing ────────────────────────────────────────────────────────────
|
|
|
|
proc testKnobAlias() =
|
|
clearEnv()
|
|
# the owner's exact .env
|
|
putEnv("TR_BITBRAIN_GAINS", "1.0,0.5,0.25")
|
|
putEnv("TR_BITBRAIN_MEM", "decay")
|
|
putEnv("TR_BITBRAIN_LOG", "1")
|
|
var g = initLeadGainGun()
|
|
check "alias: TR_BITBRAIN_GAINS feeds the candidate set",
|
|
g.cands == @[0.25, 0.5, 1.0]
|
|
check "alias: TR_BITBRAIN_MEM=decay is honoured", g.memMode == lgDecay
|
|
check "alias: TR_BITBRAIN_LOG=1 turns the log on", g.logEnabled
|
|
# the new name always wins over the legacy alias
|
|
putEnv("TR_LEADGAIN_GAINS", "0.5,0.75")
|
|
var g2 = initLeadGainGun()
|
|
check "alias: the NEW name wins when both are set", g2.cands == @[0.5, 0.75]
|
|
# the switch disowns the whole legacy namespace
|
|
putEnv(LG_NET_SWITCH_ENV, "1")
|
|
delEnv("TR_LEADGAIN_GAINS")
|
|
var g3 = initLeadGainGun()
|
|
check "alias: TR_BITBRAIN_NET=1 makes the legacy names inert for this gun",
|
|
g3.memMode == lgPerRound and not g3.logEnabled and
|
|
g3.cands == @[0.0, 0.25, 0.5, 0.75, 1.0]
|
|
# ... and then the NEW names still work
|
|
putEnv("TR_LEADGAIN_MEM", "retained")
|
|
var g4 = initLeadGainGun()
|
|
check "alias: TR_LEADGAIN_* is always read, in both modes",
|
|
g4.memMode == lgRetained
|
|
clearEnv()
|
|
|
|
# ── rack alias ───────────────────────────────────────────────────────────────
|
|
|
|
proc testRackAlias() =
|
|
clearEnv()
|
|
putEnv(LegacyRackEnvName, "both")
|
|
let m = loadRackMembership()
|
|
check "rack: TR_RACK_BITBRAIN=both still selects LEADGAIN (id 16)",
|
|
m[LeadGainId] == rmBoth and
|
|
vBulletAdmitted(LeadGainId, rm1v1, m, true)
|
|
putEnv(LG_NET_SWITCH_ENV, "1")
|
|
let m2 = loadRackMembership()
|
|
check "rack: TR_BITBRAIN_NET=1 hands the name to the new ADE+SBC gun (id 17)",
|
|
m2[LeadGainId] == rmOff
|
|
clearEnv()
|
|
putEnv("TR_RACK_LEADGAIN", "both")
|
|
putEnv(LegacyRackEnvName, "off")
|
|
let m3 = loadRackMembership()
|
|
check "rack: the new name wins over the legacy alias",
|
|
m3[LeadGainId] == rmBoth
|
|
clearEnv()
|
|
|
|
# ── the deprecation line ─────────────────────────────────────────────────────
|
|
|
|
proc testDeprecationLine() =
|
|
clearEnv()
|
|
check "depr: no legacy knobs => no deprecation line",
|
|
lgDeprecationLine().len == 0
|
|
putEnv("TR_BITBRAIN_GAINS", "1.0")
|
|
let line = lgDeprecationLine()
|
|
check "depr: a legacy knob produces exactly one line naming the new name",
|
|
line.startsWith("[depr]") and
|
|
line.contains("TR_BITBRAIN_GAINS -> TR_LEADGAIN_GAINS") and
|
|
line.contains(NewPrefix)
|
|
putEnv(LG_NET_SWITCH_ENV, "1")
|
|
check "depr: the line is silent once the switch is flipped",
|
|
lgDeprecationLine().len == 0
|
|
clearEnv()
|
|
|
|
# ── shipped-default parity ───────────────────────────────────────────────────
|
|
|
|
proc testDefaultParity() =
|
|
clearEnv()
|
|
let m = loadRackMembership()
|
|
var onlyPattern = true
|
|
for i in 0..<RackGunNames.len:
|
|
let want = if i == 5: rmBoth else: rmOff
|
|
if m[i] != want: onlyPattern = false
|
|
check "parity: a clean env still loads the shipped onlyPattern rack", onlyPattern
|
|
check "parity: the rack is still 17 guns at id 16 = LEADGAIN",
|
|
RackGunNames.len == 17 and RackGunNames[LeadGainId] == "LEADGAIN"
|
|
var g = initLeadGainGun()
|
|
check "parity: a clean env resolves the shipped candidate set",
|
|
g.cands == @[0.0, 0.25, 0.5, 0.75, 1.0] and g.memMode == lgPerRound
|
|
clearEnv()
|
|
|
|
testAliasTableIsDisjoint()
|
|
testSwitch()
|
|
testKnobAlias()
|
|
testRackAlias()
|
|
testDeprecationLine()
|
|
testDefaultParity()
|
|
|
|
if failures > 0:
|
|
echo "\n", failures, " check(s) FAILED"
|
|
quit(1)
|
|
echo "\nAll LEADGAIN legacy-alias checks passed."
|