Spectator parties and live racing-place rotation
23 October 2026 - v1.0.9-spectator-playtest.2

The feature is connected to the production targets through the optional
spectators/ReleaseOverlay.cmake composition. Build/archive receipts record
whether a particular artifact finished compiling. Gameplay acceptance belongs
to the owner: no game, mod, test executable or AppImage is launched here.

All authored changes are in patches/spectators. Transformations read final
target sources and write isolated external build copies. Checked-out
submodules, RecompiledFuncs and RecompiledPatches are not edited. Unrelated
work, including patches/library-workflow, is left alone.

Architecture

- The legacy four-racer backend remains when parties are disabled. Party mode
  has a separate authenticated Hello marker and versioned envelope. Watchers
  cannot be silently admitted as racing port zero.
- DirectSession retains transport keys, nonce counters, replay protection,
  Quick Join signalling, ROM/build checks, mod consent and resource admission.
  PartyLink is a separate registry, not an expansion of peers_[4] or a change
  to DirectSession's class layout.
- Party has member identities, roles, optional controller leases, an independent
  host identity and a bounded roster: four racers plus eight spectators.
  Waiting-lobby assignments are separate from confirmed live transfers.
- Quick Join route/pin limits accommodate the larger roster. Racing control
  has reserved queue space. Bulk has per-recipient caps and separate transport/
  replay lanes. Watchers cannot submit input, scene votes or host state.
- PartyRuntime uses the real rollback Driver on the simulation owner.
  OffsetWorld rebases Driver history after a handover, not guest clocks,
  EEPROM/Pak/action cursors, commands or irreversible effects.
- Racers supply immutable leased input. The authority forwards it and stamps
  host-authorised SDK2 commands. Progress/history repair covers delayed
  future-window delivery. Generation/lease checks fence stale outgoing input.
  Network authority does not require ownership of port zero.

Confirmed playback

- The Driver hook observes actual input/commands only after commit. A joining
  checkpoint is copied only at equal simulated/confirmed frontiers. Speculative
  RAM is never an offered baseline.
- Lossless wire encoding/decoding runs on background jobs. Match, schema,
  bounded size, exact decoded layout and digest checks precede admission.
  Offers are acknowledged before unordered chunks start. Confirmed history
  has bounded reordering, acknowledgement and retransmission.
- A slow watcher requests a new baseline rather than entering required racing
  input/scene barriers.
- The concrete ObserverWorld calls the real owned adapter. Thread-local hooks
  enforce the simulation owner. Retirement waits on actual GPU/CPU ownership.
- New future-frame/epoch admission stages EEPROM, Paks, Magic Codes, native
  state, mods and code before guest restoration. Ordinary restore() methods
  retain their irreversible-cursor rollback guards.
- Confirmed Magic Code action history is explicit admission metadata, not a
  reversible checkpoint field. Already confirmed actions cannot be reissued.
- Observer read-only status is local and not checkpointed. It suppresses
  achievement observation/submission, not canonical gameplay journals.
- Party cold boot uses an in-memory EEPROM callback and no personal Pak route.
  Only the authority writes communal online saves, Paks and course records.

Scene changes and player swaps

- Required racers plus the authority agree on confirmed scene continuation
  and constructed baseline hashes. Watchers do not vote. Existing loader
  budgets, allocator guards, validation and GPU retirement remain in place.
- A handover schedules a future input fence, confirms its tail and compares
  state/action signatures from required racing members. The incoming watcher
  transactionally admits that exact checkpoint before acknowledging it.
- Party commits the role/lease transfer only after every required proof agrees.
  A fresh control generation and bounded Driver history begin at the same
  actual frame. The replacement supplies input; the former racer is a watcher,
  not a mandatory hidden input proxy.
- Timeout/cancellation keeps the old owner. Scene changes cancel pending swaps.
  Watcher departure does not stop racing; required racer departure retires
  the match. Host departure closes the lobby; host migration is not claimed.

Presentation and UI

- Spectator-capable lobby is a persisted Host settings control, never a join
  preference. Racers automatically follow the host's selected backend; watch
  requests cannot enable spectators in a lobby whose host disabled them.
- The normal online page provides Racer/Watch Race joining, separate rosters,
  ready/start, host admission, waiting-role changes, seat requests/approval and
  cancellation. Connection, overlay and friend panels remain accessible.
- All Splits retains split display. Follow Player uses the existing full-screen
  HUD/sky/divider/nameplate path with a separate local watch target.
- Director cycles racers and can build cinematic views using the private
  camera draw kernel and retained static collision queries. Canonical
  ttcam_update is never called to move the spectator camera.
- The older private draw closure predates GPU-only custom cars. With custom
  cars present, director uses automatic full-screen racing cameras instead,
  preserving their visuals and seating. Scripted/unsupported views use native
  cameras. This fallback is intentional and documented in PLAYTEST.txt.
- Spectator controls never enter the N64 input ledger. Physical racing input
  changes route only after the committed release.

Peer contract, build and receipts

- A normalized spectator source contract is mixed with each existing owned
  engine identity into a 64-hex admission identity. Windows/Linux must agree;
  old or differently patched peers are rejected before simulation.
- audit.py verifies external source receipts, staged authored files, both ROM
  owners, unchanged ordinary sidecar restore/Driver input and step methods,
  retained scene transactions/work guards, binary markers and optional full
  pre-work source hashes. These are static checks, not gameplay tests.
- package.py uses the existing allowlisted release packager. Windows is a ZIP;
  Linux is a type-2 AppImage assembled/inspected with filesystem tools, never
  by launching it. ROMs, saves, profiles, logs, dumps, keys and debug/authoring
  files are excluded. Required copyright/licence material remains.
- Packages have PLAYTEST.txt, SHA256 sums and source/build receipts. They are
  not uploaded, auto-update-signed or represented as hardware-tested releases.

Windows build:
D:/DiddykongWorkFolder/custom-magic-codes-20261015/windows-build
Linux x86_64 build:
/home/admin/dkr-legacy-behaviour-20261010-x64
Baseline evidence:
D:/DiddykongWorkFolder/spectators-20261022/baseline/SOURCE-FILES.json

Use configure.py with the appropriate build and release source capsule to
reconstruct this composition. stage_core.py also stages a compile-only
portable policy library with MSVC/GCC warnings as errors. Neither route
defines or executes gameplay acceptance tests.
