Skip to content

Commit 78078fc

Browse files
Document M-003 higher-score findings
1 parent d1dfcb9 commit 78078fc

4 files changed

Lines changed: 79 additions & 2 deletions

File tree

.clue/id-ledger.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
counters:
22
ADR: "1"
3-
AN: "11"
3+
AN: "12"
44
API: "6"
55
ARCH: "3"
66
C: "7"
@@ -78,6 +78,11 @@ entries:
7878
state: live
7979
prefix: AN
8080
component: "11"
81+
- id: AN-012
82+
kind: numeric
83+
state: live
84+
prefix: AN
85+
component: "12"
8186
- id: API-001
8287
kind: numeric
8388
state: live
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
id: AN-012
3+
type: analysis
4+
status: active
5+
links: [P-001, CAP-005, CAP-002, CAP-007, C-003, C-004, AN-001, AN-002, AN-011]
6+
title: M-003 finds one bridge-only lifecycle failure and no reproducible higher-score gap in the other two candidates
7+
provenance: inferred
8+
reversal-cost: low
9+
---
10+
11+
# AN-012 — M-003 finds one bridge-only lifecycle failure and no reproducible higher-score gap in the other two candidates
12+
13+
## What was investigated
14+
15+
Whether the three bots selected by the stale compatibility report as materially higher under Tank Royale — ScalarR, Ar1, and BasicSurfer — still diverge under the current bridge at official `roborumble` parameters, and whether each result can be given a named cause or a within-band disposition.
16+
17+
## Evidence boundary
18+
19+
The spike ran on 2026-09-04 in a prepared Windows environment using PowerShell 7.6.5, Python 3.14.2, OpenJDK 24.0.2 for the surrounding process, the bridge repository at `d1dfcb9a4cd0f0b23f2e7d2bbea2c075427d7a21`, and the Tank Royale repository at `b79f256ea4c6f3bf2f309a5600d44f972dde63da`. The classic worker auto-selected the separately installed JDK 17 required by classic Robocode's SecurityManager.
20+
21+
The classic side used the installation at `C:\robocode` and the Tank Royale side used the local runner and Bot API builds from `C:\Code\tank-royale`. The bridge API jar SHA-256 was `D5C0D65C4F88DF2169E0F5FEE9C4781998B5823653E96906CB4B27DE0B8ECCAF`, the wrapper jar SHA-256 was `A68A12532551C17117D6EEBDD716560C92263EC2A336328D4C6B02CB8EBA1B47`, the runner jar SHA-256 was `2D3838F3BCAC4D73104D9D3C9B1EE98E54E5A0B8BDE7FBD8324FDBBA8B3719BB`, and the Bot API was the matched local 1.2.0 build.
22+
23+
The population was the three higher-score rows named by the prior report and pinned in `compat-test/regression-set.json`: `aaa.r.ScalarR_0.005h.053.jar`, `adt.Ar1_2.1.jar`, and `And.BasicSurfer_FF1.6.jar`. Each pair was robot-versus-itself on classic and Tank Royale. The official setup was 800×600, 35 rounds, and two participants. No `--rounds` override was used.
24+
25+
Scores are stochastic and Tank Royale has no deterministic battle seed, so repeated deltas establish the presence or absence of a gross current divergence for these candidates, not exact cross-engine replay equivalence or population-wide quality. A Tank-Royale-only exception is categorical; the harness stopped that battle rather than inventing a score.
26+
27+
## What was found
28+
29+
| Bot | Comparable samples | Classic mean | Tank Royale mean | Per-pair deltas | Disposition |
30+
|---|---:|---:|---:|---|---|
31+
| `aaa.r.ScalarR_0.005h.053.jar` | 0 of 1 | 4,130 ||| Bridge-only lifecycle/tick-boundary failure |
32+
| `adt.Ar1_2.1.jar` | 5 of 5 | 3,888.0 | 3,587.4 | −21.7%, +4.0%, −14.8%, −4.8%, −0.9% | Within ±25% band; mean delta −7.6% |
33+
| `And.BasicSurfer_FF1.6.jar` | 5 of 5 | 4,165.2 | 3,666.2 | −2.0%, −13.4%, −10.1%, −15.5%, −18.0% | Within ±25% band; mean delta −11.8% |
34+
35+
### ScalarR: a reproducible bridge-only lifecycle/tick-boundary failure
36+
37+
The classic pair completed with a combined score of 4,130 and no errors. Tank Royale produced no result and two bridge-side errors before the harness stopped it. The signature was `dev.robocode.tankroyale.botapi.BotException: Game is not running or tick has not occurred yet. Make sure onTick() event handler has been called first`.
38+
39+
The stack ran through `BaseBotInternals.getCurrentTickOrThrow``BaseBot.getTurnNumber``BotPeer.getTime` → the obfuscated ScalarR custom-event path → `BotPeer.dispatchCustomEvent` → the Bot API event queue's final-turn dispatch. The observation establishes that the legacy robot's custom-event callback can reach `BotPeer.getTime()` when the Bot API has no current tick. It does not yet establish whether the bridge callback boundary or the Bot API's final-turn scheduling owns the mismatch.
40+
41+
This is a bridge-only categorical failure under `C-004`, not a low score that should be averaged. It is a focused lifecycle/tick-boundary repair candidate.
42+
43+
### Ar1: the old higher score does not reproduce as a material gap
44+
45+
Ar1 completed all five official pairs with no errors. Its deltas ranged from −21.7% to −0.9% and averaged −7.6%, inside the current absolute ±25% screening band. The old +64.2% single-run figure is not a current material higher-score observation. The result does not establish exact parity or provide a reason to change physics or state semantics.
46+
47+
### BasicSurfer: the old higher score does not reproduce as a material gap
48+
49+
BasicSurfer completed all five official pairs with no errors. Its deltas ranged from −18.0% to −2.0% and averaged −11.8%, inside the current absolute ±25% screening band. The old +79.2% single-run figure is not a current material higher-score observation. The result does not establish exact parity or isolate the radar and bullet-state behaviours mentioned in the old watch-list note.
50+
51+
## What was tried and rejected
52+
53+
The historical report's single-run higher-score deltas were not reused as baselines. `AN-001` and the watch-list comments state that they were measured at a setup matching no division and before the event-dispatch redesign and Bot API upgrade.
54+
55+
All measurements used the official `roborumble` setup rather than a reduced round count, because an override would produce a number incomparable with the rumble under `C-003`.
56+
57+
ScalarR was not rerun four more times after the first bridge-only exception. Repetition cannot improve a categorical bridge-only failure, and `C-004` requires the battle to stop without a fabricated score.
58+
59+
Ar1 and BasicSurfer were each run for five completed pairs because their first runs completed without errors and score deltas are noisy. No production repair was made for either bot, and no physics or radar conclusion was inferred from the stale higher-score reports.
60+
61+
The measured deltas were not written into `regression-set.json` as baselines. `M-006` has not produced the first official baseline, and the ±15 percentage-point regression movement band is not applicable to these null baselines.
62+
63+
## What it means
64+
65+
`M-003`'s exit criterion is met for the three named higher-score candidates: ScalarR has a named and reproducible bridge-only lifecycle failure, while Ar1 and BasicSurfer are within the current absolute score band after five official repeats. The old higher-score findings for Ar1 and BasicSurfer should be treated as stale noise, not as reasons for speculative bridge changes.
66+
67+
The next plan milestone is `M-004`, robot file-I/O sandboxing. ScalarR should remain a focused repair candidate and should receive targeted lifecycle evidence before any repair is selected. `M-127` remains open because the score-parity criterion is not discharged by this observational spike and the harness's Python evidence remains outside the supported acceptance carriers described by `AN-003`.
68+
69+
## What this does not establish
70+
71+
It does not establish the owner of ScalarR's tick-boundary mismatch, exact parity for Ar1 or BasicSurfer, a regression baseline, population-wide score parity, or parity for any robot outside the three-candidate population. It also does not establish that the old higher-score deltas were caused by one shared engine-level defect.

docs/analysis/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ An incident where the corpus was green but later evidence contradicted it carrie
1919
- [AN-009 — The Tank Royale server never sends a death event to any bot, which is why onDeath never fires](AN-009-the-server-never-sends-a-death-to-any-bot.md) · `active` — The cause of `AN-006`, which measured that `onDeath` is never called under the bridge and named a suspect it could not confirm: the Bot API event queue's age and criticality filter.
2020
- [AN-010 — The unit tier's evidence tags mostly hold — two small gaps, and why the failure mode CH-003 found is concentrated elsewhere](AN-010-unit-tier-tags-mostly-hold-two-small-gaps.md) · `active``G-002`'s extension from the conformance tier, which it audited, to the unit tier: every test under `robocode-api/src/test/java/dev/robocode/tankroyale/bridge/` against the `CAP-003`
2121
- [AN-011 — M-002 leaves one lower-score bot within the band and names causes for the other two](AN-011-m-002-lower-score-gaps-remain-or-have-named-causes.md) · `active` — The three lower-score candidates were re-measured at official `roborumble` parameters: AetosFirstBot is within the band, while CodaFirst and Bl4ck remain lower with named lifecycle and startup/physics causes.
22+
- [AN-012 — M-003 finds one bridge-only lifecycle failure and no reproducible higher-score gap in the other two candidates](AN-012-m-003-higher-score-gaps-do-not-reproduce.md) · `active` — The three higher-score candidates were re-measured at official `roborumble` parameters: ScalarR has a named bridge-only lifecycle failure, while Ar1 and BasicSurfer are within the band.
2223
<!-- clue:index:end -->

docs/plans/P-001-bridge-parity-campaign.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The milestone order after `M-001` follows the priority order the project had alr
2626
|---|---|---|---|
2727
| M-001 | test foundation | The unit tier runs in CI over the adapter's mapper classes; the conformance tier runs classic's test robots against both engines from one stated expectation; the harness runs each division at its official parameters, averages repeats, and aborts on a Tank-Royale-only exception. The criteria those tiers prove are active rather than `@draft`. | done |
2828
| M-002 | score gaps where Tank Royale scores lower | Every bot the report flags as scoring materially lower has been re-measured under the current bridge at official parameters, and each is either within the band or has a named cause recorded in analysis. | done |
29-
| M-003 | score gaps where Tank Royale scores higher | The same, for bots scoring materially higher. A bot scoring *better* under the bridge is as much a fidelity defect as one scoring worse, and is easier to overlook. | todo |
29+
| M-003 | score gaps where Tank Royale scores higher | The same, for bots scoring materially higher. A bot scoring *better* under the bridge is as much a fidelity defect as one scoring worse, and is easier to overlook. | done |
3030
| M-004 | file I/O sandboxing | Robot file I/O is confined to the robot's data directory as classic confines it, and the bot that surfaced the defect completes a battle without the access errors it currently produces. | todo |
3131
| M-005 | team robot support | The wrapper produces runnable Tank Royale bot directories for team jars, and the team division is no longer skipped by the harness. | todo |
3232
| M-007 | every peer method is proven to route correctly | Each method on the five `robocode.robotinterfaces.peer` interfaces has a unit test proving which Bot API call it makes and with what arguments, and a reflective coverage check fails the build when a method has none. | done |

0 commit comments

Comments
 (0)