@ -1,4 +1,4 @@
# AUDIT — 2026-05-07 — YOU500 void-death on AuthMe restore
# AUDIT — 2026-05-07 — < PLAYER > void-death on AuthMe restore
Reviewer: Claude (auth-limbo audit pass).
Reviewer: Claude (auth-limbo audit pass).
Scope: Read-only review of `src/main/java/ru/authlimbo/**` against a real
Scope: Read-only review of `src/main/java/ru/authlimbo/**` against a real
@ -10,21 +10,21 @@ Status: **Audit-only — no code changes applied.** Fixes tracked in
## 1. Incident
## 1. Incident
` YOU500 ` joined the server, was held in `auth_limbo` (correct), authenticated
` <PLAYER> ` joined the server, was held in `auth_limbo` (correct), authenticated
to AuthMe, and was teleported back to overworld — but Paper rejected the
to AuthMe, and was teleported back to overworld — but Paper rejected the
teleport and the player void-died with full inventory loss.
teleport and the player void-died with full inventory loss.
### Raw log (paper-server.log, trimmed)
### Raw log (paper-server.log, trimmed)
```
```
17:13:35 YOU500[/45.157.234.219 ] logged in with entity id 26548
17:13:35 < PLAYER > [/< HOME-IP > ] logged in with entity id 26548
at ([auth_limbo]0.5, 128.0, 0.5)
at ([auth_limbo]0.5, 128.0, 0.5)
17:13:38 [AuthMe] YOU500 logged in
17:13:38 [AuthMe] < PLAYER > logged in
17:13:39 [INFO:DEBUG] Restoring fly speed for LimboPlayer YOU500 to 0.1 (RESTORE_NO_ZERO mode)
17:13:39 [INFO:DEBUG] Restoring fly speed for LimboPlayer < PLAYER > to 0.1 (RESTORE_NO_ZERO mode)
17:13:39 [INFO:DEBUG] Teleporting ` YOU500 ` after login, based on the player auth
17:13:39 [INFO:DEBUG] Teleporting ` <PLAYER> ` after login, based on the player auth
17:13:39 YOU500 left the confines of this world < -- VOID DEATH
17:13:39 < PLAYER > left the confines of this world < -- VOID DEATH
17:13:39 [AuthLimbo] Restoring YOU500 to world(2380.4, 69.9, -11358.4)
17:13:39 [AuthLimbo] Restoring < PLAYER > to world(2380.4, 69.9, -11358.4)
17:13:39 [AuthLimbo] teleportAsync returned false for YOU500
17:13:39 [AuthLimbo] teleportAsync returned false for < PLAYER >
— Paper may have rejected the location.
— Paper may have rejected the location.
```
```
@ -38,7 +38,7 @@ the restore step.
`authme.db` and schedules `addPluginChunkTicket` on `world` chunk
`authme.db` and schedules `addPluginChunkTicket` on `world` chunk
`(2380>>4=148, -11359>>4=-710)` . So far so good.
`(2380>>4=148, -11359>>4=-710)` . So far so good.
2. AuthMe authenticates and runs **its own** broken teleport
2. AuthMe authenticates and runs **its own** broken teleport
(`Teleporting YOU500 after login`). This is the AuthMe-fork log line, not
(`Teleporting < PLAYER > after login`). This is the AuthMe-fork log line, not
ours — AuthMe does a `teleportAsync` of its own with no chunk preload.
ours — AuthMe does a `teleportAsync` of its own with no chunk preload.
3. AuthMe's teleport partially moves the entity into `world` at the saved
3. AuthMe's teleport partially moves the entity into `world` at the saved
coords **before the chunk is actually loaded** . The entity is now at
coords **before the chunk is actually loaded** . The entity is now at
@ -78,7 +78,7 @@ behaviour on void death. We do not snapshot inventories.
### H1 — AuthMe's own broken teleport voids the player BEFORE our handler fires *(most likely)*
### H1 — AuthMe's own broken teleport voids the player BEFORE our handler fires *(most likely)*
The AuthMe-fork log line `Teleporting YOU500 after login, based on the
The AuthMe-fork log line `Teleporting < PLAYER > after login, based on the
player auth` at `17:13:39` is from AuthMe-ReReloaded fork b49 itself
player auth` at `17:13:39` is from AuthMe-ReReloaded fork b49 itself
(`PlayerAuth.teleportOnLogin` flow). AuthMe does a teleport with **no chunk
(`PlayerAuth.teleportOnLogin` flow). AuthMe does a teleport with **no chunk
preload** to the saved coords. In Paper 1.21.11, calling `teleportAsync` to
preload** to the saved coords. In Paper 1.21.11, calling `teleportAsync` to
@ -107,7 +107,7 @@ description of the race.
`onAsyncPreLogin` adds a ticket on the chunk computed from the saved
`onAsyncPreLogin` adds a ticket on the chunk computed from the saved
quit-location. But the player's first-time-join behaviour might use a
quit-location. But the player's first-time-join behaviour might use a
different teleport target (AuthMe spawn-on-first-login). For an existing
different teleport target (AuthMe spawn-on-first-login). For an existing
player like YOU500 this is unlikely — they have a saved row.
player like < PLAYER > this is unlikely — they have a saved row.
### H3 — `teleport-delay-ticks: 10` is too long *(secondary)*
### H3 — `teleport-delay-ticks: 10` is too long *(secondary)*
@ -148,7 +148,7 @@ While a player is in the post-LoginEvent restore window, register a
limbo spawn (`limboManager.spawn()`) at y=128. Then re-attempt the
limbo spawn (`limboManager.spawn()`) at y=128. Then re-attempt the
authoritative teleport via `doTeleport` with a backoff.
authoritative teleport via `doTeleport` with a backoff.
This single guard would have saved YOU500 's life and inventory.
This single guard would have saved < PLAYER > 's life and inventory.
### F2 — MUST: when `teleportAsync` future returns `false` , recover
### F2 — MUST: when `teleportAsync` future returns `false` , recover
@ -202,7 +202,7 @@ inventory is ever lost on an auth-flow death.
If F1– F4 all fail and the player is still in void state after N retries,
If F1– F4 all fail and the player is still in void state after N retries,
set `GameMode.SPECTATOR` , teleport to overworld spawn (server world's
set `GameMode.SPECTATOR` , teleport to overworld spawn (server world's
default spawn), and send admin a Discord/console alert: "AuthLimbo could
default spawn), and send admin a Discord/console alert: "AuthLimbo could
not restore YOU500 — manual `/authlimbo tp YOU500 ` required". The
not restore < PLAYER > — manual `/authlimbo tp <PLAYER> ` required". The
spectator mode prevents further damage and lets the player observe the
spectator mode prevents further damage and lets the player observe the
world while admin acts.
world while admin acts.