auth-limbo/ROADMAP.md
s8n 1f9d4bb198
Some checks are pending
Build / build (push) Waiting to run
docs: incident audit + roadmap for 2026-05-07 void-death
Player YOU500 lost full inventory at 17:13:39 due to AuthLimbo
teleportAsync rejection during AuthMe-driven post-login teleport.
Items void-dropped, no backup recoverable.

AUDIT-2026-05-07.md traces code path (LoginListener.java:128, 172-175)
and ranks fix candidates F1-F7. ROADMAP.md slots them across
v1.1.0/v1.2.0/v1.3.0 with priority and acceptance criteria.

P0 fixes pending source change:
- F1: VOID-damage guard (EntityDamageEvent listener at HIGHEST)
- F2: recovery on teleportAsync false (sync-TP back to limbo + retry)
- F4: pre-empt AuthMe internal teleport (LoginEvent at LOWEST)

Privacy posture preserved across all proposed changes.
2026-05-07 17:33:07 +01:00

127 lines
4.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ROADMAP — AuthLimbo
Tracked work items for the plugin. Format: priority, ID, title, status,
acceptance criteria. Source-of-truth for what needs to ship next.
Status legend:
- `OPEN` — not started
- `WIP` — in progress on a branch
- `BLOCKED` — waiting on upstream / external
- `DONE` — landed on `main`, in a tagged release
---
## P0 — must-fix (data-loss bugs)
### F1 · OPEN · Void-damage guard during post-login restore
Source: [AUDIT-2026-05-07.md](AUDIT-2026-05-07.md) §4 F1. Triggered by
YOU500 incident on 2026-05-07 — full inventory loss to void on login.
Acceptance:
- New `Set<UUID> pendingTransit` in `LoginListener`.
- UUID added on `LoginEvent`, removed on TP success or final retry give-up.
- `EntityDamageEvent` listener at `EventPriority.HIGHEST`: if
`entity instanceof Player`, UUID in `pendingTransit`, cause is `VOID`
`setCancelled(true)` and `player.teleport(limboManager.spawn())`
*synchronously* (we need to land before the next tick voids them again).
- Covered by test plan §5.1 and §5.4 in AUDIT-2026-05-07.md.
### F2 · OPEN · Recovery when teleportAsync returns false
Source: [AUDIT-2026-05-07.md](AUDIT-2026-05-07.md) §4 F2.
Today: `LoginListener.java:172175` only logs. After fix:
- On `success == false`: synchronously TP to limbo spawn, schedule one
retry of `doTeleport` after 20 ticks.
- Track retry count per UUID (max 3). After 3 failures: drop into F6 path.
- Also wire the `exceptionally` branches (lines 180185, 186191) into
the same recovery.
Acceptance: test plan §5.2 passes — invalid coords trigger recovery, no
void death, admin sees logged retries.
### F4 · OPEN · Pre-empt AuthMe's own broken teleport
Source: [AUDIT-2026-05-07.md](AUDIT-2026-05-07.md) §4 F4. Implements
option (a): add a second `LoginEvent` handler at `EventPriority.LOWEST`
that immediately teleports the player back to limbo spawn. AuthMe's
internal teleport then runs against an irrelevant location, our MONITOR
handler wins last.
Depends on: F1 (so void damage during the LOWEST→MONITOR window is
guarded).
Acceptance: in test plan §5.6, log shows AuthMe's TP line followed by no
`left the confines` event before our authoritative TP fires.
---
## P1 — defensive (failure modes we know about)
### F3 · OPEN · Pre-flight 3x3 chunk preload before teleportAsync
Source: [AUDIT-2026-05-07.md](AUDIT-2026-05-07.md) §4 F3.
In `doTeleport` (LoginListener.java:133), before calling
`getChunkAtAsyncUrgently` on the centre chunk, also `addPluginChunkTicket`
on the eight neighbours. Release all nine tickets via the existing
`scheduleTicketRelease` path (extend it to take a list).
Acceptance: test plan §5.1 passes even when the centre chunk is on a
section boundary that previously triggered "loaded but not ready".
### F5 · OPEN · Inventory snapshot + auto-restore on transit death
Source: [AUDIT-2026-05-07.md](AUDIT-2026-05-07.md) §4 F5. Defence in
depth — even if F1F4 all fail, no inventory is lost.
- On `AuthMeAsyncPreLoginEvent` (in addition to chunk pin), snapshot
player inventory + xp + location into `Map<UUID, Snapshot>`.
- Optionally persist to `plugins/AuthLimbo/snapshots/<uuid>.nbt` for
crash-survivability.
- On `PlayerDeathEvent` while UUID in `pendingTransit`:
`event.getDrops().clear()`, `event.setKeepInventory(true)`,
`event.setKeepLevel(true)`. On `PlayerRespawnEvent`, restore from
snapshot if needed and TP to limbo spawn for re-restore.
- Snapshot discarded 30 s after successful TP.
Acceptance: test plan §5.5 — induced death during transit yields full
inventory on respawn.
---
## P2 — nice-to-have
### F6 · OPEN · Spectator-mode admin-alert fallback
Source: [AUDIT-2026-05-07.md](AUDIT-2026-05-07.md) §4 F6. After 3 failed
retries (F2): set spectator, TP to overworld default spawn, console log
+ optional Discord webhook config key. Player gets a message to ping
staff for manual `/authlimbo tp`.
### F7 · OPEN · Telemetry counters + `/authlimbo stats`
Source: [AUDIT-2026-05-07.md](AUDIT-2026-05-07.md) §4 F7.
Track per-session counters: restore_success, restore_retry,
restore_fail, void_damage_blocked, snapshot_restored. Expose via a new
`/authlimbo stats` subcommand. Reset on plugin reload.
---
## Done
(Nothing landed since v1.0.0 release on 2026-04-30. First post-1.0
release will be triggered by F1+F2+F4 landing as v1.1.0.)
---
## Release plan
- **v1.1.0** — F1, F2, F4 (data-loss fix). Target: ASAP.
- **v1.2.0** — F3, F5 (defence in depth). Target: within 2 weeks.
- **v1.3.0** — F6, F7 (ops UX). Target: opportunistic.
Privacy invariant (limbo-on-join, no overworld exposure pre-auth) must
hold across every release. See `AUDIT-2026-05-07.md` §6.