docs/PHASE0-PLAN.md: - Lab topology mirroring production 1:1 - two minimum-shape sites (console + 2 cockpits) + hub, hub-and-spoke WireGuard over a host-only "WAN" net with netem as the simulated internet. - Lab IP conventions (strawman seat map; flagged for alignment with real bay numbering before Phase 1). - VM inventory: full 9-VM set and a 5-VM minimum-viable start. - VM management recommendations: VMware Workstation Pro 17 (free personal; host is Win11 Home so no Hyper-V) for the first pass, Proxmox VE on a spare box as the persistent lab / future hub staging; gold images + linked clones, snapshot-per-experiment discipline, config-as-code under lab/, one-knob netem sweep script. - Experiments E1-E9 with pass criteria mapped to the brainstorm's open questions: routed fabric + console RPC over WAN, broadcast locality, FS directed join + port matrix, latency cliff table, WAN-drop behavior, MTU, BT411 cross-subnet egg push, hub host + stream rehearsal, event-day dry run (SiteConfigMerge gate). - Risks: MW4-in-VM rendering (physical-host fallback), vPOD fidelity limits, firewall discipline. Linked from BRAINSTORM Phase 0 and the README contents table. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
282 lines
18 KiB
Markdown
282 lines
18 KiB
Markdown
# SiteLink — design brainstorm
|
||
|
||
Working record, started 2026-07-10. Companion to
|
||
[PODBAY-ECOSYSTEM.md](PODBAY-ECOSYSTEM.md), which holds the verified facts this
|
||
brainstorm builds on.
|
||
|
||
## 0. Goals (proposed — confirm/edit)
|
||
|
||
1. **Cross-site play**: cockpits at site A and site B in the same match (Firestorm first;
|
||
BT411/RP as they mature).
|
||
2. **Preserve the air gap**: the linked fleet is one private network. No bay machine ever
|
||
gets a route to the general internet.
|
||
3. **Fleet visibility/command**: an operator (eventually a master console) can see — and
|
||
where appropriate command — pods at every site.
|
||
4. **Shared front-of-house**: cross-site events share a queue, callsigns, scores.
|
||
(Voice: backburnered — see §6.)
|
||
5. **Zero changes to cockpit hardware**, minimal changes to bay-local operation: a bay
|
||
must keep working stand-alone when the link is down.
|
||
|
||
Non-goals (for now): public matchmaking, spectating from home, per-player home clients.
|
||
|
||
## 1. The seed proposal
|
||
|
||
> Each site gets its own `10.0.y.x` subnet (we get `10.0.1.x`, you get `10.0.2.x`, …),
|
||
> VPN them all together into a single /16, collect every site's `.siteconfig`,
|
||
> concatenate them, and give the result to a master console that commands the fleet.
|
||
|
||
**Verdict: sound skeleton.** The three pieces (site-numbered subnets, VPN mesh into
|
||
`10.0.0.0/16`, merged fleet config) survive contact with the code. The refinements below
|
||
are about *how*, not *whether*.
|
||
|
||
## 2. Addressing plan
|
||
|
||
- **`10.0.<siteID>.0/24` per site**, keeping each bay's existing last-octet conventions
|
||
(pods `.1–.8`, `.11–.18`, camera `.9`, …) so per-site configs become a template
|
||
stamped with a site ID. Legacy `200.0.0.x` bays get renumbered on joining — that
|
||
space is public internet space and must not exist inside the linked fleet.
|
||
- **Reserve `10.0.0.0/24` for shared infrastructure**: VPN hub, master console, central
|
||
PQS, Mumble, NTP, a neutral dedicated game host. Nothing site-specific lives there.
|
||
- **Site ID registry lives in this repo** (`sites/` — one small file per site: ID, name,
|
||
operator, subnet, contact). First allocation: `10.0.1.0/24` = Fallout Shelter Arcade;
|
||
`10.0.2.0/24` = next site. **Scale reality (2026): 6 active pod bays, fewer than 120
|
||
cockpits in existence** — 254 site IDs is beyond generous, and every topology choice
|
||
below can assume single-digit sites.
|
||
- **Netmask choice is the real design fork** (see §3): hosts configured `/24` + gateway
|
||
= routed model; hosts configured `/16` = requires a bridged L2 overlay.
|
||
- Renumbering mechanics: TeslaConsole already owns pod IP config (provisioning writes
|
||
`mIPAddress/mGateway/mDns/mSubnet`), and the CTCL `[teslas]` inis are trivially
|
||
regenerated from a template. So renumbering is a console-driven afternoon, not a
|
||
reimage.
|
||
|
||
## 3. Topology: routed L3 vs bridged L2
|
||
|
||
### Option A — Routed L3 (recommended default)
|
||
Each site keeps its `/24`; a per-site VPN gateway (its *only* new hardware) routes
|
||
between sites over **WireGuard** tunnels.
|
||
|
||
- ✅ Works because Firestorm's join path is **directed by IP** (`TryToJoinASpecificGame`,
|
||
see ecosystem doc) and every console→pod protocol (53290 RPC, Munga 1501, BT egg
|
||
push) is directed TCP. Nothing in the *match-play* path needs broadcast.
|
||
- ✅ Clean failure isolation, no cross-WAN broadcast chatter from era Windows boxes,
|
||
easy per-flow firewalling at each gateway.
|
||
- ✅ Hub-and-spoke (hub on shared infra, e.g. alongside mysticmachines.com) or full mesh —
|
||
WireGuard does either; start hub-and-spoke, it's simpler and the hub is also where
|
||
shared services live.
|
||
- ⚠️ Breaks broadcast-dependent conveniences: DirectPlay "browse LAN games" listing and
|
||
SecureConfig first-boot beacons don't cross sites. Both are acceptable: game joins are
|
||
console-directed anyway, and provisioning is an on-site act by design.
|
||
|
||
### Option B — Bridged L2 overlay (fallback / experiment)
|
||
One virtual Ethernet across all sites (ZeroTier, VXLAN/EoIP between gateways, tinc
|
||
switch mode); hosts could then even use a flat `/16`.
|
||
|
||
- ✅ Everything behaves like one big LAN — broadcast discovery, any undiscovered
|
||
broadcast assumption in 1996–2009 era code, zero renumbering logic beyond uniqueness.
|
||
- ❌ One broadcast domain of ancient unpatched Windows across the WAN (NetBIOS chatter,
|
||
broadcast storms), MTU headaches, harder to reason about, and failure at one site can
|
||
be noisy everywhere.
|
||
- Position: **keep in the back pocket.** If Phase-0 testing (vPOD + two subnets) turns up
|
||
a flow that genuinely requires broadcast, bridge *only* that (e.g. a targeted UDP
|
||
broadcast relay) before going full L2.
|
||
|
||
### VPN tech choice
|
||
WireGuard first (kernel-fast, tiny config, UDP hole-punch friendly, runs on a $50 box or
|
||
the site router). Tailscale/NetBird/ZeroTier are managed alternates if key/peer
|
||
management becomes a burden — but note ZeroTier is the L2 option, Tailscale/NetBird are
|
||
L3. The bay machines themselves never run VPN software; only the per-site gateway does.
|
||
**Bay boxes keep no default route** — gateways carry routes for `10.0.0.0/16` only.
|
||
|
||
## 4. Fleet configuration: master console vs federation
|
||
|
||
The seed proposal: merge all `.siteconfig` files → one master console commands the fleet.
|
||
|
||
**The merge tool exists:** [`tools/SiteConfigMerge`](../tools/SiteConfigMerge/README.md)
|
||
decodes `<siteName>.siteconfig` files and emits one `master.siteconfig`, renaming every
|
||
squad **`<siteName>-<original squad name>`** ("FSA-bay1", "Pharaoh-bay1", …) — one
|
||
squad group per site, which TeslaConsole's UI already organizes naturally. Pod records
|
||
pass through byte-for-byte; verified against the real TeslaConsole 4.11.4.1 loader.
|
||
|
||
**The operating model (settled 2026-07-10): event-scoped authority handover.** When a
|
||
SiteLink event runs, **every participating site willingly hands console authority to
|
||
the central console for the duration of the event** — concretely, by contributing its
|
||
`<siteName>.siteconfig` to the merged master. Outside events, each site console is
|
||
authoritative over its own bay. Notes that keep this clean:
|
||
|
||
- The pod keys inside a siteconfig have no practical value outside the bay's
|
||
air-gapped network (anyone with bay access has the file anyway) — handing the file
|
||
over *is* the handover ceremony, not a security event.
|
||
- Siteconfigs change over time, so they are exchanged fresh per event and are not
|
||
stored in this repo (tools only).
|
||
- Nothing *enforces* the handover — TeslaLauncher has no arbitration if a site console
|
||
and the central console command the same pod concurrently. Convention: site consoles
|
||
stand down for the event window. A soft "event mode" lock in TeslaConsole is a
|
||
nice-to-have if the convention ever gets violated in practice.
|
||
- Remaining technical to-do for the central console: WAN-tolerant RPC timeouts, and
|
||
it should live on shared infra (`10.0.0.0/24`) with a decent uplink.
|
||
|
||
**Federation (a coordinator service so raw keys never leave a site) is off the table**
|
||
at current scale — 6 bays run by trusted operators doesn't need it. Recorded here only
|
||
in case the fleet's trust model ever changes.
|
||
|
||
## 5. Linking the games themselves
|
||
|
||
### Firestorm (first target)
|
||
- **Session model:** one DirectPlay host; everyone joins directed-by-IP. Options for
|
||
host placement:
|
||
- a) Host at one site's console (simplest; other site eats the WAN RTT; O(n²) load on
|
||
that console's uplink);
|
||
- b) **Neutral host at the WireGuard hub (preferred direction, 2026-07-10).**
|
||
Symmetric latency for every site, best uplink — and it exploits an operational
|
||
fact: **the Firestorm server is almost always the Live Cam for that game.** A
|
||
hub-hosted host running the camera-ship role turns the neutral server into the
|
||
event's broadcast point: capture its output and **stream the show to every
|
||
participating site** (Live Cam screens everywhere show the same feed), and
|
||
optionally **stream it publicly to the internet** as the fleet's shop window.
|
||
Considerations: the camera ship *renders*, so the hub box needs a real GPU
|
||
(physical box at the hub location or a GPU cloud instance — not a bare VPS);
|
||
`mw4dedicatedui` (headless) remains the fallback if hub rendering is impractical,
|
||
with a camera-ship client joining from a site instead. Streaming transport is
|
||
one-way and latency-tolerant: OBS capture → SRT/RTMP internally, Twitch/YouTube
|
||
for the public leg. Needs validation either way (dedicated UI is unexercised in
|
||
the modern tree; camera-ship-as-DirectPlay-host in the CTCL flow should be
|
||
confirmed against `ctcl-game.ini`'s `*1`/cameraship entry and the PQS
|
||
`cameraship` flag).
|
||
- **The Mission Review instance lives at the hub too, for the same reasons:** one
|
||
authoritative post-match review (`ctcl-mr` role / MSRSpectator) running next to
|
||
the host that recorded the match, its output streamed to every site's Mission
|
||
Review screen — every bay debriefs from the same show.
|
||
- **Player counts:** the golden first milestone is **8v8 across two sites (8 cockpits
|
||
each) — inside the stock 16-player cap, zero engine changes.** Full 16v16 site-vs-site
|
||
needs the already-drafted 16→32 plan in `firestorm\CLAUDE.md` (compiled defaults +
|
||
drop-zone authoring per map + lobby UI polish).
|
||
- **Latency budget:** the netcode shipped for dial-up (150–300 ms era). Inter-city
|
||
internet (20–80 ms) + WireGuard (~1 ms) should be comfortable. Measure, don't assume:
|
||
put netem delay/jitter/loss on a test gateway and find the cliff (see Phase 0).
|
||
- **Port hygiene:** set the `DirectPlayPort` registry value at every site so game traffic
|
||
is a single known port for the gateways' firewalls, instead of DirectPlay's default
|
||
47624 + 2300–2400 spread.
|
||
- **Fixed-port + MTU checks:** DirectPlay UDP datagrams over a 1420-byte WireGuard MTU —
|
||
verify no fragmentation weirdness (era stacks are fragile here).
|
||
|
||
### BT411 (classic BattleTech)
|
||
- The console already launches multi-pod games by address list (`btconsole.py MP.EGG
|
||
10.0.1.11:1501 10.0.2.11:1501` *is* a cross-site launch). Two unknowns to resolve:
|
||
1. Does the pod↔pod mesh derived from the egg `[pilots]` list carry literal IPs
|
||
(routes fine) or assume same-subnet?
|
||
2. The 1996 sim's latency tolerance — lockstep-ish engines of that era can be
|
||
unforgiving. netem test early.
|
||
- Console-must-stay-connected quirk means the WAN link drop kills the match — argues for
|
||
running the BT console *at the site with the most pods*, or fixing the engine bug.
|
||
|
||
### Red Planet (RP411 reconstruction)
|
||
- Same console-directed model (Munga TCP 1501). Park until BT411 learnings land — shared
|
||
engine lineage means most answers transfer.
|
||
|
||
### Original Tesla 4.10 games under emulation (TeslaRel410)
|
||
- When the DOSBox-X/VPX emulator matures, the *original* BT/RP binaries land on
|
||
current pod hardware speaking their original network stack: **WATTCP (real
|
||
TCP/IP) via NetNub**, surfaced through NE2000-emulation bridged onto the bay LAN
|
||
via pcap. Because it's plain IP with the emulated pod holding a real bay address,
|
||
the routed-VPN model extends to them *in principle* unchanged.
|
||
- Unknowns to test (cheap — emulator instances run on any PC, no cockpit needed):
|
||
NetNub discovery/mesh addressing across subnets, and the latency tolerance of a
|
||
30 Hz 1996 lockstep-era sim. Fold into the Phase 0 netem lab once the emulator
|
||
reaches its networking phase (PLAN.md Phase 6).
|
||
- Strategic note: BT411/RP411 (native, netcode we can patch) and TeslaRel410
|
||
(faithful, netcode frozen in 1996) are complementary. If the original protocol
|
||
proves WAN-hostile, the answer may be "emulated originals for local play, native
|
||
reconstructions for cross-site" — SiteLink shouldn't promise WAN play for the
|
||
emulated path until measured.
|
||
|
||
## 6. Shared services (the `10.0.0.0/24` rack)
|
||
|
||
| Service | Notes |
|
||
|---------|-------|
|
||
| WireGuard hub | The rendezvous point; a VPS (could sit near the existing mysticmachines.com infra) or a box at the best-connected site |
|
||
| Virtual scoresheet printer | A virtual printer at the hub that "prints" event debriefings/scoresheets to **PDF** (Firestorm's print path: `printdebriefing` / `mw4print`). PDFs land in one place and are retrievable from any site on the link — a simple web share on the hub over the VPN. Sites can still print paper locally from the PDFs |
|
||
| Voice (backburnered) | The FS507D release integrated Mumble, but only one operator ever ran it. Technically easy to stand up on the shared network — revisit only if event interest warrants |
|
||
| Queue/roster coordination (future) | Cross-site events will want one queue/roster. **PQS** — the operator-built event traffic-flow tool — is the natural seed, but for now it stays support tooling. If promoted: (a) one central instance all consoles poll — simplest, DB schema grows a `site` column; (b) per-site instances + sync — only if WAN-down resilience of the local queue matters during events. Callsign uniqueness would become fleet-wide |
|
||
| Neutral game host + event broadcast | Firestorm host for site-vs-site matches, co-located with the WireGuard hub. Doubles as the Live Cam (the FS server usually *is* the Live Cam): stream its output to all sites' Live Cam screens, optionally to the public internet. The **Mission Review instance runs at the hub too** — one authoritative debrief streamed to every site's MR screen. Needs GPU at the hub |
|
||
| NTP | One clock for scores, logs, and replay/debrief alignment |
|
||
| Fleet monitoring | VncThumbnailViewer pointed across the VPN; later, master-console status board |
|
||
|
||
Local-only forever: printer and RIO/cockpit I/O. For cross-site events the Live Cam
|
||
and Mission Review *instances* run at the hub (above); each site's LC/MR *screens*
|
||
become display endpoints for the hub streams, serving the local audience. Bay-local
|
||
games keep running their own LC/MR stations exactly as today. Cross-site scoresheets
|
||
go to the hub's virtual PDF printer (table above) — retrievable from any site, with
|
||
local paper printing off the PDFs where wanted.
|
||
|
||
## 7. Security posture
|
||
|
||
- **The fleet stays air-gapped as a whole.** Only gateways touch the internet, only to
|
||
carry WireGuard to known peers. Bay machines: no default route, no DNS egress, static
|
||
`10.0.0.0/16` routes via the gateway.
|
||
- **Gateway firewall = allowlist by flow**, per the port map in the ecosystem doc.
|
||
Suggested split:
|
||
- *Game plane* (DirectPlay fixed port, Munga 1501, Mumble): site↔site and site↔shared.
|
||
- *Management plane* (TCP 53290 launcher RPC, VNC 5900): only site-console↔own-pods
|
||
and master-console↔pods — other sites' consoles have no business on your 53290.
|
||
- **Repo hygiene:** WireGuard private keys never enter this repo. Siteconfigs aren't
|
||
stored here either — not because the pod keys matter off-site (they don't; the bays
|
||
are air-gapped and anyone with bay access has the file), but because they're living
|
||
operational data exchanged fresh per event. Repo holds tools, templates, and
|
||
*public* site registry data (subnets, endpoint hostnames, WireGuard public keys).
|
||
- Era-Windows reality: assume every bay box is compromised-if-reachable. The allowlist
|
||
above is the actual security boundary; the VPN is transport, not trust.
|
||
|
||
## 8. Open questions
|
||
|
||
1. **FS end-to-end join over routed subnets** — directed-join API confirmed in source;
|
||
prove the whole ConLobby/CTCL flow passes the host IP (vPOD + two subnets, or two
|
||
VMs). Any broadcast dependency hiding in the lobby flow?
|
||
2. **`DirectPlayPort` in practice** — is it set at existing sites, and does a fixed port
|
||
carry all session traffic (or only enumeration) under DirectPlay Protocol?
|
||
3. **BT411 `[pilots]` mesh** — IPs or subnet assumptions? (Read `L4NET.CPP`
|
||
StartConnecting path.)
|
||
4. **Latency cliffs per title** — netem sweep: at what RTT/jitter/loss does each engine
|
||
degrade (rubber-banding, desync, disconnect)?
|
||
5. **Dedicated Firestorm host** — does `mw4dedicatedui` build & run in the modern tree,
|
||
and can camera/MR spectators join it cleanly?
|
||
6. **PQS promotion** — if/when the event queue tool becomes cross-site coordination:
|
||
site column vs event database; global callsign policy.
|
||
7. **Console arbitration** — *policy settled 2026-07-10: sites voluntarily hand
|
||
authority to the central console for the event window.* Residual: nothing enforces
|
||
it (TeslaLauncher has no arbitration); an optional soft "event mode" lock in
|
||
TeslaConsole only if the convention ever fails in practice.
|
||
8. **Who hosts shared infra** — VPS vs best-connected site; bandwidth math for a
|
||
32-player O(n²) host (~upstream estimate needed from real packet captures).
|
||
9. ~~Site count ambitions~~ — **answered 2026-07-10: 6 active bays, fewer than 120
|
||
cockpits in existence.** Hub-and-spoke is trivially sufficient; federation is
|
||
permanently unnecessary barring a trust-model change.
|
||
10. **WAN-drop behavior** — for each linked flow, what breaks when the tunnel drops
|
||
mid-match, and does the bay cleanly fall back to stand-alone?
|
||
11. **NetNub over routed subnets (TeslaRel410)** — how do the original 4.10 games
|
||
discover/address each other (read `CODE\*\MUNGA_L4\NETNUB\` + `L4NET` lineage)?
|
||
Broadcast-dependent or console-directed like their descendants? And what RTT does
|
||
the 30 Hz 1996 sim tolerate?
|
||
|
||
## 9. Phased roadmap (strawman)
|
||
|
||
- **Phase 0 — Lab proof (no hardware, no travel).** Two "bays" as VMs/vPOD instances on
|
||
two subnets with a WireGuard/netem gateway between them. Prove: console→remote-pod
|
||
RPC (53290), a 2-client Firestorm match across subnets, latency sweep, BT411
|
||
cross-subnet egg push. *Everything above that's marked "verify" gets verified here.*
|
||
**→ Full plan with lab topology, VM inventory/management, and experiments E1–E9:
|
||
[PHASE0-PLAN.md](PHASE0-PLAN.md).**
|
||
- **Phase 1 — First real link.** Two sites, gateways, tunnel, renumber to
|
||
`10.0.1.x`/`10.0.2.x`. Fleet VNC + remote Mission-Review spectating. First
|
||
cross-site Firestorm match at ≤16 total players (8v8) on the stock exe.
|
||
- **Phase 2 — Fleet operations.** ~~siteconfig merge tool~~ ✅ built
|
||
([`tools/SiteConfigMerge`](../tools/SiteConfigMerge/README.md), verified against the
|
||
real console loader) → run an event under the authority-handover model (§4): collect
|
||
`<siteName>.siteconfig`s, merge, central console commands the fleet. Optional PQS
|
||
event mode with shared queue/callsigns; debrief/scoresheet distribution to both
|
||
printers.
|
||
- **Phase 3 — Full site-vs-site.** Execute the firestorm 16→32 plan (code defaults +
|
||
drop zones), neutral dedicated host, 16v16 events.
|
||
- **Phase 4 — More titles, more sites.** BT411/RP cross-site as those engines mature;
|
||
3rd+ site onboarding kit (gateway image + site-ID allocation + config templates);
|
||
revisit federation and the GUN/GameSpy-style fleet game browser.
|