# Enemy-tracker deaths: there are no corpses **Question.** Two independent agents believed *"`BotDeathEvent` never reaches ModularBot, so dead enemies stay `alive` in `enemyTracker` forever."* If true, every consumer of the tracker (targeting, the adaptive melee radar, the virtual-bullet enemy table) would silently mis-prune. This note records the direct measurement that settled it and the verdict, so the premise is not re-invented a third time. ## Why the premise *sounds* right (and is still real) In `robocode_tankroyale_botapi` 1.0.7 the event queue's `isCritical` set is only `ekDeath`, `ekWonRound`, `ekSkippedTurn` — **not** `ekBotDeath`. `removeOldEvents` deletes any non-critical event with `turnNumber < currentTurn - MAX_EVENTS_AGE` (2). So a bot that falls more than two turns behind *does* drop `BotDeathEvent`. That mechanism is genuine and is proven at the API level by `common_libs/tests/test_event_drop_mechanism.nim`. The mistake was assuming the mechanism *triggers* in a real ModularBot match. ## Measurement A 7-bot melee (ModularBot + DrussGT + 5 legacy sample bots). A per-tick probe compared `enemyTracker` alive-count against the server's `getEnemyCount()`, and a queue probe inspected the event queue **before** `removeOldEvents` ran. The probe ran with `TR_TRACKER_RECONCILE=0` — i.e. raw behaviour, no reconciliation masking anything. | metric | server 1.3.1 (20 rounds) | server 0.35.5 (15 rounds) | |---|---:|---:| | observed enemy deaths | 83 | 68 | | non-round-ending deaths | 83 (100%) | 66 (97%) | | `ekBotDeath` events DROPPED | 0 | 0 | | max dispatch lag (turns behind) | 1 | 1 | | phantom ticks (`tracker_alive > server_ec`) | 1 / 16,820 | 1 / 12,596 | | max corpse lifetime | **0 ticks** | **0 ticks** | | victims still alive at round end | 0 | 0 | The maximum dispatch lag of 1 turn is below `MAX_EVENTS_AGE` (2), so the drop path is never reached. `onBotDeath` fires for **every** death, including non-round-ending ones, and `markDead` takes effect on the same tick. ## Verdict **There are no corpses.** `onBotDeath` + `EnemyTracker.markDead` is a complete, prompt death signal at this workload. The API-level drop mechanism is real but never triggered. The two rare phantom ticks resolve within one tick and are not persistent corpses. ## Do not re-add a corpse workaround * Do **not** reintroduce tracker reconciliation against `getEnemyCount()` (the removed `reconcileWithServer`). It was a latent mis-prune path: its own doc comment recorded that a short persistence window **marked a live enemy dead** (it then "fired three more times"). * Do **not** add an "unseen for N ticks => treat as dead" filter to `adaptive_melee_radar` or any other consumer. The tracker's `alive` flag (and `allAlive()` / `aliveCount()`) already excludes dead enemies. Treating a long-unseen entry as dead is actively wrong: it is a stale *live* enemy that the freshness fallback must re-acquire. * The `CorpseTicks = 40` radar filter and the `>60`-tick coverage filter that existed only because of this premise have been removed. If a future workload ever *does* show corpses (e.g. a much larger melee, a higher-latency link), reproduce the measurement above first — do not patch from the premise. ## Artifacts * Instrument: `TR_TRACKER_PROBE=1` in `ModularBot` (default off; writes JSONL to `TR_TRACKER_PROBE_PATH`). Kept because it produced the table above. * Measurement harness: `common_libs/tests/measure_corpse_melee.nim`. * Kept API-level proof: `common_libs/tests/test_event_drop_mechanism.nim`. * Death invariant: `common_libs/tests/test_enemy_tracker_death.nim`.