# Spawning & Respawning Authority

## Purpose
This document defines the current spawning/respawning authority model in TTT.
It is the source of truth for where spawn decisions are made, how lifecycle state interacts with spawning, and what safety guarantees exist.

## Authority map
- Lifecycle authority: `Code/Players/Lifecycle/PlayerState.cs`
  - Owns lifecycle transitions (`NotInRound`, `PreRound`, `Playing`, `DeadSpectating`) and life/respawn state bookkeeping.
- Spawn orchestration authority: `Code/Players/Spawning/SpawnSystem.cs`
  - Owns round-phase spawn orchestration, warmup/waiting auto-respawn timing, and batch windows.
- Physical spawn authority: `Code/Players/Spawning/Services/SpawnExecutionService.cs`
  - Owns spawn transform application, movement reset, reservation windows, and stabilization.
- Spawn point policy authority: `Code/Players/Spawning/Services/SpawnPointSelector.cs`
  - Owns safe point selection, overlap/clearance checks, and distance scoring.
- Participation admission authority: `Code/Players/Lifecycle/ParticipationService.cs`
  - Owns AFK/skip-round inclusion decisions.

## Core model and enums
- Spawn reason enum: `Code/Players/Spawning/Model/SpawnReason.cs`
- Participation disposition enum: `Code/Players/Lifecycle/ParticipationDisposition.cs`

## Runtime flow

### Initial join
- `Code/Game/Host/Network/GameNetworkManager.cs` seeds lifecycle and resolves initial spawn transform via `SpawnExecutionService.GetSpawnTransform(...)` before first `NetworkSpawn`.

### Pre-round admission
- `SpawnSystem.PreRoundStart()` snapshots connected players.
- For each player:
  - `ParticipationService.ShouldParticipateThisRound(...)` decides inclusion.
  - Included players are moved to `PreRound` via `PlayerState.PrepareForRound(...)`.
  - Excluded players are moved to observer via `PlayerState.EnterObserver(...)`.
- Included players are staged into the round-start participant list.
- Actual reset/spawn batch now runs in `SpawnSystem.OnRoundStart(...)`, which executes after the cleanup barrier in `GameMode.DispatchRoundStartWithBarrier(...)`.

### Round start reconciliation
- `SpawnSystem.PostRoundStart()` ensures participating players are alive/full health.
- `PreRound` participants are promoted to `Playing`.
- Final host reconciliation runs via `PlayerState.ReconcileAllForRoundStart(...)`.

### Client respawn finalize and spawn confirmation
- Client-side finalize (`PlayerComponent.State`) no longer force-possesses on timeout fallback.
- Finalize waits for convergence:
  - local owner pawn binding,
  - lifecycle in `PreRound` or `Playing`,
  - life state `Alive`.
- Finalize possession uses standard route (`ConnectedClient.ClearSpectateTarget()` + `ConnectedClient.Possess(...)`).
- Spawn confirmation (`PlayerStateComponent.SendSpawnConfirmation`) is acknowledgement-only on host (`PlayerState.FinalizeSpawnFromClient(...)`) and does not re-enter host spawn state machine.
- During map-switch transitions only, host tracks post-commit confirmations through `TransitionOrchestrator`:
  - no global round stall for stragglers,
  - each pending player has an independent timeout (`t.transition.map.player_timeout`, default `60s`),
  - timed-out players receive a soft recovery pass instead of being forced to observer:
    - pawn binding is reasserted,
    - the current host-authored life snapshot is rebroadcast.

### Targeted respawn-recovery resync
- When finalize remains blocked (pawn mismatch timeout or lifecycle/life not ready), owner client can request targeted respawn recovery resync.
- Host accepts targeted recovery only when all checks pass:
  - caller owns the pawn,
  - requested spawn transform sequence matches host sequence,
  - request is inside short post-respawn recovery window.
- Host logs explicit accept/reject reasons for this path under resync diagnostics.

### Waiting-for-players auto respawn
- `SpawnSystem.OnFixedUpdate()` handles auto-respawn.
- In `GameState.WaitingForPlayers`, a per-player timer (`RespawnDelaySeconds`, default 3s) gates transition from `RespawnState.CountingDown` to `RespawnState.Ready` and final respawn.
- Resync revive is disabled in waiting-for-players to avoid bypassing this delay path.

### Manual respawn and move-to-spawn calls
- `PlayerComponent.RespawnHost(...)` routes to `SpawnExecutionService.ExecuteRespawnHost(...)`.
- `PlayerComponent.PlayerReset(...)` routes through the same authority.
- `PlayerComponent.MoveToSpawnPoint()` routes through the same authority with `SpawnReason.MoveToSpawnPoint` and no reservation.

### AFK and re-entry behavior
- AFK participation state is host-authored (`ConnectedClient.IsAFK`).
- AFK on: host routes to observer.
- AFK off: immediate forced re-entry is only performed in `GameState.WaitingForPlayers` (prepare + manual respawn). Other states do not force respawn.

## Safety guarantees
- Batch reservation prevents duplicate spawn-point reuse within a spawn wave.
- Selector policy avoids occupied/blocked points and uses clearance + ground checks.
- Respawn execution clears movement state before and after teleport.
- Host stabilization window can clamp/rewind extreme launch behavior immediately after spawn.
- Kill/death side effects are gated to live round only via `Code/Players/Lifecycle/RoundEventPolicy.cs`.

## Tuning and diagnostics convars
- Spawn execution:
  - `t.db.spawn`
  - `t.spawn.reservation_window`
  - `t.spawn.stabilize_window`
  - `t.spawn.stabilize_max_speed`
  - `t.spawn.stabilize_max_displacement`
- Spawn selection:
  - `t.spawn.min_player_separation`
  - `t.spawn.clearance_radius`
  - `t.spawn.clearance_height`
  - `t.spawn.ground_probe_distance`
- Participation:
  - `t.db.participation`
- Resync diagnostics:
  - `t.db.resync`

## Local visual transition
- Service: `Code/Presentation/Services/LocalSpawnTransitionService.cs`
- Overlay: `Code/UI/Features/Match/State/SpawnTransitionOverlay.razor`
- Purpose: local-only spawn/respawn fade; does not participate in host authority decisions.

## Hardening playtest checklist (spawn/lifecycle)
1. Enable diagnostics:
   - `t.db.resync 1`
   - `t.db.stateauthor 1`
2. Start round and verify barrier ordering:
   - Expect cleanup barrier logs before round-start spawn execution.
3. Validate spawn confirmation behavior:
   - Host should log spawn confirmation as ack-only (`spawn confirmation ack`) with no host re-spawn side effects.
4. Validate respawn finalize convergence:
   - Client should not force-possess on pending finalize timeout.
   - If blocked, expect targeted recovery request logs (`action=request_respawn_recovery`).
5. Validate host targeted recovery decisions:
   - Expect explicit accept/reject reason logs:
     - `action=accept_respawn_recovery`
     - `action=reject_respawn_recovery reason=...`
6. Validate late-join policy:
   - Mid-round joins remain observer (`NotInRound`) until next eligible round admission.
7. Validate map reset path parity (non-regression guard):
   - Compare one round with `t.reset.registry.enable 1` and one with `t.reset.registry.enable 0`.
   - Respawn/spectate/lifecycle behavior should remain identical across both runs.
