Files
SirStone 5e32ec16df 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.
2026-09-26 19:20:23 +02:00

162 lines
6.8 KiB
Nim

## Guard test for the boot-time env report's Part 2 (the warnings).
##
## NO battle, NO Java, NO server. Run with:
## nim c -r common_libs/tests/test_env_report.nim
##
## It pins the two tables that must not drift:
## 1. the KNOWN TR_*/GUN_* name set covers every env read in the tree, so a
## new knob cannot silently start producing a false "unknown variable"
## warning (and, conversely, the set cannot rot);
## 2. the compile-time define map covers every `{.intdefine.}`/`{.strdefine.}`
## /`{.booldefine.}` symbol in the tree, and classifies the ONE real env
## twin (`TMH_NSTATES` -> `TR_TMHORIZON_NSTATES`) correctly.
import std/[os, strutils, sets, sequtils]
import gun_harness/selector
import "../../ModularBot_garage/src/env_report"
var failures = 0
proc check(name: string, ok: bool) =
if ok: echo "PASS: ", name
else: echo "FAIL: ", name; inc failures
const repoRoot = currentSourcePath().parentDir.parentDir.parentDir
# ── the source surface the scan walks (the bot's real modules) ───────────────
proc scannedFiles(): seq[string] =
## .nim files under common_libs (excluding common_libs/tests, which are
## probes/measurement scripts, not bot code) and ModularBot_garage/src.
## env_report.nim is excluded: it DEFINES the known set, so scanning it is
## circular (it also names "suggested but nonexistent" env vars on purpose).
for dir in [repoRoot / "common_libs", repoRoot / "ModularBot_garage" / "src"]:
for path in walkDirRec(dir):
if not path.endsWith(".nim"): continue
if "/tests/" in path: continue
if path.endsWith("/env_report.nim"): continue
result.add path
proc literalsOn(line: string): seq[string] =
## Double-quoted string literals on one line (env names have no escapes).
var i = 0
while i < line.len:
if line[i] == '"':
var j = i + 1
while j < line.len and line[j] != '"': inc j
if j >= line.len: break
result.add line[i + 1 ..< j]
i = j + 1
else:
inc i
proc isKnownOrPrefix(name: string, known: HashSet[string]): bool =
## A literal counts as covered when it is a known name OR a prefix of one
## (`TR_RACK_` is the rack prefix; `TR_`/`GUN_` are the filter prefixes).
if name in known: return true
for k in known:
if k.startsWith(name): return true
proc defineSymbolsOn(line: string): seq[string] =
## ` TMH_NCLAUSES* {.intdefine.} = 40` -> "TMH_NCLAUSES"
for pragma in ["{.intdefine.}", "{.strdefine.}", "{.booldefine.}"]:
if pragma in line:
var sym = line.split('{')[0].strip()
if sym.endsWith("*"): sym.setLen(sym.len - 1)
let parts = sym.splitWhitespace()
if parts.len > 0: result.add parts[^1]
# ── 1. the known-name set ────────────────────────────────────────────────────
proc testKnownNames() =
let known = knownEnvNames()
let s = known.toHashSet()
check "known set has no duplicates", known.len == s.len
check "known set only holds TR_*/GUN_* names",
known.allIt(it.startsWith("TR_") or it.startsWith("GUN_"))
check "known set covers all 17 rack names",
RackGunNames.allIt((RackEnvPrefix & it) in s)
for name in ["TR_MOVEMENT", "TR_POWER_ENERGY_MIN", "TR_TMHORIZON_NSTATES",
"GUN_VBULLET_METRIC", "TR_ENV_REPORT", "GUN_SELECTOR_SEED",
"TR_RACK_TMHORIZON", "TR_TMHORIZON_NSTATES"]:
check "known set contains " & name, name in s
# ── 2. the pure warning helpers ──────────────────────────────────────────────
proc testUnknownEnvNames() =
let unknown = unknownEnvNames(@[
("TR_POWER_LOG", "1"), ("GUN_STATS_PATH", "/tmp/x"),
("TR_TMHORIZON_NSTATE", "5"), ("PATH", "/bin"),
("TMH_NSTATES", "2"), ("JAVA_HOME", "/jdk")])
check "unknownEnvNames finds the misspelled TR_* only",
unknown == @["TR_TMHORIZON_NSTATE"]
check "unknownEnvNames ignores non TR_*/GUN_* names",
unknownEnvNames(@[("PATH", "/bin")]) == @[]
proc testDefineMap() =
check "isCompileTimeDefine(TMH_NSTATES)", isCompileTimeDefine("TMH_NSTATES")
check "isCompileTimeDefine(TM_S_DEF)", isCompileTimeDefine("TM_S_DEF")
check "isCompileTimeDefine(TR_TMHORIZON_NSTATES) is false",
not isCompileTimeDefine("TR_TMHORIZON_NSTATES")
check "defineWarningMessage is empty for a non-define",
defineWarningMessage("TR_MOVEMENT", "x") == ""
let m1 = defineWarningMessage("TMH_NSTATES", "2")
check "TMH_NSTATES warns it is compile-time and names TR_TMHORIZON_NSTATES",
"COMPILE-TIME define (-d:TMH_NSTATES=2)" in m1 and
"TR_TMHORIZON_NSTATES=2" in m1
let m2 = defineWarningMessage("TMH_NCLAUSES", "40")
check "TMH_NCLAUSES says TR_TMHORIZON_NCLAUSES does not exist",
"TR_TMHORIZON_NCLAUSES does not exist" in m2
let m3 = defineWarningMessage("TM_S_DEF", "1.5")
check "TM_S_DEF says this knob is compile-time only",
"compile-time only" in m3
let defs = setCompileTimeDefines(@[
("TMH_NSTATES", "2"), ("TR_MOVEMENT", "tfil"), ("TM_S_DEF", "1.5")])
check "setCompileTimeDefines finds both -d symbols",
defs == @["TMH_NSTATES", "TM_S_DEF"]
# ── 3. the tree scans (the anti-drift guard) ─────────────────────────────────
proc testTreeScan() =
let known = knownEnvNames().toHashSet()
var literals = 0
var missing: seq[string]
for path in scannedFiles():
for line in lines(path):
for lit in literalsOn(line):
if lit.startsWith("TR_") or lit.startsWith("GUN_"):
inc literals
if not isKnownOrPrefix(lit, known):
missing.add path.extractFilename & ":" & lit
check "tree scan is alive (>= 50 TR_*/GUN_* literals)", literals >= 50
check "every TR_*/GUN_* literal in the tree is in the known set: " &
$missing, missing.len == 0
proc testDefineScan() =
let mapped = CompileTimeDefineMap.mapIt(it.defineName).toHashSet()
var found: seq[string]
for path in scannedFiles():
for line in lines(path):
for sym in defineSymbolsOn(line):
found.add sym
var missing: seq[string]
for sym in found:
if sym notin mapped: missing.add sym
check "tree define scan is alive (>= 20 symbols)", found.len >= 20
check "every intdefine/strdefine/booldefine is in the map: " &
$missing, missing.len == 0
# ── driver ───────────────────────────────────────────────────────────────────
testKnownNames()
testUnknownEnvNames()
testDefineMap()
testTreeScan()
testDefineScan()
if failures > 0:
echo "\n", failures, " check(s) FAILED"
quit(1)
echo "\nAll env-report checks passed."