Skip to content

Commit af2355a

Browse files
Establish where the death event actually stops.
Both hypotheses are refuted by measurement. A raw-payload probe in the Bot API's WebSocket handler shows that no death message of any kind reaches any bot -- not the dying bot, and not the survivors in a four-bot battle where the round continues past three deaths. Other events arrive and dispatch normally in the same logs. So the queue never had a DeathEvent to drop, and the instant handler that stops the bot thread never ran. The bridge is correct; the cause is at or below the server-to-bot protocol boundary. The measurement also shows EVT-007 is blocked by the same cause, which nobody had written down, and that AN-006's second divergence no longer reproduces. Cliewen-Route: full Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011CzphhW5SDHycZJFfaAKLm
1 parent 838053b commit af2355a

1 file changed

Lines changed: 41 additions & 0 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
id: CH-003-findings
3+
type: findings
4+
status: open
5+
links: [CH-003, AN-006]
6+
title: CH-003 measurement log — where the death event actually stops
7+
---
8+
9+
# CH-003 — what the measurement established
10+
11+
Measured 2026-08-30 against the Tank Royale runner jar at `C:\Code\tank-royale\runner\examples\lib\robocode-tankroyale-runner.jar` and Bot API 1.0.2, using `tested.robots.BattleWin` through the conformance harness.
12+
13+
## The result
14+
15+
**No death message of any kind reaches any bot.** Not the dying bot, not the survivors.
16+
17+
The probe sat in `WebSocketHandler.onText`, before any parsing, printing the raw payload of every message whose text contained `death` in any casing. Across a two-participant battle and a four-participant battle, over two rounds each, that probe fired zero times in every bot's log — while the same logs show `ScannedBotEvent`, `HitWallEvent`, `HitByBulletEvent`, `BulletHitBotEvent`, and `WonRoundEvent` arriving and dispatching normally.
18+
19+
The four-participant run matters: there, three bots die while the round continues, so the survivors should receive `BotDeathEvent` for each. None did.
20+
21+
## What this refutes
22+
23+
Two hypotheses, both now dead.
24+
25+
**`AN-006`'s suspect — the Bot API event queue's age and criticality filter — is refuted twice over.** By reading: `DeathEvent.isCritical()` returns true, and both `isOldAndNonCriticalEvent` and `isNotOldOrIsCriticalEvent` exempt critical events from the age filter. By measurement: the queue probe printed the queue's full contents at every dispatch, and no `DeathEvent` was ever in it. Nothing was dropped, because nothing arrived.
26+
27+
**The instant-handler hypothesis this change was opened on is also refuted.** `BotInternals` does subscribe an instant handler to `DeathEvent` whose body is `baseBotInternals.stopThread()`, and the bridge's bot does inherit it, so the ordering concern was real in principle. It is not what happens: the probe on that handler never fired either, for the same reason.
28+
29+
## Where the cause is
30+
31+
Above the Bot API entirely, at or below the server-to-bot protocol boundary. The bridge is correct: it overrides the Bot API's `onDeath`, maps it, and calls the robot's handler, and a probe placed directly in that override never fires because it is never called.
32+
33+
A lead for the upstream investigation, not a conclusion — the runner jar in use and the server source read here are not known to be the same build. In `TurnProcessor.applyDefeatedBots`, the death event is added to the turn with `addPublicBotEvent`, which fans out over `turn.bots`; `TurnToTickEventForBotMapper.map` returns null for a bot no longer in the turn, and `GameServer.sendTickToParticipants` skips a participant that is neither alive nor carrying events. Whether the death event is added before or after that turn's ticks are built and sent is the question to answer upstream, and `MutableTurn.resetEvents()` clears the map between turns.
34+
35+
## The consequence nobody had written down
36+
37+
`EVT-004` is not the only criterion this blocks. `EVT-007` — the death of another robot reaches the survivors — is unprovable for the same reason and by the same measurement, and it was recorded as merely unported. Any classic robot that tracks enemies through `onRobotDeath` is running blind under the bridge, and that is a much wider fidelity gap than one handler on one robot.
38+
39+
## What did not reproduce
40+
41+
`AN-006` recorded a second divergence alongside the death finding: classic split `BattleWin`'s five rounds between the two instances while the bridge gave one instance all five. It does not reproduce. Across the runs made here the wins split 2/3 and 3/2, as classic's do. The record notes it was measured before the event-dispatch redesign and the Bot API upgrade; nothing here re-establishes it, so it is not carried forward as a live finding.

0 commit comments

Comments
 (0)