Anatomy of a coalition
audience: contributors
This chapter is the concrete instantiation of the pattern
described in Designing coalitions on mosaik.
It walks one example coalition end-to-end: the fingerprint
derivation, the public surface each component exposes on
the shared universe, the subscription graph across
citizen boundaries, and the way an integrator binds
handles through one CoalitionConfig.
The reader is assumed to have read the topology intro, the basic-services spec, and the builder architecture chapter.
Coalition identity recap
COALITION = blake3("coalition|" || SCHEMA_VERSION_U8
|| "|" || coalition_name)
COALITION_ROOT = blake3(
COALITION
|| ordered lattice stable ids
|| ordered organism stable ids
|| ordered confluence fingerprints
|| optional ticket-issuer fingerprint
)
// Lattice IDs: NOT re-derived by the coalition.
LATTICE_i = <builder's own derivation for lattice i>
ORGANISM_IN_i = <builder's own derivation for each organism in lattice i>
// Standalone-organism IDs: NOT re-derived by the coalition.
STANDALONE_j = <the organism's own derivation>
// Confluence IDs: derived independently of any coalition.
CONFLUENCE_c = blake3("confluence|" || SCHEMA_VERSION_U8
|| "|" || name
|| spanned citizens
|| content
|| acl)
// Module IDs: the three coalition-scoped components.
ATLAS_ROOT = COALITION_ROOT.derive("module").derive("atlas")
ALMANAC_ROOT = COALITION_ROOT.derive("module").derive("almanac")
CHRONICLE_ROOT = COALITION_ROOT.derive("module").derive("chronicle")
// Optional coalition-scoped ticket issuer.
TICKETS_ROOT = COALITION_ROOT.derive("tickets")
Citizen identity travels with the citizen; confluence identity travels with the confluence. Only module identity (and the optional ticket issuer) is coalition-bound. See topology-intro — Citizenship-by-reference and topology-intro — Confluences as their own rung.
Integrators bind via the CoalitionConfig they compile in
from operator-published release notes:
use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;
use coalition::CoalitionConfig;
const ETH_SUPERCHAIN: CoalitionConfig<'static> = /* operator-published */;
let network = Arc::new(Network::new(UNIVERSE).await?);
// Lattice organism handles — identical to the builder book.
let eth_bid = offer::Offer::<Bundle>::bid (&network, Ð_SUPERCHAIN.lattices[0].offer ).await?;
let uni_bid = offer::Offer::<Bundle>::bid (&network, Ð_SUPERCHAIN.lattices[1].offer ).await?;
let eth_tally = tally::Tally::<Attribution>::read(&network, Ð_SUPERCHAIN.lattices[0].tally).await?;
// Standalone-organism handles — same shape, concrete crate on the right.
let eur_feed = oracle::Feed::<Price>::read(&network, ETH_SUPERCHAIN.organisms[0].config()).await?;
// Module handles — resolved via typed helpers.
let atlas = atlas::Atlas::<CitizenCard>::read(&network, ETH_SUPERCHAIN.atlas().unwrap()).await?;
let almanac = almanac::Almanac::<AlmanacTick>::read(&network, ETH_SUPERCHAIN.almanac().unwrap()).await?;
// Confluence handles — the same shape, one rung up.
let intents = intents::Router::<Intent>::publish(&network, ETH_SUPERCHAIN.confluences_by_name("intents").unwrap()).await?;
let ledger = ledger ::Shared ::<Refund>::read (&network, ETH_SUPERCHAIN.confluences_by_name("ledger").unwrap()).await?;
An integrator only opens the handles they need. A cross-
chain searcher typically holds bid for several lattices
and intents::publish; a shared-ledger analytics consumer
typically holds ledger::read only; a cross-feed
correlator holds one oracle handle plus one confluence
handle; an observability operator holds atlas::read and
opens per-citizen handles from there.
Public surface summary
The coalition’s outward-facing primitives decompose into:
-
Every public primitive of every referenced lattice, unchanged. The builder book’s lattice public surface table applies without modification — the coalition does not touch lattice primitives.
-
Every public primitive of every referenced standalone organism, unchanged. Each organism’s own book is the reference.
-
Every module’s public surface (Atlas, Almanac, Chronicle — whichever are shipped), specified in basic services.
-
One or two public primitives per referenced confluence, following the same narrow-surface discipline as every other organism.
For an example coalition containing two confluences — an intent router and a shared ledger — plus Atlas and Almanac as modules, the coalition’s own added surfaces might look like:
| Component | Write-side primitives | Read-side primitives |
|---|---|---|
atlas | (committee-only) | Atlas map (CitizenId → CitizenCard) |
almanac | (committee-only) | Ticks stream |
intents | Publish<Intent> stream | RoutedIntents collection (per slot, per target lattice) |
ledger | (internal commits only) | SharedRefunds collection (keyed by origin citizen) |
“Committee-only” and “internal commits only” mean the primitive is ticket-gated to the organism’s committee peers. It still lives on the shared universe; the ticket gate supplies access control.
Names above are illustrative. The blueprint specifies Atlas/Almanac/Chronicle by role; all other confluence names are per-commission choices.
An example coalition: ethereum.superchain
Concrete walk-through of one plausible coalition. None of the confluences or services below are shipped; the sketch shows how the composition composes.
Composition
- Lattices:
ethereum.mainnet,unichain.mainnet,base.mainnet— all three referenced by stable id, none re-derived. - Standalone organisms:
price-feed.eur— an oracle feed publishing EUR/USD prices on the shared universe, referenced byOrganismRef. - Modules shipped: Atlas (directory), Almanac (tick beacon). Chronicle not shipped in this example; the operator can add it later without reshuffling citizens.
- Confluences referenced:
intents— a cross-chain intent router (reads from each lattice’sunseal::UnsealedPool, commits per- slotRoutedIntentskeyed by target lattice).ledger— a shared-refund aggregator (reads from each lattice’stally::Refunds, commitsSharedRefundskeyed by origin citizen).
Fingerprint sketch
ETH_SUPERCHAIN = blake3("coalition|" || SCHEMA_VERSION_U8
|| "|ethereum.superchain")
COALITION_ROOT = blake3(
ETH_SUPERCHAIN
|| LatticeConfig.stable_id(ethereum.mainnet)
|| LatticeConfig.stable_id(unichain.mainnet)
|| LatticeConfig.stable_id(base.mainnet)
|| OrganismRef.stable_id(price-feed.eur)
|| ConfluenceConfig.id(intents)
|| ConfluenceConfig.id(ledger)
|| (no ticket issuer)
)
ATLAS_ROOT = COALITION_ROOT.derive("module").derive("atlas")
ALMANAC_ROOT = COALITION_ROOT.derive("module").derive("almanac")
// Confluences derive independently of the coalition.
INTENTS_ID = blake3("confluence|" || SCHEMA_VERSION_U8 || "|intents"
|| [ethereum, unichain, base]
|| intents_content
|| intents_acl)
LEDGER_ID = blake3("confluence|" || SCHEMA_VERSION_U8 || "|ledger"
|| [ethereum, unichain, base]
|| ledger_content
|| ledger_acl)
// Per-component committee derivations follow the usual pattern.
A confluence’s spanned-citizen set may be a subset of the
coalition’s citizen set. An intents confluence might
span all three lattices while a feed-oracle confluence
spans price-feed.eur and one lattice. Each confluence
chooses its own span.
Participants
Not every component is operated by the same entity. The coalition distinguishes six classes of participant.
- Lattice operator — the team responsible for a
referenced
LatticeConfig’s identity, its committees, and its ACL. One or more lattice operators per coalition; each operates independently. - Standalone-organism operator — the team responsible
for a standalone organism (e.g.
price-feed.eur). Operates independently. - Confluence operator — the team responsible for one confluence’s committee members. Confluence operation is independent of any referencing coalition.
- Module operator — the team responsible for Atlas, Almanac, or Chronicle’s committee members. Often the coalition operator themselves; may be delegated.
- Coalition operator — the team responsible for
publishing and maintaining the
CoalitionConfigitself. Often coincides with one of the above; does not have to. Has no technical authority over the referenced citizens or confluences. - Integrator — external dev, runs no committee members, binds handles against the coalition from their own mosaik agent.
Data flow across one slot
The canonical happy path for one slot through this example coalition. Each step is a commit into one organism’s (or one confluence’s) state machine; transitions between steps are stream/collection subscriptions. No arrow represents an atomic multi-Group commit.
integrator organism / confluence commit / effect
---------- ---------------------- ----------------------------
wallet ──► zipnet[eth] ───► Broadcasts grows (sealed envelopes for slot S)
unseal[eth] ───► UnsealedPool[S] populated
(same for uni, base)
(publisher) ──► price-feed.eur ───► Price[tick T] committed (async, no slot clock)
(internal) ──► almanac ───► Ticks[K] committed (shared time axis)
(internal) ──► atlas ───► CitizenCard updates (any time)
confluence ──► intents ───► RoutedIntents[S] committed per target lattice
(sees cross-chain intents, routes them)
searcher ──► offer[eth] ───► AuctionOutcome[S] (incorporates routed intents)
searcher ──► offer[uni] ───► AuctionOutcome[S]
searcher ──► offer[base] ───► AuctionOutcome[S]
atelier[eth] ───► Candidates[S] committed
atelier[uni] ───► Candidates[S]
atelier[base] ───► Candidates[S]
relay[eth] ───► AcceptedHeaders[S]
relay[uni] ───► AcceptedHeaders[S]
relay[base] ───► AcceptedHeaders[S]
(chain inclusion watchers observe each lattice independently)
tally[eth] ───► Refunds[S]
tally[uni] ───► Refunds[S]
tally[base] ───► Refunds[S]
confluence ──► ledger ───► SharedRefunds[S] committed per origin citizen
wallet / searcher ◄── ledger refunds + attestations stream (aggregated)
dashboard ◄── atlas directory of citizens (for observability)
correlator ◄── almanac shared tick axis (for cross-citizen joins)
Two properties of this flow:
- The slot number remains the foreign key for block-
building lattices but is per-citizen. Slot
Sonethereum.mainnetis unrelated to slotSonunichain.mainnet. Confluences crossing citizen boundaries key commits by(citizen_id, slot)pairs (or(citizen_id, tick)for non-slotted standalone organisms). If the coalition ships an Almanac, confluences may optionally carry the currentalmanac_tickas an additional alignment key. - Each citizen’s pipeline is unchanged. The
intentsconfluence injects routed-intent entries into a lattice’sofferinput via a subscription, not a cross-Group command. Eachofferdecides whether and how to include routed intents in its auction. Non- slotted organisms likeprice-feed.eurcontinue publishing on their own clock; confluences read their ticks as they appear.
Where each confluence commits
The rule from the builder book — “what decision is the organism actually making at commit time” — carries to confluences and modules:
-
atlascommitsCitizenCardupdates. The state machine merges operator-submitted cards (signed by the contributing per-citizen operator, or by the coalition operator in single-operator coalitions) into theAtlasmap. -
almanaccommits a monotonic tick. The state machine runs a deadline-driven Raft round; winner’s tick becomesTicks[K+1]. -
intentscommits a routed-intents entry per slot per target lattice. State machine reads cross-chain intents from each spanned lattice’sUnsealedPool, applies the routing policy, commits{citizen_id, slot, intents[]}intoRoutedIntents. -
ledgercommits a shared-refund entry per origin citizen per slot. State machine reads each spanned lattice’stally::Refunds, performs attribution across origin citizens, and commits{origin_citizen, slot, shares[]}intoSharedRefunds.
The same discipline every organism in every lattice observes: one decision per commit, state-machine-local, no cross-organism transactions.
Internal plumbing (optional derived private networks)
Same pattern zipnet established and builder reaffirmed: the public surface lives on UNIVERSE; high-churn internal plumbing may move to a derived private network keyed off the organism’s root.
For confluences and modules:
- Per-citizen subscription fan-in. Gossip between
committee members about per-citizen cursor state may
live on
<component>_root.derive("private"). - Attestation gossip. Committee members signing off on a commit can exchange signatures privately before the public commit lands.
Committee Groups themselves stay on UNIVERSE. The argument is unchanged across every rung.
Identity under citizen upgrades
Citizen identity splits into a stable id and a content hash; each moves on a different cadence.
-
Citizen internal rotation (stable id unchanged, content hash bumps). MR_TD rotation or ACL change. Invisible to
COALITION_ROOT. Commissioned confluences that pin content hash redeploy; confluences that pin stable id only continue as-is. The coalition publishes an advisory if the change matters to downstream components, but theCoalitionConfigdoes not change. -
Citizen retirement (stable id changes). The per- citizen operator publishes a new identity. Coalitions that reference this citizen must re-publish their
CoalitionConfigwith the new stable id. Every module’s identity bumps becauseCOALITION_ROOThas changed; confluences do not re-derive unless they themselves span the retired citizen and pin its reference.
This is a material clarity win over a design where every citizen change ripples into confluence identity: a coalition referencing ten citizens rotating TDX monthly sees module identity stable unless a retirement happens.
A coalition operator insulating integrators from citizen
retirements carries a version-stable alias in the
coalition name (ethereum.superchain-v2026q2). See
Roadmap — Versioning.
Sizing — Phase 1 coalition
Order-of-magnitude targets for an illustrative coalition with three lattices, one standalone organism, two modules, and two confluences. Indicative, not binding.
| Component | Committee members (v1) | Stream bytes / event | Notable bonds |
|---|---|---|---|
| Per lattice (×3) | see builder sizing | see builder sizing | see builder sizing |
price-feed.eur | see organism sizing | see organism sizing | committee + publishers |
atlas (module) | 3 members | O(citizens × card size) | committee + coalition op |
almanac (module) | 3–5 members | O(1) per tick | committee only |
intents confluence | 3–7 TDX members | O(intents × lattices) | committee + each lattice |
ledger confluence | 3–5 members | O(refunds) | committee + each lattice |
“v1” here means the coalition-level Phase 1 shape. Phase 2 adds more confluences as cross-citizen problems arise; Phase 3 introduces multi-operator confluences where committee members span organisations.
What this chapter deliberately does not cover
- Per-confluence state machines. Each confluence owns its own spec in its own crate once commissioned.
- Per-confluence wire formats. Same.
- Chain-specific nuance inside a lattice. The builder book covers this; coalitions do not touch it.
- Organism-specific nuance inside a standalone organism. Each organism’s own book covers that.
- A canonical list of confluences or organism categories. See topology-intro — What a coalition is not.
- Heavy-coalition primitives (enforcement, taxation, judiciary). Deferred; see topology-intro — Fixed shapes, open catalogs.