Mawu · Architecture

Hosting, the Realm Fleet, Data & Compliance

A focused page within the Mawu Architecture documentation. The full map and every sibling page live in the Architecture hub.

7sections12 minread1diagram

On this page

V7 (Mawu) is a creator republic: thousands of community-operated realms, each a server-authoritative UE5 world, all riding one platform's identity, economy, safety, and persistence spine. That shape forces three operational questions the rest of the architecture only gestures at. Where do the realm servers actually run — and on whose hardware, at whose cost? Who is allowed to host — and what can a host's process touch before it crosses the platform trust boundary? And where does the durable truth of a realm live — pinned to which legal region, survivable across a server's death, and erasable on a data-subject's request? The monolith answers all three with deliberately un-trendy choices: self-hosted Agones rather than a managed vendor that might vanish (Unity Multiplay shut down Dec 2025; Hathora May 2026), a Game-Server-Provider (GSP) model that lets creators bring compute but never platform services, and an event-sourced store whose region tag travels with every aggregate. This page is the operations companion to the world-server and persistence pages: it covers hosting and orchestration, the realm fleet and its economics, the data architecture, and the residency/compliance posture — grounding each in the V7 code that exists today and labelling the parts that are still spec. The section hub is ../V7_ARCHITECTURE.md.

What ships, honestly#

The fleet, gateway, and persistence decision logic is real, deterministic, and tested Rust — but it ships as libraries with a health daemon, not yet as a live control plane wired into a running Kubernetes cluster. Three honest qualifications frame everything below.

  • The orchestration logic is real code; the live operator is spec. Danu's danu-mesh-cluster carries a genuine Agones fleet model — Fleet/GameServer CRDs, allocation with scale-down protection, a buffer-plus-webhook autoscaler, and a Spot/On-Demand/Owned cost tier selector — all covered by 22 #[test]s. But every V7 service's run_service() calls service_contract::run_health_server, which serves exactly one route, GET /health, returning the static descriptor JSON (service_contract.rs:88). The CRDs are rendered to YAML text (render_agones_fleet_crd, danu-mesh-cluster/src/lib.rs:625), not applied to a cluster; the logic is a control-plane model with an eval harness, not a controller reconciling a live fleet.
  • Residency in V7 is tagging, carried and verified — not the canonical zone enforcer. Nephthys stamps a free-form region_tag onto every realm, character, property, and vehicle aggregate, byte-verifies it across a restart, and projects it (build_residency_projection, nephthys-replica-service/src/lib.rs:2275). The platform's exhaustive cross-border transfer matrix and decision function — the seven-zone OshunResidencyZone enforcer in @oshun/data-residency — is real shared code (the V3 page documents it in depth) but is not imported by any V7 Rust service. V7 carries the tag; the canonical enforcement is the platform layer it is designed to compose, described here honestly as a seam, not a wire.
  • "Who pays" is encoded across three real subsystems. The hybrid hosting economics live in Danu's cost tiers (who runs on cheap preemptible compute), Mawu's GSP caps (what a creator-hosted process may do), and Abundantia's payout formula (how creator revenue settles). The first two are in scope here; the payout rails are in Abundantia: economy firewall & anti-fraud.

Hosting and orchestration: the Agones realm fleet#

Danu's control-plane model (danu-mesh-cluster, owner Danu, port 47202, lib.rs:46) maps the monolith's "self-hosted Agones" decision into typed, tested Rust. Its capability list names the whole surface: agones-fleet-crds, agones-gameserver-allocation, allocated-server-scale-down-protection, agones-buffer-autoscaler, agones-rp-demand-webhook, spot-stateless-cost-tier, persistent-ondemand-owned-tier, and spot-reclaim-nephthys-reallocation.

Realm → Fleet → GameServer#

A realm maps to an Agones Fleet. register_realm_fleet (:340) turns a DanuAgonesRealmProfile into a DanuAgonesFleetCrd and materializes one DanuAgonesGameServer per replica, each born Ready/Healthy with scale_down_protected_until_shutdown: false (:349). Scheduling is the DanuAgonesScheduling enum (:92) with exactly the two postures the monolith names: Packed for elastic cloud regions (cheap scale-down) and Distributed for owned bare-metal (the repo's Hetzner footprint). A server's lifecycle is the three-state Agones machine Ready | Allocated | Shutdown (DanuAgonesGameServerState, :107).

Allocation and scale-down protection#

allocate_realm_game_server (:364) moves a Ready server to Allocated, binds a session id, and — the decisive invariant — sets scale_down_protected_until_shutdown: true. This is Agones's contract encoded directly: an allocated realm cannot be reaped by the autoscaler until it calls SDK.Shutdown(), so a populated realm is never scaled out from under its players. scale_down_candidates (:426) only ever returns servers that are not allocated, which the autoscaler honors.

Autoscaling: a warm buffer, an evening curve, and instant joins#

apply_autoscaler (:438) reads a DanuAgonesAutoscalerConfig (:182) that carries a buffer_size, min/max_replicas, an evening_peak_extra_buffer, a popular_realm_extra_buffer, and joins_per_ready_server_per_minute, plus the name of the webhook service for RP-specific demand. The buffer policy keeps N pre-warmed Ready realms so joining a popular realm is instant; the webhook arm encodes roleplay-specific demand curves (a DanuRpDemandSignal carries the UTC hour, recent joins/minute, active players, and a popularity score, :193). The cold-start eval run_danu_agones_popular_realm_cold_start_eval (:667) proves the point: its passed() gate (:313) requires join_requests == allocations_without_cold_start and cold_start_waits == 0 — every join is absorbed by the warm buffer, none stalls on a server boot. Both the buffer and the webhook FleetAutoscaler are rendered as real Agones CRDs by render_agones_autoscaler_crds (:652).

Cost tiering — and why cheap compute is safe#

select_danu_realm_cost_tier (:736) is the GameLift-FleetIQ pattern as a branch table over (persistence_class, scheduling, nephthys_backed):

  • A stateless, respawnable session that is Nephthys-backed runs on Spot, preemptible: true, with a 120-second reclaim notice — up to ~90% cheaper.
  • A persistent RP realm on Distributed scheduling runs on OwnedHardware; on Packed it runs OnDemand — never preemptible.
  • A stateless session without Nephthys checkpointing is forced to OnDemand: the reason string says it plainly, "stateless-session-without-nephthys-checkpointing-cannot-use-spot" (:766).

That last branch is the load-bearing safety rule: persistent realm state is only ever placed on cheap preemptible compute because Nephthys holds the truth. run_danu_spot_reclaim_reallocation_eval (:786) closes the loop — its DanuCostTierEvalReport.passed() (:298) requires that after a spot preemption the replacement server is allocated, the preempted server is shut down, and player_visible_state_loss is false: the session is re-hydrated from a Nephthys checkpoint onto a fresh server with the restored state hash matching, so a 2-minute spot reclaim is invisible to players.

flowchart TB C["UE5 attested client"] -->|"sole ingress · scrub + rate-limit"| GW["Mawu gateway :47204<br/>origin shield"] GW -.->|"direct origin probe"| BLK["BlockedDirectOrigin<br/>(origin IP never exposed)"] GW -->|"allocate"| DANU["Danu fleet model<br/>Fleet / GameServer CRDs"] subgraph fleet["The realm fleet"] PLAT["Platform fleet<br/>Spot · On-Demand · Owned"] GSP["Creator BYO-compute (GSP)<br/>sandboxed realm logic only"] end DANU --> PLAT DANU --> GSP PLAT --> NEPH["Nephthys event store :47203<br/>region_tag on every aggregate"] GSP --> NEPH NEPH -->|"checkpoint → spot reclaim"| PLAT NEPH -.->|"residency tag (carried, projected)"| ENF["@oshun/data-residency<br/>(canonical zone enforcer · platform seam)"]

Who runs the realms, and who pays#

The hosting answer is hybrid, and the trust boundary is the whole point. The platform runs identity, economy, safety, and a buffered fleet of "official" realms; creators may bring their own compute for high-volume realms, but a creator-hosted process may run only sandboxed realm logic, never platform services. Mawu's gateway encodes exactly this.

The GSP model: bring compute, not capability#

register_creator_hosted_gsp_realm (mawu-gateway/src/lib.rs:1725) is the admission gate. The MawuGspRuntimeCapability enum is split by is_allowed_for_creator_hosted_realm, which returns true for only SandboxedRealmLogic (:109). Everything else is on the forbidden list MAWU_GSP_FORBIDDEN_CREATOR_HOSTED_CAPABILITIES (:26): PlatformIdentityService, PlatformEconomyService, PlatformSafetyService, PlatformPayoutService, NativeHostProcess, HostNetworking, and DirectClientIngress. Request any of them and registration returns ForbiddenCreatorHostedCapability; omit the sandbox capability and it returns SandboxCapabilityRequired (:1740). The resulting MawuGspRealmRuntimeProfile carries sandboxed_logic_only: true and platform_services_allowed: false, and the eval gate MawuGspRegistrationEvalReport.passed() (:253) demands all four properties at once: accepted, sandboxed-logic-only, no platform services exposed to the realm, and no origin IP exposed to clients. A creator can rent the boxes; the platform keeps the keys to identity, money, and child-safety.

The origin shield and sole-ingress DDoS posture#

Community-hosted realms sit behind the platform gateway so their origin IPs are never exposed — closing the FiveM origin-exposure weakness. A GSP registration fixes origin_disclosed: false, direct_client_ingress_allowed: false, and an origin binding that is client_visible: false / gateway_only: true (:1757:1769). origin_exposed_to_clients (:204) actively checks the public route document for any leak of the upstream endpoint or its host. The gateway is then the sole client ingress: evaluate_gateway_ddos_scrubbing (:1807) runs each MawuGatewayClientIngressAttempt through a scrubber that rate-limits, drops oversize payloads, and classifies any direct-to-origin probe as BlockedDirectOrigin. MawuGatewayDdosEvalReport.passed() (:381) requires that some traffic was rate-limited, some scrubbed, every direct-origin attempt blocked, the origin never exposed, the realm origin never reached by direct client traffic, and sole_client_ingress_enforced true. This is the platform absorbing the DDoS surface so a community operator never has to.

Who pays#

The economics fall out of the model above. The platform pays for the cross-cutting services and the buffered official fleet; Spot soaks up the cost of stateless sessions (Danu's tier selector); creators pay for their own high-volume realm compute under the GSP cap. Creator revenue — the engagement pool, direct sales, and dependency-revenue chains — settles through Abundantia's payout formula, which enforces a hard ≥70% creator floor (a direct-revenue line with creatorShareBasisPoints < 7_000 is rejected, abundantia-market-service/src/service.ts:3313) and a currency firewall that keeps non-cashable realm play-currency isolated from the real-money ledger. The full rails, KYC/tax/reserve gates, and anti-fraud graph are in Abundantia: economy firewall & anti-fraud.

Data architecture: Nephthys#

Nephthys (nephthys-replica-service, owner Nephthys, port 47203, lib.rs:18) is the event-sourced persistence and replication layer that makes the cheap-compute fleet safe. It is the most fully-realized of the V7 services: 15 #[test]s over a real append-only store, a single-writer broker, and a byte-verified restart harness.

Event sourcing and single-writer replication#

NephthysEventSourcedStateStore (:1271) appends typed NephthysStateEvents (realm bootstrap/world-mutation/economy-post; character create/inventory/wallet/ property/vehicle/position), hashes each into a chain, and snapshots every NEPHTHYS_CHECKPOINT_INTERVAL = 3 events (:11). rehydrate_aggregate (:1357) reconstructs any aggregate from its latest snapshot plus the replayed tail — the exact path a reallocated spot server takes. Authority is brokered: NephthysReplicationBroker (:878) hands a single writer an NephthysAuthorityLease with a monotonic fencing_token (grant_authority, :903), and submit_write (:942) rejects everything else — a missing lease, a lease owned by a different node, a stale fencing token, an expired lease, or a write from a node that only holds a read-only view (NephthysSingleWriterError, :820). This is how a meshed region with many sim nodes keeps exactly one authoritative writer per aggregate while others serve read-only replica views.

Byte-verified restart#

The persistence API proves durability the hard way. NephthysPersistenceApiReport.passed() (:1051) requires that the canonical bytes of both the character and realm aggregate are exactly identical before logout and after a restart-and-login (NephthysByteVerification.exact_match, :1015), with no API errors and no violations. "Your house, vehicle, inventory, and wallet survive a server restart" is not asserted in prose here — it is a byte-for-byte equality check over the serialized aggregate.

Residency tagging and the projection#

Every durable aggregate carries a region_tag, set at bootstrap/creation and folded into the state hash so a tag can never silently drift (NephthysRealmState, :123; NephthysCharacterState, :206). build_residency_projection (:2275) walks the event log and emits a BTreeMap<entity_id, region_tag> covering realms, characters, per-property, and per-vehicle residency — and the persistence eval re-checks that the projected tag for the realm, the character, each property, and each vehicle all match the expected region after restart (:1871:1875). Residency is therefore a first-class, hashed, projected property of the durable record, not a column someone hopes is set.

Residency and compliance#

Tags here, the canonical enforcer upstream#

The honest split mirrors V3's, with one difference worth stating plainly. V3 composes the shared @oshun/data-residency enforcer at its BFF; V7's Rust services do not import it yet. They carry their own region_tag and assume the canonical layer above them. That canonical layer is real and substantial: @oshun/data-residency (libs/shared/data-residency/src/) is a ResidencyEnforcementService (enforcer.ts), an AsyncLocalStorage routing context (traffic-shaping.ts), a home-zone resolver (home-zone.ts), and a DSAR router (dsr-routing.ts) composing an exhaustive per-artifact rule table and the seven-zone eu | uk | us | ca | latam | apac | global transfer matrix. In V7's target topology that engine decides whether a tagged aggregate may legally move; Nephthys's tag is the input it reads. Today the tag is enforced by V7's own byte/hash checks; the cross-border transfer decision is the documented platform seam, not V7 Rust.

Where V7 does stamp residency in code#

The one place V7 writes a residency record itself is the cross-version bridge. substrate-bridge's residency_tag (libs/v7/substrate-bridge/src/lib.rs:1804) stamps every V6 Ori write with the principal's residency_scope, a stable policy_ref of "data-residency:v7:ori-substrate-bridge", and a derived audit_id — so incarnation writes into the shared identity store carry an auditable residency provenance. The Ori passport and bridge are detailed in Eunomia governance & the Ori bridge.

Compliance posture#

The monolith's compliance commitments — GDPR/CCPA DSAR (reuse V5 compliance-dsar), DSA reporting, a COPPA path for under-13, and the platform-central age-assurance regime — are reuse-and-declare, not new V7 code: V7 routes data-subject requests into the platform's existing DSAR pipeline (the same themis.privacy.dsr.<zone> queue model the shared dsr-routing.ts produces) rather than building a bespoke V7 deletion path. The child-protection machinery that makes those obligations enforceable — CSAM/grooming detection, the voice-safety tap, age banding — is platform-central and lives in Sekhmet safety & anti-cheat. As elsewhere in Oshun: the data shapes and tagging are coded, the legal obligations are documented and audited.

Failure modes and refusals#

The layer is built to refuse rather than fabricate, and each refusal is a located eval gate:

  • A creator process asking for a platform capability → registration returns ForbiddenCreatorHostedCapability; the GSP eval fails unless platform_services_exposed_to_realm is false (lib.rs:253).
  • A direct-to-origin client probe → classified BlockedDirectOrigin; the DDoS eval fails if the realm origin ever receives direct client traffic (:381).
  • A non-authoritative writesubmit_write returns a typed single-writer error and the ledger does not advance (:942).
  • A stateless realm without checkpointing asking for Spot → the cost selector forces OnDemand; only Nephthys-backed sessions earn preemptible compute (:766).
  • A spot reclaim → re-hydrate from checkpoint with player_visible_state_loss: false, or the cost-tier eval fails (:309).
  • A restart that drops a byteexact_match is false and the persistence report fails (:1051).

Where this connects#