25 KiB
Two untested owner claims: the spinner gun, and a fair melee field
The owner reported two things from watching the GUI (2026-09-25):
- "I never seen a gun that learns wall movement or circular movement like
spinning bot so fast - like a gun made on purpose for those movements" —
a spinner-specific advantage of BitBrain over the shipped
Patterngun. - "bitbrain gun is crushing in melee, the fast adaptation is a killer feature there" — a melee advantage of BitBrain over the shipped melee rack.
Both had been recorded as untested for a specific reason, not refuted:
- Claim 1's strongest case was absent from every panel. The legacy roster
(
tools/robocode_shim/robots.json) has no purpose-built constant-turn spinner.docs/gauntlet_bitbrain_vs_pattern.md(j117) found no regular-vs- dodger difference (Mann-Whitney p=0.85 on damage) but its "regular" bucket was wall-followers / campers / a rammer / a flood-filler, anddocs/gun_campaign.md(j121) explicitly flagged the spinner half as UNTESTED. - Claim 2 was tested against the wrong field.
docs/melee_bitbrain_ab.md(j116) ran a 4-bot melee against weak in-repo adversaries and ModularBot won 97–100 % of rounds regardless of gun — a ceiling effect. The result was "not detectable", and the doc itself says the question remains open until a field exists that can punish a bad gun.
This document closes both. It adds the missing true constant-turn spinner fixture, reruns the gun A/B on it (with a convergence analysis, because the claim is about speed of adaptation), and reruns the melee A/B on a strong field of battle-validated legacy champions.
DIRECT ANSWERS (MEASURED)
- Claim 1 — spinner gun: REFUTED on a finally-fair field. Against the two true constant-turn spinners plus the sample SpinBot, BitBrain (
decay) is not better thanPatternon any metric: damage −13.4 dmg/run (0/3 spinners positive; MDE 15.3), round wins +0.00 (both arms win 5/5 — saturated), our gun's hit rate −4.4 pp (MDE 10.7). Theretainedmemory mode is the same (−14.3 dmg/run, 1/3). The convergence trajectory — the actual claim — shows BitBrain starts lower on round 1 (54.4 % vs Pattern's 69.0 %) and catches up to roughly the same level by round 5 (75.4 % vs 71.5 %); the per-run cross-round adaptation delta is +7.7 pp for BitBrain vs +0.4 pp for Pattern, but p=0.38 (not significant), and the within-round first-vs-second-half metric is the opposite (−2.7 vs +5.5 pp, p=0.45). There is no measured fast-adaptation advantage.- Claim 2 — melee: NOT SUPPORTED on a finally-fair field. The j116 ceiling is gone: on a strong field of three battle-validated legacy champions (Diamond + Dookious + GresSuffurd) ModularBot wins only 30 % of rounds with
pattern(18/60), versus 97–100 % against the old weak field. On that field BitBrain does not beat the shipped melee rack:bb_decayis −11.8 score/run and −0.08 wins/run vspattern(p=0.90 / p=1.0), andbb_retis −123.5 score/run and −0.50 wins/run (p=0.21 / p=0.35). Every point estimate is on the wrong side of the claim. The field is fair but the test is underpowered for small effects (score MDE ±312 on a mean of 992, ≈31 %; wins MDE 1.34 on a mean of 1.5). A large advantage (≥ ~31 % score) is excluded; a smaller one is unmeasured at n=12.
MEASURED = the numbers in this doc. INFERRED = mechanisms and style
labels, stated as such. Raw captures are not committed (they live under
/tmp/ab/j124_spinner/ and /tmp/melee_strong_field/); every number below is
reproducible from the committed harnesses.
1. The new adversary: ConstantSpinner [MEASURED]
common_libs/test_framework/adversaries/ConstantSpinner/ — a minimal Nim Tank
Royale bot whose entire run() loop is:
setRadarTurnRate(45.0)
setTurnRate(bot.turnRate) # constant body turn, deg/tick
setTargetSpeed(bot.speed) # constant forward speed
Its path is a circle of radius v / ω (a single frequency, perfectly
periodic). The gun is plain head-on (aim at the enemy's current position,
fire power 1.0 whenever the gun is cool) — it is a movement fixture, not a
fighter. No randomness, no adaptation, no wall logic: the server's wall
collision is the only non-periodic perturbation.
The requested turn rate is clamped to the maximum reachable at the target speed
(MAX_TURN_RATE − 0.75·speed), so the actual turn rate stays exactly
constant instead of being server-clamped while the bot accelerates or slides
along a wall. Both rate and speed are env-configurable
(SPIN_TURN_RATE, SPIN_SPEED, SPIN_FIRE_POWER), and make_variant.sh
generates named per-rate bot directories that reuse the one committed binary.
Why this is not just SpinBot. The premise that the roster had no spinner
is only half true, and the measurement says so: the sample SpinBot's capture
trace turns at a near-constant −6.2 deg/tick (94.9 % mode share), because it
requests the speed-dependent maximum. What was genuinely missing is a rate
that is (a) exactly constant — not varying with speed near walls — and
(b) not the maximum. ConstantSpinner provides both, at a slow (3 deg/tick)
and a fast (6 deg/tick) rate, both at speed 5.
Fixture validation (from the adversary's own capture trace)
Per-tick body turn and speed of each spinner opponent, pooled over its 12 runs
(3 arms × 4 runs), read from the capture's s* fields:
| opponent | ticks | turn mode (deg/tick) | mode share | turn SD | speed mode | speed mode share | wall-hug frac |
|---|---|---|---|---|---|---|---|
| ConstantSpinner_s3 | 8176 | 3.0 | 93.9 % | 0.720 | 5.0 | 89.0 % | 21.3 % |
| ConstantSpinner_s6 | 8183 | 6.0 | 94.3 % | 1.391 | 5.0 | 95.0 % | 17.4 % |
| SpinBot (control) | 7891 | −6.2 | 94.9 % | 1.067 | 5.0 | 97.3 % | 6.1 % |
The s3 variant has the lowest turn SD of all three — the exactly-constant
rate the claim needs. The wall-hug fraction is the only source of non-mode
ticks (the bot grinds a wall, keeps turning, and leaves).
It really fights
Across the 4 runs per arm, the spinner opponents fired 449–478 shots
(s3), 421–447 (s6) and 120–128 (SpinBot) and were scored by the
server in every round. In a 3-round smoke vs Diamond it fired 59 shots and won
round 1 (firstPlaces=1). It is a valid, scored adversary.
2. Claim 1 — the spinner gun test [MEASURED]
Design. One frozen ModularBot built from git archive HEAD at commit
6c21dc4c58caaaaf68dc670a28a7c0d6948e3f3e (binary sha256
cfd11b5fdf3bcfe217c5d9033e2b20a618eb3b2e30d9bd41913d88eb6a0cfeef), movement
pinned to TR_MOVEMENT=strafe in every arm (the gun-campaign standard), so
every delta is a pure gun delta.
Panel (tools/ab/panel_spinner.txt, 9 opponents): 3 spinners
(ConstantSpinner_s3, ConstantSpinner_s6, sample SpinBot) + 3 known regular
movers (WallAvoider, DiamondStealer, HawkOnFire) + 3 known dodgers
(Diamond, CassiusClay, GresSuffurd), all legacy champions from
/tmp/tr_bots/.
Arms (tools/ab/arms_spinner.txt, 3 arms, same binary):
| arm | env (beyond TR_MOVEMENT=strafe) |
role |
|---|---|---|
pattern |
(none) | shipped onlyPattern rack — reference |
bitbrain |
TR_RACK_PATTERN=off TR_RACK_BITBRAIN=both TR_BITBRAIN_GAINS=1.0,1.25,1.5,2.0 TR_BITBRAIN_MEM=decay |
the owner's config |
bitbrain_ret |
... TR_BITBRAIN_MEM=retained |
"adapt across the battle" mode |
Protocol. 9 opponents × 3 arms × 4 runs × 5 rounds = 108 battles / 540
rounds, --conc 6, 0 failed, 0 never started, 0 liveness exclusions
(tournament_run.sh --wait-arena). Runner tools/ab/tournament_run.sh,
analyzer tools/ab/spinner_analyze.py (primaries + hit rate + convergence),
cross-checked with tools/ab/tournament_analyze.py.
Liveness (verified from each run's own boot report). Every declared env
token reached the process; the rack lines read rack active 1v1 = PATTERN for
pattern and = BITBRAIN for both BitBrain arms; TR_MOVEMENT = strafe (source: env) in every run. Every opponent fired and was scored.
2.1 Per-opponent paired table (deltas are arm − pattern)
bitbrain (decay):
| opponent | style | dmg/run ref→arm | Δdmg | wins/run ref→arm | Δwins | our hit% ref→arm | Δhit (pp) |
|---|---|---|---|---|---|---|---|
| ConstantSpinner_s3 | spinner | 397.5→390.5 | −7.0 | 5.00→5.00 | +0.00 | 56.10→55.77 | −0.33 |
| ConstantSpinner_s6 | spinner | 400.1→391.2 | −8.9 | 5.00→5.00 | +0.00 | 69.01→68.14 | −0.87 |
| SpinBot | spinner | 472.0→447.8 | −24.2 | 5.00→5.00 | +0.00 | 84.37→72.27 | −12.10 |
| WallAvoider | regular | 251.3→245.4 | −6.0 | 3.75→3.25 | −0.50 | 30.62→31.22 | +0.60 |
| DiamondStealer | regular | 237.7→234.4 | −3.3 | 2.00→2.25 | +0.25 | 30.51→28.70 | −1.81 |
| HawkOnFire | regular | 172.5→198.6 | +26.1 | 3.50→4.25 | +0.75 | 22.82→25.36 | +2.54 |
| Diamond | dodger | 87.7→106.7 | +19.0 | 0.25→0.50 | +0.25 | 8.85→9.07 | +0.22 |
| CassiusClay | dodger | 134.4→113.2 | −21.2 | 2.75→2.00 | −0.75 | 13.18→12.83 | −0.35 |
| GresSuffurd | dodger | 180.6→167.9 | −12.6 | 3.25→3.00 | −0.25 | 15.58→13.65 | −1.93 |
bitbrain_ret (retained):
| opponent | style | dmg/run ref→arm | Δdmg | wins/run ref→arm | Δwins | our hit% ref→arm | Δhit (pp) |
|---|---|---|---|---|---|---|---|
| ConstantSpinner_s3 | spinner | 397.5→384.8 | −12.8 | 5.00→5.00 | +0.00 | 56.10→55.23 | −0.87 |
| ConstantSpinner_s6 | spinner | 400.1→403.2 | +3.1 | 5.00→5.00 | +0.00 | 69.01→69.04 | +0.04 |
| SpinBot | spinner | 472.0→438.9 | −33.1 | 5.00→5.00 | +0.00 | 84.37→76.13 | −8.23 |
| WallAvoider | regular | 251.3→307.0 | +55.7 | 3.75→3.00 | −0.75 | 30.62→37.28 | +6.66 |
| DiamondStealer | regular | 237.7→215.1 | −22.6 | 2.00→1.75 | −0.25 | 30.51→28.36 | −2.16 |
| HawkOnFire | regular | 172.5→178.2 | +5.8 | 3.50→4.00 | +0.50 | 22.82→21.55 | −1.27 |
| Diamond | dodger | 87.7→96.0 | +8.3 | 0.25→0.50 | +0.25 | 8.85→8.28 | −0.57 |
| CassiusClay | dodger | 134.4→107.9 | −26.5 | 2.75→0.75 | −2.00 | 13.18→12.66 | −0.51 |
| GresSuffurd | dodger | 180.6→156.0 | −24.5 | 3.25→2.75 | −0.50 | 15.58→13.78 | −1.80 |
2.2 Pooled dashboard (explanation, not the verdict)
| arm | runs | dmg/run | dmg taken/run | wins/run | round wins | win rate | our hit rate | incoming hit rate |
|---|---|---|---|---|---|---|---|---|
pattern |
36 | 259.3 | 216.8 | 3.39 | 122/180 | 67.8 % | 28.78 % | 12.45 % |
bitbrain |
36 | 255.1 | 215.0 | 3.36 | 121/180 | 67.2 % | 27.81 % | 12.92 % |
bitbrain_ret |
36 | 254.1 | 218.7 | 3.08 | 111/180 | 61.7 % | 27.82 % | 12.69 % |
2.3 Cross-opponent aggregation (the verdict layer, n=9 opponents)
| arm | metric | mean Δ | spread (SD) | 95 % CI | sign test | p(sign) | p(sign-flip) | p(Wilcoxon) | MDE |
|---|---|---|---|---|---|---|---|---|---|
bitbrain |
damage | −4.23 | 16.78 | [−15.19, +6.74] | 2/9 | 0.180 | 0.457 | 0.407 | 15.67 |
bitbrain |
wins | −0.03 | 0.44 | [−0.32, +0.26] | 3/6 | 1 | 1 | 0.915 | 0.41 |
bitbrain |
our hit rate (pp) | −1.56 | 4.17 | [−4.28, +1.17] | 3/9 | 0.508 | 0.328 | 0.286 | 3.90 |
bitbrain_ret |
damage | −5.17 | 27.50 | [−23.14, +12.79] | 4/9 | 1 | 0.602 | 0.407 | 25.68 |
bitbrain_ret |
wins | −0.31 | 0.74 | [−0.79, +0.18] | 2/6 | 0.688 | 0.344 | 0.292 | 0.69 |
bitbrain_ret |
our hit rate (pp) | −0.97 | 3.79 | [−3.44, +1.50] | 2/9 | 0.180 | 0.496 | 0.124 | 3.54 |
2.4 The sub-claim's own field: the 3 spinners only
| arm | metric | mean Δ | spread (SD) | 95 % CI | sign test | p(sign) | p(sign-flip) | MDE |
|---|---|---|---|---|---|---|---|---|
bitbrain |
damage | −13.38 | 9.46 | [−24.09, −2.66] | 0/3 | 0.25 | 0.25 | 15.31 |
bitbrain |
wins | +0.00 | 0.00 | [+0.00, +0.00] | 0/0 | 1 | 1 | 0.00 |
bitbrain |
our hit rate (pp) | −4.43 | 6.64 | [−11.95, +3.08] | 0/3 | 0.25 | 0.25 | 10.74 |
bitbrain_ret |
damage | −14.25 | 18.17 | [−34.81, +6.31] | 1/3 | 1 | 0.5 | 29.39 |
bitbrain_ret |
wins | +0.00 | 0.00 | [+0.00, +0.00] | 0/0 | 1 | 1 | 0.00 |
bitbrain_ret |
our hit rate (pp) | −3.02 | 4.54 | [−8.16, +2.11] | 1/3 | 1 | 0.5 | 7.34 |
Both BitBrain arms lose on damage and on our hit rate on the spinner field; every point estimate is on the wrong side of the claim. Round wins are saturated (5/5 for every arm on every spinner), so the win metric cannot discriminate there.
2.5 Style split
| arm | style | n | mean Δdmg | mean Δwins | mean Δour-hit (pp) |
|---|---|---|---|---|---|
bitbrain |
spinner | 3 | −13.38 | +0.00 | −4.43 |
bitbrain |
regular | 3 | +5.62 | +0.17 | +0.44 |
bitbrain |
dodger | 3 | −4.92 | −0.25 | −0.69 |
bitbrain_ret |
spinner | 3 | −14.25 | +0.00 | −3.02 |
bitbrain_ret |
regular | 3 | +12.96 | −0.17 | +1.08 |
bitbrain_ret |
dodger | 3 | −14.23 | −0.75 | −0.96 |
The spinner bucket is the worst bucket for BitBrain, not the best. This is the exact opposite of the owner's claim, and it agrees with j121's SpinBot result (Batch 1 +25.3 dmg was a small-panel fluctuation; Batch 2 −4.7 dmg).
2.6 CONVERGENCE — the actual claim
Our gun's per-round hit rate, pooled over runs. R1…R5:
all 9 opponents:
| arm | R1 | R2 | R3 | R4 | R5 | R1→Rlast |
|---|---|---|---|---|---|---|
pattern |
29.3 % | 29.6 % | 28.9 % | 26.6 % | 29.6 % | +0.3 pp |
bitbrain |
26.6 % | 28.2 % | 27.5 % | 28.6 % | 28.3 % | +1.7 pp |
bitbrain_ret |
28.9 % | 27.5 % | 26.8 % | 26.4 % | 29.6 % | +0.8 pp |
true spinners only:
| arm | R1 | R2 | R3 | R4 | R5 | R1→Rlast |
|---|---|---|---|---|---|---|
pattern |
69.0 % | 60.4 % | 82.4 % | 68.9 % | 71.5 % | +2.5 pp |
bitbrain |
54.4 % | 69.8 % | 62.5 % | 68.7 % | 75.4 % | +21.0 pp |
bitbrain_ret |
66.8 % | 63.8 % | 65.6 % | 68.3 % | 67.8 % | +1.1 pp |
The per-round trajectory looks like a BitBrain convergence story — but it is a start-lower, catch-up-to-the-same-level story: BitBrain is 14.6 pp worse in round 1, then reaches Pattern's level by round 5, never above it. A gun that adapts faster should be ahead in the early rounds, not behind.
Per-run adaptation deltas on the true spinners (n = 3 spinners × 4 runs = 12 per arm):
conv= hit rate over rounds 2..5 minus round 1 (cross-round);within= hit rate in the second half of a round minus the first half.
| arm | n | conv mean Δ | conv SD | within mean Δ | within SD |
|---|---|---|---|---|---|
pattern |
12 | +0.39 pp | 9.86 | +5.50 pp | 15.65 |
bitbrain |
12 | +7.67 pp | 24.65 | −2.72 pp | 27.92 |
bitbrain_ret |
12 | −4.66 pp | 19.26 | +16.54 pp | 34.43 |
Two-sample permutation test (200 000 draws, seed 0x5eed5eed) against
pattern:
| arm | conv Δ − ref Δ | p(conv) | within Δ − ref Δ | p(within) |
|---|---|---|---|---|
bitbrain |
+7.29 pp | 0.379 | −8.22 pp | 0.446 |
bitbrain_ret |
−5.05 pp | 0.490 | +11.04 pp | 0.381 |
The cross-round hint is not significant (p=0.38) and the within-round adaptation — the fastest possible timescale — points the other way (−2.7 pp vs Pattern's +5.5 pp). There is no measured speed advantage.
2.7 Direct answer — claim 1
REFUTED on a finally-fair field. The field now contains two purpose-built constant-turn spinners at different rates (3 and 6 deg/tick), the sample SpinBot, and regular/dodger controls; movement is pinned; the adversary fires and is scored; 108 battles, no exclusions. On that field:
- BitBrain (
decay) is not better thanPatternon damage (−4.2 dmg/run overall; −13.4 on the spinners, MDE 15.3), on round wins (−0.03 overall; +0.00 on spinners — saturated), or on our hit rate (−1.6 pp overall; −4.4 pp on the spinners, MDE 10.7). - The convergence trajectory — the mechanism the claim is about — shows a slower start and a catch-up to parity, not a faster or higher convergence; the cross-round delta is non-significant (p=0.38) and the within-round delta is opposite.
retainedmemory behaves likedecay(all deltas negative on the spinner field, none significant).
The owner's impression is consistent with BitBrain changing its aim over the
first rounds (visible in a GUI) — the trajectory is real — but the change does
not buy a hit-rate or damage advantage over Pattern; it recovers a deficit
BitBrain itself created.
3. Claim 2 — the fair melee test [MEASURED]
The j116 field is replaced. The old field was ModularBot + WaveSurfer +
PatternMover + RandomMover, against which ModularBot won 97–100 % of rounds
whatever the gun (a ceiling). The new field is ModularBot + Diamond +
Dookious + GresSuffurd — three battle-validated legacy champions from
/tmp/tr_bots/ (wave-surfing dodgers with real guns; tools/robocode_shim/robots.json)
that can and do punish a bad gun.
Arms (only ModularBot's melee rack differs):
| arm | env | role |
|---|---|---|
pattern |
(none) — shipped default melee rack | reference |
bb_ret |
TR_RACK_PATTERN=off TR_RACK_BITBRAIN=melee TR_BITBRAIN_MEM=retained TR_BITBRAIN_LOG=1 |
adapt across the battle |
bb_decay |
... TR_BITBRAIN_MEM=decay TR_BITBRAIN_GAINS=1.0,1.25,1.5,2.0 TR_BITBRAIN_LOG=1 |
the owner's config |
Protocol. One frozen ModularBot from git archive HEAD at commit
5fe28574abb3af43af8e0bd4e86d3f8f14a54f21 (binary sha256
7dc1b7c1f9a29cc4009cba1f2b53d2424cff1a6d1829fe4322df80783764b46c),
12 runs × 5 rounds per arm = 36 battles / 180 rounds, each run a fresh
random-position melee with its own Tank Royale server. Runner
common_libs/tests/measure_melee_strong_field.nim + run_melee_strong_field.sh;
analyzer common_libs/tests/analyze_melee_ab.py (the same permutation + MDE
machinery as the 1v1 A/Bs). 36/36 runs OK (two runs needed the harness's
auto-retry for a slow JVM boot).
3.1 Is the ceiling gone? YES
ModularBot's pattern arm wins 18/60 rounds (30 %) and its mean per-round
rank is 2.07/4 (never sweeping); against the j116 field the same rack won
97–100 % and ranked 1.0. The field now has enough teeth to separate guns in
principle: a bad gun would lose more rounds and score less. (Contrast: j116
pattern score/run was ~2965 against the weak field; here it is 992.)
3.2 Arm summary (melee: score = server round score = damage + survival bonus)
| arm | runs | wins/rd | score/run | survival/run | final rank | mean rank | score share | targets | target changes |
|---|---|---|---|---|---|---|---|---|---|
pattern |
12 | 18/60 (30 %) | 992 | 483 | 1.83 | 2.067 | 31.9 % | 3.00 | 32.58 |
bb_decay |
12 | 17/60 (28 %) | 980 | 483 | 1.83 | 1.900 | 31.6 % | 3.00 | 31.75 |
bb_ret |
12 | 12/60 (20 %) | 868 | 433 | 2.08 | 2.067 | 28.2 % | 3.00 | 33.33 |
3.3 Per-run values (never just the mean)
pattern wins: r1=2 r2=0 r3=1 r4=4 r5=1 r6=1 r7=2 r8=1 r9=1 r10=0 r11=2 r12=3
score: r1=1046 r2=625 r3=892 r4=1404 r5=592 r6=800 r7=1331 r8=1051 r9=769 r10=904 r11=1229 r12=1261
surv: r1=500 r2=400 r3=500 r4=700 r5=250 r6=450 r7=600 r8=450 r9=350 r10=450 r11=600 r12=550
bb_decay wins: r1=3 r2=0 r3=1 r4=0 r5=2 r6=0 r7=2 r8=2 r9=1 r10=2 r11=2 r12=2
score: r1=1100 r2=838 r3=820 r4=741 r5=908 r6=635 r7=1198 r8=1181 r9=1089 r10=1194 r11=960 r12=1099
surv: r1=500 r2=400 r3=400 r4=300 r5=500 r6=300 r7=600 r8=600 r9=500 r10=600 r11=500 r12=600
bb_ret wins: r1=3 r2=0 r3=1 r4=2 r5=1 r6=2 r7=0 r8=1 r9=0 r10=1 r11=1 r12=0
score: r1=1167 r2=779 r3=937 r4=1111 r5=815 r6=942 r7=467 r8=944 r9=862 r10=849 r11=704 r12=845
surv: r1=600 r2=350 r3=500 r4=500 r5=450 r6=400 r7=250 r8=500 r9=450 r10=450 r11=350 r12=400
3.4 Permutation tests (per-run, two-sided) and MDE
diff(A−B) is pattern − bitbrain; a positive diff means Pattern is better.
| metric | A | B | diff(A−B) | perm p | Mann-Whitney p | MDE (n=12) |
|---|---|---|---|---|---|---|
| score | pattern | bb_decay | +11.75 | 0.903 | 1.000 | ±312.0 (31 % of mean) |
| score | pattern | bb_ret | +123.50 | 0.205 | 0.341 | ±312.0 |
| survival | pattern | bb_decay | +0.00 | 1.000 | 0.883 | ±138.7 |
| survival | pattern | bb_ret | +50.00 | 0.309 | 0.278 | ±138.7 |
| wins | pattern | bb_decay | +0.083 | 1.000 | 0.952 | ±1.34 |
| wins | pattern | bb_ret | +0.500 | 0.352 | 0.288 | ±1.34 |
| mean rank | pattern | bb_decay | +0.167 | 0.552 | 0.542 | ±0.68 |
| mean rank | pattern | bb_ret | −0.000 | 1.000 | 0.954 | ±0.68 |
No metric separates the arms; the only arm with a nominal lead anywhere is
bb_decay on mean per-round rank (+0.167 in its favour, p=0.55). The point
estimates for score and wins favour pattern for both BitBrain arms.
3.5 Liveness — the premise WAS exercised
- Rack applied, verified per run:
patternreadsrack active melee = PATTERNandTR_RACK_BITBRAIN = off; both BitBrain arms readrack active melee = BITBRAINwithTR_RACK_PATTERN = offandTR_RACK_BITBRAIN = melee. All 36 runs pass (12/12 per arm). - Movement held fixed:
TR_MOVEMENT = strafe (source: env)in every run. - Targets rotate: 3.00 distinct targets/run and 31.8–33.3 target
changes/run; BitBrain resets on every switch (
bb-reset= 31.75 / 33.33 per run, equal to the target-change count;patternlogs 0). - The field is alive: ModularBot's score share is only 28–32 %, so the three champions together take ~68 %; ModularBot dies in many rounds (per-run survival varies widely, 250–700).
3.6 Direct answer — claim 2
NOT SUPPORTED on a finally-fair field. The j116 ceiling is removed: the new
field is strong enough that ModularBot wins only 30 % of rounds with the
shipped rack, so a real gun advantage had room to show. It did not show. On
score and round wins the point estimates favour the shipped pattern rack for
both BitBrain memory modes (bb_decay −11.8 score, −0.08 wins; bb_ret
−123.5 score, −0.50 wins), and nothing approaches significance. The mechanism
the owner describes was demonstrably exercised (targets rotate, BitBrain resets
on every switch), but it buys no measurable score or win advantage.
The honest caveat is power, not fairness: at 12 runs/arm the score MDE is ±312 on a mean of 992 (≈31 %). A large melee advantage (≥ ~31 % score) is excluded by this run; a smaller one is simply below the resolution of n=12. The field is fair; the question is now testable and the answer so far is "no".
MEASURED vs INFERRED
MEASURED: the ConstantSpinner fixture's per-tick turn/speed modes (table in
§1); the 108-battle spinner session (commit 6c21dc4, binary cfd11b5) with 0
failed / 0 never-started / 0 liveness exclusions; the per-opponent, pooled,
cross-opponent, spinner-only, style and convergence tables in §2; the 36-battle
strong-field melee session (commit 5fe2857, binary 7dc1b7c) with the arm
summary, per-run values, permutation p-values and MDEs in §3; the liveness boot
lines and target-switch/reset counts; the permutation/MDE machinery (reused from
tools/ab and common_libs/tests/analyze_melee_ab.py).
INFERRED: the style labels (from robots.json / the fixture's own
constants, never decompiled); the reading that "start-lower, catch-up" is a
deficit recovery rather than a fast adaptation; the mechanism by which BitBrain
reaches parity; the interpretation that a melee score effect smaller than the
n=12 MDE would be invisible.
Reproduce
# 1. build the spinner and its two rate presets
cd common_libs/test_framework/adversaries/ConstantSpinner
nim c -d:release --nimcache:/tmp/nc_j124 --out:out/ConstantSpinner src/ConstantSpinner.nim
./make_variant.sh ConstantSpinner_s3 3 5 /tmp/tr_spinners
./make_variant.sh ConstantSpinner_s6 6 5 /tmp/tr_spinners
# 2. the spinner gun A/B (waits for a free arena; ~8 min)
cd /home/davide/Projects/SirRoboGarage
TOURNAMENT_NIMCACHE=/tmp/nc_j124 tools/ab/tournament_run.sh \
--arms tools/ab/arms_spinner.txt --panel tools/ab/panel_spinner.txt \
--runs 4 --rounds 5 --conc 6 --wait-arena 45 --outdir /tmp/ab/j124_spinner
python3 tools/ab/spinner_analyze.py /tmp/ab/j124_spinner --reference pattern
# 3. the fair melee A/B (waits for a free arena; ~8 min)
nim c --nimcache:/tmp/nc_j124 --path:common_libs \
common_libs/tests/measure_melee_strong_field.nim
MELEE_RUNS=12 MELEE_ROUNDS=5 MELEE_ARMS="pattern bb_ret bb_decay" \
MELEE_FIELD=/tmp/tr_bots/Diamond,/tmp/tr_bots/Dookious,/tmp/tr_bots/GresSuffurd \
common_libs/tests/run_melee_strong_field.sh /tmp/melee_strong_field
python3 common_libs/tests/analyze_melee_ab.py /tmp/melee_strong_field --reference pattern
Files
common_libs/test_framework/adversaries/ConstantSpinner/— the fixture (src/ConstantSpinner.nim, JSON,.sh,make_variant.sh, committed binary).tools/ab/panel_spinner.txt,tools/ab/arms_spinner.txt— the 9-opponent panel and 3 arms.tools/ab/spinner_analyze.py— N-arm analyzer: primaries, hit rate, spinner-only stats, per-round convergence + permutation tests.common_libs/tests/measure_melee_strong_field.nim,common_libs/tests/run_melee_strong_field.sh— the strong-field melee harness/driver (§3).