Mawu · Architecture

Eunomia Governance & the Ori Cross-Version Bridge

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

5sections12 minread1diagram

On this page

V7 — codename Mawu — is a creator republic, and a republic needs two things a single-operator game does not: a way for communities to govern themselves without being able to vote away the platform's safety floor, and a way for a player's identity to persist beyond any one realm or product version. Those are the two halves of the "Governance & Continuity" group. Eunomia is the multi-tier governance data model — five sovereign rule spaces from platform down to guild, six plural voting models, a strict proposal lifecycle, and a non-negotiable safety floor that no vote can override. The Ori Passport is the cross-version bridge — the seam that lets a V7 character, which is fundamentally a V6 Ori identity record, incarnate into V2–V6 destinations (and now realm-to-realm) carrying only a minimal, scoped claim set, while the Ori itself remains the single source of truth no realm ever holds. The two are connected by one idea: sovereignty bounded by an inviolable core. A guild governs its charter but not child-safety; a realm renders your character but never owns it. This page grounds both halves in the code that exists today and is explicit about which seams are compiled and which are still mocked. The full section index lives at ../V7_ARCHITECTURE.md.

What ships, honestly#

Eunomia is a real, test-backed decision kernel — but a kernel, not yet a live service. apps/v7/eunomia-governance-service/src/service.ts (~1,575 lines) is a library of pure, deterministic functions: tier/parent-override validation, safety-floor evaluation, the proposal state machine, six plural-voting tally formulas, Themis appeal routing, localized-proposal rendering, and the Maya Variants/Crucible governance surface. Its service.test.ts carries 12 test cases, and the eunomiaGovernanceServiceDescriptor declares port 47302 and 16 capabilities. The honest qualification: the deployable binary (src/main.ts) is a Node http server that answers exactly one route — /health — returning the descriptor as JSON. There is no Postgres, no live proposal API, and no event bus wired in yet; the governance logic decides, but nothing yet persists or serves it over the wire. Treat Eunomia as a verified rule engine awaiting its transport, not a running governance plane.

The Ori Passport bridge is real, compiled Rust — and it genuinely links the V6 Ori store. libs/v7/substrate-bridge/src/lib.rs (2,462 lines, 8 #[test] blocks) mints passports, runs the cross-version round-trip eval, and opens the realm-federation corridor. Crucially, its Cargo.toml carries real path dependencies — egbe-ori-service = { path = "../../../apps/v6/egbe-ori-service" } and ori-model = { path = "../../v6/ori-model/rust" } — so the V6 Ori event store, projection materializer, and operator-read audit path are compiled in and exercised, not stubbed. default_substrate_bindings() labels exactly the V6 Ori/Aye-Bridge and the Maya engine-core Reused; everything else — V1 identity (libs/shared/auth-primitives), Aje, Lilith, Kuanyin, Themis, Iris, Psyche, Isis, Sophia, Yemaya, and the V6 Egbe gateway — is Mock. Two consequences to keep honest below: (1) the Aye Bridge is reused as the contract owner of the passport envelope (generated_by = "@oshun/aye-bridge", v6_aye_bridge_package_ref = "libs/v6/aye-bridge"), while the minting logic is re-implemented natively in V7 Rust; and (2) Themis treaty signing remains a reference string plus a boolean flag. Proposal appeals now have a separately configured live HTTP dispatch boundary, but no live dispatch receipt was captured in this repository slice.

Eunomia — the multi-tier governance data model#

Governance is partitioned into five tiers, ordered by scope: EUNOMIA_GOVERNANCE_TIERS = ['platform', 'game', 'realm', 'server', 'guild']. Each tier holds a sovereign rule space a parent cannot silently override. The parent chain is explicit in EUNOMIA_PARENT_TIERgame→platform, realm→game, server→realm, guild→server — and platform deliberately has no parent. The sovereignty is enforced in executeGovernanceRuleChange(): a rule change with no parentOverride is marked sovereignRuleSpace: true, and a parent may only reach into a child tier when validateParentOverride() passes all three conditions — the override names the correct parent tier for the target (parent_override_wrong_tier:* otherwise), the target tier has actually consented (consentedByTargetTier, else parent_override_requires_target_tier_consent), and a non-empty reason is given. An attempt to override at the platform tier fails with platform_tier_has_no_parent_override. This is the "a parent cannot override without consent" invariant rendered as code, not prose.

The safety floor no vote can cross#

Sovereignty stops at the platform safety floor. EunomiaSafetyFloorPolicy enumerates the five non-negotiables — minor_protection, harassment_abuse, csam_blocking, identity_privacy, and real_money_firewall — and every rule change must ship a non-empty safetyFloorChecks array (absence yields safety_floor_checks_required). evaluateEunomiaSafetyFloor() filters for any check where compliant === false; a single violation pushes both safety_floor_violation and a policy-scoped safety_floor_violation:<policy> reason, and accepted flips to false. No quorum, no token weight, and no parent-consent path can execute a change that fails the floor — the Lilith/Kuanyin safety posture is structurally above the most powerful vote. The trust-and-safety machinery that backs these policies is described in ./sekhmet-safety-and-anti-cheat.md, and the real_money_firewall policy is the governance face of the economy separation in ./abundantia-economy-firewall-and-anti-fraud.md.

The proposal lifecycle as a strict state machine#

EUNOMIA_PROPOSAL_LIFECYCLE_ORDER fixes the legal path: draft → deliberation → vote → execution → appeal. runProposalLifecycle() replays a submitted transition list against this order. Each transition must carry a non-empty actor, timestamp, and reason (transition_actor_required:* etc.); its from must equal the machine's current state (transition_from_state_mismatch:*); and its to must be exactly the next state returned by nextProposalLifecycleState() (transition_not_allowed:* otherwise). A proposal is complete only when the walk reaches appeal with no accumulated reasons. The state machine is therefore append-only and skip-proof: you cannot jump from draft straight to execution, and the report exposes the full statesVisited trail for audit.

Plural voting — six models, six real formulas#

Eunomia does not hard-code one democratic theory. EunomiaPluralVotingModel offers six, and pluralVotingBallotWeight() gives each a distinct, real weight function (mirrored as human-readable strings in pluralVotingFormula()):

  • tokentokenWeight (stake-weighted).
  • reputationreputationScore.
  • quadraticMath.sqrt(quadraticCredits) — the Weyl/Posner quadratic- voting square-root, which taxes concentration of influence.
  • convictionconvictionStake × convictionAgeHours — time-locked conviction voting, where a long-held position carries more weight.
  • delegatedbaseWeight + Σ delegatedWeights — liquid-democracy delegation.
  • time_weightedbaseWeight × min(membershipAgeDays, 365) — tenure- weighted, capped at one year so longevity cannot become unbounded capture.

tallyPluralVotingModel() does the honest bookkeeping around those formulas: it keeps only the latest ballot per voter (latestPluralVotingBallots(), dedup by castAt), rejects any ballot whose computed weight is non-positive (ballot_weight_must_be_positive), rounds to six decimal places to avoid floating-point drift, tallies for/against/abstain, and computes passed = quorumMet && winningChoice === 'for' && totals.for > totals.against. Rejected ballots are surfaced with reasons rather than silently dropped.

Appeals route to Themis#

A proposal that reaches the appeal state can be escalated by routeProposalAppealToThemis(). It refuses anything not in the appeal lifecycle state (proposal_not_in_appeal_state) and, on success, emits a typed route naming themisModule: '@themis/arbitration', a deterministic themisCaseId (themis:eunomia:<proposalId>:<appealId>), and an appealRef URI (themis://arbitration/eunomia/<proposalId>/<appealId>). Honest seam: this function only constructs the routing contract. The asynchronous dispatchProposalAppealToThemis() path invokes a configured Themis HTTP endpoint. Non-loopback endpoints require HTTPS and bearer authentication; redirects are forbidden, response bytes are bounded before JSON parsing, and the returned schema, service, case, appeal reference, receipt, and timestamp must bind exactly to the request. Rejected lifecycle input never dispatches; HTTP/network/schema failures remain explicit dispatch-failed results. The gateway is executable and contract-tested, but there is no credentialed live receipt in this slice.

Game-tier governance: Maya Variants and the Crucible#

The richest governance surface is at the game tier, where communities steward forkable game variants. publishMayaVariantFork() produces a standalone MayaVariantPublication with a full attribution chain and typed MayaVariantRevenueLinks (parent-fork, marketplace-asset, inherited-dependency), so revenue flows back along the fork lineage — basis-points-validated against MAX_REVENUE_SHARE_BASIS_POINTS = 10_000. resolveCanonicalVariantVote() runs the canonical-variant-vote proposal kind: eligible variants are tallied by latest weighted vote, and the canonical "main" branch is reassigned only when a challenger both wins and strictly out-weighs the incumbent past quorum.

Before a realm can earn Verified status, it must survive the Maya Crucible — an adversarial economic balance check. runMayaCrucibleBalanceVerification() simulates two agent strategies against a realm's economy mods: a baseline-worker that takes honest job payouts, and an exploit-seeker that greedily chains the highest-net-yield mods. detectCrucibleFindings() then flags three blocker classes — excessive-mint (net minted beyond the cap), runaway-growth (balance growth past the bps ceiling), and infinite-currency-cycle (a refund-multiplier loop whose per-tick yield grows ≥4×). evaluateMayaRealmVerifiedGate() finally gates the Verified registry status on all three signals being clean: no blocking Crucible findings, a clean Sekhmet scan, and clean moderation standing. This is governance enforcing economic soundness, and it interlocks directly with the anti-fraud machinery in ./abundantia-economy-firewall-and-anti-fraud.md. Proposals themselves are launch-localized: EUNOMIA_LAUNCH_LOCALES covers eight locales including RTL ar and he, and renderLocalizedGovernanceProposalForRegion() maps five EunomiaGovernanceRegions to default locales, requiring an approved moderation status before a translated proposal renders (else it falls back).

The Ori Passport — cross-version incarnation bridge#

The principle: the Ori is the truth, a realm is a stage#

A V7 character is not a realm's property. It is a NanaCharacterRecord (libs/v7/nana) — ori_id, realm_id, display_name, optional employment, and realm-scoped NanaBalances (cash_minor, bank_minor, society_minor as i64 minor units whose validate() refuses to go negative) — and the ori_id keys a V6 Ori identity record that is the genuine source of truth. The bridge's job is to let that identity be rendered into other Oshun product versions while the Ori root stays singular and intact. As the architecture puts it: the Ori remains the truth; a realm, like any destination, is a stage it is rendered into.

Five incarnation destinations through the reused Aye Bridge#

V7AyeIncarnationDestination enumerates the five V-destinations a character may incarnate into: V2Maya, V3Lilith, V4Odysee, V5Oshun, and V6OriNative (the native Ori return path). Each carries a stable adapter_ref (v2-fighter, v3-citizen, v4-operator, v5-companion, v6-ori-service-native) and a versioned capability_mapping_ref (e.g. capability-mapping:v3-lilith:citizen:v1), so a character's abilities are re-mapped per destination rather than copied verbatim — a fighter in V2 is not the same capability surface as a citizen in V3. default_v7_aye_incarnation_destinations() returns the full inventory, which is the V6 Aye Bridge incarnation model carried into V7 with one new corridor added (federation, below).

Minting a scoped passport: data minimisation by construction#

mint_v7_character_incarnation_passport() produces a V7CharacterIncarnationPassport. Two design choices matter. First, the passport carries only what the destination needs: scoped_claims_for_character() emits a minimal claim setidentity.display, identity.characterKey, and capabilities.mappingRef — not the character's balances, record, or relationships. Second, integrity is hashed: ori_root_integrity_hash() binds the ori_id, the stable character key, and the scoped claims into an ori_integrity_hash that must survive every subsequent lease, fault, and concurrent claim. The envelope is stamped generated_by: "@oshun/aye-bridge" and v6_aye_bridge_package_ref: "libs/v6/aye-bridge", naming the V6 Aye Bridge as the reused contract authority even though the mint runs in V7 Rust.

The round-trip eval: integrity under fault and concurrency#

round_trip_v7_character_into_destination() exercises the full journey: departure → destination actor → return → incarnation-journal write-back. It is adversarial by design. It injects a disconnection during return and recovers via a return_replay_buffer_ref; it fires a concurrent duplicate departure against the same Ori and asserts concurrent_departure_blocked; and it checks that after the dust settles there is exactly one authoritative Ori copy (active_ori_copy_count == 1) and zero lingering destination copies. The receipt's round_trip_ok() returns true only when the copy counts hold, the duplicate was blocked, ori_integrity_hash_before == ori_integrity_hash_after, and the evidence proves both round-trip-integrity and incarnation-journal-writeback — i.e. the journey is recorded back into the Ori biography. This is the same "no window with two writers or zero owners" discipline the mesh uses for authority handoff, applied to identity.

The new V7 corridor: realm-to-realm federation under treaty#

V7 adds one corridor the prior versions did not have: realm-to-realm federation. V7RealmFederationTreaty::themis_signed() defines a corridor between two realms with an explicit allowed_state_keys set and a lease_ttl_seconds; the default treaty (default_v7_realm_federation_treaty()) permits only presence.status, position.cell, party.intent, and realm.quest_state for 900 seconds. open_v7_realm_federation_corridor() then filters the source realm's state down to exactly those keys, hashes the negotiated subset, and sets out_of_scope_state_rejected true only when there genuinely was state outside the treaty that was excluded. Its round_trip_ok() requires a non-empty Themis terms reference, a stable subset hash across the round-trip, a preserved Ori integrity hash, resolved concurrent claims, and out-of-scope rejection. Honest seam: themis_signed is a constructor that sets the boolean and copies a terms reference — the corridor's governance contract is real and validated, but no live Themis call signs it yet (Themis is Mock).

run_v7_passport_eval — the combined continuity gate#

run_v7_passport_eval() is the single gate that composes both legs. It round-trips a character into a V-destination with disconnection, opens a federation corridor with disconnection, and then asserts four properties: v_destination_round_trip_ok, federated_realm_round_trip_ok, ori_integrity_preserved_under_disconnection (both legs' before/after hashes match despite injected faults), and concurrency_preserved_ori_integrity (the duplicate departure was blocked, concurrent corridor claims were resolved, and the two legs agree on the Ori hash). The test passport_eval_round_trips_v_destination_and_federated_realms_with_ori_integrity runs this end-to-end. Because the V6 Ori store is compiled in, the underlying character write (EgbeOriFacade::write_character_record) really appends a MemoryFormed event to PartitionedPostgresOriEventStore and reads it back through the audited operator_read_ori_projection path — the bridge does not fake the identity store it claims to use.

How the bridge composes shared identity#

The passport's authority chain begins at the platform principal. A V7AuthenticatedPrincipal carries user_id, tenant_id, session_id, scopes, and a residency scope — the same claim shape an @oshun/identity (libs/shared/identity) JWT issues for every other Oshun product. V7's binding to that identity layer is currently the Mock StaticIdentityProvider (V7Substrate::V1Identity → libs/shared/auth-primitives), so the shape is the shared one while the wire is still a local stand-in. The continuity guarantee sits on top of it: the V7IdentityFirewall projects the platform principal into a V7RealmScopedIdentity whose opaque_handle is an HMAC of (pepper, principal, realm_id) — so a realm sees a per-realm pseudonym, never the platform account, and the same player in two realms gets two un-linkable handles. The Ori passport then carries the platform-authoritative ori_id across version boundaries while each realm only ever touches the pseudonymous projection. That is the through-line: one shared identity at the core, many scoped renderings at the edges. The platform-side identity foundation this composes is documented in ../../platform/auth-identity.html.

flowchart TD PRIN["Platform principal<br/>@oshun/identity JWT claim shape<br/>(V1 · Mock: StaticIdentityProvider)"] FW["V7IdentityFirewall.project()<br/>opaque_handle = HMAC(pepper, principal, realm)"] NANA["NanaCharacterRecord<br/>ori_id · realm-scoped balances"] ORI["V6 Ori event store<br/>PartitionedPostgresOriEventStore<br/>+ audited operator-read<br/>(Reused · compiled Rust)"] MINT["mint_v7_character_incarnation_passport()<br/>scoped_claims + ori_integrity_hash<br/>generated_by @oshun/aye-bridge"] subgraph DEST["V-destinations — per-destination capability mapping"] V2["V2 Maya"] V3["V3 Lilith"] V4["V4 Odysee"] V5["V5 Oshun"] V6["V6 Ori-native return"] end CORR["open_v7_realm_federation_corridor()<br/>Themis-signed treaty · allowed_state_keys<br/>(Themis binding · Mock)"] PRIN --> FW FW --> NANA NANA -- "character memory (MemoryFormed)" --> ORI ORI --> MINT MINT --> DEST MINT --> CORR DEST -. "round-trip: journal write-back<br/>ori_copy==1 · hash before==after" .-> ORI CORR -. "ori-remains-truth · out-of-scope rejected" .-> ORI
  • Section hub: ../V7_ARCHITECTURE.md
  • Real code cited here: apps/v7/eunomia-governance-service/src/service.ts, apps/v7/eunomia-governance-service/src/main.ts, libs/v7/substrate-bridge/src/lib.rs, libs/v7/substrate-bridge/Cargo.toml, libs/v7/nana/src/lib.rs, and libs/v7/contracts/src/schemas.ts (the V7GovernanceContractSchema and V7CharacterContractSchema Zod contracts).