Skip to content

Add validated v17 gun-control successor - #11

Draft
subodhbgwt wants to merge 31 commits into
mainfrom
claude/measurement-fixes
Draft

subodhbgwt wants to merge 31 commits into
mainfrom
claude/measurement-fixes

Conversation

@subodhbgwt

Copy link
Copy Markdown
Collaborator

What changed

  • freeze the exact active v17 source as a local control
  • add the v17 gun-control successor
  • extend replay auditing with home-pressure timing and attacker types
  • document the 30-game live replay audit and promotion gates

Why

All seven observed v17 losses were multi-gunner core destructions. Source review found that gunners ignored lone enemy builders, could spend 10 titanium rotating between equal targets, and did not prioritize enemy gunners actively aimed at our core.

Validation

  • 200/336 (59.5%) against exact v17; core kills 187-128
  • 145/168 against Oogbest-v6 versus control 140/168
  • 144/168 against meta-generalist-v1 versus control 142/168
  • deterministic targeting, tie-breaking, and core-threat-priority tests
  • Python compilation and local smoke match

The imported production source retains its original trailing whitespace so the frozen Python files remain byte-identical to the downloaded archive.

subodhbgwt and others added 30 commits July 30, 2026 08:15
gate.py
- the per-game "<bot> first" label was a wrong WORD, not wrong data: it always
  named the bot passed as bot_a (verified against fcode run and the replay -
  bot_a is team 0). Execution interleaves ABABAB, so nobody is "first". Label
  is now "as A" and the CSV column is side_a, with a legacy alias so the 9926
  historical rows migrate instead of blanking. gate_results.csv was never
  wrong; whole-history A-seat rates are strongly structured (bridge 84%,
  skerry 22%), which a scrambled column could not produce.
- per-map lines now print the seat split and flag SEAT-LOCKED maps, on decided
  games only so a crashed bot cannot dress 0/16 draws up as a seat lock. The
  old collapsed number hid the lock: 8/16 is exactly what a locked map yields
  when the candidate holds each seat half the time.
- default opponent is now generalist-v3, not the stale champion (== oogerebus3,
  which inverted the ranking of ten bots).
- prints the 95% CI and warns when it spans 50%.

MEASUREMENT-FINDINGS.md
- CORRECTED the noise floor. One draw per n cannot estimate a spread: three
  repeats of the same 168-game identical-code control gave 49%, 56%, 51% - the
  middle one PROMOTES a bot over itself. The band is +/-8, not +/-3, and a
  168-game PROMOTE is a 1-in-10 coin flip. Use seeds=8.
- games are not reproducible at all: 46 of 48 bots call random.* unseeded and
  --seed seeds the ENGINE, not the bot. Two identical SERIAL runs flipped 8/20
  winners on sprint (10/20 with --tle 0); seeding the bot RNG gave 0/16. Not
  the worker pool, not the TLE.
- ladder diagnosis, 200 live games: rank #1/86 at 62%, but 29% in the 150-299
  turn window against the top four, with the enemy core fully healing our
  siege in 12 of 23 losses. Does NOT reproduce locally, so a local gate can
  only prove nothing broke.

heal_audit.py - offline core damage vs healing per side, no API needed.

bots/exp_heal_lock_retreat (+ trace twin, + 9 deterministic tests)
- role-2 sieger leaves a provably non-converting siege when home is threatened.
- 336-game gate vs generalist-v3: 52% (CI 47-57), kills 149-142. No regression,
  no measurable gain - as expected, since local games never enter the failure
  regime. Activation proven by replay: 1696 retreats over 168 games.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diagnosis, from 200 live games and 110 downloaded replays: the ladder's ranking
function is how fast you get a gun onto the enemy core. Powered by SmartFridge
lands its first at t19, Pantheon at t24, we managed t60. An econ probe showed
titanium was NEVER the constraint - the core holds >120 Ti from round 0 and
peaks at 470 by t45 with 5 builders - so a single constant was making us arrive
last while sitting on unspent resources.

exp_early_siege (variant A): SIEGE_START 45 -> 25. First gun t84 -> t58.
  61% vs generalist-v3 at 336 games (CI 55-66, kills 183-111), 90% vs OogwayOld
  (control 86%), 93% vs lastpop2 (control 90%).

exp_siege_on_sight (variant B): the gate becomes state, not a round number -
  enemy core located and titanium above the unchanged floor, both true from ~t5.
  67% vs generalist-v3 at 336 games (CI 61-71, kills 211-91) and 63% head to
  head vs variant A. SHIPPED as live v2 at 17:20; v1 retained for rollback.

spar_rush: sparring partner only, our engine with SIEGE_START = 5. Never submit
  it. Nothing in bots/ rushed, so no local gate could see how a candidate
  handles one - and it found a hole 500+ games against our own lineage hid:
  generalist-v3 scores 39% against it (kills 58-91) while beating our own
  lineage 86-93%. WORKFLOW.md now requires gating every candidate against it.

Still open: gun-to-core conversion. Pantheon lands 89% of its guns within 6
tiles of the enemy core and 1% in its own half; we land roughly 30%. That is a
bigger measured gap than the timing one this commit closes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The kill budget is real: 500 HP core, 10 dmg/2 ammo per gunner shot, ammo 1:1
same-turn, so a kill is 200 Ti against a 500 bank and ~55 of Pantheon's 58
median turns are logistics rather than shooting. Every attempt to exploit that
still lost, and the causes are all different:

  exp_core_pressure  46% (43% vs rush) - own-half guns are real defensive value
  exp_relay          33% - launcher road delayed the first gun t35 -> t58
  strike-v1          27% - 100% placement, 1.9 guns/game, starved with no econ
  strike-mass        13% - same starvation with 12 builders
  spar_pantheon      49% (kills 79-79) - allocation gain, economy loss, cancel
  exp_siege3         1 building, 0 titanium collected, dead t62

THE WALL: role allocation and economy are the same knob here. Economy work only
happens in the non-sieger branch, so every builder moved to delivery is one
removed from income (2 siegers -> 4.6 guns + 4.0 harvesters; 3 -> 0 and 0; all
-> 4.5 and 0). Pantheon gets 18.7 guns on the enemy core from an economy the
same size as ours, so their builders farm AND deliver. Architectural, not a
parameter.

Engine facts banked: launch() throws a friendly builder 7 tiles from 1-2 tiles
away on a 1-turn cooldown for 20 Ti, so launchers ~6 apart give a hop per turn -
we build zero, Pantheon builds zero, SmartFridge builds ~1 at t17. Ammo is 1:1
and same-turn. Whether enemy builders can be launched is UNRESOLVED; the probe's
friendly control also failed, so it proves nothing.

exp_siege_on_sight (live v2) remains the best bot we have.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
  exp_opportunist  48% - any builder near their core plants a core-capable gun.
    Economy preserved (4.2 harvesters) but on-core guns did not rise: economy
    builders never travel far enough for the opportunity to exist.
  exp_cadre        - fixed 3-builder economy cadre, everyone later sieges, with
    a cheaper spawn threshold. 2.1 guns on core, 2.8 harvesters. A builder is
    30 Ti = THREE gunners, so a marginal builder must deliver >3 guns to pay for
    itself. Population is not the lever either.
  exp_forward_armor 52% (CI 45-60, kills 76-71) - barriers at the siege seat
    when no firing seat is available. Pantheon builds ~40/game with 39% in the
    4-6 band; we reached 1.2. The only variant above 50 with a positive kill
    differential, so it is being resolved at 336.
  exp_roadcrew     - dedicated builder lays the launcher road so siegers never
    stop. Still slower to first gun (t45 vs t36) and only 1.4 of 4 launchers
    completed. That is the THIRD way of funding the relay to fail; the mechanic
    does not pay in this engine.

Nothing has beaten exp_siege_on_sight (live v2). Thirteen experiments now agree
that in this architecture a builder either farms or delivers and never both,
and that titanium spent on builders is titanium not spent on guns. Pantheon
gets 18.7 guns on the enemy core from a 4.1-harvester economy; we get 4.6 from
4.0. That difference is in how their bot is written, not in a setting reachable
from here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… is not it

builder_trace.py (new): the replay records a create event with the new entity's
position but not who built it, so this tracks every builder's position per turn
and attributes each building to the adjacent friendly builder. That yields a
per-builder timeline.

Pantheon, one game:
  builder 3   t3 harvester, t5-t33 nine conveyors    pure economy
  builder 5   t9 harvester, t11-t25 eight conveyors  pure economy
  builder 88  t34,37,39,41 four gunners              pure delivery
  builder 97  t44,50 two gunners                     pure delivery

They do NOT interleave farming and delivery - they specialise exactly as we do,
which kills the "their builders do both" hypothesis from the previous commit.

exp_phase: first CADRE_SIZE builders farm, everyone later sieges (the ordering
the trace implies, with the parent's spawn rule untouched, unlike exp_cadre).
Better economy - 5.2 harvesters, 41.9 conveyors vs 3.8 and 32.8 - and the same
total guns, but they land late and in the wrong place: first gun t51 vs t34,
1.5 on the enemy core vs 3.5. exp_phase2 flattens the spawn curve on top; more
guns (10.8 vs 7.8 total) and still 2.0 on core at t56.

CORRECTION: I read ids 88/97 as evidence Pantheon fields ~90 units. Ids are
global across both teams and all entity types, and they create ~80 entities a
game (40 barriers, 21 guns, 18 conveyors), so those ids only mean "created
late". Unit counts are comparable - our median is 12 at game end. The scale
hypothesis is dead, and so is the concurrency one: their gun builders travel
DURING the economy phase, which is what exp_siege_on_sight already does.

Fifteen experiments, no improvement on live v2. The remaining difference is
per-unit efficiency inside the firing band, which none of these variants has
isolated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
exp_ammo 36% (CI 29-43, kills 45-101). I read the parent's
`if globalAmmo < 20: convert(20 - globalAmmo)` as a hard ceiling on ammunition.
It is not - runCore executes every turn, so it is a per-turn TOP-UP to 20, i.e.
~10 shots and 100 damage per turn sustained, enough to kill a core in five
turns. Ammo was never starved. The variant then made things worse by reserving
only 150 Ti against a 120 gun floor, starving the siege it was meant to feed;
retuning to 260 still left core damage at 256 against the parent's 535.

Pantheon's win condition, resolved from 120 rounds: 86% core_destroyed at a
median of t50, 14% titanium_collected at t1000, and 59% of all wins under 60
turns. They kill fast. An earlier note that their average core damage (357) was
below a core's 500 HP was WRONG - that average mixed their losses and their
1000-turn games together.

LIVE RESULT for exp_siege_on_sight (v2), 215 rounds:
  overall 106-109 (49%) against v1's 156-129 (55%), BUT 70 of v2's rounds were
  against Pantheon and SmartFridge versus 35 of v1's. Like-for-like on the same
  schedule v2 is 49% against v1's expected 46% - about +3 points, 1 SD.
  vs OopsGotYourElo 70% (v1: 52%), vs Besvikomat 57% (v1: 46%),
  vs SmartFridge 23% (v1: 10%). Rating 1652, rank #3 of 89, up from #5.

Sixteen local experiments, all rejected; the one change that shipped is holding
up on the ladder.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Teammate pushed v3-v6 while I was iterating. Per-version LIVE records show one
thing that matters enormously:

  v2 (ours) 54% (180 rounds)   vs Pantheon  1-14  (7%)
  v3        56% (205 rounds)   vs Pantheon  1-19  (5%)
  v6        56% ( 80 rounds)   vs Pantheon 10-5  (67%)   Orizon 1-9

v6 is the only bot any of us has fielded that beats Pantheon - the matchup I
spent sixteen experiments failing to crack. Its mechanism is a TEAM-WIDE RECALL:
the core raises a flag when it is genuinely hurt AND a real shooter is in vision
(hp < 400 + nearestEnemyGunner), and units come home. Crucially it is a SCORED
state worth 7-9, below attack's core-defence ceiling of 12, so a unit that can
build a killing gunner still builds it.

exp_recall  - ported as a hard override. REGRESSION: 44% vs our v2 (CI 39-49,
              kills 120-169). It pulled siegers off live firing seats.
exp_recall2 - ported as the soft priority v6 actually uses: build the gun if
              there is one, answer the recall only when travelling or when no
              seat is available. 51% vs our v2 (CI 46-57, kills 147-143) - no
              regression, which is the right profile for a defensive mechanism.

METHODOLOGY WARNING: oogbest-v6 scores 45% against our v2 locally and 52%
against spar_rush - the same 52% our v2 scores - yet live it goes 67% against
Pantheon where ours goes 7%. spar_rush DOES NOT MODEL PANTHEON, and no local
gate we have can see this matchup. The WORKFLOW.md section I added this morning
making it a mandatory gate overstates what it proves.

Also unaddressed: every version loses to Orizon (#3), Prompt Engineers Anonymous
(#4) and The Flotte Experience (#5) at ~10-24%. Three top-five teams, one shared
weakness, and nobody has looked at their replays.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Profiled Orizon (#3), Prompt Engineers Anonymous (#4) and The Flotte Experience
(#5) in games AGAINST US, so map and matchup are controlled:

  team                1st gun  guns on OUR core  conv  harv  barr   vs us
  Oogway (us)           t24          2.2         13.4  3.0   0.0
  Orizon                t18         16.0          8.0  1.9   0.2    13-2
  Prompt Engineers      t26         14.0          3.2  1.0   0.0    17-3
  Flotte                t22          6.5          0.0  0.0   5.7    22-3
  Pantheon              t22         18.7         17.7  4.1  39.8    10-5

Every team above us puts 3-8x more guns on our core than we put on theirs, and
every one runs a leaner economy than we do. Flotte runs NO economy - zero
conveyors, zero harvesters, barriers instead - beats us 22-3, and loses to
OopsGotYourElo 5-15, a team we beat 70%. That is a counter to us specifically.

RETRACTION: I dismissed guns-on-core as "churn" on the grounds that Pantheon's
guns live 8 turns to our 30. That compared Pantheon vs top opponents against our
bot vs my own failed variants - not like for like. Four teams measured in games
against us show the same gap. The metric was right and the sixteen rejected
experiments failed on execution, not on thesis. Flotte proves zero economy works
- the configuration strike-v1 attempted and botched at 1.9 guns.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
exp_transition 56% vs shipped v7 at 336 rounds (CI 50-61, kills 173-124).

Found by tracing the teams that beat us, builder by builder, in games AGAINST
US - not by reasoning about mechanisms:

  ORIZON   b10: t6 harv, t8 conv, t12 harv, t14 conv, t16 conv -> STOPS FOREVER
           b4: t30,31,37,43 gunner    b6: t33,34,35 gunner
  PROMPTENG b3: t1 harv, t3 conv, t5 conv -> STOPS AT t5
           b5: t28,30,31 gunner       b9: t28,36,39 gunner
  US (v7)  b16: t7 conv, t9 conv, t19 GUNNER, t27 harv, then TEN conveyors
                through t43
           b4:  t1 harv ... t22, t24, t26 conv

They build a small economy, stop dead, and spend everything after on guns. We
never stop - 18.4 conveyors a game to Orizon's 7, and one builder puts down a
gunner at t19 and goes back to harvesting at t27. That is why every team above
us lands 6-18 guns on our core and we land 2-4.

The mechanism is a TRANSITION, not an allocation, which is why exp_phase (role
cadre) and spar_pantheon (economy damped from t0) both missed it: the economy
has to be built FULLY and then abandoned. One condition: after ECON_CUTOFF the
harvest and route states score zero.

Profile now matches the target: total guns 14.0 (Orizon 14.0), on-core 3.8 ->
6.9, conveyors 39.5 -> 15.9.

Sweeping ECON_CUTOFF over 10/14/20/26/32/40 before shipping - the traces put
their transitions at t5-t16, so 26 is probably late.

Also measured: v7 and v6 are indistinguishable live (44% vs 45% expected
like-for-like, n=50), and v6's Pantheon rate has regressed 67% -> 48% as its
sample grew. Both share the same holes: Orizon ~10%, Prompt Engineers 20%.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…def rejected

Cutoff sweep over nine values: t10 35%, t14 50%, t20 56%, t26 56%, t32 62%,
t40 62%, t50 53%, t65 58%, t80 58%. Their timings do NOT transfer - Orizon
stops at t16 and Prompt Engineers at t5, but copying that gives 35-50% because
our economy is slower. Confirmed the two leaders at 336 to pay back the
selection bias of a nine-way sweep: t32 55% (CI 50-60, spans 50), t40 58%
(CI 53-63, excludes 50). Shipped t40 as v8 econ-transition.

v8 unrated vs the top five: 6-19 (24%) against v7's 7-25 (28%). A TRADE, not a
gain - Prompt Engineers 1-4 -> 4-1 and Orizon 0-5 -> 1-4 (the two teams whose
plan this copies), but Pantheon 2-3 -> 0-5, Flotte 2-3 -> 0-5, SmartFridge
2-3 -> 1-4 (the three that rush our core).

exp_trans_def tested the obvious explanation - that zeroing economy states
empties our half when a rush lands - by letting the recall outrank the
transition. REJECTED: 46% vs v8 (CI 41-52, kills 138-167), 45% vs spar_rush.
So that mechanism is wrong and v8 stays live.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… vs rushers

The Flotte Experience (#5) beats us 22-3. Traced: 100% of their 28 barriers
across 5 games sit within 4 tiles of their OWN core, laid from t4 by a dedicated
builder before any threat exists. In the game traced we built ELEVEN gunners
from t13 to their eight from t18 and still lost 5-0 - our guns need seats at
range 4-6 from their core and those tiles were taken.

Our waller walls manhattan 1 with conveyors, which blocks adjacency but not the
FIRING SEATS. exp_prearmor adds the seat zone (manhattan 2-4, enemy side only,
and only tiles that pass can_fire_from against our core footprint). 3 Ti for
30 HP; our own barriers are passable to our units so it costs no movement.

  vs shipped v8 (336): 51% (CI 46-57, kills 153-149) - no regression
  vs spar_rush  (168): 60% (CI 52-67, kills 92-55)  - v7/v8 both ~52%

Not shipped: 51% does not clear the 55% bar I set for autonomous shipping.
Building 3.3 barriers/game against Flotte's 5.6, so the mechanism is
under-delivering - tuning that next.

NOT aegis-v1 or bastion: both were REACTIVE armour built after a threat
appeared and were correctly rejected. This is pre-placed, which is the point.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FLANKING - from the Battlecode 2021 postmortem (Stone Tao), whose breakthrough
was attacking from multiple directions at once, and confirmed as a real gap
here: quadrants covered around the enemy core by guns within 6 tiles is 2.75/4
for the teams that beat us against 1.83/4 for us. Cause is in our code -
_direct_siege_plans sorts seats by distance FROM THE BUILDER, so siegers
converge on whichever face they approach from. exp_flank adds a quadrant-
coverage term ahead of distance.
REJECTED: 44% vs v8 (CI 39-50, kills 130-166). Seats in unoccupied quadrants
are further away, so more turns go to walking and fewer guns get placed. A
mechanism can be real in the data, endorsed by a winning postmortem, and still
lose in our engine.

PREARMOUR - not shippable. 51% vs v8, and the rush advantage did not replicate:
60% then 52% on a rerun of the identical bot, pooled 187/336 = 56%. Count 10 at
radius 4 gives 49%.

Two process failures of mine, both caught by redoing the boring version:
1. Swept armour count AND radius together (6/4 -> 10/5, 14/5), so the
   regression could not be attributed. The clean single-variable test (10/4)
   showed count alone is not the cause.
2. Built a story on a 60% that a rerun cut to 52%, and compared it against
   v7's baseline when prearmour is built on v8. The proper control - v8 vs
   spar_rush at 336 - was never run until now.

v8 econ-transition remains live and remains the only confirmed gain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The remaining experiment, sparring, frozen and concept bots that were never
committed - exp_* variants, spar partners, trace twins, and the older lineages.
Keeps the whole fleet reproducible alongside the gate results and
MEASUREMENT-FINDINGS.md rather than living only on one machine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Everything else from the session and the wider project that had never been
committed: the tests/ suite, conveyor_audit.py, artifacts/, the packaged zips
and *_results.json evidence files, plus the working HANDOFF.md and WORKFLOW.md
edits and the remaining root sources.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts:
#	AGENTS.md
#	HANDOFF.md
#	WORKFLOW.md
…ected

Unrated scrims with the live v22 (rank #2, 1935 Diamond):
  Pantheon       0-5  (dead t42,45,73,74,100 - all core destroyed)
  CtrlAltDefeat  4-1
  Orizon         3-2
  Flotte         4-1
Pantheon is the only team beating us and the only team above us.

Replay profile of those five games (they are teamA):
                first gun   guns on core   total guns   barriers   launchers
  PANTHEON         t13         10.2          13.2         5.2        1.0
  EREBUS v22       t31          6.4          16.6         0.0        0.0

Placement, measured: 100% of their 26 barriers sit within 6 tiles of OUR core
(forward armour on the siege position they hold), and 100% of their 5 launchers
sit within 4 tiles of THEIR OWN core (a launch pad, not a chain). Note this is
the OPPOSITE of Flotte, whose barriers are 100% at their own core for seat
denial - two top teams using the same building for opposite purposes.

exp_v23_launchpad   - one pad by our core, defender-built, throws outbound
                      builders 7 tiles. 52% vs live v22 (CI 47-58, kills
                      156-145). First gun t24 -> t22 only.
exp_v23_launchpad2  - adds routing: attackers still near home detour onto the
                      pad. STILL t22, and the cap is not globally enforced so it
                      built 6.1 pads/game (~120 Ti wasted). That over-build is
                      the decisive evidence: six pads did not beat one, so pad
                      availability is not the bottleneck and the mechanism does
                      not explain their t13.
exp_v23_fwd_armor   - barriers where our guns are, inside the enemy band, only
                      when something is shooting that tile. 47% vs live v22
                      (CI 42-52, kills 138-157). Also 93% vs spar_rush with
                      kills 157-5, but that number is UNINTERPRETED - no fresh
                      parent control was run, and spar_rush is built from the
                      v8-era engine which this lineage outclasses anyway.

Frozen parent bots/live-v22-control extracted byte-for-byte from the active
submission; identical to exp_v21_eco_release_only_damaged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Traced Pantheon's launcher from their 0-5 sweep, turn by turn:
  t1  launcher built 2 tiles from their own core (18 from ours)
  t2  builder 3 (3,4) -> (4,10)   d7      t3  builder 5 -> (4,10)   d8
  t4  builder 8 -> (1,6)  d5              t5  builder 11 -> (1,17)  d5
  then the thrown builder BOLTS: b5 goes 14,13,12,11,10,9,8,7,6,5 one tile a
  turn, no detours, no economy, and the first gunner lands t13 at distance 4.
The throw buys ~6 tiles; the bolt does the rest. Without it that is a t21 gun.

Seven implementations, each fixing the last one's real bug:
  v3  pad at t1, 1/game, correct placement -> ZERO launches. Launchers never
      call setupMap(), so a launcher's own enemyCorePos is permanently None
      (mapPathfinding notes the same trap for gunners).
  v4  builders publish the target to slot 9 -> 8.5 launches from t2, but first
      gun t24 -> t26: the pad was throwing the ECONOMY crew across the map.
  v5  attackers claim the ride via slot 10 -> 17.1 launches, first gun t20.
      GATE 40% (kills 103-188). Pantheon launches 3-4 times a whole game.
  v6  one-ride-per-builder flag -> 0.8 launches, tempo gone. The flag was set on
      CLAIMING and only one claim survives the single slot per turn, so every
      builder that lost the race marked itself done.
  v7  geometry instead of a flag (throw must clear the pickup radius) -> 8.8
      launches, first gun t20. GATE 38% (kills 96-198).
  v8  rider given the same allEnemyCore fallback as the launcher -> DEADLOCK:
      riders stand at the pad waiting for a throw that never comes (b3 frozen
      t6 -> t89).
  v9  wait timeout -> oscillation: b3/b8 bounce 21<->22 all game, 1 launch.

  combo (v7 + forward armour) -> 40% (kills 100-186).

CONCLUSION SO FAR: the mechanism is real and reproduced - pad at t1, throws from
t2, first gun t24 -> t20 - and it loses every time, by 2:1 on core kills. Being
early and alone in their half gets our builders killed; the armour that should
fix that does not (47% alone, 40% combined). What we have NOT reproduced is the
BOLT: our thrown builders re-enter the ride logic and ping-pong near the pad
instead of marching. That is the next thing to fix, and it is a rider problem,
not a pad problem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Best result 45% (CI 40-51, kills 114-176) vs live v22. Progression:
  v1  pad on the exit lane, gated on resources+role      52%
  v5  riders claim, 17.1 launches/game, first gun t20    40%
  v7  geometry-limited, 8.8 launches                     38%
  v11 no detour, 3.8 launches = Pantheon's exact rate    45%
  v12 pad moved off the exit lane, bolt restored         45%

THREE LATENT BUGS IN THIS CODEBASE found while chasing it, all worth knowing
independently of the launcher:

1. LAUNCHERS NEVER CALL setupMap(). Every entity gets its own Player and only
   builders call it, so a launcher's mapPf.enemyCorePos is permanently None.
   v3 built a perfect pad that could never fire. mapPathfinding.py documents the
   same trap for gunners. Anything map-dependent in a non-builder entity has to
   come from the store.
2. mapPf.moveTo DEAD-ENDS AGAINST OUR OWN CONVEYOR RING - our conveyors are not
   passable to us. HANDOFF records this costing aegis-v1 seven turns "2 tiles
   short"; it is why every version that walked riders to the pad oscillated.
3. OUR OWN BUILDINGS BLOCK OUR OWN EXIT. Placing the pad on the tile nearest the
   enemy - the obvious choice - puts it in the doorway every builder leaves
   through. Traced: b3 bouncing 22 to 21 and back for eight turns where the
   pad-less parent marched straight out. One tile perpendicular restored the
   march (22,21,20,18,17,16,15,14,13,12,11,10,9,8). We place a lot of conveyors
   in that same corridor.

Pantheon's mechanism is now reproduced faithfully - pad at t1, 3.8 throws/game
from t2, thrown builders bolt - and it still costs about 5 points. The remaining
gap to their t13 is in what the ATTACKER ROUTINE does after landing, not the pad.

oarena (github.com/frkns/oarena) installed for 2D replay viewing: its venv needs
a .pth pointing at the fcode site-packages, since a venv made from another venv
does not inherit it. Serves on :7878, doctor all green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FIX 1 - non-builder entities have no map (exp_v23_fix_storemap).
Every entity gets its own Player and only builderBot() calls setupMap(), so in a
gunner, sentinel or launcher the pathfinder is empty: mapPf.enemyCorePos and
teamCore are permanently None. mapPathfinding already works around this for
gunners (coreThreatSpots reads the team core from slot 7) but nothing published
the ENEMY core. Builders now publish it to slot 9 and enemyCoreFromStore() reads
it. LATENT fix - the live bot has no non-builder logic needing it, so behaviour
is unchanged and there is nothing to gate. Its value is that the next launcher
or gunner routine written against mapPf.enemyCorePos will not silently never
fire, which cost a whole day of launcher work here.

FIX 2 - pathfinder dead-end (exp_v23_fix_stuck). 49% (CI 44-55, kills 147-147).
The parent waits 2 + (id % 8) turns - three to ten - before reacting to a
blocked step, then moves in a RANDOM legal direction. This sidesteps on the
first blocked turn and picks the neighbour that reduces distance to target,
falling through to the original random walk only if nothing improves. HANDOFF
blames this dead-end for aegis-v1 standing "2 tiles short for 7 turns". Neutral
at 336 games: the stall is real but rare enough not to move the aggregate.

FIX 3 - our own buildings block our own exit (exp_v23_fix_lane). 49% (CI 44-55,
kills 154-147). MEASURED FIRST rather than assumed: 41% of the live bot's
conveyors (5.75 a game) land within two tiles of the core->enemy axis, the
corridor every attacker leaves through, and our conveyors are impassable to our
own units. Reserving the single-tile lane out to 6 tiles (not the whole
corridor, which is often where the ore is) is neutral.

All three are safe robustness fixes with no regression, and none is a win. The
honest read: these bugs are real and cost individual units turns, but the
aggregate is dominated by something else. Fix 1 is still worth keeping because
it removes a silent-failure trap rather than a cost.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ed good

LAUNCHER AS AN EYE (exp_v24_launcher_eye). Pantheon told us they get full
symmetry shortly after placing a launcher. The constants support it:
LAUNCHER_VISION_RADIUS_SQ 26 vs a builder's 20, and symmetry is eliminated by
observing terrain, so a pad at home is the widest permanent sensor we own.

Implemented as mapPathfinding.setupMapObserver(): getNewTiles -> updateBoard ->
updateSymmetry for a non-builder entity, deliberately SKIPPING shareTiles, whose
12-bit channel is keyed on myNum and belongs to the builders.

MEASURED with an instrumented twin - round at which each bot first resolves the
enemy core, 8 maps:
  launcher-eye     1, 2, 3, 3, 3, 3, 4, 4, 9, 10 ...  median t18
  live v22         4, 5, 5, 5, 5, 6, 6, 6, 15, 16 ... median t18
So it DOES resolve 2-3 turns earlier for the earliest units - the effect is real
and is what Pantheon described. It just does not pay: 20 Ti, a builder action at
t1 and a blocked tile for 2-3 turns on a few units. GATE 43% (CI 37-48, kills
126-177).

THE OTHER RESULT THAT MATTERS: v24 is NOT a regression.
  fresh unrated, v24 active:  Pantheon 3-2, CtrlAltDefeat 3-2
  same scrim earlier today with v22: Pantheon 0-5
  ladder like-for-like v24 vs v22: -5 points at 1.2 sigma (NOT significant); the
  raw 80% vs 60% was schedule - v24 has played 40 rounds against Pantheon.
  vs Pantheon our first gun is now t21 to their t14, with ZERO launchers, where
  this morning it was t31 to t13. Whatever v23/v24 changed bought most of the
  tempo the launcher was supposed to buy.

Remaining measured asymmetry vs Pantheon: they build 3.2 barriers/game, we build
none.

Also in this push: the three latent-bug fixes (all gate neutral, all safe) and
twelve launcher-as-transport variants (all rejected, best 45%).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… redoing it

Thirteen attempts, all rejected, best 45%. Documents Pantheon's exact traced
pattern (pad t1 off-axis, 3-4 throws t2-t5, thrown builder bolts one tile a turn,
first gun t13), the three codebase landmines that silently kill the mechanism
(non-builders have no map; moveTo dead-ends on our own conveyors; our own
buildings block our own exit), what each of the thirteen variants proved so
nobody repeats them, and the one piece still unsolved: a thrown builder needs a
committed bolt state so runAttack's gunner-spot search stops pulling it sideways.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…not aim

Phase 0, 70 replays of v29's own losing matches. v29 is 419-81 (84%) over 500
rounds, #2 at 1966; Pantheon #1 at 2016. The only sub-50 matchup is Pantheon
(24-26, 48%); everything else is 68-100%. 23 of 26 losses are core_destroyed at
a median of t62, 12 of them inside t60.

  D1  52.7% of our guns sit in our OWN half; opponents put 29.1% there.
  D3  our guns are NOT inefficient - 9-turn median lifetime to their 5, and
      37.9 core damage each to their 25.7 (489 a game against 358).
  D2  but we win the race to first gun on their core in 15 of 64 games (23%):
      t20 to their t14 in fast games, t29 to t15 in slow ones.

E1 exp_v30_tempo_first - defer home defence until the team lands its first gun
on their core (a lone uncovered turret no longer buys a counter-gun; two still
do; after first blood it is exactly v29). Mechanism confirmed: first gun t29 ->
t25, home gun share 44% -> 26.9%, which is the 29.1% the top teams run.
GATE 49% (CI 44-54, kills 149-146) - neutral.

E2 exp_v30_core_eye - runCore never touched mapPf at all, despite
CORE_VISION_RADIUS_SQ 36 against a builder's 20 and never moving. Added an
observer path (no shareTiles: that channel is keyed on myNum). Also fixed a real
bug in it: a CORE does not appear in its own get_nearby_buildings(), so teamCore
stayed None and updateSymmetry returned immediately.
PREMISE FALSIFIED before gating: earliest symmetry resolution is identical with
and without it - [1,1,2,2,3,3,4,4,6,6] both - so the team already knows where
their core is by t1-t6. Knowledge is not the constraint.

CONCLUSION: our first gun at t22-30 is essentially TRAVEL TIME across ~20 tiles.
Not aim, not allocation (spar_v29_rush, v29 with nearly every builder attacking,
still only reaches t25), not efficiency. That is precisely what a launcher throw
shortcuts, and it is why Pantheon reaches t7-14.

Also: spar_rush is now obsolete as a sparring partner - v29 beats it 97%, since
it was built from the v8-era engine. Replaced by spar_v29_rush (v29 chassis, all
but one builder attacking) which reaches t25.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…arent

  E1 defer defence until first blood   49%  (CI 44-54, kills 149-146)
  E2 core as symmetry eye              premise falsified before gating
  E3 bolt state, band 9                52%  (CI 46-57, kills 155-141)  <- best
     band sweep: 6 -> 45%, 9 -> 52%, 13 -> 51%, 18 -> 48%
  E4 stack (bolt + defer)              45%  (CI 40-50, kills 134-164)

E3 BOLT is the one worth keeping in mind. Measured cause: runAttack calls
findGunnerSpot() every turn once the core is known and moveTo()s the seat it
returns, but that seat is rescored each turn FROM THE BUILDER'S OWN POSITION, so
a distant attacker chases a moving target instead of closing. We spend 1.50
turns per tile of progress against our opponents' 1.12. Committing to the march
outside a 9-tile band moves first gun t29 -> t25.

E4 STACK IS WORSE THAN EITHER HALF, which vindicates the WORKFLOW rule I
deviated from: stack only independently-passing features. Deferring defence AND
committing attackers forward leaves us undefended and overextended at once.

A PROCESS FAILURE WORTH RECORDING: the first stack run reported 52% and was an
UNMODIFIED COPY of the bolt. The edit anchor appeared twice in the file
(runDefend and another threat handler), the assert fired, write_text never ran,
and the shell went on to compile and gate the untouched file. The number looked
plausible because it matched the bolt exactly. Now fixed with a longer unique
anchor, and the edits are verified by counting them in the WRITTEN file rather
than trusting a clean exit. This is the third silent-failure of the day after
the launcher with no map and the core observer that could not find its own core.

CONCLUSION: Phase 0's diagnosis stands and is well evidenced - we lose the race
to first gun in 77% of games, our first gun is travel-bound (symmetry resolves
t1-6; even all-out attack reaches only t25), and our guns are the most efficient
on the board (489 core damage a game to their 358). But no tempo fix prices out
against our own parent, because the parent does not punish slow tempo. Measuring
this needs Pantheon, and that needs a candidate active on the ladder.

Nothing here is recommended for the ladder. v29 stays.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…s 54%

CLI updated 2.3.3 -> 2.3.4 in both venvs; maps already current (21).

SIX CONSTANTS CHANGED. Gunners nerfed on four axes at once, sentinels buffed on
two: GUNNER_BASE_COST 10->20, GUNNER_DAMAGE 10->7, GUNNER_AMMO_COST 2->4,
GUNNER_MAX_HP 40->25, SENTINEL_FIRE_COOLDOWN 3->2, SENTINEL_MAX_HP 30->40.

                dmg/turn  dmg/ammo  dmg/Ti   HP   reach
  gunner           7.0      1.75     0.35    25   cardinal 3, diagonal 2
  sentinel         9.0      1.80     0.60    40   cardinal 5, diagonal 4

Sentinels are now better on every axis except cooldown - 71% more damage per
titanium, 60% more HP, and TWO TILES more reach. Reach was measured with a probe
bot rather than assumed: gunnerLines is hardcoded 3/2 in mapPathfinding and a
gunner seat is not a sentinel seat, so sentinel work needs its own seat list.
Also, a 500 HP core now costs ~280 ammo instead of 100.

NEW NOISE FLOOR ON 2.3.4: byte-identical v30 against itself, 336 games, scores
54% (CI 49-60) with core kills 162-142. So:
  - anything under ~57-58% at n=336 is unproven;
  - KILL DIFFERENTIALS ARE NOT CORROBORATION. Identical code produced +20. I
    have been quoting differentials as supporting evidence all session (bolt
    155-141, defer 149-146) and that was wrong - both numbers move together.
  - every pre-patch gate result in this repo is stale.

exp_v31_sentinel: attack seats use the new sentinel geometry and build sentinels;
defence deliberately left on gunners (one change at a time). Confirmed active at
9.2 sentinels/game against the parent's zero, and 9.6 threats on the enemy core
against 7.9. Gating now.

WORKFLOW.md updated with both the rebalance table and the new noise floor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The merge took origin/main's WORKFLOW.md, which does not carry the noise-floor
section, so the previous edit's anchor genuinely did not exist and the write was
skipped. Re-inserted against a verified anchor, and the write is now confirmed by
re-reading the file rather than trusting a clean exit.

Records the six changed constants, the inverted gunner/sentinel economy
(sentinels: 0.60 dmg/Ti vs 0.35, 40 HP vs 25, reach 5/4 vs 3/2), the ~280 ammo
now needed per core kill, and the measured 2.3.4 noise floor: byte-identical code
scores 54% with a +20 kill differential, so sub-58% results and positive kill
differentials both prove nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…s every meta

ENGINE: both venvs -> 2.3.6, maps current. Diffed GameConstants out of the 2.3.6
wheel against our 2.3.4 snapshot: ZERO constant changes. 2.3.5/2.3.6 are engine
or CLI fixes; the gunner rebalance remains the live balance.

NOISE FLOOR, second draw: byte-identical v37 vs itself on 2.3.6 = 46% (CI 41-52,
kills 138-158). With the 2.3.4 draw of 54% (kills 162-142), identical code spans
46-54% and its kill differential swings +20 to -20. So: anything in 46-54 at
n=336 is nothing, and KILL DIFFERENTIALS CARRY NO INFORMATION - I quoted them as
corroboration repeatedly earlier in this work and that was wrong.

LADDER RESHUFFLED after the rebalance. Pivot #1 (1922), sporks #2 (1875 on only
90 matches), team lazy #3, Pantheon SEVENTH at 1806 - down from #1/2016, the
purest volume-rush bot hit hardest by the gunner nerf. Erebus #9 of 101 (1792),
last ten 3W-7L.

v37's "sentinel-line seal" is NOT broken and does NOT build sentinels: it is
cornerShields - 12 barriers, 36 Ti, on the tiles every enemy sentinel line into
our core must cross. Zero sentinels built is by design. v36 shipped without it,
which is why v36-era replays show zero barriers.

WE ARE NOT LOSING ON DAMAGE. In matches we lost: Coreflood 461 vs 316, sporks
641 vs 302, team lazy 580 vs 519, Pivot 1021 vs 959 - we out-damage all four.

NO SINGLE META EXISTS ANY MORE:
  team        #   gunner  barr  conv  harv  1st gun  ON CORE
  Pivot       1    19.6   8.2   16.0   4.6    t27      8.8
  sporks      2    14.8   2.4   50.2   7.8    t70      7.0
  team lazy   3     8.8   0.0   15.4   3.2    t25      6.2
  EREBUS      9    13.1   0.0   11.1   2.5    t26      4.0
Pivot plays guns+barriers, sporks plays a t70 first gun with 50 conveyors and is
#2, team lazy plays lean everything. Rush and economy are both winning for
different teams.

THE ONE INVARIANT: every team above us lands more guns on the enemy core than we
do - 8.8 / 7.0 / 6.2 against our 4.0. That has survived every patch, every meta
shift and ~25 experiments. It is not tempo (sporks is slower and #2), not
efficiency (we out-damage them), and not unit choice (nobody uses sentinels).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ic3d00 added a commit that referenced this pull request Aug 24, 2026
…g the finals bot; two economy experiments rejected

THE INCIDENT: ic3d saw v204 activate itself. Cause was mine - I killed the A/B runs with 'pkill -f autoeval.py' three times and reported 'autoeval stopped' each time, but pkill is a BASH BUILTIN and does not kill Windows processes. All six autoeval.py instances launched tonight were still alive and cycling the active submission against each other. My verification was wrong too: 'ps -ef | grep' returns nothing for Windows processes and I read that silence as confirmation. Every one of those processes carried --final 198, so at 08:15 they would have OVERRIDDEN the intended finals bot. Killed via Stop-Process by PID; v205 confirmed active.
tools/versionwatch.py now reports (never changes) the active submission every 5 minutes. Deliberately report-only: a teammate may legitimately switch the bot and a watchdog that fights them would be worse than the bug. On Windows use Get-CimInstance Win32_Process + Stop-Process, never pkill/ps.

ECONOMY EXPERIMENTS, both REJECTED on direct measurement rather than win rate. The metric is harvesters built per builder, because that is what the Bean 5-0 turned on (they had 9 harvesters off FOUR builders, we had 6 off SIX):
  unpressured                          2.13
  under pressure  v198                 1.25
  under pressure  v205                 1.37   <- best, and the answer to 'does v205 fix it'
  under pressure  fp36 economy reserve 1.11   <- WORSE
  fp35 HARV_TI 45->28   lab 74/150 = 49% CI [41,57], indistinguishable
Production collapses ~40% under pressure and v205 recovers only about a tenth of that, so NO, v205 does not fix the underlying bug - it fixes one oscillation source that feeds it. fp36 reserved half the crew from every defensive step so they would keep farming through a siege (the shape MFF1 and The Blades both endorsed); it produced FEWER harvesters, 30 against 41. Caveat: the metric is partly confounded by game length, and there was no time to normalise it.

v205 stays: best measured production under pressure, 3-2 over Clankers, 1982 Diamond rank #11 - our highest of the campaign.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant