PARTY DEPARTURE REPAIR - PLAYTEST 12
===================================

Evidence and limits
-------------------
The user confirms Playtest 11 connects, starts and plays. The local host log
contains offer acknowledgement, racer admission and release at epoch 91/frame
zero, followed by successful rendering through frame 3172. There is no departure
record before the local runtime is closed. The user says the remote client closed
DKR-R completely, while the host continued and still listed that client connected.
The supplied client log (attachment 09e3567c-1200-4fbd-afbc-ef163cca4c69) renders
through frame 3171, then reports "The host closed the lobby" at line 602. It
retires the runtime, returns to the launcher, and stays there for another 876
seconds before its clean launcher exit. It does not record a client-first close
while the host continues. This particular log therefore cannot prove the reported
departure order or distinguish a lost goodbye from another shutdown cause. The
repair below addresses verified source gaps; field acceptance remains pending.

Confirmed source gaps
---------------------
* Client disconnect sends a single Leave, flushes into the transport, then retires
  that transport without a receipt. Queue acceptance does not prove peer delivery.
* Admitted party members are absent from the generic four-port PeerRecord table;
  generic authenticated Disconnect notices need a party-specific bridge.
* Host handling ignores LinkKind::Returned, although clients emit that event when
  leaving the runtime for the lobby.
* Explicit leave, transport departure and silence expiry duplicate retirement and
  perform different cleanup. Only some set an explanatory stop reason. Silence
  expiry waits 30 seconds, and runtime stops are deferred via stop_requested.

Repair
------
A client closing its admitted party sends a versioned Leave notice bound to its
authenticated member identity. The host flushes a receipt before retiring that
member. The closing owner pumps only authenticated matching receipts, not delayed
Room/launch/game input, for at most 400 ms before proceeding with normal teardown.
No PartyLink lock is retained across this bounded pump; DirectSession retains its
existing mutex ownership. No detached helper, force termination or dependency
change is introduced. Forced process/network loss still uses independent liveness.

Authenticated leave/disconnect notices, transport closure and silence expiry
use one owner-only retirement helper. Existing manual host removal is retained. It
removes membership and Ready/role requests, purges queued member traffic, wipes
the retired key, releases the pinned route and forces a fresh roster publication.
If the departed member was a racer in a live launch, stopping is marked immediately
so the simulation cannot keep the old controller roster running; the existing
retirement/confirmed-save/return-to-lobby machinery completes the shared stop.
A spectator departure does not stop the race or acquire/reassign a controller.
Returning to the launcher ends the shared match while retaining lobby membership.

Terminal current-transport departures remain immediate. The independent watchdog
retires members after ten seconds without authenticated traffic. Recoverable
WebRTC Disconnected callbacks are NOT made immediately terminal. Current-route,
AEAD, room, sender, replay-window and strict receipt length/version/id validation
remain. The watchdog applies symmetrically when a host disappears.

Preservation and validation
---------------------------
Only patches/party-departure-repair is authored. The overlay composes after the
accepted Playtest 11 clock fix. Three first-party units are staged externally:
direct_session.cpp, experimental_runtime.cpp (compatibility identity/exit log), and
party_runtime.cpp (one early return in update_hub when retirement has begun). That
guard prevents an already-running simulation pulse from republishing its old roster
after the network owner removes a racer. Checkpoint handling, simulation/startup,
the five-second start gate, renderer, physics, mods and saves remain unchanged.
No checked-out submodule, RecompiledFuncs or RecompiledPatches is edited.

Recovery snapshot:
D:/DiddykongWorkFolder/party-departure-repair-20261023/baseline

Audits re-compose outputs, verify compiler bindings and retained source contracts,
check authentication/receipt/role/retirement ordering, and compare all pre-existing
authored files with the snapshot. Windows/Linux compile/link and ZIP/AppImage static
checks only. No game, mod, test executable or AppImage is run. Real shutdown/network
acceptance remains the user's test. No commit, push, public release or signing.
