TM radial gun: registered (default OFF) + label-bias fix that removes the bias but
retracts its own earlier learning claim === TASK 1: REGISTERED AS GUN 14, DEFAULT `off` === The radial TM gun is now a first-class rack member (`TMPATTERN`, id 14), forceable alone with `TR_RACK_TMPATTERN=both` plus every other `TR_RACK_*=off`. DEFAULT IS `off`, and the justification matters: `both` would let it compete for selection AND (because the shared VirtualTracker ring is order-sensitive) shift every other gun's learning order, so it CANNOT leave the default path unchanged. With `off` its predict and spawnBullets are additionally GATED on rack admission (the only gun wired that way), so the shipped default never spawns it at all: zero cost, zero ring perturbation. Live proof: 1-round battle with only TMPATTERN racked -> `gun 14 (TMPattern): vShots=400 selected=104 other-gun selections=0`. Default-path-unchanged proof: parity checks that the 15-gun default bestGun/ selectGun equals the old 14-gun rack RNG-draw-for-RNG-draw, that gun 14 is never selected by default, and acceptance 12/12. Cost: 0.36 ms/tick (predict 0.30 + onResult 0.05) ~= 3% of the 13.16 ms budget. Tsetlin in the same harness is 1.62 ms/tick, so the new gun is ~4.5x cheaper. === TASK 2: THE LABEL-BIAS FIX - AND A RETRACTION === Root cause confirmed: under bmPoint a SHORT radial correction resolves the virtual bullet BEFORE the base arrival tick, so the label was dropped (labelMisses). Fix: defer the label in a pending queue and flush it once the arrival tick is recorded; labels still come from the BASE arrival tick. labelMisses 4,281,695 -> 0 training samples 1,071,824 -> 5,345,847 (x5) radial head acc 48.8% -> 57.0% (shuffled control 20.0%) bmPoint hit rate 9.4/5.8% -> 9.1/5.7% (unchanged, within noise) So the fix IMPROVES LEARNING but NOT the metric. **RETRACTION OF THE PREVIOUS JOB'S CLAIM.** It reported the radial head's 48.8% against a 36.7% majority baseline and concluded "conditional learning, not a constant bias". With the bias removed, the correctly-measured majority baseline is **58.2%** - so the head at 57.0% is AT/BELOW majority. The earlier apparent conditional learning was PARTLY AN ARTEFACT OF THE BIASED SAMPLE. The bmPoint metric win is real (TMRadial > Linear early 16/2 p=0.0013, overall 18/0 p<0.0001; > shuffled 18/0 p<0.0001) but it comes from a NET-POSITIVE AVERAGE RADIAL SHIFT, not from beating a majority classifier. Recorded plainly rather than left standing. Guards: test_tm_pattern_registration 20 (new), test_tm_pattern_rack_live 4 (new), test_gun_harness 39, test_vbullet_metric 11, test_power_selection 3 (the SIGSEGV is gone - the knn_gun rewrite is now committed), test_adaptive_radar 41, test_tfil_ring_weights 24, test_power_policy 26, test_ram_decision 28, test_rack_membership 38, test_selector_tiebreak 19, test_tm_pattern_learning 3, acceptance_offline_vs_online 12/12. ModularBot compiles (release). Note: `common_libs/tests/range_guns.nim` still builds 14 offline drivers (the offline sweep constructs TmPatternGun directly and acceptance only inspects ids 0..13), so nothing breaks - but a future job wanting it in the offline rack must add a 15th driver and mirror the live admission gating. gun_stats.jsonl now emits 15 rows; downstream tooling should ignore id 14.
This commit is contained in:
@@ -139,15 +139,18 @@ proc testParseMembership() =
|
||||
|
||||
proc testDefaultsAllBoth() =
|
||||
clearRackEnv()
|
||||
# The shipped table is all-`both` EXCEPT the new TM pattern gun (id 14),
|
||||
# which defaults to `off` so it cannot alter the default selection.
|
||||
var allBoth = true
|
||||
for m in DefaultRackMembership:
|
||||
if m != rmBoth: allBoth = false
|
||||
check "defaults: the shipped membership table is all-`both`", allBoth
|
||||
for i in 0..<RackGunNames.len:
|
||||
let want = if i == 14: rmOff else: rmBoth
|
||||
if DefaultRackMembership[i] != want: allBoth = false
|
||||
check "defaults: the shipped table is all-`both` except TMPATTERN=off", allBoth
|
||||
let loaded = loadRackMembership()
|
||||
check "defaults: with a clean environment loadRackMembership() == shipped table",
|
||||
loaded == DefaultRackMembership
|
||||
check "defaults: RackGunNames covers the shipped 14-gun rack",
|
||||
RackGunNames.len == 14 and DefaultRackMembership.len == 14
|
||||
check "defaults: RackGunNames covers the shipped 15-gun rack",
|
||||
RackGunNames.len == 15 and DefaultRackMembership.len == 15
|
||||
|
||||
proc testEnvOverrides() =
|
||||
clearRackEnv()
|
||||
@@ -161,8 +164,8 @@ proc testEnvOverrides() =
|
||||
m[9] == rmOnlyMelee
|
||||
check "env: TR_RACK_HEADON=off removes only HeadOn (id 0)",
|
||||
m[0] == rmOff
|
||||
check "env: every untouched gun keeps the all-`both` default",
|
||||
m[1] == rmBoth and m[3] == rmBoth and m[13] == rmBoth
|
||||
check "env: every untouched gun keeps its shipped default",
|
||||
m[1] == rmBoth and m[3] == rmBoth and m[13] == rmBoth and m[14] == rmOff
|
||||
putEnv("TR_RACK_KNN", "banana")
|
||||
check "env: unknown values are ignored, not fatal",
|
||||
loadRackMembership()[12] == rmBoth
|
||||
|
||||
Reference in New Issue
Block a user